30 Commits

Author SHA1 Message Date
b7c3e6ee92 adjust menu renderer 2025-05-03 17:26:48 -07:00
c91e5f4bd1 shorten RATE message
not enough room to describe "fractions add up" -- maybe I can just fit
in the "remainder" to hint that it will be considered in future
upgrades?
2025-05-03 17:19:33 -07:00
ea2ddadb15 oops, method call syntax is special 2025-05-03 17:12:20 -07:00
9333c03bf3 add main gun rate upgrade to ship pool 2025-05-03 17:11:47 -07:00
1b45bd3dc3 fix rate formatting 2025-05-03 17:11:35 -07:00
71a7351d77 oops, miscalculated box width 2025-05-03 17:04:29 -07:00
80bb848468 options work better when I return them 2025-05-03 16:51:59 -07:00
b227844d12 Restyle ship stat upgrades. 2025-05-03 16:48:18 -07:00
ce14d03669 offer gun upgrades 2025-05-03 16:38:39 -07:00
ccd2c64103 update gun pick description style 2025-05-03 16:38:26 -07:00
e5b8a30cb6 cooldown reduction prototype
I decided to keep cooldown in the same unit as the frame counter,
because the extra math when calculating an upgrade is going to happen
much less frequently than actual cooldown checks and calculations, so
leaving the upgrade logic as the less efficient path seems like the
more appropriate choice.
2025-05-03 16:28:54 -07:00
7ed305d2d9 Ammo quantity upgrade prototype
Not yet tested. Will crash until I also get rate_upgrade_opt up.
2025-05-03 16:06:16 -07:00
288b7f64c8 tinker with blip colors, go back to level+1
with the current testing level, level + 1 is necessary to comfortably
get a weapon before the Wall O' Block shows up
2025-01-26 22:32:17 -08:00
aea2a8c481 red blip when shield exhausted 2025-01-26 22:27:14 -08:00
9b24f10c23 inline ow, simplify blip, no shield piercing
* any amount of shielding prevents all HP damage
* when shields are sent to 0, orange blip
* all blips are 3 frames

considering a "shimmy" animation for start of shield recovery. maybe later
2025-01-26 22:25:06 -08:00
511c18f90e remove offset when choosing category of upgrade 2025-01-26 22:15:03 -08:00
142810ee2d scatter xp drops more 2025-01-26 22:11:02 -08:00
50beae1852 don't attract xp when dead 2025-01-26 22:08:16 -08:00
9c95fc1784 suck! suck! suck! suck! suck! suck! suck! suck! 2025-01-26 21:00:39 -08:00
cb2d24c9d0 thrust performance is now also an option 2025-01-26 20:38:31 -08:00
67603f8496 start of normal ship upgrades
todo: thrust upgrade
2025-01-26 20:21:06 -08:00
2cebea663f make stat modifications actually work 2025-01-26 13:14:59 -08:00
eed7b6af87 unique bullet base instances
peel off new copies of ammo when using a new gun so we can upgrade it without screwing up the base stats
2025-01-26 13:07:43 -08:00
26c3a5b91e actually fix starting ammo
also improve box overflow
2025-01-26 12:50:27 -08:00
44c70a028f fix starting ammo 2025-01-26 12:45:43 -08:00
a90caeba85 make level less spewy, finish renaming s to icon 2025-01-26 12:42:57 -08:00
cd5b79ef4a prototype: gun picking 2025-01-26 11:21:32 -08:00
637eed1eb8 autofire and three guns 2025-01-26 01:06:37 -08:00
55ab256539 oh right I changed that name 2025-01-26 00:32:17 -08:00
22d13121a9 placeholders for card draw 2025-01-26 00:30:09 -08:00

View File

@ -126,8 +126,7 @@ end
function _init() function _init()
mode = game_mode mode = game_mode
init_blip_pals() init_blip_pals()
wipe_level() wipe_game() -- redundant?
primary_ship.main_gun = zap_gun_p.new() -- redundant?
load_level(example_level_csv) load_level(example_level_csv)
game_state = game game_state = game
pal(2,129) pal(2,129)
@ -157,7 +156,7 @@ function init_hpcols()
hpcols = hpcols_lut[min(primary_ship.maxhp,6)] hpcols = hpcols_lut[min(primary_ship.maxhp,6)]
end end
function wipe_level() function wipe_game()
xpwhoosh = nil xpwhoosh = nil
primary_ship = player.new() primary_ship = player.new()
init_hpcols() init_hpcols()
@ -170,6 +169,8 @@ function wipe_level()
intangibles_bg = linked_list.new() intangibles_bg = linked_list.new()
events = linked_list.new() events = linked_list.new()
new_events = linked_list.new() new_events = linked_list.new()
primary_ship.main_gun = zap_gun_p.new()
primary_ship.main_gun:peel()
end end
function _update60() function _update60()
@ -363,8 +364,8 @@ function drawhud()
line(127,1,127,127,5) line(127,1,127,127,5)
line(113,127) line(113,127)
draw_gun_info("❎",1,116,3,primary_ship.main_gun) draw_gun_info("❎",1,116,3,1)
draw_gun_info("🅾️",1,116,29,primary_ship.special_gun) draw_gun_info("🅾️",1,116,29,2)
inset(114,57,119,118) inset(114,57,119,118)
rectfill(119,57,124,58,13) rectfill(119,57,124,58,13)
@ -404,25 +405,26 @@ function drawhud()
fillp(0) fillp(0)
end end
function draw_gun_info(lbl,fgc,x,y,gun) function draw_gun_info(lbl,fgc,x,y,gn)
dropshadow(lbl,x,y,fgc) dropshadow(lbl,x,y,fgc)
inset(114,y+7,125,y+18) inset(114,y+7,125,y+18)
inset(114,y+20,125,y+24) inset(114,y+20,125,y+24)
if(gun) then if (not primary_ship.special_guns) return
spr(gun.icon,116,y+9,1,1) local gun = primary_ship.special_guns[gn]
--115 to 124 - ammo bar. round up if (not gun) return
if gun.ammo == nil then spr(gun.icon,116,y+9,1,1)
fillp(0xa5a5) --115 to 124 - ammo bar. round up
rectfill(115,y+21,124,y+23,0xea) if gun.ammo == nil then
fillp(0) fillp(0xa5a5)
elseif gun.ammo > 0 then rectfill(115,y+21,124,y+23,0xea)
rectfill( fillp(0)
115,y+21, elseif gun.ammo > 0 then
115+flr(9*gun.ammo/gun.maxammo), rectfill(
y+23,10) 115,y+21,
else 115+flr(9*gun.ammo/gun.maxammo),
line(118, y+22, 121, y+22, 2) y+23,10)
end else
line(118, y+22, 121, y+22, 2)
end end
end end
@ -501,14 +503,14 @@ function ship_m:die()
-- overage XP, min 100 -- overage XP, min 100
spawn_xp_at(cx, cy, 0, xp-0x0.018f) spawn_xp_at(cx, cy, 0, xp-0x0.018f)
xp = 0x0.018f -- dec 399 xp = 0x0.018f -- dec 399
z += 1 z += 2
end end
-- 100, 25, 5, 1 -- 100, 25, 5, 1
for gsz in all{0x0.0064, 0x0.0019, 0x0.0005, 0x0.0001} do for gsz in all{0x0.0064, 0x0.0019, 0x0.0005, 0x0.0001} do
while xp >= gsz do while xp >= gsz do
spawn_xp_at(cx, cy, z, gsz) spawn_xp_at(cx, cy, z, gsz)
xp -= gsz xp -= gsz
z += 1 z += 2
end end
end end
end end
@ -554,11 +556,12 @@ end
function ship_m:move() function ship_m:move()
self:refresh_shield() self:refresh_shield()
local dx, dy, shoot_spec, shoot_main = self:act() local dx, dy, shoot_spec1, shoot_spec2 = 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)
if (shoot_main) self:maybe_shoot(self.main_gun) self:maybe_shoot(self.main_gun)
if (shoot_spec) self:maybe_shoot(self.special_gun) if (shoot_spec1 and self.special_guns) self:maybe_shoot(self.special_guns[1])
if (shoot_spec2 and self.special_guns) self:maybe_shoot(self.special_guns[2])
if (dx ~= 0 or dy ~= 0) spark(self.sparks, self.x + 4*self.size, self.y + 4*self.size, dx*2.5, dy*2.5, self.sparkodds) if (dx ~= 0 or dy ~= 0) spark(self.sparks, self.x + 4*self.size, self.y + 4*self.size, dx*2.5, dy*2.5, self.sparkodds)
self.xmomentum = self:calc_velocity(self.xmomentum, dx) self.xmomentum = self:calc_velocity(self.xmomentum, dx)
self.ymomentum = self:calc_velocity(self.ymomentum, dy) self.ymomentum = self:calc_velocity(self.ymomentum, dy)
@ -609,30 +612,25 @@ end
function ship_m:hitsomething(dmg) function ship_m:hitsomething(dmg)
if (dmg <= 0) return false if (dmg <= 0) return false
self.shield_refresh_ready = lframe + self.shieldpenalty self.shield_refresh_ready = lframe + self.shieldpenalty
if self.shield >= dmg then if self.shield > 0 then
self.shield -= dmg self.shield -= dmg
self:ow(true) if self.shield > 0 then
blip(self,12)
else
self.shield = 0
blip(self,7)
end
return false return false
end end
dmg -= self.shield
self.shield = 0
self.hp -= dmg self.hp -= dmg
if self.hp < 0 then if self.hp < 0 then
self:die() self:die()
return true return true
end end
self:ow(false) blip(self, self.friendly and 8 or 7)
return false return false
end end
function ship_m:ow(shielded)
if (shielded) then
blip(self,12,3)
return
end
blip(self, 7, 3)
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
@ -678,9 +676,105 @@ bullet_base = mknew{ }
gun_base = mknew{ gun_base = mknew{
shoot_ready = -32768, shoot_ready = -32768,
icon = 20 icon = 20,
ammobonus = 1,
-- fractional frames of
-- cooldown reduction from
-- upgrades, not yet applied
cd_remainder = 0,
} }
-- gun_base subtypes are
-- level-up options that,
-- as an action, assign
-- themselves to the player
function gun_base:action()
local item = self.new()
item:peel()
item.ammo = item.maxammo
if not primary_ship.special_guns then
primary_ship.special_guns = {item}
else
add(primary_ship.special_guns, item)
end
end
-- make shot type unique so
-- stat modifications do not
-- damage base data
function gun_base:peel()
self.munition = mknew(self.munition.new())
end
-- default firing behavior:
-- single shot
function gun_base:actually_shoot(x, y)
self.munition.new{}:spawn_at(x, y)
end
-- upgrade
function gun_base:small_upgrade_opts()
local ret = {
self:ammo_upgrade_opt(),
self:rate_upgrade_opt(),
}
local s = self.special_upgrade_opt
if (s) add(ret, s(self))
return ret
end
function gun_base:ammo_upgrade_opt()
local a=self.maxammo
local x=a\10+self.ammobonus
return {
icon=self.icon,
hdr=self.hdr,
body=[[--------AMMO
more shots
before you
run out.
is: ]]..tostr(a)..[[
add: ]]..tostr(x)..[[
----------
total: ]]..tostr(a+x),
action=function()
self.maxammo+=x
self.ammo+=x
end,
}
end
function gun_base:rate_upgrade_opt()
local c=self.cooldown<<16
local rawnewc=0.85*(c-self.cd_remainder)
local newc=ceil(rawnewc)
return {
icon=self.icon,
hdr=self.hdr,
body=[[--------RATE
reduce delay
between each
shot when
firing.
is: ]]..tostr(c)..[[f
minus: ]]..tostr(c-newc)..[[f
----------
total: ]]..tostr(newc)..[[f
remainder:
]]..sub(tostr(newc-rawnewc),0,5),
action=function()
self.cooldown=newc>>16
self.cd_remainder=newc-rawnewc
end,
}
end
function bullet_base:hitship(_) function bullet_base:hitship(_)
self:die() self:die()
return true return true
@ -704,14 +798,6 @@ 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.x_off
self.y = y - self.y_off self.y = y - self.y_off
@ -763,13 +849,14 @@ zap_p = mknew(zap_e.new{
}) })
zap_gun_e = mknew(gun_base.new{ zap_gun_e = mknew(gun_base.new{
cooldown = 0x0.000a, -- frames between shots cooldown = 0x0.0020, -- frames between shots
ammo = nil, -- unlimited ammo - main gun munition = zap_e,
actually_shoot = spawn_one(zap_e),
}) })
zap_gun_p = mknew(zap_gun_e.new{ zap_gun_p = mknew(zap_gun_e.new{
actually_shoot = spawn_one(zap_p), icon = 19,
munition = zap_p,
hdr = "mAIN gUN",
}) })
blast = mknew(bullet_base.new{ blast = mknew(bullet_base.new{
@ -788,17 +875,22 @@ blast = mknew(bullet_base.new{
damage = 4, damage = 4,
dx = 0, -- px/frame dx = 0, -- px/frame
dy = -2, dy = -1,
awaitcancel = false, awaitcancel = false,
-- disable damage for 2 frames -- disable damage for 4 frames
-- when hitting something -- when hitting something
-- todo: rewrite all ship hit
-- logic so i can avoid
-- repeating hits to the
-- same ship instead of
-- using a cooldown
hitship = function(self, _) hitship = function(self, _)
if self.damage > 0 and not self.awaitcancel then if self.damage > 0 and not self.awaitcancel then
self.awaitcancel = true self.awaitcancel = true
once_next_frame(function() once_next_frame(function()
new_events:push_back{ new_events:push_back{
wait = 2, wait = 4,
obj = self, obj = self,
saved_dmg = self.damage, saved_dmg = self.damage,
move = function(self) move = function(self)
@ -819,10 +911,22 @@ blast = mknew(bullet_base.new{
blast_gun = mknew(gun_base.new{ blast_gun = mknew(gun_base.new{
icon = 13, icon = 13,
cooldown = 0x0.0020, -- frames between shots cooldown = 0x0.0078, -- 120 frames between shots
ammo = 5, ammo = 5,
maxammo = 5, maxammo = 5,
actually_shoot = spawn_one(blast), munition = blast,
hdr = "bLASTER",
body= [[---------GUN
plasma orb
cuts through
enemies.
slow.
ammo: 5
rate: 1/2sec
dmg: 4
]],
}) })
protron_e = mknew(bullet_base.new{ protron_e = mknew(bullet_base.new{
@ -854,7 +958,7 @@ protron_p = mknew(protron_e.new{
protron_gun_e = mknew(gun_base.new{ protron_gun_e = mknew(gun_base.new{
icon = 25, icon = 25,
cooldown = 0x0.000f, -- frames between shots cooldown = 0x0.0040, -- frames between shots
ammo = nil, ammo = nil,
maxammo = nil, maxammo = nil,
munition = protron_e munition = protron_e
@ -883,6 +987,19 @@ end
protron_gun_p = mknew(protron_gun_e.new{ protron_gun_p = mknew(protron_gun_e.new{
munition = protron_p, munition = protron_p,
maxammo = 20,
cooldown = 0x0.0018,
hdr = "pROTRON",
body = [[---------GUN
spray shots
in a dense
arc.
ammo: 20
rate: 2/sec
dmg: 1
]],
}) })
vulcan_e = mknew(bullet_base.new{ vulcan_e = mknew(bullet_base.new{
@ -915,7 +1032,7 @@ vulcan_p = mknew(vulcan_e.new{
vulcan_gun_e = mknew(gun_base.new{ vulcan_gun_e = mknew(gun_base.new{
icon = 37, icon = 37,
enemy = false, enemy = false,
cooldown = 0x0.0002, -- frames between shots cooldown = 0x0.0003, -- frames between shots
ammo = nil, ammo = nil,
maxammo = nil, maxammo = nil,
munition=vulcan_e, munition=vulcan_e,
@ -934,6 +1051,17 @@ vulcan_gun_e = mknew(gun_base.new{
vulcan_gun_p = mknew(vulcan_gun_e.new{ vulcan_gun_p = mknew(vulcan_gun_e.new{
munition=vulcan_p, munition=vulcan_p,
maxammo = 100,
hdr = "vULCAN",
body = [[---------GUN
rapidly fire
in a v.
ammo: 100
rate: 20/sec
dmg: 0.5
]],
}) })
-->8 -->8
@ -943,6 +1071,7 @@ 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 = mknew(ship_m.new{
friendly=true,
--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?
@ -967,10 +1096,11 @@ player = mknew(ship_m.new{
xptarget = 0x0.0004, xptarget = 0x0.0004,
last_xp_frame = 0, last_xp_frame = 0,
level = 1, level = 1,
magnet = 10,
-- gun -- gun
main_gun = nil, -- assign at spawn time main_gun = nil, -- assign at spawn time
special_gun = nil, special_guns = nil,
fire_off_x = 4, -- offset where bullets come from fire_off_x = 4, -- offset where bullets come from
fire_off_y = 0, fire_off_y = 0,
@ -979,10 +1109,10 @@ player = mknew(ship_m.new{
y=96, y=96,
xmomentum = 0, xmomentum = 0,
ymomentum = 0, ymomentum = 0,
maxspd = 2.5, -- momentum cap maxspd = 1.5, -- momentum cap
thrust = 0.25, -- momentum added from button thrust = 0.1875, -- momentum added from button
ymin = 0, ymax = 120, -- stay on screen ymin = 0, ymax = 120, -- stay on screen
drag = 0.125, -- momentum lost per frame drag = 0.0625, -- momentum lost per frame
slip = false, -- does not slide down screen slip = false, -- does not slide down screen
act = function(self) -- fetch buttons act = function(self) -- fetch buttons
local b,th = btn(),self.thrust local b,th = btn(),self.thrust
@ -1009,6 +1139,110 @@ player = mknew(ship_m.new{
end, end,
}) })
function player:small_upgrade_opts()
local cdr, pr = (self.shieldcooldown - 0x0.000f) / 8, (self.shieldpenalty - 0x0.003c) / 9
if (cdr == 0 and self.shieldcooldown > 0x0.000f) cdr = 0x0.0001
if (pr == 0 and self.shieldpenalty > 0x0.003c) pr = 0x0.0001
local ret = {{
icon=53,
hdr="hull",
body=[[--------SHIP
survive more
unshielded
hits.
+2 hp]],
action=function()
self.maxhp += 2
self.hp += 2
end,
},{
icon=52,
hdr="capacity",
body=[[------SHIELD
shield can
absorb more
hits before
recharging.
+1 hp]],
action=function()
self.maxshield += 1
self.shield += 1
end,
},{
icon=1,
hdr="thrusters",
body=[[--------SHIP
move faster,
steer more
sharply.]],
action=function()
--maxspd thrust drag
self.maxspd += 0.5
self.thrust += 0.0625
self.drag += 0.03125
end,
},{
icon=20,
hdr="magnet",
body=[[--------SHIP
pick up xp
from further
away.]],
action=function ()
self.magnet += 2
end,
},
self.main_gun:rate_upgrade_opt(),
}
if cdr > 0 then
add(ret, {
icon = 6,
hdr = "recharge",
body=[[------SHIELD
shield will
recharge at
a faster
pace.
]] .. tostr(ceil(100 * cdr / self.shieldcooldown)) .. "% faster",
action = function()
self.shieldcooldown -= cdr
end
})
end
if pr > 0 then
add(ret, {
icon = 6,
hdr = "recovery",
body=[[------SHIELD
reduce the
delay after
a hit before
shield will
start to
recharge.
]] .. tostr(ceil(100 * pr / self.shieldpenalty)) .. "% shorter",
action = function()
self.shieldpenalty -= pr
end
})
end
return ret
end
frownie = mknew(ship_m.new{ frownie = mknew(ship_m.new{
--shape --shape
sprite = 3, --index of ship sprite sprite = 3, --index of ship sprite
@ -1113,6 +1347,7 @@ chasey = mknew(ship_m.new{
end end
}) })
-- todo: use constraints
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)
@ -1345,32 +1580,9 @@ function spawn_blocking_spewy()
end end
end end
function spawn_bonus_frownie() function spawn_vulcan_chasey()
local f = spawn_frownie()
f.sprite = 7
f.die = function(self)
spawn_repair_at(self.x+4, self.y+4)
frownie.die(self)
end
end
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_e.new{enemy=true}
c.die = function(self)
spawn_main_gun_at(self.x-1, self.y-1, vulcan_gun_p)
chasey.die(self)
end
c.sprite=4
return c
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 c.sprite=4
return c return c
end end
@ -1419,7 +1631,6 @@ function spawn_rnd(typ, blocking, goodie,altspr)
freeze -= self.ice freeze -= self.ice
self.ice=0 self.ice=0
typ.die(self) typ.die(self)
spawn_goodie(goodie, self.x, self.y, self.size)
end, end,
} }
if (altspr) s.spr = altspr if (altspr) s.spr = altspr
@ -1427,14 +1638,6 @@ function spawn_rnd(typ, blocking, goodie,altspr)
return s return s
end end
-- TODO: spawn_goodie compatible versions of gun drops
-- TODO: goodie table
function spawn_goodie(goodie_name, x, y, sz)
if (not goodie_name or #goodie_name == 0) return
local sh = sz and sz/2 or 0
_ENV[goodie_name].new{}:spawn_at(x+sh,y+sh)
end
function multi(times, interval, fnm, ...) function multi(times, interval, fnm, ...)
local f,irm,vargs = _ENV[fnm],interval,pack(...) local f,irm,vargs = _ENV[fnm],interval,pack(...)
assert(type(f) == "function", fnm.." not a function") assert(type(f) == "function", fnm.." not a function")
@ -1457,31 +1660,29 @@ end
-- where offset,eol is a special case. -- where offset,eol is a special case.
example_level_csv=[[1,spawn_frownie example_level_csv=[[1,spawn_frownie
60,spawn_bonus_vulcan_chasey 60,spawn_vulcan_chasey
61,spawn_blocky 61,spawn_blocky
85,spawn_spewy 85,spawn_spewy
100,spawn_spewy
115,spawn_spewy 115,spawn_spewy
130,spawn_bonus_frownie 130,spawn_frownie
145,spawn_spewy 145,spawn_frownie
200,spawn_bonus_shield_chasey 180,spawn_spewy
230,spawn_chasey
250,spawn_blocking_blocky 250,spawn_blocking_blocky
285,spawn_spec_gun_at,35,-11,blast_gun
310,spawn_blocking_blocky 310,spawn_blocking_blocky
310,spawn_blocking_blocky 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
401,spawn_frownie 401,spawn_frownie
420,spawn_blocking_frownie 420,spawn_blocking_frownie
430,spawn_bonus_vulcan_chasey 430,spawn_vulcan_chasey
450,spawn_frownie 450,spawn_frownie
465,spawn_bonus_frownie 465,spawn_frownie
480,spawn_chasey 480,spawn_chasey
500,multi,20,12,spawn_blocking_blocky 500,multi,20,12,spawn_blocking_blocky
501,spawn_bonus_frownie 501,spawn_frownie
620,spawn_blocking_blocky 620,spawn_blocking_blocky
630,spawn_bonus_shield_chasey 630,spawn_vulcan_chasey
720,spawn_blocking_boss_chasey 720,spawn_blocking_boss_chasey
721,eol]] 721,eol]]
@ -1517,10 +1718,10 @@ function init_blip_pals()
end end
end end
function blip(obj, col, frames) function blip(obj, col)
obj.fx_pal = blip_pals[col] obj.fx_pal = blip_pals[col]
if (obj.___fx_pal_event) obj.___fx_pal_event:abort() if (obj.___fx_pal_event) obj.___fx_pal_event:abort()
events:push_back(blip_fx.new{frames=frames, obj=obj}) events:push_back(blip_fx.new{frames=3, obj=obj})
end end
bossspark = split"7,7,10,10,9,9,9,8,8,8,2,2,5,5" bossspark = split"7,7,10,10,9,9,9,8,8,8,2,2,5,5"
@ -1603,11 +1804,22 @@ function xp_gem:draw()
) )
end end
function xp_gem:move()
if not primary_ship.dead and abs(self.x + 1 - primary_ship.x - primary_ship.hurt.x_off) <= primary_ship.magnet and abs(self.y + 1 - primary_ship.y - primary_ship.hurt.y_off) <= primary_ship.magnet then
if (self.x < primary_ship.x + 3) self.x += 1
if (self.x > primary_ship.x + 5) self.x -= 1
if (self.y < primary_ship.y + 3) self.y += 1
if (self.y > primary_ship.y + 5) self.y -= 1
end
return bullet_base.move(self)
end
-- todo: "magnetic" behavior -- todo: "magnetic" behavior
-- when near player ship -- when near player ship
function xp_gem:hitship(ship) function xp_gem:hitship(ship)
if (ship ~= primary_ship) return false if (ship ~= primary_ship or primary_ship.dead) return false
primary_ship.xp += self.val primary_ship.xp += self.val
primary_ship.last_xp_frame = lframe primary_ship.last_xp_frame = lframe
return true return true
@ -1624,137 +1836,68 @@ function spawn_xp_at(x, y, off, amt)
}:spawn_at(mid(x, 0, 124),mid(y,-4,125)) }:spawn_at(mid(x, 0, 124),mid(y,-4,125))
end end
powerup = mknew(bullet_base.new{ -->8
-- animated sprite array: "sprites" -- upgrade options
-- to draw under or over anim,
-- override draw, draw the
-- under-part, call into
-- powerup.draw(self), then
-- draw the over-part
width = 1,
height = 1,
-- note: make hurtboxes larger
-- than sprite by 2px per side
-- since ship hitbox is tiny
-- but powerups should feel
-- easy to pick up
dx = 0,
dy = 0.75,
category = enemy_blt_cat, -- collides with player ship
damage = 0,
anim_speed = 2,
loop_pause = 30 -- affected by animspeed
})
-- sprite indexes for "sheen" animation -- all these return
sheen8x8 = split"2,54,55,56,57,58,59,60,61" -- a [2] of rearm_t:
--
-- icon: sprite id
-- hdr: title text
-- body: text
-- action: callback
-- (method)
function powerup:draw() spec_gunt = {
spr(self.sprites[max(1, protron_gun_p,
((lframe<<16)\self.anim_speed) vulcan_gun_p,
%(#self.sprites+self.loop_pause) blast_gun,
-self.loop_pause
+1)],
self.x, self.y,
self.width, self.height)
end
repair = mknew(powerup.new{
hurt = {
x_off = -2,
y_off = -2,
width = 12,
height = 12
},
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(self.icon, self.x, self.y, self.width, self.height)
powerup.draw(self)
end
})
function spawn_repair_at(x, y)
repair.new():spawn_at(x, y)
end
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,
width = 16,
height = 16
},
-- gun = gun_type.new{}
x_off = 6,
y_off = 0,
width = 2,
height = 2,
sprites = {64, 66, 68, 70, 72, 74, 76, 78},
hitship = function(self, ship)
if (ship ~= primary_ship) return false
ship.main_gun = self.gun
return true
end,
draw = function(self)
powerup.draw(self)
spr(self.gun.icon, self.x+2, self.y+2, 1, 1)
end
})
function spawn_main_gun_at(x, y, gunt)
if (type(gunt)=="string") gunt=_ENV[gunt]
local gun_p = gun_swap.new{
gun = gunt.new()
}
gun_p:spawn_at(x, y)
end
spec_gun_pl = {
[1] = 2,
[14] = 6,
[2] = 14
} }
function spawn_spec_gun_at(x, y, gunt) -- picks n random items from
if (type(gunt)=="string") gunt=_ENV[gunt] -- tbl; permutes tbl, selected
local gun_p = gun_swap.new{ -- items at end
gun = gunt.new(), function pick(tbl, n)
hitship = function(self, ship) local ret, top={}, #tbl
if (ship ~= primary_ship) return false for x=top,top-n,-1 do
ship.special_gun = self.gun local idx = 1+rnd(x)\1
return true add(ret, tbl[idx])
end, tbl[idx]=tbl[x]
draw = function(self) tbl[x]=ret[#ret]
pal(spec_gun_pl) end
powerup.draw(self) return ret
pal() end
spr(self.gun.icon, self.x+2, self.y+2, 1, 1)
end -- add a new gun
} function spec_gun_opts()
gun_p:spawn_at(x, y) return pick(spec_gunt, 2)
end
-- major upgrades
function big_opts()
return {{
icon=1,
hdr="placeholder",
body="placeholder",
action = function() end,
},
{
icon=1,
hdr="placeholder",
body="placeholder",
action = function() end,
}}
end
-- ordinary upgrades
function small_opts()
-- todo: include gun opts
if(not primary_ship.special_guns) return pick(primary_ship:small_upgrade_opts(), 2)
local opts = {rnd(primary_ship:small_upgrade_opts())}
for g in all(primary_ship.special_guns) do
add(opts, rnd(g:small_upgrade_opts()))
end
return pick(opts, 2)
end end
-->8 -->8
@ -1763,7 +1906,7 @@ end
rearm_mode = mknew{ rearm_mode = mknew{
sel=1, sel=1,
bfm=1, bfm=1,
crt_frm = 1, crt_frm = 0,
pos=-1, pos=-1,
init=function(this) init=function(this)
poke(0x5f5c, 255) --no btnp repeat poke(0x5f5c, 255) --no btnp repeat
@ -1778,7 +1921,7 @@ function rearm_mode:glow_box(x0, y0, x1, y1, c, cf)
i -= 1 i -= 1
rect(x0+i,y0+i,x1-i,y1-i,v) rect(x0+i,y0+i,x1-i,y1-i,v)
end end
fillp(crt[self.crt_frm&0xff]) fillp(crt[1+(self.crt_frm&7)])
rectfill(x0+4, y0+4, x1-4, y1-4, cf) rectfill(x0+4, y0+4, x1-4, y1-4, cf)
fillp() fillp()
end end
@ -1810,8 +1953,8 @@ end
function rearm_mode:draw_option(id) function rearm_mode:draw_option(id)
local rec = self.options[id] local rec = self.options[id]
self:glow_box(0,0,55,100,self:frame_col(self.sel == id),1) self:glow_box(0,0,55,101,self:frame_col(self.sel == id),1)
spr(rec.s,5, 5) spr(rec.icon,5, 5)
print(rec.hdr, 13, 8, 7) print(rec.hdr, 13, 8, 7)
print(rec.body, 5, 15, 6) print(rec.body, 5, 15, 6)
end end
@ -1828,17 +1971,14 @@ function rearm_mode:shuffle()
-- these will be placeholders -- these will be placeholders
-- until the upgrade deck -- until the upgrade deck
-- is a thing that exists -- is a thing that exists
self.options = {{ local lev = primary_ship.level + 1
s=1, if lev == 4 or lev == 12 then
hdr=" hull", self.options = spec_gun_opts()
body = "\n +1\n max\n health", elseif lev % 4 == 0 then
action = function() end, self.options = big_opts()
},{ else
s=37, self.options = small_opts()
hdr=" vulc", end
body = "\nplaceholder",
action = function() end,
}}
end end
function rearm_mode:draw() function rearm_mode:draw()
@ -1849,9 +1989,9 @@ function rearm_mode:draw()
camera(frac * -128 + (1-frac) * -56, 0) camera(frac * -128 + (1-frac) * -56, 0)
self:draw_option(2) self:draw_option(2)
camera(0, -28 * frac) camera(0, -28 * frac)
self:glow_box(0,101,111,127,self:frame_col(self.sel < 0),1) self:glow_box(0,102,111,127,self:frame_col(self.sel < 0),1)
spr(96,15,107,4,2) spr(96,15,107,4,2)
print("full ammo\nfull shield\n+50% health",54, 106, 6) print("full ammo\nfull shield\n+50% health",54, 107, 6)
end end
function rearm_mode:update_pos() function rearm_mode:update_pos()
@ -1871,6 +2011,7 @@ function rearm_mode:update_pos()
end end
function rearm_mode:update() function rearm_mode:update()
self.crt_frm+=0.25
self:update_pos() self:update_pos()
if self.pos > 1 then if self.pos > 1 then
mode = game_mode mode = game_mode
@ -1894,7 +2035,11 @@ function rearm_mode:update()
-- todo: sound: rearm -- todo: sound: rearm
primary_ship.shield = primary_ship.maxshield primary_ship.shield = primary_ship.maxshield
-- todo: rewrite for three guns -- todo: rewrite for three guns
if (primary_ship.special_gun) primary_ship.special_gun.ammo = primary_ship.special_gun.max_ammo local specs = primary_ship.special_guns
if specs then
specs[1].ammo = specs[1].maxammo
if (specs[2]) specs[2].ammo = specs[2].maxammo
end
primary_ship.hp = min(primary_ship.maxhp, primary_ship.hp + primary_ship.maxhp/2) primary_ship.hp = min(primary_ship.maxhp, primary_ship.hp + primary_ship.maxhp/2)
primary_ship.xp -= primary_ship.xptarget / 2 primary_ship.xp -= primary_ship.xptarget / 2
else else
@ -1921,14 +2066,14 @@ __gfx__
0070070065666765000000000ddddd100b33355009444220c000000c03333350b7000000a800000008888820048488203bbaabb3288aa8820000000000000000 0070070065666765000000000ddddd100b33355009444220c000000c03333350b7000000a800000008888820048488203bbaabb3288aa8820000000000000000
000000006506506500000000001111000b0b5050090920200c0000c00055550037000000a2000000008882000048420003bbbb30028888200000000000000000 000000006506506500000000001111000b0b5050090920200c0000c00055550037000000a2000000008882000048420003bbbb30028888200000000000000000
00000000650000650000000000000000000b50000009200000c0cc00000000003b00000082000000000820000008200000333300002222000000000000000000 00000000650000650000000000000000000b50000009200000c0cc00000000003b00000082000000000820000008200000333300002222000000000000000000
00000000000650000006500000000000b000000b80000000700000000bb0000008800000000000000009200000000000cccccccd000650000000000000000000 0000000000065000000650000003b0000070070080000000700000000bb0000008800000000000000009200000000000cccccccd000650000000000000000000
0000000000675000000765000000000000bbbb0080000000b0000000b76300008a920000000000009009200200000000c111111d006765000000000000000000 000000000067500000076500000370000005500080000000b0000000b76300008a920000000000009009200200000000c111111d006765000000000000000000
00000000006d6500006d6500000000000b0000b09000000030000000b663000089920000000550009994444200000000c111111d006d65000000000000000000 00000000006d6500006d6500000b7000700660079000000030000000b663000089920000000550009994444200000000c111111d006d65000000000000000000
00000000067c6650067c6650000000000b0bb0b0a000000030000000033000000220000000576d009446544200000000c111111d067c66500000000000000000 00000000067c6650067c6650000b7000056ccd50a000000030000000033000000220000000576d009446544200000000c111111d067c66500000000000000000
00000000067d6650067d6650000000000b0bb0b00000000000000000000000000000000000566d009244442200000000c111111d067d66500000000000000000 00000000067d6650067d6650000b7000056ccd500000000000000000000000000000000000566d009244442200000000c111111d067d66500000000000000000
000000005666657576667650000000000b0000b000000000000000000000000000000000000dd0009092220200000000c111111d656667650000000000000000 000000005666657576667650000b7000700dd00700000000000000000000000000000000000dd0009092220200000000c111111d656667650000000000000000
0000000056565066665656500000000000bbbb0000000000000000000000000000000000000000000090020000000000c111111d650650650000000000000000 000000005656506666565650000370000005500000000000000000000000000000000000000000000090020000000000c111111d650650650000000000000000
00000000565000566500065000000000b000000b000000000000000000000000000000000000000000a00a0000000000cddddddd650000650000000000000000 0000000056500056650006500003b00000700700000000000000000000000000000000000000000000a00a0000000000cddddddd650000650000000000000000
060007000600070006600770766c777c0000000000a0008000000000000000000000000000000000000000000000000000000000000000000000000000000000 060007000600070006600770766c777c0000000000a0008000000000000000000000000000000000000000000000000000000000000000000000000000000000
6cd07cd06cd07cd06ccd7ccd6ccd7ccd000000000090008000000000000000000000000000000000000000000000000000000000000000000000000000000000 6cd07cd06cd07cd06ccd7ccd6ccd7ccd000000000090008000000000000000000000000000000000000000000000000000000000000000000000000000000000
0d000d006cd07cd06ccd7ccd6ccd7ccd0000000000800a0000000000000000000000000000000000000000000000000000000000000000000000000000000000 0d000d006cd07cd06ccd7ccd6ccd7ccd0000000000800a0000000000000000000000000000000000000000000000000000000000000000000000000000000000