Better code readability
authorSvjatoslav Agejenko <svjatoslav@svjatoslav.eu>
Sat, 16 Aug 2025 11:45:19 +0000 (14:45 +0300)
committerSvjatoslav Agejenko <svjatoslav@svjatoslav.eu>
Sat, 16 Aug 2025 11:45:19 +0000 (14:45 +0300)
Games/Pomppu Paavo/Pomppu Paavo.bas

index 7d86bf4..91a1657 100755 (executable)
@@ -1,3 +1,5 @@
+DECLARE SUB RenderSpriteFromFile (x%, y%, widthMultiplier%, heightMultiplier%, SpriteName$)\r
+DECLARE SUB RenderFlippedSpriteFromFile (x%, y%, widthMultiplier%, heightMultiplier%, Filename$)\r
 ' Pomppu Paavo 2\r
 '\r
 ' This program is free software: released under Creative Commons Zero (CC0) license\r
 '\r
 ' Changelog:\r
 ' 1999, Initial version\r
+' 2025, Improved program readability\r
 \r
 DECLARE SUB UpdateLoadingScreen ()\r
 DECLARE SUB HandleEscapeKey ()\r
 DECLARE SUB PlayHurtSound ()\r
 DECLARE SUB GameOverSequence ()\r
 \r
-\r
 DECLARE SUB HandlePlayerDeath ()\r
 DEFINT A-Z\r
 DECLARE SUB InitializeAllLevelData ()\r
-DECLARE SUB UpdateHUD (zaz%)\r
-DECLARE SUB RenderImageFromTextFile (a1%, b1%, c1%, d1%, a$)\r
+DECLARE SUB UpdateHUD (coinIncrementAmount%)\r
 DECLARE SUB LoadCurrentLevel ()\r
-DECLARE SUB wiew (a1%, b1%, c1%, d1%, a$)\r
-DECLARE SUB intro ()\r
-DECLARE SUB inpur ()\r
+DECLARE SUB ShowIntroScreen ()\r
+DECLARE SUB WaitForUserInput ()\r
 \r
 DIM SHARED userInput$\r
 \r
+' Grid representing solid level elements (m = block, o = breakable, etc.)\r
 DIM SHARED levelGrid(-5 TO 20, -5 TO 20) AS STRING\r
-DIM SHARED ruum1(-5 TO 20, -5 TO 20) AS STRING\r
+\r
+' Tracks interactive objects like breakable blocks separately from main grid\r
+DIM SHARED interactiveObjectsGrid(-5 TO 20, -5 TO 20) AS STRING\r
+\r
+' Stores raw text-based level layouts for all worlds\r
 DIM SHARED levelData(1 TO 11, 1 TO 10) AS STRING * 15\r
+\r
+' Background color index for each world's sky\r
 DIM SHARED levelSkyColor(1 TO 10) AS INTEGER\r
-DIM SHARED currentWorld AS INTEGER\r
-DIM SHARED previousWorld AS INTEGER\r
+\r
+' Current active level number (1-10)\r
+DIM SHARED currentLevelNumber AS INTEGER\r
+\r
+' Previously played level number (for backtracking after death)\r
+DIM SHARED previousLevelNumber AS INTEGER\r
+\r
+' Temporary storage for current level's row data during loading\r
 DIM SHARED levelRowData(1 TO 15) AS STRING * 15\r
-DIM SHARED pilv(2100)\r
-DIM SHARED kast(202)\r
-DIM SHARED tellis(202)\r
-DIM SHARED poosas(1000)\r
-DIM SHARED puu(2000)\r
-DIM SHARED tuhi(202)\r
-DIM SHARED munt(202)\r
-DIM SHARED munt1(400)\r
-DIM SHARED munt2(200)\r
-DIM SHARED mari0(402)\r
-DIM SHARED mari(202, 1 TO 5)\r
-DIM SHARED koll(1 TO 230, 1 TO 10)\r
-DIM SHARED koll1(1 TO 202, 1 TO 5)\r
-DIM SHARED mobX(1 TO 10)\r
-DIM SHARED mobY(1 TO 10)\r
-DIM SHARED kollal(1 TO 10)\r
-DIM SHARED kolled(1 TO 10)\r
-\r
-DIM SHARED hudCoinDigits(1 TO 5)\r
+\r
+' Buffer to store cloud sprite image data\r
+DIM SHARED cloudSpriteBuffer(2100)\r
+\r
+' Buffer for solid block sprite images\r
+DIM SHARED solidBlockSpriteBuffer(202)\r
+\r
+' Buffer for brick/block sprite images\r
+DIM SHARED brickSpriteBuffer(202)\r
+\r
+' Buffer for power-up item sprites (like mushrooms)\r
+DIM SHARED powerUpSpriteBuffer(1000)\r
+\r
+' Buffer for tree sprite images\r
+DIM SHARED treeSpriteBuffer(2000)\r
+\r
+' Buffer for empty space sprite (used when clearing coins/breakables)\r
+DIM SHARED emptySpaceSpriteBuffer(202)\r
+\r
+' Main coin sprite buffer\r
+DIM SHARED coinSpriteBuffer(202)\r
+\r
+' Larger coin variant sprite buffer\r
+DIM SHARED largeCoinSpriteBuffer(400)\r
+\r
+' Smaller coin variant sprite buffer\r
+DIM SHARED smallCoinSpriteBuffer(200)\r
+\r
+' Player character animation frames (base + walking variants)\r
+DIM SHARED playerAnimationFrames(402)\r
+\r
+' Primary player sprite animation frames array\r
+DIM SHARED playerWalkingFrames(202, 1 TO 5)\r
+\r
+' Enemy base sprite buffers (stores background under enemies for erasing)\r
+DIM SHARED enemyBackgroundBuffers(1 TO 230, 1 TO 10)\r
+\r
+' Enemy walking animation frames\r
+DIM SHARED enemyWalkingFrames(1 TO 202, 1 TO 5)\r
+\r
+' X positions of all enemies (max 10 per level)\r
+DIM SHARED enemyXPositions(1 TO 10)\r
+\r
+' Y positions of all enemies\r
+DIM SHARED enemyYPositions(1 TO 10)\r
+\r
+' Vertical movement speeds for enemies (positive = down)\r
+DIM SHARED enemyVerticalSpeeds(1 TO 10)\r
+\r
+' Horizontal movement speeds for enemies (positive = right)\r
+DIM SHARED enemyHorizontalSpeeds(1 TO 10)\r
+\r
+' Array storing individual digits of coin counter (index 1=ones, 2=tens)\r
+DIM SHARED CoinDigits(1 TO 5)\r
+\r
+' Pre-loaded digit images for HUD display (0-9)\r
 DIM SHARED digitImages(100, 0 TO 11)\r
+\r
+' Number of remaining player lives\r
 DIM SHARED lives\r
 \r
-DIM SHARED raha\r
-DIM SHARED clra, clrb\r
-DIM SHARED a1, b1\r
+' Total coins collected by player\r
+DIM SHARED coinsCollected\r
+\r
+' Flag: set when a coin needs to be cleared from grid\r
+DIM SHARED shouldClearCoinFlag\r
+\r
+' Grid X position where coin needs clearing\r
+DIM SHARED clearCoinGridX\r
 \r
-DIM SHARED prog\r
-prog = 1\r
+' Grid Y position where coin needs clearing\r
+DIM SHARED clearCoinGridY\r
+\r
+' Player's current X coordinate on screen\r
+DIM SHARED playerX\r
+\r
+' Player's current Y coordinate on screen\r
+DIM SHARED playerY\r
+\r
+' Counter tracking loading progress dots\r
+DIM SHARED loadingProgressDotCount\r
+\r
+loadingProgressDotCount = 1\r
 SCREEN 13\r
-currentWorld = 1\r
-previousWorld = 1\r
+currentLevelNumber = 1\r
+previousLevelNumber = 1\r
 InitializeAllLevelData\r
 1\r
-zpqf = 4\r
 \r
-FOR a = 0 TO 254\r
-OUT &H3C8, a\r
+' Reset entire VGA palette to black (0-254)\r
+FOR colorIndex = 0 TO 254\r
+OUT &H3C8, colorIndex\r
 OUT &H3C9, 0\r
 OUT &H3C9, 0\r
 OUT &H3C9, 0\r
-NEXT a\r
+NEXT colorIndex\r
+\r
+' Set color 255 to bright white (60/63 intensity)\r
 OUT &H3C8, 255\r
 OUT &H3C9, 60\r
 OUT &H3C9, 60\r
@@ -82,244 +152,366 @@ LOCATE 20, 3
 COLOR 255\r
 PRINT "LOADING "\r
 \r
-\r
+' Load all game assets sequentially with visual feedback\r
 UpdateLoadingScreen\r
-wiew 0, 0, 1, 1, "pilv"\r
-GET (1, 1)-(109, 35), pilv\r
+RenderSpriteFromFile 0, 0, 1, 1, "pilv"\r
+GET (1, 1)-(109, 35), cloudSpriteBuffer\r
+\r
 UpdateLoadingScreen\r
-wiew 0, 0, 1, 1, "kast"\r
-GET (1, 2)-(20, 21), kast\r
+RenderSpriteFromFile 0, 0, 1, 1, "kast"\r
+GET (1, 2)-(20, 21), solidBlockSpriteBuffer\r
+\r
 UpdateLoadingScreen\r
-wiew 0, 0, 1, 1, "tellis"\r
-GET (1, 2)-(20, 21), tellis\r
+RenderSpriteFromFile 0, 0, 1, 1, "tellis"\r
+GET (1, 2)-(20, 21), brickSpriteBuffer\r
+\r
 UpdateLoadingScreen\r
-GET (1, 2)-(20, 21), tuhi\r
-wiew 0, 0, 1, 1, "paavo1"\r
-GET (1, 2)-(20, 21), mari(202, 1)\r
+GET (1, 2)-(20, 21), emptySpaceSpriteBuffer\r
+\r
+RenderSpriteFromFile 0, 0, 1, 1, "paavo1"\r
+GET (1, 2)-(20, 21), playerWalkingFrames(202, 1)\r
+\r
 UpdateLoadingScreen\r
-RenderImageFromTextFile 0, 0, 1, 1, "paavo1"\r
-GET (3, 2)-(22, 21), mari(202, 2)\r
+RenderFlippedSpriteFromFile 0, 0, 1, 1, "paavo1"\r
+GET (3, 2)-(22, 21), playerWalkingFrames(202, 2)\r
+\r
 UpdateLoadingScreen\r
-wiew 0, 0, 1, 1, "paavo2"\r
-GET (1, 2)-(20, 21), mari(202, 3)\r
+RenderSpriteFromFile 0, 0, 1, 1, "paavo2"\r
+GET (1, 2)-(20, 21), playerWalkingFrames(202, 3)\r
+\r
 UpdateLoadingScreen\r
-RenderImageFromTextFile 0, 0, 1, 1, "paavo2"\r
-GET (3, 2)-(22, 21), mari(202, 4)\r
+RenderFlippedSpriteFromFile 0, 0, 1, 1, "paavo2"\r
+GET (3, 2)-(22, 21), playerWalkingFrames(202, 4)\r
+\r
 UpdateLoadingScreen\r
-wiew 0, 0, 1, 1, "poosas"\r
-GET (1, 1)-(60, 21), poosas\r
+RenderSpriteFromFile 0, 0, 1, 1, "poosas"\r
+GET (1, 1)-(60, 21), powerUpSpriteBuffer\r
+\r
 UpdateLoadingScreen\r
-wiew 0, 0, 1, 1, "puu"\r
-GET (1, 1)-(40, 60), puu\r
+RenderSpriteFromFile 0, 0, 1, 1, "puu"\r
+GET (1, 1)-(40, 60), treeSpriteBuffer\r
+\r
 UpdateLoadingScreen\r
-wiew 0, 0, 1, 1, "munt"\r
-GET (1, 1)-(10, 11), munt\r
+RenderSpriteFromFile 0, 0, 1, 1, "munt"\r
+GET (1, 1)-(10, 11), coinSpriteBuffer\r
+\r
 UpdateLoadingScreen\r
-wiew 0, 0, 1, 1, "munt1"\r
-GET (0, 2)-(20, 11), munt1\r
+RenderSpriteFromFile 0, 0, 1, 1, "munt1"\r
+GET (0, 2)-(20, 11), largeCoinSpriteBuffer\r
+\r
 UpdateLoadingScreen\r
-wiew 0, 0, 1, 1, "munt2"\r
-GET (0, 2)-(20, 11), munt2\r
+RenderSpriteFromFile 0, 0, 1, 1, "munt2"\r
+GET (0, 2)-(20, 11), smallCoinSpriteBuffer\r
 \r
+' Load all numeric digit sprites for HUD display\r
 UpdateLoadingScreen\r
-wiew 0, 0, 1, 1, "0"\r
+RenderSpriteFromFile 0, 0, 1, 1, "0"\r
 GET (0, 2)-(10, 11), digitImages(100, 0)\r
+\r
 UpdateLoadingScreen\r
-wiew 0, 0, 1, 1, "1"\r
+RenderSpriteFromFile 0, 0, 1, 1, "1"\r
 GET (0, 2)-(10, 11), digitImages(100, 1)\r
+\r
 UpdateLoadingScreen\r
-wiew 0, 0, 1, 1, "2"\r
+RenderSpriteFromFile 0, 0, 1, 1, "2"\r
 GET (0, 2)-(10, 11), digitImages(100, 2)\r
+\r
 UpdateLoadingScreen\r
-wiew 0, 0, 1, 1, "3"\r
+RenderSpriteFromFile 0, 0, 1, 1, "3"\r
 GET (0, 2)-(10, 11), digitImages(100, 3)\r
+\r
 UpdateLoadingScreen\r
-wiew 0, 0, 1, 1, "4"\r
+RenderSpriteFromFile 0, 0, 1, 1, "4"\r
 GET (0, 2)-(10, 11), digitImages(100, 4)\r
+\r
 UpdateLoadingScreen\r
-wiew 0, 0, 1, 1, "5"\r
+RenderSpriteFromFile 0, 0, 1, 1, "5"\r
 GET (0, 2)-(10, 11), digitImages(100, 5)\r
+\r
 UpdateLoadingScreen\r
-wiew 0, 0, 1, 1, "6"\r
+RenderSpriteFromFile 0, 0, 1, 1, "6"\r
 GET (0, 2)-(10, 11), digitImages(100, 6)\r
+\r
 UpdateLoadingScreen\r
-wiew 0, 0, 1, 1, "7"\r
+RenderSpriteFromFile 0, 0, 1, 1, "7"\r
 GET (0, 2)-(10, 11), digitImages(100, 7)\r
+\r
 UpdateLoadingScreen\r
-wiew 0, 0, 1, 1, "8"\r
+RenderSpriteFromFile 0, 0, 1, 1, "8"\r
 GET (0, 2)-(10, 11), digitImages(100, 8)\r
+\r
 UpdateLoadingScreen\r
 GET (0, 2)-(10, 11), digitImages(100, 10)\r
-wiew 0, 0, 1, 1, "9"\r
+RenderSpriteFromFile 0, 0, 1, 1, "9"\r
 GET (0, 2)-(10, 11), digitImages(100, 9)\r
 \r
+' Load enemy sprite frames\r
 UpdateLoadingScreen\r
-wiew 0, 0, 1, 1, "tigu"\r
-GET (1, 2)-(20, 21), koll1(202, 1)\r
+RenderSpriteFromFile 0, 0, 1, 1, "tigu"\r
+GET (1, 2)-(20, 21), enemyWalkingFrames(202, 1)\r
+\r
 UpdateLoadingScreen\r
-wiew 0, 0, 1, 1, "tigu1"\r
-GET (3, 2)-(22, 21), koll1(202, 2)\r
+RenderSpriteFromFile 0, 0, 1, 1, "tigu1"\r
+GET (3, 2)-(22, 21), enemyWalkingFrames(202, 2)\r
+\r
 UpdateLoadingScreen\r
-RenderImageFromTextFile 0, 0, 1, 1, "tigu"\r
-GET (1, 2)-(20, 21), koll1(202, 3)\r
+RenderFlippedSpriteFromFile 0, 0, 1, 1, "tigu"\r
+GET (1, 2)-(20, 21), enemyWalkingFrames(202, 3)\r
+\r
 UpdateLoadingScreen\r
-RenderImageFromTextFile 0, 0, 1, 1, "tigu1"\r
-GET (3, 2)-(22, 21), koll1(202, 4)\r
+RenderFlippedSpriteFromFile 0, 0, 1, 1, "tigu1"\r
+GET (3, 2)-(22, 21), enemyWalkingFrames(202, 4)\r
 \r
 SCREEN 0\r
 SCREEN 13\r
 LoadCurrentLevel\r
-a1 = 50\r
-b1 = 50\r
-edasi = 0\r
-liig = 1\r
-ov1 = 1\r
-ov2 = 2\r
-raha = 0\r
+playerX = 50\r
+playerY = 50\r
+horizontalMovementSpeed = 0\r
+currentWalkFrameIndex = 1\r
+leftWalkFrameIndex = 1\r
+rightWalkFrameIndex = 2\r
+coinsCollected = 0\r
 lives = 3\r
-z = 1\r
+animationFrameCounter = 1\r
 UpdateHUD 0\r
 12\r
-IF b1 > 0 THEN GET (a1, b1)-(a1 + 20, b1 + 20), mari0: PUT (a1, b1), mari(202, liig), OR\r
-\r
-FOR ox = 1 TO 10\r
-IF mobY(ox) < 170 AND z = 1 THEN\r
-  mobY(ox) = mobY(ox) + kollal(ox)\r
-  mobX(ox) = mobX(ox) + kolled(ox)\r
-  GET (mobX(ox), mobY(ox))-(mobX(ox) + 20, mobY(ox) + 20), koll(202, ox)\r
-  IF kolled(ox) <= 0 THEN kolll = 1 ELSE kolll = 3\r
-  IF zz > 2 THEN kolll = kolll + 1: IF zz = 3 THEN kollal(ox) = kollal(ox) + 1\r
-  PUT (mobX(ox), mobY(ox)), koll1(202, kolll)\r
-END IF\r
-NEXT ox\r
+' Save current player position background before drawing character\r
+IF playerY > 0 THEN GET (playerX, playerY)-(playerX + 20, playerY + 20), playerAnimationFrames: PUT (playerX, playerY), playerWalkingFrames(202, currentWalkFrameIndex), OR\r
+\r
+' Process all enemies (max 10)\r
+FOR enemyIndex = 1 TO 10\r
+    ' Only update visible enemies above bottom of screen\r
+    IF enemyYPositions(enemyIndex) < 170 AND animationFrameCounter = 1 THEN\r
+        ' Apply vertical and horizontal movement\r
+        enemyYPositions(enemyIndex) = enemyYPositions(enemyIndex) + enemyVerticalSpeeds(enemyIndex)\r
+        enemyXPositions(enemyIndex) = enemyXPositions(enemyIndex) + enemyHorizontalSpeeds(enemyIndex)\r
+        ' Save background under enemy for later erasing\r
+        GET (enemyXPositions(enemyIndex), enemyYPositions(enemyIndex))-(enemyXPositions(enemyIndex) + 20, enemyYPositions(enemyIndex) + 20), enemyBackgroundBuffers(202, enemyIndex)\r
+\r
+        ' Determine which walking animation frame to show\r
+        IF enemyHorizontalSpeeds(enemyIndex) <= 0 THEN walkAnimationPhase = 1 ELSE walkAnimationPhase = 3\r
+        IF enemyAnimationFrameCounter > 2 THEN walkAnimationPhase = walkAnimationPhase + 1: IF enemyAnimationFrameCounter = 3 THEN enemyVerticalSpeeds(enemyIndex) = enemyVerticalSpeeds(enemyIndex) + 1\r
+\r
+        ' Draw enemy with correct animation frame\r
+        PUT (enemyXPositions(enemyIndex), enemyYPositions(enemyIndex)), enemyWalkingFrames(202, walkAnimationPhase)\r
+    END IF\r
+NEXT enemyIndex\r
+\r
+' Create short delay using silent sound (QBasic lacks proper delay function)\r
 SOUND 0, .5\r
-z = z + 1\r
-IF z > 3 THEN z = 1\r
-IF z = 1 THEN\r
-zz = zz + 1\r
-IF zz > 5 THEN zz = 0\r
-alla = alla + 1\r
-IF edasi > 0 THEN edasi = edasi - 1: zy = zy + 1\r
-IF edasi < 0 THEN edasi = edasi + 1: zy = zy + 1\r
-IF zy > 2 THEN zy = 1\r
-IF zy = 2 THEN ov1 = 1: ov2 = 2\r
-IF zy = 1 THEN ov1 = 3: ov2 = 4\r
-\r
-FOR ox = 1 TO 10\r
-IF mobY(ox) < 170 THEN\r
-IF levelGrid((mobX(ox) + 20) / 20, (mobY(ox) + 9) / 20) = "m" THEN kollal(ox) = -1\r
-IF mobX(ox) > 270 THEN kolled(ox) = -1\r
-IF mobX(ox) < 2 THEN kolled(ox) = 1\r
-IF levelGrid((mobX(ox) + 28) / 20, mobY(ox) / 20) = "m" THEN kolled(ox) = -1\r
-IF levelGrid((mobX(ox) + 10) / 20, mobY(ox) / 20) = "m" THEN kolled(ox) = 1\r
-IF mobX(ox) - 20 < a1 AND mobX(ox) + 20 > a1 AND mobY(ox) - 5 < b1 AND mobY(ox) + 20 > b1 THEN PlayHurtSound: HandlePlayerDeath: GOTO 12\r
-END IF\r
-NEXT ox\r
+\r
+' Cycle through animation frames\r
+animationFrameCounter = animationFrameCounter + 1\r
+IF animationFrameCounter > 3 THEN animationFrameCounter = 1\r
+\r
+' Every third frame, process physics and input\r
+IF animationFrameCounter = 1 THEN\r
+    enemyAnimationFrameCounter = enemyAnimationFrameCounter + 1\r
+    IF enemyAnimationFrameCounter > 5 THEN enemyAnimationFrameCounter = 0\r
+\r
+    ' Apply gravity to player (increases downward speed each frame)\r
+    verticalMovementSpeed = verticalMovementSpeed + 1\r
+\r
+    ' Gradually reduce horizontal movement (friction effect)\r
+    IF horizontalMovementSpeed > 0 THEN horizontalMovementSpeed = horizontalMovementSpeed - 1: walkAnimationPhaseCounter = walkAnimationPhaseCounter + 1\r
+    IF horizontalMovementSpeed < 0 THEN horizontalMovementSpeed = horizontalMovementSpeed + 1: walkAnimationPhaseCounter = walkAnimationPhaseCounter + 1\r
+\r
+    ' Alternate between walk animation phases every 2 frames\r
+    IF walkAnimationPhaseCounter > 2 THEN walkAnimationPhaseCounter = 1\r
+    IF walkAnimationPhaseCounter = 2 THEN leftWalkFrameIndex = 1: rightWalkFrameIndex = 2\r
+    IF walkAnimationPhaseCounter = 1 THEN leftWalkFrameIndex = 3: rightWalkFrameIndex = 4\r
+\r
+    ' Process enemy collisions and movements\r
+    FOR enemyIndex = 1 TO 10\r
+        IF enemyYPositions(enemyIndex) < 170 THEN\r
+            ' Reverse vertical direction when hitting ceiling block\r
+            IF levelGrid((enemyXPositions(enemyIndex) + 20) / 20, (enemyYPositions(enemyIndex) + 9) / 20) = "m" THEN enemyVerticalSpeeds(enemyIndex) = -1\r
+\r
+            ' Reverse horizontal direction at screen edges\r
+            IF enemyXPositions(enemyIndex) > 270 THEN enemyHorizontalSpeeds(enemyIndex) = -1\r
+            IF enemyXPositions(enemyIndex) < 2 THEN enemyHorizontalSpeeds(enemyIndex) = 1\r
+\r
+            ' Reverse horizontal direction when hitting wall blocks\r
+            IF levelGrid((enemyXPositions(enemyIndex) + 28) / 20, enemyYPositions(enemyIndex) / 20) = "m" THEN enemyHorizontalSpeeds(enemyIndex) = -1\r
+            IF levelGrid((enemyXPositions(enemyIndex) + 10) / 20, enemyYPositions(enemyIndex) / 20) = "m" THEN enemyHorizontalSpeeds(enemyIndex) = 1\r
+\r
+            ' Check for collision with player (trigger death)\r
+            IF enemyXPositions(enemyIndex) - 20 < playerX AND enemyXPositions(enemyIndex) + 20 > playerX AND enemyYPositions(enemyIndex) - 5 < playerY AND enemyYPositions(enemyIndex) + 20 > playerY THEN PlayHurtSound: HandlePlayerDeath: GOTO 12\r
+        END IF\r
+    NEXT enemyIndex\r
 END IF\r
 \r
-IF levelGrid((a1 + 15) / 20, (b1 + 9) / 20) = "m" THEN alla = -1: ao = 0\r
-IF levelGrid((a1 + 25) / 20, (b1 + 9) / 20) = "m" THEN alla = -1: ao = 0\r
-IF levelGrid((a1 + 20) / 20, (b1 - 8) / 20) = "m" THEN alla = 1: ao = 20\r
-IF levelGrid((a1 + 28) / 20, (b1) / 20) = "m" THEN edasi = -1: qa = 1\r
-IF levelGrid((a1 + 10) / 20, (b1) / 20) = "m" THEN edasi = 1: qa = 1\r
-\r
-IF ruum1((a1 + 20) / 20, (b1 - 8) / 20) = "o" THEN alla = 1: ruum1((a1 + 20) / 20, (b1 - 8) / 20) = "": levelGrid((a1 + 20) / 20, (b1 - 8) / 20) = "2": clra = ((a1 + 20) / 20) - 1: clrb = (b1 - 8) / 20: clr = 1:  SOUND 50, .5\r
-IF levelGrid((a1 + 20) / 20, (b1) / 20) = "1" THEN levelGrid((a1 + 20) / 20, (b1) / 20) = "2": clra = ((a1 + 21) / 20) - 1: clrb = (b1) / 20: clr = 1: raha = raha + 1: UpdateHUD 1: SOUND 1000, 1: SOUND 2000, 1\r
-ao = ao + 1\r
-a$ = INKEY$\r
-IF a$ = CHR$(0) + "H" AND ao < 10 THEN alla = -6\r
-IF a$ = CHR$(0) + "M" AND qa = 0 THEN edasi = edasi + 3: liig = ov1\r
-IF a$ = CHR$(0) + "K" AND qa = 0 THEN edasi = edasi - 3: liig = ov2\r
-IF a$ = CHR$(27) THEN HandleEscapeKey\r
-IF a$ = "+" AND qa = 0 THEN currentWorld = currentWorld + 1: LoadCurrentLevel: GOTO 12\r
-IF qa <> 0 THEN qa = 0\r
-IF edasi > 5 THEN edasi = 3\r
-IF edasi < -5 THEN edasi = -3\r
-IF alla > 3 THEN alla = 3\r
-\r
-IF b1 > 0 THEN PUT (a1, b1), mari0, PSET\r
-\r
-IF z = 1 THEN\r
-FOR ox = 10 TO 1 STEP -1\r
-IF mobY(ox) < 170 THEN PUT (mobX(ox), mobY(ox)), koll(202, ox), PSET\r
-NEXT ox\r
+' Check for player collisions with level geometry:\r
+\r
+' Ceiling collision (reverse gravity)\r
+IF levelGrid((playerX + 15) / 20, (playerY + 9) / 20) = "m" THEN verticalMovementSpeed = -1: airTimeCounter = 0\r
+\r
+' Right wall collision\r
+IF levelGrid((playerX + 25) / 20, (playerY + 9) / 20) = "m" THEN verticalMovementSpeed = -1: airTimeCounter = 0\r
+\r
+' Floor collision (stop falling)\r
+IF levelGrid((playerX + 20) / 20, (playerY - 8) / 20) = "m" THEN verticalMovementSpeed = 1: airTimeCounter = 20\r
+\r
+' Right wall collision\r
+IF levelGrid((playerX + 28) / 20, (playerY) / 20) = "m" THEN horizontalMovementSpeed = -1: wallCollisionLock = 1\r
+\r
+' Left wall collision\r
+IF levelGrid((playerX + 10) / 20, (playerY) / 20) = "m" THEN horizontalMovementSpeed = 1: wallCollisionLock = 1\r
+\r
+' Breakable block collision (turn into empty space)\r
+IF interactiveObjectsGrid((playerX + 20) / 20, (playerY - 8) / 20) = "o" THEN verticalMovementSpeed = 1: interactiveObjectsGrid((playerX + 20) / 20, (playerY - 8) / 20) = "": levelGrid((playerX + 20) / 20, (playerY - 8) / 20) = "2": clearCoinGridX  _\r
+= ((playerX + 20) / 20) - 1: clearCoinGridY = (playerY - 8) / 20: shouldClearCoinFlag = 1:                                                                                                                    SOUND 50, .5\r
+\r
+' Coin collection\r
+IF levelGrid((playerX + 20) / 20, (playerY) / 20) = "1" THEN levelGrid((playerX + 20) / 20, (playerY) / 20) = "2": clearCoinGridX = ((playerX + 21) / 20) - 1: clearCoinGridY = (playerY) / 20: shouldClearCoinFlag = 1: coinsCollected = coinsCollected  _\r
++ 1: UpdateHUD 1: SOUND 1000, 1: SOUND 2000, 1\r
+\r
+' Track time in air for jump control\r
+airTimeCounter = airTimeCounter + 1\r
+\r
+' Process keyboard input:\r
+userInput$ = INKEY$\r
+' Jump when up arrow pressed (only if not already high in air)\r
+IF userInput$ = CHR$(0) + "H" AND airTimeCounter < 10 THEN verticalMovementSpeed = -6\r
+' Move right with right arrow\r
+IF userInput$ = CHR$(0) + "M" AND wallCollisionLock = 0 THEN horizontalMovementSpeed = horizontalMovementSpeed + 3: currentWalkFrameIndex = leftWalkFrameIndex\r
+' Move left with left arrow\r
+IF userInput$ = CHR$(0) + "K" AND wallCollisionLock = 0 THEN horizontalMovementSpeed = horizontalMovementSpeed - 3: currentWalkFrameIndex = rightWalkFrameIndex\r
+' Escape key handler\r
+IF userInput$ = CHR$(27) THEN HandleEscapeKey\r
+' Level skip (debug only - plus key)\r
+IF userInput$ = "+" AND wallCollisionLock = 0 THEN currentLevelNumber = currentLevelNumber + 1: LoadCurrentLevel: GOTO 12\r
+' Reset wall collision lock each frame\r
+IF wallCollisionLock <> 0 THEN wallCollisionLock = 0\r
+\r
+' Cap movement speeds to prevent excessive speed\r
+IF horizontalMovementSpeed > 5 THEN horizontalMovementSpeed = 3\r
+IF horizontalMovementSpeed < -5 THEN horizontalMovementSpeed = -3\r
+IF verticalMovementSpeed > 3 THEN verticalMovementSpeed = 3\r
+\r
+' Restore background where player was previously drawn\r
+IF playerY > 0 THEN PUT (playerX, playerY), playerAnimationFrames, PSET\r
+\r
+' Redraw enemies on this animation frame\r
+IF animationFrameCounter = 1 THEN\r
+    FOR enemyIndex = 10 TO 1 STEP -1\r
+        IF enemyYPositions(enemyIndex) < 170 THEN PUT (enemyXPositions(enemyIndex), enemyYPositions(enemyIndex)), enemyBackgroundBuffers(202, enemyIndex), PSET\r
+    NEXT enemyIndex\r
 END IF\r
 \r
+' Apply physics to player position\r
+playerY = playerY + verticalMovementSpeed\r
+playerX = playerX + horizontalMovementSpeed\r
+\r
+' Clear collected coin/block from screen\r
+IF shouldClearCoinFlag > 0 THEN shouldClearCoinFlag = 0: PUT (clearCoinGridX * 20, clearCoinGridY * 20), emptySpaceSpriteBuffer, PSET\r
 \r
-b1 = b1 + alla\r
-a1 = a1 + edasi\r
-IF clr > 0 THEN clr = 0: PUT (clra * 20, clrb * 20), tuhi, PSET\r
-IF a1 > 280 THEN currentWorld = currentWorld + 1: LoadCurrentLevel: a1 = 3\r
-IF a1 < 2 THEN currentWorld = currentWorld - 1: LoadCurrentLevel: a1 = 279\r
-IF b1 > 170 THEN FOR a = 3000 TO 500 STEP -100: SOUND a, .3: NEXT a: HandlePlayerDeath\r
+' Level transition when reaching screen edges\r
+IF playerX > 280 THEN currentLevelNumber = currentLevelNumber + 1: LoadCurrentLevel: playerX = 3\r
+IF playerX < 2 THEN currentLevelNumber = currentLevelNumber - 1: LoadCurrentLevel: playerX = 279\r
+\r
+' Player death when falling off bottom of screen\r
+IF playerY > 170 THEN FOR tone = 3000 TO 500 STEP -100: SOUND tone, .3: NEXT tone: HandlePlayerDeath\r
 GOTO 12\r
 \r
 SUB GameOverSequence\r
-DIM diep(1 TO 2000)\r
-GET (0, 0)-(150, 20), diep\r
+' Shows game over screen with animated death effect.\r
+' First displays "You are killed!" text, then pixelates the screen,\r
+' adds flying debris animation, waits for keypress, then fades to black.\r
+\r
+DIM deathScreenBuffer(1 TO 2000)\r
+GET (0, 0)-(150, 20), deathScreenBuffer\r
 LOCATE 1, 1\r
 PRINT "You are    "\r
 LOCATE 2, 1\r
 PRINT " killed!   "\r
 \r
+' Create pixelated death effect by scaling up screen area\r
 FOR x = 0 TO 80\r
-FOR y = 0 TO 16\r
-IF POINT(x, y) > 0 THEN LINE (x * 5, y * 5 + 50)-(x * 5 + 4, y * 5 + 54), 4, BF\r
-NEXT y\r
+    FOR y = 0 TO 16\r
+        ' Only process non-background pixels\r
+        IF POINT(x, y) > 0 THEN\r
+            ' Draw 5x5 block for each original pixel (magnification effect)\r
+            LINE (x * 5, y * 5 + 50)-(x * 5 + 4, y * 5 + 54), 4, BF\r
+        END IF\r
+    NEXT y\r
 NEXT x\r
-PUT (0, 0), diep, PSET\r
-\r
-FOR a = 1 TO 100\r
-x = RND * 290 + 4\r
-y = RND * 170 + 4\r
-GET (x, y)-(x + 20, y + 20), diep\r
-x = x + RND * 4 - 2\r
-y = y + RND * 4 - 1\r
-PUT (x, y), diep, PSET\r
-NEXT a\r
-FOR a = 1 TO 50\r
-a$ = INKEY$\r
-NEXT a\r
-a$ = INPUT$(1)\r
-\r
-FOR a = 0 TO 100\r
-SOUND 0, .05\r
-LINE (0, a)-(320, a), 4\r
-LINE (0, 200 - a)-(320, 200 - a), 4\r
-NEXT a\r
-FOR a = 32 TO 0 STEP -1\r
-SOUND 0, .5\r
-OUT &H3C8, 4\r
-OUT &H3C9, a\r
-OUT &H3C9, 0\r
-OUT &H3C9, 0\r
-NEXT a\r
+PUT (0, 0), deathScreenBuffer, PSET\r
+\r
+' Add random flying debris particles\r
+FOR particle = 1 TO 100\r
+    x = RND * 290 + 4\r
+    y = RND * 170 + 4\r
+    GET (x, y)-(x + 20, y + 20), deathScreenBuffer\r
+    x = x + RND * 4 - 2\r
+    y = y + RND * 4 - 1\r
+    PUT (x, y), deathScreenBuffer, PSET\r
+NEXT particle\r
+\r
+' Wait briefly before requiring keypress\r
+FOR waitCount = 1 TO 50\r
+    userInput$ = INKEY$\r
+NEXT waitCount\r
+userInput$ = INPUT$(1)\r
+\r
+' Draw closing red lines from top and bottom\r
+FOR lineIndex = 0 TO 10\r
+    SOUND 0, .05\r
+    LINE (0, lineIndex)-(320, lineIndex), 4\r
+    LINE (0, 200 - lineIndex)-(320, 200 - lineIndex), 4\r
+NEXT lineIndex\r
+\r
+' Fade out red color channel to black\r
+FOR fadeStep = 32 TO 0 STEP -1\r
+    SOUND 0, .5\r
+    OUT &H3C8, 4\r
+    OUT &H3C9, fadeStep\r
+    OUT &H3C9, 0\r
+    OUT &H3C9, 0\r
+NEXT fadeStep\r
 END\r
 \r
 END SUB\r
 \r
 SUB HandleEscapeKey\r
-FOR b = 0 TO 20\r
-FOR a = b TO 200 STEP 20\r
-LINE (0, a)-(320, a), 0\r
-NEXT a\r
-SOUND 0, .5\r
-NEXT b\r
+' Handles ESC key press: performs smooth screen fadeout then exits to DOS.\r
+\r
+' Fade screen to black in vertical bands\r
+FOR band = 0 TO 20\r
+    FOR lineIndex = band TO 200 STEP 20\r
+        LINE (0, lineIndex)-(320, lineIndex), 0\r
+    NEXT lineIndex\r
+    SOUND 0, .5\r
+NEXT band\r
 SYSTEM\r
 \r
 END SUB\r
 \r
 SUB HandlePlayerDeath\r
-IF currentWorld > 1 THEN currentWorld = currentWorld - 1\r
+' Processes player death: moves back one level, resets player position,\r
+' decreases remaining lives, and updates HUD display.\r
+' Does not end game - continues playing from previous level.\r
+\r
+IF currentLevelNumber > 1 THEN currentLevelNumber = currentLevelNumber - 1\r
 \r
 LoadCurrentLevel\r
-a1 = 20\r
-b1 = 100\r
+playerX = 20\r
+playerY = 100\r
 lives = lives - 1\r
 UpdateHUD 0\r
 END SUB\r
 \r
 SUB InitializeAllLevelData\r
+' Sets up all level layouts as text-based grids.\r
+' Each character represents a game element:\r
+'   m = solid block\r
+'   o = breakable block\r
+'   $ = coin\r
+'   . = power-up item\r
+'   + = tree/decoration\r
+'   numbers 1-9 = enemy spawn points\r
+\r
 levelSkyColor(1) = 1\r
 levelData(1, 1) = "m              "\r
 levelData(2, 1) = "m  -      -    "\r
@@ -431,145 +623,218 @@ levelData(8, 10) = "m     .   1    "
 levelData(9, 10) = "mmmmmmmmmmm  mm"\r
 END SUB\r
 \r
-SUB inpur\r
-userInput$ = ""\r
-WHILE userInput$ = ""\r
-userInput$ = INKEY$\r
-WEND\r
-END SUB\r
-\r
-SUB intro\r
-CLS\r
-wiew 2, 2, 10, 1, "win.i01"\r
-END SUB\r
-\r
 SUB LoadCurrentLevel\r
-IF currentWorld > 10 THEN\r
-CLS\r
-PRINT "Mission complete!"\r
-PRINT "Game over"\r
-END\r
+' Loads and renders the currently selected level:\r
+' 1. Validates level number (ends game at level 11)\r
+' 2. Copies level data into working arrays\r
+' 3. Resets interactive object grid\r
+' 4. Clears enemy positions\r
+' 5. Renders all level elements based on character codes\r
+\r
+IF currentLevelNumber > 10 THEN\r
+    CLS\r
+    PRINT "Mission complete!"\r
+    PRINT "Game over"\r
+    END\r
 END IF\r
 \r
-FOR a = 1 TO 10\r
-levelRowData(a + 1) = levelData(a, currentWorld)\r
-NEXT a\r
-\r
-FOR a = 1 TO 10\r
-FOR b = 1 TO 15\r
-IF levelGrid(b, a - 2) = "2" THEN MID$(levelData(a, previousWorld), b) = " "\r
-NEXT b\r
-NEXT a\r
-previousWorld = currentWorld\r
-\r
-FOR a = -3 TO 20\r
-FOR b = -3 TO 20\r
-levelGrid(a, b) = ""\r
-ruum1(a, b) = ""\r
-NEXT b\r
-NEXT a\r
-\r
-FOR a = 1 TO 10\r
-mobY(a) = 1000\r
-kolled(a) = 1\r
-kollal(a) = 0\r
-NEXT a\r
+' Copy level rows into temporary storage\r
+FOR rowIndex = 1 TO 10\r
+    levelRowData(rowIndex + 1) = levelData(rowIndex, currentLevelNumber)\r
+NEXT rowIndex\r
+\r
+' Clear breakable blocks from previous level\r
+FOR rowIndex = 1 TO 10\r
+    FOR columnIndex = 1 TO 15\r
+        IF levelGrid(columnIndex, rowIndex - 2) = "2" THEN MID$(levelData(rowIndex, previousLevelNumber), columnIndex) = " "\r
+    NEXT columnIndex\r
+NEXT rowIndex\r
+previousLevelNumber = currentLevelNumber\r
+\r
+' Reset entire level grids to empty\r
+FOR x = -3 TO 20\r
+    FOR y = -3 TO 20\r
+        levelGrid(x, y) = ""\r
+        interactiveObjectsGrid(x, y) = ""\r
+    NEXT y\r
+NEXT x\r
+\r
+' Reset all enemies to off-screen positions\r
+FOR enemyIndex = 1 TO 10\r
+    enemyYPositions(enemyIndex) = 1000\r
+    enemyHorizontalSpeeds(enemyIndex) = 1\r
+    enemyVerticalSpeeds(enemyIndex) = 0\r
+NEXT enemyIndex\r
 \r
+' Set background color and clear screen\r
 CLS\r
-PAINT (1, 1), levelSkyColor(currentWorld)\r
-GET (1, 2)-(20, 21), tuhi\r
-FOR a = 2 TO 10\r
-FOR b = 1 TO 15\r
-c$ = RIGHT$(LEFT$(levelRowData(a), b), 1)\r
-IF c$ = "-" THEN PUT ((b - 1) * 20, (a - 2) * 20), pilv, OR\r
-IF c$ = "." THEN PUT ((b - 1) * 20, (a - 2) * 20), poosas, OR\r
-IF c$ = "+" THEN PUT ((b - 1) * 20, (a - 2) * 20), puu, OR\r
-IF c$ = "$" THEN PUT ((b - 1) * 20, (a - 2) * 20), munt, OR: levelGrid(b, a - 2) = "1"\r
-IF c$ = "m" THEN PUT ((b - 1) * 20, (a - 2) * 20), kast, PSET: levelGrid(b, a - 2) = "m"\r
-IF c$ = "o" THEN PUT ((b - 1) * 20, (a - 2) * 20), tellis, PSET: levelGrid(b, a - 2) = "m": ruum1(b, a - 2) = "o"\r
-IF c$ = " " THEN levelGrid(b, a) = " "\r
-\r
-IF c$ = "1" THEN mobX(1) = (b - 1) * 20: mobY(1) = (a - 2) * 20: GET (mobX(1), mobY(1))-(mobX(1) + 20, mobY(1) + 20), koll(202, 1)\r
-IF c$ = "2" THEN mobX(2) = (b - 1) * 20: mobY(2) = (a - 2) * 20: GET (mobX(2), mobY(2))-(mobX(2) + 20, mobY(2) + 20), koll(202, 2)\r
-IF c$ = "3" THEN mobX(3) = (b - 1) * 20: mobY(3) = (a - 2) * 20: GET (mobX(3), mobY(3))-(mobX(3) + 20, mobY(3) + 20), koll(202, 3)\r
-IF c$ = "4" THEN mobX(4) = (b - 1) * 20: mobY(4) = (a - 2) * 20: GET (mobX(4), mobY(4))-(mobX(4) + 20, mobY(4) + 20), koll(202, 4)\r
-IF c$ = "5" THEN mobX(5) = (b - 1) * 20: mobY(5) = (a - 2) * 20: GET (mobX(5), mobY(5))-(mobX(5) + 20, mobY(5) + 20), koll(202, 5)\r
-IF c$ = "6" THEN mobX(6) = (b - 1) * 20: mobY(6) = (a - 2) * 20: GET (mobX(6), mobY(6))-(mobX(6) + 20, mobY(6) + 20), koll(202, 6)\r
-IF c$ = "7" THEN mobX(7) = (b - 1) * 20: mobY(7) = (a - 2) * 20: GET (mobX(7), mobY(7))-(mobX(7) + 20, mobY(7) + 20), koll(202, 7)\r
-IF c$ = "8" THEN mobX(8) = (b - 1) * 20: mobY(8) = (a - 2) * 20: GET (mobX(8), mobY(8))-(mobX(8) + 20, mobY(8) + 20), koll(202, 8)\r
-IF c$ = "9" THEN mobX(9) = (b - 1) * 20: mobY(9) = (a - 2) * 20: GET (mobX(9), mobY(9))-(mobX(9) + 20, mobY(9) + 20), koll(202, 9)\r
-IF c$ = "0" THEN mobX(10) = (b - 1) * 20: mobY(10) = (a - 2) * 20: GET (mobX(10), mobY(10))-(mobX(10) + 20, mobY(10) + 20), koll(202, 10)\r
-NEXT b\r
-NEXT a\r
+PAINT (1, 1), levelSkyColor(currentLevelNumber)\r
+GET (1, 2)-(20, 21), emptySpaceSpriteBuffer\r
+\r
+' Process each character in level data to render elements\r
+FOR rowIndex = 2 TO 10\r
+    FOR columnIndex = 1 TO 15\r
+        ' Extract single character from level data row\r
+        character$ = RIGHT$(LEFT$(levelRowData(rowIndex), columnIndex), 1)\r
+\r
+        ' Render different elements based on character code\r
+        IF character$ = "-" THEN PUT ((columnIndex - 1) * 20, (rowIndex - 2) * 20), cloudSpriteBuffer, OR\r
+        IF character$ = "." THEN PUT ((columnIndex - 1) * 20, (rowIndex - 2) * 20), powerUpSpriteBuffer, OR\r
+        IF character$ = "+" THEN PUT ((columnIndex - 1) * 20, (rowIndex - 2) * 20), treeSpriteBuffer, OR\r
+        IF character$ = "$" THEN PUT ((columnIndex - 1) * 20, (rowIndex - 2) * 20), coinSpriteBuffer, OR: levelGrid(columnIndex, rowIndex - 2) = "1"\r
+        IF character$ = "m" THEN PUT ((columnIndex - 1) * 20, (rowIndex - 2) * 20), solidBlockSpriteBuffer, PSET: levelGrid(columnIndex, rowIndex - 2) = "m"\r
+        IF character$ = "o" THEN PUT ((columnIndex - 1) * 20, (rowIndex - 2) * 20), brickSpriteBuffer, PSET: levelGrid(columnIndex, rowIndex - 2) = "m": interactiveObjectsGrid(columnIndex, rowIndex - 2) = "o"\r
+        IF character$ = " " THEN levelGrid(columnIndex, rowIndex) = " "\r
+\r
+        ' Place enemies based on numeric character codes (1-9,0)\r
+        IF character$ = "1" THEN enemyXPositions(1) = (columnIndex - 1) * 20: enemyYPositions(1) = (rowIndex - 2) * 20: GET (enemyXPositions(1), enemyYPositions(1))-(enemyXPositions(1) + 20, enemyYPositions(1) + 20), enemyBackgroundBuffers(202, 1)\r
+        IF character$ = "2" THEN enemyXPositions(2) = (columnIndex - 1) * 20: enemyYPositions(2) = (rowIndex - 2) * 20: GET (enemyXPositions(2), enemyYPositions(2))-(enemyXPositions(2) + 20, enemyYPositions(2) + 20), enemyBackgroundBuffers(202, 2)\r
+        IF character$ = "3" THEN enemyXPositions(3) = (columnIndex - 1) * 20: enemyYPositions(3) = (rowIndex - 2) * 20: GET (enemyXPositions(3), enemyYPositions(3))-(enemyXPositions(3) + 20, enemyYPositions(3) + 20), enemyBackgroundBuffers(202, 3)\r
+        IF character$ = "4" THEN enemyXPositions(4) = (columnIndex - 1) * 20: enemyYPositions(4) = (rowIndex - 2) * 20: GET (enemyXPositions(4), enemyYPositions(4))-(enemyXPositions(4) + 20, enemyYPositions(4) + 20), enemyBackgroundBuffers(202, 4)\r
+        IF character$ = "5" THEN enemyXPositions(5) = (columnIndex - 1) * 20: enemyYPositions(5) = (rowIndex - 2) * 20: GET (enemyXPositions(5), enemyYPositions(5))-(enemyXPositions(5) + 20, enemyYPositions(5) + 20), enemyBackgroundBuffers(202, 5)\r
+        IF character$ = "6" THEN enemyXPositions(6) = (columnIndex - 1) * 20: enemyYPositions(6) = (rowIndex - 2) * 20: GET (enemyXPositions(6), enemyYPositions(6))-(enemyXPositions(6) + 20, enemyYPositions(6) + 20), enemyBackgroundBuffers(202, 6)\r
+        IF character$ = "7" THEN enemyXPositions(7) = (columnIndex - 1) * 20: enemyYPositions(7) = (rowIndex - 2) * 20: GET (enemyXPositions(7), enemyYPositions(7))-(enemyXPositions(7) + 20, enemyYPositions(7) + 20), enemyBackgroundBuffers(202, 7)\r
+        IF character$ = "8" THEN enemyXPositions(8) = (columnIndex - 1) * 20: enemyYPositions(8) = (rowIndex - 2) * 20: GET (enemyXPositions(8), enemyYPositions(8))-(enemyXPositions(8) + 20, enemyYPositions(8) + 20), enemyBackgroundBuffers(202, 8)\r
+        IF character$ = "9" THEN enemyXPositions(9) = (columnIndex - 1) * 20: enemyYPositions(9) = (rowIndex - 2) * 20: GET (enemyXPositions(9), enemyYPositions(9))-(enemyXPositions(9) + 20, enemyYPositions(9) + 20), enemyBackgroundBuffers(202, 9)\r
+        IF character$ = "0" THEN enemyXPositions(10) = (columnIndex - 1) * 20: enemyYPositions(10) = (rowIndex - 2) * 20: GET (enemyXPositions(10), enemyYPositions(10))-(enemyXPositions(10) + 20, enemyYPositions(10) + 20), enemyBackgroundBuffers(202 _\r
+, 10)\r
+    NEXT columnIndex\r
+NEXT rowIndex\r
 UpdateHUD 0\r
 END SUB\r
 \r
 SUB PlayHurtSound\r
-a = 1700\r
-b = 1900\r
-FOR c = 1 TO 50\r
-a = a + 3\r
-b = b - 5\r
-SOUND a, .2\r
-SOUND b, .2\r
-NEXT c\r
+' Plays distinctive "hurt" sound effect with descending pitch.\r
+' Creates two converging tones that slide downward in frequency.\r
+\r
+startFrequency = 1700\r
+endFrequency = 1900\r
+FOR toneStep = 1 TO 50\r
+    startFrequency = startFrequency + 3\r
+    endFrequency = endFrequency - 5\r
+    SOUND startFrequency, .2\r
+    SOUND endFrequency, .2\r
+NEXT toneStep\r
 END SUB\r
 \r
-SUB RenderImageFromTextFile (a1, b1, c1, d1, a$)\r
-a1 = a1 * 8\r
-b1 = b1 * 8\r
-laius1 = c1 - a1\r
-pikkus1 = d1 - b1\r
-OPEN a$ + ".i01" FOR INPUT AS #1\r
-INPUT #1, pikkus\r
-FOR a = 1 TO pikkus\r
-LINE INPUT #1, z$\r
-FOR b = LEN(z$) TO 1 STEP -1\r
-LINE (a1 + (b * c1), (b1 + (a * d1)) + 1)-(a1 + ((b + 1) * c1), b1 + ((a + 1) * d1)), ASC(LEFT$(RIGHT$(z$, b), 1)) - 40, BF\r
-NEXT b\r
-NEXT a\r
+SUB RenderFlippedSpriteFromFile (x%, y%, widthMultiplier%, heightMultiplier%, Filename$)\r
+' Renders sprite from text file but flips horizontally during rendering.\r
+' File format: first line = height, subsequent lines contain ASCII art\r
+' where each character's ASCII value determines color (offset by 40).\r
+\r
+x = x * 8\r
+y = y * 8\r
+spriteWidth = widthMultiplier - x\r
+spriteHeight = heightMultiplier - y\r
+OPEN Filename$ + ".i01" FOR INPUT AS #1\r
+INPUT #1, spriteHeight\r
+FOR row = 1 TO spriteHeight\r
+    LINE INPUT #1, rowText$\r
+    FOR column = LEN(rowText$) TO 1 STEP -1\r
+        ' Calculate screen coordinates and color from ASCII value\r
+        currentColor = ASC(LEFT$(RIGHT$(rowText$, column), 1)) - 40\r
+        ' Draw filled rectangle for each pixel (scaled by multipliers)\r
+        LINE (x + (column * widthMultiplier), (y + (row * heightMultiplier)) + 1)-(x + ((column + 1) * widthMultiplier), y + ((row + 1) * heightMultiplier)), currentColor, BF\r
+    NEXT column\r
+NEXT row\r
 CLOSE\r
 END SUB\r
 \r
-DEFINT A-Z\r
-SUB UpdateHUD (zaz)\r
+SUB RenderSpriteFromFile (x%, y%, widthMultiplier%, heightMultiplier%, SpriteName$)\r
+' Renders sprite from text file in normal orientation.\r
+' File format and rendering identical to RenderFlippedSpriteFromFile\r
+' but processes characters left-to-right instead of right-to-left.\r
+\r
+spriteWidth = widthMultiplier - x\r
+spriteHeight = heightMultiplier - y\r
+OPEN SpriteName$ + ".i01" FOR INPUT AS #1\r
+INPUT #1, spriteHeight\r
+FOR row = 1 TO spriteHeight\r
+    LINE INPUT #1, rowText$\r
+    FOR column = 1 TO LEN(rowText$)\r
+        ' Calculate color from ASCII value (offset by 40)\r
+        currentColor = ASC(RIGHT$(LEFT$(rowText$, column), 1)) - 40\r
+        ' Draw scaled pixel block\r
+        LINE (x + (column * widthMultiplier), (y + (row * heightMultiplier)) + 1)-(x + ((column + 1) * widthMultiplier) - 1, y + ((row + 1) * heightMultiplier)), currentColor, BF\r
+    NEXT column\r
+NEXT row\r
+CLOSE\r
+END SUB\r
+\r
+SUB ShowIntroScreen\r
+' Displays introductory splash screen using sprite rendering.\r
+\r
+CLS\r
+RenderSpriteFromFile 2, 2, 10, 1, "win.i01"\r
+END SUB\r
+\r
+SUB UpdateHUD (coinIncrementAmount%)\r
+' Updates Heads-Up Display showing coins and lives:\r
+' - Processes coin counter (with 100-coin bonus life)\r
+' - Draws coin counter digits\r
+' - Shows remaining lives\r
+\r
+' End game if no lives remain\r
 IF lives < 0 THEN GameOverSequence\r
-PUT (0, 180), munt1, PSET\r
-hudCoinDigits(1) = hudCoinDigits(1) + zaz\r
-FOR b = 1 TO 3\r
-IF hudCoinDigits(1) > 9 THEN hudCoinDigits(1) = hudCoinDigits(1) - 10: hudCoinDigits(2) = hudCoinDigits(2) + 1\r
-IF hudCoinDigits(2) > 9 THEN hudCoinDigits(1) = 0: hudCoinDigits(2) = 0: lives = lives + 1\r
-NEXT b\r
+\r
+' Draw coin icon at left of HUD\r
+PUT (0, 180), largeCoinSpriteBuffer, PSET\r
+\r
+' Add new coins to counter\r
+CoinDigits(1) = CoinDigits(1) + coinIncrementAmount%\r
+\r
+' Handle decimal carry-over for coin counter\r
+FOR digitPosition = 1 TO 3\r
+    ' Carry from ones place to tens place\r
+    IF CoinDigits(1) > 9 THEN\r
+        CoinDigits(1) = CoinDigits(1) - 10\r
+        CoinDigits(2) = CoinDigits(2) + 1\r
+    END IF\r
+\r
+    ' Convert 100 coins to extra life\r
+    IF CoinDigits(2) > 9 THEN\r
+        CoinDigits(1) = 0\r
+        CoinDigits(2) = 0\r
+        lives = lives + 1\r
+    END IF\r
+NEXT digitPosition\r
+\r
 LOCATE 1, 1\r
-r = 3\r
-FOR a = 1 TO 2\r
-r = r - 1\r
-PUT ((a * 11) + 10, 180), digitImages(100, hudCoinDigits(r)), PSET\r
-NEXT a\r
+digitPosition = 3\r
+' Draw both digits of coin counter\r
+FOR hudElement = 1 TO 2\r
+    digitPosition = digitPosition - 1\r
+    PUT ((hudElement * 11) + 10, 180), digitImages(100, CoinDigits(digitPosition)), PSET\r
+NEXT hudElement\r
+\r
+' Cap maximum lives at 10\r
 IF lives > 10 THEN lives = 10\r
+\r
+' Draw "X" before lives counter\r
 PUT (43, 180), digitImages(100, 10), PSET\r
-PUT (53, 180), munt2, PSET\r
+' Draw small coin icon next to lives counter\r
+PUT (53, 180), smallCoinSpriteBuffer, PSET\r
+' Draw current lives count\r
 PUT (73, 180), digitImages(100, lives), PSET\r
 END SUB\r
 \r
 SUB UpdateLoadingScreen\r
+' Visual progress indicator during asset loading.\r
+' Draws black screen with incremental dots on bottom row.\r
+\r
 LINE (0, 0)-(319, 150), 0, BF\r
-LOCATE 20, 10 + prog\r
-prog = prog + 1\r
+LOCATE 20, 10 + loadingProgressDotCount\r
+loadingProgressDotCount = loadingProgressDotCount + 1\r
 PRINT "."\r
 END SUB\r
 \r
-SUB wiew (a1, b1, c1, d1, a$)\r
-laius1 = c1 - a1\r
-pikkus1 = d1 - b1\r
-OPEN a$ + ".i01" FOR INPUT AS #1\r
-INPUT #1, pikkus\r
-FOR a = 1 TO pikkus\r
-LINE INPUT #1, z$\r
-FOR b = 1 TO LEN(z$)\r
-LINE (a1 + (b * c1), (b1 + (a * d1)) + 1)-(a1 + ((b + 1) * c1) - 1, b1 + ((a + 1) * d1)), ASC(RIGHT$(LEFT$(z$, b), 1)) - 40, BF\r
-NEXT b\r
-NEXT a\r
-CLOSE\r
+SUB WaitForUserInput\r
+' Waits for any keyboard input before continuing.\r
+' Clears userInput$ variable first, then polls INKEY$ until non-empty.\r
+\r
+userInput$ = ""\r
+WHILE userInput$ = ""\r
+    userInput$ = INKEY$\r
+WEND\r
 END SUB\r
 \r