Got sleeping working.
2 files changed, 16 insertions(+), 7 deletions(-)

M build/index.html
M qc.rkt
M build/index.html +6 -6
@@ 1,13 1,13 @@ 
 <!DOCTYPE html>
 <html lang="en">
   <head> <meta charset="utf-8">
-  <title>Qube*Cat - 1.0.0 </title>
+  <title>Qube*Cat - 1.0.1 </title>
   <style>@font-face { font-family: HUD; src: url('f/ShareTechMono-Regular.ttf'); }</style>
  </head>
  <body style="margin: 0;">
     <div style="display: flex; justify-content: center;">
     <canvas id="the-canvas" width="640" height="480" tabindex="1"/>
-    <script>var VERSION = "1.0.0";</script>
+    <script>var VERSION = "1.0.1";</script>
     <script>"use strict";
 var APP={name:"Qube*Cat",nickname:"qube-cat",screen:{width:640,height:480},fps:30};
 function array_p(x){"( x -- f) Is x an Array?";return (x.constructor===Array);};

          
@@ 30,7 30,7 @@ function arrange(rack,run,origin){"( rac
 function make_level(name,layout,run,base,turned,start,method){"( name layout run  base turned  start /method/ -- level) Create level.";return (((offset) => {return (((tiles) => {return ((() => {return {name:name,layout:layout,tiles:tiles,tmobs:(adjust(tiles,[-32,-96])),run:run,base:base,turn:turned,start:start,tops:(((a) => {{var a_2=layout,n=a_2.length,i=0;while((true&&true&&(i<n))){(((x) => {((a.push)((x-1)));return (i+=1);})(a_2[i]));};undefined;}return a;})([])),done:(turned.length-1),method:(method||"advance"),state:"PLAY",tick:0};})());})((arrange(layout,run,offset))));})([((APP.screen.width-(32*run))/2),(APP.screen.height-16-(48*(layout.length/run)))]));};
 var Layouts={full:[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,1,0,0,0,0,0,0,0,0,0,1,0,1,0,1,0,1,0,0,0,0,0,0,0,1,0,1,0,1,0,1,0,1,0,0,0,0,0,1,0,1,0,1,0,1,0,1,0,1,0,0,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],demo:[0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,1,0,1,0,0,0,1,0,1,0,1,0,0,0,0,0,0,0,0]};
 var Levels=[(make_level("Gentle Demo",Layouts.demo,7,["#ffc2c7","#b6e5d8"],["#8fdde7","#ffff00"],10)),(make_level("Sweet Breeze",Layouts.full,15,["#ffc2c7","#b6e5d8"],["#8fdde7","#ffff00"],22)),(make_level("Light Rain",Layouts.full,15,["#eeb5eb","#c26dbc"],["#3cacae","#c8f4f9"],22)),(make_level("Thunder!",Layouts.full,15,["#000c66","#050a30"],["#0000ff","#ff3333","#7ec8e3"],22))];
-var Game={cx:false,timestamp_old:false,nlevel:0,level:false,clock:0,log:{fps:0}};
+var Game={cx:false,timestamp_old:false,nlevel:0,level:false,clock:0,log:{keytick:0,fps:0}};
 function level_set(n,state){"( n /state/ --) Set (or reset) level.";(all_stop());((yarnball)["state"]="HIDE");((Game)["nlevel"]=n);((Game)["level"]=Levels[n]);((Game)["level"]["state"]=(state||Game.level.state));((Game)["clock"]=0);((Sounds)["king"]["loop"]=true);(play("king"));return (mob_dropping(player,Game.level.start));};
 var player={i:22,t:-1,x:0,face:0,frame:0,tick:0,state:"IDLE",score:0,falls:0,anim:{IDLE:[[0,7],[1,8],0],IDL2:[[0,15],[0,15],0],SLEP:[[9,15],[10,15],0],JUMP:[[2,3],[3,3],[4,99]],PLAY:[],PTLI:[],PTLO:[],FALL:[[5,15],[6,15],[5,5],[6,5],2],DROP:[[6,5],[7,5],[8,99]]}};
 var yarnball={i:22,target:-1,x:0,frame:0,tick:0,state:"HIDE",anim:{IDLE:[[0,99]],JUMP:[[2,10],[1,10],[2,99]],DROP:[[0,10],[2,2],[0,99]]}};

          
@@ 49,12 49,12 @@ function yarnball_landing(m,target){((m)
 function frame_get(m,n){"( m /n/ -- (s d)|f|state) Get next frame from current animation.";return m.anim[m.state][(n||m.frame)];};
 function frame_set(m,f){"( m f -- m) Set m.frame to f. Reset ticks.";((m)["frame"]=f);((m)["tick"]=0);return m;};
 function state_set(m,s){"( m s -- m) Set new state for mob.";((m)["state"]=s);return (frame_set(m,0));};
-function animate(){"( --) Handle animation loops.";((player)["tick"]=(player.tick+1));(((frame) => {return ((() => {return ((((second(frame))<player.tick)===false)?undefined:((() => {return (((fn) => {return (((next) => {return ((() => {return (((array_p(next))===false)?(((string_p(next))===false)?((() => {return (frame_set(player,next));})()):((() => {((player)["state"]=frame);return (frame_set(player,0));})())):((() => {return (frame_set(player,fn));})()));})());})((frame_get(player,fn))));})((player.frame+1)));})()));})());})((frame_get(player))));((("JUMP"===player.state)===false)?((("FALL"===player.state)===false)?((("DROP"===player.state)===false)?undefined:((() => {((player)["x"]=[((first(player.x))-(second(player.x))),(second(player.x))]);return (((zero_p((first(player.x))))===false)?undefined:((() => {return (player_landing(player,Game.level.start));})()));})())):((() => {((player)["x"]=[((first(player.x))+(second(player.x))),(2+(second(player.x)))]);return (((320<(first(player.x)))===false)?undefined:((() => {return (mob_dropping(player,Game.level.start));})()));})())):((() => {((player)["x"]=(player.x+0.1));return (((1.0<=player.x)===false)?undefined:((() => {return (((zero_p(Game.level.layout[player.target]))===false)?(player_landing(player,player.target)):(player_falling(player,player.target)));})()));})()));((yarnball)["tick"]=(yarnball.tick+1));(((("HIDE"===yarnball.state)&&(!("PAWS"===Game.level.state))&&(99<Game.level.layout.length)&&(!(player.i===Game.level.start))&&(0.97<((Math.random)())))===false)?((("DROP"===yarnball.state)===false)?((("JUMP"===yarnball.state)===false)?undefined:((() => {((yarnball)["x"]=(yarnball.x+0.05));return (((1.0<=yarnball.x)===false)?undefined:((() => {return (((zero_p(Game.level.layout[yarnball.target]))===false)?(yarnball_landing(yarnball,yarnball.target)):(state_set(yarnball,"HIDE")));})()));})())):((() => {((yarnball)["x"]=[((first(yarnball.x))-(second(yarnball.x))),(second(yarnball.x))]);return (((zero_p((first(yarnball.x))))===false)?undefined:((() => {return (yarnball_landing(yarnball,Game.level.start));})()));})())):((() => {return (mob_dropping(yarnball,Game.level.start));})()));(((((-1===player.target)&&(yarnball.target===player.i))||((-1<player.target)&&(yarnball.target===player.target)))===false)?undefined:((() => {return (level_pawsing(Game.level));})()));return (((("PAWS"===Game.level.state)&&(150<Game.level.tick))===false)?undefined:((() => {return ((Game)["level"]["state"]="PLAY");})()));};
+function animate(){"( --) Handle animation loops.";((player)["tick"]=(player.tick+1));(((frame) => {return ((() => {return ((((second(frame))<player.tick)===false)?undefined:((() => {return (((fn) => {return (((next) => {return ((() => {return (((array_p(next))===false)?(((string_p(next))===false)?((() => {return (frame_set(player,next));})()):((() => {((player)["state"]=frame);return (frame_set(player,0));})())):((() => {return (frame_set(player,fn));})()));})());})((frame_get(player,fn))));})((player.frame+1)));})()));})());})((frame_get(player))));((("JUMP"===player.state)===false)?((("FALL"===player.state)===false)?((("DROP"===player.state)===false)?(((("IDLE"===player.state)&&(90<Game.log.keytick))===false)?(((("IDL2"===player.state)&&(300<Game.log.keytick))===false)?undefined:((() => {return (state_set(player,"SLEP"));})())):((() => {return (state_set(player,"IDL2"));})())):((() => {((player)["x"]=[((first(player.x))-(second(player.x))),(second(player.x))]);return (((zero_p((first(player.x))))===false)?undefined:((() => {return (player_landing(player,Game.level.start));})()));})())):((() => {((player)["x"]=[((first(player.x))+(second(player.x))),(2+(second(player.x)))]);return (((320<(first(player.x)))===false)?undefined:((() => {return (mob_dropping(player,Game.level.start));})()));})())):((() => {((player)["x"]=(player.x+0.1));return (((1.0<=player.x)===false)?undefined:((() => {return (((zero_p(Game.level.layout[player.target]))===false)?(player_landing(player,player.target)):(player_falling(player,player.target)));})()));})()));((yarnball)["tick"]=(yarnball.tick+1));(((("HIDE"===yarnball.state)&&(!("PAWS"===Game.level.state))&&(99<Game.level.layout.length)&&(!(player.i===Game.level.start))&&(0.97<((Math.random)())))===false)?((("DROP"===yarnball.state)===false)?((("JUMP"===yarnball.state)===false)?undefined:((() => {((yarnball)["x"]=(yarnball.x+0.05));return (((1.0<=yarnball.x)===false)?undefined:((() => {return (((zero_p(Game.level.layout[yarnball.target]))===false)?(yarnball_landing(yarnball,yarnball.target)):(state_set(yarnball,"HIDE")));})()));})())):((() => {((yarnball)["x"]=[((first(yarnball.x))-(second(yarnball.x))),(second(yarnball.x))]);return (((zero_p((first(yarnball.x))))===false)?undefined:((() => {return (yarnball_landing(yarnball,Game.level.start));})()));})())):((() => {return (mob_dropping(yarnball,Game.level.start));})()));(((((-1===player.target)&&(yarnball.target===player.i))||((-1<player.target)&&(yarnball.target===player.target)))===false)?undefined:((() => {return (level_pawsing(Game.level));})()));return (((("PAWS"===Game.level.state)&&(150<Game.level.tick))===false)?undefined:((() => {return ((Game)["level"]["state"]="PLAY");})()));};
 var d2face={sw:0,se:1,ne:3,nw:2};
 function dir2loc(start,d){"( start d -> location) Figure out new location from start and direction.";return (((run) => {return ((("sw"===d)===false)?((("se"===d)===false)?((("ne"===d)===false)?((("nw"===d)===false)?undefined:((() => {return (start-run-(-1));})())):((() => {return (start-run-1);})())):((() => {return (start+run+1);})())):((() => {return (start+run+-1);})()));})(Game.level.run));};
 function jumping(mob,d){"( mob d --) Set mob up for jump.";((mob)["state"]="JUMP");((mob)["x"]=0.0);((mob)["target"]=(dir2loc(mob.i,d)));((mob)["face"]=d2face[d]);return (frame_set(mob,0));};
-function game_loop(timestamp){(((cx) => {return (((fps_limit) => {return (((delta) => {return (((seconds_passed) => {return (((fps) => {return ((() => {return (((delta>=fps_limit)===false)?undefined:((() => {((Game)["log"]["fps"]=fps);((Game)["timestamp_old"]=timestamp);((Game)["level"]["tick"]=(Game.level.tick+1));(draw(APP.screen,cx));return (animate());})()));})());})(((Math.round)((1.0/seconds_passed)))));})((delta/1000)));})((timestamp-Game["timestamp_old"])));})((1000/APP.fps)));})(Game.cx));return ((window["requestAnimationFrame"])(game_loop));};
-((window["addEventListener"])("keyup",((e) => {return (((idle) => {return ((("PLAY"===Game.level.state)===false)?(((("WINS"===Game.level.state)||("WAIT"===Game.level.state))===false)?((("LOSE"===Game.level.state)===false)?undefined:((() => {return (((("Enter"===e.key)||(" "===e.key))===false)?undefined:((() => {return (level_set(Game.nlevel));})()));})())):((() => {return (((("Enter"===e.key)||(" "===e.key))===false)?undefined:((() => {return (level_set((Game.nlevel+1)));})()));})())):((() => {return (((idle&&("z"===e.key))===false)?(((idle&&("x"===e.key))===false)?(((idle&&("a"===e.key))===false)?(((idle&&("s"===e.key))===false)?undefined:((() => {return (jumping(player,"nw"));})())):((() => {return (jumping(player,"ne"));})())):((() => {return (jumping(player,"se"));})())):((() => {return (jumping(player,"sw"));})()));})()));})((("IDLE"===player.state)||("IDL2"===player.state)||("SLEP"===player.state))));})));
+function game_loop(timestamp){(((cx) => {return (((fps_limit) => {return (((delta) => {return (((seconds_passed) => {return (((fps) => {return ((() => {return (((delta>=fps_limit)===false)?undefined:((() => {((Game)["log"]["keytick"]=(Game.log.keytick+1));((Game)["log"]["fps"]=fps);((Game)["timestamp_old"]=timestamp);((Game)["level"]["tick"]=(Game.level.tick+1));(draw(APP.screen,cx));return (animate());})()));})());})(((Math.round)((1.0/seconds_passed)))));})((delta/1000)));})((timestamp-Game["timestamp_old"])));})((1000/APP.fps)));})(Game.cx));return ((window["requestAnimationFrame"])(game_loop));};
+((window["addEventListener"])("keyup",((e) => {((Game)["log"]["keytick"]=0);return (((idle) => {return ((("PLAY"===Game.level.state)===false)?(((("WINS"===Game.level.state)||("WAIT"===Game.level.state))===false)?((("LOSE"===Game.level.state)===false)?undefined:((() => {return (((("Enter"===e.key)||(" "===e.key))===false)?undefined:((() => {return (level_set(Game.nlevel));})()));})())):((() => {return (((("Enter"===e.key)||(" "===e.key))===false)?undefined:((() => {return (level_set((Game.nlevel+1)));})()));})())):((() => {return (((idle&&("z"===e.key))===false)?(((idle&&("x"===e.key))===false)?(((idle&&("a"===e.key))===false)?(((idle&&("s"===e.key))===false)?undefined:((() => {return (jumping(player,"nw"));})())):((() => {return (jumping(player,"ne"));})())):((() => {return (jumping(player,"se"));})())):((() => {return (jumping(player,"sw"));})()));})()));})((("IDLE"===player.state)||("IDL2"===player.state)||("SLEP"===player.state))));})));
 function init(){(level_set(0));(((canvas) => {return ((() => {return ((Game)["cx"]=((canvas["getContext"])("2d")));})());})(((document["getElementById"])("the-canvas"))));return ((window["requestAnimationFrame"])(game_loop));};
 (init());
 </script>

          
M qc.rkt +10 -1
@@ 6,7 6,7 @@ 
               (nickname "qube-cat")
               (description "Cat on a hot, cubular roof!")
               (author "oofoe@cjmunday.com")
-              (version "1.0.0")
+              (version "1.0.1")
               (license "GPL-3.0-or-later")))
 
 ; Utilities

          
@@ 187,6 187,7 @@ 
                  [level #f] ; Cache a pointer to level here for easy access.
                  [clock 0] ; Game clock.
                  [log (object ; Handy place to stash performance/monitoring info.
+                       [keytick 0]
                        [fps 0])]
                  ))
 

          
@@ 496,6 497,10 @@ 
             (:= player.x (list (- (first player.x) (second player.x))
                                (second player.x)))
             (when (zero? (first player.x)) (player-landing player Game.level.start))]
+           [(and (= 'IDLE player.state) (< 90 Game.log.keytick))
+            (state-set player 'IDL2)]
+           [(and (= 'IDL2 player.state) (< 300 Game.log.keytick))
+            (state-set player 'SLEP)]
            )
 
      ; Yarnball

          
@@ 566,6 571,7 @@ 
             )
 
        (when (>= delta fps-limit)
+         (:= Game.log.keytick (+ Game.log.keytick 1))
          (:= Game.log.fps fps)
          (:= Game.timestamp-old timestamp)
 

          
@@ 582,6 588,9 @@ 
    (window.addEventListener
     "keyup" (λ (e)
               ;; (console.log e.key) ; Debug.
+
+              (:= Game.log.keytick 0)
+              
               (let ([idle (or (= 'IDLE player.state)
                               (= 'IDL2 player.state)
                               (= 'SLEP player.state))]