32 Commits

Author SHA1 Message Date
3151db5430 fix precedence error 2025-05-31 22:27:03 -07:00
2964159858 fix offset, try but fail to fix variants 2025-05-31 22:19:35 -07:00
95d4b6eb37 what the hell was I thinking when I wrote this 2025-05-31 22:06:48 -07:00
96312e3adf fix offset bugs 2025-05-31 22:05:47 -07:00
bf9a45d87e fix gframe unit 2025-05-31 21:55:21 -07:00
36f7c6572f fix ship spawning 2025-05-31 21:54:02 -07:00
45b70d3aca did you know that 4 is not 1? mindboggling! 2025-05-31 21:43:51 -07:00
35980d801a forgot my increments! 2025-05-31 21:40:17 -07:00
734811bd62 math works better when you return your values 2025-05-31 21:33:06 -07:00
4fddbea82c use the right loader 2025-05-31 21:31:20 -07:00
f675e31967 oops, I accidentally 2025-05-31 21:30:30 -07:00
0bd1463416 replace demo level with infinite copies of flotilla 0 2025-05-31 21:29:54 -07:00
267f8a3667 actually add ships we keep 2025-05-31 21:02:26 -07:00
fa206c37c5 "redistribute"-type flotilla: update 2025-05-31 21:00:27 -07:00
928e7f7418 prototype flotilla loader 2025-05-31 20:39:07 -07:00
2439fda068 ship prototype tweaks 2025-05-31 20:38:59 -07:00
d13290f438 placeholder flotilla ships 2025-05-31 19:03:38 -07:00
e3a2810f0a Prototype a flotilla template. 2025-05-25 21:03:51 -07:00
3764063b20 abandon "offset" sprites, use "row tier" sprites 2025-05-25 20:49:27 -07:00
90f6df2922 flotilla notes and sprites 2025-05-25 19:11:44 -07:00
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

View File

@ -127,7 +127,6 @@ function _init()
mode = game_mode mode = game_mode
init_blip_pals() init_blip_pals()
wipe_game() -- redundant? wipe_game() -- redundant?
load_level(example_level_csv)
game_state = game game_state = game
pal(2,129) pal(2,129)
pal() pal()
@ -171,6 +170,10 @@ function wipe_game()
new_events = linked_list.new() new_events = linked_list.new()
primary_ship.main_gun = zap_gun_p.new() primary_ship.main_gun = zap_gun_p.new()
primary_ship.main_gun:peel() primary_ship.main_gun:peel()
gframe = 0
interlude = 0
waves_complete = 0
current_wave = nil
end end
function _update60() function _update60()
@ -185,12 +188,44 @@ function call_move(x)
return x:move() return x:move()
end end
function ones(n)
local ret = 0
while n != 0 do
if (n&0x0.0001) ret += 1
n >>= 1
end
return ret
end
function updategame() function updategame()
if (primary_ship.xp >= primary_ship.xptarget) and (lframe - primary_ship.last_xp_frame > 0x0.000f) and (not primary_ship.dead) then if (primary_ship.xp >= primary_ship.xptarget) and (gframe - primary_ship.last_xp_frame > 0x0.000f) and (not primary_ship.dead) then
mode = rearm_mode.new() mode = rearm_mode.new()
return _update60() return _update60()
end end
leveldone = level_frame() gframe += 0x0.0001
if current_wave then
if current_wave:update() then
-- end of stage
waves_complete += 1
current_wave = nil
if waves_complete < 32767 then
interlude = 59 -- plus one dead frame with load_level but no update
else
-- you maxed out the level
-- counter. what the fuck
-- is wrong with you?
-- go outside.
--
-- do not spawn more levels.
interlude = 32767
end
end
elseif interlude > 0 then
interlude -= 1
else
current_wave = flotilla.new()
current_wave:load(0, 0, min(ones(waves_complete)\2, 4))
end
events:vore(new_events) events:vore(new_events)
events:strip(call_move) events:strip(call_move)
for _, lst in ipairs{intangibles_bg, pships, eships, pbullets, ebullets} do for _, lst in ipairs{intangibles_bg, pships, eships, pbullets, ebullets} do
@ -254,7 +289,7 @@ function updategame()
intangibles_fg:strip(call_move) intangibles_fg:strip(call_move)
if leveldone and not eships.next and not ebullets.next and not events.next then if waves_complete == 32767 and not eships.next and not ebullets.next and not events.next then
game_state = win game_state = win
end end
if (not pships.next) game_state = lose if (not pships.next) game_state = lose
@ -466,6 +501,14 @@ end
-->8 -->8
--ship behavior --ship behavior
-- generic full sprite hurtbox
box8 = {
x_off = 0,
y_off = 1,
width = 8,
height = 8
}
scrollrate = 0.25 --in px/frame scrollrate = 0.25 --in px/frame
ship_m = mknew{ ship_m = mknew{
@ -611,7 +654,7 @@ 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 = gframe + self.shieldpenalty
if self.shield > 0 then if self.shield > 0 then
self.shield -= dmg self.shield -= dmg
if self.shield > 0 then if self.shield > 0 then
@ -633,10 +676,10 @@ end
function ship_m:refresh_shield() function ship_m:refresh_shield()
if (self.shield >= self.maxshield) return if (self.shield >= self.maxshield) return
if (lframe < self.shield_refresh_ready) return if (gframe < self.shield_refresh_ready) return
self.shield += 1 self.shield += 1
self.shield = min(self.shield, self.maxshield) self.shield = min(self.shield, self.maxshield)
self.shield_refresh_ready = lframe + self.shieldcooldown self.shield_refresh_ready = gframe + self.shieldcooldown
end end
-->8 -->8
@ -676,7 +719,13 @@ 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 -- gun_base subtypes are
@ -707,6 +756,68 @@ function gun_base:actually_shoot(x, y)
self.munition.new{}:spawn_at(x, y) self.munition.new{}:spawn_at(x, y)
end 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
@ -737,12 +848,12 @@ function bullet_base:spawn_at(x, y)
end end
function gun_base:shoot(x, y) function gun_base:shoot(x, y)
if (lframe < self.shoot_ready) return false if (gframe < self.shoot_ready) return false
if self.ammo then if self.ammo then
if (self.ammo <= 0) return false if (self.ammo <= 0) return false
self.ammo -= 1 self.ammo -= 1
end end
self.shoot_ready = lframe + self.cooldown self.shoot_ready = gframe + self.cooldown
self:actually_shoot(x, y) self:actually_shoot(x, y)
return true return true
end end
@ -848,7 +959,9 @@ blast_gun = mknew(gun_base.new{
maxammo = 5, maxammo = 5,
munition = blast, munition = blast,
hdr = "bLASTER", hdr = "bLASTER",
body= [[plasma orb body= [[---------GUN
plasma orb
cuts through cuts through
enemies. enemies.
slow. slow.
@ -920,7 +1033,9 @@ protron_gun_p = mknew(protron_gun_e.new{
maxammo = 20, maxammo = 20,
cooldown = 0x0.0018, cooldown = 0x0.0018,
hdr = "pROTRON", hdr = "pROTRON",
body = [[spray shots body = [[---------GUN
spray shots
in a dense in a dense
arc. arc.
@ -981,9 +1096,10 @@ vulcan_gun_p = mknew(vulcan_gun_e.new{
munition=vulcan_p, munition=vulcan_p,
maxammo = 100, maxammo = 100,
hdr = "vULCAN", hdr = "vULCAN",
body = [[rapid fire body = [[---------GUN
in a v
shape. rapidly fire
in a v.
ammo: 100 ammo: 100
rate: 20/sec rate: 20/sec
@ -1074,7 +1190,11 @@ function player:small_upgrade_opts()
local ret = {{ local ret = {{
icon=53, icon=53,
hdr="hull", hdr="hull",
body=[[ armor body=[[--------SHIP
survive more
unshielded
hits.
+2 hp]], +2 hp]],
action=function() action=function()
@ -1083,8 +1203,13 @@ function player:small_upgrade_opts()
end, end,
},{ },{
icon=52, icon=52,
hdr="shield", hdr="capacity",
body=[[ capacity body=[[------SHIELD
shield can
absorb more
hits before
recharging.
+1 hp]], +1 hp]],
action=function() action=function()
@ -1094,10 +1219,11 @@ function player:small_upgrade_opts()
},{ },{
icon=1, icon=1,
hdr="thrusters", hdr="thrusters",
body=[[performance body=[[--------SHIP
move faster, move faster,
steer faster]], steer more
sharply.]],
action=function() action=function()
--maxspd thrust drag --maxspd thrust drag
self.maxspd += 0.5 self.maxspd += 0.5
@ -1106,22 +1232,29 @@ steer faster]],
end, end,
},{ },{
icon=20, icon=20,
hdr="hull", hdr="magnet",
body=[[ magnet body=[[--------SHIP
pick up xp pick up xp
from further from further
away]], away.]],
action=function () action=function ()
self.magnet += 2 self.magnet += 2
end, end,
}} },
self.main_gun:rate_upgrade_opt(),
}
if cdr > 0 then if cdr > 0 then
add(ret, { add(ret, {
icon = 6, icon = 6,
hdr = "shield", hdr = "recharge",
body=[[charge rate body=[[------SHIELD
shield will
recharge at
a faster
pace.
]] .. tostr(ceil(100 * cdr / self.shieldcooldown)) .. "% faster", ]] .. tostr(ceil(100 * cdr / self.shieldcooldown)) .. "% faster",
action = function() action = function()
@ -1133,8 +1266,15 @@ from further
if pr > 0 then if pr > 0 then
add(ret, { add(ret, {
icon = 6, icon = 6,
hdr = "shield", hdr = "recovery",
body=[[disruption body=[[------SHIELD
reduce the
delay after
a hit before
shield will
start to
recharge.
]] .. tostr(ceil(100 * pr / self.shieldpenalty)) .. "% shorter", ]] .. tostr(ceil(100 * pr / self.shieldpenalty)) .. "% shorter",
action = function() action = function()
@ -1146,81 +1286,10 @@ from further
return ret return ret
end end
frownie = mknew(ship_m.new{ -- original prototype leftover;
--shape -- likely to be the basis of a
sprite = 3, --index of ship sprite -- standard raider type, so
size = 1, --all ships are square; how many 8x8 sprites? -- i am keeping it around
hurt = { -- hurtbox - where this ship can be hit
x_off = 0, -- upper left corner
y_off = 1, -- relative to ship ulc
width = 8,
height = 6
},
sparks = smokespark,
sparkodds = 8,
hp = 0.5, -- enemy ships need no max hp
xp = 0x0.0001,
-- position
x=60, -- x and y are for upper left corner
y=8,
xmomentum = 0,
ymomentum = 0,
maxspd = 2, -- momentum cap
thrust = 0.12, -- momentum added from button
drag = 0.07, -- momentum lost per frame
slip = true,
act = function(self)
local tstate,dx = (1 + flr(4*t() + 0.5)) % 6,0
if (tstate==1 or tstate==2) dx=-self.thrust
if (tstate>=4) dx=self.thrust
return dx,0,false,false
end,
})
blocky = mknew(frownie.new{
sprite = 10,
hp = 1.5,
xp = 0x0.0002,
hurt = {
x_off = 0,
y_off = 0,
width = 8,
height = 7
},
ow = function(self)
if self.hp < 1 then
self.sprite = 11
else
self.sprite = 10
end
ship_m.ow(self)
end
})
spewy = mknew(frownie.new{
sprite=26,
xp = 0x0.0003,
hurt = {
x_off=0,
y_off=1,
width=8,
height=5
},
hp=0.5,
fire_off_x=4,
fire_off_y=7,
act=function(self)
local dx,dy,shoot_spec=frownie.act(self)
return dx, dy, shoot_spec, self.y > 10
end,
init = function(ship)
ship.main_gun=ship.main_gun or protron_gun_e.new{}
end
})
chasey = mknew(ship_m.new{ chasey = mknew(ship_m.new{
sprite = 5, sprite = 5,
xp = 0x0.0004, xp = 0x0.0004,
@ -1250,7 +1319,6 @@ 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)
@ -1288,6 +1356,53 @@ xl_chasey=mknew(chasey.new{
end, end,
}) })
-- flotilla ships
ship_f = mknew(ship_m.new{
-- sprite required
size = 1,
hurt = box8,
-- no sparks
hp = 0.5,
xp = 0x0.0001,
maxspd = 3,
thrust = 0.1,
drag = 0.05,
slip = false,
act = function(self)
local wx,wy=self.want_x,self.want_y
self.xmin,self.xmax,self.ymin,self.ymax = wx,wx,wy,wy
return 0,0,false,false
end,
})
ship_mook = mknew(ship_f.new{
sprite=103
})
ship_defender = mknew(ship_f.new{
sprite=105,
hp = 2.5,
xp = 0x0.0003,
})
ship_turret = mknew(ship_f.new{
sprite=106,
xp = 0x0.0002,
})
ship_skirmisher = mknew(ship_f.new{
sprite=107,
xp = 0x0.0004,
spark = smokespark,
sparkodds = 4,
})
function rnd_spawn_loc()
local x,y = flr(rnd(304)), flr(rnd(32))
if (x<184) return x-40,-y-8
if (x<244) return -y-8,x-184
return 112+y, x-244
end
-->8 -->8
-- collisions -- collisions
@ -1352,242 +1467,163 @@ function collider:get_collisions(item)
end end
return found return found
end end
-->8 -->8
-- level and event system -- flotillas
-- a level is a map from -- a template for a wave, read
-- effective frame number to -- from the map. each ship can
-- a list of actions for that -- alternate between "attack"
-- frame. an action is a -- and "formation" modes, like
-- method name and its args. -- galaxian or galaga. ships
-- with different roles have
-- different rules for becoming
-- aggressive, but aggression
-- ramps up during the wave.
-- effective frame number stops -- flotilla placeholders are
-- when freeze count is nonzero -- defined by sprite flags.
-- see obsidian vault for
-- full docs.
-- a level is won when it hits flotilla = mknew{
-- the end-of-level sentinel use_var = 0x1111,
-- and there are no more opt_odds = split"0.5,0.5,0.5,0.5",
-- tracked enemies. init=function(this)
-- lost when there are no this.ship_bases={
-- player ships left. [0]=mknew(ship_mook.new{ship_t=0}),
[1]=mknew(ship_mook.new{ship_t=1, sprite=104}),
-- effective frame [4]=mknew(ship_defender.new{ship_t=4}),
distance = 0 [5]=mknew(ship_defender.new{ship_t=5, sprite=10}),
-- actual frame count since [8]=mknew(ship_turret.new{ship_t=8}),
-- start of level times 0x0.0001 [9]=mknew(ship_turret.new{ship_t=9, sprite=4}),
lframe = 0 [12]=mknew(ship_skirmisher.new{ship_t=12}),
[13]=mknew(ship_skirmisher.new{ship_t=13, sprite=26}),
-- do not advance distance when }
-- nonzero
freeze = 0
eol = {}
function load_level(levelfile)
distance = 0
lframe = 0
freeze = 0
leveldone = false
current_level = {}
local found_eol = false
if (type(levelfile)=="string") levelfile = csv(levelfile)
for row in all(levelfile) do
local x = current_level[row[1]]
if row[2] == "eol" then
found_eol = true
assert(x==nil, "events on eol frame")
current_level[row[1]] = eol
else
row.next = x
current_level[row[1]]=row
end
end
assert(found_eol)
end
function level_frame()
lframe += 0x0.0001
if (current_level == nil) return true
if freeze == 0 then
distance += 1
local cbs = current_level[distance]
if cbs ~= nil then
if cbs == eol then
current_level = nil
return true
else
while cbs do
assert(cbs[1] == distance)
local f = _ENV[cbs[2]]
assert(type(f) == "function", cbs[2].." at "..distance.." is not a function")
f(unpack(cbs, 3))
cbs=cbs.next
end
end
end
end
return false
end
-->8
-- example level
function spawn_blocking_rnd_x(typ)
freeze += 1
s = typ.new{
x = rnd(104),
y = -7,
ice = 1,
orig_die = typ.die,
die = function(self)
freeze -= self.ice
self.ice = 0
self:orig_die()
end, end,
} }
eships:push_back(s)
return s
end
function spawn_frownie() function flotilla:load(ulc_cx, ulc_cy, lvl)
return spawn_rnd(frownie) local rows,cy,uv,counts={},ulc_cy,self.use_var,{
end [0]=0,
[1]=0,
function spawn_blocking_frownie() [4]=0,
spawn_blocking_rnd_x(frownie) [5]=0,
end [8]=0,
[9]=0,
function spawn_blocky() [12]=0,
spawn_rnd(blocky) [13]=0,
end
function spawn_blocking_blocky()
spawn_rnd(blocky, 1)
end
function spawn_spewy()
return spawn_rnd(spewy)
end
function spawn_chasey()
return spawn_rnd(chasey)
end
function spawn_blocking_spewy()
freeze += 1
local s = spawn_spewy()
s.ice = 1
s.die = function(self)
freeze -= self.ice
self.ice = 0
frownie.die(self)
end
end
function spawn_vulcan_chasey()
local c = spawn_chasey()
c.main_gun=vulcan_gun_e.new{enemy=true}
c.sprite=4
return c
end
helpers = {
spawn_frownie,
spawn_frownie,
spawn_frownie,
spawn_blocky,
spawn_blocky,
spawn_chasey,
spawn_spewy,
} }
repeat
function spawn_blocking_boss_chasey() local row,cx,opt,f,mode= {},ulc_cx,{},0,0
local c = spawn_rnd(xl_chasey, 1) for i,v in ipairs(self.opt_odds) do
local nextspawn = lframe + 0x0.0080 opt[i*4-4]=rnd()<v
events:push_back{move=function()
if lframe >= nextspawn then
helpers[flr(rnd(#helpers))+1]()
nextspawn += 0x0.0040
end end
return c.dead repeat
end} f=fget(mget(cx, cy))
-- bits 0x03: control mark or ship?
return c mode = f&0x03
end if mode==2 then
-- bits 0x0c: ship class
function std_spawn(tnm, n, blocking, goodie,altspr) local ship_t = f&0x0c
local typ = _ENV[tnm] -- bit 0x20: optional?
assert(typ and typ.new, tostr(tnm).." not a class") if f&0x20 == 0 or opt[ship_t] then
for i=1,(n or 1) do -- bit 0x10: alternate ship?
spawn_rnd(typ, blocking, goodie,altspr) -- increment ship id if
-- alternate is requested
-- and we allow alternates
-- for this type of ship
ship_t+=(uv>>ship_t&0x1)&((f&0x10)>>4)
add(row, self.ship_bases[ship_t].new{col=cx-ulc_cx})
end end
end end
cx += 1
-- blocking: 1 or 0 until mode==1
function spawn_rnd(typ, blocking, goodie,altspr) -- mode 1: end of line control mark
blocking = blocking or 0 -- bits 0x18: what size flotilla is this row used for?
freeze += blocking if (f&0x18)>>3 <= lvl then
s = typ.new{ -- keep the row; count it
x = rnd(104), for s in all(row) do
y = -(typ.size * 8 - 1), counts[s.ship_t] += 1
ice=blocking, s.x,s.y=rnd_spawn_loc()
die=function(self)
freeze -= self.ice
self.ice=0
typ.die(self)
end,
}
if (altspr) s.spr = altspr
eships:push_back(s) eships:push_back(s)
return s end
add(rows, row)
end
cy += 1
-- control mark bit 0x04: end of flotilla
until f&0x04 > 0
self.rows=rows
self:statisfy(counts)
end end
function multi(times, interval, fnm, ...) function flotilla:statisfy(counts)
local f,irm,vargs = _ENV[fnm],interval,pack(...) -- TODO: now that we know how
assert(type(f) == "function", fnm.." not a function") -- many ships of each kind
f(...) -- exist, build ships to match
events:push_back{move=function() -- difficulty target
irm-=1 --
if irm <= 0 then -- no difficulty model is yet
irm=interval -- implemented, though, so
times-=1 -- just use base ships only
f(unpack(vargs)) -- for this prototype
return times <= 1
end
end}
end end
-- then convert sample_level to csv. function flotilla:update()
-- spawn_spec_gun_at and spawn_main_gun_at will need parsed forms. -- algorithm: redistribute
-- the boss also needs to be reachable, but one-off is fine. -- TODO: alternate flotilla movement algorithms
-- each row of level csv is offset,event,event-args...
-- where offset,eol is a special case.
example_level_csv=[[1,spawn_frownie -- find effective width and height
60,spawn_vulcan_chasey local min_col,max_col,live_rows=999,0,0
61,spawn_blocky for row in all(self.rows) do
85,spawn_spewy local row_alive=false
115,spawn_spewy for ship in all(row) do
130,spawn_frownie if not ship.dead then
145,spawn_frownie row_alive=true
180,spawn_spewy local col=ship.col
230,spawn_chasey if (col < min_col) min_col = col
250,spawn_blocking_blocky if (col > max_col) max_col = col
310,spawn_blocking_blocky end
310,spawn_blocking_blocky end -- scanned row
310,spawn_blocking_blocky if (row_alive) live_rows += 1
311,spawn_frownie end -- extent search
401,spawn_frownie
420,spawn_blocking_frownie if (live_rows == 0) return true -- done
430,spawn_vulcan_chasey
450,spawn_frownie -- distribute across box:
465,spawn_frownie -- x = [4, 100)
480,spawn_chasey -- y = [4, 60)
500,multi,20,12,spawn_blocking_blocky
501,spawn_frownie local x_interval,x_offset = 0,52
620,spawn_blocking_blocky if min_col < max_col then
630,spawn_vulcan_chasey x_interval=96/(max_col-min_col)
720,spawn_blocking_boss_chasey x_offset = 4-min_col*x_interval
721,eol]] end
local y_interval,y_offset=0,40
if live_rows > 1 then
y_interval=52/(live_rows-1)
y_offset=4-y_interval
end
-- now assign target locations
local real_row=0
for row in all(self.rows) do
local row_alive = false
for ship in all(row) do
if not ship.dead then
if not row_alive then
real_row += 1
row_alive = true
end
ship.want_x = ship.col * x_interval + x_offset
ship.want_y = real_row * y_interval + y_offset
end -- ship updated
end -- row updated
end -- table updated
return false -- some ships remain
end
-->8 -->8
-- standard events -- standard events
@ -1695,10 +1731,10 @@ function xp_gem:draw()
-- sprite map position: -- sprite map position:
-- sprite id to x and y, -- sprite id to x and y,
-- offset shifts specific low -- offset shifts specific low
-- bits of lframe up to the the -- bits of gframe up to the the
-- bit with value 4 as a cheap -- bit with value 4 as a cheap
-- way to pick an anim frame -- way to pick an anim frame
if (lframe&0x0.003 == 0) qx, qy = (lframe&0x0.0004)<<16, (lframe&0x0.0008)<<15 if (gframe&0x0.003 == 0) qx, qy = (gframe&0x0.0004)<<16, (gframe&0x0.0008)<<15
sspr( sspr(
(s%16<<3)+qx, (s%16<<3)+qx,
(s\16<<3)+qy, (s\16<<3)+qy,
@ -1724,7 +1760,7 @@ end
function xp_gem:hitship(ship) function xp_gem:hitship(ship)
if (ship ~= primary_ship or primary_ship.dead) 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 = gframe
return true return true
end end
@ -1795,7 +1831,12 @@ end
-- ordinary upgrades -- ordinary upgrades
function small_opts() function small_opts()
-- todo: include gun opts -- todo: include gun opts
return pick(primary_ship:small_upgrade_opts(), 2) 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
@ -1804,7 +1845,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
@ -1819,7 +1860,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
@ -1851,7 +1892,7 @@ 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.icon,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)
@ -1887,9 +1928,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()
@ -1909,6 +1950,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
@ -2003,21 +2045,21 @@ cddddddddddd0000cddddddddddd0000cddddddddddd0000cddddddddddd0000cddddddddddd0000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
04444400044444440000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 044444000444444400000000000000000000000000000000000000000000000000000000000000000000000000000000000bb000000aa0000009900000088000
447777700477777a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 447777700477777a0000000000000000000000000000000000000000000666000077700008888800000ab00006000060000bb000000aa0000009900000088000
477aaa7a0477aaaa0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 477aaa7a0477aaaa0000000000000000000000000000000000000000006ddd5007fff70008eeee20000ab00006c006d0000bb000000aa0000009900000088000
47a0047a047a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 47a0047a047a0000000000000000000000000000000000000000000006dd7d5007ffff4008eeee200aaabbb006ccccd0000bb000000aa0000009900000088000
47a0447a047a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 47a0447a047a0000000000000000000000000000000000000000000006d7dd5007ffff4008eeee200bbb333006ccccd0000bb000000aa0000009900000088000
47a4477a047a44400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 47a4477a047a4440000000000000000000000000000000000000000006ddd500004fff4008eeee20000b300006d00cd0000bb000000aa0000009900000088000
477777a00477777a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 477777a00477777a0000000000000000000000000000000000000000005550000004440002222200000b30000d0000d0000bb000000aa0000009900000088000
477770000422aaaa2222000200000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 477770000422aaaa22220002000002000000000000000000000000000000000000000000000000000000000000000000000bb000000aa0000009900000088000
47a77700022ee0002eeee002e00022e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 47a77700022ee0002eeee002e00022e00000000000000000000000000000000000000000000000000000000000000000000bb000000aa0000009900000088000
47a4777002ea2e002e002e02ee022ee0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 47a4777002ea2e002e002e02ee022ee00000000000000000000000000005600000474000028282000004b000060000000bbbbbb00aaaaaa00999999008888880
47a0477a22ea2e002e002e02e2e2e2e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 47a0477a22ea2e002e002e02e2e2e2e0000000000000000000000000005d0d0004f0f400080e0e00000a000000c000d00b0000b00a0000a00900009008000080
47a0047a2e2222e02e222e02e02e02e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 47a0047a2e2222e02e222e02e02e02e000000000000000000000000005d07050070f0f2002e0e02004a0b0b0060c0c000b0bb0b00a0aa0a00909909008088080
47a0047a2eeeeeea2eeee002e02e02e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 47a0047a2eeeeeea2eeee002e02e02e000000000000000000000000006070d1004f0f040080e0e000b0b035000c0c0d00b0bb0b00a0aa0a00909909008088080
0aa000aa2e7aa2ea2e00e002e02e02e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 0aa000aa2e7aa2ea2e00e002e02e02e000000000000000000000000000d0d100002f0f2002e0e0200000300006000c000b0000b00a0000a00900009008000080
000000002e0002e02e002e02e02e02e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 000000002e0002e02e002e02e02e02e0000000000000000000000000000510000002420002020200000b5000000000d00bbbbbb00aaaaaa00999999008888880
000000000e0000e00e000e00e00e00e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 000000000e0000e00e000e00e00e00e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
__label__ __label__
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007777777777777777 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007777777777777777
@ -2149,3 +2191,12 @@ __label__
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007666666666666665 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007666666666666665
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007555555555555555 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007555555555555555
__gff__
000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000212060a0e01091119000000000000002232363a3e050d151d
0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
__map__
00006b6b00006f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
7b6a00006a7b6e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
7778686878776c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
6767777767676c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
7877676777787d00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000