taizo-hori 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (78) hide show
  1. package/README.md +179 -0
  2. package/assets/sprites/dig_dug_title.png +0 -0
  3. package/assets/sprites/flower_large_1.png +0 -0
  4. package/assets/sprites/flower_large_2.png +0 -0
  5. package/assets/sprites/flower_small.png +0 -0
  6. package/assets/sprites/fygar_fire_1.png +0 -0
  7. package/assets/sprites/fygar_fire_2.png +0 -0
  8. package/assets/sprites/fygar_fire_3.png +0 -0
  9. package/assets/sprites/fygar_ghosting_1.png +0 -0
  10. package/assets/sprites/fygar_ghosting_2.png +0 -0
  11. package/assets/sprites/fygar_inflating_1.png +0 -0
  12. package/assets/sprites/fygar_inflating_2.png +0 -0
  13. package/assets/sprites/fygar_inflating_3.png +0 -0
  14. package/assets/sprites/fygar_popped.png +0 -0
  15. package/assets/sprites/fygar_smooshed.png +0 -0
  16. package/assets/sprites/fygar_walking_1.png +0 -0
  17. package/assets/sprites/fygar_walking_2.png +0 -0
  18. package/assets/sprites/hose_line_horizontal.png +0 -0
  19. package/assets/sprites/hose_line_vertical.png +0 -0
  20. package/assets/sprites/hose_nozzle_horizontal.png +0 -0
  21. package/assets/sprites/hose_nozzle_vertical.png +0 -0
  22. package/assets/sprites/player_digging_horizontal_1.png +0 -0
  23. package/assets/sprites/player_digging_horizontal_2.png +0 -0
  24. package/assets/sprites/player_digging_vertical_1.png +0 -0
  25. package/assets/sprites/player_digging_vertical_2.png +0 -0
  26. package/assets/sprites/player_dying_horizontal_1.png +0 -0
  27. package/assets/sprites/player_dying_horizontal_2.png +0 -0
  28. package/assets/sprites/player_dying_horizontal_3.png +0 -0
  29. package/assets/sprites/player_dying_horizontal_4.png +0 -0
  30. package/assets/sprites/player_dying_horizontal_5.png +0 -0
  31. package/assets/sprites/player_dying_vertical_1.png +0 -0
  32. package/assets/sprites/player_dying_vertical_2.png +0 -0
  33. package/assets/sprites/player_dying_vertical_3.png +0 -0
  34. package/assets/sprites/player_dying_vertical_4.png +0 -0
  35. package/assets/sprites/player_dying_vertical_5.png +0 -0
  36. package/assets/sprites/player_pumping_horizontal_1.png +0 -0
  37. package/assets/sprites/player_pumping_horizontal_2.png +0 -0
  38. package/assets/sprites/player_pumping_vertical_1.png +0 -0
  39. package/assets/sprites/player_pumping_vertical_2.png +0 -0
  40. package/assets/sprites/player_shooting_horizontal.png +0 -0
  41. package/assets/sprites/player_shooting_vertical.png +0 -0
  42. package/assets/sprites/player_smooshed_horizontal.png +0 -0
  43. package/assets/sprites/player_smooshed_vertical.png +0 -0
  44. package/assets/sprites/player_walking_horizontal_1.png +0 -0
  45. package/assets/sprites/player_walking_horizontal_2.png +0 -0
  46. package/assets/sprites/player_walking_vertical_1.png +0 -0
  47. package/assets/sprites/player_walking_vertical_2.png +0 -0
  48. package/assets/sprites/pooka_ghosting_1.png +0 -0
  49. package/assets/sprites/pooka_ghosting_2.png +0 -0
  50. package/assets/sprites/pooka_inflating_1.png +0 -0
  51. package/assets/sprites/pooka_inflating_2.png +0 -0
  52. package/assets/sprites/pooka_inflating_3.png +0 -0
  53. package/assets/sprites/pooka_popped.png +0 -0
  54. package/assets/sprites/pooka_smooshed.png +0 -0
  55. package/assets/sprites/pooka_walking_1.png +0 -0
  56. package/assets/sprites/pooka_walking_2.png +0 -0
  57. package/assets/sprites/prize_1.png +0 -0
  58. package/assets/sprites/prize_10.png +0 -0
  59. package/assets/sprites/prize_11.png +0 -0
  60. package/assets/sprites/prize_2.png +0 -0
  61. package/assets/sprites/prize_3.png +0 -0
  62. package/assets/sprites/prize_4.png +0 -0
  63. package/assets/sprites/prize_5.png +0 -0
  64. package/assets/sprites/prize_6.png +0 -0
  65. package/assets/sprites/prize_7.png +0 -0
  66. package/assets/sprites/prize_8.png +0 -0
  67. package/assets/sprites/prize_9.png +0 -0
  68. package/assets/sprites/rock_1.png +0 -0
  69. package/assets/sprites/rock_2.png +0 -0
  70. package/assets/sprites/rock_crumbling_1.png +0 -0
  71. package/assets/sprites/rock_crumbling_2.png +0 -0
  72. package/assets/sprites/score_sheet.png +0 -0
  73. package/dist/assets/style.css +1 -0
  74. package/dist/digdug.es.js +3197 -0
  75. package/dist/digdug.es.js.map +1 -0
  76. package/dist/digdug.umd.js +2 -0
  77. package/dist/digdug.umd.js.map +1 -0
  78. package/package.json +61 -0
@@ -0,0 +1,2 @@
1
+ (function(A,H){typeof exports=="object"&&typeof module<"u"?H(exports):typeof define=="function"&&define.amd?define(["exports"],H):(A=typeof globalThis<"u"?globalThis:A||self,H(A.DigDug={}))})(this,function(A){"use strict";const X="digdug_highscore",m={MENU:"menu",INTRO:"intro",PLAYING:"playing",PAUSED:"paused",DYING:"dying",RESPAWNING:"respawning",LEVEL_COMPLETE:"level_complete",GAME_OVER:"game_over"},w={EMPTY:0,DIRT:1,ROCK:2},h={UP:"up",DOWN:"down",LEFT:"left",RIGHT:"right"},b={SPEED:1.2,START_LIVES:3,PUMP_RANGE:16*3},G={POOKA:"pooka",FYGAR:"fygar"},R={MIN_GHOST_DURATION:1200,POOKA:{SPEED:.7,POINTS:200,GHOST_SPEED:.5,GHOST_MODE_DELAY:()=>5e3+Math.floor(Math.random()*3)*2500},FYGAR:{SPEED:.6,GHOST_SPEED:.4,GHOST_MODE_DELAY:1e4,FIRE_RANGE:16*4,FIRE_COOLDOWN:2500,FIRE_CHARGE_TIME:300,FIRE_DURATION:450}},k={DIG_TILE:10,PUMP_KILL:{POOKA:[200,300,400,500],FYGAR:[200,300,400,500],FYGAR_HORIZONTAL:[400,600,800,1e3]},ROCK_KILL:[0,1e3,2500,4e3,6e3,8e3,1e4,12e3,15e3],BONUS_ITEMS:[400,600,800,1e3,2e3,3e3,4e3,5e3,6e3,7e3,8e3]},_={BACKGROUND:"#000000",SKY:"rgb(0, 0, 145)",TEXT_WHITE:"#ffffff",TEXT_RED:"#e33122"},O={FALL_DELAY:300,FALL_SPEED:3,SHAKE_DURATION:200},v={START_ENEMIES:4,MAX_ENEMIES:8,ENEMY_INCREMENT:1,ROCKS_PER_LEVEL:3},Z={ANIMATION_DURATION:1500,RESPAWN_DELAY:3e3,INVINCIBILITY_TIME:2e3},U=L=>new Promise((t,i)=>{const e=new Image;e.onload=()=>t(e),e.onerror=s=>i(s),e.src=L}),V=[{DIRT_TOP:"rgb(244, 187, 64)",DIRT_MID:"rgb(207, 111, 41)",DIRT_LOW:"rgb(169, 49, 24)",DIRT_LOWEST:"rgb(138, 26, 16)"},{DIRT_TOP:"rgb(128, 128, 128)",DIRT_MID:"rgb(162, 130, 74)",DIRT_LOW:"rgb(222, 171, 58)",DIRT_LOWEST:"rgb(187, 102, 37)"},{DIRT_TOP:"rgb(128, 128, 128)",DIRT_MID:"rgb(104, 104, 69)",DIRT_LOW:"rgb(73, 103, 68)",DIRT_LOWEST:"rgb(64, 64, 64)"}];function C(L){const[t,i,e]=L.match(/\d+/g).map(Number),s=t/255,r=i/255,n=e/255,o=Math.max(s,r,n),a=Math.min(s,r,n);let l,d;const c=(o+a)/2;if(o===a)l=d=0;else{const f=o-a;switch(d=c>.5?f/(2-o-a):f/(o+a),o){case s:l=(r-n)/f+(r<n?6:0);break;case r:l=(n-s)/f+2;break;case n:l=(s-r)/f+4;break}l/=6}return{h:Math.round(l*360),s:Math.round(d*100),l:Math.round(c*100)}}function B(L){const i=Math.floor((L-1)/4)%V.length,{DIRT_TOP:e,DIRT_MID:s,DIRT_LOW:r,DIRT_LOWEST:n}=V[i];return[{stop:0,color:C(e)},{stop:.33,color:C(s)},{stop:.66,color:C(r)},{stop:1,color:C(n)}]}class ${constructor(t){this.config=t,this.canvas=document.createElement("canvas"),this.ctx=this.canvas.getContext("2d"),this.canvas.width=t.width,this.canvas.height=t.height,t.scale&&t.scale!==1&&(this.canvas.style.width=`${t.width*t.scale}px`,this.canvas.style.height=`${t.height*t.scale}px`),this.ctx.imageSmoothingEnabled=!1,this.sprites={},this.spritesLoaded=!1,this.loadSprites(),this.scoreSheet=null,this.scoreSheetLoaded=!1,this.loadScoreSheet(),this.scoreSpriteMap={200:{x:23,y:0,w:15,h:7},300:{x:42,y:0,w:15,h:7},400:{x:61,y:0,w:15,h:7},500:{x:81,y:0,w:15,h:7},600:{x:100,y:0,w:15,h:7},800:{x:119,y:0,w:15,h:7},1e3:{x:0,y:15,w:17,h:7},2e3:{x:21,y:15,w:20,h:7},2500:{x:45,y:15,w:20,h:7},3e3:{x:69,y:15,w:20,h:7},4e3:{x:93,y:15,w:20,h:7},5e3:{x:117,y:15,w:20,h:7},6e3:{x:141,y:15,w:20,h:7},7e3:{x:13,y:30,w:20,h:7},8e3:{x:40,y:30,w:20,h:7},1e4:{x:66,y:30,w:22,h:7},12e3:{x:95,y:30,w:22,h:7},15e3:{x:124,y:30,w:22,h:7}},this.backgroundCanvas=document.createElement("canvas"),this.backgroundCanvas.width=t.width,this.backgroundCanvas.height=t.height,this.backgroundCtx=this.backgroundCanvas.getContext("2d"),this.backgroundCtx.imageSmoothingEnabled=!1,this.backgroundDirty=!0,this.lastGridState=null}loadSprites(){const t=["player_walking_horizontal_1.png","player_walking_horizontal_2.png","player_walking_vertical_1.png","player_walking_vertical_2.png","player_digging_horizontal_1.png","player_digging_horizontal_2.png","player_digging_vertical_1.png","player_digging_vertical_2.png","player_shooting_horizontal.png","player_shooting_vertical.png","player_pumping_horizontal_1.png","player_pumping_horizontal_2.png","player_pumping_vertical_1.png","player_pumping_vertical_2.png","player_smooshed_horizontal.png","player_smooshed_vertical.png","player_dying_horizontal_1.png","player_dying_horizontal_2.png","player_dying_horizontal_3.png","player_dying_horizontal_4.png","player_dying_horizontal_5.png","player_dying_vertical_1.png","player_dying_vertical_2.png","player_dying_vertical_3.png","player_dying_vertical_4.png","player_dying_vertical_5.png","hose_line_horizontal.png","hose_line_vertical.png","hose_nozzle_horizontal.png","hose_nozzle_vertical.png","pooka_walking_1.png","pooka_walking_2.png","pooka_ghosting_1.png","pooka_ghosting_2.png","fygar_walking_1.png","fygar_walking_2.png","fygar_ghosting_1.png","fygar_ghosting_2.png","fygar_fire_1.png","fygar_fire_2.png","fygar_fire_3.png","pooka_inflating_1.png","pooka_inflating_2.png","pooka_inflating_3.png","pooka_popped.png","pooka_smooshed.png","fygar_inflating_1.png","fygar_inflating_2.png","fygar_inflating_3.png","fygar_popped.png","fygar_smooshed.png","rock_1.png","rock_2.png","rock_crumbling_1.png","rock_crumbling_2.png","flower_small.png","prize_1.png","prize_2.png","prize_3.png","prize_4.png","prize_5.png","prize_6.png","prize_7.png","prize_8.png","prize_9.png","prize_10.png","prize_11.png"];let i=0;const e=t.length;t.forEach(s=>{const r=new Image;r.onload=()=>{i++,i===e&&(this.spritesLoaded=!0)},r.onerror=()=>{console.warn(`Failed to load sprite: ${s}`),i++,i===e&&(this.spritesLoaded=!0)};const n=s.replace(".png","");r.src=`/assets/sprites/${s}`,this.sprites[n]=r})}async loadScoreSheet(){const t=await U("/assets/sprites/score_sheet.png");this.scoreSheet=t,this.scoreSheetLoaded=!0}attachTo(t){t.appendChild(this.canvas)}async drawMenu(){const t=await U("/assets/sprites/dig_dug_title.png"),i=t.naturalWidth*1.5;this.ctx.drawImage(t,432/2-i/2,16*2,i,t.naturalHeight*1.5),this.drawText("▶ 1 PLAYER",432/2,288/2+16*6,{size:8,color:_.TEXT_WHITE,align:"center"})}clear(){(this.backgroundDirty||!this.lastGridState)&&(this.ctx.fillStyle=_.BACKGROUND,this.ctx.fillRect(0,0,this.canvas.width,this.canvas.height))}forceClear(){this.ctx.fillStyle=_.BACKGROUND,this.ctx.fillRect(0,0,this.canvas.width,this.canvas.height)}markBackgroundDirty(){this.backgroundDirty=!0}drawGrid(t,i){const e=t.getStateHash?t.getStateHash():null;e!==this.lastGridState&&(this.backgroundDirty=!0,this.lastGridState=e),this.backgroundDirty&&(this.renderBackgroundToCache(t,i),this.backgroundDirty=!1),this.ctx.drawImage(this.backgroundCanvas,0,0)}getDirtColorHSL(t,i){const e=Math.max(0,Math.min(1,t)),s=B(i);let r=s[0],n=s[s.length-1];for(let l=0;l<s.length-1;l++)if(e>=s[l].stop&&e<=s[l+1].stop){r=s[l],n=s[l+1];break}const o=n.stop-r.stop,a=(e-r.stop)/o;return o===0?n.color:{h:Math.round(r.color.h+(n.color.h-r.color.h)*a),s:Math.round(r.color.s+(n.color.s-r.color.s)*a),l:Math.round(r.color.l+(n.color.l-r.color.l)*a)}}renderBackgroundToCache(t,i){const e=this.backgroundCtx;e.fillStyle=_.BACKGROUND,e.fillRect(0,0,this.backgroundCanvas.width,this.backgroundCanvas.height);for(let s=0;s<t.height;s++)for(let r=0;r<t.width;r++){const n=t.getTile(r,s),o=r*16,a=s*16;if(s<2){e.fillStyle=_.SKY,e.fillRect(o,a,16,16);continue}if(n===w.DIRT||n===w.ROCK){const l=(s-2)/(t.height-2),{h:d,s:c,l:f}=this.getDirtColorHSL(l,i);e.fillStyle=`hsl(${d}, ${c}%, ${f}%)`,e.fillRect(o,a,16,16);const u=`hsl(${d}, ${Math.min(100,c+20)}%, ${Math.max(0,f-15)}%)`,g=`hsl(${d}, ${Math.min(100,c+10)}%, ${Math.min(100,f+10)}%)`,T=4,I=2;e.fillStyle=u;for(let p=0;p<16;p+=T)for(let E=0;E<16;E+=T){const x=r*16+E,D=s*16+p;Math.abs(Math.sin(x*12.989+D*78.233)*43758.545)%1<.15&&e.fillRect(o+E+1,a+p+1,I,I)}e.fillStyle=g;for(let p=0;p<16;p+=T)for(let E=0;E<16;E+=T){const x=r*16+E,D=s*16+p;Math.abs(Math.sin(x*90.123+D*11.456)*12345.678)%1<.08&&e.fillRect(o+E+1,a+p+1,I,I)}}}}getPlayerOrientation(t){return t.direction===h.LEFT||t.direction===h.RIGHT?"horizontal":"vertical"}drawPlayer(t){if(t.isDying){this.drawPlayerDeath(t);return}if(t.isInvincible&&!(Math.floor(t.invincibilityTimer/100)%2===0))return;t.pumpLength>0&&this.drawPumpLine(t);const i=t.x,e=t.y;if(this.spritesLoaded){let s="walking";t.isDigging?s="digging":t.isPumping&&(s="pumping");let r=t.animationFrame===0?"_1":"_2";const n=this.getPlayerOrientation(t);t.isShooting&&(s="shooting",r="");const o=this.sprites[`player_${s}_${n}${r}`];if(o&&o.complete)if(t.spriteFlipH||t.spriteFlipV){const l=i+8,d=e+16/2;this.drawFlippedSprite(l,d,t.spriteFlipH,t.spriteFlipV,o)}else this.ctx.drawImage(o,i,e,16,16)}}drawFlippedSprite(t,i,e,s,r){this.ctx.save(),this.ctx.translate(t,i),this.ctx.scale(e?-1:1,s?-1:1),this.ctx.drawImage(r,-16/2,-16/2,16,16),this.ctx.restore()}drawPlayerDeath(t){var a;const i=t.x,e=t.y,s=this.getPlayerOrientation(t);if(t.isSmooshed&&((a=t.attachedToRock)!=null&&a.isFalling||t.smooshedDelayTimer<t.SMOOSHED_DELAY)){const l=`player_smooshed_${s}`;if(this.spritesLoaded){const d=this.sprites[l];if(d&&d.complete){if(t.spriteFlipH){const c=i+8,f=e+16/2;this.drawFlippedSprite(c,f,!0,!1,d)}else this.ctx.drawImage(d,i,e,16,16);return}}}const r=t.deathTimer/Z.ANIMATION_DURATION,n=Math.min(5,Math.floor(r*5)+1),o=`player_dying_${s}_${n}`;if(this.spritesLoaded){const l=this.sprites[o];if(l&&l.complete){if(t.spriteFlipH){const d=i+8,c=e+16/2;this.drawFlippedSprite(d,c,!0,!1,l)}else this.ctx.drawImage(l,i,e,16,16);return}}}drawPumpLine(t){if(!this.spritesLoaded)return;const i=16,e=i/2,s=t.x,r=t.y,n=t.getPumpEndPoint(),o=this.ctx,a=this.getPlayerOrientation(t),l=this.sprites[`hose_nozzle_${a}`],d=this.sprites[`hose_line_${a}`];if(!l||!l.complete||!d||!d.complete)return;const c=Math.round((s+e-n.x)/i),f=Math.round((r+e-n.y)/i),u=t.spriteFlipH,g=t.spriteFlipV;if(f<0){let T=Math.abs(f)-1;if(u){const I=s+e;let p=n.y-i*.25;for(this.drawFlippedSprite(I,p,u,g,l);T>0;)p-=i,this.drawFlippedSprite(I,p,u,g,d),T--}else{const I=s;let p=n.y-i*.75;for(o.drawImage(l,I,p,i,i);T>0;)p-=i,o.drawImage(d,I,p,i,i),T--}return}if(f>0){let T=Math.abs(f)-1;const I=s+e;let p=n.y+i*.25;for(this.drawFlippedSprite(I,p,u,g,l);T>0;)p+=i,this.drawFlippedSprite(I,p,u,g,d),T--;return}if(c<0){let T=Math.abs(c)-1,I=n.x-i*.25;const p=r+e;for(this.drawFlippedSprite(I,p,u,g,l);T>0;)I-=i,this.drawFlippedSprite(I,p,u,g,d),T--;return}if(c>0){let T=Math.abs(c)-1,I=n.x-i*.25;for(o.drawImage(l,I,r,i,i);T>0;)I+=i,o.drawImage(d,I,r,i,i),T--}}drawEnemy(t){const i=t.x,e=t.y,s=i+16/2,r=e+16/2;if(t.isSmooshed){this.drawEnemySmooshed(t,s,r);return}if(t.isPopped){this.drawEnemyPopped(t,s,r);return}if(t.inflateLevel>1){this.drawEnemyInflating(t,s,r);return}if(this.spritesLoaded){const n=t.animationFrame===0?"1":"2",o=t.isGhosting?"ghosting":"walking",a=this.sprites[`${t.type}_${o}_${n}`];this.drawEnemySprite(a,s,r,t.spriteFlipH)}t.type===G.FYGAR&&(t.isCharging&&t.isCharging()?this.drawFygarCharging(t):t.isFireActive&&t.isFireActive()&&this.drawFygarFire(t))}drawEnemyInflating(t,i,e){const s=(t.inflateLevel-1)/1;let r;s<.33?r=1:s<.66?r=2:r=3;const n=`${t.type}_inflating_${r}`,o=this.sprites[n];this.drawEnemySprite(o,i,e,t.spriteFlipH)}drawEnemyPopped(t,i,e){const s=this.sprites[`${t.type}_popped`];this.drawEnemySprite(s,i,e,t.spriteFlipH)}drawEnemySprite(t,i,e,s){if(t&&t.complete){const r=t.naturalWidth,n=t.naturalHeight;this.ctx.save(),this.ctx.translate(i,e),s&&this.ctx.scale(-1,1),this.ctx.drawImage(t,-r/2,-n/2,r,n),this.ctx.restore()}}drawEnemySmooshed(t,i,e){const s=this.sprites[`${t.type}_smooshed`];this.drawEnemySprite(s,i,e,t.spriteFlipH)}drawFygarCharging(t){const i=t.x+8,e=t.y+16/2,s=t.getFireDirection(),r=Math.floor(Date.now()/100)%2;this.ctx.fillStyle=r===0?"#ff6600":"#ff3300";const n=s===h.RIGHT?16/2:-16/2;this.ctx.beginPath(),this.ctx.arc(i+n,e,3,0,Math.PI*2),this.ctx.fill()}drawFygarFire(t){if(!t.getFireHitbox())return;const s=t.getFireDirection()===h.LEFT,r=t.getFireTileCount?t.getFireTileCount():3,n=this.sprites[`fygar_fire_${r}`];if(n&&n.complete){this.ctx.save();const o=r*16;let a;s?a=t.x-o:a=t.x+16;const l=t.y,d=a+o/2,c=l+16/2;this.ctx.translate(d,c),s||this.ctx.scale(-1,1),this.ctx.drawImage(n,-o/2,-16/2,o,16),this.ctx.restore()}}drawRock(t){const i=t.x,e=t.y;if(t.isSpawning){const r=t.spawnTimer/t.SPAWN_DURATION,n=r,o=8+r*12,a=Math.sin(t.spawnTimer*o*.01),l=(1-r)*.4,d=Math.min(1,n+a*l);if(this.ctx.save(),this.ctx.globalAlpha=Math.max(0,d),this.spritesLoaded){const c=this.sprites.rock_1;c&&c.complete&&this.ctx.drawImage(c,i,e,16,16)}this.ctx.restore();return}if(t.isCrumbling){const n=t.crumbleTimer/t.CRUMBLE_DURATION<.5?"rock_crumbling_1":"rock_crumbling_2";if(this.spritesLoaded){const o=this.sprites[n];if(o&&o.complete){this.ctx.drawImage(o,i,e,16,16);return}}}let s="rock_1";if(t.isShaking&&(s=Math.floor(t.shakeTimer/200)%2===0?"rock_1":"rock_2"),this.spritesLoaded){const r=this.sprites[s];r&&r.complete&&this.ctx.drawImage(r,i,e,16,16)}}drawBonusItem(t,i=1){const e=t.x,s=t.y;if(t.isFlashing&&t.isFlashing()&&!(Math.floor(t.elapsedTime/100)%2===0))return;const r=Math.min(Math.floor((i-1)/20),8),n=(t.bonusIndex||0)%3,a=`prize_${Math.min(r+n+1,11)}`;if(this.spritesLoaded){const l=this.sprites[a];l&&l.complete&&this.ctx.drawImage(l,e,s,16,16)}}drawFloatingScores(t){!this.scoreSheetLoaded||!this.scoreSheet||t.forEach(i=>{const e=this.scoreSpriteMap[i.points];if(!e)return;const s=Math.round(i.x+(16-e.w)/2),r=Math.round(i.y);this.ctx.drawImage(this.scoreSheet,e.x,e.y,e.w,e.h,s,r,e.w,e.h)})}drawUI(t,i){if(this.drawText("1UP",4,10,{size:6,color:_.TEXT_RED,align:"left"}),this.drawText(`${t.score}`.padStart(2,"0"),4,20,{size:8,color:_.TEXT_WHITE,align:"left"}),this.spritesLoaded){const e=this.sprites.player_digging_horizontal_1;if(e&&e.complete)for(let s=1;s<t.lives;s++){const r=28+(s-1)*16;this.ctx.drawImage(e,r,0,16,16)}}if(this.drawText("HI-SCORE",432/2,10,{size:6,color:_.TEXT_RED,align:"center"}),this.drawText(`${t.highScore}`.padStart(2,"0"),432/2,20,{size:8,color:_.TEXT_WHITE,align:"center"}),this.drawText(`ROUND ${i.currentLevel}`,428,10,{size:6,color:_.TEXT_WHITE,align:"right"}),this.spritesLoaded){const e=this.sprites.flower_small;if(e&&e.complete)for(let s=1;s<=i.currentLevel;s++)this.ctx.drawImage(e,432-16*s,16,16,16)}}drawText(t,i,e,s={}){const r=s.size||16,n=s.color||_.TEXT_WHITE,o=s.align||"left";this.ctx.font=`${r}px "Press Start 2P", "Courier New", monospace`,this.ctx.fillStyle=n,this.ctx.textAlign=o,this.ctx.fillText(t,i,e)}renderRespawning(){this.drawText("PLAYER 1",432/2,288/2-3,{size:10,color:_.TEXT_WHITE,align:"center"}),this.drawText("READY!",432/2,288/2+16+15,{size:10,color:_.TEXT_WHITE,align:"center"})}drawDebugInfo(t,i){this.ctx.strokeStyle="rgba(255, 255, 255, 0.1)",this.ctx.lineWidth=1;for(let e=0;e<=432;e+=16)this.ctx.beginPath(),this.ctx.moveTo(e,0),this.ctx.lineTo(e,288),this.ctx.stroke();for(let e=0;e<=288;e+=16)this.ctx.beginPath(),this.ctx.moveTo(0,e),this.ctx.lineTo(432,e),this.ctx.stroke();t&&(this.ctx.strokeStyle="rgba(0, 255, 0, 0.5)",this.ctx.strokeRect(t.x,t.y,16,16)),i.forEach(e=>{this.ctx.strokeStyle="rgba(255, 0, 0, 0.5)",this.ctx.strokeRect(e.x,e.y,16,16)})}}class q{constructor(){this.width=27,this.height=18,this.tiles=[],this.stateVersion=0,this.init()}init(){this.tiles=[];for(let t=0;t<this.height;t++){this.tiles[t]=[];for(let i=0;i<this.width;i++)t<=1?this.tiles[t][i]=w.EMPTY:this.tiles[t][i]=w.DIRT}this.stateVersion++}getTile(t,i){return t<0||t>=this.width||i<0||i>=this.height?w.DIRT:this.tiles[i][t]}setTile(t,i,e){t>=0&&t<this.width&&i>=0&&i<this.height&&this.tiles[i][t]!==e&&(this.tiles[i][t]=e,this.stateVersion++)}getStateHash(){return this.stateVersion}isEmpty(t,i){return this.getTile(t,i)===w.EMPTY}isDirt(t,i){return this.getTile(t,i)===w.DIRT}isRock(t,i){return this.getTile(t,i)===w.ROCK}dig(t,i){return this.isDirt(t,i)?(this.setTile(t,i,w.EMPTY),!0):!1}countDirt(){let t=0;for(let i=0;i<this.height;i++)for(let e=0;e<this.width;e++)this.isDirt(e,i)&&t++;return t}pixelToGrid(t,i){return{x:Math.floor(t/16),y:Math.floor(i/16)}}gridToPixel(t,i){return{x:t*16,y:i*16}}gridToPixelCenter(t,i){return{x:t*16+16/2,y:i*16+16/2}}isWalkable(t,i){const{x:e,y:s}=this.pixelToGrid(t,i);return this.isEmpty(e,s)}canMove(t,i,e,s=16){let r=t,n=i;switch(e){case"up":n-=1;break;case"down":n+=1;break;case"left":r-=1;break;case"right":r+=1;break}return[{x:r,y:n},{x:r+s-1,y:n},{x:r,y:n+s-1},{x:r+s-1,y:n+s-1}].every(a=>{const{x:l,y:d}=this.pixelToGrid(a.x,a.y);return l>=0&&l<this.width&&d>=0&&d<this.height})}clearHorizontalTunnel(t,i,e){const s=Math.min(t,i),r=Math.max(t,i);for(let n=s;n<=r;n++)this.setTile(n,e,w.EMPTY)}clearVerticalTunnel(t,i,e){const s=Math.min(i,e),r=Math.max(i,e);for(let n=s;n<=r;n++)this.setTile(t,n,w.EMPTY)}placeRock(t,i){this.setTile(t,i,w.ROCK)}removeRock(t,i){this.isRock(t,i)&&this.setTile(t,i,w.EMPTY)}getRockPositions(){const t=[];for(let i=0;i<this.height;i++)for(let e=0;e<this.width;e++)this.isRock(e,i)&&t.push({x:e,y:i});return t}hasDirtBelow(t,i){return this.isDirt(t,i+1)}reset(){this.init()}}class j{constructor(){this.keys=new Set,this.keysPressed=new Set,this.handleKeyDown=this.handleKeyDown.bind(this),this.handleKeyUp=this.handleKeyUp.bind(this)}init(){document.addEventListener("keydown",this.handleKeyDown),document.addEventListener("keyup",this.handleKeyUp)}handleKeyDown(t){this.keys.has(t.code)||this.keysPressed.add(t.code),this.keys.add(t.code),["ArrowUp","ArrowDown","ArrowLeft","ArrowRight","Space"].includes(t.code)&&t.preventDefault()}handleKeyUp(t){this.keys.delete(t.code),this.keysPressed.delete(t.code)}isKeyDown(t){return this.keys.has(t)}isKeyPressed(t){const i=this.keysPressed.has(t);return i&&this.keysPressed.delete(t),i}isUpPressed(){return this.isKeyDown("ArrowUp")||this.isKeyDown("KeyW")}isDownPressed(){return this.isKeyDown("ArrowDown")||this.isKeyDown("KeyS")}isLeftPressed(){return this.isKeyDown("ArrowLeft")||this.isKeyDown("KeyA")}isRightPressed(){return this.isKeyDown("ArrowRight")||this.isKeyDown("KeyD")}isSpacePressed(){return this.isKeyDown("Space")}getDirection(){return this.isUpPressed()?"up":this.isDownPressed()?"down":this.isLeftPressed()?"left":this.isRightPressed()?"right":null}destroy(){document.removeEventListener("keydown",this.handleKeyDown),document.removeEventListener("keyup",this.handleKeyUp),this.keys.clear(),this.keysPressed.clear()}}class Q{constructor(t){this.grid=t}checkAABB(t,i,e,s,r,n,o,a){return t<r+o&&t+e>r&&i<n+a&&i+s>n}checkPlayerEnemyCollision(t,i){return this.checkAABB(t.x,t.y,10,10,i.x,i.y,10,10)}checkRockEntityCollision(t,i){return this.checkAABB(t.x,t.y,16,16,i.x,i.y,16,16)}checkPlayerBonusCollision(t,i){return this.checkAABB(t.x,t.y,16,16,i.x,i.y,16,16)}checkPumpRange(t,i,e){const s=t.x+8-(i.x+8),r=t.y+16/2-(i.y+16/2);return Math.sqrt(s*s+r*r)<=e}isFacing(t,i,e){const s=i.x-t.x,r=i.y-t.y;switch(e){case h.UP:return r<0&&Math.abs(r)>Math.abs(s);case h.DOWN:return r>0&&Math.abs(r)>Math.abs(s);case h.LEFT:return s<0&&Math.abs(s)>Math.abs(r);case h.RIGHT:return s>0&&Math.abs(s)>Math.abs(r);default:return!1}}getDistance(t,i,e,s){const r=e-t,n=s-i;return Math.sqrt(r*r+n*n)}hasLineOfSight(t,i){const{x:e,y:s}=this.grid.pixelToGrid(t.x,t.y),{x:r,y:n}=this.grid.pixelToGrid(i.x,i.y),o=Math.abs(r-e),a=Math.abs(n-s),l=e<r?1:-1,d=s<n?1:-1;let c=o-a,f=e,u=s;for(;f!==r||u!==n;){if(this.grid.isDirt(f,u))return!1;const g=2*c;g>-a&&(c-=a,f+=l),g<o&&(c+=o,u+=d)}return!0}}class K{constructor(t,i,e,s,r=1){this.x=t,this.y=i,this.type=e,this.level=r,this.baseSpeed=s,this.speed=s+(r-1)*.1,this.direction=h.DOWN,this.isMoving=!0,this.directionInitialized=!1,this.state="roaming",this.stateTimer=0,this.directionChangeTimer=0,this.lastGridX=-1,this.lastGridY=-1,this.prevGridX=-1,this.prevGridY=-1,this.tilesTraveledInDirection=0,this.minTilesBeforeReverse=2,this.animationFrame=0,this.animationTimer=0,this.spriteFlipH=!1,this.isInflating=!1,this.inflateLevel=1,this.inflateTimer=0,this.INFLATE_DURATION=1200,this.deflateTimer=0,this.isPopped=!1,this.poppedTimer=0,this.POPPED_DURATION=400,this.isSmooshed=!1,this.smooshedTimer=0,this.SMOOSHED_DURATION=400,this.isDestroyed=!1,this.distanceFromPlayer=0,this.ghostModeTimer=0,this.canGhostMode=!1,this.isGhosting=!1,this.ghostingDuration=0,this.GHOST_MODE_DELAY=e===G.POOKA?R.POOKA.GHOST_MODE_DELAY():R.FYGAR.GHOST_MODE_DELAY,this.MIN_GHOST_DURATION=R.MIN_GHOST_DURATION,this.wasInDirt=!1,this.isLastEnemy=!1,this.isEscaping=!1,this.hasEscaped=!1}update(t,i,e){if(this.isPopped){this.updatePoppedState(t);return}if(this.isSmooshed){this.updateSmooshedState(t);return}if(!this.directionInitialized){this.initializeDirection(e),this.directionInitialized=!0;const{x:s,y:r}=e.pixelToGrid(this.x+16/2,this.y+16/2);this.lastGridX=s,this.lastGridY=r}if((this.isInflating||this.inflateLevel>1)&&this.updateInflation(t),i&&this.updateAI(t,i),this.updateGhostMode(t,i,e),this.isMoving&&!this.isInflating&&this.move(e,i),this.isEscaping&&!this.hasEscaped&&this.x+16<=0&&(this.hasEscaped=!0),this.updateAnimation(t),i){const s=this.x-i.x,r=this.y-i.y;this.distanceFromPlayer=Math.sqrt(s*s+r*r)}}updateGhostMode(t,i,e){const{x:s,y:r}=e.pixelToGrid(this.x+8,this.y+8),n=e.isEmpty(s,r),o=!n&&!e.isRock(s,r);if(this.isGhosting&&(this.ghostingDuration+=t),this.isGhosting&&n&&this.ghostingDuration>=this.MIN_GHOST_DURATION&&(this.ghostModeTimer=0,this.canGhostMode=!1,this.isGhosting=!1,this.ghostingDuration=0),this.isGhosting&&!n&&this.ghostingDuration>=this.MIN_GHOST_DURATION){const c=this.findAdjacentTunnel(e,s,r);c&&(this.x=c.x*16,this.y=c.y*16,this.lastGridX=c.x,this.lastGridY=c.y,this.ghostModeTimer=0,this.canGhostMode=!1,this.isGhosting=!1,this.ghostingDuration=0)}this.wasInDirt=o,this.isGhosting||(this.ghostModeTimer+=t,this.ghostModeTimer>=this.GHOST_MODE_DELAY&&(this.canGhostMode=!0));const a=r<=1,l=this.isEscaping&&this.state==="escaping"&&a;this.canGhostMode&&!this.isGhosting&&i&&!l&&(this.isGhosting=!0,this.ghostingDuration=0)}updateAI(t,i){if(this.isLastEnemy&&this.state!=="chasing"&&(this.isEscaping||(this.isEscaping=!0,this.state="escaping",this.stateTimer=0)),this.isEscaping){const a=this.x-i.x,l=this.y-i.y,d=Math.sqrt(a*a+l*l),c=16*4;d<=c?this.state="chasing":this.state="escaping",this.stateTimer+=t,this.directionChangeTimer+=t;return}const e=this.x-i.x,s=this.y-i.y,r=Math.sqrt(e*e+s*s),n=16*8,o=16*10;r<=n&&this.state!=="chasing"?(this.state="chasing",this.stateTimer=0):r>o&&this.state!=="roaming"&&(this.state="roaming",this.stateTimer=0),this.stateTimer+=t,this.directionChangeTimer+=t}move(t,i=null){if(this.isGhosting&&i){this.moveGhost(t,i);return}const e=this.x+16/2,s=this.y+16/2,{x:r,y:n}=t.pixelToGrid(e,s);r!==this.lastGridX||n!==this.lastGridY?(this.prevGridX=this.lastGridX,this.prevGridY=this.lastGridY,this.lastGridX=r,this.lastGridY=n,this.tilesTraveledInDirection++,i&&this.state==="chasing"?this.decideDirectionAtTile(i,t,r,n):this.state==="escaping"?this.escapeAtTile(t,r,n):this.state==="roaming"&&this.roamAtTile(t,r,n)):i&&this.state==="chasing"?this.checkForBetterDirection(i,t,r,n):this.state==="escaping"&&this.checkForBetterEscapeDirection(t,r,n);let a=this.x,l=this.y;switch(this.direction){case h.UP:l-=this.speed;break;case h.DOWN:l+=this.speed;break;case h.LEFT:a-=this.speed,this.spriteFlipH&&(this.spriteFlipH=!1);break;case h.RIGHT:a+=this.speed,this.spriteFlipH||(this.spriteFlipH=!0);break}this.canMoveInDirection(a,l,this.direction,t)?(this.x=a,this.y=l,this.applyGridSnapping(t)):(this.snapToGrid(t),this.pickValidDirection(t,i,r,n),this.tilesTraveledInDirection=0)}moveGhost(t,i){const e=this.ghostSpeed||this.speed*.8;let s,r;this.isEscaping&&this.state==="escaping"?(s=this.x,r=-16):(s=i.x,r=i.y);const n=s-this.x,o=r-this.y,a=Math.sqrt(n*n+o*o);if(a<2)return;const l=n/a,d=o/a,c=l*e,f=d*e,u=this.x+c,g=this.y+f;let T;Math.abs(n)>Math.abs(o)?T=n>0?h.RIGHT:h.LEFT:T=o>0?h.DOWN:h.UP;const I=this.canGhostMoveToPosition(this.x+c,this.y,t),p=this.canGhostMoveToPosition(this.x,this.y+f,t);if(I&&p){this.x=u,this.y=g,this.direction=T;return}if(I){this.x=this.x+c,this.direction=n>0?h.RIGHT:h.LEFT;return}if(p){this.y=this.y+f,this.direction=o>0?h.DOWN:h.UP;return}let E=[];Math.abs(n)>Math.abs(o)?o>0?E=[h.DOWN,h.UP]:E=[h.UP,h.DOWN]:n>0?E=[h.RIGHT,h.LEFT]:E=[h.LEFT,h.RIGHT];for(const D of E){const y=this.getNewPosition(this.x,this.y,D,e);if(this.canGhostMoveToPosition(y.x,y.y,t)){this.x=y.x,this.y=y.y,this.direction=D;return}}const x=[h.UP,h.DOWN,h.LEFT,h.RIGHT];for(const D of x){const y=this.getNewPosition(this.x,this.y,D,e);if(this.canGhostMoveToPosition(y.x,y.y,t)){this.x=y.x,this.y=y.y,this.direction=D;return}}}canGhostMoveToPosition(t,i,e){const{y:s}=e.pixelToGrid(t+8,i+8);return s!==0}getPerpendicularDirection(t,i){if(i)switch(t){case h.UP:return h.RIGHT;case h.RIGHT:return h.DOWN;case h.DOWN:return h.LEFT;case h.LEFT:return h.UP}else switch(t){case h.UP:return h.LEFT;case h.LEFT:return h.DOWN;case h.DOWN:return h.RIGHT;case h.RIGHT:return h.UP}return t}getNewPosition(t,i,e,s){let r=t,n=i;switch(e){case h.UP:n-=s;break;case h.DOWN:n+=s;break;case h.LEFT:r-=s;break;case h.RIGHT:r+=s;break}return{x:r,y:n}}checkForBetterDirection(t,i,e,s){const r=this.getValidDirectionsFromTile(i,e,s);if(r.length<3||!r.includes(this.direction))return;const n=t.x-this.x,o=t.y-this.y;let a;if(Math.abs(n)>Math.abs(o)?a=n>0?h.RIGHT:h.LEFT:a=o>0?h.DOWN:h.UP,this.direction===a||!r.includes(a))return;const l=this.direction===h.LEFT||this.direction===h.RIGHT,d=a===h.LEFT||a===h.RIGHT,c=l!==d,f=e*16,u=s*16;if(c){let g;l?g=Math.abs(this.x-f):g=Math.abs(this.y-u);const T=this.speed;g<=T&&(this.direction=a,this.tilesTraveledInDirection=0,this.x=f,this.y=u)}else this.tilesTraveledInDirection>=this.minTilesBeforeReverse&&(this.direction=a,this.tilesTraveledInDirection=0)}decideDirectionAtTile(t,i,e,s){const r=this.getValidDirectionsFromTile(i,e,s);if(r.length===0||r.length===1)return;const n=r.includes(this.direction),o=this.getOppositeDirection(this.direction);if(r.length===2){if(!n){const E=r.find(x=>x!==o);E&&(this.direction=E,this.tilesTraveledInDirection=0);return}if(!r.includes(o)){const E=r.find(x=>x!==this.direction);E&&this.shouldTurnToward(t,E)&&(this.direction=E,this.tilesTraveledInDirection=0)}return}const a=r.filter(p=>this.isViableDirection(i,e,s,p)),l=this.getDirectionToTile(e,s,this.prevGridX,this.prevGridY),d=a.filter(p=>p!==l),c=d.length>0?d:a.length>0?a:r,f=t.x-this.x,u=t.y-this.y;let g,T;if(Math.abs(f)>Math.abs(u)?(g=f>0?h.RIGHT:h.LEFT,T=u>0?h.DOWN:h.UP):(g=u>0?h.DOWN:h.UP,T=f>0?h.RIGHT:h.LEFT),c.includes(g)){this.direction=g;return}if(c.includes(T)){this.direction=T;return}if(c.includes(this.direction))return;const I=c.filter(p=>p!==o);I.length>0?this.direction=I[0]:c.length>0&&(this.direction=c[0])}getDirectionToTile(t,i,e,s){const r=e-t,n=s-i;return r===1&&n===0?h.RIGHT:r===-1&&n===0?h.LEFT:r===0&&n===1?h.DOWN:r===0&&n===-1?h.UP:null}getOppositeDirection(t){switch(t){case h.UP:return h.DOWN;case h.DOWN:return h.UP;case h.LEFT:return h.RIGHT;case h.RIGHT:return h.LEFT;default:return t}}shouldTurnToward(t,i){const e=t.x-this.x,s=t.y-this.y;switch(i){case h.RIGHT:return e>16;case h.LEFT:return e<-16;case h.DOWN:return s>16;case h.UP:return s<-16}return!1}findAdjacentTunnel(t,i,e){const r=[{x:i-1,y:e},{x:i+1,y:e},{x:i,y:e-1},{x:i,y:e+1}];for(const n of r)if(t.isEmpty(n.x,n.y)&&!t.isRock(n.x,n.y)){const o=Math.abs(this.x-n.x*16),a=Math.abs(this.y-n.y*16);if(o<9.6&&a<9.6)return n}return null}isViableDirection(t,i,e,s){let n=i,o=e,a=s;for(let l=0;l<5;l++){let d=n,c=o;switch(a){case h.UP:c--;break;case h.DOWN:c++;break;case h.LEFT:d--;break;case h.RIGHT:d++;break}if(!t.isEmpty(d,c)||t.isRock(d,c))return!1;const f=this.getOppositeDirection(a),g=this.getValidDirectionsFromTile(t,d,c).filter(T=>T!==f);if(g.length>1)return!0;if(g.length===1){n=d,o=c,a=g[0];continue}return!1}return!0}roamAtTile(t,i,e){const s=this.getValidDirectionsFromTile(t,i,e);if(s.length===0||s.length===1)return;const r=this.getDirectionToTile(i,e,this.prevGridX,this.prevGridY),n=s.filter(l=>l!==r),o=n.length>0?n:s;o.includes(this.direction)&&this.directionChangeTimer<1e3+Math.random()*1e3||(this.directionChangeTimer=0,o.length>0&&(this.direction=o[Math.floor(Math.random()*o.length)]))}escapeAtTile(t,i,e){if(e===1&&i<=1){this.direction=h.LEFT;return}const s=this.getValidDirectionsFromTile(t,i,e);if(s.length===0)return;if(s.length===1){this.direction=s[0];return}const r=this.getDirectionToTile(i,e,this.prevGridX,this.prevGridY),n=s.filter(c=>this.isViableDirection(t,i,e,c)),o=n.filter(c=>c!==r);let l=o.length>0?o:n;if(l.length===0){const c=s.filter(f=>f!==r);l=c.length>0?c:s}const d=[h.UP,h.LEFT,h.DOWN,h.RIGHT];e<=1&&(d[0]=h.LEFT,d[1]=h.UP);for(const c of d)if(l.includes(c)){this.direction=c;return}this.direction=s[0]}checkForBetterEscapeDirection(t,i,e){const s=this.getValidDirectionsFromTile(t,i,e);if(s.length<3||!s.includes(this.direction))return;let r;if(e<=1?r=h.LEFT:r=h.UP,this.direction===r||!s.includes(r))return;const n=this.direction===h.LEFT||this.direction===h.RIGHT,o=r===h.LEFT||r===h.RIGHT,a=n!==o,l=i*16,d=e*16;if(a){let c;n?c=Math.abs(this.x-l):c=Math.abs(this.y-d);const f=this.speed;c<=f&&(this.direction=r,this.tilesTraveledInDirection=0,this.x=l,this.y=d)}else this.direction=r,this.tilesTraveledInDirection=0}getValidDirectionsFromTile(t,i,e){const s=[];return t.isEmpty(i,e-1)&&!t.isRock(i,e-1)&&s.push(h.UP),t.isEmpty(i,e+1)&&!t.isRock(i,e+1)&&s.push(h.DOWN),t.isEmpty(i-1,e)&&!t.isRock(i-1,e)&&s.push(h.LEFT),t.isEmpty(i+1,e)&&!t.isRock(i+1,e)&&s.push(h.RIGHT),s}canMoveInDirection(t,i,e,s){let r,n;switch(e){case h.UP:r=t+16/2,n=i;break;case h.DOWN:r=t+16/2,n=i+16-1;break;case h.LEFT:r=t,n=i+16/2;break;case h.RIGHT:r=t+16-1,n=i+16/2;break;default:r=t+16/2,n=i+16/2}const{x:o,y:a}=s.pixelToGrid(r,n);return this.isEscaping&&this.state==="escaping"&&e===h.LEFT&&a===1?!0:a===0?!1:this.isGhosting?!0:s.isRock(o,a)?!1:this.isGhosting?!0:!!s.isEmpty(o,a)}snapToGrid(t){const i=this.x+8,e=this.y+16/2,{x:s,y:r}=t.pixelToGrid(i,e);this.x=s*16,this.y=r*16}pickValidDirection(t,i,e,s){const r=this.getValidDirectionsFromTile(t,e,s);if(r.length!==0){if(this.isEscaping&&this.state==="escaping"){this.pickEscapeDirection(t,e,s,r);return}if(i&&this.state==="chasing"){const n=i.x-this.x,o=i.y-this.y;let a,l;if(Math.abs(n)>Math.abs(o)?(a=n>0?h.RIGHT:h.LEFT,l=o>0?h.DOWN:h.UP):(a=o>0?h.DOWN:h.UP,l=n>0?h.RIGHT:h.LEFT),r.includes(a)){this.direction=a;return}if(r.includes(l)){this.direction=l;return}}this.direction=r[Math.floor(Math.random()*r.length)]}}pickEscapeDirection(t,i,e,s){if(e===1&&i<=1){this.direction=h.LEFT;return}const r=this.getOppositeDirection(this.direction),n=s.filter(c=>this.isViableDirection(t,i,e,c)),o=n.filter(c=>c!==r);let l=o.length>0?o:n;if(l.length===0){const c=s.filter(f=>f!==r);l=c.length>0?c:s}const d=e<=1?[h.LEFT,h.UP,h.DOWN,h.RIGHT]:[h.UP,h.LEFT,h.DOWN,h.RIGHT];for(const c of d)if(l.includes(c)){this.direction=c;return}this.direction=s[0]}applyGridSnapping(t){const{x:i,y:e}=t.pixelToGrid(this.x+8,this.y+8);if(t.isEmpty(i,e)){if(this.direction===h.LEFT||this.direction===h.RIGHT){const r=e*16-this.y;if(Math.abs(r)>0){const n=Math.sign(r)*Math.min(Math.abs(r),this.speed);this.y+=n}}if(this.direction===h.UP||this.direction===h.DOWN){const r=i*16-this.x;if(Math.abs(r)>0){const n=Math.sign(r)*Math.min(Math.abs(r),this.speed);this.x+=n}}}}initializeDirection(t){const{x:i,y:e}=t.pixelToGrid(this.x+8,this.y+8),s=this.getValidDirectionsFromTile(t,i,e);s.includes(h.RIGHT)?this.spriteFlipH=!0:s.includes(h.LEFT)?this.direction=h.LEFT:s.includes(h.DOWN)?this.direction=h.DOWN:s.includes(h.UP)&&(this.direction=h.UP)}startInflation(){this.isInflating=!0,this.isMoving=!1,this.deflateTimer=0}stopInflation(){}updateInflation(t){this.isInflating?(this.inflateTimer+=t,this.inflateLevel=1+this.inflateTimer/this.INFLATE_DURATION,this.inflateLevel>=2&&this.pop()):this.inflateLevel>1&&(this.deflateTimer+=t,this.deflateTimer>300&&(this.inflateTimer=Math.max(0,this.inflateTimer-t*.5),this.inflateLevel=1+this.inflateTimer/this.INFLATE_DURATION,this.inflateLevel<=1&&(this.inflateLevel=1,this.inflateTimer=0,this.deflateTimer=0,this.isMoving=!0))),this.isInflating=!1}pop(){this.isPopped=!0,this.poppedTimer=0,this.isMoving=!1}smoosh(){this.isSmooshed=!0,this.smooshedTimer=0,this.isMoving=!1}updatePoppedState(t){this.isPopped&&(this.poppedTimer+=t,this.poppedTimer>=this.POPPED_DURATION&&(this.isDestroyed=!0))}updateSmooshedState(t){this.isSmooshed&&(this.attachedToRock&&this.attachedToRock.isFalling||(this.smooshedTimer+=t,this.smooshedTimer>=this.SMOOSHED_DURATION&&(this.isDestroyed=!0)))}updateAnimation(t){this.animationTimer+=t,this.animationTimer>400&&(this.animationFrame=(this.animationFrame+1)%2,this.animationTimer=0)}getCenter(){return{x:this.x+16/2,y:this.y+16/2}}resetTimers(){this.ghostModeTimer=0,this.canGhostMode=!1,this.isGhosting=!1,this.ghostingDuration=0,this.stateTimer=0,this.directionChangeTimer=0,this.inflateTimer=0,this.inflateLevel=1,this.isInflating=!1,this.deflateTimer=0,this.isMoving=!0,this.isLastEnemy=!1,this.isEscaping=!1,this.hasEscaped=!1,this.state="roaming"}}class J extends K{constructor(t,i,e=1){super(t,i,G.POOKA,R.POOKA.SPEED,e),this.ghostSpeed=R.POOKA.GHOST_SPEED}}class tt extends K{constructor(t,i,e=1){super(t,i,G.FYGAR,R.FYGAR.SPEED,e),this.ghostSpeed=R.FYGAR.GHOST_SPEED,this.fireState="ready",this.fireStateTimer=0,this.fireCooldownTimer=0,this.fireDirection=null,this.fireHitbox=null}update(t,i,e){super.update(t,i,e),i&&!this.isInflating&&!this.isGhosting&&this.updateFireBreath(t,i,e),(this.isInflating||this.inflateLevel>1)&&(this.fireState==="charging"||this.fireState==="firing")&&this.cancelFire(),this.isGhosting&&(this.fireState==="charging"||this.fireState==="firing")&&this.cancelFire()}updateGhostMode(t,i,e){this.fireState==="charging"||this.fireState==="firing"||super.updateGhostMode(t,i,e)}updateFireBreath(t,i,e){if(this.fireState==="cooldown"){this.fireCooldownTimer+=t,this.fireCooldownTimer>=R.FYGAR.FIRE_COOLDOWN&&(this.fireState="ready",this.fireCooldownTimer=0);return}if(this.fireState==="ready"){if(this.direction!==h.LEFT&&this.direction!==h.RIGHT)return;(this.direction===h.RIGHT&&this.x<i.x||this.direction===h.LEFT&&this.x>i.x)&&this.isPlayerInFireRange(i,e)&&this.startCharging();return}if(this.fireState==="charging"){this.fireStateTimer+=t,this.fireStateTimer>=R.FYGAR.FIRE_CHARGE_TIME&&this.startFiring();return}if(this.fireState==="firing"){this.fireStateTimer+=t,this.calculateFireHitbox(),this.fireStateTimer>=R.FYGAR.FIRE_DURATION&&this.stopFiring();return}}isPlayerInFireRange(t,i){const e=t.x-this.x,s=t.y-this.y;if(Math.abs(s)>16*.75||!(this.direction===h.RIGHT&&e>0&&e<R.FYGAR.FIRE_RANGE||this.direction===h.LEFT&&e<0&&e>-64))return!1;const n=Math.floor((this.x+16/2)/16),o=Math.floor((t.x+16/2)/16),a=Math.floor((this.y+16/2)/16),l=Math.min(n,o),d=Math.max(n,o);for(let c=l+1;c<d;c++)if(i.isDirt(c,a))return!1;return!0}startCharging(){this.fireState="charging",this.fireStateTimer=0,this.fireDirection=this.direction,this.isMoving=!1;const t=Math.floor((this.x+16/2)/16),i=Math.floor((this.y+16/2)/16);this.x=t*16,this.y=i*16,this.lastGridX=t,this.lastGridY=i}startFiring(){this.fireState="firing",this.fireStateTimer=0,this.calculateFireHitbox()}calculateFireHitbox(){const t=this.getFireTileCount();if(t===0){this.fireHitbox=null;return}const i=t*16,e=this.y+16/2;this.fireDirection===h.RIGHT?this.fireHitbox={x:this.x+16,y:e-16/4,width:i,height:16/2}:this.fireHitbox={x:this.x-i,y:e-16/4,width:i,height:16/2}}stopFiring(){this.fireState="cooldown",this.fireStateTimer=0,this.fireCooldownTimer=0,this.fireHitbox=null,this.fireDirection=null,this.isMoving=!0;const t=Math.floor((this.x+16/2)/16),i=Math.floor((this.y+16/2)/16);this.lastGridX=t,this.lastGridY=i}cancelFire(){this.fireState="cooldown",this.fireStateTimer=0,this.fireCooldownTimer=R.FYGAR.FIRE_COOLDOWN*.5,this.fireHitbox=null,this.fireDirection=null}isFireActive(){return this.fireState==="firing"&&this.fireHitbox!==null}isCharging(){return this.fireState==="charging"}getFireHitbox(){return this.fireHitbox}getFireDirection(){return this.fireDirection}getFireTileCount(){if(this.fireState!=="firing")return 0;const t=this.fireStateTimer/R.FYGAR.FIRE_DURATION;return t<.33?1:t<.66?2:3}resetTimers(){super.resetTimers(),this.fireState="ready",this.fireStateTimer=0,this.fireCooldownTimer=0,this.fireDirection=null,this.fireHitbox=null}}class z{constructor(t,i,e){this.x=t,this.y=i,this.grid=e,this.isFalling=!1,this.isShaking=!1,this.shakeTimer=0,this.fallDelay=O.FALL_DELAY,this.fallSpeed=O.FALL_SPEED,this.isCrumbling=!1,this.crumbleTimer=0,this.CRUMBLE_DURATION=800,this.waitingToCrumble=!1,this.crumbleDelayTimer=0,this.CRUMBLE_DELAY=400,this.crushedEnemy=!1,this.enemiesKilled=0,this.killPositions=[],this.playerStillBelow=!1,this.playerLastX=0,this.playerLastY=0,this.fallDelayTimer=0,this.waitingToFall=!1,this.gridX=Math.floor(t/16),this.gridY=Math.floor(i/16),this.isSpawning=!1,this.spawnTimer=0,this.SPAWN_DURATION=2e3}update(t,i,e){if(this.isSpawning){this.spawnTimer+=t,this.spawnTimer>=this.SPAWN_DURATION&&(this.isSpawning=!1);return}if(this.waitingToCrumble){this.crumbleDelayTimer+=t,this.crumbleDelayTimer>=this.CRUMBLE_DELAY&&(this.waitingToCrumble=!1,this.isCrumbling=!0,this.crumbleTimer=0);return}if(this.isCrumbling){this.crumbleTimer+=t,this.crumbleTimer>this.CRUMBLE_DURATION&&(this.isDestroyed=!0);return}this.isShaking&&(this.shakeTimer+=t,this.shakeTimer>O.SHAKE_DURATION&&(e&&this.playerStillBelow?this.hasPlayerCleared(e)&&(this.playerStillBelow=!1,this.waitingToFall=!0,this.fallDelayTimer=0):this.waitingToFall||this.startFalling(i))),this.waitingToFall&&(this.fallDelayTimer+=t,this.fallDelayTimer>=this.fallDelay&&(this.waitingToFall=!1,this.startFalling(i))),this.isFalling&&this.fall(i),!this.isFalling&&!this.isShaking&&e&&this.checkPlayerTrigger(e,i)}checkPlayerTrigger(t,i){const e=i.isDirt(this.gridX,this.gridY+1),s=i.isRock(this.gridX,this.gridY+1);if(e||s||this.gridY>=i.height-1)return;const r=Math.floor(t.x/16),o=Math.floor(t.y/16)===this.gridY+1&&Math.abs(r-this.gridX)<=1,a=t.y,l=this.y+16,d=Math.abs(a-l)<4,c=Math.abs(t.x-this.x)<16;(o&&d&&c||d&&c&&t.y<this.y)&&(this.playerStillBelow=!0,this.playerLastX=t.x,this.playerLastY=t.y,this.startShaking())}hasPlayerCleared(t){const i=t.x,e=t.x+16,s=this.x,r=this.x+16,n=e<=s||i>=r,a=Math.floor(t.y/16)!==this.gridY+1;return n||a}startSpawnAnimation(){this.isSpawning=!0,this.spawnTimer=0}startShaking(){this.isShaking=!0,this.shakeTimer=0}startFalling(t){this.isFalling=!0,this.isShaking=!1,t.removeRock(this.gridX,this.gridY)}fall(t){this.y+=this.fallSpeed;const i=Math.floor(this.y/16);if(i!==this.gridY){this.gridY=i;const e=t.isDirt(this.gridX,this.gridY+1),s=t.isRock(this.gridX,this.gridY+1),r=this.gridY>=t.height-1;(e||s||r)&&this.stopFalling()}}stopFalling(){this.isFalling=!1,this.y=this.gridY*16,this.waitingToCrumble=!0,this.crumbleDelayTimer=0}markEnemyCrushed(){this.crushedEnemy=!0}incrementKillCount(t,i){return this.enemiesKilled++,this.killPositions.push({x:t,y:i}),this.enemiesKilled}getLastKillPosition(){return this.killPositions.length>0?this.killPositions[this.killPositions.length-1]:{x:this.x,y:this.y}}getCenter(){return{x:this.x+16/2,y:this.y+16/2}}reset(){this.isShaking=!1,this.shakeTimer=0,this.playerStillBelow=!1,this.waitingToFall=!1,this.fallDelayTimer=0,this.waitingToCrumble=!1,this.crumbleDelayTimer=0}}class it{constructor(t){this.grid=t,this.currentLevel=0,this.rocks=[]}generateLevel(t){this.currentLevel=t,this.grid.reset(),this.rocks=[],this.currentEnemies=[],this.generateTunnels()}generateTunnels(){const t=Math.floor(13.5),i=Math.floor(18/2);this.grid.clearHorizontalTunnel(t-1,t+1,i),this.currentLevel>1&&this.grid.clearVerticalTunnel(t,2,i),this.playerStartTunnel={x:t,y:i}}placeRocksAfterEnemies(t,i){const e=Math.floor(t/3),s=Math.min(v.ROCKS_PER_LEVEL+e,6),r=3,n=27,o=18,a=n/2,l=a-2,d=a+2,c=i.map(p=>({x:Math.floor(p.x/16),y:Math.floor(p.y/16)}));this.rocks=[];const f=[],u=4,g=5;for(let p=g;p<o-5;p++)for(let E=u;E<n-8;E++)E>=l&&E<=d||this.grid.isDirt(E,p)&&f.push({x:E,y:p});for(let p=f.length-1;p>0;p--){const E=Math.floor(Math.random()*(p+1));[f[p],f[E]]=[f[E],f[p]]}const T=(p,E,x,D)=>{const{x:y,y:P}=p;for(let S=0;S<this.rocks.length;S++){const M=this.rocks[S],F=Math.abs(M.gridX-y),W=Math.abs(M.gridY-P);if(F<D&&W<D)return!1}if(x>0)for(let S=0;S<c.length;S++){const M=c[S],F=Math.abs(M.x-y),W=Math.abs(M.y-P);if(F<x&&W<x)return!1}for(let S=-E;S<=E;S++)for(let M=-E;M<=E;M++)if(!(M===0&&S===0)&&this.grid.isEmpty(y+M,P+S))return!1;return!0},I=[{target:s,path:3,enemy:6,rock:10},{target:s,path:2,enemy:4,rock:4},{target:r,path:1,enemy:0,rock:2}];for(const p of I)if(!(this.rocks.length>=p.target))for(const E of f){if(this.rocks.length>=p.target)break;this.grid.isRock(E.x,E.y)||T(E,p.path,p.enemy,p.rock)&&(this.grid.placeRock(E.x,E.y),this.rocks.push(new z(E.x*16,E.y*16,this.grid)))}}spawnEnemies(t){const i=[],e=Math.min(v.START_ENEMIES+(t-1)*v.ENEMY_INCREMENT,v.MAX_ENEMIES),s=Math.min(.5,.2+t*.05),r=Math.floor(e*s),n=e-r;this.enemyTunnels=[],this.createEnemyTunnels(e);for(let o=0;o<n;o++){const a=this.getEnemySpawnPosition(o);i.push(new J(a.x,a.y,t))}for(let o=0;o<r;o++){const a=this.getEnemySpawnPosition(n+o);i.push(new tt(a.x,a.y,t))}return i}createEnemyTunnels(t){this.enemyTunnels=[];const i=27,e=18,s=Math.floor(i/2),r=Math.floor(e/2),n=100,o=36,a=[],l=4,d=4;for(let g=d;g<e-d;g++)for(let T=l;T<i-l;T++){const I=T-s,p=g-r;I*I+p*p<o||a.push({x:T,y:g})}for(let g=a.length-1;g>0;g--){const T=Math.floor(Math.random()*(g+1));[a[g],a[T]]=[a[T],a[g]]}const c=(g,T,I,p)=>{if(I){const E=Math.min(p,i-2-g);return{minX:g,maxX:g+E,minY:T,maxY:T}}else{const E=Math.min(p,e-2-T);return{minX:g,maxX:g,minY:T,maxY:T+E}}},f=(g,T,I)=>g.minX<=T.maxX+I&&g.maxX>=T.minX-I&&g.minY<=T.maxY+I&&g.maxY>=T.minY-I,u=(g,T)=>{for(let I=0;I<a.length;I++){if(this.enemyTunnels.length>=t)return;const{x:p,y:E}=a[I],x=p-s,D=E-r;if(x*x+D*D<T)continue;const y=Math.random()>.5,P=Math.floor(Math.random()*2)+2,S=c(p,E,y,P);let M=!0;for(const F of this.enemyTunnels)if(f(S,F.bounds,g)){M=!1;break}M&&(y?this.grid.clearHorizontalTunnel(S.minX,S.maxX,S.minY):this.grid.clearVerticalTunnel(S.minX,S.minY,S.maxY),this.enemyTunnels.push({x:p,y:E,horizontal:y,length:P,bounds:S}))}};u(6,n),this.enemyTunnels.length<t&&u(2,o)}getEnemySpawnPosition(t){if(t<this.enemyTunnels.length){const i=this.enemyTunnels[t],e=i.horizontal?Math.floor(Math.random()*i.length):0,s=i.horizontal?0:Math.floor(Math.random()*i.length),r=i.x+e,n=i.y+s;if(this.grid.isEmpty(r,n))return{x:r*16,y:n*16}}for(let i=0;i<this.grid.height;i++)for(let e=0;e<this.grid.width;e++)if(this.grid.isEmpty(e,i)&&i>2)return{x:e*16,y:i*16};return{x:16*5,y:16*5}}spawnBonusItem(t=0){const i=Math.floor(13.5)*16,e=Math.floor(18/2)*16;return{x:i,y:e,bonusIndex:t,FLASH_START:3e3,FLASH_DURATION:2e3,elapsedTime:0,update:function(s){return this.elapsedTime+=s,!(this.elapsedTime>this.FLASH_START+this.FLASH_DURATION)},isFlashing:function(){return this.elapsedTime>=this.FLASH_START}}}spawnSingleRock(){const t=[];for(let s=4;s<16;s++)for(let r=2;r<25;r++){if(!this.grid.isDirt(r,s)||r>=27/2-2&&r<=27/2+2)continue;let n=!1;for(const o of this.rocks){const a=Math.floor(o.x/16),l=Math.floor(o.y/16);if(Math.abs(r-a)+Math.abs(s-l)<4){n=!0;break}}n||t.push({x:r,y:s})}if(t.length===0)return null;const i=t[Math.floor(Math.random()*t.length)];return this.grid.placeRock(i.x,i.y),new z(i.x*16,i.y*16,this.grid)}getRocks(){return this.rocks}}class et{constructor(){this.score=0,this.lives=b.START_LIVES,this.highScore=this.loadHighScore(),this.nextExtraLifeThreshold=2e4}reset(){this.score=0,this.lives=b.START_LIVES,this.nextExtraLifeThreshold=2e4}addDigScore(){const t=k.DIG_TILE;return this.addScore(t),t}getDepthQuarter(t){const i=Math.floor(t/16),e=2,r=16/4,n=Math.max(0,i-e);return Math.min(3,Math.floor(n/r))}addEnemyKill(t,i,e=!1){const s=this.getDepthQuarter(i);let r;return t===G.FYGAR&&e?r=k.PUMP_KILL.FYGAR_HORIZONTAL[s]:t===G.FYGAR?r=k.PUMP_KILL.FYGAR[s]:r=k.PUMP_KILL.POOKA[s],this.addScore(r),r}addRockKill(t){const i=Math.min(t,8),e=k.ROCK_KILL[i];return this.addScore(e),e}addBonusItem(t){const i=Math.min(t,k.BONUS_ITEMS.length-1),e=k.BONUS_ITEMS[i];return this.addScore(e),e}addScore(t){return this.score+=t,this.checkExtraLife()}checkExtraLife(){return this.score>=this.nextExtraLifeThreshold?(this.gainLife(),this.nextExtraLifeThreshold===2e4?this.nextExtraLifeThreshold=5e4:this.nextExtraLifeThreshold+=5e4,!0):!1}loseLife(){this.lives--}gainLife(){this.lives++}loadHighScore(){try{const t=localStorage.getItem(X);return t?parseInt(t,10):0}catch{return 0}}saveHighScore(){try{localStorage.setItem(X,this.highScore.toString())}catch{}}}class N{constructor(t){this.grid=t;const i=Math.floor(t.width/2),e=Math.floor(t.height/2);this.x=16*i,this.y=16*e,this.speed=b.SPEED,this.direction=h.LEFT,this.previousDirection=h.LEFT,this.isMoving=!1,this.isShooting=!1,this.isPumping=!1,this.pumpTarget=null,this.pumpLength=0,this.pumpMaxLength=b.PUMP_RANGE,this.pumpExtendSpeed=4,this.pumpRetractSpeed=8,this.shouldAutoRetract=!1,this.pumpUsed=!1,this.fullLengthTimer=0,this.fullLengthDelay=200,this.animationFrame=0,this.animationTimer=0,this.spriteFlipH=!1,this.spriteFlipV=!1,this.isDigging=!1,this.isDying=!1,this.deathTimer=0,this.deathType=null,this.isSmooshed=!1,this.attachedToRock=null,this.smooshedDelayTimer=0,this.SMOOSHED_DELAY=400,this.isInvincible=!1,this.invincibilityTimer=0,this.pumpCooldown=800,this.pumpCooldownTimer=0}startDeath(t){this.isDying=!0,this.deathTimer=0,this.deathType=t,this.isMoving=!1}smoosh(t){this.isSmooshed=!0,this.attachedToRock=t,this.startDeath("rock")}update(t,i,e){if(this.isDying){if(this.isSmooshed&&this.attachedToRock&&this.attachedToRock.isFalling)return;if(this.isSmooshed&&this.smooshedDelayTimer<this.SMOOSHED_DELAY){this.smooshedDelayTimer+=t;return}this.deathTimer+=t;return}this.isInvincible&&(this.invincibilityTimer+=t,this.invincibilityTimer>Z.INVINCIBILITY_TIME&&(this.isInvincible=!1)),this.pumpCooldownTimer<this.pumpCooldown&&(this.pumpCooldownTimer+=t);const s=this.pumpCooldownTimer>=this.pumpCooldown,r=i.isSpacePressed();r||(this.pumpUsed=!1),r&&s&&!this.shouldAutoRetract&&!this.pumpUsed?(this.isShooting||this.startPump(),this.extendPump(t)):(this.isShooting||this.pumpLength>0)&&this.retractPump();const n=i.getDirection();n&&!this.isShooting&&!this.isPumping?(n!==this.direction&&(this.previousDirection=this.direction,this.updateSpriteOrientation(n)),this.direction=n,this.isMoving=!0,this.move(n,e)):this.isMoving=!1,(this.isMoving||this.isPumping)&&(this.animationTimer+=t,this.animationTimer>(this.isMoving?100:200)&&(this.animationFrame=(this.animationFrame+1)%2,this.animationTimer=0)),this.checkDiggingState(e),this.dig(e)}move(t,i){let e=this.x,s=this.y;switch(t){case h.UP:s-=this.speed;break;case h.DOWN:s+=this.speed;break;case h.LEFT:e-=this.speed;break;case h.RIGHT:e+=this.speed;break}e<0&&(e=0),e>i.width*16-16&&(e=i.width*16-16),s<0&&(s=0),s>i.height*16-16&&(s=i.height*16-16);const r=e+16/2,n=s+16/2,o=i.pixelToGrid(r,n);if(i.dig(o.x,o.y),this.canMoveToPosition(e,s,i)){if(this.x=e,this.y=s,t===h.LEFT||t===h.RIGHT){const l=this.y+8,f=Math.floor(l/16)*16-this.y;Math.abs(f)>0&&(this.y+=Math.sign(f)*Math.min(Math.abs(f),this.speed))}if(t===h.UP||t===h.DOWN){const l=this.x+8,f=Math.floor(l/16)*16-this.x;Math.abs(f)>0&&(this.x+=Math.sign(f)*Math.min(Math.abs(f),this.speed))}}}canMoveToPosition(t,i,e){return[{x:t,y:i},{x:t+16-1,y:i},{x:t,y:i+16-1},{x:t+16-1,y:i+16-1}].every(r=>{const{x:n,y:o}=e.pixelToGrid(r.x,r.y);return o===0?!1:!e.isRock(n,o)})}checkDiggingState(t){const i=this.x+8,e=this.y+16/2,{x:s,y:r}=t.pixelToGrid(i,e);let n=!1;switch(this.direction){case h.LEFT:n=t.isDirt(s-1,r);break;case h.RIGHT:n=t.isDirt(s+1,r);break;case h.UP:n=t.isDirt(s,r-1);break;case h.DOWN:n=t.isDirt(s,r+1);break}this.isDigging=n}dig(t){const i=this.x+8,e=this.y+16/2,{x:s,y:r}=t.pixelToGrid(i,e);t.dig(s,r)}updateSpriteOrientation(t){t===h.LEFT||t===h.RIGHT?t===h.RIGHT?(this.spriteFlipH=!0,this.spriteFlipV=!1):(this.spriteFlipH=!1,this.spriteFlipV=!1):t===h.DOWN?this.previousDirection===h.RIGHT?(this.spriteFlipH=!0,this.spriteFlipV=!1):this.previousDirection===h.UP?this.spriteFlipV=!this.spriteFlipV:this.previousDirection===h.LEFT&&(this.spriteFlipH=!1,this.spriteFlipV=!1):t===h.UP&&(this.previousDirection===h.LEFT?(this.spriteFlipH=!0,this.spriteFlipV=!0):this.previousDirection===h.RIGHT?(this.spriteFlipH=!1,this.spriteFlipV=!0):this.previousDirection===h.DOWN&&(this.spriteFlipV=!this.spriteFlipV))}startPump(){this.isShooting=!0,this.isMoving=!1}extendPump(t){if(this.pumpTarget){this.isShooting=!1,this.isPumping=!0,this.pumpTarget.isDestroyed&&(this.pumpLength=0,this.stopPump());return}if(this.pumpLength<this.pumpMaxLength){const i=Math.min(this.pumpLength+this.pumpExtendSpeed,this.pumpMaxLength);this.canPumpExtendTo(i)?(this.pumpLength=i,this.fullLengthTimer=0):(this.fullLengthTimer+=t,this.fullLengthTimer>=this.fullLengthDelay&&(this.shouldAutoRetract=!0))}else this.fullLengthTimer+=t,this.fullLengthTimer>=this.fullLengthDelay&&(this.shouldAutoRetract=!0)}canPumpExtendTo(t){const i=this.x+8,e=this.y+16/2;let s=i,r=e;switch(this.direction){case h.UP:r=e-t;break;case h.DOWN:r=e+t;break;case h.LEFT:s=i-t;break;case h.RIGHT:s=i+t;break}const{x:n,y:o}=this.grid.pixelToGrid(s,r);return!this.grid.isDirt(n,o)&&!this.grid.isRock(n,o)}retractPump(){if(this.pumpTarget&&this.pumpTarget.isDestroyed){this.pumpLength=0,this.stopPump();return}this.pumpLength=Math.max(0,this.pumpLength-this.pumpRetractSpeed),this.pumpLength===0&&this.stopPump()}stopPump(){this.isShooting=!1,this.isPumping=!1,this.pumpTarget=null,this.pumpLength=0,this.shouldAutoRetract=!1,this.pumpUsed=!0,this.fullLengthTimer=0}getPumpEndPoint(){const t=this.x+8,i=this.y+16/2;switch(this.direction){case h.UP:return{x:t,y:i-this.pumpLength};case h.DOWN:return{x:t,y:i+this.pumpLength};case h.LEFT:return{x:t-this.pumpLength,y:i};case h.RIGHT:return{x:t+this.pumpLength,y:i};default:return{x:t,y:i}}}getGridPosition(){return this.grid.pixelToGrid(this.x,this.y)}getCenter(){return{x:this.x+16/2,y:this.y+16/2}}resetTimers(){this.pumpCooldownTimer=0,this.invincibilityTimer=0,this.animationTimer=0,this.fullLengthTimer=0,this.pumpLength=0,this.isShooting=!1,this.isPumping=!1,this.pumpTarget=null,this.shouldAutoRetract=!1,this.pumpUsed=!1,this.isSmooshed=!1,this.attachedToRock=null,this.smooshedDelayTimer=0}}class Y{constructor(t={}){this.config={container:t.container||document.body,width:t.width||432,height:t.height||288,scale:t.scale||1,debug:t.debug||!1,onGameOver:t.onGameOver||(()=>{}),onLevelComplete:t.onLevelComplete||(()=>{}),onScoreChange:t.onScoreChange||(()=>{})},this.state=m.MENU,this.lastTime=0,this.animationFrameId=null,this.renderer=new $(this.config),this.grid=new q,this.inputManager=new j,this.collisionSystem=new Q(this.grid),this.levelManager=new it(this.grid),this.scoreManager=new et,this.player=null,this.enemies=[],this.rocks=[],this.bonusItems=[],this.rockRespawnTimer=0,this.ROCK_RESPAWN_DELAY=5e3,this.needsRockRespawn=!1,this.bonusSpawnCount=0,this.floatingScores=[],this.lastDirtCount=0,this.gameLoop=this.gameLoop.bind(this)}init(){this.renderer.attachTo(this.config.container),this.inputManager.init(),this.showMenu()}showMenu(){if(this.state=m.MENU,this.renderer.clear(),this.renderer.drawMenu(),!this.menuListenerAdded){this.menuListenerAdded=!0;const t=i=>{i.code==="Space"&&this.state===m.MENU&&(document.removeEventListener("keydown",t),this.menuListenerAdded=!1,this.startGame())};document.addEventListener("keydown",t)}}startGame(){this.animationFrameId&&(cancelAnimationFrame(this.animationFrameId),this.animationFrameId=null),this.scoreManager.reset(),this.lastTime=0,this.startIntro(),this.gameLoop(0)}startIntro(){this.state=m.INTRO,this.levelManager.generateLevel(1),this.enemies=this.config.debug?[]:this.levelManager.spawnEnemies(1),this.levelManager.placeRocksAfterEnemies(1,this.enemies),this.rocks=this.levelManager.getRocks(),this.bonusItems=[],this.droppedRocksCount=0,this.bonusSpawnCount=0,this.rockRespawnTimer=0,this.needsRockRespawn=!1,this.introCenterX=Math.floor(this.grid.width/2),this.introCenterY=Math.floor(this.grid.height/2),this.introTargetX=this.introCenterX*16,this.introTargetY=this.introCenterY*16,this.player=new N(this.grid),this.player.x=this.grid.width*16,this.player.y=16,this.player.direction=h.LEFT,this.player.spriteFlipH=!1,this.player.isMoving=!0,this.introPhase="walk_left",this.introTimer=0,this.introReadyDelay=1e3}resetAllTimers(){this.enemies.forEach(t=>{t.resetTimers()}),this.player&&this.player.resetTimers()}startLevel(t){this.levelManager.generateLevel(t),this.player=new N(this.grid),this.enemies=this.levelManager.spawnEnemies(t),this.levelManager.placeRocksAfterEnemies(t,this.enemies),this.rocks=this.levelManager.getRocks(),this.bonusItems=[],this.droppedRocksCount=0,this.rockRespawnTimer=0,this.needsRockRespawn=!1,this.floatingScores=[]}gameLoop(t){const i=t-this.lastTime,e=Math.min(i,100);switch(this.lastTime=t,this.state){case m.INTRO:this.updateIntro(e),this.renderIntro();break;case m.PLAYING:this.update(e),this.render();break;case m.DYING:this.updateDeath(e),this.render();break;case m.RESPAWNING:this.updateRespawn(e),this.renderRespawning();break;case m.PAUSED:this.renderPaused();break;case m.LEVEL_COMPLETE:this.renderLevelComplete();break;case m.GAME_OVER:this.renderGameOver();break}this.animationFrameId=requestAnimationFrame(this.gameLoop)}updateIntro(t){const i=this.config.debug?3:1.6;switch(this.introPhase!=="ready"&&(this.player.animationTimer+=t,this.player.animationTimer>100&&(this.player.animationFrame=(this.player.animationFrame+1)%2,this.player.animationTimer=0)),this.introPhase){case"walk_left":this.player.x-=i,this.player.isMoving=!0,this.player.direction=h.LEFT,this.player.spriteFlipH=!1,this.player.x<=this.introTargetX&&(this.player.x=this.introTargetX,this.introPhase="dig_down",this.player.direction=h.DOWN,this.player.spriteFlipH=!1,this.player.spriteFlipV=!1);break;case"dig_down":{this.player.y+=i,this.player.isMoving=!0,this.player.isDigging=!0,this.player.direction=h.DOWN;const e=this.grid.pixelToGrid(this.player.x+16/2,this.player.y+16/2);this.grid.dig(e.x,e.y),this.player.y>=this.introTargetY&&(this.player.y=this.introTargetY,this.introPhase="ready",this.introTimer=0,this.player.isMoving=!1,this.player.isDigging=!1,this.player.direction=h.RIGHT,this.player.spriteFlipH=!0);break}case"ready":this.player.animationFrame=0,this.introTimer+=t,this.introTimer>=this.introReadyDelay&&(this.introPhase="done",this.finishIntro());break}}finishIntro(){this.player.resetTimers(),this.resetAllTimers(),this.state=m.PLAYING}renderIntro(){this.renderer.clear(),this.renderer.drawGrid(this.grid,this.levelManager.currentLevel),this.rocks.forEach(t=>{this.renderer.drawRock(t)}),this.player&&this.renderer.drawPlayer(this.player),this.enemies.forEach(t=>{this.renderer.drawEnemy(t)}),this.renderer.drawUI(this.scoreManager,this.levelManager),this.renderer.renderRespawning()}update(t){if(this.inputManager.isKeyPressed("Escape")){this.pause();return}if(this.player){const i=this.countDirtTiles();this.player.update(t,this.inputManager,this.grid);const e=this.countDirtTiles(),s=i-e;for(let r=0;r<s;r++)this.scoreManager.addDigScore();s>0&&this.config.onScoreChange(this.scoreManager.score)}if(this.enemies.length===1&&(this.enemies[0].isLastEnemy=!0),this.enemies.forEach(i=>{i.update(t,this.player,this.grid)}),this.rocks.forEach(i=>{i.update(t,this.grid,this.player)}),this.needsRockRespawn&&this.rocks.length===0&&(this.rockRespawnTimer+=t,this.rockRespawnTimer>=this.ROCK_RESPAWN_DELAY)){const i=this.levelManager.spawnSingleRock();i?(i.startSpawnAnimation(),this.rocks.push(i),this.needsRockRespawn=!1,this.rockRespawnTimer=0):this.needsRockRespawn=!1}this.bonusItems.forEach(i=>{i.update(t)}),this.updateFloatingScores(t),this.checkCollisions(),!this.config.debug&&this.enemies.length===0&&this.levelComplete()}checkCollisions(){this.player.pumpLength>0&&this.checkPumpCollisions(),this.checkFireCollisions(),this.enemies.forEach(i=>{i.deflateTimer===0&&this.collisionSystem.checkPlayerEnemyCollision(this.player,i)&&this.playerHit("enemy")}),this.rocks.forEach(i=>{i.isFalling&&(this.enemies.forEach(e=>{e.isSmooshed||this.collisionSystem.checkRockEntityCollision(i,e)&&(i.markEnemyCrushed(),i.incrementKillCount(e.x,e.y),this.droppedRocksCount++,this.checkBonusSpawn(),e.smoosh(),e.attachedToRock=i,e.x=i.x,e.y=i.y)}),!this.player.isSmooshed&&this.collisionSystem.checkRockEntityCollision(i,this.player)&&(this.player.smoosh(i),this.player.x=i.x,this.player.y=i.y,this.state=m.DYING,this.deathStartTime=Date.now())),this.enemies.forEach(e=>{e.isSmooshed&&e.attachedToRock===i&&(e.x=i.x,e.y=i.y)}),this.player.isSmooshed&&this.player.attachedToRock===i&&(this.player.x=i.x,this.player.y=i.y)});const t=this.rocks.length;this.rocks=this.rocks.filter(i=>{if(i.isDestroyed){if(i.enemiesKilled>0){const e=this.scoreManager.addRockKill(i.enemiesKilled);this.config.onScoreChange(this.scoreManager.score),this.spawnFloatingScore(e,i.x,i.y)}return!1}return!0}),this.rocks.length===0&&t>0&&(this.needsRockRespawn=!0,this.rockRespawnTimer=0),this.enemies=this.enemies.filter(i=>!i.hasEscaped),this.enemies=this.enemies.filter(i=>{if(i.isDestroyed){if(!i.isSmooshed){const e=this.player.direction===h.LEFT||this.player.direction===h.RIGHT,s=this.scoreManager.addEnemyKill(i.type,i.y,e);this.config.onScoreChange(this.scoreManager.score),this.spawnFloatingScore(s,i.x,i.y)}return!1}return!0}),this.bonusItems=this.bonusItems.filter(i=>{if(this.collisionSystem.checkPlayerBonusCollision(this.player,i)){const e=this.scoreManager.addBonusItem(i.bonusIndex);return this.config.onScoreChange(this.scoreManager.score),this.spawnFloatingScore(e,i.x,i.y),!1}return!0})}checkPumpCollisions(){if(this.player.pumpTarget&&!this.player.pumpTarget.isDestroyed){this.player.pumpTarget.startInflation();return}const t=this.player.getCenter(),i=this.player.getPumpEndPoint(),e=this.player.pumpLength;let s=null,r=1/0;this.enemies.forEach(n=>{if(n.isDestroyed)return;const o=n.getCenter(),a=this.pointToLineDistance(o.x,o.y,t.x,t.y,i.x,i.y),l=Math.sqrt(Math.pow(o.x-t.x,2)+Math.pow(o.y-t.y,2)),d=16*.6;a<d&&l<=e+16/2&&this.isInPumpDirection(t,i,o)&&l<r&&(r=l,s=n)}),s&&(s.startInflation(),this.player.pumpTarget=s)}pointToLineDistance(t,i,e,s,r,n){const o=r-e,a=n-s,l=o*o+a*a;if(l===0)return Math.sqrt((t-e)**2+(i-s)**2);let d=((t-e)*o+(i-s)*a)/l;d=Math.max(0,Math.min(1,d));const c=e+d*o,f=s+d*a;return Math.sqrt((t-c)**2+(i-f)**2)}isInPumpDirection(t,i,e){const s=i.x-t.x,r=i.y-t.y,n=e.x-t.x,o=e.y-t.y;return s*n+r*o>0}checkFireCollisions(){this.enemies.forEach(t=>{if(t.type===G.POOKA||!t.isFireActive())return;const i=t.getFireHitbox();if(!i)return;this.collisionSystem.checkAABB(i.x,i.y,i.width,i.height,this.player.x,this.player.y,16,16)&&this.playerHit("enemy")})}checkBonusSpawn(){if(this.droppedRocksCount===2&&this.bonusItems.length===0){const t=this.levelManager.spawnBonusItem(this.bonusSpawnCount);t&&(this.bonusItems.push(t),this.bonusSpawnCount++)}}spawnFloatingScore(t,i,e){this.floatingScores.push({points:t,x:i,y:e,timer:0,duration:1e3})}updateFloatingScores(t){this.floatingScores=this.floatingScores.filter(i=>(i.timer+=t,i.timer<i.duration))}countDirtTiles(){return this.grid.countDirt()}playerHit(t="enemy"){this.player.isInvincible||(this.player.startDeath(t),this.state=m.DYING,this.deathStartTime=Date.now())}updateDeath(t){this.player.update(t,null,this.grid),this.player.isSmooshed&&(this.rocks.forEach(i=>{i.update(t,this.grid,null)}),this.player.attachedToRock&&(this.player.x=this.player.attachedToRock.x,this.player.y=this.player.attachedToRock.y)),this.player.deathTimer>=Z.ANIMATION_DURATION&&(this.scoreManager.loseLife(),this.scoreManager.lives<=0?this.gameOver():this.startRespawn())}startRespawn(){this.state=m.RESPAWNING,this.respawnStartTime=Date.now(),this.player=new N(this.grid),this.player.isInvincible=!0,this.enemies.forEach((t,i)=>{const e=this.levelManager.getEnemySpawnPosition(i);t.x=e.x,t.y=e.y,t.resetTimers(),t.inTunnel=!0,t.state="roaming",t.isLastEnemy=!1,t.isEscaping=!1,t.hasEscaped=!1}),this.rocks.forEach(t=>{t.reset()})}updateRespawn(t){Date.now()-this.respawnStartTime>=Z.RESPAWN_DELAY&&(this.state=m.PLAYING,this.resetAllTimers())}levelComplete(){this.state=m.LEVEL_COMPLETE;const t=this.levelManager.currentLevel+1;this.config.onLevelComplete(t-1),setTimeout(()=>{this.startLevel(t),this.state=m.PLAYING},2e3)}gameOver(){this.state=m.GAME_OVER,this.config.onGameOver(this.scoreManager.score),this.scoreManager.score>this.scoreManager.highScore&&(this.scoreManager.highScore=this.scoreManager.score,this.scoreManager.saveHighScore())}pause(){this.state=m.PAUSED}resume(){this.state=m.PLAYING}render(){this.renderer.clear(),this.renderer.drawGrid(this.grid,this.levelManager.currentLevel),this.rocks.forEach(t=>{this.renderer.drawRock(t)}),this.bonusItems.forEach(t=>{this.renderer.drawBonusItem(t,this.levelManager.currentLevel)}),this.player&&this.renderer.drawPlayer(this.player),this.enemies.forEach(t=>{this.renderer.drawEnemy(t)}),this.renderer.drawFloatingScores(this.floatingScores),this.renderer.drawUI(this.scoreManager,this.levelManager),this.config.debug&&this.renderer.drawDebugInfo(this.player,this.enemies)}renderPaused(){if(this.inputManager.isKeyPressed("Escape")){this.resume();return}this.render(),this.renderer.drawText("PAUSED",432/2,288/2,{size:16,color:_.TEXT_WHITE,align:"center"})}renderRespawning(){this.render(),this.renderer.renderRespawning()}renderLevelComplete(){this.render(),this.renderer.drawText(`LEVEL ${this.levelManager.currentLevel} `,432/2,288/2-10,{size:12,color:_.TEXT_WHITE,align:"center"}),this.renderer.drawText("COMPLETE",432/2,288/2+10,{size:12,color:_.TEXT_WHITE,align:"center"})}renderGameOver(){if(this.renderer.forceClear(),this.renderer.drawText("GAME OVER",432/2,288/2-40,{size:12,color:_.TEXT_RED,align:"center"}),this.renderer.drawText("SCORE",432/2,288/2,{size:8,color:_.TEXT_WHITE,align:"center"}),this.renderer.drawText(`${this.scoreManager.score}`,432/2,288/2+20,{size:10,color:_.TEXT_RED,align:"center"}),this.renderer.drawText("PRESS SPACE",432/2,288/2+50,{size:6,color:_.TEXT_WHITE,align:"center"}),this.renderer.drawText("TO RESTART",432/2,288/2+65,{size:6,color:_.TEXT_WHITE,align:"center"}),!this.restartListenerAdded){this.restartListenerAdded=!0;const t=i=>{i.code==="Space"&&this.state===m.GAME_OVER&&(document.removeEventListener("keydown",t),this.restartListenerAdded=!1,this.startGame())};document.addEventListener("keydown",t)}}start(){this.init()}stop(){this.animationFrameId&&(cancelAnimationFrame(this.animationFrameId),this.animationFrameId=null),this.inputManager.destroy()}}if(typeof window<"u"){const L=document.getElementById("game");if(L){const t=new Y({container:L,scale:window.devicePixelRatio,debug:!1,onGameOver:i=>{},onLevelComplete:i=>{},onScoreChange:i=>{}});t.start(),window.digdugGame=t}}A.Game=Y,A.default=Y,Object.defineProperties(A,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}})});
2
+ //# sourceMappingURL=digdug.umd.js.map