Kistaro Windrider
58da8e6dc3
the menu eases in, the menu eases out, the menu eases in and you shake it all about
2110 lines
62 KiB
Lua
2110 lines
62 KiB
Lua
pico-8 cartridge // http://www.pico-8.com
|
|
version 42
|
|
__lua__
|
|
-- vacuum gambit
|
|
-- by kistaro windrider
|
|
|
|
game = 1
|
|
win = 2
|
|
lose = 3
|
|
|
|
function usplit(str)
|
|
return unpack(split(str))
|
|
end
|
|
function csv(s)
|
|
local ret=split(s,"\n")
|
|
for i,v in ipairs(ret) do
|
|
ret[i] = type(v) == "string" and split(v) or {v}
|
|
end
|
|
return ret
|
|
end
|
|
function const_fxn(x)
|
|
return function()
|
|
return x
|
|
end
|
|
end
|
|
|
|
-- generate standard "overlay"
|
|
-- constructor for type tt.
|
|
-- if tt.init is defined, generated
|
|
-- new calls tt.init(ret) after
|
|
-- ret is definitely not nil,
|
|
-- before calling setmetatable.
|
|
-- use to initialize mutables.
|
|
--
|
|
-- if there was a previous new,
|
|
-- it is invoked on the new
|
|
-- object *after* more, because
|
|
-- this works better with the
|
|
-- `more` impls i use.
|
|
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)
|
|
if(oldnew) oldnew(ret)
|
|
setmetatable(ret, mt)
|
|
return ret
|
|
end
|
|
return tt
|
|
end
|
|
|
|
-- intrusive singly-linked list.
|
|
-- cannot be nested!
|
|
linked_list = mknew{
|
|
is_linked_list=true,
|
|
init = function(x)
|
|
x.next=nil
|
|
x.tail=x
|
|
end,
|
|
}
|
|
|
|
function linked_list:push_back(x)
|
|
self.tail.next = x
|
|
self.tail = x
|
|
end
|
|
|
|
function linked_list:push_front(x)
|
|
if (not self.next) self.tail = x
|
|
x.next = self.next
|
|
self.next = x
|
|
end
|
|
|
|
-- vore eats another linked list
|
|
-- by appending its contents.
|
|
-- the ingested linked is empty.
|
|
function linked_list:vore(x)
|
|
if (not x.next) return
|
|
self.tail.next = x.next
|
|
self.tail = x.tail
|
|
x.next = nil
|
|
x.tail = x
|
|
end
|
|
|
|
-- strip calls f(x) for each
|
|
-- node, removing each node for
|
|
-- which f(x) returns true. it
|
|
-- returns the new tail; nil
|
|
-- if the list is now empty.
|
|
function linked_list:strip(f)
|
|
local p, n = self, self.next
|
|
while n do
|
|
if f(n) then
|
|
p.next = n.next
|
|
else
|
|
p = n
|
|
end
|
|
n = n.next
|
|
end
|
|
self.tail = p
|
|
return p
|
|
end
|
|
|
|
-- optimized special case -
|
|
-- could be done with strip but
|
|
-- this avoids extra function
|
|
-- calls and comparisions since
|
|
-- draw isn't allowed to kill
|
|
-- the item
|
|
function linked_list:draw()
|
|
local n = self.next
|
|
while n do
|
|
n:draw()
|
|
n = n.next
|
|
end
|
|
end
|
|
|
|
|
|
function linked_list:pop_front()
|
|
local ret = self.next
|
|
if (not ret) return
|
|
self.next = ret.next
|
|
if (not ret.next) ret.tail = nil
|
|
return ret
|
|
end
|
|
|
|
function _init()
|
|
mode = game_mode
|
|
init_blip_pals()
|
|
wipe_level()
|
|
primary_ship.main_gun = zap_gun_p.new() -- redundant?
|
|
load_level(example_level_csv)
|
|
game_state = game
|
|
pal(2,129)
|
|
pal()
|
|
end
|
|
|
|
function once_next_frame(f)
|
|
new_events:push_back{
|
|
move = function()
|
|
f()
|
|
return true
|
|
end,
|
|
}
|
|
end
|
|
|
|
-- health gradients for 1..5 hp
|
|
-- exactly, then all "more".
|
|
hpcols_lut = csv[[36
|
|
34, 136
|
|
34, 130, 136
|
|
34, 34, 130, 136
|
|
34, 34, 130, 130, 136]]
|
|
|
|
-- call after any change to maxhp
|
|
-- configures health gradient
|
|
function init_hpcols()
|
|
hpcols = hpcols_lut[min(primary_ship.maxhp,6)]
|
|
end
|
|
|
|
function wipe_level()
|
|
xpwhoosh = nil
|
|
primary_ship = player.new()
|
|
init_hpcols()
|
|
pships = linked_list.new()
|
|
pships:push_back(primary_ship)
|
|
eships = linked_list.new()
|
|
pbullets = linked_list.new()
|
|
ebullets = linked_list.new()
|
|
intangibles_fg = linked_list.new()
|
|
intangibles_bg = linked_list.new()
|
|
events = linked_list.new()
|
|
new_events = linked_list.new()
|
|
end
|
|
|
|
function _update60()
|
|
mode:update()
|
|
end
|
|
|
|
function call_f(x)
|
|
return x:f()
|
|
end
|
|
|
|
function call_move(x)
|
|
return x:move()
|
|
end
|
|
|
|
function updategame()
|
|
if (primary_ship.xp >= primary_ship.xptarget) and (lframe - primary_ship.last_xp_frame > 0x0.000f) and (not primary_ship.dead) then
|
|
mode = rearm_mode.new()
|
|
return _update60()
|
|
end
|
|
leveldone = level_frame()
|
|
events:vore(new_events)
|
|
events:strip(call_move)
|
|
for _, lst in ipairs{intangibles_bg, pships, eships, pbullets, ebullets} do
|
|
lst:strip(call_move)
|
|
end
|
|
|
|
pships:strip(
|
|
function(ps)
|
|
local pbox, pded = hurtbox(ps), false
|
|
eships:strip(
|
|
function(es)
|
|
if (not collides(pbox, hurtbox(es))) return
|
|
pded = pded or ps:hitship(es)
|
|
return es:hitship(ps)
|
|
end
|
|
)
|
|
return pded
|
|
end
|
|
)
|
|
pships:strip(
|
|
function(ps)
|
|
local pbox, pded = hurtbox(ps), false
|
|
ebullets:strip(
|
|
function(eb)
|
|
if (not collides(pbox, hurtbox(eb))) return
|
|
pded = pded or ps:hitbullet(eb)
|
|
return eb:hitship(ps)
|
|
end
|
|
)
|
|
return pded
|
|
end
|
|
)
|
|
|
|
-- many bullets and many enemy ships;
|
|
-- use bucket collider for efficiency
|
|
local pbullet_collider = collider.new()
|
|
local p, n = pbullets, pbullets.next
|
|
while n do
|
|
n.prev = p
|
|
pbullet_collider:insert(n)
|
|
p = n
|
|
n = p.next
|
|
end
|
|
|
|
eships:strip(
|
|
function(es)
|
|
for pb in all(pbullet_collider:get_collisions(es)) do
|
|
if pb:hitship(es) then
|
|
pbullet_collider:hide(pb)
|
|
pb.prev.next = pb.next
|
|
if pb.next then
|
|
pb.next.prev = pb.prev
|
|
else
|
|
pbullets.tail = pb.prev
|
|
end
|
|
end
|
|
if (es:hitbullet(pb)) return true
|
|
end
|
|
end
|
|
)
|
|
|
|
intangibles_fg:strip(call_move)
|
|
|
|
if leveldone and not eships.next and not ebullets.next and not events.next then
|
|
game_state = win
|
|
end
|
|
if (not pships.next) game_state = lose
|
|
|
|
if primary_ship.xp >= primary_ship.xptarget then
|
|
if not xpwhoosh then
|
|
xpwhoosh = 0
|
|
else
|
|
xpwhoosh += 1
|
|
if (xpwhoosh > 60) xpwhoosh = 0
|
|
end
|
|
else
|
|
xpwhoosh = nil
|
|
end
|
|
end
|
|
|
|
function _draw()
|
|
mode:draw()
|
|
end
|
|
|
|
function drawgame_top()
|
|
camera()
|
|
fillp(0)
|
|
drawgame()
|
|
if (game_state == game) fadelvl = -45
|
|
if (game_state == win) dropshadow("win",50,61,11)
|
|
if (game_state == lose) dropshadow("fail",48,61,8)
|
|
fadescreen()
|
|
end
|
|
|
|
game_mode = {
|
|
update = updategame,
|
|
draw = drawgame_top,
|
|
}
|
|
|
|
fadetable = split"0,1.5,1025.5,1029.5,1285.5,1413.5,9605.5,9637.5,-23130.5,-23066.5,-18970.5,-18954.5,-2570.5,-2568.5,-520.5,-8.5,-0.5"
|
|
|
|
function fadescreen()
|
|
fadelvl += 0.25
|
|
if (fadelvl < 1) return
|
|
local i = min(flr(fadelvl), #fadetable)
|
|
fillp(fadetable[#fadetable+1-i])
|
|
rectfill(0,0,128,128,0)
|
|
end
|
|
|
|
-- puke emits a verbose string
|
|
-- describing item, indented to
|
|
-- the specified depth (0 by
|
|
-- default). used for table
|
|
-- debugging. table-type keys
|
|
-- are not legible here
|
|
function puke(item, indent, seen, hidekey)
|
|
if (type(item) ~= "table") return tostr(item)
|
|
|
|
seen = seen or {}
|
|
if (seen[item]) return "<<...>>"
|
|
seen[item] = true
|
|
|
|
indent = indent or 0
|
|
local pfx = "\n"
|
|
for _=1,indent do
|
|
pfx ..= " "
|
|
end
|
|
local xpfx = pfx.." "
|
|
|
|
if item.is_linked_list then
|
|
local ret,n = "linked_list <",0
|
|
item:strip(function(x)
|
|
n += 1
|
|
ret ..= xpfx..tostr(n)..": "..puke(x, indent+2, seen, "next")
|
|
end)
|
|
return ret..pfx..">"
|
|
end
|
|
|
|
local ret = "{"
|
|
for k, v in pairs(item) do
|
|
if (k ~= hidekey) ret ..= xpfx..tostr(k)..": "..puke(v, indent+2, seen)
|
|
end
|
|
return ret..pfx.."}"
|
|
end
|
|
|
|
-- convenience for debugging
|
|
function puketh(item, ...)
|
|
printh(puke(item), ...)
|
|
end
|
|
|
|
function pukeboard(item)
|
|
puketh(item, "@clip")
|
|
end
|
|
|
|
function drawgame()
|
|
clip(0,0,112,128)
|
|
rectfill(0,0,112,128,0)
|
|
for slist in all{intangibles_bg, pbullets, pships, eships, ebullets, intangibles_fg} do
|
|
slist:draw()
|
|
end
|
|
clip(0,0,128,128)
|
|
drawhud()
|
|
end
|
|
|
|
powcols=split"170,154,153,148,68"
|
|
shlcols = split"204,220,221"
|
|
function drawhud()
|
|
-- 112-and-right is hud zone
|
|
rectfill(112, 0, 127, 127,0x56)
|
|
rect(112,0,127,127,7)
|
|
line(127,1,127,127,5)
|
|
line(113,127)
|
|
|
|
draw_gun_info("❎",1,116,3,primary_ship.main_gun)
|
|
draw_gun_info("🅾️",1,116,29,primary_ship.special_gun)
|
|
|
|
inset(114,57,119,118)
|
|
rectfill(119,57,124,58,13)
|
|
inset(120,64,125,125)
|
|
rectfill(114,124,120,125,7)
|
|
print("XP",119,55,1)
|
|
print("HP",114,122,1)
|
|
fillp(0x5a5a)
|
|
if xpwhoosh then
|
|
clip(115,58,4,60)
|
|
rectfill(115,58,118,117,0xaa)
|
|
local voff = 5*xpwhoosh+6
|
|
rectfill(115,118-voff,118,117-voff+10,0xbb)
|
|
rectfill(115,118-voff+11,118,117-voff+20,0xba)
|
|
clip()
|
|
else
|
|
vertmeter(115,58,118,117,primary_ship.xp, primary_ship.xptarget, powcols)
|
|
end
|
|
-- 60 px vertically. note that
|
|
-- there was at one point an
|
|
-- off-by-one and I'm not sure
|
|
-- it's actually fixed
|
|
local mxs, cs, mxh, ch = primary_ship.maxshield, primary_ship.shield, primary_ship.maxhp, primary_ship.hp
|
|
if (mxs > 0) and (mxh > 0) then
|
|
local split = 59 * (mxs / (mxs + mxh)) \ 1 + 64
|
|
line(121, split, 124, split, 0xba)
|
|
vertmeter(121,65,124,split-1,cs, mxs,shlcols)
|
|
vertmeter(121,split+1,124,124,ch, mxh, hpcols)
|
|
elseif mxs > 0 then
|
|
vertmeter(121,65,124,124,cs,mxs,shlcols)
|
|
elseif mxh > 0 then
|
|
vertmeter(121,65,124,124,ch,mxh,hpcols)
|
|
else
|
|
print("!", 122, 93, 9)
|
|
print("!", 121, 92, 8)
|
|
end
|
|
fillp(0)
|
|
end
|
|
|
|
function draw_gun_info(lbl,fgc,x,y,gun)
|
|
dropshadow(lbl,x,y,fgc)
|
|
inset(114,y+7,125,y+18)
|
|
inset(114,y+20,125,y+24)
|
|
if(gun) then
|
|
spr(gun.icon,116,y+9,1,1)
|
|
--115 to 124 - ammo bar. round up
|
|
if gun.ammo == nil then
|
|
fillp(0xa5a5)
|
|
rectfill(115,y+21,124,y+23,0xea)
|
|
fillp(0)
|
|
elseif gun.ammo > 0 then
|
|
rectfill(
|
|
115,y+21,
|
|
115+flr(9*gun.ammo/gun.maxammo),
|
|
y+23,10)
|
|
else
|
|
line(118, y+22, 121, y+22, 2)
|
|
end
|
|
end
|
|
end
|
|
|
|
function vertmeter(x0,y0,x1,y1,val,maxval,cols)
|
|
if ((val <= 0) or (maxval <= 0)) return
|
|
if val < 0x0.001 or maxval < 0x0.001 then
|
|
val *= 16
|
|
maxval *= 16
|
|
end
|
|
val=min(val, maxval)
|
|
local h = y1-y0
|
|
local px = val*h/maxval \ 1
|
|
local ncols = #cols
|
|
local firstcol = ((h-px)*ncols\h)+1
|
|
local lastbottom = y0+(h*firstcol\ncols)
|
|
rectfill(x0, y1-px, x1, lastbottom, cols[firstcol])
|
|
for i=firstcol+1,ncols do
|
|
local bottom = y0+h*i\ncols
|
|
rectfill(x0,lastbottom,x1,bottom,cols[i])
|
|
lastbottom = bottom
|
|
end
|
|
end
|
|
|
|
function inset(x0,y0,x1,y1)
|
|
rectfill(x0,y0,x1,y1,0)
|
|
-- use "wide colors" to draw
|
|
-- monochrome regardless of
|
|
-- fillp
|
|
rect(x0,y0,x1,y1,119)
|
|
line(x1,y0,x0,y0,85)
|
|
line(x0,y1-1,85)
|
|
end
|
|
|
|
function dropshadow(str, x, y, col)
|
|
print(str, x+1, y+1, 5)
|
|
print(str, x, y, col)
|
|
end
|
|
|
|
-->8
|
|
--ship behavior
|
|
|
|
scrollrate = 0.25 --in px/frame
|
|
|
|
ship_m = mknew{
|
|
|
|
-- ships have no shield by default
|
|
shield = 0,
|
|
maxshield = 0,
|
|
shieldcooldown = 0x0.003c,--1s
|
|
shieldpenalty = 0x0.012c, --5s
|
|
shield_refresh_ready = 0,
|
|
|
|
slip = true, -- most enemies slide
|
|
|
|
xmomentum = 0,
|
|
ymomentum = 0,
|
|
|
|
-- xmin, xmax, ymin, ymax:
|
|
-- movement constraints
|
|
-- enforced by `constrain`.
|
|
xmin = 0, xmax = 104,
|
|
-- ymin, ymax default to nil
|
|
-- pship needs more constraint
|
|
}
|
|
|
|
function ship_m:die()
|
|
self.dead = true
|
|
if (self.hp >= 0) return
|
|
|
|
-- blow up and drop xp
|
|
local sz4 = self.size * 4
|
|
local cx, cy, xp, z = self.x + sz4, self.y + sz4, self.xp or 0, 0
|
|
boom(cx, cy, 3*sz4, self.boss)
|
|
if xp > 0x0.01f3 then -- dec 499
|
|
-- spawn a huge gem with all
|
|
-- overage XP, min 100
|
|
spawn_xp_at(cx, cy, 0, xp-0x0.018f)
|
|
xp = 0x0.018f -- dec 399
|
|
z += 1
|
|
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
|
|
end
|
|
end
|
|
end
|
|
|
|
function ship_m:calc_velocity(v0, t)
|
|
v0 = mid(v0 + t, self.maxspd, -self.maxspd)
|
|
return v0 - mid(self.drag, -self.drag, v0)
|
|
end
|
|
|
|
function ship_m:brake_dist(v0)
|
|
local brake_max = self.thrust + self.drag
|
|
local tri_frames = abs(v0\brake_max)
|
|
local chunks = tri_frames * (tri_frames - 1) >> 1
|
|
local chunk_zone = chunks * brake_max
|
|
local overage = abs(v0) - tri_frames * brake_max
|
|
return (chunk_zone + overage * (tri_frames + 1)) * sgn(v0), (overage > 0) and tri_frames + 1 or tri_frames
|
|
end
|
|
|
|
function ship_m:constrain(p, dp, pmin, pmax, want)
|
|
if (not pmin) return want
|
|
local v1, bd, bf, bp
|
|
function calc_targets()
|
|
-- velocity after move
|
|
v1 = self:calc_velocity(dp, want)
|
|
-- brake distance and frames
|
|
bd, bf = self:brake_dist(v1)
|
|
-- brake point
|
|
bp = p + bd + v1
|
|
end
|
|
calc_targets()
|
|
if bp < pmin then
|
|
-- undershoot. max thrust,
|
|
-- then treat as overshoot
|
|
-- targeting minimum bound
|
|
want, pmax = self.thrust, pmin
|
|
calc_targets()
|
|
end
|
|
if (bp <= pmax) return want
|
|
-- spread overshoot across frames
|
|
want -= (bp - pmax)/max(bf,1)
|
|
return max(want, -self.thrust)
|
|
end
|
|
|
|
function ship_m:move()
|
|
self:refresh_shield()
|
|
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)
|
|
if (shoot_main) self:maybe_shoot(self.main_gun)
|
|
if (shoot_spec) self:maybe_shoot(self.special_gun)
|
|
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.ymomentum = self:calc_velocity(self.ymomentum, dy)
|
|
|
|
self.x += self.xmomentum
|
|
self.y += self.ymomentum
|
|
|
|
-- "scrolling" behavior
|
|
if self.slip then
|
|
self.y += scrollrate
|
|
if self.y >= 128 then
|
|
self:die()
|
|
return true
|
|
end
|
|
end
|
|
return false
|
|
end
|
|
|
|
function ship_m:draw()
|
|
if(self.fx_pal) pal(self.fx_pal)
|
|
spr(self.sprite, self.x, self.y, self.size, self.size)
|
|
pal()
|
|
end
|
|
|
|
function hurtbox(ship)
|
|
local h = ship.hurt
|
|
return {
|
|
x=ship.x + h.x_off,
|
|
y=ship.y + h.y_off,
|
|
width=h.width,
|
|
height=h.height
|
|
}
|
|
end
|
|
|
|
function ship_m:maybe_shoot(gun)
|
|
if (not gun) return
|
|
return gun:shoot(self.x + self.fire_off_x, self.y + self.fire_off_y)
|
|
end
|
|
|
|
function ship_m:hitship(other)
|
|
return self:hitsomething(1)
|
|
end
|
|
|
|
function ship_m:hitbullet(b)
|
|
return self:hitsomething(b.damage)
|
|
end
|
|
|
|
function ship_m:hitsomething(dmg)
|
|
if (dmg <= 0) return false
|
|
self.shield_refresh_ready = lframe + self.shieldpenalty
|
|
if self.shield >= dmg then
|
|
self.shield -= dmg
|
|
self:ow(true)
|
|
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)
|
|
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
|
|
self.shield += 1
|
|
self.shield = min(self.shield, self.maxshield)
|
|
self.shield_refresh_ready = lframe + self.shieldcooldown
|
|
end
|
|
|
|
-->8
|
|
-- bullet and gun behaviors
|
|
|
|
function player_blt_cat()
|
|
return pbullets
|
|
end
|
|
|
|
function enemy_blt_cat()
|
|
return ebullets
|
|
end
|
|
|
|
-- 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 = mknew{
|
|
shoot_ready = -32768,
|
|
icon = 20
|
|
}
|
|
|
|
function bullet_base:hitship(_)
|
|
self:die()
|
|
return true
|
|
end
|
|
|
|
function bullet_base:die()
|
|
end
|
|
|
|
function bullet_base:move()
|
|
self.x += self.dx
|
|
self.y += self.dy
|
|
if (self.f) self.f -= 1
|
|
if (self.y > 145) or (self.y < -8 * self.height) or (self.f and self.f < 0) then
|
|
self:die()
|
|
return true
|
|
end
|
|
return false
|
|
end
|
|
|
|
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
|
|
self.category():push_back(self)
|
|
end
|
|
|
|
function gun_base:shoot(x, y)
|
|
if (lframe < self.shoot_ready) return false
|
|
if self.ammo then
|
|
if (self.ammo <= 0) return false
|
|
self.ammo -= 1
|
|
end
|
|
self.shoot_ready = lframe + self.cooldown
|
|
self:actually_shoot(x, y)
|
|
return true
|
|
end
|
|
|
|
-->8
|
|
-- bullets and guns
|
|
|
|
zap_e = mknew(bullet_base.new{
|
|
--shape
|
|
sprite = 9, --index of ammo sprite
|
|
width = 1, --in 8x8 blocks
|
|
height = 1,
|
|
hurt = { -- hurtbox - where this ship can be hit
|
|
x_off = 0, -- upper left corner
|
|
y_off = 0, -- relative to sprite
|
|
width = 2,
|
|
height = 8
|
|
},
|
|
x_off = 1, -- how to position by ship
|
|
y_off = 8,
|
|
|
|
damage = 1,
|
|
dx = 0, -- px/frame
|
|
dy = 4,
|
|
|
|
hitship = const_fxn(true),
|
|
|
|
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{
|
|
cooldown = 0x0.000a, -- frames between shots
|
|
ammo = nil, -- unlimited ammo - main gun
|
|
actually_shoot = spawn_one(zap_e),
|
|
})
|
|
|
|
zap_gun_p = mknew(zap_gun_e.new{
|
|
actually_shoot = spawn_one(zap_p),
|
|
})
|
|
|
|
blast = mknew(bullet_base.new{
|
|
--shape
|
|
sprite = 12, --index of player ammo sprite
|
|
width = 1, --in 8x8 blocks
|
|
height = 1,
|
|
hurt = { -- hurtbox - where this ship can be hit
|
|
x_off = 1, -- upper left corner
|
|
y_off = 1, -- relative to sprite
|
|
width = 6,
|
|
height = 6
|
|
},
|
|
x_off = 4, -- how to position by ship
|
|
y_off = 0,
|
|
|
|
damage = 4,
|
|
dx = 0, -- px/frame
|
|
dy = -2,
|
|
awaitcancel = false,
|
|
|
|
-- disable damage for 2 frames
|
|
-- when hitting something
|
|
hitship = function(self, _)
|
|
if self.damage > 0 and not self.awaitcancel then
|
|
self.awaitcancel = true
|
|
once_next_frame(function()
|
|
new_events:push_back{
|
|
wait = 2,
|
|
obj = self,
|
|
saved_dmg = self.damage,
|
|
move = function(self)
|
|
self.wait -= 1
|
|
if self.wait <= 0 then
|
|
self.obj.damage = self.saved_dmg
|
|
return true
|
|
end
|
|
end,
|
|
}
|
|
self.damage = 0
|
|
self.awaitcancel = false
|
|
end)
|
|
end
|
|
end,
|
|
category=player_blt_cat
|
|
})
|
|
|
|
blast_gun = mknew(gun_base.new{
|
|
icon = 13,
|
|
cooldown = 0x0.0020, -- frames between shots
|
|
ammo = 5,
|
|
maxammo = 5,
|
|
actually_shoot = spawn_one(blast),
|
|
})
|
|
|
|
protron_e = mknew(bullet_base.new{
|
|
--shape
|
|
sprite = 24,
|
|
width = 1, --in 8x8 blocks
|
|
height = 1,
|
|
hurt = { -- hurtbox - where this ship can be hit
|
|
x_off = 1, -- upper left corner
|
|
y_off = 1, -- relative to sprite
|
|
width = 2,
|
|
height = 2
|
|
},
|
|
x_off = 1, -- how to position by ship
|
|
y_off = 4,
|
|
|
|
damage = 1,
|
|
dym = 0.5, -- gun sets dy;
|
|
-- this is mult
|
|
category = enemy_blt_cat,
|
|
})
|
|
|
|
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,
|
|
cooldown = 0x0.000f, -- frames between shots
|
|
ammo = nil,
|
|
maxammo = nil,
|
|
munition = protron_e
|
|
})
|
|
|
|
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
|
|
sprite = 21,
|
|
width = 1, --in 8x8 blocks
|
|
height = 1,
|
|
hurt = { -- hurtbox - where this ship can be hit
|
|
x_off = 0, -- upper left corner
|
|
y_off = 0, -- relative to sprite
|
|
width = 1,
|
|
height = 4
|
|
},
|
|
x_off = 0.5, -- how to position by ship
|
|
y_off = 0,
|
|
|
|
damage = 0.5,
|
|
-- dx from gun
|
|
dy = 2,
|
|
category=enemy_blt_cat
|
|
})
|
|
|
|
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,
|
|
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 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
|
|
})
|
|
|
|
vulcan_gun_p = mknew(vulcan_gun_e.new{
|
|
munition=vulcan_p,
|
|
})
|
|
|
|
-->8
|
|
--ships, including player
|
|
|
|
firespark = split"9, 8, 2, 5, 1"
|
|
smokespark = split"13, 13, 5, 5"
|
|
|
|
player = mknew(ship_m.new{
|
|
--shape
|
|
sprite = 1, --index of ship sprite
|
|
size = 1, --all ships are square; how many 8x8 sprites?
|
|
hurt = { -- hurtbox - where this ship can be hit
|
|
x_off = 3, -- upper left corner
|
|
y_off = 2, -- relative to ship ulc
|
|
width = 1,
|
|
height = 3
|
|
},
|
|
sparks = firespark, -- see tab 9
|
|
sparkodds = 2,
|
|
boss = true, -- dramatic special effects
|
|
|
|
-- health
|
|
hp = 3, -- current health, non-regenerating
|
|
maxhp = 3, -- player only; other ships never heal
|
|
shield = 2, -- regenerates
|
|
maxshield = 2,
|
|
|
|
-- xp in increments of 0x0.0001
|
|
xp = 0,
|
|
xptarget = 0x0.0004,
|
|
last_xp_frame = 0,
|
|
level = 1,
|
|
|
|
-- gun
|
|
main_gun = nil, -- assign at spawn time
|
|
special_gun = nil,
|
|
fire_off_x = 4, -- offset where bullets come from
|
|
fire_off_y = 0,
|
|
|
|
-- position
|
|
x=52, -- x and y are for upper left corner
|
|
y=96,
|
|
xmomentum = 0,
|
|
ymomentum = 0,
|
|
maxspd = 2.5, -- momentum cap
|
|
thrust = 0.25, -- momentum added from button
|
|
ymin = 0, ymax = 120, -- stay on screen
|
|
drag = 0.125, -- momentum lost per frame
|
|
slip = false, -- does not slide down screen
|
|
act = function(self) -- fetch buttons
|
|
local b,th = btn(),self.thrust
|
|
local blr = b&0x3
|
|
if blr == 1 then
|
|
self.sprite=17
|
|
elseif blr==2 then
|
|
self.sprite=18
|
|
else
|
|
self.sprite=1
|
|
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,
|
|
|
|
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,
|
|
})
|
|
|
|
frownie = mknew(ship_m.new{
|
|
--shape
|
|
sprite = 3, --index of ship sprite
|
|
size = 1, --all ships are square; how many 8x8 sprites?
|
|
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{
|
|
sprite = 5,
|
|
xp = 0x0.0004,
|
|
size = 1,
|
|
hurt = {
|
|
x_off = 1,
|
|
y_off = 2,
|
|
width = 6,
|
|
height = 5,
|
|
},
|
|
sparks = smokespark,
|
|
sparkodds = 8,
|
|
hp = 1.5,
|
|
shield = 1,
|
|
maxshield = 1,
|
|
|
|
fire_off_x = 4,
|
|
fire_off_y = 7,
|
|
|
|
maxspd = 2,
|
|
thrust = 0.2,
|
|
drag = 0.075,
|
|
slip = true,
|
|
|
|
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.y > 10 and self.x - 16 < primary_ship.x and self.x + 16 > primary_ship.x
|
|
end
|
|
|
|
xl_chasey=mknew(chasey.new{
|
|
size=2,
|
|
xp = 0x0.000a,
|
|
maxspd=1.25,
|
|
hurt = {
|
|
x_off = 2,
|
|
y_off = 4,
|
|
width = 12,
|
|
height = 10
|
|
},
|
|
fire_off_x = 8,
|
|
fire_off_y = 15,
|
|
hp = 19.5,
|
|
shield = 5,
|
|
boss = true,
|
|
slip = false,
|
|
act = function(self)
|
|
local dx,dy,shoot_spec,shoot_main = chasey.act(self)
|
|
if (self.y < 4) dy=self.thrust
|
|
return dx,dy,shoot_spec,shoot_main
|
|
end,
|
|
draw = function(self)
|
|
if(self.fx_pal) pal(self.fx_pal)
|
|
sspr(40, 0, 8, 8, self.x, self.y, 16, 16)
|
|
pal()
|
|
end,
|
|
init = function(ship)
|
|
ship.main_gun=ship.main_gun or zap_gun_e.new{}
|
|
end,
|
|
})
|
|
|
|
-->8
|
|
-- collisions
|
|
|
|
-- box: x, y, width, height
|
|
|
|
function collides(box1, box2)
|
|
return not (
|
|
box1.x>box2.x+box2.width
|
|
or box1.y>box2.y+box2.height
|
|
or box1.x+box1.width<box2.x
|
|
or box1.y+box1.height<box2.y)
|
|
end
|
|
|
|
collider = mknew{
|
|
init = function(x)
|
|
x.suppress = {}
|
|
end,
|
|
}
|
|
|
|
function collider_indexes(box)
|
|
local ret = {}
|
|
for x = box.x\8, (box.x+box.width)\8 do
|
|
for y = box.y\8, (box.y+box.height)\8 do
|
|
add(ret, x+256*y)
|
|
end
|
|
end
|
|
return ret
|
|
end
|
|
|
|
function collider:insert(item)
|
|
-- todo: separate "big items" list?
|
|
local bdx = collider_indexes(hurtbox(item))
|
|
for i in all(bdx) do
|
|
local x = self[i]
|
|
if not x then
|
|
x = {}
|
|
self[i] = x
|
|
end
|
|
add(x, item)
|
|
end
|
|
end
|
|
|
|
function collider:hide(item)
|
|
self.suppress[item]=true
|
|
end
|
|
|
|
function collider:get_collisions(item)
|
|
local found = { }
|
|
local seen = { }
|
|
local box = hurtbox(item)
|
|
local bucket_ids = collider_indexes(box)
|
|
for b_idx in all(bucket_ids) do
|
|
local bucket = self[b_idx]
|
|
if bucket then
|
|
for candidate in all(bucket) do
|
|
if not (seen[candidate] or self.suppress[candidate]) then
|
|
seen[candidate] = true
|
|
if (collides(box, hurtbox(candidate))) add(found, candidate)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
return found
|
|
end
|
|
-->8
|
|
-- level and event system
|
|
|
|
-- a level is a map from
|
|
-- effective frame number to
|
|
-- a list of actions for that
|
|
-- frame. an action is a
|
|
-- method name and its args.
|
|
|
|
-- effective frame number stops
|
|
-- when freeze count is nonzero
|
|
|
|
-- a level is won when it hits
|
|
-- the end-of-level sentinel
|
|
-- and there are no more
|
|
-- tracked enemies.
|
|
-- lost when there are no
|
|
-- player ships left.
|
|
|
|
-- effective frame
|
|
distance = 0
|
|
-- actual frame count since
|
|
-- start of level times 0x0.0001
|
|
lframe = 0
|
|
|
|
-- 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,
|
|
}
|
|
eships:push_back(s)
|
|
return s
|
|
end
|
|
|
|
function spawn_frownie()
|
|
return spawn_rnd(frownie)
|
|
end
|
|
|
|
function spawn_blocking_frownie()
|
|
spawn_blocking_rnd_x(frownie)
|
|
end
|
|
|
|
function spawn_blocky()
|
|
spawn_rnd(blocky)
|
|
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_bonus_frownie()
|
|
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()
|
|
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
|
|
return c
|
|
end
|
|
|
|
helpers = {
|
|
spawn_frownie,
|
|
spawn_frownie,
|
|
spawn_frownie,
|
|
spawn_blocky,
|
|
spawn_blocky,
|
|
spawn_chasey,
|
|
spawn_spewy,
|
|
}
|
|
|
|
function spawn_blocking_boss_chasey()
|
|
local c = spawn_rnd(xl_chasey, 1)
|
|
local nextspawn = lframe + 0x0.0080
|
|
events:push_back{move=function()
|
|
if lframe >= nextspawn then
|
|
helpers[flr(rnd(#helpers))+1]()
|
|
nextspawn += 0x0.0040
|
|
end
|
|
return c.dead
|
|
end}
|
|
|
|
return c
|
|
end
|
|
|
|
function std_spawn(tnm, n, blocking, goodie,altspr)
|
|
local typ = _ENV[tnm]
|
|
assert(typ and typ.new, tostr(tnm).." not a class")
|
|
for i=1,(n or 1) do
|
|
spawn_rnd(typ, blocking, goodie,altspr)
|
|
end
|
|
end
|
|
|
|
-- blocking: 1 or 0
|
|
function spawn_rnd(typ, blocking, goodie,altspr)
|
|
blocking = blocking or 0
|
|
freeze += blocking
|
|
s = typ.new{
|
|
x = rnd(104),
|
|
y = -(typ.size * 8 - 1),
|
|
ice=blocking,
|
|
die=function(self)
|
|
freeze -= self.ice
|
|
self.ice=0
|
|
typ.die(self)
|
|
spawn_goodie(goodie, self.x, self.y, self.size)
|
|
end,
|
|
}
|
|
if (altspr) s.spr = altspr
|
|
eships:push_back(s)
|
|
return s
|
|
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, ...)
|
|
local f,irm,vargs = _ENV[fnm],interval,pack(...)
|
|
assert(type(f) == "function", fnm.." not a function")
|
|
f(...)
|
|
events:push_back{move=function()
|
|
irm-=1
|
|
if irm <= 0 then
|
|
irm=interval
|
|
times-=1
|
|
f(unpack(vargs))
|
|
return times <= 1
|
|
end
|
|
end}
|
|
end
|
|
|
|
-- then convert sample_level to csv.
|
|
-- spawn_spec_gun_at and spawn_main_gun_at will need parsed forms.
|
|
-- the boss also needs to be reachable, but one-off is fine.
|
|
-- each row of level csv is offset,event,event-args...
|
|
-- where offset,eol is a special case.
|
|
|
|
example_level_csv=[[1,spawn_frownie
|
|
60,spawn_bonus_vulcan_chasey
|
|
61,spawn_blocky
|
|
85,spawn_spewy
|
|
100,spawn_spewy
|
|
115,spawn_spewy
|
|
130,spawn_bonus_frownie
|
|
145,spawn_spewy
|
|
200,spawn_bonus_shield_chasey
|
|
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
|
|
311,spawn_frownie
|
|
350,spawn_main_gun_at,70,-11,protron_gun_p
|
|
401,spawn_frownie
|
|
420,spawn_blocking_frownie
|
|
430,spawn_bonus_vulcan_chasey
|
|
450,spawn_frownie
|
|
465,spawn_bonus_frownie
|
|
480,spawn_chasey
|
|
500,multi,20,12,spawn_blocking_blocky
|
|
501,spawn_bonus_frownie
|
|
620,spawn_blocking_blocky
|
|
630,spawn_bonus_shield_chasey
|
|
720,spawn_blocking_boss_chasey
|
|
721,eol]]
|
|
|
|
-->8
|
|
-- standard events
|
|
|
|
blip_fx = mknew{
|
|
cancel=false
|
|
}
|
|
|
|
function blip_fx:move()
|
|
if (self.cancel) return true
|
|
self.frames -= 1
|
|
if self.frames < 0 then
|
|
self.obj.fx_pal = nil
|
|
return true
|
|
end
|
|
return false
|
|
end
|
|
|
|
function blip_fx:abort()
|
|
self.cancel=true
|
|
end
|
|
|
|
blip_pals = {}
|
|
function init_blip_pals()
|
|
for i=0,15 do
|
|
local pp = {[0]=0}
|
|
for j=1,15 do
|
|
pp[j] = i
|
|
end
|
|
blip_pals[i]=pp
|
|
end
|
|
end
|
|
|
|
function blip(obj, col, frames)
|
|
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})
|
|
end
|
|
|
|
bossspark = split"7,7,10,10,9,9,9,8,8,8,2,2,5,5"
|
|
|
|
function boom(x,y,boominess,is_boss)
|
|
local sp = firespark
|
|
if is_boss then
|
|
boominess *= 10
|
|
sp = bossspark
|
|
end
|
|
local boombase = min(0.023 * boominess, 0.25)
|
|
local boombonus = min(0.05 * boominess, 1.25)
|
|
for _=1,boominess do
|
|
local angle = rnd(1)
|
|
spark(sp,x+4,y+4,cos(angle), sin(angle),boombase+rnd(boombonus),1, true)
|
|
end
|
|
return
|
|
end
|
|
|
|
spark_particle=mknew{}
|
|
|
|
function spark_particle:move()
|
|
if (rnd(4) < 1) self.sidx += 1
|
|
if (self.sidx > #self.sprs) return true
|
|
self.x += self.dx
|
|
self.y += self.dy
|
|
self.dx -= mid(0.05,-0.05, self.dx)
|
|
self.dy -= mid(0.05,-0.05, self.dy)
|
|
end
|
|
function spark_particle:draw()
|
|
pset(self.x,self.y,self.sprs[self.sidx])
|
|
end
|
|
|
|
function spark(sprs, x, y, dx, dy, odds, fg)
|
|
if (sprs==nil or flr(rnd(odds)) ~= 0) return
|
|
local target = fg and intangibles_fg or intangibles_bg
|
|
target:push_back(spark_particle.new{
|
|
x = x + rnd(4) - 2,
|
|
y = y + rnd(4) - 2,
|
|
sprs = sprs,
|
|
sidx = 1,
|
|
dx = dx + rnd(2) - 1,
|
|
dy = dy + rnd(2) - 1,
|
|
})
|
|
end
|
|
-->8
|
|
-- powerups
|
|
|
|
xp_gem = mknew(bullet_base.new{
|
|
dx = 0,
|
|
dy = 0.75,
|
|
width=1, -- not used for spr but
|
|
height=1,-- bullet_base uses it
|
|
category = enemy_blt_cat,
|
|
damage = 0,
|
|
hurt = {
|
|
x_off = -2,
|
|
y_off = -2,
|
|
width = 8,
|
|
height = 8,
|
|
},
|
|
x_off = 2,
|
|
y_off = 2,
|
|
})
|
|
|
|
function xp_gem:draw()
|
|
local s,qx,qy = self.qsprite,0,0
|
|
-- sprite map position:
|
|
-- sprite id to x and y,
|
|
-- offset shifts specific low
|
|
-- bits of lframe up to the the
|
|
-- bit with value 4 as a cheap
|
|
-- way to pick an anim frame
|
|
if (lframe&0x0.003 == 0) qx, qy = (lframe&0x0.0004)<<16, (lframe&0x0.0008)<<15
|
|
sspr(
|
|
(s%16<<3)+qx,
|
|
(s\16<<3)+qy,
|
|
4, 4,
|
|
self.x, self.y
|
|
)
|
|
end
|
|
|
|
-- todo: "magnetic" behavior
|
|
-- when near player ship
|
|
|
|
function xp_gem:hitship(ship)
|
|
if (ship ~= primary_ship) return false
|
|
primary_ship.xp += self.val
|
|
primary_ship.last_xp_frame = lframe
|
|
return true
|
|
end
|
|
|
|
-- small gems for 1, 5, 25
|
|
-- exactly; else huge
|
|
function spawn_xp_at(x, y, off, amt)
|
|
x += rnd(off+off)-off
|
|
y += rnd(off+off)-off
|
|
xp_gem.new{
|
|
qsprite=amt == 0x0.0001 and 32 or amt == 0x0.0005 and 33 or amt == 0x0.0019 and 34 or 35,
|
|
val = amt,
|
|
}:spawn_at(mid(x, 0, 124),mid(y,-4,125))
|
|
end
|
|
|
|
powerup = mknew(bullet_base.new{
|
|
-- animated sprite array: "sprites"
|
|
-- 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
|
|
sheen8x8 = split"2,54,55,56,57,58,59,60,61"
|
|
|
|
function powerup:draw()
|
|
spr(self.sprites[max(1,
|
|
((lframe<<16)\self.anim_speed)
|
|
%(#self.sprites+self.loop_pause)
|
|
-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)
|
|
if (type(gunt)=="string") gunt=_ENV[gunt]
|
|
local gun_p = gun_swap.new{
|
|
gun = gunt.new(),
|
|
hitship = function(self, ship)
|
|
if (ship ~= primary_ship) return false
|
|
ship.special_gun = self.gun
|
|
return true
|
|
end,
|
|
draw = function(self)
|
|
pal(spec_gun_pl)
|
|
powerup.draw(self)
|
|
pal()
|
|
spr(self.gun.icon, self.x+2, self.y+2, 1, 1)
|
|
end
|
|
}
|
|
gun_p:spawn_at(x, y)
|
|
end
|
|
|
|
-->8
|
|
-- rearm screen
|
|
|
|
rearm_mode = mknew{
|
|
sel=1,
|
|
bfm=1,
|
|
crt_frm = 1,
|
|
pos=-1,
|
|
init=function(this)
|
|
poke(0x5f5c, 255) --no btnp repeat
|
|
rearm_mode.shuffle(this)
|
|
end,
|
|
}
|
|
|
|
crt={-91,-166,-2641,-1441,-23041,23295,-20491,24570}
|
|
|
|
function rearm_mode:glow_box(x0, y0, x1, y1, c, cf)
|
|
for i,v in ipairs{c[1],c[2],c[1],0} do
|
|
i -= 1
|
|
rect(x0+i,y0+i,x1-i,y1-i,v)
|
|
end
|
|
fillp(crt[self.crt_frm&0xff])
|
|
rectfill(x0+4, y0+4, x1-4, y1-4, cf)
|
|
fillp()
|
|
end
|
|
|
|
function easeoutbounce(t)
|
|
local n1=7.5625
|
|
local d1=2.75
|
|
|
|
if (t<1/d1) then
|
|
return n1*t*t;
|
|
elseif(t<2/d1) then
|
|
t-=1.5/d1
|
|
return n1*t*t+.75;
|
|
elseif(t<2.5/d1) then
|
|
t-=2.25/d1
|
|
return n1*t*t+.9375;
|
|
else
|
|
t-=2.625/d1
|
|
return n1*t*t+.984375;
|
|
end
|
|
end
|
|
|
|
|
|
function rearm_mode:frame_col(hot)
|
|
if (not hot) return {4,10}
|
|
if (self.bfm<=16) return {14,7}
|
|
return {2,8}
|
|
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)
|
|
spr(rec.s,5, 5)
|
|
print(rec.hdr, 13, 8, 7)
|
|
print(rec.body, 5, 15, 6)
|
|
end
|
|
|
|
function rearm_mode:pos_frac()
|
|
local pos = self.pos
|
|
if (not pos) return
|
|
if (pos < 0) return 1-easeoutbounce(1+pos)
|
|
if (pos > 0) return (1-pos)*(1-pos)
|
|
return 0
|
|
end
|
|
|
|
function rearm_mode:shuffle()
|
|
-- these will be placeholders
|
|
-- until the upgrade deck
|
|
-- is a thing that exists
|
|
self.options = {{
|
|
s=1,
|
|
hdr=" hull",
|
|
body = "\n +1\n max\n health",
|
|
action = function() end,
|
|
},{
|
|
s=37,
|
|
hdr=" vulc",
|
|
body = "\nplaceholder",
|
|
action = function() end,
|
|
}}
|
|
end
|
|
|
|
function rearm_mode:draw()
|
|
drawgame_top()
|
|
local frac = self:pos_frac()
|
|
camera(frac * 55, 0)
|
|
self:draw_option(1)
|
|
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)
|
|
spr(96,15,107,4,2)
|
|
print("full ammo\nfull shield\n+50% health",54, 106, 6)
|
|
end
|
|
|
|
function rearm_mode:update_pos()
|
|
local pos = self.pos
|
|
if (not pos) return
|
|
if (pos == 0) then
|
|
if (primary_ship.xp < primary_ship.xptarget) self.pos = 1
|
|
xpwhoosh = nil
|
|
return
|
|
end
|
|
if (pos < 0) pos = min(pos + 0x0.05, 0)
|
|
if pos > 0 then
|
|
pos -= 0x0.1
|
|
if (pos <= 0) pos = 999
|
|
end
|
|
self.pos = pos
|
|
end
|
|
|
|
function rearm_mode:update()
|
|
self:update_pos()
|
|
if self.pos > 1 then
|
|
mode = game_mode
|
|
return -- do not advance frame
|
|
end
|
|
local sel, bfm = self.sel, self.bfm
|
|
if (btn(3) and sel > 0 or btn(2) and sel < 0) sel=-sel
|
|
if (btn(0)) sel = 1
|
|
if (btn(1)) sel = 2
|
|
if (btn()&0xF ~= 0) and bfm >= 10 or bfm >= 30 then
|
|
bfm = 1
|
|
else
|
|
bfm += 1
|
|
end
|
|
self.bfm = bfm
|
|
|
|
if primary_ship.xp < primary_ship.xptarget then
|
|
sel = 0
|
|
elseif btnp(4) or btnp(5) and self.pos == 0 then
|
|
if sel < 0 then
|
|
-- todo: sound: rearm
|
|
primary_ship.shield = primary_ship.maxshield
|
|
-- todo: rewrite for three guns
|
|
if (primary_ship.special_gun) primary_ship.special_gun.ammo = primary_ship.special_gun.max_ammo
|
|
primary_ship.hp = min(primary_ship.maxhp, primary_ship.hp + primary_ship.maxhp/2)
|
|
primary_ship.xp -= primary_ship.xptarget / 2
|
|
else
|
|
local c = self.options[sel]
|
|
if c then
|
|
-- todo: sound: upgrade
|
|
c:action()
|
|
primary_ship.xp -= primary_ship.xptarget
|
|
primary_ship.xptarget += primary_ship.level * 0x0.0002
|
|
primary_ship.level += 1
|
|
if (primary_ship.xp >= primary_ship.xptarget) self:shuffle()
|
|
end
|
|
end
|
|
end
|
|
self.sel = sel
|
|
end
|
|
|
|
__gfx__
|
|
00000000000650000000000000000000bb0b50b59909209200cc0c00000000003b00000082000000e00e8002e00e800200333300002222000000000000000000
|
|
00000000006765000000000000cccc00b50b3055920940220c0000c000bbbb0037000000a2000000e0e8880240e8480403bbbb30028888200000000000000000
|
|
00700700006d6500000000000cddddd00b33335009444420c00c000c0b333330b7000000a8000000e88e2882e48e24823bbaabb3288aa8820000000000000000
|
|
00077000067c665000000000cdd10cd10b3dd350094dd42000c0000cb3350b35b7000000a8000000e88e2882484e24423ba77ab328a77a820000000000000000
|
|
00077000067d665000000000cd10cdd100b3350000944200c0000000b350b335b7000000a8000000e88e2882e84e28823ba77ab328a77a820000000000000000
|
|
0070070065666765000000000ddddd100b33355009444220c000000c03333350b7000000a800000008888820048488203bbaabb3288aa8820000000000000000
|
|
000000006506506500000000001111000b0b5050090920200c0000c00055550037000000a2000000008882000048420003bbbb30028888200000000000000000
|
|
00000000650000650000000000000000000b50000009200000c0cc00000000003b00000082000000000820000008200000333300002222000000000000000000
|
|
00000000000650000006500000000000b000000b80000000700000000bb0000008800000000000000009200000000000cccccccd000650000000000000000000
|
|
0000000000675000000765000000000000bbbb0080000000b0000000b76300008a920000000000009009200200000000c111111d006765000000000000000000
|
|
00000000006d6500006d6500000000000b0000b09000000030000000b663000089920000000550009994444200000000c111111d006d65000000000000000000
|
|
00000000067c6650067c6650000000000b0bb0b0a000000030000000033000000220000000576d009446544200000000c111111d067c66500000000000000000
|
|
00000000067d6650067d6650000000000b0bb0b00000000000000000000000000000000000566d009244442200000000c111111d067d66500000000000000000
|
|
000000005666657576667650000000000b0000b000000000000000000000000000000000000dd0009092220200000000c111111d656667650000000000000000
|
|
0000000056565066665656500000000000bbbb0000000000000000000000000000000000000000000090020000000000c111111d650650650000000000000000
|
|
00000000565000566500065000000000b000000b000000000000000000000000000000000000000000a00a0000000000cddddddd650000650000000000000000
|
|
060007000600070006600770766c777c0000000000a0008000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
|
6cd07cd06cd07cd06ccd7ccd6ccd7ccd000000000090008000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
|
0d000d006cd07cd06ccd7ccd6ccd7ccd0000000000800a0000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
|
000000000d000d000dd00dd0cdd1cdd0000000000080090000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
|
0600060006000600066006607667766c00000000000a080000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
|
67d06c7067d06c70677d6cc7677d6cc7000000000009080000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
|
0d00070067d06c7067cd6cc767cd6cc7000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
|
000000000d0007000dd007707dd1c771000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
|
00000000000000000000000000000000cccccccccccccccc77000000007700000000770000000077000000000000000000000000000000000000000000000000
|
|
00000000000000000000000000000000c116611dc11ee11d70000000077000000007700000000770000000070000000000000000000000000000000000000000
|
|
00000000000000000000000000000000c1611c1dc11ee11d00000000770000000077000000007700000000770000000700000000000000000000000000000000
|
|
00000000000000000000000000000000c61111cdceeeeeed00000000700000000770000000077000000007700000007700000000000000000000000000000000
|
|
00000000000000000000000000000000c6111bcdceeeeeed00000000000000007700000000770000000077000000077000000007000000000000000000000000
|
|
00000000000000000000000000000000c161bbbdc11ee11d00000000000000007000000007700000000770000000770000000077000000000000000000000000
|
|
00000000000000000000000000000000c11ccb1dc11ee11d00000000000000000000000077000000007700000007700000000770000000070000000000000000
|
|
00000000000000000000000000000000cdddddddcddddddd00000000000000000000000070000000077000000077000000007700000000770000000000000000
|
|
cccccccccccc0000cccccccccccc0000cccccccccccc0000cccccccccccc0000cccccccccccc0000cccccccccccc0000cccccccccccc0000cccccccccccc0000
|
|
c1111111111d0000c1111111111d0000c1111111111d0000c1111111111d0000c1111111111d0000c111eeee111d0000ceee2222eeed0000c2221111222d0000
|
|
c1111111111d0000c1111111111d0000c1111111111d0000c1111111111d0000c111eeee111d0000c1ee2222ee1d0000ce22111122ed0000c2111111112d0000
|
|
c1111111111d0000c1111111111d0000c1111111111d0000c111eeee111d0000c11e2222e11d0000c1e211112e1d0000ce21111112ed0000c2111111112d0000
|
|
c1111111111d0000c1111111111d0000c1111ee1111d0000c11ee22ee11d0000c1e221122e1d0000ce21111112ed0000c2111111112d0000c1111111111d0000
|
|
c1111111111d0000c1111ee1111d0000c111e22e111d0000c11e2112e11d0000c1e211112e1d0000ce21111112ed0000c2111111112d0000c1111111111d0000
|
|
c1111111111d0000c1111ee1111d0000c111e22e111d0000c11e2112e11d0000c1e211112e1d0000ce21111112ed0000c2111111112d0000c1111111111d0000
|
|
c1111111111d0000c1111111111d0000c1111ee1111d0000c11ee22ee11d0000c1e221122e1d0000ce21111112ed0000c2111111112d0000c1111111111d0000
|
|
c1111111111d0000c1111111111d0000c1111111111d0000c111eeee111d0000c11e2222e11d0000c1e211112e1d0000ce21111112ed0000c2111111112d0000
|
|
c1111111111d0000c1111111111d0000c1111111111d0000c1111111111d0000c111eeee111d0000c1ee2222ee1d0000ce22111122ed0000c2111111112d0000
|
|
c1111111111d0000c1111111111d0000c1111111111d0000c1111111111d0000c1111111111d0000c111eeee111d0000ceee2222eeed0000c2221111222d0000
|
|
cddddddddddd0000cddddddddddd0000cddddddddddd0000cddddddddddd0000cddddddddddd0000cddddddddddd0000cddddddddddd0000cddddddddddd0000
|
|
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
|
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
|
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
|
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
|
04444400044444440000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
|
447777700477777a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
|
477aaa7a0477aaaa0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
|
47a0047a047a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
|
47a0447a047a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
|
47a4477a047a44400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
|
477777a00477777a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
|
477770000422aaaa2222000200000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
|
47a77700022ee0002eeee002e00022e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
|
47a4777002ea2e002e002e02ee022ee0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
|
47a0477a22ea2e002e002e02e2e2e2e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
|
47a0047a2e2222e02e222e02e02e02e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
|
47a0047a2eeeeeea2eeee002e02e02e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
|
0aa000aa2e7aa2ea2e00e002e02e02e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
|
000000002e0002e02e002e02e02e02e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
|
000000000e0000e00e000e00e00e00e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
|
__label__
|
|
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007777777777777777
|
|
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007666666666666665
|
|
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007666666666666665
|
|
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007666611111666665
|
|
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007666115151166665
|
|
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007666111611156665
|
|
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007666115161156665
|
|
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007666611111556665
|
|
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007666665555566665
|
|
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007666666666666665
|
|
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007655555555555565
|
|
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007650000000000765
|
|
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007650b000000b0765
|
|
0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000765000bbbb000765
|
|
000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000076500b0000b00765
|
|
00000000000000000000000000000000000000000000e00e800200000000000000000000000000000000000000000000000000000000000076500b0bb0b00765
|
|
00000000000000000000000050000000000000000000e0e8880200000000000000000000000000000000000000000000000000000000000076500b0bb0b00765
|
|
00000000000000000000000000000000000000000000e88e288200000000000000000000000000000000000000000000000000000000000076500b0000b00765
|
|
00000000000000000000000000000000000000000d00e88e2882000000000000000000000000000000000000000000000000000000000000765000bbbb000765
|
|
00000000000000000000000000000000000000000000e88e28820000000000000000000000000000000000000000000000000000000000007650b000000b0765
|
|
00000000000000000000000000000000000000000000088888200000000000000000000000000000000000000000000000000000000000007650000000000765
|
|
00000000000000000000000000000000000000000000008882000000000000000000000000000000000000000000000000000000000000007657777777777765
|
|
00000000000000000000000000000000000000000000000820000000000000000000000000000000000000000000000000000000000000007666666666666665
|
|
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007655555555555565
|
|
0000000000000000000000000000000000000005000000000000000000000000000000000000000000000000000000000000000000000000765aeaeaeaeae765
|
|
0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000765eaeaeaeaea765
|
|
0000000000000000000000000000000000000000000000000000000000000000000000000050000000000000000000000000000000000000765aeaeaeaeae765
|
|
00000000000000000000000000000000000000000000000000000009909209200000000000000000000000000000000000000000000000007657777777777765
|
|
00000000000000000000000000000000000000000000000000000009209402200000000000000000000000000000000000000000000000007666666666666665
|
|
00000000000000000000000000000000000000000000000000000000944442000000000000000000000000000000000000000000000000007666666666666665
|
|
0000000000000000000000000000000000000000000000000000000094dd42000000000000000000000000000000000000000000000000007666666666666665
|
|
00000000000000000000000000000000000000000000000000000000094420000000000000000000000000000000000000000000000000007666622222666665
|
|
00000000000000000000000000000000000000000000000000500000944422000000000000000000000000000000000000000000000000007666225552266665
|
|
00000000000000000000000000000000000000000000000000000000909202000000000000000000000000000000000000000000000000007666225262256665
|
|
00000000000000000000000000000000000000000000000000000000009200000000000000000000000000000000000000000000000000007666225652256665
|
|
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007666622222556665
|
|
00000000000000500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007666665555566665
|
|
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007666666666666665
|
|
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007655555555555565
|
|
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007650000000000765
|
|
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007650000000000765
|
|
00000000000000000005000000009200000000000000000000000000000000000000000000000000000000000000000000000000000000007650000000000765
|
|
00000000050000000000000009009200200000000000000000000000000000000000000000000000000000000000000000000000000000007650000000000765
|
|
000000000000000000d0000009994444200000000000000000000000000000000000000000000000000000000000000000000000000000007650000000000765
|
|
00000000000000000000000009446544200000000000000000000000000000000000000000000000000000000000000000000000000000007650000000000765
|
|
00000000000000000000000009244442200000000000000000000000000000000000000000000000000000000000000000000000000000007650000000000765
|
|
0000000000000000000000000909222020000000000000000bbbb000000000000000000000000000000000000000000000000000000000007650000000000765
|
|
000000000000000000000000000900200000000000000000b3333300000000000000000000000000000000000000000000000000000000007650000000000765
|
|
000000000000000000000000000a00a0000000000000000b3350b350000000000000000000000000000000000000000000000000000000007650000000000765
|
|
00000000000000000000000000000000000000000000000b350b3350000000000000000000000000000000000000000000000000000000007657777777777765
|
|
00000000000000000000000000000000000000000000000033333500000000000000000000000000000000000000000000000000000000007666666666666665
|
|
00000000000000000000000000000000088000000000000005555000000000000000000000000000000000000000000000000000000000007655555555555565
|
|
000000000000000000000000000000058a9200000000000000000000000000000000000000000000000000000000000000000000000000007650000000000765
|
|
00000000000000000000000000000000899200000000000000000000008200000000000000000000000000000000000000000000000000007650000000000765
|
|
0000000000000000000000000000000002200000000000000000000000a200000000000000000000000000000000000000000000000000007650000000000765
|
|
0000000000000000000500000000000000000000000000000000000000a800000000000000000000000000000000000000000000000000007657777777777765
|
|
0000000000000000000000000000000000000000000000000000000000a800000000000000000000000000000000000000000000000000007666666666666665
|
|
0000000000000000000000000000000000000000000000000000000000a800000000000000000000000000000000000000000000000000007666666666666665
|
|
0000000000000000000000000088000000000050000000000000000000a800000000000000000000000000000000000000000000000000007666666666666665
|
|
20000000000000000000000008a9200000000000000000000000000000a200000000000000000000000000000000000000000000000000007611161616111665
|
|
20000000000000000000000008992000000000000000000000000000008200000000000000000000000000000000000000000000000000007615151515151565
|
|
000000000000000000000000002200000d0000000000000000000000000000000000000000000000000000000000000000000000000000007611151515116565
|
|
0000000000000000000000000000000000000e00e800200000000000e00e80020000000000000000000000000000000000000000000000007615551115151665
|
|
0000000000000000000000000000000d00000e0e8880200000000000e0e888020000000000000000000000000000000000000000000000007615661115151565
|
|
0000000000000000000000000000000000d00e88e2882000000d0000e88e28820000000000000000000000000000000000000000000000007665666555656565
|
|
0000088000000000000880000000000000000e88e288200000000000e88e28820000000000000000000000000000000000000000000000007666666666666665
|
|
00008a9200000000008a92000000000000000e88e288200000000000e88e28820000000000000000000000000000000000000000000000007655555555555565
|
|
0000899200000000008992000000000000000088888200000000000008888820000000000000000000000000000000000000000000000000765aaaaaaaaaa765
|
|
0000022000000000000220000000000000000008882000000000000000888200000000000000000000000000000000000000000000000000765aaaaaaaaaa765
|
|
0000000000000000000000000000000000000000820000000000000000082000000000000000000000000000000000000000000000000000765aaaaaaaaaa765
|
|
0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000765aaaaaaaaaa765
|
|
0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000765a9a9a9a9a9765
|
|
00000000000088000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007659a9a9a9a9a765
|
|
000000000008a920000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000765a9a9a9a9a9765
|
|
00000000000899200000000000000000000008800000000000000000000000000000000000000000000000000000000000000000000000007659a9a9a9a9a765
|
|
0000000000002200000000000000000000008a92000000000000000000000000000000000000000000000000000000000000000000000000765a9a9a9a9a9765
|
|
00000000000000000000000000000000000089920000000000000000000000000000000000000000000000000000000000000000000000007659999999999765
|
|
00000000000000000000000000000000000002200000000000000000000000000000000000000000000000000000000000000000000000007659999999999765
|
|
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007659999999999765
|
|
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007659999999999765
|
|
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007659999999999765
|
|
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007654949494949765
|
|
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007659494949494765
|
|
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007654949494949765
|
|
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007659494949494765
|
|
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007654949494949765
|
|
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007654444444444765
|
|
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007654444444444765
|
|
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007654444444444765
|
|
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007654444444444765
|
|
00000000000000000000000000000000000000000000000000000000008200000000000000000000000000000000000000000000000000007654444444444765
|
|
0000000000000000000000000000000000000000000000000000000000a200000000000000000000000000000000000000000000000000007654444444444765
|
|
0000000000000000000000000000000000000000000000000000000000a800000000000000000000000000000000000000000000000000007657777777777765
|
|
0000000000000000000000000000000000000000000000000000000000a800000000000000000000000000000000000000000000000000007666666666666665
|
|
0000000000000000000000000000000000000000000000000000000000a800000000000000000000000000000000000000000000000000007666666666666665
|
|
0000000000000000000000000000000000000000000000000000000000a800000000000000000000000000000000000000000000000000007666666666666665
|
|
0000000000000000000000000000000000000000000000000000000000a200000000000000000000000000000000000000000000000000007666666666666665
|
|
00000000000000000000000000000000000000000000000000000000008200000000000000000000000000000000000000000000000000007616166666611665
|
|
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007615156666165565
|
|
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007611156666111665
|
|
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007615156666651565
|
|
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007615156666116565
|
|
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007665656666655665
|
|
00000000000000000000000000000000000000000000000000000000000000000008800000000000000000000000000000000000000000007666666666666665
|
|
0000000000000000000000000000000000000000000000000000000000000000008a920000000000000000000000000000000000000000007655555555555565
|
|
00000000000000000000000000000000000000000000000000000000000000000089920000000000000000000000000000000000000000007652222750000765
|
|
00000000000000000000000000000000000000000000000000000000000000000002200000000000000000000000000000000000000000007652222750000765
|
|
00000000000000000000000000000000000000000000000000000000006500000000000000000000000000000000000000000000000000007652222750000765
|
|
00000000000000000000000000000000000000000000000000000000067650000000000000000000000000000000000000000000000000007652222750000765
|
|
0000000000000000000000000000000000000000000000000000000006d650000000000000000000000000000000000000000000000000007652222750000765
|
|
0000000000000000000000000000000000000000000000000000000067c665000000000000000000000000000000000000000000000000007652222750000765
|
|
0000000000000000000000000000000000000000000000000000000067d665000000000000000000000000000000000000000000000000007652828750000765
|
|
00000000000000000000000000000000000000000000000000000006566676500000000000000000000000000000000000000000000000007658282750000765
|
|
00000000000000000000000000000000000000000000000000000006506506500000000000000000000000000000000000000000000000007652828750000765
|
|
00000000000000000000000000000000000000000000000000000006500006500000000000000000000000000000000000000000000000007658282750000765
|
|
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007652828750000765
|
|
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007658282750000765
|
|
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007658888750000765
|
|
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007658888750000765
|
|
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007658888750000765
|
|
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007658888750000765
|
|
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007658888750000765
|
|
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007658888750000765
|
|
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007658888750000765
|
|
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007658888750000765
|
|
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007657777757777765
|
|
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007666666666666665
|
|
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007555555555555555
|
|
|