diff options
| author | LLLL Colonq <llll@colonq> | 2026-08-26 23:47:59 -0400 |
|---|---|---|
| committer | LLLL Colonq <llll@colonq> | 2026-08-26 23:47:59 -0400 |
| commit | 0d2d8cd897e94bd94e0b3ae7c6ce9aa580a44a0a (patch) | |
| tree | e9039d1c3aedca515d6cb499451d4b73aca4f5fd /2026/games/yukievt/index.html | |
| parent | 242943e5b023ce40eb3be826c418a478d4672f78 (diff) | |
Add a_tension_span
Diffstat (limited to '2026/games/yukievt/index.html')
| -rw-r--r-- | 2026/games/yukievt/index.html | 652 |
1 files changed, 0 insertions, 652 deletions
diff --git a/2026/games/yukievt/index.html b/2026/games/yukievt/index.html deleted file mode 100644 index fd23d5a..0000000 --- a/2026/games/yukievt/index.html +++ /dev/null @@ -1,652 +0,0 @@ -<!DOCTYPE html>
-<html lang="en">
- <head>
- <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
- <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
- <title>Pat The Long Yooks (YukieVT's entry for the LCOLONQ MICROJAM 2K26-A-PALOOZA)</title>
- <style>
- * {
- margin: 0px;
- padding: 0px;
- }
- body {
- font-size: 10px;
- font-family: monospace;
- }
- /* Stretching to fill screen while preserving aspect ratio from:
- https://stackoverflow.com/questions/67758479/how-to-fit-html-canvas-to-screen-while-maintaining-aspect-ratio-and-not-cutting
- */
- .screen {
- position: fixed;
- top: 0;
- right: 0;
- bottom: 0;
- left: 0;
- display: flex;
- justify-content: center;
- align-items: center;
- }
- #canvas {
- object-fit: contain;
- width: 100%;
- height: 100%;
- image-rendering: pixelated; */ From https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API/Tutorial/Drawing_shapes */
- }
- </style>
-
- <script type="module">
- window.addEventListener("message", ev => {
- switch (ev.data.op) {
- case "start":
- Difficulty = ev.data.difficulty
- DoStart();
- break;
- }
- });
- /* window.addEventListener("click", ev => {
- window.parent.postMessage({op: "done", win: true});
- });*/
- window.onload = DoInit;
- </script>
-
- </head>
- <body>
- <div class="screen">
- <canvas id="canvas" width=240 height=160></canvas>
- </div>
-
- <script>
- function ShowTextOnly(Text, Colour) {
- ctx.fillStyle = "#000000";
- ctx.fillRect(0, 0, 240, 160);
- ctx.fillStyle = Colour;
- ctx.fillText(Text, 10, 10);
- }
-
- function DoInit() {
- canvas = document.getElementById("canvas");
- ctx = canvas.getContext("2d", {alpha: false});
- FPS = 60.0;
- FrameInterval = 1000 / FPS;
-
- //Audio:
- ShowTextOnly("Loading sounds...", "#0000FF");
- audTicks = [LoadAud("TickL.wav"), LoadAud("TickH.wav")];
- audTimerUp = LoadAud("TimerUp.ogg");
- audHeartPop = LoadAud("HeartPop.wav");
- audPat = LoadAud("Pat.ogg");
- audHappy = LoadAud("Happy.ogg");
- audSad = LoadAud("Sad.ogg");
- audSuccess = LoadAud("Success.ogg");
- audFailure = LoadAud("Failure.ogg");
- audRustleInL = LoadAud("RustleInL.ogg");
- audRustleInR = LoadAud("RustleInR.ogg");
- audRustleOutL = LoadAud("RustleOutL.ogg");
- audRustleOutR = LoadAud("RustleOutR.ogg");
-
- //Images (ii = Image Index (index in Imgs[])):
- iiYookL = 0
- iiYookR = 1
- iiYookLHappy = 2
- iiYookRHappy = 3
- iiHandL = 4
- iiHandR = 5
- iiHeartSmall = 6
- iiMouseGuide = 7
- iiTinyDark = 8
- iiTinyLight1 = 9
- iiTinyLight2 = 10
- iiSuccess = 11
- iiFailure = 12
- iiPatAll = 13
- iiPatNoL = 14
- iiPatNoR = 15
- iiTimer = 16
- iiTimerUp = 17
- iiFG = 18
- iiBG = 19
- iiNumTotal = 20
- ImgFNs = [];
- ImgFNs.length = iiNumTotal;
- ImgFNs[iiYookL] = "YookL.png";
- ImgFNs[iiYookR] = "YookR.png";
- ImgFNs[iiYookLHappy] = "YookLHappy.png";
- ImgFNs[iiYookRHappy] = "YookRHappy.png";
- ImgFNs[iiHandL] = "HandL.png";
- ImgFNs[iiHandR] = "HandR.png";
- ImgFNs[iiHeartSmall] = "HeartSmall.png";
- ImgFNs[iiMouseGuide] = "MouseGuide.png";
- ImgFNs[iiTinyDark] = "TinyDark.png";
- ImgFNs[iiTinyLight1] = "TinyLight1.png";
- ImgFNs[iiTinyLight2] = "TinyLight2.png";
- ImgFNs[iiSuccess] = "Success.png";
- ImgFNs[iiFailure] = "Failure.png";
- ImgFNs[iiPatAll] = "PatAll.png";
- ImgFNs[iiPatNoL] = "PatNoL.png";
- ImgFNs[iiPatNoR] = "PatNoR.png";
- ImgFNs[iiTimer] = "Timer.png";
- ImgFNs[iiTimerUp] = "TimerUp.png";
- ImgFNs[iiFG] = "FG.png";
- ImgFNs[iiBG] = "BG.png";
- NumImgsLoaded = 0;
- console.log("iiNumTotal: " + iiNumTotal.toString() + ". ImgFNs: " + ImgFNs)
-
- Imgs = [];
- Imgs.length = iiNumTotal;
- ShowTextOnly("Loading " + iiNumTotal + " images...", "#0000FF");
- LoadNextImg();
- }
-
- function LoadAud(FNCur) {
- audCur = new Audio(FNCur)
- audCur.loop = false
- audCur.muted = false
- audCur.volume = 1.0
- return audCur
- }
-
- function LoadNextImg() {
- if (NumImgsLoaded > 0) {
- //ctx.drawImage(Imgs[NumImgsLoaded - 1], (NumImgsLoaded - 1) * 10, 0);
- }
- if (NumImgsLoaded == iiNumTotal) {
- InitFinished();
- Difficulty = 0; //Used when debugging. Overwritten by the jam's e.g. {op: "start", difficulty: 42.0}.
- //DoStart(); //FOR ACTUAL JAM WITH HARNESS, COMMENT THIS OUT! TO RUN ALONE, UNCOMMENT THIS.
- return;
- }
- Imgs[NumImgsLoaded] = new Image();
- Imgs[NumImgsLoaded].addEventListener("load", () => {
- NumImgsLoaded += 1;
- LoadNextImg();
- });
- Imgs[NumImgsLoaded].addEventListener("error", () => {
- ctx.fillStyle = "#FF0000";
- ctx.fillText("Failed to load image: " + ImgFNs[NumImgsLoaded], 10, 30);
- });
- Imgs[NumImgsLoaded].src = ImgFNs[NumImgsLoaded];
- }
-
- function InitFinished() {
- ShowTextOnly("(Ready)", "#00FF00");
- window.parent.postMessage({op: "ready"});
- }
-
-
-
- function onMouseDown(e) { //Based on https://stackoverflow.com/questions/2405771/is-right-click-a-javascript-event
- console.log("onMouseDown, e: " + e)
- switch (e.button) {
- case 0:
- LastClick = 0;
- break;
- case 2:
- LastClick = 1;
- break;
- }
- }
- function ContextMenuBlocker(e) {
- e.preventDefault();
- }
- function DisableContextMenu(DisableNow) {
- if (DisableNow) {
- document.addEventListener("contextmenu", ContextMenuBlocker);
- } else {
- document.removeEventListener("contextmenu", ContextMenuBlocker);
- }
- }
-
- function AnimCreate(Img, Loop = false) {
- return {Img: Img, KFs: [], IndKF: -1, IndFrame: 0, Loop: Loop, XFrom: 0, YFrom: 0, XCur: 0, YCur: 0};
- }
- function AnimAddKF(Anim, XNew, YNew, NumFrames = 0) {
- Anim.KFs[Anim.KFs.length] = {X: XNew, Y: YNew, NumFrames: NumFrames};
- }
- function AnimDraw(Anim) { //Returns true if animation has finished playing (if it's not set to loop).
- if (Anim.IndKF == -1) { //If starting animation for first time...
- Anim.XFrom = Anim.KFs[0].X //Start moving from first frame's pos.
- Anim.YFrom = Anim.KFs[0].Y
- Anim.IndKF = 1; //Start moving towards second frame's pos.
- }
- if (Anim.IndKF >= Anim.KFs.length) { //If we've just reached the end of the animation...
- if (Anim.Loop) { //If we should loop...
- Anim.IndKF = 0; //Start moving towards first frame's pos
- Anim.IndFrame = 0; //We're at the beginning of this new movement.
- } else { //Else, if we should not loop...
- return true; //Return that the animation has finished.
- }
- }
-
- //Work out current position based on current keyframe and frame index, and draw the image at that position.
- KFCur = Anim.KFs[Anim.IndKF]
- Anim.XCur = Anim.XFrom + ((KFCur.X - Anim.XFrom) * (Anim.IndFrame / KFCur.NumFrames));
- Anim.YCur = Anim.YFrom + ((KFCur.Y - Anim.YFrom) * (Anim.IndFrame / KFCur.NumFrames));
- ctx.drawImage(Anim.Img, Math.round(Anim.XCur), Math.round(Anim.YCur));
-
- //Next time, draw next frame. This may be the first frame in the next keyframe.
- //If there is no next keyframe, that will be dealt with on the next call of this function, rather than
- //reporting "end of animation" now, to give the just-drawn frame a chance to be displayed.
- Anim.IndFrame ++;
- if (Anim.IndFrame >= KFCur.NumFrames) {
- Anim.XFrom = Anim.XCur //Next time, start a movement from the current pos (end of cur movement).
- Anim.YFrom = Anim.YCur
- Anim.IndKF ++; //Move on to (potentially-non-existent) next keyframe.
- Anim.IndFrame = 0; //Next time will be the first frame of a new movement.
- }
- return false; //Return that the animation has not yet finished playing.
- }
-
- function ParticlesDraw() {
- ctx.globalCompositeOperation = "lighter";
- for (IndParticle = 0; IndParticle < NumParticlesMax; IndParticle ++) {
- if (Particles[IndParticle].FramesLeft > 0) {
- ctx.globalAlpha = Math.min(1.0, Particles[IndParticle].FramesLeft / 30.0);
- ctx.drawImage(Imgs[iiHeartSmall], Particles[IndParticle].X, Particles[IndParticle].Y);
- Particles[IndParticle].X += Particles[IndParticle].HSpeed;
- Particles[IndParticle].Y += Particles[IndParticle].VSpeed;
- Particles[IndParticle].HSpeed *= Particles[IndParticle].Momentum;
- Particles[IndParticle].VSpeed *= Particles[IndParticle].Momentum;
- Particles[IndParticle].FramesLeft --;
- }
- }
- ctx.globalCompositeOperation = "source-over";
- ctx.globalAlpha = 1.0;
- }
- function ParticleCreate(XNew, YNew, FramesLeftMin) {
- Particles[IndParticleNext].FramesLeft = FramesLeftMin + (Math.random() * (FramesLeftMin * 0.5));
- Particles[IndParticleNext].X = XNew;
- Particles[IndParticleNext].Y = YNew;
- Particles[IndParticleNext].HSpeed = -1.2 + (Math.random() * 2.4);
- Particles[IndParticleNext].VSpeed = -0.8 + (Math.random() * -0.4);
- IndParticleNext ++;
- if (IndParticleNext == NumParticlesMax) {IndParticleNext = 0;}
- }
- function ParticlesCreateOnYook(ValYook, XYook, YYook, FramesLeftMin, NumParticlesNew) {
- ParticleX = 0
- if (ValYook == 0) {
- ParticleX = XYook + 64;
- } else {
- ParticleX = XYook + 3;
- }
- for (IndRepeat = 0; IndRepeat < NumParticlesNew; IndRepeat ++) {
- ParticleCreate(
- ParticleX - 10 + (Math.random() * 20),
- (YYook - 10) - 10 + (Math.random() * 20),
- FramesLeftMin
- );
- }
- }
-
- function TiniesInit() {
- TinyGap = 2;
- TinyFrameInterval = 15;
-
- TinyFramesLeft = TinyFrameInterval
- TinyFramePolarity = 0;
- TinyXInc = Imgs[iiTinyDark].width + TinyGap;
- TinyTotalWidth = TinyXInc * NumYooks;
- TinyFirstX = Math.floor((240 - TinyTotalWidth) / 2);
- TinyY = 4
- TinyXs = [];
- for (IndTiny = 0; IndTiny < NumYooks; IndTiny ++) {
- TinyXs[IndTiny] = TinyFirstX + (TinyXInc * IndTiny);
- }
- }
-
- function TiniesDraw() {
- for (IndTiny = 0; IndTiny < NumYooks; IndTiny ++) {
- if (IndTiny < IndYook) {
- ctx.drawImage(Imgs[iiTinyLight1 + TinyFramePolarity], TinyXs[IndTiny], TinyY);
- } else {
- ctx.drawImage(Imgs[iiTinyDark], TinyXs[IndTiny], TinyY);
- }
- }
- if (TinyFramesLeft == 0) {
- TinyFramePolarity = 1 - TinyFramePolarity;
- TinyFramesLeft = TinyFrameInterval;
- } else {
- TinyFramesLeft --;
- }
- }
-
- function TimerSetNumSecsMax(NewVal) {
- TimerNumSecsMax = NewVal;
- NumFramesPerTimerTile = (FPS * TimerNumSecsMax) / TimerNumTiles;
- }
- function TimerInit() {
- TimerNumTiles = 8; //(Excluding an extra final "time has run out" frame in the image).
- TimerTileWidth = Imgs[iiTimer].width / (TimerNumTiles + 1);
- TimerTileHeight = Imgs[iiTimer].height;
- TimerIndFrame = 0; //Increments while waiting for input. Used for input time limit.
- TimerIndTilePrev = 0;
-
- AnimTimerUp = AnimCreate(Imgs[iiTimerUp], true)
- AnimAddKF(AnimTimerUp, 207, 0, 3); //Centre (usual position)
- AnimAddKF(AnimTimerUp, 205, 0, 3); //Left
- //AnimAddKF(AnimTimerUp, 207, 4, 2); //Centre
- //AnimAddKF(AnimTimerUp, 209, 4, 2); //Right
- }
- function TimerDraw() {
- TimerIndTile = Math.min(TimerNumTiles, Math.floor(TimerIndFrame / NumFramesPerTimerTile))
- if (TimerIndTile < TimerNumTiles) {
- ctx.drawImage(
- Imgs[iiTimer],
- TimerIndTile * TimerTileWidth, 0, TimerTileWidth, TimerTileHeight,
- 216, 2, TimerTileWidth, TimerTileHeight
- );
- if (TimerIndTile != TimerIndTilePrev) {
- if (TimerIndTile != 0) { //Don't play tick on frame index 0, because timer's not yet running (it's just rewound).
- audTicks[TimerIndTile % 2].play(); //Play tick 0 on even numbers, tick 1 on odd numbers.
- }
- }
- } else {
- AnimDraw(AnimTimerUp);
- if (TimerIndTile != TimerIndTilePrev) {audTimerUp.play();}
- }
- TimerIndTilePrev = TimerIndTile;
- }
-
- async function DoStart() {
- window.parent.postMessage({op: "started", verb: "pat!"});
- DisableContextMenu(true);
-
- //Make an array of available particles.
- NumParticlesMax = 20
- Particles = [];
- Particles.length = NumParticlesMax;
- for (IndParticle = 0; IndParticle < NumParticlesMax; IndParticle ++) {
- Particles[IndParticle] = {FramesLeft: 0, X: 0, Y: 0, HSpeed: 0, VSpeed: 0, Momentum: 0.97}
- }
- IndParticleNext = 0;
-
- //Make an array of long yooks which can appear. 0 = on the left, 1 = on the right.
- NumYooks = 3;
- Yooks = [];
- Yooks.length = NumYooks;
- for (IndYook = 0; IndYook < NumYooks; IndYook ++) {
- Yooks[IndYook] = Math.floor(Math.random() * 2);
- }
- IndYook = 0;
- TiniesInit();
- TimerInit();
-
- //Different number of seconds on the timer for each yook that appears. The last one will be used if IndYook is past end of this array.
- if (Difficulty >= 40) {
- SecsPerYook = [2.00, 0.80, 0.50]
- } else if (Difficulty >= 20) {
- SecsPerYook = [2.50, 1.50, 0.80]
- } else {
- SecsPerYook = [3.00, 2.00, 1.50]
- }
-
- //Gameplay state:
- staInitYook = 0
- staAnimYookOn = 1
- staInitInput = 2
- staAwaitInput = 3
- staInitHand = 4
- staAnimHandOn = 5
- staAnimHandPat = 6
- staAnimHandOff = 7
- staFailMain = 8
- staFailDetail = 9
- staAnimYookOff = 10
- staSuccMain = 11
- staSuccDetail = 12
- staCur = staInitYook
-
- AnimMouseBounce = AnimCreate(Imgs[iiMouseGuide], true);
- AnimAddKF(AnimMouseBounce, 89, 92, 8);
- AnimAddKF(AnimMouseBounce, 89, 96, 8);
- SuccessHeartFrameInterval = 9;
-
- GameLoop: while (true) {
- //ctx.fillStyle = "#505050";
- //ctx.fillRect(0, 0, 240, 160);
- ctx.drawImage(Imgs[iiBG], 0, 0)
-
- //If a long yook should be fully on the screen, draw it at its sitting position (happy, if current answer was correct and at least pat has begun).
- if ((staCur > staAnimYookOn) && (staCur < staAnimYookOff)) {
- IsHappy = (LastClick == ValYook) && (staCur >= staAnimHandPat)
- ctx.drawImage((IsHappy ? Imgs[iiYookLHappy + ValYook] : Imgs[ValYook]), PosYookSitX, PosYookSitY);
- ctx.drawImage(Imgs[iiFG], 0, 0)
- }
-
- switch (staCur) {
- case staInitYook: //Prepare new long yook. Prepare "yook on/off" animations. Fall through to animating.
- console.log("State: InitYook");
- ValYook = Yooks[IndYook]; //IndYook has already been set to a new value either above or when patting a previous one.
- TimerSetNumSecsMax(SecsPerYook[Math.min(SecsPerYook.length, IndYook)]) //Set how many secs are on the timer for patting this yook.
- TimerIndFrame = 0; //Set timer back to 0 ASAP. A few breaks below might increment this, so it's reset later too.
-
- AnimYookOn = AnimCreate(Imgs[ValYook]);
- AnimYookOff = AnimCreate(Imgs[iiYookLHappy + ValYook]);
- PosYookSitX = 0
- PosYookSitY = 48
- NumFramesYookOn = 10
- NumFramesYookOff = 90
-
- IndFrameMisc = 0 //For miscellaneous animations (like zooms) done in the state machine below.
- NumFramesEndZoomDuring = 10
- NumFramesEndZoomAfter = 40
- NumFramesEndDetailWait = 100
-
- if (ValYook == 0) {
- PosYookSitX = 110 - Imgs[iiYookL].width;
- AnimAddKF(AnimYookOn, 0 - Imgs[iiYookL].width, PosYookSitY);
- AnimAddKF(AnimYookOff, PosYookSitX, PosYookSitY);
- AnimAddKF(AnimYookOff, 240, PosYookSitY, NumFramesYookOff);
- } else {
- PosYookSitX = (240 - 110);
- AnimAddKF(AnimYookOn, 240, PosYookSitY);
- AnimAddKF(AnimYookOff, PosYookSitX, PosYookSitY);
- AnimAddKF(AnimYookOff, -117, PosYookSitY, NumFramesYookOff);
- }
- AnimAddKF(AnimYookOn, PosYookSitX, PosYookSitY, NumFramesYookOn);
-
- staCur = staAnimYookOn;
- (ValYook ? audRustleInR : audRustleInL).play();
-
- case staAnimYookOn: //Animate long yook sliding onto screen. Fall through to init input when done.
- ctx.drawImage(Imgs[iiFG], 0, 0);
- if (AnimDraw(AnimYookOn)) {
- staCur = staInitInput;
- } else {
- break;
- }
-
-
- case staInitInput: //Forget any previous mouse click. Fall through to awaiting input.
- console.log("State: InitInput");
- LastClick = -1;
- //Start monitoring for mouse clicks.
- //Clicked mouse button will be 0 for LMB or 1 for RMB. Any other button is ignored. Reset to -1 when we've used the value.
- window.addEventListener("mousedown", onMouseDown);
-
- TimerIndFrame = 0;
- staCur = staAwaitInput;
-
- case staAwaitInput: //Wait for L or R click while bouncing the mouse guide image. Fall through when answered.
- AnimDraw(AnimMouseBounce);
- if (LastClick != -1) { //If a mouse button was clicked...
- window.removeEventListener("mousedown", onMouseDown); //Stop monitoring for mouse clicks, so that LastClick can't keep changing.
- staCur = staInitHand;
- }
- if (TimerIndTile >= TimerNumTiles) { //If timer has run out...
- window.removeEventListener("mousedown", onMouseDown); //Stop monitoring for mouse clicks here, too.
- staCur = staFailMain;
- } else {
- TimerIndFrame ++;
- }
- break;
-
- case staInitHand: //Set up "hand on/off" animations. Fall through to animating.
- console.log("State: InitHand")
- PosHandOffX = 0; //To be set below.
- PosHandHoverX = 0; //To be set below.
- PosHandOffY = -10;
- PosHandHoverY = 25;
- if (LastClick == 0) {
- PosHandOffX = -117;
- PosHandHoverX = -19;
- } else {
- PosHandOffX = 240;
- PosHandHoverX = 259 - 117;
- }
- AnimHandOn = AnimCreate(Imgs[iiHandL + LastClick]);
- AnimAddKF(AnimHandOn, PosHandOffX, PosHandOffY);
- AnimAddKF(AnimHandOn, PosHandHoverX, PosHandHoverY, 15);
- AnimHandOff = AnimCreate(AnimHandOn.Img);
- AnimAddKF(AnimHandOff, PosHandHoverX, PosHandHoverY);
- AnimAddKF(AnimHandOff, PosHandOffX, PosHandOffY, 10);
- staCur = staAnimHandOn;
-
- case staAnimHandOn: //Animate hand moving onto screen.
- AnimHandPat = null;
- if (AnimDraw(AnimHandOn)) { //If "hand on" animation has finished...
- if (LastClick == ValYook) { //If mouse input matched yook...
- //Prepare a "hand pat" animation.
- AnimHandPat = AnimCreate(Imgs[iiHandL + LastClick]);
- AnimAddKF(AnimHandPat, PosHandHoverX, PosHandHoverY); //Current (hover)
- AnimAddKF(AnimHandPat, PosHandHoverX, PosHandHoverY, 8); //Initial delay (hover)
- AnimAddKF(AnimHandPat, PosHandHoverX, PosHandHoverY + 8, 4); //Down quickly (touching)
- AnimAddKF(AnimHandPat, PosHandHoverX, PosHandHoverY , 12); //Up slowly (hover)
- AnimAddKF(AnimHandPat, PosHandHoverX, PosHandHoverY , 3); //Wait (hover)
- AnimAddKF(AnimHandPat, PosHandHoverX, PosHandHoverY + 8, 4); //Down quickly (touching)
- AnimAddKF(AnimHandPat, PosHandHoverX, PosHandHoverY , 12); //Up slowly (hover)
- //AnimAddKF(AnimHandPat, PosHandHoverX, PosHandHoverY , 3); //Wait (hover)
-
- //Make some heart particles (hearticles) now that the "hand pat" animation is about to begin.
- ParticlesCreateOnYook(ValYook, PosYookSitX, PosYookSitY, 60, 5)
-
- //Queue pat sounds to play in sync with the pat animation.
- setTimeout(() => {audPat.play();}, 12 * FrameInterval);
- setTimeout(() => {audPat.play();}, 31 * FrameInterval);
- audHappy.playbackRate = 0.97 + (Math.random() * 0.06);
- audHappy.preservesPitch = false;
- audHappy.play();
- IndYook ++; //Prepare to move on to next long yook now (causes another "tiny" to light up).
- }
- staCur = staAnimHandPat; //Even if "hand pat" anim wasn't made, fall through and attempt to animate it (will skip it).
- } else { //Else, if animation hasn't finished yet...
- break; //Wait another frame (ONLY if animation hasn't finished yet).
- } //Ended if "hand on" animation has finished yet or not.
-
- case staAnimHandPat: //Animate "hand pat", if one was prepared. If not, fall through to "hand off" animation.
- if (AnimHandPat != null) {
- if (AnimDraw(AnimHandPat)) {
- staCur = staAnimHandOff;
- } else {
- break;
- }
- }
-
- case staAnimHandOff: //Animate hand moving off the screen. Fall through to success (if patted) when done.
- if (AnimDraw(AnimHandOff)) {
- if (LastClick == ValYook) {
- staCur = staAnimYookOff;
- (ValYook ? audRustleOutR : audRustleOutL).play();
- NumFramesUntilHeart = SuccessHeartFrameInterval;
- } else {
- staCur = staFailMain;
- audFailure.play();
- IndFrameMisc = 0;
- break;
- }
- } else { //Else, if animation hasn't finished yet...
- break; //Wait another frame.
- }
-
- case staAnimYookOff:
- if (AnimDraw(AnimYookOff)) {
- if (IndYook == NumYooks) {
- staCur = staSuccMain;
- audSuccess.play();
- IndFrameMisc = 0;
- } else {
- staCur = staInitYook;
- }
- }
- ctx.drawImage(Imgs[iiFG], 0, 0);
- if (NumFramesUntilHeart == 0) {
- ParticlesCreateOnYook(ValYook, AnimYookOff.XCur, AnimYookOff.YCur, 30, 1);
- audHeartPop.volume = 0.1 + (Math.random() * 0.9);
- audHeartPop.play();
- NumFramesUntilHeart = SuccessHeartFrameInterval;
- } else {
- NumFramesUntilHeart --;
- }
- break;
-
- case staSuccMain: //Animate zooming in of success image. After enough time, fall through to success detail.
- ctx.drawImage(Imgs[iiFG], 0, 0);
- if (IndFrameMisc < NumFramesEndZoomAfter) {
- CurScale = Math.min(1.0, IndFrameMisc / NumFramesEndZoomDuring);
- ctx.drawImage(Imgs[iiSuccess], (1 - CurScale) * 120, (1 - CurScale) * 80, 240 * CurScale, 160 * CurScale);
- IndFrameMisc ++;
- break;
- } else {
- IndFrameMisc = 0;
- staCur = staSuccDetail;
- }
-
- case staSuccDetail: //Show the success detail for a while (and spawn hearts). Afterwards, end entire game.
- ctx.drawImage(Imgs[iiFG], 0, 0);
- ctx.drawImage(Imgs[iiSuccess], 0, 0);
- ctx.drawImage(Imgs[iiPatAll], 0, 0);
- if (IndFrameMisc < NumFramesEndDetailWait) {
- IndFrameMisc ++;
- } else {
- break GameLoop;
- }
- if (NumFramesUntilHeart == 0) {
- ParticleCreate(16 + (Math.random() * (240 - 32)), 16 + (Math.random() * (160 - 32)) , 20);
- NumFramesUntilHeart = SuccessHeartFrameInterval;
- } else {
- NumFramesUntilHeart --;
- }
- break;
-
- case staFailMain: //Animate zooming in of failure image. After enough time, fall through to failure detail.
- if (IndFrameMisc < NumFramesEndZoomAfter) {
- CurScale = Math.min(1.0, IndFrameMisc / NumFramesEndZoomDuring);
- ctx.drawImage(Imgs[iiFailure], (1 - CurScale) * 120, (1 - CurScale) * 80, 240 * CurScale, 160 * CurScale);
- IndFrameMisc ++;
- break;
- } else {
- IndFrameMisc = 0;
- staCur = staFailDetail;
- audSad.play(); //Play a sad long yook voice sound.
- }
-
- case staFailDetail: //Show the failure detail for a while. Afterwards, end entire game.
- ctx.drawImage(Imgs[iiFailure], 0, 0);
- ctx.drawImage(Imgs[iiPatNoL + ValYook], 0, 0);
- if (IndFrameMisc < NumFramesEndDetailWait) {
- IndFrameMisc ++;
- } else {
- break GameLoop;
- }
- break;
-
- default:
- ctx.fillStyle = "#FF0000"
- ctx.fillText("Unhandled state (" + staCur + ")!", 5, 10);
- break;
- } //Ended switch on current state machine state.
-
- ParticlesDraw();
- TiniesDraw();
- if (staCur < staAnimYookOff) {TimerDraw();} //Draw timer if current long yook isn't moving off the screen yet, or on failure.
- await new Promise(r => setTimeout(r, FrameInterval));
-
- } //Ended outermost infinite game loop.
-
- ctx.fillStyle = "#00FF00"
- ctx.fillText("(Done)", 5, 10);
- window.parent.postMessage({op: "done", win: (LastClick == ValYook)});
- }
- </script>
-
- </body>
-</html>
\ No newline at end of file |
