Compare commits

..

41 Commits

Author SHA1 Message Date
2507a3f218 Final tutorial improvements 2024-02-14 18:17:19 -08:00
89dcee996f Add better cover 2024-02-14 18:03:31 -08:00
55eb61825e Add a tips page 2024-02-14 17:51:57 -08:00
184ce112bd Fix a crash 2024-02-14 17:32:27 -08:00
c2a978e315 Grabbed cards float 2024-02-14 16:29:49 -08:00
93161c6465 Stacked moves 2024-02-14 15:55:00 -08:00
7f87814d35 Remove unused code 2024-02-14 14:10:19 -08:00
a7697fa1b2 Don't undo during restart animation 2024-02-13 19:15:19 -08:00
0912e90510 Change undo behavior
- Undo while holding a card drops it
- Undo can be redone
2024-02-13 19:09:35 -08:00
119155a903 Update rood 2024-02-12 17:50:38 -08:00
e3bc5a0dc6 Add content warning 2024-02-12 16:34:26 -08:00
dd46a76f54 Improve pickup/drop 2024-02-12 15:03:55 -08:00
ff1c59adf3 Add image to cart 2024-02-11 21:54:32 -08:00
2085ba5a63 Complete the rood 2024-02-11 21:53:19 -08:00
4747e297b4 Add sounds 2024-02-11 20:54:01 -08:00
bb2cfdd6af Add QOL features 2024-02-11 20:40:30 -08:00
3b9c61329b Add music manager 2024-02-11 20:18:01 -08:00
da41929613 Add some music 2024-02-11 20:12:49 -08:00
2cca0cd857 Don't show a menu on restart 2024-02-11 18:04:51 -08:00
6949abc2fb Final win screen! 2024-02-11 17:58:34 -08:00
4a61d8afd3 Archaeology feature 2024-02-11 17:28:41 -08:00
21d0ed432d Get rid of old unneeded file 2024-02-11 16:48:22 -08:00
172fd30ad0 Tiling menu 2024-02-11 16:48:11 -08:00
f30b7d6023 Misc bugfixes 2024-02-11 15:58:40 -08:00
343e4a2ea9 Cart data reset, excavate button 2024-02-11 15:51:56 -08:00
c4b11071e5 Add menu 2024-02-11 14:59:20 -08:00
cdaedc8be3 Improve a line of liturgy 2024-02-11 13:52:34 -08:00
1f8a937107 Add liturgy 2024-02-11 13:44:45 -08:00
a06ea160b2 Track whether the player hsa completed the tutorial 2024-02-10 22:19:54 -08:00
d7d91dd3a7 Restart menu 2024-02-10 22:01:05 -08:00
8b23695945 Restart level animation 2024-02-10 21:41:48 -08:00
b4f4b8cbb5 Improve layout 2024-02-10 21:02:31 -08:00
6998d614a9 Better board/cursor graphics 2024-02-10 20:56:48 -08:00
e184552458 Tutorial: improved 2024-02-10 20:40:12 -08:00
15e86c7940 Tutorial code 1 2024-02-10 19:42:38 -08:00
2ad6a0bc3a Add state manager and ironman mode 2024-02-10 17:44:38 -08:00
59de5962dc Use a seed list for level 7 2024-02-10 16:35:57 -08:00
917f50370b Undo feature 2024-02-09 22:35:55 -08:00
3508072c0e Card rotation 2024-02-09 22:17:57 -08:00
6a92341695 Remove shadows as a feature 2024-02-09 21:43:01 -08:00
94a410a587 Support multiple seed pools 2024-02-09 21:05:24 -08:00
49 changed files with 81138 additions and 346 deletions

2
.gitignore vendored
View File

@ -0,0 +1,2 @@
*.pyc
__pycache__/

106
board.lua
View File

@ -1,11 +1,15 @@
board=klass() board=klass()
function board:init(ruleset) function board:init(w)
local ruleset=w.ruleset
self.watcher=w
self.ruleset=ruleset self.ruleset=ruleset
self.cursor=cursor:new(self) self.cursor=cursor:new(self)
self.animator=animator:new() self.animator=animator:new()
self.checkpoint=nil
self.slots={} self.slots={}
self.wells={} self.wells={}
self.restart_progress=0
-- board slots -- board slots
-- ...n_slots: normal -- ...n_slots: normal
@ -18,11 +22,13 @@ function board:init(ruleset)
-- wells: -- wells:
-- ...n_suits: wands, cups, swords, pentacles, etc -- ...n_suits: wands, cups, swords, pentacles, etc
local function add_suit(_self,suit) local function add_suit(_self,suit)
add(_self.wells,well:new(_self.ruleset, function(lst,new) local w=well:new(_self.ruleset, function(lst,new)
assert(lst) -- the ace is always present initially assert(lst) -- the ace is always present initially
if (new.suit!=suit) return if (new.suit!=suit) return
return new.suit==suit and new.rank==lst.rank+1 return new.suit==suit and new.rank==lst.rank+1
end)) end)
w.obscured_by_extra_slot=true
add(_self.wells, w)
end end
for suit in all(self.ruleset.deck.suits) do for suit in all(self.ruleset.deck.suits) do
add_suit(self,suit) add_suit(self,suit)
@ -33,16 +39,29 @@ function board:init(ruleset)
if (not lst) return new.rank==0 if (not lst) return new.rank==0
return new.rank==lst.rank+1 return new.rank==lst.rank+1
end)) end))
self.wells[#self.wells].obscured_by_last_well=true
-- n_suits+2: arcana descending -- n_suits+2: arcana descending
add(self.wells,well:new(self.ruleset,function(lst,new) add(self.wells,well:new(self.ruleset,function(lst,new)
if (new.suit!='a') return if (new.suit!='a') return
if (not lst) return new.rank==self.ruleset.n_arcana-1 if (not lst) return new.rank==self.ruleset.n_arcana-1
return new.rank==lst.rank-1 return new.rank==lst.rank-1
end)) end))
self.wells[#self.wells].obscured_by_last_well=true
-- top arcana
add(self.wells,well:new(self.ruleset,function(lst,new)
local w1=self.wells[self.ruleset.n_suits+1]
local w2=self.wells[self.ruleset.n_suits+2]
if (#w1.contents + #w2.contents != self.ruleset.n_arcana-1) return
return new.suit=='a'
end))
local seed=seeds:choose(self.ruleset.pool) self:deal(w.seed or seeds:choose(self.ruleset.pool))
printh("chosen seed: "..tostr(seed,2)) end
self:deal(seeds:choose(self.ruleset.pool))
function board:get_endgame_card()
local last_arcana=self.wells[#self.wells]:peek()
if (last_arcana) return last_arcana
return self.last_card or 1
end end
function board:deal(seed) function board:deal(seed)
@ -65,24 +84,54 @@ function board:deal(seed)
end end
end end
function board:set_restart_progress(progress)
self.restart_progress=progress
end
function board:get_completion_level()
return self.ruleset.completion_level
end
function board:undo()
if (not self.checkpoint) return
if (not self.watcher:intercept("undo")) sounds:dire() return
sounds:menu()
local current_checkpoint=checkpoint:new(self,self.checkpoint.card)
self.checkpoint:apply(self)
self.checkpoint=current_checkpoint
end
function board:on_idle() function board:on_idle()
self:find_automove() self:find_automove()
end end
function board:pre_move(card)
self.checkpoint=checkpoint:new(self,card)
end
function board:on_move() function board:on_move()
-- TODO: Make checkpoint
self:find_automove() self:find_automove()
end end
function board:is_won()
if (not self:can_take_input()) return false
for s=1,#self.slots do
if (self.slots[s]:peek()) return false
end
return true
end
function board:find_automove() function board:find_automove()
for s=1,#self.slots do for s=1,#self.slots do
local top=self.slots[s]:peek() local top=self.slots[s]:peek()
if top then if top then
for w=1,#self.wells do for w=#self.wells,1,-1 do
if w<=self.ruleset.n_suits and self.slots[self.ruleset.n_slots+1]:peek()!=nil then if w<=self.ruleset.n_suits and self.slots[self.ruleset.n_slots+1]:peek()!=nil then
-- the top wells are blocked -- the top wells are blocked
elseif self.wells[w]:would_accept(top) then elseif self.wells[w]:would_accept(top) then
self.cursor:drop_grab_silent()
self:animate_and_move_to_well(s,w) self:animate_and_move_to_well(s,w)
self.last_card=top
return true return true
end end
@ -102,26 +151,40 @@ function board:update()
if (not was_idle and is_idle) then if (not was_idle and is_idle) then
self:on_idle() self:on_idle()
end end
if (is_idle) self.cursor:update()
end end
function board:draw() function board:draw()
local extra_slot_full=self.slots[self.ruleset.n_slots+1]:peek()!=nil
local last_well_full=self.wells[#self.wells]:peek()!=nil
for w_ix=1,#self.wells do for w_ix=1,#self.wells do
local w=self.wells[w_ix] local w=self.wells[w_ix]
local l=self.ruleset.layouts:well(w_ix) local l=self.ruleset.layouts:well(w_ix)
local shadowed=nil
if w.obscured_by_last_well and last_well_full then
shadowed=true
end
if w.obscured_by_extra_slot and extra_slot_full then
shadowed=true
end
for i=1,#w.contents do for i=1,#w.contents do
local x,y=l:place_card(i) local x,y=l:place_card(i)
self.ruleset.deck:draw_card(x,y,w.contents[i],i<#w.contents) self.ruleset.deck:draw_card(x,y,w.contents[i],{rotate=l.rotated,shadowed=shadowed})
end end
end end
local grabs={}
for s_ix in all(self.cursor.grabbed_slots) do
grabs[s_ix]=(grabs[s_ix] or 0)+1
end
local function forall_slots(cb) local function forall_slots(cb)
for s_ix=1,#self.slots do for s_ix=1,#self.slots do
local s=self.slots[s_ix] local s=self.slots[s_ix]
local l=self.ruleset.layouts:slot(s_ix) local l=self.ruleset.layouts:slot(s_ix)
local n=#s.contents local n=#s.contents-(grabs[s_ix] or 0)
if (self.cursor.grabbed==s_ix) n-=1
cb(x,y,s_ix,s,l,n) cb(x,y,s_ix,s,l,n)
end end
@ -130,21 +193,29 @@ function board:draw()
forall_slots(function(x,y,s_ix,s,l,n) forall_slots(function(x,y,s_ix,s,l,n)
for i=1,n do for i=1,n do
local x,y=l:place_card(i) local x,y=l:place_card(i)
self.ruleset.deck:draw_card(x,y,s.contents[i],i<n) self.ruleset.deck:draw_card(x,y,s.contents[i],{rotate=l.rotated})
end end
end) end)
if self.checkpoint then
local cpl=self.ruleset.layouts:checkpoint()
local x,y=cpl:place_card(0)
self.ruleset.deck:draw_card(x,y,self.checkpoint.card,{shadowed=true})
end
self.animator:draw() self.animator:draw()
if self.animator:idle() then if self.animator:idle() then
self.watcher:draw(self)
local hover_slot=self.cursor:hover_slot() local hover_slot=self.cursor:hover_slot()
forall_slots(function(x,y,s_ix,s,l,n) forall_slots(function(x,y,s_ix,s,l,n)
if hover_slot==s_ix then if hover_slot==s_ix then
local x,y=l:place_card(n+1) self.cursor:draw_at(l,n)
self.cursor:draw_at(x,y)
end end
end) end)
end end
democrap:distort_screen(self.restart_progress)
end end
slot=klass() slot=klass()
@ -166,8 +237,8 @@ end
function slot:add(card) function slot:add(card)
add(self.contents,card) add(self.contents,card)
end end
function slot:peek() function slot:peek(depth)
return self.contents[#self.contents] return self.contents[#self.contents-(depth or 0)]
end end
function slot:pop() function slot:pop()
return deli(self.contents,#self.contents) return deli(self.contents,#self.contents)
@ -192,4 +263,7 @@ function well:add(card)
end end
function well:clear() function well:clear()
self.contents={} self.contents={}
end
function well:peek()
return self.contents[#self.contents]
end end

View File

@ -55,13 +55,13 @@ function board:_animate_move_card(card,on_end,start_x,start_y,compute_end)
if (frame==0) end_x,end_y=compute_end() if (frame==0) end_x,end_y=compute_end()
frame+=1 frame+=1
progress=frame/7 progress=frame/7
if (progress>=1.0) on_end() return false if (progress>=1.0) sounds:deal_card() on_end() return false
return true return true
end end
function anim_obj:draw() function anim_obj:draw()
local x=start_x+(end_x-start_x)*progress local x=start_x+(end_x-start_x)*progress
local y=start_y+(end_y-start_y)*progress local y=start_y+(end_y-start_y)*progress
_self.ruleset.deck:draw_card(x,y,card,false) _self.ruleset.deck:draw_card(x,y,card,{})
end end
self.animator:add(anim_obj) self.animator:add(anim_obj)

40
checkpoint.lua Normal file
View File

@ -0,0 +1,40 @@
checkpoint=klass()
function checkpoint:init(board,card)
self.card=card
self.slots={}
self.wells={}
for s=1,#board.slots do
local cnt={}
for c in all(board.slots[s].contents) do
add(cnt,c)
end
self.slots[s]=cnt
end
for w=1,#board.wells do
local cnt={}
for c in all(board.wells[w].contents) do
add(cnt,c)
end
self.wells[w]=cnt
end
end
function checkpoint:apply(board)
for s=1,#board.slots do
while #board.slots[s].contents>0 do
deli(board.slots[s].contents)
end
for i in all(self.slots[s]) do
add(board.slots[s].contents,i)
end
end
for w=1,#board.wells do
while #board.wells[w].contents>0 do
deli(board.wells[w].contents)
end
for i in all(self.wells[w]) do
add(board.wells[w].contents,i)
end
end
board.cursor:drop_grab()
end

67
completion_tracker.lua Normal file
View File

@ -0,0 +1,67 @@
completion_tracker={}
add(modules,completion_tracker)
function completion_tracker:init()
cartdata("pyrex_fortunesfoundation_1")
end
function completion_tracker:reset()
for i=0,63 do
if (i!=59) dset(i,0) -- don't clear music pref flag
end
end
function completion_tracker:get_metascore()
local b0=dget"60"
local b1=dget"61"
local b2=dget"62"
local b3=dget"63"
return (b0<<8)+b1+(b2>>8)+(b3>>16)
end
function completion_tracker:incr_metascore()
local ms=self:get_metascore()
ms+=0x0.0001
dset(60,(ms>>8)&0xff)
dset(61,(ms)&0xff)
dset(62,(ms<<8)&0xff)
dset(63,(ms<<16)&0xff)
end
function completion_tracker:get_completion_level()
return dget(0)
end
function completion_tracker:advance_completion_level(clevel)
dset(0,max(dget(0), clevel))
end
function completion_tracker:get_music_preference()
return dget(59)==0
end
function completion_tracker:set_music_preference()
if (dget(59)==0) dset(59,1) return
dset(59,0)
end
-- TODO: Bitfield instead
function completion_tracker:mark_seen(text_id)
local ix,bit=self:_unpack_text_id(text_id)
dset(ix,dget(ix)|bit)
end
function completion_tracker:was_seen(text_id)
local ix,bit=self:_unpack_text_id(text_id)
return dget(ix)&bit !=0
end
function completion_tracker:_unpack_text_id(text_id)
assert(text_id>0)
assert(text_id<120) -- max 120 texts for now
-- using bytes 1 through 15
local ix,bit=1+text_id\8,text_id%8
assert(ix<16)
return ix,1<<bit
end
function completion_tracker:should_show_tutorial()
return self:get_completion_level() < tutorial.completion_stage
end

BIN
cover.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

View File

@ -10,16 +10,18 @@ function cursor:init(board)
self.board=board self.board=board
self.hover_x=self.ruleset.n_slots\2 self.hover_x=self.ruleset.n_slots\2
self.hover_y=1 self.hover_y=1
self.grabbed=nil self.saved_hover_x_y=nil
self.grabbed_slots={}
end end
function cursor:acceptance_state() function cursor:acceptance_state()
if self.grabbed then local hover=self:hover_slot()
local hover=self:hover_slot() local slot=self:grabbed_slot()
if hover==self.grabbed then if slot then
if hover==slot then
return acceptance_state.no_move return acceptance_state.no_move
end end
local source=self.board.slots[self.grabbed] local source=self.board.slots[slot]
local target=self.board.slots[self:hover_slot()] local target=self.board.slots[self:hover_slot()]
local card=source:peek() local card=source:peek()
if target:would_accept(card) then if target:would_accept(card) then
@ -28,35 +30,115 @@ function cursor:acceptance_state()
return acceptance_state.would_not_accept return acceptance_state.would_not_accept
end end
else else
return acceptance_state.not_grabbed if (self.board.slots[hover]:peek()) return acceptance_state.not_grabbed
return acceptance_state.would_not_accept
end end
end end
function cursor:save_hover()
self.saved_hover_x_y={self.hover_x,self.hover_y}
end
--[[
function cursor:restore_hover()
self.wants_to_restore_hover=true
end
]]
--[[
function cursor:actually_restore_hover()
if (not self.saved_hover_x_y) return
-- self.wants_to_restore_hover=false
-- try restoring hover x
local old_hover_x,old_hover_y=self.hover_x,self.hover_y
self.hover_x,self.hover_y=unpack(self.saved_hover_x_y)
-- try very hard to be in a valid spot
for i in all{
function() self.hover_x,self.hover_y=old_hover_x,old_hover_y end,
function() self:move_x(-1) end,
function() self:move_y(1) end,
function() self:move_x(-1) end,
function() self:move_y(-1) end
} do
if (self:acceptance_state()!=acceptance_state.would_not_accept) return
i()
end
end
]]--
function cursor:toggle_grab() function cursor:toggle_grab()
local acc,src,tar=self:acceptance_state() local acc,src,tar=self:acceptance_state()
local slot=self:hover_slot()
if acc==acceptance_state.not_grabbed then if acc==acceptance_state.not_grabbed then
if (self.board.slots[self:hover_slot()]:peek()) self.grabbed=self:hover_slot() if (not self.board.watcher:intercept("grab",slot)) sounds:dire() return
if (self.board.slots[slot]:peek()) self.grabbed_slots={slot}
self:save_hover()
sounds:menu()
elseif acc==acceptance_state.would_accept then elseif acc==acceptance_state.would_accept then
local card=src:pop() if (not self.board.watcher:intercept("drop",slot)) sounds:dire() return
tar:add(card) self.board:pre_move(src:peek())
self.grabbed=nil while self:acceptance_state() == acceptance_state.would_accept do
self.board:on_move(card) local card=src:pop()
tar:add(card)
deli(self.grabbed_slots)
end
self.grabbed_slots={}
self.board:on_move()
-- if (#self.grabbed_slots == 0) self:restore_hover()
sounds:menu()
elseif acc==acceptance_state.no_move or acc==acceptance_state.would_not_accept then elseif acc==acceptance_state.no_move or acc==acceptance_state.would_not_accept then
self.grabbed=nil self:drop_grab()
else else
assert(false,"invalid acceptance state") assert(false,"invalid acceptance state")
end end
end end
function cursor:incr_grab()
local slot=self:hover_slot()
if (slot!=self:grabbed_slot()) return
if (not self.board.watcher:intercept("incr_grab",slot)) sounds:dire() return
local new_card = self.board.slots[slot]:peek(#self.grabbed_slots)
if (not new_card) return
local old_card = self.board.slots[slot]:peek(#self.grabbed_slots-1)
if (not self:_can_incr_grab(old_card,new_card)) return
add(self.grabbed_slots,slot)
sounds:menu()
end
function cursor:drop_grab_silent()
self.grabbed_slots={}
end
function cursor:drop_grab()
if (not self.board.watcher:intercept("cancel")) sounds:dire() return
self.grabbed_slots={}
-- self:restore_hover()
sounds:menu()
end
function cursor:update()
-- if (self.wants_to_restore_hover) self:actually_restore_hover()
end
function cursor:move_x(dx) function cursor:move_x(dx)
if (self.hover_y==0) return if (self.hover_y==0) return
self.hover_x+=dx if (dx==0) return
self.hover_x%=self.ruleset.n_slots -- TODO: Don't hard-code local orig_x=self.hover_x
while true do
self.hover_x+=dx
self.hover_x%=self.ruleset.n_slots
if (self.hover_x==orig_x) return
if (self:acceptance_state()!=acceptance_state.would_not_accept) return true
end
return
end end
function cursor:move_y(dy) function cursor:move_y(dy)
local old_y=self.hover_y
if (self.hover_y==0 and dy==1) self.hover_y=1 if (self.hover_y==0 and dy==1) self.hover_y=1
if (self.hover_y==1 and dy==-1) self.hover_y=0 if (self.hover_y==1 and dy==-1 and #self.grabbed_slots<2) self.hover_y=0
if (self:acceptance_state()==acceptance_state.would_not_accept) if (not self:move_x(-1)) self.hover_y=old_y
end end
function cursor:hover_slot() function cursor:hover_slot()
@ -64,29 +146,42 @@ function cursor:hover_slot()
return self.hover_x+1 return self.hover_x+1
end end
function cursor:grabbed_slot()
return self.grabbed_slots[#self.grabbed_slots]
end
function cursor:grabbed_card() function cursor:grabbed_card()
if self.grabbed then local grabbed_slot=self:grabbed_slot()
local slot=self.board.slots[self.grabbed] if grabbed_slot then
return slot:peek() return self.board.slots[grabbed_slot]:peek()
end end
return nil
end end
function cursor:draw_at(x,y) function cursor:draw_at(l,i)
local card=self:grabbed_card() local slot=self:grabbed_slot()
local acc=self:acceptance_state()
if card and acc!=acceptance_state.would_accept and acc!=acceptance_state.no_move then if not slot then
x+=sin(time()/2)*2+0.5 local filled=false
y+=sin(time()/4)+0.5+1 if (i<1) i=1 filled=true
draw_layout_hint(l,i,12,filled)
return
end end
if card then local not_moving=self:acceptance_state()==acceptance_state.no_move
local card_fg=self.ruleset.deck:draw_card(x,y,card,false) for i2=1,#self.grabbed_slots do
local ix=i2-1
if (not_moving) ix=#self.grabbed_slots-i2
local card=self.board.slots[slot]:peek(ix)
local x,y=l:place_card(i+i2+1)
local card_fg=self.ruleset.deck:draw_card(x,y,card,{rotate=l.rotated})
local fg=card_fg local fg=card_fg
if (acc==acceptance_state.would_accept) fg=9 if (i2==1) draw_layout_hint(l,i+i2+1,9,false)
if (fg) rect(x-1,y-1,x+9,y+16,fg)
else
rectfill(x,y,x+8,y+15,9)
end end
end
function cursor:_can_incr_grab(c0,c1)
c0=self.board.ruleset.deck.cards[c0]
c1=self.board.ruleset.deck.cards[c1]
if (c0.suit!=c1.suit) return false
return c0.rank==c1.rank+1 or c1.rank==c0.rank+1
end end

35
democrap.lua Normal file
View File

@ -0,0 +1,35 @@
democrap={
patterns={
0b1111111111111111,
0b1111111111111111,
0b1111111111111111,
0b1111111111111111,
0b1111111111111111,
0b1111111111111111,
0b1111111111111111,
0b1111111111111100,
0b1111111111110000,
0b1111110011110000,
0b1111000011110000,
0b1111000011000000,
0b1111000000000000,
0b1100000000000000,
0b0000000000000000
}
}
function democrap:distort_screen(progress)
if (progress <= 0) return
progress=min(progress,1)
for src=0x6004,0x7fc4,64 do
dst=src+sin(t()+src/0x800)*(4*progress)+0.5
memcpy(dst,src,56)
end
local ps=democrap.patterns
local p=ps[1+flr(progress*#ps)] or ps[#ps]
fillp(p)
local old=@0x5333
poke(0x5f33,1)
rectfill(0,0,127,127,13)
poke(0x5f33,old)
fillp()
end

View File

@ -2,7 +2,6 @@
modules={} modules={}
function _init() function _init()
-- printh("restarting")
_doall("init") _doall("init")
end end
@ -33,43 +32,10 @@ function klass()
return k return k
end end
function alives(tbl) function gsv(s)
local tbl2={}
for i in all(tbl) do
if (not i.dead) add(tbl2,i)
end
return tbl2
end
function trunc4(x)
if (x < 0) return -trunc4(-x)
return x\0.25/4
end
function stepstep(by,x0,x1,f)
local x=x0
if (x==x1) return
if x0>x1 then
return stepstep(by,-x0,-x1,function(x) return f(-x) end)
end
x=x\by*by
while true do
x+=by
if (x>=x1) f(x1) break
if (not f(x)) break
end
end
function lerp(x,x0,x1)
return x0+x*(x1-x0)
end
function csv(s)
local ret=split(s,"\n") local ret=split(s,"\n")
for i,v in ipairs(ret) do for i,v in ipairs(ret) do
ret[i] = type(v) == "string" and split(v) or {v} end ret[i] = type(v) == "string" and split(v,"`") or {v} end
return ret return ret
end end

View File

@ -1,6 +1,7 @@
layout_mode={ layout_mode={
obscured=0, -- for wells obscured=0, -- for wells
vertical=1, -- for conventional slots vertical=1, -- for conventional slots
rotated=2,
-- todo: sideways -- todo: sideways
} }
@ -9,10 +10,13 @@ function layout:init(x,y,mode)
self.x=x self.x=x
self.y=y self.y=y
self.mode=mode self.mode=mode
if (mode==layout_mode.rotated) self.rotated=true
if (mode!=layout_mode.vertical) self.obscured=true
end end
function layout:place_card(i) function layout:place_card(i)
if (self.mode==layout_mode.obscured) return self.x,self.y if (self.mode==layout_mode.obscured) return self.x,self.y
if (self.mode==layout_mode.rotated) return self.x,self.y
if (self.mode==layout_mode.vertical) return self.x,self.y+(i-1)*6 if (self.mode==layout_mode.vertical) return self.x,self.y+(i-1)*6
assert(false,"unexpected mode: "..self.mode) assert(false,"unexpected mode: "..self.mode)
end end

37
layout_hint.lua Normal file
View File

@ -0,0 +1,37 @@
function draw_layout_hint(l,i,fg,filled,tut_border)
-- layout, index
local x,y=l:place_card(i)
if (l.obscured) filled=false
if filled then
if l.rotated then
rectfill(x-3,y+7,x+12,y+15,fg)
else
rectfill(x,y,x+8,y+15,fg)
end
else
if tut_border then
local exclude=1+flr(time()*3)%3
pal(1,14)
pal(2,14)
pal(3,14)
palt(13,true)
pal(exclude,13)
if l.rotated then
spr(32,x-5,y+5,3,2)
else
-- rect(x-3,y-3,x+11,y+18,13)
spr(14,x-2,y-2,2,3)
end
pal()
palt()
return
end
if l.rotated then
rect(x-4,y+6,x+13,y+16,fg)
else
rect(x-1,y-1,x+9,y+16,fg)
end
end
end

151
liturgy.lua Normal file
View File

@ -0,0 +1,151 @@
liturgy={
holy_book=gsv[[rood 1`1,2,3
rood 2`4,5,6,7
rood 3`8,9,10
rood 4`11,12,13
rood 5`14,15,16,17,18
rood 6`19,20
rood 7`21,22,23
rood 8`24,25,26]],
sacred_text_lines=gsv
[[1`one meerkat, one day
1`stood on two legs. it said:
1`'come into this thicket.
1` i have a bright wreath.
1` my laurel is vibrant.'
2`all sweet things tolerated,
2`those who came when called
2`were sheared of their fur.
2`this was the first day:
2`the dandelions blown.
3`the hollow,
3`which opens to a key: music.
3`the meerkats were led there.
3`where they stood.
4`now even the water
4`knows how to talk.
4`their leader, first to stand,
4`calls them to choir.
5`a dulcimer's sweet harmony and,
5`pretending to weep,
5`it announces the title of
5`a scroll: 'the fate.'
6`now they are a regiment.
6`gather them.
6`pour oil.
7`catching a leaf, ride it.
7`suture its veins.
7`scatter glass in the vineyard.
8`lanias came in silver.
8`he milled the wheat and barley.
8`he took oranges from the trees.
8`meerkats dashed to the ferns.
8`he raised his bow and screamed.
9`the bolt became the wind.
9`the silver sails lashed.
9`the silver ospreys swarmed.
9`the silver shadow wailed.
10`burning oil from bay to sky.
10`scampering keas in bags!
10`there was no one in the field.
10`lanias came and went in silver.
11`ravens are an old people.
11`but the mandate is new.
11`the spry one turns in the egg.
12`it reads 'the fate':
12`'man is woman'
12`'a house in heaven
12` is bought on earth.'
12`and not by hatching.
13`the egg turns. it cracks.
13`a meerkat tumbles out.
13`cold, it breathes its last.
14`when lanias drags down stars
14`in his net, he cannot
14`take down one: beauty.
15`he cannot envy the vain,
15`so lanias wrote this rood:
15`the vain will not have it.
16`no longer is 'the fate':
16`there are many fates.
16`the music is over now.
16`it is quiet in the garden.
17`where are you? a small bird,
17`divine. you are in the fences.
17`you are seedling, little one.
17`the gorgeous lily blooms.
18`a star in the sky shines
18`and you are born.
18`accept its blessing: caw,
18`do not sing.
19`you have your room.
19`i have mine.
19`let's dig a river,
19`and build a bridge.
20`let's dig a trap.
20`let's line it with spikes.
20`let's cover it with a sheet,
20`and bury it in soil.
21`a cuckoo stole an egg.
21`in the nest it left its young.
21`the summer was so lean
21`and the snow so deep.
22`it was plump as a berry
22`and it hatched.
22`meerkats were in the trees.
23`lanias said: old men suffer
23`and die for nothing. listen:
23`when you grow: you won't
23`understand it. you want what
23`you cannot have.
24`night is here.
24`you're asleep.
24`you leave this body.
24`you won't want to come back.
25`cross your eyes: 'the fate'
25`is in them, their tears,
25`their music, their silence.
26`our rood is the final one.
26`those we killed have been
26`planted like seeds. this rood,
26`like this city, will not
26`be destroyed.]]
}
function liturgy:init()
local verse_lines={}
for line in all(self.sacred_text_lines) do
local verse=tonum(line[1])
if (not verse_lines[verse]) verse_lines[verse]={}
add(verse_lines[verse], line[2])
end
local annotated_verses={}
for bookdata in all(self.holy_book) do
local name=bookdata[1]
local ix=1
for verse in all(split(bookdata[2])) do
local annotated_verse_name=name
local lines=verse_lines[verse]
annotated_verse_name..=":"..ix.."-"
ix+=#lines
annotated_verse_name..=ix-1
local annotated_verse=""
for l in all(lines) do
if (annotated_verse!="") annotated_verse..="\n"
annotated_verse..=l
end
annotated_verses[verse]={annotated_verse_name,annotated_verse}
end
end
self.annotated_verses=annotated_verses
end
liturgy:init()
function liturgy:suggest_verse(ruleset,card)
local meta=ruleset.deck.cards[card]
local i=2+meta.rank
if (meta.suit!="a") i=ruleset.preferred_verse or i
return i, unpack(liturgy.annotated_verses[i])
end

View File

@ -3,36 +3,23 @@ add(modules,main)
function main:init() function main:init()
extcmd("rec") extcmd("rec")
self.board=board:new(progression[1]) self.state_manager=state_manager:new() -- instantiate one global
self.state_manager:push(state_menu:new())
--[[
local b=board:new(watcher:new(progression[#progression],1,{}))
b.last_card=75
self.state_manager:push(state_wonround:new(b))
]]--
if (completion_tracker:should_show_tutorial()) self.state_manager:push(state_ironman:new(tutorial)) self.state_manager:push(state_content_warning:new())
end end
function main:update() function main:update()
self.board:update() self.state_manager:update()
if self.board:can_take_input() then
if (btnp(0)) self.board.cursor:move_x(-1)
if (btnp(1)) self.board.cursor:move_x(1)
if (btnp(2)) self.board.cursor:move_y(-1)
if (btnp(3)) self.board.cursor:move_y(1)
if (btnp(4)) self.board.cursor:toggle_grab()
end
end end
function main:draw() function main:draw()
cls(13) self.state_manager:draw()
self.board:draw() apply_palette()
-- bg
pal(13,-3,1)
-- arcana
-- pal(1,0,1)
pal(15,-9,1)
-- suits
pal(4,-11,1) -- first suit
pal(12,12,1)
pal(2,-8,1)
pal(3,-5,1)
-- pal(8,-9,1)
-- pal(14,8,1)
end end

546
main.p8
View File

@ -1,170 +1,416 @@
pico-8 cartridge // http://www.pico-8.com pico-8 cartridge // http://www.pico-8.com
version 41 version 41
__lua__ __lua__
-- raven's rood
-- by pyrex and nyeo
#include engine.lua #include engine.lua
#include palette.lua
#include animator.lua #include animator.lua
#include board.lua #include board.lua
#include board_animations.lua #include board_animations.lua
#include checkpoint.lua
#include completion_tracker.lua
#include dealer.lua #include dealer.lua
#include democrap.lua
#include cursor.lua #include cursor.lua
#include layout.lua #include layout.lua
#include layout_hint.lua
#include liturgy.lua
#include music_manager.lua
#include ruleset.lua #include ruleset.lua
#include palette.lua
#include progression.lua #include progression.lua
#include seed_constants.lua #include seed_constants.lua
#include seeds.lua #include seeds.lua
#include sounds.lua
#include state_archaeology.lua
#include state_content_warning.lua
#include state_excavate_menu.lua
#include state_manager.lua
#include state_menu.lua
#include state_gameround.lua
#include state_ironman.lua
#include state_reset_menu.lua
#include state_wonironman.lua
#include state_wonround.lua
#include tutorial.lua
#include text.lua
#include watcher.lua
#include main.lua #include main.lua
--[[
srand(2)
for i=1,10 do
print(tostr(rnd(),2))
end
stop()]]
__gfx__ __gfx__
00000000000000000000000000000000777770000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000077777000000000000000000000000000000000000000000000000000000000000000000000000000ddddddddddddd000
00000000007000000777000000070000700070000707070000000000000000000000000000000000000000000000000000000000000000000000000000000000 0000000000700000077700000007000070007000070707000000000000000000000000000000000000000000000000000000000000000000d31231231231d000
07070000007000000777000000700000707070000077770000000000000000000000000000000000000000000000000000000000000000000000000000000000 0707000000700000077700000070000070707000007777000000000000000000000000000000000000000000000000000000000000000000d20000000002d000
00700000007000000777000000700000707070000770700000000000000000000000000000000000000000000000000000000000000000000000000000000000 0070000000700000077700000070000070707000077070000000000000000000000000000000000000000000000000000000000000000000d10000000003d000
07070000077700000070000007000000777070000077777000000000000000000000000000000000000000000000000000000000000000000000000000000000 0707000007770000007000000700000077707000007777700000000000000000000000000000000000000000000000000000000000000000d30000000001d000
00000000007000000777000007000000700070000700777000000000000000000000000000000000000000000000000000000000000000000000000000000000 0000000000700000077700000700000070007000070077700000000000000000000000000000000000000000000000000000000000000000d20000000002d000
00000000000000000000000000000000707770000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000070777000000000000000000000000000000000000000000000000000000000000000000000000000d10000000003d000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d30000000001d000
00000000000000000000000000000000000000000000000000000000000070000000700000007000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000007000000070000000700000000000000000000000000000000000d20000000002d000
00000000000070000000700000700070007000700070007000700070007000700070007000700070070707000707070007070700000000000000000000000000 0000000000007000000070000070007000700070007000700070007000700070007000700070007007070700070707000707070000000000d10000000003d000
00000000000000000000000000000000000000000000000000000000000070000000700000007000007777000077770000777700000000000000000000000000 0000000000000000000000000000000000000000000000000000000000007000000070000000700000777700007777000077770000000000d30000000001d000
00007000000000000000700000000000000070000070007000707070000000000070007000700070077070000770700007707000000000000000000000000000 0000700000000000000070000000000000007000007000700070707000000000007000700070007007707000077070000770700000000000d20000000002d000
00000000000000000000000000000000000000000000000000000000000070000000000000007000007777700077777000777770000000000000000000000000 0000000000000000000000000000000000000000000000000000000000007000000000000000700000777770007777700077777000000000d10000000003d000
00000000000070000000700000700070007000700070007000700070007000700070007000700070070077700700777007007770000000000000000000000000 0000000000007000000070000070007000700070007000700070007000700070007000700070007007007770070077700700777000000000d30000000001d000
00000000000000000000000000000000000000000000000000000000000070000000700000007000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000007000000070000000700000000000000000000000000000000000d20000000002d000
0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d10000000003d000
dddddddddddddddddddd00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d30000000001d000
d123123123123123123d00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d20000000002d000
d300000000000000001d00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d13213213213d000
d200000000000000002d00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ddddddddddddd000
d100000000000000003d000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
d300000000000000001d000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
d200000000000000002d000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
d100000000000000003d000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
d300000000000000001d000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
d200000000000000002d000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
d100000000000000003d000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
d321321321321321321d000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
dddddddddddddddddddd000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 fffffffff000000000000000000000000000000000000ff00000000000000000000000a000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 0ff0000fff00000000000000000000000000000000000ff00000000000fff000900009aa0000a000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 0ff00000ff000ffff00ffff00fff00ffff000ff0fff00f00fffff000000fff00999009aa00aaa000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 0ff0000ff000f000ff00ff0000f00f000ff0ffff00ff000ff000f00000fff000099999aaaaaa0000000000000000000000000000000000000000000770000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 0ff0fff000000000ff00ff0000f0ff000ff00ff000ff000ff000000000000000099999aaaaaa0000000000000000000000000000000000000000777700000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 0ff00ff000000fffff000ff00f00fffffff00ff000ff000ffff0000000000000099999aaaaaa0000000000000000000000000000000000000777777700000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 0ff000ff0000f000ff000ff00f00ff0000000ff000ff00000ffff00000000000009999aaaaa00000000000000000000000000000000000007777777700000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 0ff0000ff00ff000ff0000f0f000ff0000000ff000ff0000000ff00000000000009999aaaaa00000000000000000000000000000000000777777777000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 0ff00000ff0ff00fff0000fff0000ff000f00ff000ff000f000ff000000000000000000000000000000000000000000000000000000007777777700000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 ffff0000fff0fff0fff0000f000000ffff00ffff00fff00fffff0000000000000000000000000000000000000000000000000000000077777777000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000777777770000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 fffffffff0000000000000000000000000fff0000000000000000000000000000000000000000000000000000000000000000000007777777700000dd0000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 0ff0000fff0000000000000000000000000ff000000000000000000000000000000000000000000000000000000000000000000000777777700000ddd0000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 0ff00000ff000ffff00000ffff00000fff0ff0000000000000000000000000000000000000000000000000000000000000000000077777770000dddddd000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 0ff0000ff000ff00ff000ff00ff000ff00fff00000000000000000000000000000000000000000000000000000000000000000000777777700ddddddd0000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 0ff0fff0000ff0000ff0ff0000ff0ff0000ff0000000000000000000000000000000000000000000000000000000000000000000777777770ddddddd00000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 0ff00ff0000ff0000ff0ff0000ff0ff0000ff0000000000000000000000000000000000000000000000000000000000000000000777777777dddddd000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 0ff000ff000ff0000ff0ff0000ff0ff0000ff000000000000000000000000000000000000000000000000000000000000000000077777777dddddd0000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 0ff0000ff00ff0000ff0ff0000ff0ff0000ff000000000000000000000000000000000000000000000000000000000000000000077777777ddddd00000777000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 0ff00000ff00ff00ff000ff00ff000ff00fff000000000000000000000000000000000000000000000000000000000000000000077777777dddd000007777770
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 ffff0000fff00ffff00000ffff00000fff0fff0000000000000000000000000000000000000000000000000000000000000000077777777dddd0000077777777
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000777777dd7ddd7770777777700
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000777777d7777777777777777000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007777777777777777777777777000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000777777777777777777777777777700
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007777777777777777777770000777700
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000077707777777777777777000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000077777777777777777770000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000077777777777777777770000700000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000077770000007777777700000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000077700000000077770000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000070000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 c9311100fc009820e4509a50ca603c90a3a009a0d5b00dd055f027215d21a531e531d6319831e8317931277132a5120a007276821161320416d14631d331e862
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 7462511341324319b5779502eb05d82194423941818023885111644669aa2a169110a1561bb28201632467214103762f4812302241975603a9799117a3111c31
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 54224678216131332299517613113822a1a81b2191451b9d4a12444e2146331121146b18a623a1212143b4414461930716662c10145931ca52421046d1d46453
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 e285625e10d0416a445310369c1d2d7a2210b4211365372a523145221379e432bc1f2343132211370354624605c7135214298212a65197288711ef6c10155410
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 2c023d63b2113522c6311131a711c2a23d1225273cc7c29b131364b26426e319811152a15f72b15a1c968691342059612724f532114262315793231026100223
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 e71b1831203ac658400341618db534033046726b64398c48116104050184601409453c11302421261347612b1131431a21385ba8204483115178622001227391
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 12161520248c8131276695811852091625941e250592543263163b098e7033340202485337d4c474719812a1e151946ff9354a543261203d82811352d0750ff4
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 62e13078413345221a4093473d592e235275d2f067b11349521811063506406626048503b21f19932271e447917243136a9118433c0c1b1b00126c523d552811
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 b3b090a138154420832f1c2b359214132417364e4b602d7684137112b0190343a05954d117631421672111324410805550316535815351443515515512135301
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 85032431522303a45b403c0aa0360f5944347b0018170a1312011307511c2075829964331301088305c86241754c071719a68aa302a962944fa20393c3e726a6
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 308b36804a7013505043247423215f30f77413244003620624034405a12c02347070330103b0d524535c21cbd1187013311316c161583180b01250f8a9230865
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 2817329c22012551c2746157071abd696554091183b5453222346324005c7a502274729035031320a54610a134145270606923d2624887d45601017bcf92a570
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 c08002538065a37722d440060430371f7796b901314fc00040caa73b9d670a016c26305a67795c32f67a3c48bd372e664136e003442a036e6a48009d460a8413
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 333005a15c122125feb24a024641a930649018e06af40613c6df323df0922136c0b3a628a9704887eb465f103eb312113a71d6132681ec5314660112a592500a
a45b403c0aa0360f5944347b0018170a1312011307511c2075829964331301088305c86241754c071719a68aa302a962944fa20393c3e726a6308b36804a7013 7332050b1100222133bf841ad2e08531151212008b1b93269808f6e7084bf509645c4d17e5381030d09a21374097e7205833281b4968b2d257805070cb23f660
505043247423215f30f77413244003620624034405a12c02347070330103b0d524535c21cbd1187013311316c161583180b01250f8a92308652817329c220125 123a8961d0221799c4a3543235608e61c082461387e3a08112422243124c95b80527b4c70297bb53111112ae012101701d57021a33baa5320a75220703e67316
51c2746157071abd696554091183b5453222346324005c7a502274729035031320a54610a134145270606923d2624887d45601017bcf92a570c08002538065a3 450a470811222f2407132570675cad8466b089c6ae8b1cd63445254321211112211225171902cc2f52b3431a96e0621a0b320810118847210217302c829172a9
7722d440060430371f7796b901314fc00040caa73b9d670a016c26305a67795c32f67a3c48bd372e664136e003442a036e6a48009d460a8413333005a15c1221 142e81471a1222151012109139251e01535f3f60d066309689f475500ac31f0c51550fb2c040636116072bb95c3c20623312d15802729e11a786361023556504
25feb24a024641a930649018e06af40613c6df323df0922136c0b3a628a9704887eb465f103eb312113a71d6132681ec5314660112a592500a7332050b110022 1e05d8111027902303bb6766a35d19634125255536468126950ed0511d2004a869600b03606008402c423631430234c82143b431911ad813080730a56952dff8
2133bf841ad2e08531151212008b1b93269808f6e7084bf509645c4d17e5381030d09a21374097e7205833281b4968b2d257805070cb23f660123a8961d02217 d930c0710f9c591560411e195885ab12a47046a513355330834851127111b0b01223b425a03700713fd455012919b962ea2204803297512905048b60e0070b10
99c4a3543235608e61c082461387e3a08112422243124c95b80527b4c70297bb53111112ae012101701d57021a33baa5320a75220703e67316450a470811222f db28d95d0413346413616371255f16bc72123662020571218053d29a0a08d5614cb03218e4202307a3331121072003208b5216380484d071152504157a34646b
2407132570675cad8466b089c6ae8b1cd63445254321211112211225171902cc2f52b3431a96e0621a0b320810118847210217302c829172a9142e81471a1222 93320421067bfd71328140448aa00003916fb823a42960baf06050bbbc50802215d3247720e254ada00e824740640b1d220134900a865163575c651d12fb3a51
151012109139251e01535f3f60d066309689f475500ac31f0c51550fb2c040636116072bb95c3c20623312d15802729e11a7863610235565041e05d811102790 42e10402804018d34432745132241ea1144102343936850621e24e38478403732882714b6095a00a8bc12563fb29a95124622b191e132d71031028233188cff2
2303bb6766a35d19634125255536468126950ed0511d2004a869600b03606008402c423631430234c82143b431911ad813080730a56952dff8d930c0710f9c59 b6054c5a50022006461bb07141bd203519449c4a7b81059519e186332206a601080782219753433271d3f7a60bb0325500dcd0320a4f425263a0635103119131
1560411e195885ab12a47046a513355330834851127111b0b01223b425a03700713fd455012919b962ea2204803297512905048b60e0070b10db28d95d041334 a6c114220d483c22692c1f36d0a4e4b650a574d52035129d6043a71416f190d044201e640d9361a28795850d841420008330235203565132f09c1062b314c011
6413616371255f16bc72123662020571218053d29a0a08d5614cb03218e4202307a3331121072003208b5216380484d071152504157a34646b93320421067bfd 001302148260794433210066db20e7d4243c00363044503221a9a248028275163032437db731156197323b110083556bc6882b62120145932723c41014172050
71328140448aa00003916fb823a42960baf06050bbbc50802215d3247720e254ada00e824740640b1d220134900a865163575c651d12fb3a5142e10402804018 2110607096341b040253269c334a9ad729304c593a6541c8512542d252305530103c61142f64d7d884937139a6082c8af4436d472012b2a520dc2401b055ce74
d34432745132241ea1144102343936850621e24e38478403732882714b6095a00a8bc12563fb29a95124622b191e132d71031028233188cff2b6054c5a500220 72750d2a334f5002c529bd7c0950635919c19f7b339d700061121604392031118b4550112932e89603008cd0fb931925c5c25b110a43460d23941436924a2020
06461bb07141bd203519449c4a7b81059519e186332206a601080782219753433271d3f7a60bb0325500dcd0320a4f425263a0635103119131a6c114220d483c 77044914a618d2411e3341031101c5e0f0127719125212545515771b9b1db33070001903110033333c01032c3265162f30010b00d3232022416e5a6625a391e0
22692c1f36d0a4e4b650a574d52035129d6043a71416f190d044201e640d9361a28795850d841420008330235203565132f09c1062b314c01100130214826079 736112b0030131a33e106330c444a849058741a02733922393921f0230f2e645234d441b84f20ae452222723d363f2c0a0230136181d550c1054542190004072
4433210066db20e7d4243c00363044503221a9a248028275163032437db731156197323b110083556bc6882b62120145932723c410141720502110607096341b 371d4e130691530b905062ea1b1831348050161007723cbf05e0122080c4030533b1396114221153345021058405d139924e92ad06010105e0452a8c0b703116
040253269c334a9ad729304c593a6541c8512542d252305530103c61142f64d7d884937139a6082c8af4436d472012b2a520dc2401b055ce7472750d2a334f50 f0342005c6645162110200c314070a144300ca63855bc1be01cb9326008aeb0a2bc12e0fcb2120d13c806494815a00b2a2048007195e54f49f9a1bda72163953
02c529bd7c0950635919c19f7b339d700061121604392031118b4550112932e89603008cd0fb931925c5c25b110a43460d23941436924a202077044914a618d2 e4b55516013e0117a030e8e9009dc461a41017a8de92072403ff12724200356739323429133a3131030ae919a118c38268a569e604609027e6d12511e1d1005f
411e3341031101c5e0f0127719125212545515771b9b1db33070001903110033333c01032c3265162f30010b00d3232022416e5a6625a391e0736112b0030131 235661d08a66420101913aeb58522a65c9ab7108b412d5315940519305310d5e83a39a0621605902354212014ab3ce24e0276205201da9d25322db8158e0e533
a33e106330c444a849058741a02733922393921f0230f2e645234d441b84f20ae452222723d363f2c0a0230136181d550c1054542190004072371d4e13069153 501c733deb2b6582032123367845157b8203031329616024114326763031c67207e61b1489f1114603909b3c320200775856471002965c31007f4393c0339104
0b905062ea1b1831348050161007723cbf05e0122080c4030533b1396114221153345021058405d139924e92ad06010105e0452a8c0b703116f0342005c66451 33505033001c5984070b4404312f550d8caa4271887618b24c141401141266c2277005a2483e931a24844542112793c3321009f7657185617119015e70300490
62110200c314070a144300ca63855bc1be01cb9326008aeb0a2bc12e0fcb2120d13c806494815a00b2a2048007195e54f49f9a1bda72163953e4b55516013e01 21154661a246d566a51123ec45154031a14727580101433190b05309382063244766e0c0226217503bc02064936f032241d81650511057171f2150044f213b2e
17a030e8e9009dc461a41017a8de92072403ff12724200356739323429133a3131030ae919a118c38268a569e604609027e6d12511e1d1005f235661d08a6642 0015a38c243680ab3010b466481db267510761c2073003b10640243926b0d90ad4600429f4134323130114132d435c4793621a6823fa402629e1806045135b3f
0101913aeb58522a65c9ab7108b412d5315940519305310d5e83a39a0621605902354212014ab3ce24e0276205201da9d25322db8158e0e533501c733deb2b65 5818112091025a1cf83438cf042533381708106085ca79020210f55003c06020c49848d20503c6363f7c9c22b32c7b3b1878752222a40235c1c2b14211647f20
82032123367845157b8203031329616024114326763031c67207e61b1489f1114603909b3c320200775856471002965c31007f4393c033910433505033001c59 fd51b5b067c2672604670f173da221902fc232269007651016f335274e02e3117ca6b341230d75011062b2318619531730a6117d0373b36509292c0541894509
84070b4404312f550d8caa4271887618b24c141401141266c2277005a2483e931a24844542112793c3321009f7657185617119015e7030049021154661a246d5 68133141c1162519883316235530007105f02314791a01789012050c740b010649696124b1d9032b0c0720002a065c9005105f018d4038a17751006954418031
66a51123ec45154031a14727580101433190b05309382063244766e0c0226217503bc02064936f032241d81650511057171f2150044f213b2e0015a38c243680 1c4706247018197059d63554287564a047bd9950e732c14f54a6000529070b24850d07200bd70c41b910c31d47a516d353e06f179262831975015958350d3673
ab3010b466481db267510761c2073003b10640243926b0d90ad4600429f4134323130114132d435c4793621a6823fa402629e1806045135b3f5818112091025a 088f55721440f37026505f3ad2527235bafc335b0098035d138016c174031131100f445e48359829326a09225332136c105f455032720f3d44419d36a1992113
1cf83438cf042533381708106085ca79020210f55003c06020c49848d20503c6363f7c9c22b32c7b3b1878752222a40235c1c2b14211647f20fd51b5b067c267 032eec61831447772809a792545913677b4371a877796c6889264a50119462f21f812291e2014390815078140047a9947008e0c04056628323530064650372a6
2604670f173da221902fc232269007651016f335274e02e3117ca6b341230d75011062b2318619531730a6117d0373b36509292c054189450968133141c11625 1457c623857aa953a9204033200112353841122a6e302401a32f15432d4013abf436474330056605c404c203724428e5674062403d34112f18010bd0e592916c
19883316235530007105f02314791a01789012050c740b010649696124b1d9032b0c0720002a065c9005105f018d4038a177510069544180311c470624701819 903dc8560379500963008c803f0293932a5e51c20b072148c512262b43313104d25024589451b058802c1841a0b8270b5e26631812671c11c112d10e036b5426
7059d63554287564a047bd9950e732c14f54a6000529070b24850d07200bd70c41b910c31d47a516d353e06f179262831975015958350d3673088f55721440f3 5454171427a0627542720a0601caaf273804730a30522111a952078e747641627573704c2a5400e01056145a2e32f78676232d26450b251e0122e41f23405c95
7026505f3ad2527235bafc335b0098035d138016c174031131100f445e48359829326a09225332136c105f455032720f3d44419d36a1992113032eec61831447 8804600d10455491625709a60196f0c064058d9e08493d8235ba39651a2270531a2488a78f8b64a2231744a5d602a151e3570080513385731e0e111381713211
772809a792545913677b4371a877796c6889264a50119462f21f812291e2014390815078140047a9947008e0c04056628323530064650372a61457c623857aa9 d0a3b419c6a5b321960bf53736235130011060a60b6130cf0740d02623371061122b0b534203b0e25ea1142535276f95a104a1215e30d9a986f06cc1a102940f
53a9204033200112353841122a6e302401a32f15432d4013abf436474330056605c404c203724428e5674062403d34112f18010bd0e592916c903dc856037950 2650208b0cd04712478de7de3090c730504d10602c021027703a2ca90517d200a010910530952ae7016861d4771215c179b4415d75011800242382101763d381
0963008c803f0293932a5e51c20b072148c512262b43313104d25024589451b058802c1841a0b8270b5e26631812671c11c112d10e036b54265454171427a062 001400106532047336e0035a17802eb329002522210400747e76730e6c90450450e3a13da5620322c2222b0132a810451c9c25f7030278f24830113651ea1436
7542720a0601caaf273804730a30522111a952078e747641627573704c2a5400e01056145a2e32f78676232d26450b251e0122e41f23405c958804600d104554 0862331d411164f4d3295a634022c3aba1357001210e97a22e92278142a024f428351f32101f756a317403268d31755712811374d5122834b921b3c40d10241f
91625709a60196f0c064058d9e08493d8235ba39651a2270531a2488a78f8b64a2231744a5d602a151e3570080513385731e0e111381713211d0a3b419c6a5b3 ee0a126a64581825a1d55000186c218507281030124af1277320570775768c19d3472120ed02354318d105e4006d5009e5ff413b83e92008b04a28028075bf3a
21960bf53736235130011060a60b6130cf0740d02623371061122b0b534203b0e25ea1142535276f95a104a1215e30d9a986f06cc1a102940f2650208b0cd047 c3e4f850c139624f5f50ea324fb344364186a4353a218a0b92031555100b3220b223cd363370400077d3317921a42e21618b4b80641e904b11703b8153b0620a
12478de7de3090c730504d10602c021027703a2ca90517d200a010910530952ae7016861d4771215c179b4415d75011800242382101763d38100140010653204 b00247d001403aba700a3b007243401f64164418a02304d6b03e394d601060f751614681301c8487413905019331570124d500c91833315f025be0707208e706
7336e0035a17802eb329002522210400747e76730e6c90450450e3a13da5620322c2222b0132a810451c9c25f7030278f24830113651ea14360862331d411164 a4a37409bb540c40000c320db304c953f1176063aa48613172e632832a049452806011b07054d23e09b340d032110c557a0c29247e191298c4770d4304422411
f4d3295a634022c3aba1357001210e97a22e92278142a024f428351f32101f756a317403268d31755712811374d5122834b921b3c40d10241fee0a126a645818 5053864571060e00766473701905322a148177154ce13230963323000062502063e891168081a7911003750054042a745834a70b80d1147ad551a37c14465a54
25a1d55000186c218507281030124af1277320570775768c19d3472120ed02354318d105e4006d5009e5ff413b83e92008b04a28028075bf3ac3e4f850c13962 fa1da3a42c14300b02d04505c8f103471874735968bb1cd203743347342fd27240c1b613504750648c426c016021707720c683d21133a05c2412045914071344
4f5f50ea324fb344364186a4353a218a0b92031555100b3220b223cd363370400077d3317921a42e21618b4b80641e904b11703b8153b0620ab00247d001403a 03ae02b36c8c514251261327004c729e0c3b328012e5011d6b854332683d0910a0002639144b901b0300211a613433c05b4630153bf3e30b23172d2023440a05
ba700a3b007243401f64164418a02304d6b03e394d601060f751614681301c8487413905019331570124d500c91833315f025be0707208e706a4a37409bb540c 9c01b3275426f023383a370375496c0760039d00f8d25101f4809032302198261111202ace6ac100543264641289340f1634390cac2f204ad300548641a5086d
40000c320db304c953f1176063aa48613172e632832a049452806011b07054d23e09b340d032110c557a0c29247e191298c4770d43044224115053864571060e 11333409b448400d3111694b3d464b62e17460311442855d05cd3704923e9d0770707c0132109b399428a8146012d7a5043207d64e03fd1126742b0167456035
00766473701905322a148177154ce13230963323000062502063e891168081a7911003750054042a745834a70b80d1147ad551a37c14465a54fa1da3a42c1430 00113043464471777326217676060195001268be8381430c862a1c2b0265a4234a69635140318597cb49370643550c2a314e33781b490095f73245600a00de12
0b02d04505c8f103471874735968bb1cd203743347342fd27240c1b613504750648c426c016021707720c683d21133a05c241204591407134403ae02b36c8c51 041497c80550a4701604144259018e4314582680b0bb8a28b4061216010d3063521c666031d4460d1412012e2547030e2389252b19e9da341623912035220923
4251261327004c729e0c3b328012e5011d6b854332683d0910a0002639144b901b0300211a613433c05b4630153bf3e30b23172d2023440a059c01b3275426f0 220d61f5d10673575950d15619fb7355715a214d604411ab425c28017fa0069204b0663402432027a2205515603021b5012178664215329112a53b219206035f
23383a370375496c0760039d00f8d25101f4809032302198261111202ace6ac100543264641289340f1634390cac2f204ad300548641a5086d11333409b44840 __label__
0d3111694b3d464b62e17460311442855d05cd3704923e9d0770707c0132109b399428a8146012d7a5043207d64e03fd1126742b016745603500113043464471 5555gggggggggggggggggg55555555555555555555555555555555555555gggggggg55gggggg5555555555555555gggggggggggggggggggggggggggggggggggg
777326217676060195001268be8381430c862a1c2b0265a4234a69635140318597cb49370643550c2a314e33781b490095f73245600a00de12041497c80550a4 5555gggggggggggggggggg55555555555555555555555555555555555555gggggggg55gggggg5555555555555555gggggggggggggggggggggggggggggggggggg
701604144259018e4314582680b0bb8a28b4061216010d3063521c666031d4460d1412012e2547030e2389252b19e9da341623912035220923220d61f5d10673 55gggggggggggggggggggg55555555gggggggggggg5555555555555555gggggggggggggggg5555555555555555gggggggggg5555gggggggggggggggggggggg55
575950d15619fb7355715a214d604411ab425c28017fa0069204b0663402432027a2205515603021b5012178664215329112a53b219206035f3c10116e562c1b 55gggggggggggggggggggg55555555gggggggggggg5555555555555555gggggggggggggggg5555555555555555gggggggggg5555gggggggggggggggggggggg55
810f50bb51811900008920109036a46044a566fa5c3d75f2930d101b41033e6e718450e5f32d36072531f1022065d01546295b20f09900200b200f125f060105 gggggggggg555555gggggg555555gggggggggggggggggg55555555gggggggggggggggggggg55555555555555gggggggggg555555gggggggggggggggggg555555
320bd2021354bd12376d4391020cb46909a21392d066d219e072259f0c554057d6f02b893514531a4a873080f05063001516435231229200a15d50aab311e82b gggggggggg555555gggggg555555gggggggggggggggggg55555555gggggggggggggggggggg55555555555555gggggggggg555555gggggggggggggggggg555555
2f4c3353942ab36526425316135b3894161e224530243321900532352125720229f25b6e63272685339f70b62724ac734dfb9539aa81104f7c43c6125303a0b0 gggggggg555555555555gg55gggggggggggggggggggggggggggggggggggggggggggggggg55555555555555gggggggg555555555555gggggggggggggg55555555
26c576b4123535e13346510610016436b311015422250811770250d4a3f86291acde02513d9541811164981402046f2351d5331390f538664452a09411464591 gggggggg555555555555gg55gggggggggggggggggggggggggggggggggggggggggggggggg55555555555555gggggggg555555555555gggggggggggggg55555555
1923e750019b705151701c1633b06eb064015121181cb6b1414b1120e03d715118259963471fa8151bb5a2502492222a910611365306ee6fa1a43015d227e65b gggggg5555555555555555gggggggggggggggggggggggggggggggggggggggggggggggggg55555555555555gggg55555555555555gggggggggggggg555555gg55
407033404721f0c019292341e5e8206104601ed1574d21e8ca05171a04320ed862140210590a090430985c1289011804206a049a71f054016463335440135936 gggggg5555555555555555gggggggggggggggggggggggggggggggggggggggggggggggggg55555555555555gggg55555555555555gggggggggggggg555555gg55
02c6202303351c50f3406fb0a1004610142f161400b481df8b740f3617bafb033c64f26562057017c58400d5a13a2320210631b361f2a1029211268166226207 55gg55555555555555gggggggggggggggggg5555gggggggggggggggggggggggggggggg5555555555555555gg55555555555555gggggggggggggggg5555555555
013285caa12003604001110f152c7671a80f8e743406d0505156083235037931dd020107a700781e2bf6dc081266341019e61cee2698eb259d0759c481710139 55gg55555555555555gggggggggggggggggg5555gggggggggggggggggggggggggggggg5555555555555555gg55555555555555gggggggggggggggg5555555555
255c14601869861492306742b03a2f060513a1211130042a0575301102220c20d30a5458c01554312484223950410b463035e232a58773710174065266239d2a 5555555555555555gggggggggggggg55555555gggggggggggggggggggggggggggggggg555555555555555555555555555555gggggggggggggggggg5555555555
5555555555555555gggggggggggggg55555555gggggggggggggggggggggggggggggggg555555555555555555555555555555gggggggggggggggggg5555555555
5555555555555555gggggggg55555555555555gggggggggggggggggggggggggggggggg5555555555555555555555555555gggggggggggggggggggg55555555gg
5555555555555555gggggggg55555555555555gggggggggggggggggggggggggggggggg5555555555555555555555555555gggggggggggggggggggg55555555gg
555555555555555555gggg5555555555555555gggggggggggggggggggggggggggggggg55555555555555555555555555gggggggggg555555gggggg555555gggg
555555555555555555gggg5555555555555555gggggggggggggggggggggggggggggggg55555555555555555555555555gggggggggg555555gggggg555555gggg
55gggggggg55555555555555555555555555gggggggggggggggggggggggggggggggggg555555555555555555555555gggggggggg555555555555gg55gggggggg
55gggggggg55555555555555555555555555gggggggggggggggggggggggggggggggggg555555555555555555555555gggggggggg555555555555gg55gggggggg
gggggggggggggggg5555555555555555gggggggggggggggggggggggggggggggggggg555555555555555555555555gggggggggg5555555555555555gggggggggg
gggggggggggggggg5555555555555555gggggggggggggggggggggggggggggggggggg555555555555555555555555gggggggggg5555555555555555gggggggggg
gggggggggggggg5555555555555555gggggggggggggggggggggggggggggggggggggg555555555555555555555555555555gg55555555555555gggggggggggggg
gggggggggggggg5555555555555555gggggggggggggggggggggggggggggggggggggg555555555555555555555555555555gg55555555555555gggggggggggggg
gggg55gggggg5555555555555555gggggggggggggggggggggggggggggggggggggg5555555555555555555555555555555555555555555555gggggggggggggg55
gggg55gggggg5555555555555555gggggggggggggggggggggggggggggggggggggg5555555555555555555555555555555555555555555555gggggggggggggg55
gggggggggg5555555555555555gggggggggg5555gggggggggggggggggggggg55555555555555555555555555555555555555555555555555gggggggg55555555
gggggggggg5555555555555555gggggggggg5555gggggggggggggggggggggg55555555555555555555555555555555555555555555555555gggggggg55555555
gggggggggg55555555555555gggggggggg555555gggggggggggggggggg55555555555555555555555555555555555555555555555555555555gggg5555555555
gggggggggg55555555555555gggggggggg555555gggggggggggggggggg55555555555555555555555555555555555555555555555555555555gggg5555555555
gggggggg55555555555555gggggggg555555555555gggggggggggggg555555555555555555555555555555555555555555gggggggg5555555555555555555555
gggggggg55555555555555gggggggg555555555555gggggggggggggg555555555555555555555555555555555555555555gggggggg5555555555555555555555
gggggggg55555555555555gggg55555555555555gggggggggggggg555555gg55555555555555555555555555555555gggggggggggggggggg5555555555555555
gggggggg55555555555555gggg55555555555555gggggggggggggg555555gg55555555555555555555555555555555gggggggggggggggggg5555555555555555
gggggg5555555555555555gg55555555555555gggggggggggggggg55555555555555555555555555555555555555gggggggggggggggggg5555555555555555gg
gggggg5555555555555555gg55555555555555gggggggggggggggg55555555555555555555555555555555555555gggggggggggggggggg5555555555555555gg
gggggg555555555555555555555555555555gggggggggggggggggg55555555555555555555555555555555555555gggggggg55gggggg5555555555555555gggg
gggggg555555555555555555555555555555gggggggggggggggggg55555555555555555555555555555555555555gggggggg55gggggg5555555555555555gggg
gggggg5555555555555555555555555555gggggggggggggggggggg55555555gggggggggggg5555555555555555gggggggggggggggg5555555555555555gggggg
gggggg5555555555555555555555555555gggggggggggggggggggg55555555gggggggggggg5555555555555555gggggggggggggggg5555555555555555gggggg
gggggg55555555555555555555555555gggggggggg555555gggggg555555gggggggggggggggggg55555555gggggggggggggggggggg55555555555555gggggggg
gggggg55555555555555555555555555gggggggggg555555gggggg555555gggggggggggggggggg55555555gggggggggggggggggggg55555555555555gggggggg
gggggg555555555555555555555555gggggggggg555555555555gg55gggggggggggggggggggggggggggggggggggggggggggggggg55555555555555gggggggg55
gggggg555555555555555555555555gggggggggg555555555555gg55gggggggggggggggggggggggggggggggggggggggggggggggg55555555555555gggggggg55
gggg555555nnnnnnnnnnnnnnnnnngggggggggg5555555555555555ggggggggggggggggggggggggggggggggggggggggggggggnnnn55555555555555gggg555555
gggg555555nnnnnnnnnnnnnnnnnngggggggggg5555555555555555ggggggggggggggggggggggggggggggggggggggggggggggnnnn55555555555555gggg555555
gggg55555555nnnn55555555nnnnnn5555gg55555555555555gggggggggggggggggg5555ggggggggggggggggggggggggggggnnnn55555555555555gg55555555
gggg55555555nnnn55555555nnnnnn5555gg55555555555555gggggggggggggggggg5555ggggggggggggggggggggggggggggnnnn55555555555555gg55555555
gg5555555555nnnn5555555555nnnn555555nnnnnnnn5555nnnnnnnnggggnnnnnn5555nnnnnnnnggggggnnnnggnnnnnnggggnn5555nnnnnnnnnn555555555555
gg5555555555nnnn5555555555nnnn555555nnnnnnnn5555nnnnnnnnggggnnnnnn5555nnnnnnnnggggggnnnnggnnnnnnggggnn5555nnnnnnnnnn555555555555
555555555555nnnn55555555nnnn555555nn555555nnnn55ggnnnngg555555nn5555nnggggggnnnnggnnnnnnnnggggnnnngggg55nnnn555555nn555555555555
555555555555nnnn55555555nnnn555555nn555555nnnn55ggnnnngg555555nn5555nnggggggnnnnggnnnnnnnnggggnnnngggg55nnnn555555nn555555555555
555555555555nnnn55nnnnnn555555555555555555nnnn5555nnnn55555555nn55nnnnggggggnnnnggggnnnnggggggnnnngggg55nnnn55555555555555555555
555555555555nnnn55nnnnnn555555555555555555nnnn5555nnnn55555555nn55nnnnggggggnnnnggggnnnnggggggnnnngggg55nnnn55555555555555555555
555555555555nnnn5555nnnn5555555555ggnnnnnnnnnn555555nnnn5555nn5555nnnnnnnnnnnnnnggggnnnnggggggnnnngggg55nnnnnnnn55555555555555gg
555555555555nnnn5555nnnn5555555555ggnnnnnnnnnn555555nnnn5555nn5555nnnnnnnnnnnnnnggggnnnnggggggnnnngggg55nnnnnnnn55555555555555gg
555555555555nnnn555555nnnn5555ggggnnggggggnnnngg5555nnnn5555nn55ggnnnnggggggggggggggnnnnggggggnnnngg55555555nnnnnnnn55555555gggg
555555555555nnnn555555nnnn5555ggggnnggggggnnnngg5555nnnn5555nn55ggnnnnggggggggggggggnnnnggggggnnnngg55555555nnnnnnnn55555555gggg
555555555555nnnn55555555nnnnggggnnnnggggggnnnn55555555nn55nn55ggggnnnnggggggggggggggnnnnggggggnnnngg555555555555nnnn555555555555
555555555555nnnn55555555nnnnggggnnnnggggggnnnn55555555nn55nn55ggggnnnnggggggggggggggnnnnggggggnnnngg555555555555nnnn555555555555
555555555555nnnn5555555555nnnnggnnnn55ggnnnnnn55555555nnnnnnggggggggnnnnggggggnnggggnnnnggggggnnnn555555nn555555nnnn555555555555
555555555555nnnn5555555555nnnnggnnnn55ggnnnnnn55555555nnnnnnggggggggnnnnggggggnnggggnnnnggggggnnnn555555nn555555nnnn555555555555
ggggggggggnnnnnnnn55555555nnnnnnggnnnnnnggnnnnnn55555555nngggggggggg55nnnnnnnnggggnnnnnnnnggggnnnnnn5555nnnnnnnnnn55555555555555
ggggggggggnnnnnnnn55555555nnnnnnggnnnnnnggnnnnnn55555555nngggggggggg55nnnnnnnnggggnnnnnnnnggggnnnnnn5555nnnnnnnnnn55555555555555
gggggggggggggg55555555gggggggggggggggggggg55555555555555gggggggggg555555gggggggggggggggggg55555555555555555555555555555555555555
gggggggggggggg55555555gggggggggggggggggggg55555555555555gggggggggg555555gggggggggggggggggg55555555555555555555555555555555555555
ggggggggggnnnnnnnnnnnnnnnnnngggggggggggg55555555555555gggggggg555555555555ggggnnnnnngggg5555555555555555555555555555555555555555
ggggggggggnnnnnnnnnnnnnnnnnngggggggggggg55555555555555gggggggg555555555555ggggnnnnnngggg5555555555555555555555555555555555555555
ggggggggggggnnnnggggggggnnnnnngggggggggg55555555555555gggg55555555555555ggggggggnnnngg555555gg55555555555555555555555555555555gg
ggggggggggggnnnnggggggggnnnnnngggggggggg55555555555555gggg55555555555555ggggggggnnnngg555555gg55555555555555555555555555555555gg
gggg5555ggggnnnnggggggggggnnnnggggggnnnnnnnn5555555555nnnnnnnn55555555ggnnnnnnggnnnngg55555555555555555555555555555555555555gggg
gggg5555ggggnnnnggggggggggnnnnggggggnnnnnnnn5555555555nnnnnnnn55555555ggnnnnnnggnnnngg55555555555555555555555555555555555555gggg
555555ggggggnnnnggggggggnnnnggggggnnnn5555nnnn555555nnnn5555nnnn5555ggnnnnggggnnnnnngg55555555555555555555555555555555555555gggg
555555ggggggnnnnggggggggnnnnggggggnnnn5555nnnn555555nnnn5555nnnn5555ggnnnnggggnnnnnngg55555555555555555555555555555555555555gggg
555555ggggggnnnnggnnnnnnggggggggnnnngg555555nnnn55nnnn55555555nnnnggnnnnggggggggnnnngg55555555gggggggggggg5555555555555555gggggg
555555ggggggnnnnggnnnnnnggggggggnnnngg555555nnnn55nnnn55555555nnnnggnnnnggggggggnnnngg55555555gggggggggggg5555555555555555gggggg
555555ggggggnnnnggggnnnnggggggggnnnngg555555nnnn55nnnn55555555nnnnggnnnngg555555nnnngg555555gggggggggggggggggg55555555gggggggggg
555555ggggggnnnnggggnnnnggggggggnnnngg555555nnnn55nnnn55555555nnnnggnnnngg555555nnnngg555555gggggggggggggggggg55555555gggggggggg
5555ggggggggnnnnggggggnnnnggggggnnnngg555555nnnn55nnnn55555555nnnnggnnnn55555555nnnngg55gggggggggggggggggggggggggggggggggggggggg
5555ggggggggnnnnggggggnnnnggggggnnnngg555555nnnn55nnnn55555555nnnnggnnnn55555555nnnngg55gggggggggggggggggggggggggggggggggggggggg
ggggggggggggnnnnggggggggnnnnggggnnnn55555555nnnn55nnnn555555ggnnnnggnnnn55555555nnnn55gggggggggggggggggggggggggggggggggggggggggg
ggggggggggggnnnnggggggggnnnnggggnnnn55555555nnnn55nnnn555555ggnnnnggnnnn55555555nnnn55gggggggggggggggggggggggggggggggggggggggggg
ggggggggggggnnnnggggggggggnnnnggggnnnn5555nnnn555555nnnn5555nnnn55gg55nnnn5555nnnnnngggggggggggggggg5555gggggggggggggggggggggggg
ggggggggggggnnnnggggggggggnnnnggggnnnn5555nnnn555555nnnn5555nnnn55gg55nnnn5555nnnnnngggggggggggggggg5555gggggggggggggggggggggggg
ggggggggggnnnnnnnnggggggggnnnnnngg55nnnnnnnn5555555555nnnnnnnn5555555555nnnnnn55nnnnnngggggggg55555555gggggggggggggggggggggggggg
ggggggggggnnnnnnnnggggggggnnnnnngg55nnnnnnnn5555555555nnnnnnnn5555555555nnnnnn55nnnnnngggggggg55555555gggggggggggggggggggggggggg
gggg5555gggggggggggggggggggggg55555555555555555555555555555555555555555555555555gggggggg55555555555555gggggggggggggggggggggggggg
gggg5555gggggggggggggggggggggg55555555555555555555555555555555555555555555555555gggggggg55555555555555gggggggggggggggggggggggggg
gg555555gggggggggggggggggg55555555555555555555555555555555555555555555555555555555gggg5555555555555555gggggggggggggggggggggggggg
gg555555gggggggggggggggggg55555555555555555555555555555555555555555555555555555555gggg5555555555555555gggggggggggggggggggggggggg
5555555555gggggggggggggg555555555555555555555555555555555555555555gggggggg55555555555555555555555555gggggggggggggggggggggggggggg
5555555555gggggggggggggg555555555555555555555555555555555555555555gggggggg55555555555555555555555555gggggggggggggggggggggggggggg
55555555gggggggggggggg555555gg55555555555555555555555555555555gggggggggggggggggg5555555555555555gggggggggggggggggggggggggggggggg
55555555gggggggggggggg555555gg55555555555555555555555555555555gggggggggggggggggg5555555555555555gggggggggggggggggggggggggggggggg
555555gggggggggggggggg55555555555555555555555555555555555555gggggggggggggggggg5555555555555555gggggggggggggggggggggggggggggggggg
555555gggggggggggggggg55555555555555555555555555555555555555gggggggggggggggggg5555555555555555gggggggggggggggggggggggggggggggggg
5555gggggggggggggggggg55555555555555555555555555555555555555gggggggg55gggggg5555555555555555gggggggggggggggggggggggggggggggggggg
5555gggggggggggggggggg55555555555555555555555555555555555555gggggggg55gggggg5555555555555555gggggggggggggggggggggggggggggggggggg
55gggggggggggggggggggg55555555gggggggggggg5555555555555555gggggggggggggggg5555555555555555gggggggggg5555gggggggggggggggggggggg55
55gggggggggggggggggggg55555555gggggggggggg5555555555555555gggggggggggggggg5555555555555555gggggggggg5555gggggggggggggggggggggg55
gggggggggg555555gggggg555555gggggggggggggggggg55555555gggggggggggggggggggg55555555555555gggggggggg555555gggggggggggggggggg555555
gggggggggg555555gggggg555555gggggggggggggggggg55555555gggggggggggggggggggg55555555555555gggggggggg555555gggggggggggggggggg555555
gggggggg555555555555gg55gggggggggggggggggggggggggggggggggggggggggggggggg55555555555555gggggggg555555555555gggggggggggggg55555555
gggggggg555555555555gg55gggggggggggggggggggggggggggggggggggggggggggggggg55555555555555gggggggg555555555555gggggggggggggg55555555
gggggg5555555555555555gggggggggggggggggggggggggggggggggggggggggggggggggg55555555555555gggg55555555555555gggggggggggggg555555gg55
gggggg5555555555555555gggggggggggggggggggggggggggggggggggggggggggggggggg55555555555555gggg55555555555555gggggggggggggg555555gg55
55gg55555555555555gggggggggggggggggg5555gggggggggggggggggggggggggggggg5555555555555555gg55555555555555gggggggggggggggg5555555555
55gg55555555555555gggggggggggggggggg5555gggggggggggggggggggggggggggggg5555555555555555gg55555555555555gggggggggggggggg5555555555
5555555555555555gggggggggggggg55555555gggggggggggggggggggggggggggggggg555555555555555555555555555555gggggggggggggggggg5555555555
5555555555555555gggggggggggggg55555555gggggggggggggggggggggggggggggggg555555555555555555555555555555gggggggggggggggggg5555555555
5555555555555555gggggggg55555555555555gggggggggggggggggggggggggggggggg5555555555555555555555555555gggggggggggggggggggg55555555gg
5555555555555555gggggggg55555555555555gggggggggggggggggggggggggggggggg5555555555555555555555555555gggggggggggggggggggg55555555gg
555555555555555555gggg5555555555555555gggggggggggggggggggggggggggggggg55555555555555555555555555gggggggggg555555gggggg555555gggg
555555555555555555gggg5555555555555555gggggggggggggggggggggggggggggggg55555555555555555555555555gggggggggg555555gggggg555555gggg
55gggggggg55555555555555555555555555gggggggggggggggggggggggggggggggggg555555555555555555555555gggggggggg555555555555gg55gggggggg
55gggggggg55555555555555555555555555gggggggggggggggggggggggggggggggggg555555555555555555555555gggggggggg555555555555gg55gggggggg
gggggggggggggggg5555555555555555gggggggggggggggggggggggggggggggggggg555555555555555555555555gggggggggg5555555555555555gggggggggg
gggggggggggggggg5555555555555555gggggggggggggggggggggggggggggggggggg555555555555555555555555gggggggggg5555555555555555gggggggggg
gggggggggggggg5555555555555555gggggggggggggggggggggggggggggggggggggg555555555555555555555555555555gg55555555555555gggggggggggggg
gggggggggggggg5555555555555555gggggggggggggggggggggggggggggggggggggg555555555555555555555555555555gg55555555555555gggggggggggggg
gggg55gggggg5555555555555555gggggggggggggggggggggggggggggggggggggg5555555555555555555555555555555555555555555555gggggggggggggg55
gggg55gggggg5555555555555555gggggggggggggggggggggggggggggggggggggg5555555555555555555555555555555555555555555555gggggggggggggg55
gggggggggg5555555555555555gggggggggg5555gggggggggggggggggggggg55555555555555555555555555555555555555555555555555gggggggg55555555
gggggggggg5555555555555555gggggggggg5555gggggggggggggggggggggg55555555555555555555555555555555555555555555555555gggggggg55555555
gggggggggg55555555555555gggggggggg555555gggggggggggggggggg55555555555555555555555555555555555555555555555555555555gggg5555555555
gggggggggg55555555555555gggggggggg555555gggggggggggggggggg55555555555555555555555555555555555555555555555555555555gggg5555555555
gggggggg55555555555555gggggggg555555555555gggggggggggggg555555555555555555555555555555555555555555gggggggg5555555555555555555555
gggggggg55555555555555gggggggg555555555555gggggggggggggg555555555555555555555555555555555555555555gggggggg5555555555555555555555
__map__ __map__
12272711306328d47551b51b4c8610acf67a11171810339055e1331841200028a2611a977291bc0633572201044ba2d638db0dc860213021c3d112540c847a3d2b88693720504c31e4c2a055431ea47602f804e4f405ea10be68d639ab9642a1a0f9744232be8b125319405159f512649d3402d0f79b242cc8070585421956f1 c30111e665c2b118f005bb151891000098020109634a06445a66afc5d3572f39d001b11430e3e61748055e3fd2637052131f2002560d516492b5020f990002b002f021f560105023b02d203145db2173d6341920c04b96902a31290d662d910e2752f9c05504756d0fb298534135a1a47803080f05360051613425132229001a
0584116d681c448868019160838b3092e51133c11263b7e4a313b74352a3a46110ad32d144b302e26975019463487231002d09c89c9840767c1233002a63a4119274ca950163625513502e12302efaa1f0da9bd420612524a1633109a700f00006686083c205503d7474030070402a080b771442d79631632280e071b7d0fbb7 d505aa3b118eb2f2c4333549a23b566224356131b5834961e12254034233120950235312522720922fb5e63672625833f9076b7242ca37d4bf5993aa1801f4c7346c2135300a0b625c674b2153531e33641560011046633b111045225280117720054d3a8f2619caed2015d3591418114689412040f632155d3331095f836644
412f13543919c4033e083182299b4330060551235013a835620e5a550325022a2d7b6250b34740163bde22730861f407910271937553c120b5c744206292856e00177230131e46015d219b307ea03d1374224f339b0332ac1d305462d2072b67cc2b2c719fd41b6d7055c4034638560aa482d0b4174a44155203a5f26b03e1c4 250a491164541991327e0510b907151507c161330be60b4610151281c16b1b14b411020ed317158152993674f18a51b15b2a05422922a2196011633560eef61a4a03512d726eb50407330474120f0c919232145e8e02164006e11d75d4128eac5071a14023e08d2641200195a090400389c5219810814002a640a9170f451046
050a061bb02125530606752302412b605a53d7031508303520ee7358104b094101782e0da82aa965130b220f5118784700058771bb09c1848a84e32894119c8c830111590f933415202a40e60104443520d85821d00105399c0423922c8a8c60c600a333716c6097531112330c7bb050227f550833742371ac8e2e2312dd34e0 36334504319563206c02323053c1053f04f60b1a00640141f26141004b18fdb847f06371abbf30c3462f56265007715c48005d1aa332021260133b162f1a202911621866222670102358ac1a023006041011f051c267178af0e84743600d051565802353309713dd2010707a0087e1b26fcd8021664301916ec1ee6289be52d9
95107d34612049251a3deb6208401203151a43a27a118cf1a03f760708847432034f246608904943930431780a3ed102d070346a8180e40001b5fba3451b167353e0ab21fec20653f18161b035200815132041a5511b50c80cb8ec658516319143950f05932c71460162439bb00c35530113be243271389c083c73c731106070 70954c1817109352c5410681966841290376240ba3f26050311a12110340a2505703112022c0023da045850c514513424822930514b06403532e235a783717104760256632d9a212272711306328d47551b51b4c8610acf67a11171810339055e1331841200028a2611a977291bc0633572201044ba2d638db0dc860213021c3
335009dd0051113622908990265b11472516044a777d4707da0a9053504030942690db86053408221540300221a1b223d201403440048d1f484031617635e060621524e87647400b86740349c001590791270282f1305f32609b70132269a2e523f29108033096e310074312114a134e52922a29092b23421793346149671bd4 d112540c847a3d2b88693720504c31e4c2a055431ea47602f804e4f405ea10be68d639ab9642a1a0f9744232be8b125319405159f512649d3402d0f79b242cc8070585421956f10584116d681c448868019160838b3092e51133c11263b7e4a313b74352a3a46110ad32d144b302e26975019463487231002d09c89c9840767c
91176025541256501109144457253663a3041a394b173931169515f337ae26330c801902d2354d51a0d502f19a68088df41a38841f83044202165400107b081e045b2d911211a8712289a63102323b2a767022341116b34c639c0304052bc382e21905427000630d0344c8516c4665925034920b9e82e6539039736e02064780 1233002a63a4119274ca950163625513502e12302efaa1f0da9bd420612524a1633109a700f00006686083c205503d7474030070402a080b771442d79631632280e071b7d0fbb7412f13543919c4033e083182299b4330060551235013a835620e5a550325022a2d7b6250b34740163bde22730861f407910271937553c120b5
1142321b12b421352743f871c100440b6f531b020113e6371140020437a921126a05779678c4402151412281754c4778ca02ac432553e12607330d3b1af86533a032400724969268734f760a27f45001fc40174422188a161d2b20289007145394e66022a840575b320200f8407e833275018515844490ad0274093119b1a801 c744206292856e00177230131e4664132299e1cb25282d52b13828222771226595220403221d43773619434346126c3567c96af1356d483de56b331814220046b94129728703d0161517aa693313119c341152942202213d0f1f3f26e9332496232652160c514733116f421606531606104212d4a953269428a1125134a1d912
0367323f2135ad8338806974bdcf944424070b0100c95446014320023a08347f77b21f31872f09139552112c417007140f63fcb520a41120160295260120027224b5b87554902044101506154406128150c06446423260ca5002317a18f37405043057165158a6084708c515050021be292a811208283572c826a2810977302e 0eb422597b26350120a171e349612134c9142d146749443a140164485321c32601712ac41553453c214fb331161a65e2311177e8260325372426315b61313431198737c765a021231371d1125145133556411898141f522524f242365433456f33d1c3851221d8856206221266a11902860574f2c2f669925566e1111414c216
c94a55ff919502b2a33442144b74715544716219300212f37011e813c08fd56608a386131e44f220902515151bc569b305210218c1e545826c4d34323500a9431391130198127276500440b220a1422b6b58b6a6367635e10b61808b7002313e52053a146635275f70118a2339ba62046d760b5000d3bd0012687814013f87a2 17383d226bb8043e7225a85d2a54a253020293660733115946a1320927aad3b3062216247d464736831c541a55e3111133321844817061314233552193ff90261b2115c3311b0f11394d112c4b50b226832392a1800362e0af2112964d51c62e7438138044111251527392453356127117a4411e248128543533430112251446
a306831030325632662132df101a5135900a7f1b3300e00860033081ec4010c00204b14440037253060c2451d45409e76d349560b2593b336532459905b00864008c262420078270533013221a930d612db04c05a42fb620419293885f24e59110d0005c320075cd4841a019089c63f521d6b8c92babf6430b48030084324d00 83645030104244478b155ca4692124a7218533bd53d241a2285d231014c2404d8a4a3893e5311961125b8ca4c05718918a6a22fa37133a16443366c0ef85111113c11455a33f14751e14158c1329235342037e4851a118373e8123318690513322191542512c343211e12364535642522d851577d5031131a138388026281d23
25af206b02e0300bf8854a07666b0423108028201456180b4216287129020549401639a610ba03231030662131c41543d3b070208d0a12323071431b689680b02410030f304bfb6684a31fc6017605041745581335b0749863260429ad11e061ed6e25a287895137ef20b21260418041d2a04408aa5b960a230a1b522000b325 4117175b245135513316154f5128b77794216263421a2343431311a184232183197d861324702222405412743042d311014272164277061d76144351142869112287525947671572332141e8951123821203a5e0862b4b354e1fb26a21728815247d154173b42354321b79e552161b41b2503203182e4b6082e414b233331639
e270a090811741436d45572801621c4496bd57895524875309220b5187209a1b20519b253842509224b56812a2910935501f1d040a008a2460155508248600254795b5b16ea19227d1778a7880d91843084837f450a85c0013035505588001e0718000312c7340025143107c3f1e39c5515151621712018f7700112d81170956 121334545121215928201243496b6827120283421a11100245161641634b91b514137d1812ecd1513b2472615615311681783ad325b945b4402636f2a56321125051546183466a11312e64cd91263281da08321132af727a3e726714219329984c2120046523493343415c42fa969b3316921b6514d5ab2a0cd5135342353425
13020005794534d3241ab897b0d1bd287c0020012b01f0008d4b05418a400af2271362259c660a090391020222c0df12e86b3440000584050c5637072006bf05e801b465c2621967083d0b0398115119a8a3035b04210310cba70b9aa852730f100d307b00062fb003b20767442823f233303082432338c029c70e761c381418 d206c1895317208b2de9282306212575c00233774525443c0f812116531c830224481114144a3118d210c21473403c7953773536496c23a222eb02829461138291c63113276135357d001236316101010251e6a72aab5343410243d6e1125a2f492f7d1ed486627333559362436e472c1a042a12671a7e251133fe725e521653
0802150300df070980c19b3745ea37f075717622a530a08765450627000082080a0054706b6695b73832b009290054e7001c98404c2be41203aa5d07675526e306a49c50e220e7350148d085070623116528350f05003090f21400007d0047c035240273124800700339218809070000b43005252e00371000840c048e01ea20 41e913524751c3037713931886122a5333192129a3315f390f11425f81141ae11e4594146216cd26424bb52d79115100267010503862403941458b52b259527d235a1335a84153811735631359012d74206d3e5a45b18341301102252980647329127411134317ac232312825c9042920c262a80231434551040439991d68e22
84000d5530c12756ac1d93d0d5c060c70004d0106720b8c800b0d8e0038000504108d78577810481533ba0f0c804000c07005205760000b85002f76081e1020f00d0d01e9a14224e1e4078186105860002404003070950000090001f430910009b0300290de050d6d02077c01400f00400048d00e050060c500c87060000020d 5efb5b7c040b81037c5d437350ac1f44137816585262514866a35c3a9152504d17191410113001133d217b45132e34c192124951696506b11e2422425013a9a360248c25142471a6d50192401265c5024523301244541421018c52247191a0233975403812111e9433531727325171432918580310b03159411130221834a212
00c0006540d290002100586000a0d00d00b14a00000a00f044f9002800600003a0400af00b0409580d040070670c0005000009e805000000200000070000080678000300600009000b00d06000000f0d77e0000000000400c000009610d00000000000a050000000000000080000a0d0000a60d805000000080000026000b000 3111b7d0849034ed18467546445e2b3167255e79165432a331705302731704321109454d0341e61812b6d42eb5771922c28bc22620063780836e81622b135d31b1622aab15522382156322d23113536643231643a5a49e1371693151622649ac561598477102584c601212b15813b504231351813239eb237622c0321896153c
00000060c0e000000000000080500004000009e0000306000000000000000000000706700000000050d0600000906000b00000900c0000000000030d00c0050000090000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 3486b40b2d4231d242282e36a1e6726a12a1302d14f3d1400529e2f19643207240ee304011231952567133651e2143621739061162108bd51f232358514e3135122d1122a5138418f8233354401121281234913781f031213346a1b43342303127d243318931023a5e01a2233b448d644462444261412323233e21f217a31429
741114111131124046148334d11335112223525ff4471301199555613413565326933b1d2102a1140711c14188c365261222f18d107519116014231709e5059181b33791143555116381a05b3279b533316c582838377716c23065147444329d137295fd8790264c18f77014161053362d18631d0d5a42120689912c9c553846
1571b752651e1b3173befa40215c1574f082332ca51e482d510a9419e91132166214903271193c61a7c6153378111241021461a03053455311d2244115a33a11362646e44b31134b1015c179e1c2f843134912233e71566542713761111de19c893725541e4195112a9a5a384411e53519553312f2911c20e00695b237944452
228256512f66243b14c0414a12b915a17485cc1336a41d166571b39272251b38136142846559e2d46316031b4711044f43625867974535a87348160882162355c71339439562e22421253266289a3a26092643ac631c33c08414b933102370392411193533719733230f3b0314e48435460612326b20904515919322e3639d43
8a074c50428115e11322211931133e1355519a21a26981d96042210a12d323c32884d6e833c4756b1c311773352367394025473561809122110b56042330b1231427854c724d64492359a112343295360a204808598543044d522c2b5696152456b11416325124319121427124836b0daa2917131b3135441335e2217ca2029f
564011f57a1036357762523322096ff25183883a59305548245832cc32a55583cf1184202161a751e4a709034223344852a19456db41a634823171345c77122a4a1d11402b462e430546171aa413a85247b6a45286074a211536282332323936a327243333a62724248a537216143720e16041107f0612f413611222e3421001
5604b1d04e19331b34405b2542811616221019132cdb2e36c302371801ad521931840fb4213110c59645731821c7731101d506c1930202623f524a033165112133369272d2548f23821580662142151432933910316146ac3231b73875510283462a23216868111f2ea042641358deb33e24488161388a70d91313115d634003
c492289b5141433d10374b16ac6712152316072551b722065a5283281a38c5231917332655ba5132645398212681682366db513652522963701fe6723a24511d01384ce43011451847018f145627a209222c220271255a694633a9051ccd817d5637235922660701b13a672095b2180038bd21e40a215147541542a093157131
11815492467355afc91233693c11353858911a9435472621655585113bb221b41231b7503d446362128922324731c7464641d6621824a229a261503263221082a3c16342933fe47632531159b36121c4c2617387d2981056ada6034141238333442c30816334d66a12841135335e3614732211ea451553443241434600a51605
ac49a4516135e231316332ea30311c4262420391515020b57bd441827626ac3121117111e314397621634cb3447532223145c52549d3474b525a1c989c31b862b1326188144227333515131111fc3b65b224f64bd1527f81533141132c0400436907b5a141116192500377c52a4204cb5b1443093181151372271275a5c21543
0213443436179d540a0421b1332362702b151242c2450e1821020294022d139137116a265363201a417e6bc5e1a31234223159790027b329244251720d751333b1252336219722c103e2724730b622fb01376883122163095251130106632831c48231207c9502184135264193b2424137132e90260124b61613235227611101
13712081357d5710d54533453922517613848b628b3b641f43a7663345121216810362b2c7156715654325282652161c51606571a9496a031289a2214237520b1418c711153501152334053265f63459171a382d422ca31647d14515b66413354007a217748646555a90432161424550847b2265129382112252243570e43c51
65c36534685711e9102895112512419d21062604c95c130841452445322376286c511128422626915a101d1784631830017c530411332960ae66b0413c47d931b13c711089060157a17361523352b25d1361221c656591611341ab14204a11439732663150620112032a4302036325e8322eb5573042a212431b18cf56578e33
01447a75130226312881342247810740351d14141305239e12a4a2a05f13240a271933164e873663574b18d11154b2a2c2b508bd1139611c011433129273356283427d6691126215131a293225461533e0141302912a4014a0a339c5412251367842eb475112a2161c3053660c4165f0088114571448943b44b0213366192131
3595095320212d4246bb3525231d3b3234458d54831ad803236b13b2846895482785e36db149044cb33736ca3e121195567012831f4015944f3b1e536b19875925733040180b521901843ca07c561341e32205335aa1312525119424621210263825580964765b25958843f318b4b51518289837551312e812d22097226242e0
__sfx__
911300001305013031130321303213032130321105011031110321103211032110321505215031150321503215032150321503215032150321503215032150321503215032150321503215032150321503215032
911300001305013031130321303213032130321303213032130321303013030130301303013032130321303215050150311503015030150321503215032150301503015030150301503215032150321503215030
911300001605016031160301603016032160321805018031180301803018030180301105011031110301103011030110301103011030110321103211032130501505015031150321305011050110311103013052
911300001005210052100520905009031090300905009031090300903009030090300903009032090320903215050150311503015030150301503015030150301503015030150321503215032150301503015030
911300001806018031180301803218032180321606016031160301603216032160321a0601a0411a0401a0421a0421a0421a0401a0401a0401a0421a0421a0421a0421a0421a0511a0501a0501a0521a0521a052
91130000180501803118030180301803018030180321803218032180321803218032180321803218032180321a0601a0411a0401a0401a0401a0401a0421a0421a0421a0421a0421a0421a0421a0421a0421a040
911300001b0501b0311b0301b0321b0321b0321d0501d0311d0301d0321d0321d0321605016031160301603016030160301603216032160321603216032180501a0501a0311a0301805016050160311603218052
911300001505015031150300e0500e0310e0300e0500e0310e0300e0300e0300e0300e0300e0300e0300e0301a0501a0311a0301a0301a0301a0301a0301a0301a0301a0301a0301a0301a0301a0301a0301a030
91130000190511a0311a0301a0301a0301a0301805018031180301803018030180301c0511c0311c0301c0301c0301c0301c0301c0301c0301c0301c0301c0301c0301c0301c0301c0301c0301c0301c0301b031
911300001a0501a0311a0301a0301a0301a0301a0301a0301a0301a0301a0301a0301a0301a0301a0301a0301a0301a0301a0301a0301a0301a0301a0301a0301a0301a0301a0301a0301a0301a0301a0301a030
011300000c7530000007050070211a643000000000000000050500502105025000001a643000000a0500a0500c7530000000000000001a643000000a0500a0210a02500000000001a60302050020210102500000
011300000c7530000000050000211a643000000000000000000500002100025000001a6430000000000000000c7530000005050050501a643000000000000000050500505005025000001a643000000000000000
0113000000000000000c0500c0210c0250000000000000000a0500a0210a0250000000000000000f0500f0210f02500000000000000000000000000f0500f0210f02500000000000000007050070210602500000
011300000c753050000502505021050250000000000000000c753050000502505021050250000000000000000c7530a0000a0250a0210a0250000000000000000c7530a0000a0250a0210c753000000a0250a021
011300000c7530c0210c0200c0200c0200c0200c0200c0200c7530a0210a0200a0200a0200a0200a0200a0200c7530f0210f0200f0200f0200f0200f0500f0210c7530f0200f0200f02007050070210702006021
011300000c753050000502005020040250000000000000000c753050000502005020050200502005020050200c753000000a0500a0210a0250000000000000000c7530a0000a0200a0200a0200a0200a02500000
1513000000000000001a5552155521215265551a215000001b5552255522215275551b215000001a5552155521215265551a215000001a2051a2051a205000000c7530000000000000001a643000001a64300000
1513000000000000001c5552155521215285551c215000001c5552155521215285551c215000001d5552155521215295551d2150000000000000001d5552155521215295551d2150000000000000000000000000
1513000000000000001f52026520265212b5202b5202b5202052027520275212c5202c5202c5201f52026520265202b5202b5212b5222b5222b5202b5202b5202b5202b5202b5202b5202b5202b5202b5202b520
151300002b5202b5211f52526520265212b5202b5212b5202052527520275212c5202c5212c5221f52526520265212b5202b5222b5222b5222b5222b5222b5222b5222b5222b5222b5222b5222b5222b5222b522
151300002b5202b5222152026520265222d5202d5222d5222152026520265222d5202d5222d5222252026520265202e5202e5222e5222e5222e5202e5202e5202e5202e5202252026520265202f5202f5202f520
011300000c7530000000000000001a6430000000000000000c7530000000000000001a6430000000000000000c7530000000000000001a6430000000000000000c7530000000000000001a643000000000000000
011300000c7000000000000000001a6030000000000000000c7530000000000000001a6030000000000000000c7000000000000000001a6030000000000000000c7530000000000000001a643000000000000000
151300003053030530305303053030530305302e5302e5302e5202e5202e5202e5203252032520325203252032520325203052030520305203052030520305213051030510305103051030511305103051030510
a51300003051030510305103051030510305103051030510305103051030510305103051030510305103051524500245002450024500245002450024500245002450024500245002450024500245002450024500
011000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
011000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
930a00003766437625000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
954a00002b66518000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
010400000c25512255232550000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
0108000013335113000c3000c3050c305000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
__music__
01 00551544
00 01551544
00 020a1644
00 030b1644
00 000a1644
00 010b1644
00 020a1644
00 030b1644
00 000a1044
00 010b1044
00 020a1044
00 030b1144
00 040c1244
00 050d1344
00 060e1344
00 070f1444
00 08171544
02 09181544

19
music_manager.lua Normal file
View File

@ -0,0 +1,19 @@
music_manager={}
add(modules,music_manager)
function music_manager:init()
self._allow=true
end
function music_manager:allow(a)
self._allow=a
end
function music_manager:update()
if (not self._allow) music(-1,0) return
local is_playing = stat(54) != -1
local should_be_playing = completion_tracker:get_music_preference()
if (is_playing and not should_be_playing) music(-1,500)
if (not is_playing and should_be_playing) music(0)
local label,pref="start music",true
if (should_be_playing) label,pref="stop music",false
menuitem(1,label,function() completion_tracker:set_music_preference(pref) end)
end

17
palette.lua Normal file
View File

@ -0,0 +1,17 @@
function apply_palette()
-- bg
pal(13,-3,1)
-- arcana
-- pal(1,0,1)
pal(15,-9,1)
-- suits
pal(4,-11,1) -- first suit
pal(12,12,1)
pal(2,-8,1)
pal(3,-5,1)
-- pal(8,-9,1)
-- pal(14,8,1)
end

View File

@ -1,16 +1,16 @@
progression={ progression={
-- level 1 -- level 1
-- ruleset:new(5,1,9,0), ruleset:new(1,5,1,9,0,nil,1), -- by test: always winnable
-- level 2 -- level 2
-- ruleset:new(5,2,9,0), ruleset:new(2,5,2,9,0,nil,2), -- by test: always winnable
-- level 3 -- level 3
-- ruleset:new(7,2,9,8), ruleset:new(3,7,2,9,8), -- by test: always winnable
-- level 4 (first challenging) -- level 4 (first challenging)
-- ruleset:new(9,3,9,16), ruleset:new(4,9,3,9,16, "l4"),
-- level 5 -- level 5
-- ruleset:new(9,3,11,18), ruleset:new(5,9,3,11,18, "l5"),
-- fortune's foundation -- fortune's foundation
ruleset:new(11,4,13,22,"seeds_ff") ruleset:new(6,11,4,13,22,"ff"),
-- harder than fortune's foundation -- harder than fortune's foundation
-- ruleset:new(11,5,10,25) ruleset:new(7,11,5,10,25,"l7")
} }

View File

@ -1,5 +1,6 @@
ruleset=klass() ruleset=klass()
function ruleset:init( function ruleset:init(
completion_level,
-- Number of unlocked slots (up to 11) -- Number of unlocked slots (up to 11)
-- Includes the one in the middle -- Includes the one in the middle
-- For Fortune's Foundation: 11 -- For Fortune's Foundation: 11
@ -17,13 +18,16 @@ function ruleset:init(
-- Number of arcana (unbounded) -- Number of arcana (unbounded)
-- For Fortune's Foundation: 22 -- For Fortune's Foundation: 22
n_arcana, n_arcana,
pool pool,
preferred_verse
) )
self.completion_level=completion_level
self.n_slots=n_slots self.n_slots=n_slots
self.n_suits=n_suits self.n_suits=n_suits
self.n_cards_per_suit=n_cards_per_suit self.n_cards_per_suit=n_cards_per_suit
self.n_arcana=n_arcana self.n_arcana=n_arcana
self.pool=pool self.pool=pool
self.preferred_verse=preferred_verse
assert(self.n_slots<=11) assert(self.n_slots<=11)
assert(self.n_suits<=5) assert(self.n_suits<=5)
assert(self.n_cards_per_suit<=13) assert(self.n_cards_per_suit<=13)
@ -83,24 +87,32 @@ function ruleset:generate_deck()
if (rank==0 or rank==self.n_arcana-1) deck.instantly_accepted[#deck.cards]=true if (rank==0 or rank==self.n_arcana-1) deck.instantly_accepted[#deck.cards]=true
end end
function deck:draw_card(x,y,c,shadow) function deck:draw_card(x,y,c,special)
if special.rotate then
camera(0,-64)
poke(0x5f55,0x00)
else
camera(-x,-y)
end
local meta=deck.cards[c] local meta=deck.cards[c]
local is_extreme=meta.rank==0 or meta.rank==ruleset.n_arcana-1 local is_extreme=meta.rank==0 or meta.rank==ruleset.n_arcana-1
local s,fg local s,fg
local bg,shadowbg local bg
if meta.suit=='a' or meta.suit=='b' then if meta.suit=='a' or meta.suit=='b' then
bg,shadowbg=1,1 bg=1
if (shadow) bg,shadowbg=1,1 if (is_extreme) bg=15
if (is_extreme) bg,shadowbg=15,15
else else
bg,shadowbg=7,7 bg=7
--if (shadow) bg,shadowbg=7,6 end
if special.shadowed then
if (bg==1) bg=4
if (bg==7) bg=6
end end
rectfill(x,y,x+8,y+4,bg) rectfill(0,0,8,15,bg)
rectfill(x,y+5,x+8,y+15,shadowbg)
if (meta.suit=='p') s,fg=0,4 if (meta.suit=='p') s,fg=0,4
if (meta.suit=='s') s,fg=1,12 if (meta.suit=='s') s,fg=1,12
@ -113,23 +125,38 @@ function ruleset:generate_deck()
local rank=""..meta.rank local rank=""..meta.rank
pal(7,15) pal(7,15)
if (is_extreme) pal(7,1) if (is_extreme) pal(7,1)
print(meta.rank,x+5-#rank*2,y+1,7) print(meta.rank,5-#rank*2,1,7)
spr(5,x,y+8) spr(5,0,8)
pal() pal()
else else
local name=sub(deck.rank_name,meta.rank,meta.rank) local name=sub(deck.rank_name,meta.rank,meta.rank)
local x2=x local x2=0
if (meta.suit=='b') x2+=1 if (meta.suit=='b') x2+=1
rectfill(x,y,x+3,y+6,fg) rectfill(0,0,3,6,fg)
print(name,x2,y+1,bg) print(name,x2,1,bg)
pal(7,fg) pal(7,fg)
spr(s,x+4,y) spr(s,4,0)
if not shadow then spr(15+meta.rank,0,8)
spr(15+meta.rank,x,y+8)
end
pal() pal()
end end
camera()
if special.rotate then
poke(0x5f55,0x60)
mset(0,0,128)
mset(1,0,129)
mset(0,1,144)
mset(1,1,145)
x-=3
y+=7
for sx=0,8 do
for sy=0,15 do
tline(x+sy,y+sx,x+sy,y,(0)/8,sy/8,1/8,0)
end
end
tline()
end
return fg return fg
end end
end end
@ -141,24 +168,31 @@ function ruleset:generate_layouts()
local ruleset=self local ruleset=self
local width=ruleset.n_slots*10 local width=ruleset.n_slots*10
local x=(128-width)\2 local x=(128-width)\2
local y=9 -- 1 is also fine
function layouts:well(i) function layouts:well(i)
if i<=ruleset.n_suits then if i<=ruleset.n_suits then
local wx=width-ruleset.n_suits*10+(i-1)*10 local wx=width-ruleset.n_suits*10+(i-1)*10
return layout:new(x+wx,1,layout_mode.obscured) return layout:new(x+wx,y,layout_mode.obscured)
end end
i-=ruleset.n_suits i-=ruleset.n_suits
if (i==1) return layout:new(x,1,layout_mode.obscured) if (i==1) return layout:new(x,y,layout_mode.obscured)
if (i==2) return layout:new(x+10,1,layout_mode.obscured) if (i==2) return layout:new(x+10,y,layout_mode.obscured)
if (i==3) return layout:new(x+5,y,layout_mode.rotated)
assert(false,"unknown well") assert(false,"unknown well")
end end
function layouts:checkpoint()
local wx=(ruleset.n_slots\2)*10
return layout:new(x+wx,y,layout_mode.obscured)
end
function layouts:slot(i) function layouts:slot(i)
if i<=ruleset.n_slots then if i<=ruleset.n_slots then
local sx=(i-1)*10 local sx=(i-1)*10
return layout:new(x+sx,18,layout_mode.vertical) return layout:new(x+sx,y+17,layout_mode.vertical)
end end
if (i==ruleset.n_slots+1) return layout:new(x+width-ruleset.n_suits*5-5,1,layout_mode.obscured) if (i==ruleset.n_slots+1) return layout:new(x+width-ruleset.n_suits*5-5,y,layout_mode.rotated)
assert(false, "unknown slot") assert(false, "unknown slot")
end end
end end

View File

@ -3,19 +3,48 @@ import struct
import zlib import zlib
def main(): def main():
ff = load_seeds("input/fortunes_foundation.txt") # No need to store any seeds for level 2 or 3: all 5000 of the first 5000 seeds are fine
# We could use negencode_delta_4b, which is pretty uneventful
# level_1 = load_seeds("input/level_1.txt")[:5000]
# analyze(level_1)
# level_2 = load_seeds("input/level_2.txt")[:5000]
# analyze(level_2)
# level_3 = load_seeds("input/level_3.txt")[:5000]
# analyze(level_3)
level_4 = load_seeds("input/level_4.txt")[:5000]
# analyze(level_4)
level_5 = load_seeds("input/level_5.txt")[:5000]
# analyze(level_5)
ff = load_seeds("input/fortunes_foundation.txt")[:7578]
# analyze(ff)
ffdata = delta_4b(ff) level_7 = load_seeds("input/level_7.txt")[:6000]
# analyze(level_7)
augment_map("../main.p8", "../seed_constants.lua", ffdata, { level_4_data = negencode_16b(level_4)
"ffdata_start": 0, level_5_data = negencode_delta_4b(level_5)
"ffdata_end": len(ffdata), ff_data = delta_4b(ff)
}) level_7_data = delta_4b(level_7)
all_data = b""
offsets = {}
for block, data in [
("l4", level_4_data),
("l5", level_5_data),
("ff", ff_data),
("l7", level_7_data),
]:
offsets[f"{block}_start"] = len(all_data)
all_data += data
offsets[f"{block}_end"] = len(all_data)
augment_map("../main.p8", "../seed_constants.lua", all_data, offsets)
def augment_map(target, constants_file, binary, offsets): def augment_map(target, constants_file, binary, offsets):
assert isinstance(binary, bytes) and len(binary) < 8192 # length of mapdata
print(f"Length of basic extra map data: {len(binary)}") print(f"Length of basic extra map data: {len(binary)}")
assert isinstance(binary, bytes) and len(binary) <= 8192 # length of mapdata
mapdata = (binary + bytes([0] * 8192))[:8192] mapdata = (binary + bytes([0] * 8192))[:8192]
cart = Pico8Cart.load(target) cart = Pico8Cart.load(target)
@ -58,13 +87,21 @@ def analyze(seeds):
print("{} seeds".format(len(seeds))) print("{} seeds".format(len(seeds)))
for encoding in [ for encoding in [
naive, delta_8b, delta_3b, delta_4b, delta_5b, zlib_delta_4b, zlib_delta_8b naive, bitfield, delta_8b, delta_2b, delta_3b, delta_4b, delta_5b, zlib_delta_4b, zlib_delta_8b,
negencode_delta_4b, negencode_16b,
]: ]:
print("{} encoding: {} bytes".format(encoding.__name__, len(encoding(seeds)))) print("{} encoding: {} bytes".format(encoding.__name__, len(encoding(seeds))))
def naive(seeds): def naive(seeds):
return b"".join(struct.pack("<I", s) for s in seeds) return b"".join(struct.pack("<I", s) for s in seeds)
def bitfield(seeds):
mx = max(seeds)
out = bytearray((mx+7)//8)
for s in seeds:
out[s // 8] |= 1 << (s % 8)
return bytes(out)
def delta_8b(seeds): def delta_8b(seeds):
out = b"" out = b""
acc = 0 acc = 0
@ -110,6 +147,9 @@ def delta_4b(seeds):
def zlib_delta_4b(seeds): def zlib_delta_4b(seeds):
return zlib.compress(delta_4b(seeds)) return zlib.compress(delta_4b(seeds))
def delta_2b(seeds):
return delta_nb(seeds, 2)
def delta_3b(seeds): def delta_3b(seeds):
return delta_nb(seeds, 3) return delta_nb(seeds, 3)
@ -151,6 +191,26 @@ def delta_nb(seeds, n):
out += bytes(chunk_bytes) out += bytes(chunk_bytes)
return out return out
def negencode_delta_4b(seeds):
mx, new = negencode(seeds)
return struct.pack("<H", mx) + delta_4b(new)
def negencode_16b(seeds):
mx, new = negencode(seeds)
out = b""
out += struct.pack("<H", mx)
for i in new:
out += struct.pack("<H", i)
return out
def negencode(seeds):
mn = 0
mx = max(seeds) + 1
everyone = set(range(mn, mx))
for i in seeds:
everyone.remove(i)
return mx, sorted(everyone)
if __name__ == "__main__": if __name__ == "__main__":
main() main()

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,10 @@
seed_constants={ seed_constants={
ffdata_start=4096, l4_start=4096,
ffdata_end=10434 l4_end=4138,
l5_start=4138,
l5_end=4679,
ff_start=4679,
ff_end=9102,
l7_start=9102,
l7_end=12288
} }

View File

@ -1,25 +1,55 @@
seeds={} seeds={}
add(modules,seeds) add(modules,seeds)
function seeds:init() function seeds:init()
self.seeds_ff=seed_pool:new(seed_constants.ffdata_start,seed_constants.ffdata_end) self.l4=seed_pool:new(seed_constants.l4_start,seed_constants.l4_end,_naive_16b,true)
self.l5=seed_pool:new(seed_constants.l5_start,seed_constants.l5_end,_delta_4b,true)
self.ff=seed_pool:new(seed_constants.ff_start,seed_constants.ff_end,_delta_4b)
self.l7=seed_pool:new(seed_constants.l7_start,seed_constants.l7_end,_delta_4b)
end end
function seeds:choose(pool) function seeds:choose(pool)
if (pool) return rnd(self[pool].seeds) if (pool) return self[pool]:choose()
return rnd(0xffff.ffff) return rnd(5000>>16)
end end
seed_pool=klass() seed_pool=klass()
function seed_pool:init(addr_start,addr_end,routine,negencode)
function seed_pool:init(addr_start,addr_end) if (negencode) self.neg_max=(%addr_start)>>16 addr_start+=2
local seeds={} local seeds={}
routine(seeds,addr_start,addr_end)
self.seeds=seeds
self.is_seed={}
for s in all(seeds) do
self.is_seed[s] = true
end
end
function seed_pool:choose()
if self.neg_max then
while true do
local r = rnd(self.neg_max)
if (not self.is_seed[r]) return r
end
end
return rnd(self.seeds)
end
function _delta_4b(seeds,s,e)
local acc=0 local acc=0
while addr_start < addr_end do while s < e do
local byte=@addr_start local byte=@s
local nb0=byte>>20 local nb0=byte>>20
local nb1=(byte&0xf)>>16 local nb1=(byte&0xf)>>16
if nb0==0 then acc+=0x0.000f else acc+=nb0 add(seeds,acc) end if nb0==0 then acc+=0x0.000f else acc+=nb0 add(seeds,acc) end
if nb1==0 then acc+=0x0.000f else acc+=nb1 add(seeds,acc) end if nb1==0 then acc+=0x0.000f else acc+=nb1 add(seeds,acc) end
addr_start+=1 s+=1
end
end
function _naive_16b(seeds,s,e)
while s < e do
add(seeds,%s)
s+=2
end end
self.seeds=seeds
end end

View File

@ -1,4 +1,4 @@
use std::{borrow::Borrow, fs::File, io::Write, sync::{Arc, Mutex}}; use std::{fs::File, io::Write, sync::{Arc, Mutex}};
use board::Board; use board::Board;
use ruleset::Ruleset; use ruleset::Ruleset;
@ -16,28 +16,7 @@ mod zobrist;
fn main() { fn main() {
/* /*
let mut rng = PicoRng::srand(0x20000); let filename = "level_1.txt";
for _ in 0..10 {
println!("{}", rng.rnd(0x10000));
}
return;
*/
/*
let ruleset = Ruleset {
n_slots: 11,
n_suits: 5,
n_cards_per_suit: 10,
n_arcana: 25
};
*/
let ruleset = Ruleset {
n_slots: 11,
n_suits: 4,
n_cards_per_suit: 13,
n_arcana: 22
};
/*
let ruleset = Ruleset { let ruleset = Ruleset {
n_slots: 5, n_slots: 5,
n_suits: 1, n_suits: 1,
@ -46,6 +25,16 @@ fn main() {
}; };
*/ */
/* /*
let filename = "level_2.txt";
let ruleset = Ruleset {
n_slots: 5,
n_suits: 2,
n_cards_per_suit: 9,
n_arcana: 0
};
*/
/*
let filename = "level_3.txt";
let ruleset = Ruleset { let ruleset = Ruleset {
n_slots: 7, n_slots: 7,
n_suits: 2, n_suits: 2,
@ -54,37 +43,61 @@ fn main() {
}; };
*/ */
/* /*
let filename = "level_4.txt";
let ruleset = Ruleset {
n_slots: 9,
n_suits: 3,
n_cards_per_suit: 9,
n_arcana: 16
};
*/
/*
let filename = "level_5.txt";
let ruleset = Ruleset { let ruleset = Ruleset {
n_slots: 9, n_slots: 9,
n_suits: 3, n_suits: 3,
n_cards_per_suit: 11, n_cards_per_suit: 11,
n_arcana: 18 n_arcana: 18
};
*/
/*
let filename = "fortunes_foundation.txt";
let ruleset = Ruleset {
n_slots: 11,
n_suits: 4,
n_cards_per_suit: 13,
n_arcana: 22
}; };
*/ */
let filename = "level_7.txt";
let ruleset = Ruleset {
n_slots: 11,
n_suits: 5,
n_cards_per_suit: 10,
n_arcana: 25
};
let setup = ruleset.compile().expect("compilation should succeed"); let setup = ruleset.compile().expect("compilation should succeed");
/*
for _ in 0..10000 {
Deal::deal(&setup, &mut rand::thread_rng());
}
*/
const THREADS: usize = 28; const THREADS: usize = 28;
let winnable_seeds_file = Arc::new(Mutex::new(File::create("winnable_seeds_multithreaded.txt").expect("should be able to create"))); let work_source: WorkSource = WorkSource::new(0);
let winnable_seeds_file = Arc::new(Mutex::new(File::create(filename).expect("should be able to create")));
let mut threads = Vec::new(); let mut threads = Vec::new();
for i in 0..THREADS { for _ in 0..THREADS {
let setup2 = setup.clone(); let setup2 = setup.clone();
let source = work_source.clone();
let wsf = winnable_seeds_file.clone(); let wsf = winnable_seeds_file.clone();
threads.push(std::thread::spawn(move || { threads.push(std::thread::spawn(move || {
winnable_seeds_thread( winnable_seeds_thread(
&setup2, &setup2,
source,
|seed| { |seed| {
let mut f = wsf.lock().expect("must be able to lock"); let mut f = wsf.lock().expect("must be able to lock");
write!(f, "{}\n", seed).expect("write should succeed"); write!(f, "{}\n", seed).expect("write should succeed");
f.flush().expect("flush should succeed"); f.flush().expect("flush should succeed");
}, },
i as u32,
THREADS as u32
); );
})); }));
} }
@ -95,11 +108,31 @@ fn main() {
} }
fn winnable_seeds_thread(setup: &ruleset::Setup, mut cb: impl FnMut(u32), start: u32, step: u32) { #[derive(Clone)]
struct WorkSource {
seed: Arc<Mutex<Option<u32>>>
}
impl WorkSource {
fn new(seed: u32) -> Self {
return WorkSource { seed: Arc::new(Mutex::new(Some(seed))) }
}
fn take(&self) -> Option<u32> {
let mut self_seed = self.seed.lock().expect("shouldn't have panicked");
if let Some(seed) = *self_seed {
*self_seed = seed.checked_add(1);
return Some(seed);
}
return None
}
}
fn winnable_seeds_thread(setup: &ruleset::Setup, source: WorkSource, mut cb: impl FnMut(u32)) {
let mut winnable = 0; let mut winnable = 0;
let mut total = 0; let mut total = 0;
for seed in (start..0xffffffff).step_by(step as usize) { while let Some(seed) = source.take() {
let mut board = Board::new(&setup); let mut board = Board::new(&setup);
board.deal(Deal::deal(&setup, seed)); board.deal(Deal::deal(&setup, seed));
board.display(); board.display();

View File

@ -10832,3 +10832,109 @@
85247 85247
92829 92829
91669 91669
97597
85443
84931
91729
88458
92969
95686
86653
88570
86989
79762
87578
90767
89826
86559
90667
89319
89598
85609
89626
89416
88794
90134
87662
97716
91243
92688
86171
96000
93473
79902
86671
87690
97877
86923
89767
86057
93557
92638
90891
90919
89823
90883
89822
89878
92881
84476
92722
92513
92716
84588
94005
98017
89836
90088
94145
90172
90995
92597
97884
90312
80182
88850
80294
81556
84840
96140
91753
80434
90974
91087
91809
94453
98024
87129
81948
82004
91271
86197
91311
90718
85323
87157
92793
92905
91977
94789
94817
85407
96224
98248
91479
88082
85631
91535
91591
85064
82200
98500
89102
98640
80518
82312
82480
89158
96308

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

13
sounds.lua Normal file
View File

@ -0,0 +1,13 @@
sounds={}
function sounds:menu()
sfx(63,3)
end
function sounds:deal_card()
sfx(60,3)
end
function sounds:dire()
sfx(62,3)
end
function sounds:win()
sfx(61,3)
end

94
state_archaeology.lua Normal file
View File

@ -0,0 +1,94 @@
state_archaeology=klass()
function state_archaeology:init(tips_mode)
self.tips_mode=tips_mode
self.n_holy_books=#liturgy.holy_book
self:select_book(1)
end
function state_archaeology:enter() end
function state_archaeology:exit(new_top) end
function state_archaeology:reenter() end
function state_archaeology:suspend() end
function state_archaeology:select_book(n)
self.selection=n
if (self.tips_mode) self.title="tips" self.full_text=archaeology_tips return
local lines={}
local hb=liturgy.holy_book[self.selection]
self.title=hb[1]
printh()
for source in all(split(hb[2])) do
for line in all(liturgy.sacred_text_lines) do
if (line[1]==source) add(lines,self:_censor(source,line[2]))
end
end
self.full_text=""
for i=1,#lines do
if (i>1) self.full_text..="\n"
self.full_text..=lines[i]
end
end
function state_archaeology:_censor(src,line)
if (completion_tracker:was_seen(src)) return line
local line2=""
for i=1,#line do
local c=sub(line,i,i)
if ("a"<=c and c<="z") c="?"
line2..=c
end
return "\f6"..line2.."\ff"
end
function state_archaeology:update()
local vel=0
if (btnp(0)) vel-=1
if (btnp(1)) vel+=1
if (btnp(5)) sounds:menu() self.done=true
if (vel!=0) sounds:menu() self:select_book((self.selection+vel-1)%self.n_holy_books+1)
end
function state_archaeology:draw()
local fullw,fullh=measure_text(self.full_text)
local total_height=fullh+16
cls(13)
local y=64-total_height\2
local tw=measure_text(self.title)-1
local x=64-tw\2
local tx=x
print(self.title,x,y,15)
y+=6
line(x,y,x+tw-1,y,15)
y+=3
local x=64-fullw\2
rectfill(x-1,y-1,x+fullw,y+fullh-1,4)
print(self.full_text,x,y,15)
y+=fullh+1
line(tx,y,tx+tw-1,y,15)
y+=2
if not self.tips_mode then
print("⬅️",tx,y)
print("➡️",tx+tw-7,y)
end
print("❎ go back",1,122,15)
end
archaeology_tips=[[
wise archaeologists know these
secrets:
- hold ❎ to get a new board.
- hold 🅾️ to pick up more than
one card.
- updates and other games by
pyrex and nyeo are
available at nyeogmi.itch.io
and lexaloffle.
only diligent research can
uncover sacred mysteries!
- p & n]]

42
state_content_warning.lua Normal file
View File

@ -0,0 +1,42 @@
state_content_warning=klass()
function state_content_warning:init(prior_menu)
self.prior_menu=prior_menu
self.frame=0
self.frames=4
self.progress=0
end
function state_content_warning:enter() music_manager:allow(false) end
function state_content_warning:exit(new_top) music_manager:allow(true) end
function state_content_warning:reenter() end
function state_content_warning:suspend() end
function state_content_warning:update()
for i=0,6 do
if (btnp(i)) self.done=true
end
end
function state_content_warning:draw()
cls(0)
print([[
raven's rood explores post-
colonial subject matter,
including violent conflict
leading to genocide.
these themes are artistically
essential and inseparable from
the overall content of the game.
we understand all games are not
suitable for every individual.
we hope you enjoy our game
despite the bleak nature of its
subject matter.
once you continue, the tutorial
will begin, and you will not
encounter this message again.
]],2,2,6)
print("🅾️ continue",2,121,15)
end

23
state_excavate_menu.lua Normal file
View File

@ -0,0 +1,23 @@
-- todo: actually display a level picker or something
state_excavate_menu=klass()
function state_excavate_menu:init(prior_menu)
self.prior_menu=prior_menu
self.frame=0
self.frames=4
self.progress=0
end
function state_excavate_menu:enter() end
function state_excavate_menu:exit(new_top) end
function state_excavate_menu:reenter() end
function state_excavate_menu:suspend() end
function state_excavate_menu:update()
self.frame+=1
self.progress=self.frame/self.frames
if (self.progress>1) self.done=true main.state_manager:push(state_ironman:new(non_tutorial))
end
function state_excavate_menu:draw()
self.prior_menu:draw()
democrap:distort_screen(self.progress)
end

75
state_gameround.lua Normal file
View File

@ -0,0 +1,75 @@
state_gameround=klass()
function state_gameround:init(watcher,ruleset)
self.board=board:new(watcher,ruleset)
self.outcome=nil
self.grab_frames=0
self.restart_frames=0
self.picking_up=false
end
function state_gameround:enter() self:add_menu() end
function state_gameround:exit() self:remove_menu() end
function state_gameround:reenter() self:add_menu() end
function state_gameround:suspend() self:remove_menu() end
function state_gameround:add_menu()
menuitem(4,"restart",function() self.outcome="restart" self.done=true end)
menuitem(5,"go to menu",function() self.outcome="menu" self.done=true end)
end
function state_gameround:remove_menu()
menuitem(4)
menuitem(5)
end
function state_gameround:update()
self.board:update()
if btn(4) then
self.grab_frames+=1
else
self.grab_frames=0
end
if btn(5) then
self.restart_frames+=1
else
self.restart_frames=0
end
local restart_progress=self.restart_frames/60
self.board:set_restart_progress(restart_progress)
if restart_progress>=1.0 then
self.outcome="restart"
self.done=true
return
end
if self.board:can_take_input() then
if (btnp(0)) self.board.cursor:move_x(-1) self.picking_up=false
if (btnp(1)) self.board.cursor:move_x(1) self.picking_up=false
if (btnp(2)) self.board.cursor:move_y(-1) self.picking_up=false
if (btnp(3)) self.board.cursor:move_y(1) self.picking_up=false
if btnp(4) then
if self.grab_frames<4 then
self.board.cursor:toggle_grab()
self.picking_up=true
else
self.board.cursor:incr_grab()
end
end
if btnp(5) and self.restart_frames < 4 then
if self.board.cursor:grabbed_card() then
self.board.cursor:drop_grab()
else
self.board:undo()
self.picking_up=false
end
end
end
if (self.board:is_won()) self.outcome="win" self.done=true main.state_manager:push(state_wonround:new(self.board))
end
function state_gameround:draw()
cls(13)
self.board:draw()
end

41
state_ironman.lua Normal file
View File

@ -0,0 +1,41 @@
state_ironman=klass()
function state_ironman:init(sequence)
self.sequence=sequence
self.level=1
end
function state_ironman:enter() self:on_enter() end
function state_ironman:exit() end
function state_ironman:reenter(round)
if round.outcome=="win" then
self.level+=1
elseif round.outcome=="menu" then
self.done=true
elseif round.outcome=="restart" then
else
assert(false,"unrecognized outcome: "..round.outcome)
end
self:on_enter()
end
function state_ironman:suspend() end
function state_ironman:on_enter()
local level=self.level
if (self.done) return
if level <= #self.sequence then
local w=self.sequence[level]()
main.state_manager:push(state_gameround:new(w))
else
main.state_manager:push(state_wonironman:new())
self.done=true
end
end
function state_ironman:update()
assert(false,"wtf")
end
function state_ironman:draw()
assert(false,"wtf2")
end

34
state_manager.lua Normal file
View File

@ -0,0 +1,34 @@
state_manager=klass()
function state_manager:init()
self._states={}
end
function state_manager:push(state)
local top=self:peek()
add(self._states,state)
if (top) top:suspend(state)
state:enter(top)
end
function state_manager:pop()
local top=deli(self._states,#self._states)
if (not top) return
local new_top=self:peek()
top:exit(new_top)
if (new_top) new_top:reenter(top)
return top
end
function state_manager:peek()
return self._states[#self._states]
end
function state_manager:update()
local state=self:peek()
if (state) state:update()
while true do
local state=self:peek()
if state and state.done then self:pop() else break end
end
end
function state_manager:draw()
local state=self:peek()
if (state) state:draw()
end

117
state_menu.lua Normal file
View File

@ -0,0 +1,117 @@
state_menu=klass()
function state_menu:init()
self.selection=1
self.frame=0
local function plain_opt(n,s,a)
return menu_option:new(function() return n end,function()
main.state_manager:push(s:new(a))
end)
end
self.options={
plain_opt("excavate",state_excavate_menu,self),
plain_opt("archaeology",state_archaeology),
menu_option:new(),
menu_option:new(function()
local pref=completion_tracker:get_music_preference()
if (pref) return "stop music"
return "start music"
end,function()
completion_tracker:set_music_preference(not completion_tracker:get_music_preference())
end),
plain_opt("reset data",state_reset_menu,self),
plain_opt("tips",state_archaeology,true)
}
end
function state_menu:enter() end
function state_menu:exit() end
function state_menu:reenter()
self.selection=1
end
function state_menu:suspend()
self.selection=nil
end
function state_menu:update()
self.frame+=1
self.frame%=1024
if (btnp(1) or btnp(4)) sounds:menu() self.options[self.selection]:cb() return
local vel=0
if (btnp(2)) vel-=1
if (btnp(3)) vel+=1
if vel!=0 then
while true do
self.selection=(self.selection+vel-1)%#self.options+1
if (self.options[self.selection].cb!=nil) break
end
end
end
function state_menu:draw()
cls(13)
self:draw_bg()
local optionsh=1
for o in all(self.options) do
optionsh+=2
if (o.cb) optionsh+=4
end
local totalh=optionsh+32
local y=128-totalh-1--64-totalh\2
-- rectfill(68,y,126,y+totalh-1,13)
local y0=y
spr(64,68,y,7,3)
y+=22
line(68,y,126,y,15)
y+=2
local optionsy=y+1
rectfill(68,y,126,y+optionsh-1,4)
y+=optionsh+1
line(68,y,126,y,15)
y+=2
print("by pyrex & nyeo",68,y,15)
local y1=y
local x=69
y=optionsy
for i=1,#self.options do
local o=self.options[i]
if (self.selection==i) spr(71,x-7+cos(time())*0.5,y)
local fg=13
if (o.cb) fg=15
if o.name then
print(o.name(),x,y,fg)
y+=6
else
line(x-1,y,x+57,y,fg)
y+=2
end
end
-- metascore
local metascore=completion_tracker:get_metascore()
if metascore>0 then
spr(72,66,y0-9,2,1)
print("="..tostr(metascore,2),79,y0-6,6)
end
end
function state_menu:draw_bg()
pal(7,1)
pal(13,1)
local m=128-(self.frame/2)%128
for col=-8,7 do
for row=-3,7 do
local realx=flr(col*32-row*16)+m
local realy=flr(row*30-col*12)
spr(76,realx,realy,4,4)
end
end
pal()
end
menu_option=klass()
function menu_option:init(name,cb)
self.name=name
self.cb=cb
end

62
state_reset_menu.lua Normal file
View File

@ -0,0 +1,62 @@
state_reset_menu=klass()
function state_reset_menu:init(prior_menu)
self.prior_menu=prior_menu
self.options="⬅️➡️⬆️⬇️🅾️"
self.code={}
self.code_i=1
for i=1,5 do
local i=flr(rnd(#self.options))
add(self.code,i)
end
end
function state_reset_menu:enter() end
function state_reset_menu:exit(new_top) end
function state_reset_menu:reenter() end
function state_reset_menu:suspend() end
function state_reset_menu:update()
for o=0,5 do
if btnp(o) then
if self.code_i>#self.code then
run()
end
if self.code[self.code_i]==o then
sounds:dire()
self.code_i+=1
if (self.code_i>#self.code) completion_tracker:reset()
else
self.done=true
end
return
end
end
end
function state_reset_menu:caption()
if (self.code_i > #self.code) return "savedata reset!"
local caption="to reset your\nsavedata, type\nthis code\n\n"
local code="\f7"
for i=1,#self.code do
local o=self.code[i]+1
local c=sub(self.options,o,o)
if (i-1<self.code_i and i>=self.code_i) code..="\ff"
if (i!=1) code..=" "
code..=c
end
return caption..code
end
function state_reset_menu:draw()
self.prior_menu:draw()
local caption=self:caption()
local w,h=measure_text(caption)
h-=1
local x=64-w\2
local y=64-h\2
rect(x-2,y-2,x+w+1,y+h+1,15)
rectfill(x-1,y-1,x+w,y+h,4)
print(caption,x,y,15)
end

31
state_wonironman.lua Normal file
View File

@ -0,0 +1,31 @@
state_wonironman=klass()
function state_wonironman:init()
end
function state_wonironman:enter()
sounds:win()
completion_tracker:incr_metascore()
end
function state_wonironman:exit(new_top) end
function state_wonironman:reenter() end
function state_wonironman:suspend() end
function state_wonironman:update()
if (btnp(4)) sounds:menu() self.done=true self.outcome="menu"
end
function state_wonironman:draw()
cls(13)
local msg="you have reached the bottom\n\nreceive one majestic kroner"
local w,h=measure_text(msg)
local x=64-w\2
local y=64-h\2
line(64-7,y-3,64+7,y-3,15)
line(64-7,y+h+1,64+7,y+h+1,15)
rectfill(x-1,y-1,x+w,y+h-1,4)
print(msg,x,y,15)
y+=h+3
spr(72,64-6,y,2,1)
line(64-7,y+9,64+7,y+9,15)
print("next",57,y+11,15)
print("(🅾️)",57,y+17,15)
end

76
state_wonround.lua Normal file
View File

@ -0,0 +1,76 @@
state_wonround=klass()
function state_wonround:init(board)
self.board=board
self.frame=0
self.frames=30
self.progress=0.0
self.card=self.board:get_endgame_card()
self.verse_id,self.verse_name,self.verse=liturgy:suggest_verse(self.board.ruleset,self.card)
end
seen_tip_this_session=false
function state_wonround:enter()
sounds:win()
completion_tracker:mark_seen(self.verse_id)
completion_tracker:advance_completion_level(self.board:get_completion_level())
if (self.board.watcher:allow_tips()) self.tip=deli(_won_round_tips,1) add(_won_round_tips,self.tip)
end
function state_wonround:exit(new_top) end
function state_wonround:reenter() end
function state_wonround:suspend() end
function state_wonround:update()
self.frame=min(self.frame+1,self.frames)
self.progress=self.frame/self.frames
self.board:set_restart_progress(self.progress)
if (self.progress<1.0) return
if (btnp(4)) sounds:menu() self.done=true
end
function state_wonround:draw()
cls(13)
if self.progress<1.0 then
self.board:draw()
return
end
self.board.ruleset.deck:draw_card(0,0,self.card,{})
poke(0x5f54,0x60)
-- blow it up
sspr(0,0,9,16,55,28+sin(time())+0.5,18,32)
poke(0x5f54,0x00)
rectfill(0,0,8,15,13)
local w,_=measure_text(self.verse_name)
local x=64-w\2
-- rectfill(x,64,x+w-2,70,4)
print(self.verse_name,x,64,15)
line(x,70,x+w-2,70,15)
local oldx,oldw=x,w
local y=73
local w,h=measure_text(self.verse)
local x=64-w\2
rectfill(x-1,y-1,x+w,y+h-1,4)
print(self.verse,x,y,15)
--[[
for line in all(split(self.verse,"\n")) do
local w,_=measure_text(line)
print(line,64-w\2,y,7)
y+=6
end
]]--
y+=h+1
line(oldx,y,oldx+oldw-2,y,15)
print("next",57,y+2,15)
print("(🅾️)",57,y+8,15)
if self.tip then
local w=measure_text(self.tip)
print(self.tip,64-w\2,122,15)
end
end
_won_round_tips={
"tip: hold ❎ to restart",
"tip: hold 🅾️ to stack cards"
}

9
text.lua Normal file
View File

@ -0,0 +1,9 @@
function measure_text(s)
local w=0
local lines=split(s,"\n")
for l in all(lines) do
w=max(w,print(l,0,128))
end
local h=#lines*6
return w,h
end

48
tutorial.lua Normal file
View File

@ -0,0 +1,48 @@
standard_watcher_cb=function(i) return function() return watcher:new(progression[i]) end end
tutorial={
-- function() return watcher:new(progression[6]) end,
function()
return watcher:new(progression[1], 10,{
tutorial_grab:new(1,4,"stack cards ascending..."),
tutorial_grab:new(5,1,"... or descending."),
tutorial_grab:new(4,3),
tutorial_grab:new(2,4,"fill the wells."),
})
end,
function()
return watcher:new(progression[2], 10,{
tutorial_grab:new(1,6,"use the extra slot."),
tutorial_grab:new(1,2,"it blocks the wells."),
tutorial_grab:new(1,5,"it blocks the wells."),
tutorial_grab:new(1,5,"it blocks the wells."),
tutorial_grab:new(2,1,"it blocks the wells."),
tutorial_grab:new(2,1,"it blocks the wells."),
tutorial_grab:new(6,1,"drag it down."),
})
end,
function()
return watcher:new(progression[3],3,{
tutorial_grab:new(7,6,"here are more cards."),
tutorial_undo:new("undo. (or hold to restart.)"),
tutorial_grab:new(6,7),
tutorial_grab:new(6,8,"they have their own well."),
tutorial_grab:new(2,6,"it can't be blocked."),
tutorial_grab:new(2,4,"stack ascending or descending."),
tutorial_grab:new(3,1,"collect the last card\nto read a scroll!"),
})
end,
standard_watcher_cb(4),
standard_watcher_cb(5),
standard_watcher_cb(6),
standard_watcher_cb(7),
completion_stage=3
}
non_tutorial={
standard_watcher_cb(3),
standard_watcher_cb(4),
standard_watcher_cb(5),
standard_watcher_cb(6),
standard_watcher_cb(7)
}

100
watcher.lua Normal file
View File

@ -0,0 +1,100 @@
watcher=klass()
function watcher:init(ruleset,seed,stages)
self.ruleset=ruleset
self.seed=seed
self._stages=stages or {}
self._allow_tips=#self._stages == 0
end
function watcher:allow_tips()
return self._allow_tips
end
function watcher:active_stage(board)
local stage=self._stages[1]
if (stage and stage:active()) return stage
end
function watcher:intercept(x,arg)
local stage=self:active_stage()
if (not stage) return true
local allowed,drop=stage:intercept(x,arg)
if (drop) deli(self._stages,1)
return allowed
end
function watcher:draw(board)
local stage=self:active_stage()
if (not stage) return
local layouts=board.ruleset.layouts
local layout,i,x,y,text
layout,i,text=stage:draw(board,layouts)
x,y=layout:place_card(i)
local w,h=measure_text(text)
x+=1
y+=20
local lx=x+3
rectfill(x-2,y-2,x+w,y+h,1)
rect(x-2,y-2,x+w,y+h,15)
print(text,x,y,15)
local note=stage.note
if (not note) return
local w,h=measure_text(note)
local x=64-w\2
local y=88
rectfill(x-1,y-1,x+w-1,y+h-1,1)
rect(x-2,y-2,x+w,y+h,15)
print(note,x,y,15)
end
tutorial_grab=klass()
function tutorial_grab:init(src,dst,note)
self.src=src
self.dst=dst
self.note=note
end
function tutorial_grab:active()
return true
end
function tutorial_grab:intercept(x, slot)
if (x=="grab" and slot==self.src) return true,false
if (x=="drop" and slot==self.dst) return true,true
end
function tutorial_grab:draw(board,layouts)
local layout,i,text
if board.cursor:grabbed_card() == nil then
-- show a hint for grabbing
layout=layouts:slot(self.src)
i=#board.slots[self.src].contents
draw_layout_hint(layout,i,15,false,true)
text="🅾️"
else
layout=layouts:slot(self.dst)
i=#board.slots[self.dst].contents+2
draw_layout_hint(layout,i,15,false,true)
text="🅾️"
end
return layout,i,text
end
tutorial_undo=klass()
function tutorial_undo:init(note)
self.note=note
end
function tutorial_undo:active()
return true
end
function tutorial_undo:intercept(x)
if (x=="undo") return true,true
end
function tutorial_undo:draw(board,layouts)
local layout,i,text
layout=layouts:checkpoint()
draw_layout_hint(layout,0,15,false,true)
text=""
return layout,i,text
end
-- todo: restart?