Tutorial: improved

This commit is contained in:
Pyrex 2024-02-10 20:40:12 -08:00
parent 15e86c7940
commit e184552458
9 changed files with 169 additions and 119 deletions

View File

@ -1,7 +1,8 @@
board=klass() board=klass()
function board:init(watcher,ruleset) function board:init(w)
self.watcher=watcher 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()
@ -44,9 +45,7 @@ function board:init(watcher,ruleset)
return new.rank==lst.rank-1 return new.rank==lst.rank-1
end)) end))
local seed=seeds:choose(self.ruleset.pool) self:deal(w.seed or seeds:choose(self.ruleset.pool))
printh("chosen seed: "..tostr(seed,2))
self:deal(watcher.seed or seeds:choose(self.ruleset.pool))
end end
function board:deal(seed) function board:deal(seed)
@ -70,13 +69,13 @@ function board:deal(seed)
end end
function board:undo() function board:undo()
if (self.checkpoint) self.checkpoint:apply(self) print("applied") if (not self.watcher:intercept("undo")) return
if (self.checkpoint) self.checkpoint:apply(self)
self.checkpoint=nil self.checkpoint=nil
end end
function board:on_idle() function board:on_idle()
self:find_automove() self:find_automove()
self.watcher:update(self)
end end
function board:pre_move(card) function board:pre_move(card)
@ -85,7 +84,6 @@ end
function board:on_move() function board:on_move()
self:find_automove() self:find_automove()
self.watcher:update(self)
end end
function board:is_won() function board:is_won()
@ -166,7 +164,6 @@ function board:draw()
local cpl=self.ruleset.layouts:checkpoint() local cpl=self.ruleset.layouts:checkpoint()
local x,y=cpl:place_card(0) local x,y=cpl:place_card(0)
self.ruleset.deck:draw_card(x,y,self.checkpoint.card,{shadowed=true}) self.ruleset.deck:draw_card(x,y,self.checkpoint.card,{shadowed=true})
print("",x+1,y+9,7)
end end
self.animator:draw() self.animator:draw()
@ -175,13 +172,12 @@ function board:draw()
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+1)
self.cursor:draw_at(l,x,y)
end end
end) end)
end
self.watcher:draw(self) self.watcher:draw(self)
end
end end
slot=klass() slot=klass()

View File

@ -34,15 +34,19 @@ 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)) printh("intercepted") return
if (self.board.slots[slot]:peek()) self.grabbed=slot
elseif acc==acceptance_state.would_accept then elseif acc==acceptance_state.would_accept then
if (not self.board.watcher:intercept("drop",slot)) return
self.board:pre_move(src:peek()) self.board:pre_move(src:peek())
local card=src:pop() local card=src:pop()
tar:add(card) tar:add(card)
self.grabbed=nil self.grabbed=nil
self.board:on_move(card) self.board:on_move(card)
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
if (not self.board.watcher:intercept("cancel")) return
self.grabbed=nil self.grabbed=nil
else else
assert(false,"invalid acceptance state") assert(false,"invalid acceptance state")
@ -73,42 +77,23 @@ function cursor:grabbed_card()
return nil return nil
end end
function cursor:draw_at(l,x,y) function cursor:draw_at(l,i)
local card=self:grabbed_card() local card=self:grabbed_card()
local acc=self:acceptance_state() local acc=self:acceptance_state()
local dx,dy=0,0
if card and acc!=acceptance_state.would_accept and acc!=acceptance_state.no_move then if card and acc!=acceptance_state.would_accept and acc!=acceptance_state.no_move then
x+=sin(time()/2)*2+0.5 dx=flr(sin(time()/2)*2+0.5)
y+=sin(time()/4)+0.5+1 dy=flr(sin(time()/4)+0.5+1)
end end
x=flr(x)
y=flr(y)
local function draw_surround_box(fg)
if (not fg) return
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
local function draw_overlapping_box(fg)
if (l.obscured) draw_surround_box(fg) return
if l.rotated then
rectfill(x-3,y+7,x+12,y+15,fg)
else
rectfill(x,y,x+8,y+15,fg)
end
end
if card then if card then
local card_fg=self.ruleset.deck:draw_card(x,y,card,{rotate=l.rotated}) local x,y=l:place_card(i)
local card_fg=self.ruleset.deck:draw_card(x+dx,y+dy,card,{rotate=l.rotated})
local fg=card_fg local fg=card_fg
if (acc==acceptance_state.would_accept) fg=9 if (acc==acceptance_state.would_accept) fg=9
draw_surround_box(fg) draw_layout_hint(l,i,fg,false,dx,dy)
else else
draw_overlapping_box(9) draw_layout_hint(l,i,9,true,dx,dy)
end end
end end

21
layout_hint.lua Normal file
View File

@ -0,0 +1,21 @@
function draw_layout_hint(l,i,fg,filled,dx,dy)
-- layout, index
local x,y=l:place_card(i)
x+=dx
y+=dy
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 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

View File

@ -4,7 +4,7 @@ add(modules,main)
function main:init() function main:init()
extcmd("rec") extcmd("rec")
self.state_manager=state_manager:new() -- instantiate one global self.state_manager=state_manager:new() -- instantiate one global
self.state_manager:push(state_ironman:new()) self.state_manager:push(state_ironman:new(tutorial))
end end
function main:update() function main:update()

View File

@ -9,6 +9,7 @@ __lua__
#include dealer.lua #include dealer.lua
#include cursor.lua #include cursor.lua
#include layout.lua #include layout.lua
#include layout_hint.lua
#include ruleset.lua #include ruleset.lua
#include progression.lua #include progression.lua
#include seed_constants.lua #include seed_constants.lua
@ -16,11 +17,10 @@ __lua__
#include state_manager.lua #include state_manager.lua
#include state_gameround.lua #include state_gameround.lua
#include state_ironman.lua #include state_ironman.lua
#include tutorial_watcher.lua
#include tutorial.lua #include tutorial.lua
#include text.lua #include text.lua
#include watcher.lua
#include main.lua #include main.lua
--[[ --[[
srand(2) srand(2)
for i=1,10 do for i=1,10 do

View File

@ -1,7 +1,7 @@
state_ironman=klass() state_ironman=klass()
function state_ironman:init() function state_ironman:init(sequence)
self.sequence=sequence
self.level=1 self.level=1
self.tutorial_enabled=true
end end
function state_ironman:enter() self:on_enter() end function state_ironman:enter() self:on_enter() end
@ -14,11 +14,9 @@ function state_ironman:on_enter()
self.done=true self.done=true
local level=self.level local level=self.level
self.level+=1 self.level+=1
if level <= #progression then if level <= #self.sequence then
local watcher_fn=tutorial[level] local w=self.sequence[level]()
local watcher=tutorial_watcher:new() main.state_manager:push(state_gameround:new(w))
if (self.tutorial_enabled and watcher_fn) watcher=watcher_fn()
main.state_manager:push(state_gameround:new(watcher, progression[level]))
end end
end end

View File

@ -1,12 +1,36 @@
tutorial={ tutorial={
[1]=function() function()
return tutorial_watcher:new(10,{ return watcher:new(progression[1], 10,{
tutorial_stage:new( tutorial_grab:new(1,4),
"slot",1,2, tutorial_grab:new(5,1),
tutorial_move_slot(1,1), tutorial_grab:new(4,3),
"stack on 5! (🅾️)", tutorial_grab:new(2,4),
function(b) return b:can_take_input() end
)
}) })
end end,
function()
return watcher:new(progression[2], 10,{
tutorial_grab:new(1,6),
tutorial_grab:new(1,2),
tutorial_grab:new(1,5),
tutorial_grab:new(1,5),
tutorial_grab:new(2,1),
tutorial_grab:new(2,1),
tutorial_grab:new(6,1),
})
end,
function()
return watcher:new(progression[3],3,{
tutorial_grab:new(7,6),
tutorial_undo:new(),
tutorial_grab:new(6,7),
tutorial_grab:new(6,8),
tutorial_grab:new(2,6),
tutorial_grab:new(2,4),
tutorial_grab:new(3,1),
})
end,
function() return watcher:new(progression[4]) end,
function() return watcher:new(progression[5]) end,
function() return watcher:new(progression[6]) end,
function() return watcher:new(progression[7]) end
} }

View File

@ -1,59 +0,0 @@
tutorial_watcher=klass()
function tutorial_watcher:init(seed,stages)
self.seed=seed
self._stages=stages
end
function tutorial_watcher:update(board)
local stage=self._stages[1]
if (stage) stage:update(board)
end
function tutorial_watcher:active_stage(board)
local stage=self._stages[1]
if (stage and stage:active()) return stage
end
function tutorial_watcher:draw(board)
local stage=self:active_stage()
if (not stage) return
local layouts=board.ruleset.layouts
-- stop("calling: "..stage._layout_name)
local layout=layouts[stage._layout_name](layouts,stage._layout_arg)
local x,y=layout:place_card(stage._layout_arg_2)
local tx=stage._text
local w,h=measure_text(tx)
x+=4
x-=w\2
y+=25
local lx=x+w\2
line(lx,y-9,lx,y,15)
rectfill(x-2,y-2,x+w,y+h,1)
rect(x-2,y-2,x+w,y+h,15)
print(tx,x,y,15)
end
tutorial_stage=klass()
function tutorial_stage:init(layout_name,layout_arg,layout_arg_2,move,text,requirement_cb)
self._layout_name=layout_name
self._layout_arg=layout_arg
self._layout_arg_2=layout_arg_2
self._move=move
self._text=text
self._requirement_cb=requirement_cb
self._enabled=not self._requirement_cb
end
function tutorial_stage:update(board)
if (not self._enabled and self._requirement_cb(board)) self._enabled=true
end
function tutorial_stage:active()
return self._enabled
end
-- todo: restart?
function tutorial_move_undo()
return "undo"
end
function tutorial_move_slot(slot_src,slot_dst)
return tostr(slot_src).."->"..tostr(slot_dst)
end

85
watcher.lua Normal file
View File

@ -0,0 +1,85 @@
watcher=klass()
function watcher:init(ruleset,seed,stages)
self.ruleset=ruleset
self.seed=seed
self._stages=stages or {}
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
line(lx,y-4,lx,y,15)
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)
end
tutorial_grab=klass()
function tutorial_grab:init(src,dst)
self.src=src
self.dst=dst
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:acceptance_state() == acceptance_state.not_grabbed then
-- show a hint for grabbing
layout=layouts:slot(self.src)
i=#board.slots[self.src].contents
draw_layout_hint(layout,i,15,false,0,0)
text="🅾️"
else
layout=layouts:slot(self.dst)
i=#board.slots[self.dst].contents+1
draw_layout_hint(layout,i,15,false,0,0)
text="🅾️"
end
return layout,i,text
end
tutorial_undo=klass()
function tutorial_undo:init() 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,0,0)
text=""
return layout,i,text
end
-- todo: restart?