Better code readability
authorSvjatoslav Agejenko <svjatoslav@svjatoslav.eu>
Sun, 24 Aug 2025 20:03:04 +0000 (23:03 +0300)
committerSvjatoslav Agejenko <svjatoslav@svjatoslav.eu>
Sun, 24 Aug 2025 20:03:04 +0000 (23:03 +0300)
Games/Pomppu Paavo/Pomppu Paavo.bas

index 57cd220..7017b72 100755 (executable)
@@ -1,4 +1,4 @@
-DECLARE SUB RenderSpriteFromFile (p%, o%, m%, fr%, teler%)\r
+DECLARE SUB RenderSpriteFromFile (p%, O%, m%, fr%, teler%)\r
 ' Pomppu Paavo\r
 '\r
 ' This program is free software: released under Creative Commons Zero (CC0) license\r
@@ -75,6 +75,7 @@ DIM SHARED PlayerRunLeft2SpriteSmall(51)
 DIM SHARED PlayerJumpingSpriteSmall(51)\r
 DIM SHARED DoorSpriteSmall(50)\r
 \r
+' Define keyboard control sequences\r
 leftArrowKey$ = CHR$(0) + "K"\r
 rightArrowKey$ = CHR$(0) + "M"\r
 upArrowKey$ = CHR$(0) + "H"\r
@@ -236,7 +237,8 @@ PUT (Companion1PositionX%, Companion1PositionY%), HedgehogSprite, OR
 GET (Companion2PositionX%, Companion2PositionY%)-(Companion2PositionX% + 10, Companion2PositionY% + 10), HedgehogSprite2\r
 PUT (Companion2PositionX%, Companion2PositionY%), HedgehogSprite, OR\r
 \r
-' Create short delay using sound command (workaround for no built-in delay)\r
+' Create short delay using sound command (workaround since QBasic lacks built-in sub-second delay)\r
+' SOUND 0,0.8 creates an inaudible tone that takes approximately 8 milliseconds to process\r
 SOUND 0, .8\r
 \r
 ' Check collisions with terrain (z = solid block)\r
@@ -647,46 +649,77 @@ NEXT e
 123\r
 END SUB\r
 \r
-SUB RenderSpriteFromFile (p, o, m, fr, teler)\r
-' Renders a sprite on screen loaded from file "img/<m>.i01"\r
+SUB RenderSpriteFromFile (x%, y%, spriteID%, animationFrame%, scaleFactor%)\r
 '\r
-' File format: First line = height (number of rows)\r
-' Subsequent lines = strings of digit characters ('0'-'3') representing pixel colors</m>\r
+' Renders a sprite on screen by loading pixel data from external file\r
+' File format explanation:\r
+' - First line contains height (number of rows)\r
+' - Subsequent lines contain strings of digit characters:\r
+'     '0' = transparent/background\r
+'     '1'-'3' = color indexes (mapped to current palette)\r
+' Example file for 3x2 sprite:\r
+'     2\r
+'     123\r
+'     010\r
+'\r
+' Parameters:\r
+' x%, y%        = Top-left drawing position\r
+' spriteID%     = Which sprite file to load (img/<id>.i01)\r
+' animationFrame% = Special handling:\r
+'                   1 = normal rendering\r
+'                   50 = horizontally flipped\r
+'                   Other values = scaled rendering (value = scale factor)\r
+' scaleFactor%  = Pixel scaling factor (1 = full size, 2 = half size)\r
+\r
 DIM rowText AS STRING\r
-fileName$ = "img/" + LTRIM$(STR$(m)) + ".i01"\r
+fileName$ = "img/" + LTRIM$(STR$(spriteID%)) + ".i01"\r
 OPEN fileName$ FOR INPUT AS #1\r
 INPUT #1, height%\r
-DIM ao(1 TO 100) AS STRING\r
-FOR a = 1 TO height%\r
-LINE INPUT #1, ao(a)\r
-NEXT a\r
+DIM spritePixelRows(1 TO 100)  AS STRING\r
+FOR rowIndex% = 1 TO height%\r
+    LINE INPUT #1, spritePixelRows(rowIndex%)\r
+NEXT rowIndex%\r
 CLOSE #1\r
-IF fr = 50 THEN GOTO DrawFlippedSprite\r
-IF fr > 1 THEN GOTO DrawScaledSprite\r
-FOR a = 1 TO 100                ' Normal sprite\r
-IF ao(a) = "" THEN GOTO FinishDrawing\r
-FOR b = 1 TO LEN(ao(a))\r
-PSET ((p + b) \ teler, (o + a) \ teler), ASC(RIGHT$(LEFT$(ao(a), b), 1)) - 48\r
-NEXT b\r
-NEXT a\r
+\r
+' Handle special rendering modes based on animationFrame parameter\r
+IF animationFrame% = 50 THEN GOTO DrawFlippedSprite\r
+IF animationFrame% > 1 THEN GOTO DrawScaledSprite\r
+\r
+' Normal rendering mode (1:1 pixels)\r
+FOR rowIndex% = 1 TO 100\r
+    IF spritePixelRows(rowIndex%) = "" THEN GOTO FinishDrawing\r
+    FOR columnIndex% = 1 TO LEN(spritePixelRows(rowIndex%))\r
+        ' Convert character digit to numeric color value (0-3)\r
+        pixelColor% = ASC(RIGHT$(LEFT$(spritePixelRows(rowIndex%), columnIndex%), 1)) - 48\r
+        ' Calculate actual screen position considering scaleFactor\r
+        PSET ((x% + columnIndex%) \ scaleFactor%, (y% + rowIndex%) \ scaleFactor%), pixelColor%\r
+    NEXT columnIndex%\r
+NEXT rowIndex%\r
 GOTO FinishDrawing\r
-DrawScaledSprite:               ' Scaled sprite\r
-FOR a = 1 TO 100\r
-IF ao(a) = "" THEN GOTO FinishDrawing\r
-FOR b = 1 TO LEN(ao(a))\r
-c = ASC(RIGHT$(LEFT$(ao(a), b), 1)) - 48\r
-LINE (p + (b * fr), o + (a * fr))-(p + (b * fr) + fr, o + (a * fr) + fr), c, BF\r
-NEXT b\r
-NEXT a\r
+\r
+DrawScaledSprite:\r
+' Scaled rendering mode (stretches pixels)\r
+FOR rowIndex% = 1 TO 100\r
+    IF spritePixelRows(rowIndex%) = "" THEN GOTO FinishDrawing\r
+    FOR columnIndex% = 1 TO LEN(spritePixelRows(rowIndex%))\r
+        pixelColor% = ASC(RIGHT$(LEFT$(spritePixelRows(rowIndex%), columnIndex%), 1)) - 48\r
+        ' Draw filled rectangle instead of single pixel\r
+        LINE (x% + (columnIndex% * animationFrame%), y% + (rowIndex% * animationFrame%))-(x% + (columnIndex% * animationFrame%) + animationFrame%, y% + (rowIndex% * animationFrame%) + animationFrame%), pixelColor%, BF\r
+    NEXT columnIndex%\r
+NEXT rowIndex%\r
 GOTO FinishDrawing\r
-DrawFlippedSprite:              ' Horizontally flipped sprite\r
-FOR a = 1 TO 100\r
-IF ao(a) = "" THEN GOTO FinishDrawing\r
-FOR b = 1 TO LEN(ao(a))\r
-PSET ((p + (LEN(ao(a)) - b + 1)) \ teler, (o + a) \ teler), ASC(RIGHT$(LEFT$(ao(a), b), 1)) - 48\r
-NEXT b\r
-NEXT a\r
+\r
+DrawFlippedSprite:\r
+' Horizontally flipped rendering\r
+FOR rowIndex% = 1 TO 100\r
+    IF spritePixelRows(rowIndex%) = "" THEN GOTO FinishDrawing\r
+    FOR columnIndex% = 1 TO LEN(spritePixelRows(rowIndex%))\r
+        ' Note: X position is mirrored (right-to-left)\r
+        PSET ((x% + (LEN(spritePixelRows(rowIndex%)) - columnIndex% + 1)) \ scaleFactor%, (y% + rowIndex%) \ scaleFactor%), ASC(RIGHT$(LEFT$(spritePixelRows(rowIndex%), columnIndex%), 1)) - 48\r
+    NEXT columnIndex%\r
+NEXT rowIndex%\r
+\r
 FinishDrawing:\r
-ERASE ao\r
+ERASE spritePixelRows\r
 END SUB\r
 \r