acceptance_state={ not_grabbed=0, would_accept=1, would_not_accept=2, no_move=3 } cursor=klass() function cursor:init(board) self.ruleset=board.ruleset self.board=board self.hover_x=self.ruleset.n_slots\2 self.hover_y=1 self.saved_hover_x_y=nil self.grabbed_slots={} end function cursor:acceptance_state() local hover=self:hover_slot() local slot=self:grabbed_slot() if slot then if hover==slot then return acceptance_state.no_move end local source=self.board.slots[slot] local target=self.board.slots[self:hover_slot()] local card=source:peek() if target:would_accept(card) then return acceptance_state.would_accept,source,target else return acceptance_state.would_not_accept end else if (self.board.slots[hover]:peek()) return acceptance_state.not_grabbed return acceptance_state.would_not_accept 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() local acc,src,tar=self:acceptance_state() local slot=self:hover_slot() if acc==acceptance_state.not_grabbed then 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 if (not self.board.watcher:intercept("drop",slot)) sounds:dire() return self.board:pre_move(src:peek()) while self:acceptance_state() == acceptance_state.would_accept do 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 self:drop_grab() else assert(false,"invalid acceptance state") 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) if (self.hover_y==0) return if (dx==0) return 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 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==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 function cursor:hover_slot() if (self.hover_y==0) return self.ruleset.n_slots+1 return self.hover_x+1 end function cursor:grabbed_slot() return self.grabbed_slots[#self.grabbed_slots] end function cursor:grabbed_card() local grabbed_slot=self:grabbed_slot() if grabbed_slot then return self.board.slots[grabbed_slot]:peek() end end function cursor:draw_at(l,i) local slot=self:grabbed_slot() if not slot then local filled=false if (i<1) i=1 filled=true draw_layout_hint(l,i,12,filled) return end local not_moving=self:acceptance_state()==acceptance_state.no_move 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 if (i2==1) draw_layout_hint(l,i+i2+1,9,false) 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