32 Commits

Author SHA1 Message Date
26c3a5b91e actually fix starting ammo
also improve box overflow
2025-01-26 12:50:27 -08:00
44c70a028f fix starting ammo 2025-01-26 12:45:43 -08:00
a90caeba85 make level less spewy, finish renaming s to icon 2025-01-26 12:42:57 -08:00
cd5b79ef4a prototype: gun picking 2025-01-26 11:21:32 -08:00
637eed1eb8 autofire and three guns 2025-01-26 01:06:37 -08:00
55ab256539 oh right I changed that name 2025-01-26 00:32:17 -08:00
22d13121a9 placeholders for card draw 2025-01-26 00:30:09 -08:00
58da8e6dc3 fix hokey pokey menu
the menu eases in, the menu eases out, the menu eases in and you shake it all about
2025-01-20 18:02:50 -08:00
8ff0732cbc draw rearm pane; exit behavior is broken
Nil transparency has screwed me over; I am uploading this version as
an illustrative example
2025-01-20 17:43:21 -08:00
c88e7c0657 I really wish Lua had real classes rather than forcing you to assemble it yourself 2025-01-20 17:09:47 -08:00
ff3552bc45 fix unit error for xp frame logic 2025-01-20 17:02:02 -08:00
2dcb95b0cd menu prototype 2025-01-20 16:59:57 -08:00
87451bbd3a incomplete start to porting ui 2025-01-12 22:58:20 -08:00
89a42e6c8b improve xp gem art 2025-01-12 21:51:32 -08:00
e2be11a2da fix order of magnitude error in XP logic 2025-01-12 21:47:11 -08:00
175099d778 make maxval work better near p8 precision limits 2024-12-29 23:44:39 -08:00
33fede4ed8 update comment about off-by-1 error 2024-12-29 23:41:47 -08:00
afa1f22170 go back to 0x0.0001 increments for xp
I foresee the 32K limit being a bigger problem than the math in vertmeter, although I will probably need to go patch vertmeter up too
2024-12-29 23:39:56 -08:00
78b200272e fix shield crash 2024-12-29 23:33:45 -08:00
42ac2abc20 groundwork for full mode switching 2024-12-29 23:26:48 -08:00
c55ea000fd whoosh animation when level up pending 2024-12-28 19:56:42 -08:00
2c1ad0a0b3 drop xp gems 2024-12-28 19:27:54 -08:00
e0b784ce7d clean up, run at 60 fps
now the bounce animation feels like it takes too long, trying to fix it
2024-12-26 17:43:04 -08:00
e1a70cc6fc dark blue, not dark gray, for pane bg 2024-12-26 17:16:48 -08:00
cbdf2a27cd fast quadratic exit feels better 2024-12-26 17:05:55 -08:00
caaf848722 fixed it 2024-12-26 16:59:43 -08:00
25f58d5cce messed up entry animation but it's a start
* wrong Y positions for everything
* both directions are "enter"
2024-12-26 16:19:52 -08:00
c15ec61494 partial prototype of object-oriented drawing and entry 2024-12-26 12:32:31 -08:00
7ff5cf97ad functioning prototype 2024-12-24 19:23:14 -08:00
f761d1a172 prototype for REARM screen UI 2024-12-24 19:04:07 -08:00
98f56328a6 off by 1 2024-12-24 18:10:48 -08:00
93792c36c9 sketch for possible REARM ui blank 2024-12-24 18:10:17 -08:00
2 changed files with 687 additions and 212 deletions

223
rearm_prototype.p8 Normal file
View File

@ -0,0 +1,223 @@
pico-8 cartridge // http://www.pico-8.com
version 42
__lua__
-- vacuum gambit
-- by kistaro windrider
-- stdlib
-- 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
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
-->8
-- entry points
function _draw()
cls()
draw_hud_placeholder()
left_pane:draw()
right_pane:draw()
rearm_pane_instance:draw()
end
function _init()
item=1
bfm=1
crt_frm = 1
left_pane = weapon_pane.new{}
right_pane = weapon_pane.new{
is_left=false,
s = 2,
hdr = "vulc",
body = " rate\n\n faster\n firing\n rate",
hot = function() return item == 2 end}
rearm_pane_instance = rearm_pane.new{hot=function() return item < 0 end}
end
function _update60()
crt_frm += 0.25
if (crt_frm >= 9) crt_frm = 1
if (btn(3) and item > 0 or btn(2) and item < 0) item = -item
if (btn(0)) item = 1
if (btn(1)) item = 2
if (btn() & 0xF ~= 0) and bfm >= 10 or bfm >= 30 then
bfm = 1
else
bfm += 1
end
if btnp(4) then
left_pane.pos = -1
right_pane.pos = -1
rearm_pane_instance.pos = -1
end
if btnp(5) then
left_pane.pos = 1
right_pane.pos = 1
rearm_pane_instance.pos = 1
end
left_pane:update()
right_pane:update()
rearm_pane_instance:update()
end
function draw_hud_placeholder()
rectfill(112, 0, 127, 127,0x56)
rect(112,0,127,127,7)
line(127,1,127,127,5)
line(113,127)
end
-->8
-- rearm pane drawing
crt={-91,-166,-2641,-1441,-23041,23295,-20491,24570}
function 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[crt_frm&0xff])
rectfill(x0+4, y0+4, x1-4, y1-4, cf)
fillp()
end
function frame_col(hot)
if (not hot) return {4,10}
if (bfm<=16) return {14,7}
return {2,8}
end
function draw_weap_opt(x, y, c, s, hdr, body)
camera(-x,-y)
glow_box(0,0,55,100,c,1)
spr(s,5, 5)
print(hdr, 13, 8, 7)
print(body, 5, 15, 6)
camera()
end
function draw_rearm(c)
glow_box(0,101,111,127,c,1)
spr(5,15,107,4,2)
print("full ammo\nfull shield\n+50% health",54, 106, 6)
end
-->8
-- rearm pane objects
easing_pane = mknew{
-- to enter: pos = -1; to exit: pos = 1
-- runs for 32 frames in, 16 frames out
}
function easing_pane: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 easing_pane:update()
local pos = self.pos
if (not pos or pos == 0) return
if (pos < 0) pos = min(pos + 0x0.05, 0)
if pos > 0 then
pos -= 0x0.1
if (pos <= 0) pos = nil
end
self.pos = pos
end
weapon_pane = mknew(easing_pane.new{
is_left = true,
s = 1,
hdr = "hull",
body = "\n +1\n max\n health",
hot = function() return item == 1 end,
})
function weapon_pane:draw()
local frac, is_left = self:frac(), self.is_left
if (not frac) return
camera(
frac * (is_left and 55 or -128) + (1-frac) * (is_left and 0 or -56),
0)
glow_box(0,0,55,100,frame_col(self:hot()),1)
spr(self.s,5, 5)
print(self.hdr, 13, 8, 7)
print(self.body, 5, 15, 6)
camera()
end
rearm_pane = mknew(easing_pane.new{})
function rearm_pane:draw()
local frac = self:frac()
if (not frac) return
camera(0, -28 * frac)
glow_box(0,101,111,127,frame_col(self:hot()),1)
spr(5,15,107,4,2)
print("full ammo\nfull shield\n+50% health",54, 106, 6)
camera()
end
__gfx__
000000000b00000000000a0007700770000aa0000444440004444444000000000000000000000000000000000000000000000000000000000000000000000000
00000000bba80880000008000aa00aa00a0880a0447777700477777a000000000000000000000000000000000000000000000000000000000000000000000000
007007000aaa28780a0000000990099008000080477aaa7a0477aaaa000000000000000000000000000000000000000000000000000000000000000000000000
0007000008a8887808000000099009900080080047a0047a047a0000000000000000000000000000000000000000000000000000000000000000000000000000
00007000088888820000a000088008800000000047a0447a047a0000000000000000000000000000000000000000000000000000000000000000000000000000
00700700008888200000800008800880a000000a47a4477a047a4440000000000000000000000000000000000000000000000000000000000000000000000000
000000000008820000a0000008800880080aa080477777a00477777a000000000000000000000000000000000000000000000000000000000000000000000000
0000000000002000008000000880088000088000477770000422aaaa222200020000020000000000000000000000000000000000000000000000000000000000
0d5000000000000000000000000000000000000047a77700022ee0002eeee002e00022e000000000000000000000000000000000000000000000000000000000
d00000000000000000000000000000000000000047a4777002ea2e002e002e02ee022ee000000000000000000000000000000000000000000000000000000000
500000000000000000000000000000000000000047a0477a22ea2e002e002e02e2e2e2e000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000047a0047a2e2222e02e222e02e02e02e000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000047a0047a2eeeeeea2eeee002e02e02e000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000aa000aa2e7aa2ea2e00e002e02e02e000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000002e0002e02e002e02e02e02e000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000e0000e00e000e00e00e00e000000000000000000000000000000000000000000000000000000000

View File

@ -124,11 +124,12 @@ function linked_list:pop_front()
end end
function _init() function _init()
mode = game_mode
init_blip_pals() init_blip_pals()
wipe_level() wipe_level()
primary_ship.main_gun = zap_gun_p.new() -- redundant? primary_ship.main_gun = zap_gun_p.new() -- redundant?
load_level(example_level_csv) load_level(example_level_csv)
state = game game_state = game
pal(2,129) pal(2,129)
pal() pal()
end end
@ -157,6 +158,7 @@ function init_hpcols()
end end
function wipe_level() function wipe_level()
xpwhoosh = nil
primary_ship = player.new() primary_ship = player.new()
init_hpcols() init_hpcols()
pships = linked_list.new() pships = linked_list.new()
@ -171,7 +173,7 @@ function wipe_level()
end end
function _update60() function _update60()
updategame() mode:update()
end end
function call_f(x) function call_f(x)
@ -183,6 +185,10 @@ function call_move(x)
end 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
mode = rearm_mode.new()
return _update60()
end
leveldone = level_frame() leveldone = level_frame()
events:vore(new_events) events:vore(new_events)
events:strip(call_move) events:strip(call_move)
@ -248,20 +254,41 @@ 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 leveldone and not eships.next and not ebullets.next and not events.next then
state = win 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
if (not pships.next) state = lose
end end
function _draw() function _draw()
mode:draw()
end
function drawgame_top()
camera()
fillp(0) fillp(0)
drawgame() drawgame()
if (state == game) fadelvl = -45 if (game_state == game) fadelvl = -45
if (state == win) dropshadow("win",50,61,11) if (game_state == win) dropshadow("win",50,61,11)
if (state == lose) dropshadow("fail",48,61,8) if (game_state == lose) dropshadow("fail",48,61,8)
fadescreen() fadescreen()
end 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" 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() function fadescreen()
@ -336,8 +363,8 @@ function drawhud()
line(127,1,127,127,5) line(127,1,127,127,5)
line(113,127) line(113,127)
draw_gun_info("❎",1,116,3,primary_ship.main_gun) draw_gun_info("❎",1,116,3,1)
draw_gun_info("🅾️",1,116,29,primary_ship.special_gun) draw_gun_info("🅾️",1,116,29,2)
inset(114,57,119,118) inset(114,57,119,118)
rectfill(119,57,124,58,13) rectfill(119,57,124,58,13)
@ -346,8 +373,20 @@ function drawhud()
print("XP",119,55,1) print("XP",119,55,1)
print("HP",114,122,1) print("HP",114,122,1)
fillp(0x5a5a) 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) vertmeter(115,58,118,117,primary_ship.xp, primary_ship.xptarget, powcols)
-- 59 px vertically 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 local mxs, cs, mxh, ch = primary_ship.maxshield, primary_ship.shield, primary_ship.maxhp, primary_ship.hp
if (mxs > 0) and (mxh > 0) then if (mxs > 0) and (mxh > 0) then
local split = 59 * (mxs / (mxs + mxh)) \ 1 + 64 local split = 59 * (mxs / (mxs + mxh)) \ 1 + 64
@ -365,11 +404,13 @@ function drawhud()
fillp(0) fillp(0)
end end
function draw_gun_info(lbl,fgc,x,y,gun) function draw_gun_info(lbl,fgc,x,y,gn)
dropshadow(lbl,x,y,fgc) dropshadow(lbl,x,y,fgc)
inset(114,y+7,125,y+18) inset(114,y+7,125,y+18)
inset(114,y+20,125,y+24) inset(114,y+20,125,y+24)
if(gun) then if (not primary_ship.special_guns) return
local gun = primary_ship.special_guns[gn]
if (not gun) return
spr(gun.icon,116,y+9,1,1) spr(gun.icon,116,y+9,1,1)
--115 to 124 - ammo bar. round up --115 to 124 - ammo bar. round up
if gun.ammo == nil then if gun.ammo == nil then
@ -385,12 +426,16 @@ function draw_gun_info(lbl,fgc,x,y,gun)
line(118, y+22, 121, y+22, 2) line(118, y+22, 121, y+22, 2)
end end
end end
end
function vertmeter(x0,y0,x1,y1,val,maxval,cols) function vertmeter(x0,y0,x1,y1,val,maxval,cols)
if ((val <= 0) or (maxval <= 0)) return 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 h = y1-y0
local px = val/maxval * h \ 1 local px = val*h/maxval \ 1
local ncols = #cols local ncols = #cols
local firstcol = ((h-px)*ncols\h)+1 local firstcol = ((h-px)*ncols\h)+1
local lastbottom = y0+(h*firstcol\ncols) local lastbottom = y0+(h*firstcol\ncols)
@ -429,6 +474,7 @@ ship_m = mknew{
maxshield = 0, maxshield = 0,
shieldcooldown = 0x0.003c,--1s shieldcooldown = 0x0.003c,--1s
shieldpenalty = 0x0.012c, --5s shieldpenalty = 0x0.012c, --5s
shield_refresh_ready = 0,
slip = true, -- most enemies slide slip = true, -- most enemies slide
@ -445,7 +491,27 @@ ship_m = mknew{
function ship_m:die() function ship_m:die()
self.dead = true self.dead = true
if (self.hp < 0) boom(self.x+self.size*4, self.y+self.size*4,12*self.size, self.boss) 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 end
function ship_m:calc_velocity(v0, t) function ship_m:calc_velocity(v0, t)
@ -489,11 +555,12 @@ end
function ship_m:move() function ship_m:move()
self:refresh_shield() self:refresh_shield()
local dx, dy, shoot_spec, shoot_main = self:act() local dx, dy, shoot_spec1, shoot_spec2 = self:act()
dx = self:constrain(self.x, self.xmomentum, self.xmin, self.xmax, dx) dx = self:constrain(self.x, self.xmomentum, self.xmin, self.xmax, dx)
dy = self:constrain(self.y, self.ymomentum, self.ymin, self.ymax, dy) dy = self:constrain(self.y, self.ymomentum, self.ymin, self.ymax, dy)
if (shoot_main) self:maybe_shoot(self.main_gun) self:maybe_shoot(self.main_gun)
if (shoot_spec) self:maybe_shoot(self.special_gun) if (shoot_spec1 and self.special_guns) self:maybe_shoot(self.special_guns[1])
if (shoot_spec2 and self.special_guns) self:maybe_shoot(self.special_guns[2])
if (dx ~= 0 or dy ~= 0) spark(self.sparks, self.x + 4*self.size, self.y + 4*self.size, dx*2.5, dy*2.5, self.sparkodds) if (dx ~= 0 or dy ~= 0) spark(self.sparks, self.x + 4*self.size, self.y + 4*self.size, dx*2.5, dy*2.5, self.sparkodds)
self.xmomentum = self:calc_velocity(self.xmomentum, dx) self.xmomentum = self:calc_velocity(self.xmomentum, dx)
self.ymomentum = self:calc_velocity(self.ymomentum, dy) self.ymomentum = self:calc_velocity(self.ymomentum, dy)
@ -616,6 +683,20 @@ gun_base = mknew{
icon = 20 icon = 20
} }
-- gun_base subtypes are
-- level-up options that,
-- as an action, assign
-- themselves to the player
function gun_base:action()
local item = self.new()
item.ammo = item.maxammo
if not primary_ship.special_guns then
primary_ship.special_guns = {item}
else
add(primary_ship.special_guns, item)
end
end
function bullet_base:hitship(_) function bullet_base:hitship(_)
self:die() self:die()
return true return true
@ -628,7 +709,7 @@ function bullet_base:move()
self.x += self.dx self.x += self.dx
self.y += self.dy self.y += self.dy
if (self.f) self.f -= 1 if (self.f) self.f -= 1
if (self.y > 128) or (self.y < -8 * self.height) or (self.f and self.f < 0) then if (self.y > 145) or (self.y < -8 * self.height) or (self.f and self.f < 0) then
self:die() self:die()
return true return true
end end
@ -698,13 +779,13 @@ zap_p = mknew(zap_e.new{
}) })
zap_gun_e = mknew(gun_base.new{ zap_gun_e = mknew(gun_base.new{
cooldown = 0x0.000a, -- frames between shots cooldown = 0x0.0020, -- frames between shots
ammo = nil, -- unlimited ammo - main gun
actually_shoot = spawn_one(zap_e), actually_shoot = spawn_one(zap_e),
}) })
zap_gun_p = mknew(zap_gun_e.new{ zap_gun_p = mknew(zap_gun_e.new{
actually_shoot = spawn_one(zap_p), actually_shoot = spawn_one(zap_p),
hdr = "mAIN gUN",
}) })
blast = mknew(bullet_base.new{ blast = mknew(bullet_base.new{
@ -723,17 +804,22 @@ blast = mknew(bullet_base.new{
damage = 4, damage = 4,
dx = 0, -- px/frame dx = 0, -- px/frame
dy = -2, dy = -1,
awaitcancel = false, awaitcancel = false,
-- disable damage for 2 frames -- disable damage for 4 frames
-- when hitting something -- when hitting something
-- todo: rewrite all ship hit
-- logic so i can avoid
-- repeating hits to the
-- same ship instead of
-- using a cooldown
hitship = function(self, _) hitship = function(self, _)
if self.damage > 0 and not self.awaitcancel then if self.damage > 0 and not self.awaitcancel then
self.awaitcancel = true self.awaitcancel = true
once_next_frame(function() once_next_frame(function()
new_events:push_back{ new_events:push_back{
wait = 2, wait = 4,
obj = self, obj = self,
saved_dmg = self.damage, saved_dmg = self.damage,
move = function(self) move = function(self)
@ -754,10 +840,20 @@ blast = mknew(bullet_base.new{
blast_gun = mknew(gun_base.new{ blast_gun = mknew(gun_base.new{
icon = 13, icon = 13,
cooldown = 0x0.0020, -- frames between shots cooldown = 0x0.0078, -- 120 frames between shots
ammo = 5, ammo = 5,
maxammo = 5, maxammo = 5,
actually_shoot = spawn_one(blast), actually_shoot = spawn_one(blast),
hdr = "bLASTER",
body= [[plasma orb
cuts through
enemies.
slow.
ammo: 5
rate: 1/2sec
dmg: 4
]],
}) })
protron_e = mknew(bullet_base.new{ protron_e = mknew(bullet_base.new{
@ -789,7 +885,7 @@ protron_p = mknew(protron_e.new{
protron_gun_e = mknew(gun_base.new{ protron_gun_e = mknew(gun_base.new{
icon = 25, icon = 25,
cooldown = 0x0.000f, -- frames between shots cooldown = 0x0.0040, -- frames between shots
ammo = nil, ammo = nil,
maxammo = nil, maxammo = nil,
munition = protron_e munition = protron_e
@ -818,6 +914,17 @@ end
protron_gun_p = mknew(protron_gun_e.new{ protron_gun_p = mknew(protron_gun_e.new{
munition = protron_p, munition = protron_p,
maxammo = 20,
cooldown = 0x0.0018,
hdr = "pROTRON",
body = [[spray shots
in a dense
arc.
ammo: 20
rate: 2/sec
dmg: 1
]],
}) })
vulcan_e = mknew(bullet_base.new{ vulcan_e = mknew(bullet_base.new{
@ -850,7 +957,7 @@ vulcan_p = mknew(vulcan_e.new{
vulcan_gun_e = mknew(gun_base.new{ vulcan_gun_e = mknew(gun_base.new{
icon = 37, icon = 37,
enemy = false, enemy = false,
cooldown = 0x0.0002, -- frames between shots cooldown = 0x0.0003, -- frames between shots
ammo = nil, ammo = nil,
maxammo = nil, maxammo = nil,
munition=vulcan_e, munition=vulcan_e,
@ -869,6 +976,16 @@ vulcan_gun_e = mknew(gun_base.new{
vulcan_gun_p = mknew(vulcan_gun_e.new{ vulcan_gun_p = mknew(vulcan_gun_e.new{
munition=vulcan_p, munition=vulcan_p,
maxammo = 100,
hdr = "vULCAN",
body = [[rapid fire
in a v
shape.
ammo: 100
rate: 20/sec
dmg: 0.5
]],
}) })
-->8 -->8
@ -897,14 +1014,15 @@ player = mknew(ship_m.new{
shield = 2, -- regenerates shield = 2, -- regenerates
maxshield = 2, maxshield = 2,
-- xp, increments of 0x0.01 -- xp in increments of 0x0.0001
xp = 0, xp = 0,
xptarget = 0x0.05, xptarget = 0x0.0004,
last_xp_frame = 0,
level = 1, level = 1,
-- gun -- gun
main_gun = nil, -- assign at spawn time main_gun = nil, -- assign at spawn time
special_gun = nil, special_guns = nil,
fire_off_x = 4, -- offset where bullets come from fire_off_x = 4, -- offset where bullets come from
fire_off_y = 0, fire_off_y = 0,
@ -956,8 +1074,8 @@ frownie = mknew(ship_m.new{
sparks = smokespark, sparks = smokespark,
sparkodds = 8, sparkodds = 8,
-- health
hp = 0.5, -- enemy ships need no max hp hp = 0.5, -- enemy ships need no max hp
xp = 0x0.0001,
-- position -- position
x=60, -- x and y are for upper left corner x=60, -- x and y are for upper left corner
@ -979,6 +1097,7 @@ frownie = mknew(ship_m.new{
blocky = mknew(frownie.new{ blocky = mknew(frownie.new{
sprite = 10, sprite = 10,
hp = 1.5, hp = 1.5,
xp = 0x0.0002,
hurt = { hurt = {
x_off = 0, x_off = 0,
y_off = 0, y_off = 0,
@ -998,6 +1117,7 @@ blocky = mknew(frownie.new{
spewy = mknew(frownie.new{ spewy = mknew(frownie.new{
sprite=26, sprite=26,
xp = 0x0.0003,
hurt = { hurt = {
x_off=0, x_off=0,
y_off=1, y_off=1,
@ -1018,6 +1138,7 @@ spewy = mknew(frownie.new{
chasey = mknew(ship_m.new{ chasey = mknew(ship_m.new{
sprite = 5, sprite = 5,
xp = 0x0.0004,
size = 1, size = 1,
hurt = { hurt = {
x_off = 1, x_off = 1,
@ -1044,6 +1165,7 @@ chasey = mknew(ship_m.new{
end end
}) })
-- todo: use constraints
function chasey:act() function chasey:act()
self.xmin = max(primary_ship.x-8, 0) self.xmin = max(primary_ship.x-8, 0)
self.xmax = min(primary_ship.x + 8, 112 - 8*self.size) self.xmax = min(primary_ship.x + 8, 112 - 8*self.size)
@ -1052,6 +1174,7 @@ end
xl_chasey=mknew(chasey.new{ xl_chasey=mknew(chasey.new{
size=2, size=2,
xp = 0x0.000a,
maxspd=1.25, maxspd=1.25,
hurt = { hurt = {
x_off = 2, x_off = 2,
@ -1275,32 +1398,9 @@ function spawn_blocking_spewy()
end end
end end
function spawn_bonus_frownie() function spawn_vulcan_chasey()
local f = spawn_frownie()
f.sprite = 7
f.die = function(self)
spawn_repair_at(self.x+4, self.y+4)
frownie.die(self)
end
end
function spawn_bonus_vulcan_chasey()
local c = spawn_chasey() local c = spawn_chasey()
c.main_gun=vulcan_gun_e.new{enemy=true} c.main_gun=vulcan_gun_e.new{enemy=true}
c.die = function(self)
spawn_main_gun_at(self.x-1, self.y-1, vulcan_gun_p)
chasey.die(self)
end
c.sprite=4
return c
end
function spawn_bonus_shield_chasey()
local c = spawn_chasey()
c.die = function(self)
spawn_shield_upgrade_at(self.x-1, self.y-1)
chasey.die(self)
end
c.sprite=4 c.sprite=4
return c return c
end end
@ -1349,7 +1449,6 @@ function spawn_rnd(typ, blocking, goodie,altspr)
freeze -= self.ice freeze -= self.ice
self.ice=0 self.ice=0
typ.die(self) typ.die(self)
spawn_goodie(goodie, self.x, self.y, self.size)
end, end,
} }
if (altspr) s.spr = altspr if (altspr) s.spr = altspr
@ -1357,14 +1456,6 @@ function spawn_rnd(typ, blocking, goodie,altspr)
return s return s
end end
-- TODO: spawn_goodie compatible versions of gun drops
-- TODO: goodie table
function spawn_goodie(goodie_name, x, y, sz)
if (not goodie_name or #goodie_name == 0) return
local sh = sz and sz/2 or 0
_ENV[goodie_name].new{}:spawn_at(x+sh,y+sh)
end
function multi(times, interval, fnm, ...) function multi(times, interval, fnm, ...)
local f,irm,vargs = _ENV[fnm],interval,pack(...) local f,irm,vargs = _ENV[fnm],interval,pack(...)
assert(type(f) == "function", fnm.." not a function") assert(type(f) == "function", fnm.." not a function")
@ -1387,31 +1478,29 @@ end
-- where offset,eol is a special case. -- where offset,eol is a special case.
example_level_csv=[[1,spawn_frownie example_level_csv=[[1,spawn_frownie
60,spawn_bonus_vulcan_chasey 60,spawn_vulcan_chasey
61,spawn_blocky 61,spawn_blocky
85,spawn_spewy 85,spawn_spewy
100,spawn_spewy
115,spawn_spewy 115,spawn_spewy
130,spawn_bonus_frownie 130,spawn_frownie
145,spawn_spewy 145,spawn_frownie
200,spawn_bonus_shield_chasey 180,spawn_spewy
230,spawn_chasey
250,spawn_blocking_blocky 250,spawn_blocking_blocky
285,spawn_spec_gun_at,35,-11,blast_gun
310,spawn_blocking_blocky 310,spawn_blocking_blocky
310,spawn_blocking_blocky 310,spawn_blocking_blocky
310,spawn_blocking_blocky 310,spawn_blocking_blocky
311,spawn_frownie 311,spawn_frownie
350,spawn_main_gun_at,70,-11,protron_gun_p
401,spawn_frownie 401,spawn_frownie
420,spawn_blocking_frownie 420,spawn_blocking_frownie
430,spawn_bonus_vulcan_chasey 430,spawn_vulcan_chasey
450,spawn_frownie 450,spawn_frownie
465,spawn_bonus_frownie 465,spawn_frownie
480,spawn_chasey 480,spawn_chasey
500,multi,20,12,spawn_blocking_blocky 500,multi,20,12,spawn_blocking_blocky
501,spawn_bonus_frownie 501,spawn_frownie
620,spawn_blocking_blocky 620,spawn_blocking_blocky
630,spawn_bonus_shield_chasey 630,spawn_vulcan_chasey
720,spawn_blocking_boss_chasey 720,spawn_blocking_boss_chasey
721,eol]] 721,eol]]
@ -1499,143 +1588,286 @@ end
-->8 -->8
-- powerups -- powerups
powerup = mknew(bullet_base.new{ xp_gem = 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, dx = 0,
dy = 1.5, -- 0.75 after enemyspd dy = 0.75,
category = enemy_blt_cat, -- collides with player ship width=1, -- not used for spr but
height=1,-- bullet_base uses it
category = enemy_blt_cat,
damage = 0, 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"
-- todo: draw two sprites
-- on top of each other here
-- so all powerups can share
-- the "sheen" animation?
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 = { hurt = {
x_off = -2, x_off = -2,
y_off = -2, y_off = -2,
width = 12, width = 8,
height = 12 height = 8,
}, },
x_off = 4, x_off = 2,
y_off = 0, y_off = 2,
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) function xp_gem:draw()
repair.new():spawn_at(x, y) 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 end
shield_upgrade = mknew(repair.new{ -- todo: "magnetic" behavior
icon=52 -- when near player ship
})
function shield_upgrade:hitship(ship) function xp_gem:hitship(ship)
if (ship ~= primary_ship) return false if (ship ~= primary_ship) return false
primary_ship.maxshield += 1 primary_ship.xp += self.val
primary_ship.last_xp_frame = lframe
return true return true
end end
function spawn_shield_upgrade_at(x, y) -- small gems for 1, 5, 25
shield_upgrade.new():spawn_at(x,y) -- 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 end
gun_swap = mknew(powerup.new{ -->8
hurt = { -- upgrade options
x_off = -2,
y_off = -2, -- all these return
width = 16, -- a [2] of rearm_t:
height = 16 --
-- icon: sprite id
-- hdr: title text
-- body: text
-- action: callback
-- (method)
spec_gunt = {
protron_gun_p,
vulcan_gun_p,
blast_gun,
}
-- picks n random items from
-- tbl; permutes tbl, selected
-- items at end
function pick(tbl, n)
local ret, top={}, #tbl
for x=top,top-n,-1 do
local idx = 1+rnd(x)\1
add(ret, tbl[idx])
tbl[idx]=tbl[x]
tbl[x]=ret[#ret]
end
return ret
end
-- add a new gun
function spec_gun_opts()
return pick(spec_gunt, 2)
end
-- major upgrades
function big_opts()
return {{
icon=1,
hdr="placeholder",
body="placeholder",
action = function() end,
}, },
-- gun = gun_type.new{} {
x_off = 6, icon=1,
y_off = 0, hdr="placeholder",
width = 2, body="placeholder",
height = 2, action = function() end,
sprites = {64, 66, 68, 70, 72, 74, 76, 78}, }}
hitship = function(self, ship) end
if (ship ~= primary_ship) return false
ship.main_gun = self.gun -- ordinary upgrades
return true function small_opts()
return {{
icon=1,
hdr="placeholder",
body="placeholder",
action = function() end,
},
{
icon=1,
hdr="placeholder",
body="placeholder",
action = function() end,
}}
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, 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) crt={-91,-166,-2641,-1441,-23041,23295,-20491,24570}
if (type(gunt)=="string") gunt=_ENV[gunt]
local gun_p = gun_swap.new{ function rearm_mode:glow_box(x0, y0, x1, y1, c, cf)
gun = gunt.new(), for i,v in ipairs{c[1],c[2],c[1],0} do
hitship = function(self, ship) i -= 1
if (ship ~= primary_ship) return false rect(x0+i,y0+i,x1-i,y1-i,v)
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 end
} fillp(crt[self.crt_frm&0xff])
gun_p:spawn_at(x, y) rectfill(x0+4, y0+4, x1-4, y1-4, cf)
fillp()
end 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.icon,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
local lev = primary_ship.level + 1
if lev == 4 or lev == 12 then
self.options = spec_gun_opts()
elseif lev % 4 == 0 then
self.options = big_opts()
else
self.options = small_opts()
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
local specs = primary_ship.special_guns
if specs then
specs[1].ammo = specs[1].maxammo
if (specs[2]) specs[2].ammo = specs[2].maxammo
end
primary_ship.hp = min(primary_ship.maxhp, primary_ship.hp + primary_ship.maxhp/2)
primary_ship.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__ __gfx__
00000000000650000000000000000000bb0b50b59909209200cc0c00000000003b00000082000000e00e8002e00e800200333300002222000000000000000000 00000000000650000000000000000000bb0b50b59909209200cc0c00000000003b00000082000000e00e8002e00e800200333300002222000000000000000000
00000000006765000000000000cccc00b50b3055920940220c0000c000bbbb0037000000a2000000e0e8880240e8480403bbbb30028888200000000000000000 00000000006765000000000000cccc00b50b3055920940220c0000c000bbbb0037000000a2000000e0e8880240e8480403bbbb30028888200000000000000000
@ -1653,14 +1885,14 @@ __gfx__
000000005666657576667650000000000b0000b000000000000000000000000000000000000dd0009092220200000000c111111d656667650000000000000000 000000005666657576667650000000000b0000b000000000000000000000000000000000000dd0009092220200000000c111111d656667650000000000000000
0000000056565066665656500000000000bbbb0000000000000000000000000000000000000000000090020000000000c111111d650650650000000000000000 0000000056565066665656500000000000bbbb0000000000000000000000000000000000000000000090020000000000c111111d650650650000000000000000
00000000565000566500065000000000b000000b000000000000000000000000000000000000000000a00a0000000000cddddddd650000650000000000000000 00000000565000566500065000000000b000000b000000000000000000000000000000000000000000a00a0000000000cddddddd650000650000000000000000
000000000000000000000000000000000000000000a0008000000000000000000000000000000000000000000000000000000000000000000000000000000000 060007000600070006600770766c777c0000000000a0008000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000090008000000000000000000000000000000000000000000000000000000000000000000000000000000000 6cd07cd06cd07cd06ccd7ccd6ccd7ccd000000000090008000000000000000000000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000800a0000000000000000000000000000000000000000000000000000000000000000000000000000000000 0d000d006cd07cd06ccd7ccd6ccd7ccd0000000000800a0000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000080090000000000000000000000000000000000000000000000000000000000000000000000000000000000 000000000d000d000dd00dd0cdd1cdd0000000000080090000000000000000000000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000a080000000000000000000000000000000000000000000000000000000000000000000000000000000000 0600060006000600066006607667766c00000000000a080000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000009080000000000000000000000000000000000000000000000000000000000000000000000000000000000 67d06c7067d06c70677d6cc7677d6cc7000000000009080000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000 0d00070067d06c7067cd6cc767cd6cc7000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000 000000000d0007000dd007707dd1c771000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000cccccccccccccccc77000000007700000000770000000077000000000000000000000000000000000000000000000000 00000000000000000000000000000000cccccccccccccccc77000000007700000000770000000077000000000000000000000000000000000000000000000000
00000000000000000000000000000000c116611dc11ee11d70000000077000000007700000000770000000070000000000000000000000000000000000000000 00000000000000000000000000000000c116611dc11ee11d70000000077000000007700000000770000000070000000000000000000000000000000000000000
00000000000000000000000000000000c1611c1dc11ee11d00000000770000000077000000007700000000770000000700000000000000000000000000000000 00000000000000000000000000000000c1611c1dc11ee11d00000000770000000077000000007700000000770000000700000000000000000000000000000000
@ -1681,6 +1913,26 @@ c1111111111d0000c1111111111d0000c1111111111d0000c111eeee111d0000c11e2222e11d0000
c1111111111d0000c1111111111d0000c1111111111d0000c1111111111d0000c111eeee111d0000c1ee2222ee1d0000ce22111122ed0000c2111111112d0000 c1111111111d0000c1111111111d0000c1111111111d0000c1111111111d0000c111eeee111d0000c1ee2222ee1d0000ce22111122ed0000c2111111112d0000
c1111111111d0000c1111111111d0000c1111111111d0000c1111111111d0000c1111111111d0000c111eeee111d0000ceee2222eeed0000c2221111222d0000 c1111111111d0000c1111111111d0000c1111111111d0000c1111111111d0000c1111111111d0000c111eeee111d0000ceee2222eeed0000c2221111222d0000
cddddddddddd0000cddddddddddd0000cddddddddddd0000cddddddddddd0000cddddddddddd0000cddddddddddd0000cddddddddddd0000cddddddddddd0000 cddddddddddd0000cddddddddddd0000cddddddddddd0000cddddddddddd0000cddddddddddd0000cddddddddddd0000cddddddddddd0000cddddddddddd0000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
04444400044444440000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
447777700477777a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
477aaa7a0477aaaa0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
47a0047a047a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
47a0447a047a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
47a4477a047a44400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
477777a00477777a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
477770000422aaaa2222000200000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
47a77700022ee0002eeee002e00022e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
47a4777002ea2e002e002e02ee022ee0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
47a0477a22ea2e002e002e02e2e2e2e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
47a0047a2e2222e02e222e02e02e02e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
47a0047a2eeeeeea2eeee002e02e02e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
0aa000aa2e7aa2ea2e00e002e02e02e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
000000002e0002e02e002e02e02e02e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
000000000e0000e00e000e00e00e00e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
__label__ __label__
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007777777777777777 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007777777777777777
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007666666666666665 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007666666666666665