9 Commits

Author SHA1 Message Date
5870c129eb staggered "xp", "hp" labels in UI 2024-09-07 16:33:58 -07:00
68863280f3 stagger the bars 2024-09-07 16:17:38 -07:00
3f7c4f59c0 stretch meter area 2024-09-07 16:15:00 -07:00
804eb62ae7 p is now x in ui
"x" looks pretty bad with a drop shadow! will tweak soon anyway
2024-09-07 16:07:40 -07:00
303148876d Remove power mechanics. Replace with XP stub.
Also a few random comments and cleanups along the way.
2024-09-07 16:04:01 -07:00
b379e47dbf bonus shield powerup
mostly to test whether redistributing the shield and health meters works
2024-09-02 15:22:33 -07:00
4ca3913637 it's still tyrian-like so update last_tyrianlike 2024-09-02 15:09:27 -07:00
f9ba59d992 refactor mknew
saves tokens, harder to forget to use it
2024-09-02 15:08:58 -07:00
dd143060ac squash: refactor bullets to remove enemy flag
commit ead2a7d874
Author: Kistaro Windrider <kistaro@gmail.com>
Date:   Mon Sep 2 14:45:56 2024 -0700

    fix remaining `vulcan`-family bug

commit 571412b15e
Author: Kistaro Windrider <kistaro@gmail.com>
Date:   Mon Sep 2 14:15:56 2024 -0700

    fix chasey xl offsets

commit 907bd8318c
Author: Kistaro Windrider <kistaro@gmail.com>
Date:   Mon Sep 2 14:12:35 2024 -0700

    several more fixes, now runs to the end but shot offset is wrong

commit 7170552448
Author: Kistaro Windrider <kistaro@gmail.com>
Date:   Mon Sep 2 13:41:42 2024 -0700

    first three waves of bug fixes

commit 01ab6d3969
Author: Kistaro Windrider <kistaro@gmail.com>
Date:   Mon Sep 2 12:59:49 2024 -0700

    maybe the rest of the refactor?

commit 7869192dee
Author: Kistaro Windrider <kistaro@gmail.com>
Date:   Tue Aug 20 01:21:13 2024 -0700

    partial refactor continued

commit a4658e3ef4
Author: Kistaro Windrider <kistaro@gmail.com>
Date:   Mon Aug 19 16:00:16 2024 -0700

    halfway through bullet refactor
2024-09-02 14:46:51 -07:00
2 changed files with 384 additions and 401 deletions

View File

@ -1,5 +1,5 @@
pico-8 cartridge // http://www.pico-8.com pico-8 cartridge // http://www.pico-8.com
version 41 version 42
__lua__ __lua__
-- vacuum gambit -- vacuum gambit
-- by kistaro windrider -- by kistaro windrider
@ -18,12 +18,17 @@ 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 more is defined, generated -- if tt.init is defined, generated
-- new calls more(ret) after -- new calls tt.init(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.
-- --
@ -32,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, more) function mknew(tt)
local mt,oldnew = {__index=tt},tt.new local mt,oldnew,more = {__index=tt},tt.new,rawget(tt, "init")
tt.new=function(ret) tt.new=function(ret)
if(not ret) ret = {} if(not ret) ret = {}
if(more) more(ret) if(more) more(ret)
@ -41,15 +46,18 @@ function mknew(tt, more)
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 = {is_linked_list=true} linked_list = mknew{
mknew(linked_list, function(x) is_linked_list=true,
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
@ -118,7 +126,7 @@ end
function _init() 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_p.new() -- redundant?
load_level(example_level_csv) load_level(example_level_csv)
state = game state = game
pal(2,129) pal(2,129)
@ -412,7 +420,7 @@ end
scrollrate = 0.25 --in px/frame scrollrate = 0.25 --in px/frame
ship_m = { ship_m = mknew{
-- ships have no shield by default -- ships have no shield by default
shield = 0, shield = 0,
@ -437,7 +445,6 @@ ship_m = {
-- 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
@ -580,16 +587,20 @@ end
-->8 -->8
-- bullet and gun behaviors -- bullet and gun behaviors
bullet_base = { function player_blt_cat()
enemyspd = 0.5 return pbullets
} end
mknew(bullet_base)
gun_base = { function enemy_blt_cat()
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()
@ -601,19 +612,11 @@ end
function bullet_base:move() function bullet_base:move()
self.x += self.dx self.x += self.dx
if self.enemy then
self.y += self.dy self.y += self.dy
if self.y > 128 then if (self.y > 128) or (self.y < -8 * self.height) then
self:die() self:die()
return true return true
end end
else
self.y -= self.dy
if self.y < -8*self.height then
self:die()
return true
end
end
return false return false
end end
@ -621,19 +624,20 @@ 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
function bullet_base:spawn_at(x, y) -- An `actually_shoot` factory
self.x = x - self.center_x_off -- for trivial guns
if self.enemy then function spawn_one(t)
self.dx *= self.enemyspd return function(gun, x, y)
self.dy *= self.enemyspd t.new{}:spawn_at(x, y)
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 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)
end
function gun_base:shoot(x, y) function gun_base:shoot(x, y)
if (lframe < self.shoot_ready) return false if (lframe < self.shoot_ready) return false
if self.ammo then if self.ammo then
@ -645,23 +649,12 @@ 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 = bullet_base.new{ zap_e = mknew(bullet_base.new{
--shape --shape
psprite = 8, --index of player ammo sprite sprite = 9, --index of enemy 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
@ -670,33 +663,39 @@ zap = bullet_base.new{
width = 2, width = 2,
height = 8 height = 8
}, },
center_x_off = 1, -- how to position by ship x_off = 1, -- how to position by ship
bottom_y_off = 0, y_off = 8,
top_y_off = 0,
damage = 1, damage = 1,
dx = 0, -- px/frame dx = 0, -- px/frame
dy = 8, dy = 4,
hitship = function(_, _) hitship = const_fxn(true),
return true
end
}
mknew(zap)
zap_gun = gun_base.new{ category = enemy_blt_cat,
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
t = zap -- metatable of bullet to fire actually_shoot = spawn_one(zap_e),
} })
mknew(zap_gun)
blast = bullet_base.new{ zap_gun_p = mknew(zap_gun_e.new{
actually_shoot = spawn_one(zap_p),
})
blast = mknew(bullet_base.new{
--shape --shape
psprite = 12, --index of player ammo sprite sprite = 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
@ -705,13 +704,12 @@ blast = bullet_base.new{
width = 6, width = 6,
height = 6 height = 6
}, },
center_x_off = 4, -- how to position by ship x_off = 4, -- how to position by ship
bottom_y_off = 0, 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
@ -736,25 +734,22 @@ blast = bullet_base.new{
self.awaitcancel = false self.awaitcancel = false
end) end)
end end
end end,
} category=player_blt_cat
mknew(blast) })
blast_gun = gun_base.new{ blast_gun = mknew(gun_base.new{
icon = 13, icon = 13,
enemy = false, power = 0, -- only cost is ammo
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,
t = blast -- type of bullet to fire actually_shoot = spawn_one(blast),
} })
mknew(blast_gun)
protron = bullet_base.new{ protron_e = mknew(bullet_base.new{
--shape --shape
psprite = 23, --index of player ammo sprite sprite = 24,
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
@ -763,56 +758,59 @@ protron = bullet_base.new{
width = 2, width = 2,
height = 2 height = 2
}, },
center_x_off = 1, -- how to position by ship x_off = 1, -- how to position by ship
bottom_y_off = 4, y_off = 4,
top_y_off = 0,
damage = 1, damage = 1,
dx = 0, -- px/frame dym = 0.5, -- gun sets dy;
dy = 3, -- this is mult
} category = enemy_blt_cat,
mknew(protron) })
protron_gun = gun_base.new{ protron_p = mknew(protron_e.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,
actually_shoot = function(self, x, y) munition = protron_e
local sprite = protron.psprite })
if (self.enemy) sprite=protron.esprite
function protron_gun_e:actually_shoot(x, y)
local m = self.munition.dym
for i=1,3 do for i=1,3 do
local b = protron.new{ local b = self.munition.new{
enemy=self.enemy, dx = i*m,
sprite=sprite, dy = (4-i)*m,
dx = i,
dy = 4-i
} }
b:spawn_at(x,y) b:spawn_at(x,y)
local b2 = protron.new{ local b2 = self.munition.new{
enemy=self.enemy, dx = -i*m,
sprite=sprite, dy = (4-i)*m,
dx = -i,
dy = 4-i
} }
b2:spawn_at(x,y) b2:spawn_at(x,y)
end end
local bup = protron.new{ local bup = self.munition.new{
enemy=self.enemy, dx=0,
sprite=sprite, dy=4*m,
dy=4
} }
bup:spawn_at(x,y) bup:spawn_at(x,y)
end end
}
mknew(protron_gun)
vulcan = bullet_base.new{ protron_gun_p = mknew(protron_gun_e.new{
munition = protron_p,
})
vulcan_e = mknew(bullet_base.new{
--shape --shape
psprite = 22, --index of player ammo sprite sprite = 21,
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
@ -821,39 +819,46 @@ vulcan = bullet_base.new{
width = 1, width = 1,
height = 4 height = 4
}, },
center_x_off = 0.5, -- how to position by ship x_off = 0.5, -- how to position by ship
bottom_y_off = 4, y_off = 0,
top_y_off = 0,
damage = 0.5, damage = 0.5,
dx = 0, -- px/frame -- dx from gun
dy = 4, dy = 2,
} category=enemy_blt_cat
mknew(vulcan) })
vulcan_gun = gun_base.new{ vulcan_p = mknew(vulcan_e.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 sprite = self.enemy and vulcan.esprite or vulcan.psprite local b = self.munition.new{
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
@ -861,7 +866,7 @@ mknew(vulcan_gun)
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 = ship_m.new{ player = mknew(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?
@ -911,21 +916,20 @@ player = 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,
}
mknew(player, init = function(p)
function(p) p.main_gun = zap_gun_p.new()
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 = ship_m.new{ frownie = mknew(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,10 +960,9 @@ frownie = 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 = frownie.new{ blocky = mknew(frownie.new{
sprite = 10, sprite = 10,
hp = 1.5, hp = 1.5,
hurt = { hurt = {
@ -977,10 +980,9 @@ blocky = frownie.new{
end end
ship_m.ow(self) ship_m.ow(self)
end end
} })
mknew(blocky)
spewy = frownie.new{ spewy = mknew(frownie.new{
sprite=26, sprite=26,
power=-20, power=-20,
hurt = { hurt = {
@ -997,13 +999,13 @@ spewy = 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 = ship_m.new{ chasey = mknew(ship_m.new{
sprite = 5, sprite = 5,
size = 1, size = 1,
hurt = { hurt = {
@ -1026,10 +1028,11 @@ chasey = ship_m.new{
thrust = 0.2, thrust = 0.2,
drag = 0.075, drag = 0.075,
slip = true, slip = true,
}
mknew(chasey, function(ship) init = function(ship)
ship.main_gun=ship.main_gun or zap_gun.new{enemy=true} 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)
@ -1037,7 +1040,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=chasey.new{ xl_chasey=mknew(chasey.new{
size=2, size=2,
maxspd=1.25, maxspd=1.25,
hurt = { hurt = {
@ -1046,6 +1049,8 @@ xl_chasey=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,
@ -1060,10 +1065,11 @@ xl_chasey=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)
mknew(xl_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) })
-->8 -->8
-- collisions -- collisions
@ -1077,12 +1083,11 @@ function collides(box1, box2)
or box1.y+box1.height<box2.y) or box1.y+box1.height<box2.y)
end end
collider = { } collider = mknew{
mknew(collider, init = function(x)
function(x)
x.suppress = {} x.suppress = {}
end end,
) }
function collider_indexes(box) function collider_indexes(box)
local ret = {} local ret = {}
@ -1271,9 +1276,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.new{enemy=true} c.main_gun=vulcan_gun_e.new{enemy=true}
c.die = function(self) c.die = function(self)
spawn_main_gun_at(self.x-1, self.y-1, vulcan_gun) spawn_main_gun_at(self.x-1, self.y-1, vulcan_gun_p)
chasey.die(self) chasey.die(self)
end end
c.sprite=4 c.sprite=4
@ -1376,7 +1381,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 350,spawn_main_gun_at,70,-11,protron_gun_p
401,spawn_frownie 401,spawn_frownie
420,spawn_blocking_frownie 420,spawn_blocking_frownie
430,spawn_bonus_vulcan_chasey 430,spawn_bonus_vulcan_chasey
@ -1486,8 +1491,9 @@ 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
* psprite, esprite - index of * sprite - sprite index.
player or enemy sprite. * x_off, y_off - renamed for
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.
@ -1776,7 +1782,7 @@ true, they are dropped.
-->8 -->8
-- standard events -- standard events
blip_fx = { blip_fx = mknew{
cancel=false cancel=false
} }
@ -1794,8 +1800,6 @@ 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
@ -1830,8 +1834,7 @@ function boom(x,y,boominess,is_boss)
return return
end end
spark_particle={} spark_particle=mknew{}
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
@ -1860,7 +1863,7 @@ end
-->8 -->8
-- powerups -- powerups
powerup = bullet_base.new{ powerup = mknew(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,13 +1879,12 @@ powerup = 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
enemy = true, -- collides with player ship category = enemy_blt_cat, -- 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"
@ -1902,16 +1904,15 @@ function powerup:draw()
self.width, self.height) self.width, self.height)
end end
repair = powerup.new{ repair = mknew(powerup.new{
hurt = { hurt = {
x_off = -2, x_off = -2,
y_off = -2, y_off = -2,
width = 12, width = 12,
height = 12 height = 12
}, },
center_x_off = 4, x_off = 4,
top_y_off = 0, 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
@ -1922,14 +1923,13 @@ repair = 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 = powerup.new{ gun_swap = mknew(powerup.new{
hurt = { hurt = {
x_off = -2, x_off = -2,
y_off = -2, y_off = -2,
@ -1937,9 +1937,8 @@ gun_swap = powerup.new{
height = 16 height = 16
}, },
-- gun = gun_type.new{} -- gun = gun_type.new{}
center_x_off = 6, x_off = 6,
top_y_off = 0, 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},
@ -1952,8 +1951,7 @@ gun_swap = 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 more is defined, generated -- if tt.init is defined, generated
-- new calls more(ret) after -- new calls tt.init(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, more) function mknew(tt)
local mt,oldnew = {__index=tt},tt.new local mt,oldnew,more = {__index=tt},tt.new,rawget(tt, "init")
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,15 +46,18 @@ function mknew(tt, more)
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 = {is_linked_list=true} linked_list = mknew{
mknew(linked_list, function(x) is_linked_list=true,
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
@ -334,28 +337,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,31,primary_ship.special_gun) draw_gun_info("🅾️",1,116,29,primary_ship.special_gun)
dropshadow("p h",114,59,1) inset(114,57,119,118)
inset(114,66,119,125) rectfill(119,57,125,58,13)
inset(120,64,125,125)
rectfill(114,124,120,125,13)
print("XP",120,56,1)
print("HP",113,121,1)
fillp(0x5a5a) fillp(0x5a5a)
vertmeter(115,67,118,124,primary_ship.power, primary_ship.max_power, powcols) vertmeter(115,58,118,117,primary_ship.xp, primary_ship.xptarget, 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 = 57 * (mxs / (mxs + mxh)) \ 1 + 66 local split = 59 * (mxs / (mxs + mxh)) \ 1 + 64
line(121, split, 124, split, 0xba) line(121, split, 124, split, 0xba)
vertmeter(121,67,124,split-1,cs, mxs,shlcols) vertmeter(121,65,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,67,124,124,cs,mxs,shlcols) vertmeter(121,65,124,124,cs,mxs,shlcols)
elseif mxh > 0 then elseif mxh > 0 then
vertmeter(121,67,124,124,ch,mxh,hpcols) vertmeter(121,65,124,124,ch,mxh,hpcols)
else else
print("!", 122, 94, 9) print("!", 122, 93, 9)
print("!", 121, 93, 8) print("!", 121, 92, 8)
end end
fillp(0) fillp(0)
end end
@ -417,19 +422,14 @@ end
scrollrate = 0.25 --in px/frame scrollrate = 0.25 --in px/frame
ship_m = { ship_m = mknew{
-- 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,7 +442,6 @@ ship_m = {
-- 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
@ -490,7 +489,6 @@ 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)
@ -532,9 +530,7 @@ end
function ship_m:maybe_shoot(gun) function ship_m:maybe_shoot(gun)
if (not gun) return if (not gun) return
if (self.power < gun.power) return return gun:shoot(self.x + self.fire_off_x, self.y + self.fire_off_y)
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)
@ -575,10 +571,8 @@ 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
@ -593,14 +587,34 @@ function enemy_blt_cat()
return ebullets return ebullets
end end
bullet_base = { } -- x, y: position
mknew(bullet_base) -- dx, dy: movement (linear)
-- 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 = { 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()
@ -613,7 +627,8 @@ 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.y > 128) or (self.y < -8 * self.height) then if (self.f) self.f -= 1
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
@ -652,9 +667,9 @@ end
-->8 -->8
-- bullets and guns -- bullets and guns
zap_e = bullet_base.new{ zap_e = mknew(bullet_base.new{
--shape --shape
sprite = 9, --index of enemy ammo sprite sprite = 9, --index of 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
@ -673,31 +688,26 @@ zap_e = bullet_base.new{
hitship = const_fxn(true), hitship = const_fxn(true),
category = enemy_blt_cat, category = enemy_blt_cat,
} })
mknew(zap_e)
zap_p = zap_e.new{ zap_p = mknew(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 = gun_base.new{ zap_gun_e = mknew(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 = zap_gun_e.new{ zap_gun_p = mknew(zap_gun_e.new{
actually_shoot = spawn_one(zap_p), actually_shoot = spawn_one(zap_p),
} })
mknew(zap_gun_p)
blast = bullet_base.new{ blast = mknew(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
@ -740,20 +750,17 @@ blast = bullet_base.new{
end end
end, end,
category=player_blt_cat category=player_blt_cat
} })
mknew(blast)
blast_gun = gun_base.new{ blast_gun = mknew(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 = bullet_base.new{ protron_e = mknew(bullet_base.new{
--shape --shape
sprite = 24, sprite = 24,
width = 1, --in 8x8 blocks width = 1, --in 8x8 blocks
@ -771,26 +778,22 @@ protron_e = 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 = protron_e.new{ protron_p = mknew(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 = gun_base.new{ protron_gun_e = mknew(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
@ -813,12 +816,11 @@ function protron_gun_e:actually_shoot(x, y)
bup:spawn_at(x,y) bup:spawn_at(x,y)
end end
protron_gun_p = protron_gun_e.new{ protron_gun_p = mknew(protron_gun_e.new{
munition = protron_p, munition = protron_p,
} })
mknew(protron_gun_p)
vulcan_e = bullet_base.new{ vulcan_e = mknew(bullet_base.new{
--shape --shape
sprite = 21, sprite = 21,
width = 1, --in 8x8 blocks width = 1, --in 8x8 blocks
@ -836,21 +838,18 @@ vulcan_e = 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 = vulcan_e.new{ vulcan_p = mknew(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 = gun_base.new{ vulcan_gun_e = mknew(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,
@ -866,13 +865,11 @@ vulcan_gun_e = 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 = vulcan_gun_e.new{ vulcan_gun_p = mknew(vulcan_gun_e.new{
munition=vulcan_p, munition=vulcan_p,
} })
mknew(vulcan_gun_p)
-->8 -->8
--ships, including player --ships, including player
@ -880,7 +877,7 @@ mknew(vulcan_gun_p)
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 = ship_m.new{ player = mknew(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?
@ -894,13 +891,16 @@ player = ship_m.new{
sparkodds = 2, sparkodds = 2,
boss = true, -- dramatic special effects boss = true, -- dramatic special effects
-- health and power -- health
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, using power shield = 2, -- regenerates
maxshield = 2, maxshield = 2,
shieldcost = 60, -- power cost to refill shield
generator = 2, -- xp, increments of 0x0.01
xp = 0,
xptarget = 0x0.05,
level = 1,
-- gun -- gun
main_gun = nil, -- assign at spawn time main_gun = nil, -- assign at spawn time
@ -930,10 +930,9 @@ player = 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,
}
mknew(player, init = function(p)
function(p)
p.main_gun = zap_gun_p.new() p.main_gun = zap_gun_p.new()
-- ONE HIT MODE -- ONE HIT MODE
-- --
@ -941,10 +940,10 @@ mknew(player,
-- p.maxhp = 0 -- p.maxhp = 0
-- p.shield = 0 -- p.shield = 0
-- p.maxshield = 0 -- p.maxshield = 0
end end,
) })
frownie = ship_m.new{ frownie = mknew(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?
@ -957,7 +956,7 @@ frownie = ship_m.new{
sparks = smokespark, sparks = smokespark,
sparkodds = 8, sparkodds = 8,
-- health and power -- health
hp = 0.5, -- enemy ships need no max hp hp = 0.5, -- enemy ships need no max hp
-- position -- position
@ -975,10 +974,9 @@ frownie = 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 = frownie.new{ blocky = mknew(frownie.new{
sprite = 10, sprite = 10,
hp = 1.5, hp = 1.5,
hurt = { hurt = {
@ -996,12 +994,10 @@ blocky = frownie.new{
end end
ship_m.ow(self) ship_m.ow(self)
end end
} })
mknew(blocky)
spewy = frownie.new{ spewy = mknew(frownie.new{
sprite=26, sprite=26,
power=-20,
hurt = { hurt = {
x_off=0, x_off=0,
y_off=1, y_off=1,
@ -1009,20 +1005,18 @@ spewy = 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, true return dx, dy, shoot_spec, self.y > 10
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 = ship_m.new{ chasey = mknew(ship_m.new{
sprite = 5, sprite = 5,
size = 1, size = 1,
hurt = { hurt = {
@ -1036,7 +1030,6 @@ chasey = 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,
@ -1045,18 +1038,19 @@ chasey = ship_m.new{
thrust = 0.2, thrust = 0.2,
drag = 0.075, drag = 0.075,
slip = true, slip = true,
}
mknew(chasey, function(ship) init = 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.x - 16 < primary_ship.x and self.x + 16 > primary_ship.x return 0, 0, false, self.y > 10 and self.x - 16 < primary_ship.x and self.x + 16 > primary_ship.x
end end
xl_chasey=chasey.new{ xl_chasey=mknew(chasey.new{
size=2, size=2,
maxspd=1.25, maxspd=1.25,
hurt = { hurt = {
@ -1081,10 +1075,11 @@ xl_chasey=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)
mknew(xl_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,
})
-->8 -->8
-- collisions -- collisions
@ -1098,12 +1093,11 @@ function collides(box1, box2)
or box1.y+box1.height<box2.y) or box1.y+box1.height<box2.y)
end end
collider = { } collider = mknew{
mknew(collider, init = function(x)
function(x)
x.suppress = {} x.suppress = {}
end end,
) }
function collider_indexes(box) function collider_indexes(box)
local ret = {} local ret = {}
@ -1301,6 +1295,16 @@ function spawn_bonus_vulcan_chasey()
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,
spawn_frownie, spawn_frownie,
@ -1390,7 +1394,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_chasey 200,spawn_bonus_shield_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
@ -1407,8 +1411,9 @@ 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
700,spawn_blocking_boss_chasey 630,spawn_bonus_shield_chasey
701,eol]] 720,spawn_blocking_boss_chasey
721,eol]]
-->8 -->8
-- readme.md -- readme.md
@ -1460,10 +1465,6 @@ 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.
@ -1491,11 +1492,6 @@ 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.
@ -1582,39 +1578,19 @@ or less hp calls self:die() and
tells the main game loop to tells the main game loop to
remove it. remove it.
ships have power, from 0 to shieldcooldown is the interval
ship.maxpower, increasing by between restoring shield points.
ship.generator per frame. shieldpenalty is the delay
in maybe_shoot, ships check that before restoring points after
they have power to fire before any damage, reset to this value
trying to fire (the gun itself on every damaging hit (whether
checks ammo and cooldown), and it is absorbed by the shield or
spend that power if they fire. not) -- shield behaves like
halo and other shooters in its
power is also used to restore heritage, where it recovers if
shields - ship.shieldcost per you avoid damage for a while.
point of shields. shieldcooldown not that there is any safe cover
is the interval between in this kind of game.
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
@ -1798,7 +1774,7 @@ true, they are dropped.
-->8 -->8
-- standard events -- standard events
blip_fx = { blip_fx = mknew{
cancel=false cancel=false
} }
@ -1816,8 +1792,6 @@ 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
@ -1852,8 +1826,7 @@ function boom(x,y,boominess,is_boss)
return return
end end
spark_particle={} spark_particle=mknew{}
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
@ -1882,7 +1855,7 @@ end
-->8 -->8
-- powerups -- powerups
powerup = bullet_base.new{ powerup = mknew(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
@ -1903,8 +1876,7 @@ powerup = 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"
@ -1924,7 +1896,7 @@ function powerup:draw()
self.width, self.height) self.width, self.height)
end end
repair = powerup.new{ repair = mknew(powerup.new{
hurt = { hurt = {
x_off = -2, x_off = -2,
y_off = -2, y_off = -2,
@ -1934,23 +1906,37 @@ repair = 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(53, self.x, self.y, self.width, self.height) spr(self.icon, 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 = powerup.new{ shield_upgrade = mknew(repair.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,
@ -1972,8 +1958,7 @@ gun_swap = 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]
@ -2032,14 +2017,14 @@ __gfx__
00000000000000000000000000000000000000000009080000000000000000000000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000009080000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000cccccccc77000000007700000000770000000077000000000000000000000000000000000000000000000000 00000000000000000000000000000000cccccccccccccccc77000000007700000000770000000077000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000c11ee11d70000000077000000007700000000770000000070000000000000000000000000000000000000000 00000000000000000000000000000000c116611dc11ee11d70000000077000000007700000000770000000070000000000000000000000000000000000000000
0000000000000000000000000000000000000000c11ee11d00000000770000000077000000007700000000770000000700000000000000000000000000000000 00000000000000000000000000000000c1611c1dc11ee11d00000000770000000077000000007700000000770000000700000000000000000000000000000000
0000000000000000000000000000000000000000ceeeeeed00000000700000000770000000077000000007700000007700000000000000000000000000000000 00000000000000000000000000000000c61111cdceeeeeed00000000700000000770000000077000000007700000007700000000000000000000000000000000
0000000000000000000000000000000000000000ceeeeeed00000000000000007700000000770000000077000000077000000007000000000000000000000000 00000000000000000000000000000000c6111bcdceeeeeed00000000000000007700000000770000000077000000077000000007000000000000000000000000
0000000000000000000000000000000000000000c11ee11d00000000000000007000000007700000000770000000770000000077000000000000000000000000 00000000000000000000000000000000c161bbbdc11ee11d00000000000000007000000007700000000770000000770000000077000000000000000000000000
0000000000000000000000000000000000000000c11ee11d00000000000000000000000077000000007700000007700000000770000000070000000000000000 00000000000000000000000000000000c11ccb1dc11ee11d00000000000000000000000077000000007700000007700000000770000000070000000000000000
0000000000000000000000000000000000000000cddddddd00000000000000000000000070000000077000000077000000007700000000770000000000000000 00000000000000000000000000000000cdddddddcddddddd00000000000000000000000070000000077000000077000000007700000000770000000000000000
cccccccccccc0000cccccccccccc0000cccccccccccc0000cccccccccccc0000cccccccccccc0000cccccccccccc0000cccccccccccc0000cccccccccccc0000 cccccccccccc0000cccccccccccc0000cccccccccccc0000cccccccccccc0000cccccccccccc0000cccccccccccc0000cccccccccccc0000cccccccccccc0000
c1111111111d0000c1111111111d0000c1111111111d0000c1111111111d0000c1111111111d0000c111eeee111d0000ceee2222eeed0000c2221111222d0000 c1111111111d0000c1111111111d0000c1111111111d0000c1111111111d0000c1111111111d0000c111eeee111d0000ceee2222eeed0000c2221111222d0000
c1111111111d0000c1111111111d0000c1111111111d0000c1111111111d0000c111eeee111d0000c1ee2222ee1d0000ce22111122ed0000c2111111112d0000 c1111111111d0000c1111111111d0000c1111111111d0000c1111111111d0000c111eeee111d0000c1ee2222ee1d0000ce22111122ed0000c2111111112d0000