From e18455245834482768d77ce47aa1ec350a88a466 Mon Sep 17 00:00:00 2001 From: Nyeogmi Date: Sat, 10 Feb 2024 20:40:12 -0800 Subject: [PATCH] Tutorial: improved --- board.lua | 22 +++++------- cursor.lua | 41 +++++++-------------- layout_hint.lua | 21 +++++++++++ main.lua | 2 +- main.p8 | 4 +-- state_ironman.lua | 12 +++---- tutorial.lua | 42 +++++++++++++++++----- tutorial_watcher.lua | 59 ------------------------------ watcher.lua | 85 ++++++++++++++++++++++++++++++++++++++++++++ 9 files changed, 169 insertions(+), 119 deletions(-) create mode 100644 layout_hint.lua delete mode 100644 tutorial_watcher.lua create mode 100644 watcher.lua diff --git a/board.lua b/board.lua index 2cd1659..d393942 100644 --- a/board.lua +++ b/board.lua @@ -1,7 +1,8 @@ board=klass() -function board:init(watcher,ruleset) - self.watcher=watcher +function board:init(w) + local ruleset=w.ruleset + self.watcher=w self.ruleset=ruleset self.cursor=cursor:new(self) self.animator=animator:new() @@ -44,9 +45,7 @@ function board:init(watcher,ruleset) return new.rank==lst.rank-1 end)) - local seed=seeds:choose(self.ruleset.pool) - printh("chosen seed: "..tostr(seed,2)) - self:deal(watcher.seed or seeds:choose(self.ruleset.pool)) + self:deal(w.seed or seeds:choose(self.ruleset.pool)) end function board:deal(seed) @@ -70,13 +69,13 @@ function board:deal(seed) end 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 end function board:on_idle() self:find_automove() - self.watcher:update(self) end function board:pre_move(card) @@ -85,7 +84,6 @@ end function board:on_move() self:find_automove() - self.watcher:update(self) end function board:is_won() @@ -166,7 +164,6 @@ function board:draw() 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}) - print("❎",x+1,y+9,7) end self.animator:draw() @@ -175,13 +172,12 @@ function board:draw() 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(l,x,y) + self.cursor:draw_at(l,n+1) end end) - end - self.watcher:draw(self) + self.watcher:draw(self) + end end slot=klass() diff --git a/cursor.lua b/cursor.lua index d624445..19e456f 100644 --- a/cursor.lua +++ b/cursor.lua @@ -34,15 +34,19 @@ 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 (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 + if (not self.board.watcher:intercept("drop",slot)) return self.board:pre_move(src:peek()) local card=src:pop() tar:add(card) self.grabbed=nil self.board:on_move(card) 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 else assert(false,"invalid acceptance state") @@ -73,42 +77,23 @@ function cursor:grabbed_card() return nil end -function cursor:draw_at(l,x,y) +function cursor:draw_at(l,i) local card=self:grabbed_card() 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 - x+=sin(time()/2)*2+0.5 - y+=sin(time()/4)+0.5+1 + dx=flr(sin(time()/2)*2+0.5) + dy=flr(sin(time()/4)+0.5+1) 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 - 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 if (acc==acceptance_state.would_accept) fg=9 - draw_surround_box(fg) + draw_layout_hint(l,i,fg,false,dx,dy) else - draw_overlapping_box(9) + draw_layout_hint(l,i,9,true,dx,dy) end end \ No newline at end of file diff --git a/layout_hint.lua b/layout_hint.lua new file mode 100644 index 0000000..e4e1d6d --- /dev/null +++ b/layout_hint.lua @@ -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 \ No newline at end of file diff --git a/main.lua b/main.lua index 372dc7d..977873c 100644 --- a/main.lua +++ b/main.lua @@ -4,7 +4,7 @@ add(modules,main) function main:init() extcmd("rec") 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 function main:update() diff --git a/main.p8 b/main.p8 index 82f8932..1064254 100644 --- a/main.p8 +++ b/main.p8 @@ -9,6 +9,7 @@ __lua__ #include dealer.lua #include cursor.lua #include layout.lua +#include layout_hint.lua #include ruleset.lua #include progression.lua #include seed_constants.lua @@ -16,11 +17,10 @@ __lua__ #include state_manager.lua #include state_gameround.lua #include state_ironman.lua -#include tutorial_watcher.lua #include tutorial.lua #include text.lua +#include watcher.lua #include main.lua - --[[ srand(2) for i=1,10 do diff --git a/state_ironman.lua b/state_ironman.lua index 786f79b..12f052c 100644 --- a/state_ironman.lua +++ b/state_ironman.lua @@ -1,7 +1,7 @@ state_ironman=klass() -function state_ironman:init() +function state_ironman:init(sequence) + self.sequence=sequence self.level=1 - self.tutorial_enabled=true end function state_ironman:enter() self:on_enter() end @@ -14,11 +14,9 @@ function state_ironman:on_enter() self.done=true local level=self.level self.level+=1 - if level <= #progression then - local watcher_fn=tutorial[level] - local watcher=tutorial_watcher:new() - if (self.tutorial_enabled and watcher_fn) watcher=watcher_fn() - main.state_manager:push(state_gameround:new(watcher, progression[level])) + if level <= #self.sequence then + local w=self.sequence[level]() + main.state_manager:push(state_gameround:new(w)) end end diff --git a/tutorial.lua b/tutorial.lua index 26a1487..1bf2f1d 100644 --- a/tutorial.lua +++ b/tutorial.lua @@ -1,12 +1,36 @@ tutorial={ - [1]=function() - return tutorial_watcher:new(10,{ - tutorial_stage:new( - "slot",1,2, - tutorial_move_slot(1,1), - "stack on 5! (🅾️)", - function(b) return b:can_take_input() end - ) + function() + return watcher:new(progression[1], 10,{ + tutorial_grab:new(1,4), + tutorial_grab:new(5,1), + tutorial_grab:new(4,3), + tutorial_grab:new(2,4), }) - 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 } diff --git a/tutorial_watcher.lua b/tutorial_watcher.lua deleted file mode 100644 index 931261f..0000000 --- a/tutorial_watcher.lua +++ /dev/null @@ -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 \ No newline at end of file diff --git a/watcher.lua b/watcher.lua new file mode 100644 index 0000000..7cbf18d --- /dev/null +++ b/watcher.lua @@ -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? \ No newline at end of file