fortunes_foundation/board.lua

194 lines
4.2 KiB
Lua

board=klass()
function board:init(ruleset)
self.ruleset=ruleset
self.cursor=cursor:new(self)
self.animator=animator:new()
self.slots={}
self.wells={}
-- board slots
-- ...n_slots: normal
for i=1,ruleset.n_slots do
add(self.slots,slot:new(ruleset))
end
-- n_slots+1: special
add(self.slots,slot:new(ruleset,1))
-- wells:
-- ...n_suits: wands, cups, swords, pentacles, etc
local function add_suit(_self,suit)
add(_self.wells,well:new(_self.ruleset, function(lst,new)
assert(lst) -- the ace is always present initially
if (new.suit!=suit) return
return new.suit==suit and new.rank==lst.rank+1
end))
end
for suit in all(self.ruleset.deck.suits) do
add_suit(self,suit)
end
-- n_suits+1: arcana ascending
add(self.wells,well:new(self.ruleset,function(lst,new)
if (new.suit!='a') return
if (not lst) return new.rank==0
return new.rank==lst.rank+1
end))
-- n_suits+2: arcana descending
add(self.wells,well:new(self.ruleset,function(lst,new)
if (new.suit!='a') return
if (not lst) return new.rank==self.ruleset.n_arcana-1
return new.rank==lst.rank-1
end))
self:deal()
end
function board:deal()
local deal=deal(self.ruleset)
local n_usable_slots=self.ruleset.n_slots - 1
for i=1,#self.ruleset.deck.aces do
local well=self.wells[i]
local ace=self.ruleset.deck.aces[i]
well:add(ace) -- temporarily, so would_accept will work
self:animate_move_ace_to_well(ace,i)
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)
end
end
end
function board:on_idle()
self:find_automove()
end
function board:on_move()
-- TODO: Make checkpoint
self:find_automove()
end
function board:find_automove()
for s=1,#self.slots do
local top=self.slots[s]:peek()
if top then
for w=1,#self.wells do
if w<=self.ruleset.n_suits and self.slots[self.ruleset.n_slots+1]:peek()!=nil then
-- the top wells are blocked
elseif self.wells[w]:would_accept(top) then
self:animate_and_move_to_well(s,w)
return true
end
end
end
end
end
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
end
function board:draw()
for w_ix=1,#self.wells do
local w=self.wells[w_ix]
local l=self.ruleset.layouts:well(w_ix)
for i=1,#w.contents do
local x,y=l:place_card(i)
self.ruleset.deck:draw_card(x,y,w.contents[i],i<#w.contents)
end
end
local function forall_slots(cb)
for s_ix=1,#self.slots do
local s=self.slots[s_ix]
local l=self.ruleset.layouts:slot(s_ix)
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)
self.ruleset.deck:draw_card(x,y,s.contents[i],i<n)
end
end)
self.animator:draw()
if self.animator:idle() then
local hover_slot=self.cursor:hover_slot()
forall_slots(function(x,y,s_ix,s,l,n)
if hover_slot==s_ix then
local x,y=l:place_card(n+1)
self.cursor:draw_at(x,y)
end
end)
end
end
slot=klass()
function slot:init(ruleset,max_n)
self.ruleset=ruleset
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
lst=self.ruleset.deck.cards[lst]
new=self.ruleset.deck.cards[new]
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()
function well:init(ruleset,accept_cb)
self.ruleset=ruleset
self.accept_cb=accept_cb
self.contents={}
end
function well:would_accept(new)
local lst=self.contents[#self.contents]
if (lst) lst=self.ruleset.deck.cards[lst]
assert(new,"must be populated")
new=self.ruleset.deck.cards[new]
assert(new,"must be populated")
return self.accept_cb(lst,new)
end
function well:add(card)
add(self.contents,card)
end
function well:clear()
self.contents={}
end