6 Commits

Author SHA1 Message Date
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 370 additions and 389 deletions

View File

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

View File

@ -26,9 +26,9 @@ end
-- generate standard "overlay"
-- constructor for type tt.
-- if more is defined, generated
-- new calls more(ret) after
-- ret is definitely not nil
-- if tt.init is defined, generated
-- new calls tt.init(ret) after
-- ret is definitely not nil,
-- before calling setmetatable.
-- use to initialize mutables.
--
@ -37,8 +37,8 @@ end
-- object *after* more, because
-- this works better with the
-- `more` impls i use.
function mknew(tt, more)
local mt,oldnew = {__index=tt},tt.new
function mknew(tt)
local mt,oldnew,more = {__index=tt},tt.new,rawget(tt, "init")
tt.new=function(ret)
if(not ret) ret = {}
if(more) more(ret)
@ -46,15 +46,18 @@ function mknew(tt, more)
setmetatable(ret, mt)
return ret
end
return tt
end
-- intrusive singly-linked list.
-- cannot be nested!
linked_list = {is_linked_list=true}
mknew(linked_list, function(x)
linked_list = mknew{
is_linked_list=true,
init = function(x)
x.next=nil
x.tail=x
end)
end,
}
function linked_list:push_back(x)
self.tail.next = x
@ -336,10 +339,10 @@ function drawhud()
draw_gun_info("❎",1,116,3,primary_ship.main_gun)
draw_gun_info("🅾️",1,116,31,primary_ship.special_gun)
dropshadow("p h",114,59,1)
dropshadow("x h",114,59,1)
inset(114,66,119,125)
fillp(0x5a5a)
vertmeter(115,67,118,124,primary_ship.power, primary_ship.max_power, powcols)
vertmeter(115,67,118,124,primary_ship.xp, primary_ship.xptarget, powcols)
inset(120,66,125,125)
-- 57 px vertically
@ -417,19 +420,14 @@ end
scrollrate = 0.25 --in px/frame
ship_m = {
ship_m = mknew{
-- ships have no shield by default
shield = 0,
maxshield = 0,
shieldcost = 32767.9,
shieldcooldown = 0x0.003c,--1s
shieldpenalty = 0x0.012c, --5s
max_power = 120,
power = 120,
generator = 2, -- power gen per frame
slip = true, -- most enemies slide
xmomentum = 0,
@ -442,7 +440,6 @@ ship_m = {
-- ymin, ymax default to nil
-- pship needs more constraint
}
mknew(ship_m)
function ship_m:die()
self.dead = true
@ -490,7 +487,6 @@ end
function ship_m:move()
self:refresh_shield()
self.power = min(self.max_power, self.power + self.generator)
local dx, dy, shoot_spec, shoot_main = self:act()
dx = self:constrain(self.x, self.xmomentum, self.xmin, self.xmax, dx)
dy = self:constrain(self.y, self.ymomentum, self.ymin, self.ymax, dy)
@ -532,9 +528,7 @@ end
function ship_m:maybe_shoot(gun)
if (not gun) return
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
return gun:shoot(self.x + self.fire_off_x, self.y + self.fire_off_y)
end
function ship_m:hitship(other)
@ -575,10 +569,8 @@ end
function ship_m:refresh_shield()
if (self.shield >= self.maxshield) return
if (lframe < self.shield_refresh_ready) return
if (self.power < self.shieldcost) return
self.shield += 1
self.shield = min(self.shield, self.maxshield)
self.power -= self.shieldcost
self.shield_refresh_ready = lframe + self.shieldcooldown
end
@ -593,14 +585,34 @@ function enemy_blt_cat()
return ebullets
end
bullet_base = { }
mknew(bullet_base)
-- x, y: position
-- 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,
icon = 20
}
mknew(gun_base)
function bullet_base:hitship(_)
self:die()
@ -613,7 +625,8 @@ end
function bullet_base:move()
self.x += self.dx
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()
return true
end
@ -652,9 +665,9 @@ end
-->8
-- bullets and guns
zap_e = bullet_base.new{
zap_e = mknew(bullet_base.new{
--shape
sprite = 9, --index of enemy ammo sprite
sprite = 9, --index of ammo sprite
width = 1, --in 8x8 blocks
height = 1,
hurt = { -- hurtbox - where this ship can be hit
@ -673,31 +686,26 @@ zap_e = bullet_base.new{
hitship = const_fxn(true),
category = enemy_blt_cat,
}
mknew(zap_e)
})
zap_p = zap_e.new{
zap_p = mknew(zap_e.new{
sprite = 8,
dy = -8,
y_off = 0,
category = player_blt_cat,
}
mknew(zap_p)
})
zap_gun_e = gun_base.new{
power = 20, -- power consumed per shot
zap_gun_e = mknew(gun_base.new{
cooldown = 0x0.000a, -- frames between shots
ammo = nil, -- unlimited ammo - main gun
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),
}
mknew(zap_gun_p)
})
blast = bullet_base.new{
blast = mknew(bullet_base.new{
--shape
sprite = 12, --index of player ammo sprite
width = 1, --in 8x8 blocks
@ -740,20 +748,17 @@ blast = bullet_base.new{
end
end,
category=player_blt_cat
}
mknew(blast)
})
blast_gun = gun_base.new{
blast_gun = mknew(gun_base.new{
icon = 13,
power = 0, -- only cost is ammo
cooldown = 0x0.0020, -- frames between shots
ammo = 5,
maxammo = 5,
actually_shoot = spawn_one(blast),
}
mknew(blast_gun)
})
protron_e = bullet_base.new{
protron_e = mknew(bullet_base.new{
--shape
sprite = 24,
width = 1, --in 8x8 blocks
@ -771,26 +776,22 @@ protron_e = bullet_base.new{
dym = 0.5, -- gun sets dy;
-- this is mult
category = enemy_blt_cat,
}
mknew(protron_e)
})
protron_p = protron_e.new{
protron_p = mknew(protron_e.new{
sprite=23,
dym = -1,
y_off = 0,
category=player_blt_cat,
}
mknew(protron_p)
})
protron_gun_e = gun_base.new{
protron_gun_e = mknew(gun_base.new{
icon = 25,
power = 60,
cooldown = 0x0.000f, -- frames between shots
ammo = nil,
maxammo = nil,
munition = protron_e
}
mknew(protron_gun_e)
})
function protron_gun_e:actually_shoot(x, y)
local m = self.munition.dym
@ -813,12 +814,11 @@ function protron_gun_e:actually_shoot(x, y)
bup:spawn_at(x,y)
end
protron_gun_p = protron_gun_e.new{
protron_gun_p = mknew(protron_gun_e.new{
munition = protron_p,
}
mknew(protron_gun_p)
})
vulcan_e = bullet_base.new{
vulcan_e = mknew(bullet_base.new{
--shape
sprite = 21,
width = 1, --in 8x8 blocks
@ -836,21 +836,18 @@ vulcan_e = bullet_base.new{
-- dx from gun
dy = 2,
category=enemy_blt_cat
}
mknew(vulcan_e)
})
vulcan_p = vulcan_e.new{
vulcan_p = mknew(vulcan_e.new{
sprite=22,
y_off = 4,
dy = -4,
category=player_blt_cat
}
mknew(vulcan_p)
})
vulcan_gun_e = gun_base.new{
vulcan_gun_e = mknew(gun_base.new{
icon = 37,
enemy = false,
power = 8,
cooldown = 0x0.0002, -- frames between shots
ammo = nil,
maxammo = nil,
@ -866,13 +863,11 @@ vulcan_gun_e = gun_base.new{
self.dxidx += 1
if (self.dxidx > #self.dxs) self.dxidx = 1
end
}
mknew(vulcan_gun_e)
})
vulcan_gun_p = vulcan_gun_e.new{
vulcan_gun_p = mknew(vulcan_gun_e.new{
munition=vulcan_p,
}
mknew(vulcan_gun_p)
})
-->8
--ships, including player
@ -880,7 +875,7 @@ mknew(vulcan_gun_p)
firespark = split"9, 8, 2, 5, 1"
smokespark = split"13, 13, 5, 5"
player = ship_m.new{
player = mknew(ship_m.new{
--shape
sprite = 1, --index of ship sprite
size = 1, --all ships are square; how many 8x8 sprites?
@ -894,13 +889,16 @@ player = ship_m.new{
sparkodds = 2,
boss = true, -- dramatic special effects
-- health and power
-- health
hp = 3, -- current health, non-regenerating
maxhp = 3, -- player only; other ships never heal
shield = 2, -- regenerates, using power
shield = 2, -- regenerates
maxshield = 2,
shieldcost = 60, -- power cost to refill shield
generator = 2,
-- xp, increments of 0x0.01
xp = 0,
xptarget = 0x0.05,
level = 1,
-- gun
main_gun = nil, -- assign at spawn time
@ -930,10 +928,9 @@ player = ship_m.new{
end
--dx, dy, shoot_spec, shoot_main
return (((b&0x2)>>1) - (b&0x1)) * th, (((b&0x8)>>3) - ((b&0x4)>>2)) * th, (b&0x10) > 0, (b&0x20) > 0
end
}
mknew(player,
function(p)
end,
init = function(p)
p.main_gun = zap_gun_p.new()
-- ONE HIT MODE
--
@ -941,10 +938,10 @@ mknew(player,
-- p.maxhp = 0
-- p.shield = 0
-- p.maxshield = 0
end
)
end,
})
frownie = ship_m.new{
frownie = mknew(ship_m.new{
--shape
sprite = 3, --index of ship sprite
size = 1, --all ships are square; how many 8x8 sprites?
@ -957,7 +954,7 @@ frownie = ship_m.new{
sparks = smokespark,
sparkodds = 8,
-- health and power
-- health
hp = 0.5, -- enemy ships need no max hp
-- position
@ -975,10 +972,9 @@ frownie = ship_m.new{
if (tstate>=4) dx=self.thrust
return dx,0,false,false
end,
}
mknew(frownie)
})
blocky = frownie.new{
blocky = mknew(frownie.new{
sprite = 10,
hp = 1.5,
hurt = {
@ -996,12 +992,10 @@ blocky = frownie.new{
end
ship_m.ow(self)
end
}
mknew(blocky)
})
spewy = frownie.new{
spewy = mknew(frownie.new{
sprite=26,
power=-20,
hurt = {
x_off=0,
y_off=1,
@ -1009,20 +1003,18 @@ spewy = frownie.new{
height=5
},
hp=0.5,
maxpower=70,
generator=0.5,
fire_off_x=4,
fire_off_y = 7,
fire_off_y=7,
act=function(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
}
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,
size = 1,
hurt = {
@ -1036,7 +1028,6 @@ chasey = ship_m.new{
hp = 1.5,
shield = 1,
maxshield = 1,
shieldcost = 180,
fire_off_x = 4,
fire_off_y = 7,
@ -1045,18 +1036,19 @@ chasey = ship_m.new{
thrust = 0.2,
drag = 0.075,
slip = true,
}
mknew(chasey, function(ship)
ship.main_gun=ship.main_gun or zap_gun_e.new{}
end)
init = function(ship)
ship.main_gun=ship.main_gun or zap_gun_e.new{}
end
})
function chasey:act()
self.xmin = max(primary_ship.x-8, 0)
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
xl_chasey=chasey.new{
xl_chasey=mknew(chasey.new{
size=2,
maxspd=1.25,
hurt = {
@ -1081,10 +1073,11 @@ xl_chasey=chasey.new{
sspr(40, 0, 8, 8, self.x, self.y, 16, 16)
pal()
end,
}
mknew(xl_chasey, function(ship)
ship.main_gun=ship.main_gun or zap_gun_e.new{}
end)
init = function(ship)
ship.main_gun=ship.main_gun or zap_gun_e.new{}
end,
})
-->8
-- collisions
@ -1098,12 +1091,11 @@ function collides(box1, box2)
or box1.y+box1.height<box2.y)
end
collider = { }
mknew(collider,
function(x)
collider = mknew{
init = function(x)
x.suppress = {}
end
)
end,
}
function collider_indexes(box)
local ret = {}
@ -1299,7 +1291,17 @@ function spawn_bonus_vulcan_chasey()
end
c.sprite=4
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 = {
spawn_frownie,
@ -1390,7 +1392,7 @@ example_level_csv=[[1,spawn_frownie
115,spawn_spewy
130,spawn_bonus_frownie
145,spawn_spewy
200,spawn_chasey
200,spawn_bonus_shield_chasey
250,spawn_blocking_blocky
285,spawn_spec_gun_at,35,-11,blast_gun
310,spawn_blocking_blocky
@ -1407,8 +1409,9 @@ example_level_csv=[[1,spawn_frownie
500,multi,20,12,spawn_blocking_blocky
501,spawn_bonus_frownie
620,spawn_blocking_blocky
700,spawn_blocking_boss_chasey
701,eol]]
630,spawn_bonus_shield_chasey
720,spawn_blocking_boss_chasey
721,eol]]
-->8
-- readme.md
@ -1460,10 +1463,6 @@ algorithm expressed.
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.
fired once in the bullet's
default direction per shot.
@ -1491,11 +1490,6 @@ actually_shoot to change
projectile logic while keeping
cooldown and ammo logic.
ships manage generator power
before asking the gun to shoot.
this behavior is in
ship_m:maybe_shoot.
bullets
-------
* dx, dy - movement per frame.
@ -1582,39 +1576,19 @@ or less hp calls self:die() and
tells the main game loop to
remove it.
ships have power, from 0 to
ship.maxpower, increasing by
ship.generator per frame.
in maybe_shoot, ships check that
they have power to fire before
trying to fire (the gun itself
checks ammo and cooldown), and
spend that power if they fire.
power is also used to restore
shields - ship.shieldcost per
point of shields. shieldcooldown
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.
shieldcooldown is the interval
between restoring shield points.
shieldpenalty is the delay
before restoring points after
any damage, reset to this value
on every damaging hit (whether
it is absorbed by the shield or
not) -- shield behaves like
halo and other shooters in its
heritage, where it recovers if
you avoid damage for a while.
not that there is any safe cover
in this kind of game.
ships do not repair hp on their
own. negative-damage bullets
@ -1798,7 +1772,7 @@ true, they are dropped.
-->8
-- standard events
blip_fx = {
blip_fx = mknew{
cancel=false
}
@ -1816,8 +1790,6 @@ function blip_fx:abort()
self.cancel=true
end
mknew(blip_fx)
blip_pals = {}
function init_blip_pals()
for i=0,15 do
@ -1852,8 +1824,7 @@ function boom(x,y,boominess,is_boss)
return
end
spark_particle={}
mknew(spark_particle)
spark_particle=mknew{}
function spark_particle:move()
if (rnd(4) < 1) self.sidx += 1
@ -1882,7 +1853,7 @@ end
-->8
-- powerups
powerup = bullet_base.new{
powerup = mknew(bullet_base.new{
-- animated sprite array: "sprites"
-- to draw under or over anim,
-- override draw, draw the
@ -1903,8 +1874,7 @@ powerup = bullet_base.new{
anim_speed = 2,
loop_pause = 30 -- affected by animspeed
}
mknew(powerup)
})
-- sprite indexes for "sheen" animation
sheen8x8 = split"2,54,55,56,57,58,59,60,61"
@ -1924,7 +1894,7 @@ function powerup:draw()
self.width, self.height)
end
repair = powerup.new{
repair = mknew(powerup.new{
hurt = {
x_off = -2,
y_off = -2,
@ -1934,23 +1904,37 @@ repair = powerup.new{
x_off = 4,
y_off = 0,
sprites = sheen8x8,
icon = 53,
hitship = function(self, ship)
if (ship ~= primary_ship) return false
primary_ship.hp = min(primary_ship.maxhp, primary_ship.hp + 1)
return true
end,
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)
end
}
mknew(repair)
})
function spawn_repair_at(x, y)
repair.new():spawn_at(x, y)
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 = {
x_off = -2,
y_off = -2,
@ -1972,8 +1956,7 @@ gun_swap = powerup.new{
powerup.draw(self)
spr(self.gun.icon, self.x+2, self.y+2, 1, 1)
end
}
mknew(gun_swap)
})
function spawn_main_gun_at(x, y, gunt)
if (type(gunt)=="string") gunt=_ENV[gunt]
@ -2032,14 +2015,14 @@ __gfx__
00000000000000000000000000000000000000000009080000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000cccccccc77000000007700000000770000000077000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000c11ee11d70000000077000000007700000000770000000070000000000000000000000000000000000000000
0000000000000000000000000000000000000000c11ee11d00000000770000000077000000007700000000770000000700000000000000000000000000000000
0000000000000000000000000000000000000000ceeeeeed00000000700000000770000000077000000007700000007700000000000000000000000000000000
0000000000000000000000000000000000000000ceeeeeed00000000000000007700000000770000000077000000077000000007000000000000000000000000
0000000000000000000000000000000000000000c11ee11d00000000000000007000000007700000000770000000770000000077000000000000000000000000
0000000000000000000000000000000000000000c11ee11d00000000000000000000000077000000007700000007700000000770000000070000000000000000
0000000000000000000000000000000000000000cddddddd00000000000000000000000070000000077000000077000000007700000000770000000000000000
00000000000000000000000000000000cccccccccccccccc77000000007700000000770000000077000000000000000000000000000000000000000000000000
00000000000000000000000000000000c116611dc11ee11d70000000077000000007700000000770000000070000000000000000000000000000000000000000
00000000000000000000000000000000c1611c1dc11ee11d00000000770000000077000000007700000000770000000700000000000000000000000000000000
00000000000000000000000000000000c61111cdceeeeeed00000000700000000770000000077000000007700000007700000000000000000000000000000000
00000000000000000000000000000000c6111bcdceeeeeed00000000000000007700000000770000000077000000077000000007000000000000000000000000
00000000000000000000000000000000c161bbbdc11ee11d00000000000000007000000007700000000770000000770000000077000000000000000000000000
00000000000000000000000000000000c11ccb1dc11ee11d00000000000000000000000077000000007700000007700000000770000000070000000000000000
00000000000000000000000000000000cdddddddcddddddd00000000000000000000000070000000077000000077000000007700000000770000000000000000
cccccccccccc0000cccccccccccc0000cccccccccccc0000cccccccccccc0000cccccccccccc0000cccccccccccc0000cccccccccccc0000cccccccccccc0000
c1111111111d0000c1111111111d0000c1111111111d0000c1111111111d0000c1111111111d0000c111eeee111d0000ceee2222eeed0000c2221111222d0000
c1111111111d0000c1111111111d0000c1111111111d0000c1111111111d0000c111eeee111d0000c1ee2222ee1d0000ce22111122ed0000c2111111112d0000