fortunes_foundation/board.lua

264 lines
6.0 KiB
Lua
Raw Normal View History

2024-02-05 04:55:56 +00:00
board=klass()
2024-02-11 04:40:12 +00:00
function board:init(w)
local ruleset=w.ruleset
self.watcher=w
2024-02-05 06:11:17 +00:00
self.ruleset=ruleset
2024-02-05 04:55:56 +00:00
self.cursor=cursor:new(self)
2024-02-05 06:55:13 +00:00
self.animator=animator:new()
2024-02-10 06:35:55 +00:00
self.checkpoint=nil
2024-02-05 04:55:56 +00:00
self.slots={}
self.wells={}
2024-02-11 05:41:48 +00:00
self.restart_progress=0
2024-02-05 04:55:56 +00:00
-- board slots
2024-02-05 06:11:17 +00:00
-- ...n_slots: normal
for i=1,ruleset.n_slots do
add(self.slots,slot:new(ruleset))
2024-02-05 04:55:56 +00:00
end
2024-02-05 06:11:17 +00:00
-- n_slots+1: special
add(self.slots,slot:new(ruleset,1))
2024-02-05 04:55:56 +00:00
-- wells:
2024-02-05 06:11:17 +00:00
-- ...n_suits: wands, cups, swords, pentacles, etc
2024-02-05 04:55:56 +00:00
local function add_suit(_self,suit)
2024-02-10 06:17:57 +00:00
local w=well:new(_self.ruleset, function(lst,new)
2024-02-05 04:55:56 +00:00
assert(lst) -- the ace is always present initially
if (new.suit!=suit) return
return new.suit==suit and new.rank==lst.rank+1
2024-02-10 06:17:57 +00:00
end)
w.obscured_by_extra_slot=true
add(_self.wells, w)
2024-02-05 04:55:56 +00:00
end
2024-02-05 06:11:17 +00:00
for suit in all(self.ruleset.deck.suits) do
2024-02-05 04:55:56 +00:00
add_suit(self,suit)
end
2024-02-05 06:11:17 +00:00
-- n_suits+1: arcana ascending
add(self.wells,well:new(self.ruleset,function(lst,new)
2024-02-05 04:55:56 +00:00
if (new.suit!='a') return
if (not lst) return new.rank==0
return new.rank==lst.rank+1
end))
2024-02-11 21:44:45 +00:00
self.wells[#self.wells].obscured_by_last_well=true
2024-02-05 06:11:17 +00:00
-- n_suits+2: arcana descending
add(self.wells,well:new(self.ruleset,function(lst,new)
2024-02-05 04:55:56 +00:00
if (new.suit!='a') return
2024-02-05 06:11:17 +00:00
if (not lst) return new.rank==self.ruleset.n_arcana-1
2024-02-05 04:55:56 +00:00
return new.rank==lst.rank-1
end))
2024-02-11 21:44:45 +00:00
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))
2024-02-05 04:55:56 +00:00
2024-02-11 04:40:12 +00:00
self:deal(w.seed or seeds:choose(self.ruleset.pool))
2024-02-05 04:55:56 +00:00
end
2024-02-11 21:44:45 +00:00
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
2024-02-10 02:13:39 +00:00
function board:deal(seed)
local deal=deal(self.ruleset,seed)
2024-02-05 06:11:17 +00:00
local n_usable_slots=self.ruleset.n_slots - 1
2024-02-05 06:11:17 +00:00
for i=1,#self.ruleset.deck.aces do
2024-02-05 04:55:56 +00:00
local well=self.wells[i]
2024-02-05 06:11:17 +00:00
local ace=self.ruleset.deck.aces[i]
2024-02-05 06:55:13 +00:00
self:animate_move_ace_to_well(ace,i)
2024-02-05 04:55:56 +00:00
end
local rows=#deal[1]
for y=1,rows do
for x=1,#deal do
local outx=x
if (x>n_usable_slots\2) outx+=1
self:animate_move_new_card_to_slot(deal[x][y],outx)
2024-02-05 04:55:56 +00:00
end
end
end
2024-02-11 05:41:48 +00:00
function board:set_restart_progress(progress)
self.restart_progress=progress
end
function board:get_completion_level()
return self.ruleset.completion_level
end
2024-02-10 06:35:55 +00:00
function board:undo()
2024-02-12 04:54:01 +00:00
if (not self.checkpoint) return
if (not self.watcher:intercept("undo")) sounds:dire() return
sounds:menu()
self.checkpoint:apply(self)
2024-02-10 06:35:55 +00:00
self.checkpoint=nil
end
2024-02-05 06:55:13 +00:00
function board:on_idle()
self:find_automove()
end
2024-02-10 06:35:55 +00:00
function board:pre_move(card)
self.checkpoint=checkpoint:new(self,card)
end
2024-02-05 04:55:56 +00:00
function board:on_move()
2024-02-05 06:55:13 +00:00
self:find_automove()
2024-02-05 04:55:56 +00:00
end
2024-02-11 01:44:38 +00:00
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
2024-02-05 06:55:13 +00:00
function board:find_automove()
2024-02-05 04:55:56 +00:00
for s=1,#self.slots do
local top=self.slots[s]:peek()
if top then
2024-02-11 21:44:45 +00:00
for w=#self.wells,1,-1 do
2024-02-05 06:11:17 +00:00
if w<=self.ruleset.n_suits and self.slots[self.ruleset.n_slots+1]:peek()!=nil then
2024-02-05 04:55:56 +00:00
-- the top wells are blocked
elseif self.wells[w]:would_accept(top) then
2024-02-05 06:55:13 +00:00
self:animate_and_move_to_well(s,w)
2024-02-11 21:44:45 +00:00
self.last_card=top
2024-02-05 06:55:13 +00:00
2024-02-05 04:55:56 +00:00
return true
end
end
end
end
end
2024-02-05 06:55:13 +00:00
function board:can_take_input()
return self.animator:idle()
end
function board:update()
local was_idle=self.animator:idle()
self.animator:update()
local is_idle=self.animator:idle()
if (not was_idle and is_idle) then
self:on_idle()
end
2024-02-12 23:03:55 +00:00
if (is_idle) self.cursor:update()
2024-02-05 06:55:13 +00:00
end
2024-02-05 04:55:56 +00:00
function board:draw()
2024-02-10 06:17:57 +00:00
local extra_slot_full=self.slots[self.ruleset.n_slots+1]:peek()!=nil
2024-02-11 21:44:45 +00:00
local last_well_full=self.wells[#self.wells]:peek()!=nil
2024-02-05 04:55:56 +00:00
for w_ix=1,#self.wells do
local w=self.wells[w_ix]
2024-02-05 06:11:17 +00:00
local l=self.ruleset.layouts:well(w_ix)
2024-02-05 04:55:56 +00:00
2024-02-10 06:17:57 +00:00
local shadowed=nil
2024-02-11 21:44:45 +00:00
if w.obscured_by_last_well and last_well_full then
shadowed=true
end
2024-02-10 06:17:57 +00:00
if w.obscured_by_extra_slot and extra_slot_full then
shadowed=true
end
2024-02-05 04:55:56 +00:00
for i=1,#w.contents do
local x,y=l:place_card(i)
2024-02-11 21:44:45 +00:00
self.ruleset.deck:draw_card(x,y,w.contents[i],{rotate=l.rotated,shadowed=shadowed})
2024-02-05 04:55:56 +00:00
end
end
local function forall_slots(cb)
for s_ix=1,#self.slots do
local s=self.slots[s_ix]
2024-02-05 06:11:17 +00:00
local l=self.ruleset.layouts:slot(s_ix)
2024-02-05 04:55:56 +00:00
local n=#s.contents
if (self.cursor.grabbed==s_ix) n-=1
cb(x,y,s_ix,s,l,n)
end
end
forall_slots(function(x,y,s_ix,s,l,n)
for i=1,n do
local x,y=l:place_card(i)
2024-02-10 06:17:57 +00:00
self.ruleset.deck:draw_card(x,y,s.contents[i],{rotate=l.rotated})
2024-02-05 04:55:56 +00:00
end
end)
2024-02-10 06:35:55 +00:00
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
2024-02-05 06:55:13 +00:00
self.animator:draw()
if self.animator:idle() then
2024-02-11 04:56:48 +00:00
self.watcher:draw(self)
2024-02-05 06:55:13 +00:00
local hover_slot=self.cursor:hover_slot()
forall_slots(function(x,y,s_ix,s,l,n)
if hover_slot==s_ix then
2024-02-11 04:56:48 +00:00
self.cursor:draw_at(l,n)
2024-02-05 06:55:13 +00:00
end
end)
2024-02-11 04:40:12 +00:00
end
2024-02-11 05:41:48 +00:00
democrap:distort_screen(self.restart_progress)
2024-02-05 04:55:56 +00:00
end
slot=klass()
2024-02-05 06:11:17 +00:00
function slot:init(ruleset,max_n)
self.ruleset=ruleset
2024-02-05 04:55:56 +00:00
self.contents={}
self.max_n=max_n
end
function slot:would_accept(new)
local n=#self.contents
if (n==self.max_n) return
local lst=self.contents[n]
if (not lst) return true
2024-02-05 06:11:17 +00:00
lst=self.ruleset.deck.cards[lst]
new=self.ruleset.deck.cards[new]
2024-02-05 04:55:56 +00:00
return lst.suit==new.suit and (lst.rank==new.rank-1 or lst.rank==new.rank+1)
end
function slot:add(card)
add(self.contents,card)
end
function slot:peek()
return self.contents[#self.contents]
end
function slot:pop()
return deli(self.contents,#self.contents)
end
well=klass()
2024-02-05 06:11:17 +00:00
function well:init(ruleset,accept_cb)
self.ruleset=ruleset
2024-02-05 04:55:56 +00:00
self.accept_cb=accept_cb
self.contents={}
end
function well:would_accept(new)
local lst=self.contents[#self.contents]
2024-02-05 06:11:17 +00:00
if (lst) lst=self.ruleset.deck.cards[lst]
2024-02-05 04:55:56 +00:00
assert(new,"must be populated")
2024-02-05 06:11:17 +00:00
new=self.ruleset.deck.cards[new]
2024-02-05 04:55:56 +00:00
assert(new,"must be populated")
return self.accept_cb(lst,new)
end
function well:add(card)
add(self.contents,card)
2024-02-05 06:55:13 +00:00
end
function well:clear()
self.contents={}
2024-02-11 21:44:45 +00:00
end
function well:peek()
return self.contents[#self.contents]
2024-02-05 04:55:56 +00:00
end