23 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

View File

@ -126,8 +126,7 @@ end
function _init()
mode = game_mode
init_blip_pals()
wipe_level()
primary_ship.main_gun = zap_gun_p.new() -- redundant?
wipe_game() -- redundant?
load_level(example_level_csv)
game_state = game
pal(2,129)
@ -157,7 +156,7 @@ function init_hpcols()
hpcols = hpcols_lut[min(primary_ship.maxhp,6)]
end
function wipe_level()
function wipe_game()
xpwhoosh = nil
primary_ship = player.new()
init_hpcols()
@ -170,6 +169,8 @@ function wipe_level()
intangibles_bg = linked_list.new()
events = linked_list.new()
new_events = linked_list.new()
primary_ship.main_gun = zap_gun_p.new()
primary_ship.main_gun:peel()
end
function _update60()
@ -502,14 +503,14 @@ function ship_m:die()
-- overage XP, min 100
spawn_xp_at(cx, cy, 0, xp-0x0.018f)
xp = 0x0.018f -- dec 399
z += 1
z += 2
end
-- 100, 25, 5, 1
for gsz in all{0x0.0064, 0x0.0019, 0x0.0005, 0x0.0001} do
while xp >= gsz do
spawn_xp_at(cx, cy, z, gsz)
xp -= gsz
z += 1
z += 2
end
end
end
@ -611,30 +612,25 @@ end
function ship_m:hitsomething(dmg)
if (dmg <= 0) return false
self.shield_refresh_ready = lframe + self.shieldpenalty
if self.shield >= dmg then
if self.shield > 0 then
self.shield -= dmg
self:ow(true)
if self.shield > 0 then
blip(self,12)
else
self.shield = 0
blip(self,7)
end
return false
end
dmg -= self.shield
self.shield = 0
self.hp -= dmg
if self.hp < 0 then
self:die()
return true
end
self:ow(false)
blip(self, self.friendly and 8 or 7)
return false
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()
if (self.shield >= self.maxshield) return
if (lframe < self.shield_refresh_ready) return
@ -680,7 +676,13 @@ bullet_base = mknew{ }
gun_base = mknew{
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
@ -689,6 +691,7 @@ gun_base = mknew{
-- 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}
@ -697,6 +700,81 @@ function gun_base:action()
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(_)
self:die()
return true
@ -720,14 +798,6 @@ function bullet_base:draw()
spr(self.sprite, self.x, self.y, self.width, self.height)
end
-- An `actually_shoot` factory
-- for trivial guns
function spawn_one(t)
return function(gun, x, y)
t.new{}:spawn_at(x, y)
end
end
function bullet_base:spawn_at(x, y)
self.x = x - self.x_off
self.y = y - self.y_off
@ -780,11 +850,12 @@ zap_p = mknew(zap_e.new{
zap_gun_e = mknew(gun_base.new{
cooldown = 0x0.0020, -- frames between shots
actually_shoot = spawn_one(zap_e),
munition = zap_e,
})
zap_gun_p = mknew(zap_gun_e.new{
actually_shoot = spawn_one(zap_p),
icon = 19,
munition = zap_p,
hdr = "mAIN gUN",
})
@ -843,12 +914,14 @@ blast_gun = mknew(gun_base.new{
cooldown = 0x0.0078, -- 120 frames between shots
ammo = 5,
maxammo = 5,
actually_shoot = spawn_one(blast),
munition = blast,
hdr = "bLASTER",
body= [[plasma orb
body= [[---------GUN
plasma orb
cuts through
enemies.
slow.
enemies.
slow.
ammo: 5
rate: 1/2sec
@ -917,9 +990,11 @@ protron_gun_p = mknew(protron_gun_e.new{
maxammo = 20,
cooldown = 0x0.0018,
hdr = "pROTRON",
body = [[spray shots
in a dense
arc.
body = [[---------GUN
spray shots
in a dense
arc.
ammo: 20
rate: 2/sec
@ -978,9 +1053,10 @@ vulcan_gun_p = mknew(vulcan_gun_e.new{
munition=vulcan_p,
maxammo = 100,
hdr = "vULCAN",
body = [[rapid fire
in a v
shape.
body = [[---------GUN
rapidly fire
in a v.
ammo: 100
rate: 20/sec
@ -995,6 +1071,7 @@ firespark = split"9, 8, 2, 5, 1"
smokespark = split"13, 13, 5, 5"
player = mknew(ship_m.new{
friendly=true,
--shape
sprite = 1, --index of ship sprite
size = 1, --all ships are square; how many 8x8 sprites?
@ -1019,6 +1096,7 @@ player = mknew(ship_m.new{
xptarget = 0x0.0004,
last_xp_frame = 0,
level = 1,
magnet = 10,
-- gun
main_gun = nil, -- assign at spawn time
@ -1031,10 +1109,10 @@ player = mknew(ship_m.new{
y=96,
xmomentum = 0,
ymomentum = 0,
maxspd = 2.5, -- momentum cap
thrust = 0.25, -- momentum added from button
maxspd = 1.5, -- momentum cap
thrust = 0.1875, -- momentum added from button
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
act = function(self) -- fetch buttons
local b,th = btn(),self.thrust
@ -1061,6 +1139,110 @@ player = mknew(ship_m.new{
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{
--shape
sprite = 3, --index of ship sprite
@ -1536,10 +1718,10 @@ function init_blip_pals()
end
end
function blip(obj, col, frames)
function blip(obj, col)
obj.fx_pal = blip_pals[col]
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
bossspark = split"7,7,10,10,9,9,9,8,8,8,2,2,5,5"
@ -1622,11 +1804,22 @@ function xp_gem:draw()
)
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
-- when near player 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.last_xp_frame = lframe
return true
@ -1698,18 +1891,13 @@ end
-- ordinary upgrades
function small_opts()
return {{
icon=1,
hdr="placeholder",
body="placeholder",
action = function() end,
},
{
icon=1,
hdr="placeholder",
body="placeholder",
action = function() end,
}}
-- 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
-->8
@ -1718,7 +1906,7 @@ end
rearm_mode = mknew{
sel=1,
bfm=1,
crt_frm = 1,
crt_frm = 0,
pos=-1,
init=function(this)
poke(0x5f5c, 255) --no btnp repeat
@ -1733,7 +1921,7 @@ function rearm_mode:glow_box(x0, y0, x1, y1, c, cf)
i -= 1
rect(x0+i,y0+i,x1-i,y1-i,v)
end
fillp(crt[self.crt_frm&0xff])
fillp(crt[1+(self.crt_frm&7)])
rectfill(x0+4, y0+4, x1-4, y1-4, cf)
fillp()
end
@ -1765,7 +1953,7 @@ end
function rearm_mode:draw_option(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.icon,5, 5)
print(rec.hdr, 13, 8, 7)
print(rec.body, 5, 15, 6)
@ -1801,9 +1989,9 @@ function rearm_mode:draw()
camera(frac * -128 + (1-frac) * -56, 0)
self:draw_option(2)
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)
print("full ammo\nfull shield\n+50% health",54, 106, 6)
print("full ammo\nfull shield\n+50% health",54, 107, 6)
end
function rearm_mode:update_pos()
@ -1823,6 +2011,7 @@ function rearm_mode:update_pos()
end
function rearm_mode:update()
self.crt_frm+=0.25
self:update_pos()
if self.pos > 1 then
mode = game_mode
@ -1877,14 +2066,14 @@ __gfx__
0070070065666765000000000ddddd100b33355009444220c000000c03333350b7000000a800000008888820048488203bbaabb3288aa8820000000000000000
000000006506506500000000001111000b0b5050090920200c0000c00055550037000000a2000000008882000048420003bbbb30028888200000000000000000
00000000650000650000000000000000000b50000009200000c0cc00000000003b00000082000000000820000008200000333300002222000000000000000000
00000000000650000006500000000000b000000b80000000700000000bb0000008800000000000000009200000000000cccccccd000650000000000000000000
0000000000675000000765000000000000bbbb0080000000b0000000b76300008a920000000000009009200200000000c111111d006765000000000000000000
00000000006d6500006d6500000000000b0000b09000000030000000b663000089920000000550009994444200000000c111111d006d65000000000000000000
00000000067c6650067c6650000000000b0bb0b0a000000030000000033000000220000000576d009446544200000000c111111d067c66500000000000000000
00000000067d6650067d6650000000000b0bb0b00000000000000000000000000000000000566d009244442200000000c111111d067d66500000000000000000
000000005666657576667650000000000b0000b000000000000000000000000000000000000dd0009092220200000000c111111d656667650000000000000000
0000000056565066665656500000000000bbbb0000000000000000000000000000000000000000000090020000000000c111111d650650650000000000000000
00000000565000566500065000000000b000000b000000000000000000000000000000000000000000a00a0000000000cddddddd650000650000000000000000
0000000000065000000650000003b0000070070080000000700000000bb0000008800000000000000009200000000000cccccccd000650000000000000000000
000000000067500000076500000370000005500080000000b0000000b76300008a920000000000009009200200000000c111111d006765000000000000000000
00000000006d6500006d6500000b7000700660079000000030000000b663000089920000000550009994444200000000c111111d006d65000000000000000000
00000000067c6650067c6650000b7000056ccd50a000000030000000033000000220000000576d009446544200000000c111111d067c66500000000000000000
00000000067d6650067d6650000b7000056ccd500000000000000000000000000000000000566d009244442200000000c111111d067d66500000000000000000
000000005666657576667650000b7000700dd00700000000000000000000000000000000000dd0009092220200000000c111111d656667650000000000000000
000000005656506666565650000370000005500000000000000000000000000000000000000000000090020000000000c111111d650650650000000000000000
0000000056500056650006500003b00000700700000000000000000000000000000000000000000000a00a0000000000cddddddd650000650000000000000000
060007000600070006600770766c777c0000000000a0008000000000000000000000000000000000000000000000000000000000000000000000000000000000
6cd07cd06cd07cd06ccd7ccd6ccd7ccd000000000090008000000000000000000000000000000000000000000000000000000000000000000000000000000000
0d000d006cd07cd06ccd7ccd6ccd7ccd0000000000800a0000000000000000000000000000000000000000000000000000000000000000000000000000000000