T3RRYT3RR0R

Batch Game Engine Developer version

Jan 1st, 2021 (edited)
2,593
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Batch 48.82 KB | None | 0 0
  1. @Echo off
  2. REM IMPORTANT - script updated for windows 11 compatability.
  3.  
  4. ::::::::::::::::::: DO NOT move OR rename OR modify THIS FILE. Filename: Game_EngineDEBUG.bat
  5. ::: [ * Author: T3RRY * ] Creation Date - 16/12/2020                     Developer version
  6. :::            Border and Sprite Macro definition package for Batch Arcade games
  7. :::            Purpose: Create a system to convert ASCII Art into sprites that can be moved and interacted with.
  8. ============================
  9. ::: COMPLETE archive with the latest updates:
  10. ::: Games_by_T3RRY: https://drive.google.com/file/d/1cAQLd-f9HN6SuWowBUETccKCZd2dVbWj/view?usp=sharing
  11. ::: See a DEMO using this engine:
  12. ::: https://www.youtube.com/watch?v=Wi3izdqbwcw
  13. ::: Leave a comment if you have any ideas or requests, Share a link if you want to show off your own games.
  14. ============================
  15. ::: Additional Accreditation
  16. ::: Getkey.Exe by Antonio {https://stackoverflow.com/users/778560/aacini}
  17. ::: * REQUIRED * for Extended key controls.
  18. ::: Getfontsize.Exe by Antonio {https://stackoverflow.com/users/778560/aacini}
  19. ::: From: https://stackoverflow.com/a/62087328/12343998
  20. ::: * REQUIRED * to accurately determine the consoles maximum Y;X values
  21. ::::::::::::::::::::::::::::
  22. ::: Sleep.bat by Dave Benham { https://stackoverflow.com/users/1012053/dbenham }
  23. ::: - Not required; allows for more precise sub second delays than other methods.
  24. =============================================================================
  25. ::: Recommended Resources:
  26. ::: Batch Macro's with Arguments Appended:
  27. ::: https://www.dostips.com/forum/viewtopic.php?f=3&t=2518
  28. ::: VT sequence Information:
  29. ::: https://docs.microsoft.com/en-us/windows/console/console-virtual-terminal-sequences
  30. ::: 255 bit color chart [ for VT color sequences ]
  31. ::: https://www.rapidtables.com/web/color/RGB_Color.html
  32. =============================================================================
  33. :::                                          *** Important notes ***
  34. ::: Game_Engine.bat & Game_EngineDEBUG.bat Macro's:
  35. :::  - Enable definition; movement; rotation and collision / capture testing of ASCII sprites
  36. ::: Dev Toolkit - Refer to Game_EngineDEBUG.bat
  37. :::  - Contains advanced usage information ; performs error testing when Game_EngineDEBUG.bat defines Macros.
  38. :::    Defines Macro Resources required to run .Bat arcade Games_by_T3RRY
  39. ::: Game_Engine Macro's act as a whole system; and as such have dependencies on other macro's in the system
  40. :::  - Background.Border macro should ALWAYS be the first macro expanded; As it defines variables that
  41. :::    constrain the dimension of the playfield used by all other Sprite macros.
  42. :::  - Def.Sprite or Def.MultiCol.Sprite must be used to define sprites prior to Move.Sprite or Rotate.Sprite
  43. :::    being used
  44. =============================================================================
  45. :::::::::: Version 2.1 22/01/2022
  46. ::: Updated for Windows 11 users
  47. :::::::::: Version 2.0 01/01/2021
  48. ::: Changes Jan 2021
  49. ::: *** Updated all .Sprite macros to support definition of sprite cells ***
  50. :::     using 255 bit Color codes. Ie: 38;2;200;25;100
  51. ::: Updated Def.Sprite and Def.Multicol.Sprite to define Obj.{l|m|u}{X|Y} variables
  52. ::: /* Changed Collide.Type Return Var to Obj.Collide.Type  /*
  53. ::: - Object specific prefix allows more sophisticated testing of the collision types that have occured during a game "turn"
  54. :::   - enables more game design options like pushable sprites.
  55. :::   - Each sprite now has it's own array for captured / collided cells that can be tested
  56. :::: WHERE obj =  SPRITEVARNAME
  57. :::   - Array Variables:   index var:  Array Name:                    Value:
  58. :::           Collision:   Obj.Coll    Obj.Collide.Type[Col][#=index] Collision Character
  59. :::           Capture  :   Obj.Capt    Obj.Collide.Type[Cap][#=index] Capture Character
  60. :::   ** Obj.Coll and Obj.Capt return the total number of collisions and captures Obj=SPRITEVARNAME has had after a move.
  61. :::  - Added Getfontsize.exe to archive and calculation of true max console Dimensions.
  62. :::  - Expanded Error Testing and Debug output
  63. :::  - Cloned Game_Engine into Debug and Prodution versions
  64. :::  - Finished games can obtain a performance advantage by using the production version.
  65. :::::::::: Version 1.8 28/12/2020
  66. ::: Renamed to Game_Engine.bat
  67. ::: Version Changes 28/12/2020:
  68. ::: Added Play.Music and Stop.Music macro's to
  69. ::: Added Obj.Collide.Type return var to simplify testing of collision type that has occured within move.sprite macro
  70. ::: Added calculation of Sprite Mid{y;x} values to allow determination of sprite center
  71. ::: - Useful for calculating movement directions relevent to other sprites
  72. ::: - return vars: Obj.mx Obj.my [ Obj substituted with SPRITEVARNAME during Move.Sprite expansion ]
  73. ::: - Added SnakeSprite.bat to library to demonstrate how to apply sprite chase using these values
  74. :::::::::::::::::::::::::::::::
  75. ::: Version Changes 23/12/2020:
  76. ::: Added Rotate.Sprite Macro
  77. ::: Added Usage tests and output to Background.Border Def.Sprite Show.Sprite and Move.Sprite Macro's
  78. :::::::::::::::::::::::::::::::
  79. ::: Version Changes 19/12/2020:
  80. ::: Removed Response handling of collision from Move.Sprite macro
  81. ::: Upgraded move.sprite macro to accept arguments for Collision or Capture Characters
  82. ::: - return Vars [Collision is True: Valid=0] [Capture is True: Obj.capt=1]
  83. ::: - Implemented Title based level load indicator during sprite definition
  84. ::: - Improved modelling of handling game exit / End of level cleanup.
  85. ::: - Added 7th arg to Background.Border macro for flagging Border collision as Fatal T[0]/F[-1]
  86. :::::::::::::::
  87.  
  88. rem /* Establish and verify required resources. */
  89. rem /* Game_engine built for use with Getkey.exe ; tests for getkey.exe in subfolders and */
  90. rem /* Quits if not found ; else ensures folder containing Getkey.exe is named 'Components' */
  91.  
  92.  If not Exist "%~dp0Components" (
  93.   Setlocal EnableDelayedExpansion
  94.   For /F "Delims=" %%G in (' dir "%~dp0*GetKey.exe" /B /S 2^> nul ')Do Set "MyPath=%%~G"
  95.   If "!MyPath!" == "" (Echo/Critical resources missing^^^!&Endlocal & Pause & Exit)
  96.   Set "MyPath=!MyPath:\=;!"
  97.   Set "MyPath=!MyPath: =[space]!"
  98.   For %%G in (!Mypath!)Do If /I not "%%~G" == "GetKey.exe" Call Set "DirPath=%%G"
  99.   Set "DirPath=!DirPath:[space]= !"
  100.   Ren "!DirPath!" Components
  101.   Endlocal
  102.  )
  103.  
  104. rem /* Test Environment is suitable for definition of Macro's */
  105.  If "!![" == "[" (Echo/Delayed expansion Must not be enabled prior to starting %~n0.bat & Pause & Exit /B 0)
  106.  
  107. =============================================================================
  108. ::: CRITICAL RESOURCE DEFINITION AND VALIDATION
  109. =============================================================================
  110.  
  111.  CHCP 65001 > nul
  112.  
  113. rem /* Titlebar macro */
  114.  Set "MSG=Title ?"
  115.  %MSG:?= Verifying Resources ...%
  116.  
  117. rem /* Define Escape character used for console virtual terminal sequences */
  118. rem - https://docs.microsoft.com/en-us/windows/console/console-virtual-terminal-sequences
  119.  for /F "delims=" %%e in ('Echo(Prompt $E^|cmd') do set "\E=%%e"
  120.  
  121.  Call:TestVT || (
  122.   Echo(Vitual terminal sequences not enabled on your system
  123.   Exit /b 1
  124.  )
  125.  
  126. rem /* Define Getkey path wit /n no wait parameter */
  127.  For /F "Delims=" %%C in ('dir "%~dp0*GetKey.exe" /B /S') Do If not defined GetKey Set "GetKey="%%C" /n"
  128.  
  129. rem /* Test getkey var is defined with valid exe path. Exit with notice if not. */
  130.  Echo/%GetKey%|findstr.exe /LIC:"GetKey.exe" > nul || (Echo/GetKey.Exe not found in Directory. Game cannot be played without GetKey.exe &Pause &Exit /B 0)
  131.  
  132. rem /* Ensure prefix used for Collision detection array unnassigned */
  133.  (For /F "Tokens=1,2 Delims==" %%G in ('Set "}" 2^> Nul ')Do Set "%%~G=") 2> nul
  134.  
  135. rem /* If TEMP path not found; Assign Current Directory as ~tmp file output folder */
  136.  If not exist "%TEMP%" (Set "Save.Dir=%~dp0")Else Set "Save.Dir=%TEMP%\"
  137.  
  138. rem /* Test write permission in the assigned directory. Exit with notice if no write permission */
  139.  break >"%Save.Dir%%~n0_testpermission.tst" || (
  140.   Echo/Write permission required in %Save.Dir% to continue
  141.   Pause
  142.   Exit /B
  143.  )
  144.  Set Background="%Save.Dir%%~n0_background.~tmp"
  145.  Set Foreground="%Save.Dir%%~n0_foreground.~tmp"
  146.  DEL %Foreground% 2> Nul
  147.  
  148.  %= --------------------------------------------------------- =%
  149. ::: MACRO DEFINITIONS
  150. (Set LF=^
  151.  
  152.  
  153. %= Linefeed var. DO NOT MODIFY =%)
  154. (Set \n=^^^
  155.  
  156. %= Macro newline var. DO NOT MODIFY =%)
  157. ::: COMMENT macro expands to rem - \n
  158. ::: allowing for remarks in multiline variables
  159. ::: Expanded using substring modification with an absent string to ensure comments aren't defined into the macro.
  160. (Set COMMENT=rem - ^^^
  161.  
  162. %= Macro Comment var. DO NOT MODIFY =%)
  163. =============================================================================
  164. ::: Screen Formatting and border definiton.
  165. rem /* Default Width for game control info panel */
  166.  If Not "%~2" == "/N" (
  167.   Set "CNTRL.Width=20"
  168.   Set "}2;!CNTRL!=%\E%[2;!CNTRL!H%\E%[33mControls:"
  169.   Set "}3;!CNTRL!=%\E%[3;!CNTRL!H  ▲    - Up"
  170.   Set "}4;!CNTRL!=%\E%[4;!CNTRL!H  ◄    - Left"
  171.   Set "}5;!CNTRL!=%\E%[5;!CNTRL!H  ▼    - Down"
  172.   Set "}6;!CNTRL!=%\E%[6;!CNTRL!H  ►    - Right"
  173.   Set "}7;!CNTRL!=%\E%[7;!CNTRL!HSpace  - Pause"
  174.   Set "}8;!CNTRL!=%\E%[8;!CNTRL!HEscape - Quit"
  175.  ) Else ( If not "%~3" == "" ( Set /A "CNTRL.Width=%~3" 2> nul ) Else ( Set "CNTRL.Width=20" ))
  176. ::: Optional Macro providing Supplemental Information panel for game design debug purposes
  177.  Set "Debug.Sprite=< nul Set /P "=%\E%[14;!CNTRL!H%\E%[38;2;0;60;70mObj.Coll - !Obj.Coll! %\E%[15;!CNTRL!HObj.Capt - !Obj.Capt! %\E%[16;!CNTRL!HType - !Obj.Collide.Type! %\E%[17;!CNTRL!HGrounded - !Obj.On.Surface! %\E%[18;!CNTRL!H{lmu}X - !Obj.lX!;!Obj.mX!;!Obj.uX!    %\E%[19;!CNTRL!H{lmu}Y - !Obj.lY!;!Obj.mY!;!Obj.uY!    %\E%[20;!CNTRL!Hwidth - !Obj.width! %\E%[0m""
  178.  
  179. ::: BACKGROUND.BORDER macro. Define border color;dimensions;character;collision state.
  180. ::: Resizes console; padding right of the border for Control display
  181. ::: Defines Critical Variables needed for .sprite + other macro's; using the arguments supplied
  182.  Set "Border.Usage=%%Background.Border:CNTRL.Width=INTEGER%%{VTcolorcode}{.Xmin}{.Xmax}{.Ymin}{.Ymax}{BorderCharacter}{0|-1}"
  183.  Set "error=Echo/Error in level !lvl!.!LF! Arg # for %%Background.Border%%!Border!!LF! Invalid:"
  184.  
  185. ::: ***************************************************************
  186. ::: - Get screen Dimensions
  187.     For /f "delims=" %%# in  ('"wmic path Win32_VideoController get CurrentHorizontalResolution,CurrentVerticalResolution /format:value"') do (
  188.         Set "%%#">nul
  189.     )
  190.  
  191. ::: - Get scale Factor in effect. Registry value requires restart to update if scale has changed.
  192.     For /F "Tokens=3 Delims= " %%A in ('REG QUERY "HKCU\Control Panel\Desktop\WindowMetrics" /V AppliedDPI') Do Set /A SF=%%A / 100 + 1
  193.  
  194. ::: - Get Font Size
  195.     (For /F "Delims=" %%S in ('dir GetFontSize.exe /B /S') Do (%%S)) 2> Nul
  196.     Set /A "Font.H=%errorlevel% >> 16, Font.W=%errorlevel% & 0xFF"
  197.  
  198. :::::::::: Calculate Max{Y;X} Constraints for Background.Border below
  199.     Set /A "Max{X}= ( CurrentHorizontalResolution / ( Font.W * SF ) )"
  200.     Set /A "Max{Y}= ( ( CurrentVerticalResolution / Font.H ) / SF ) - 4"
  201.  
  202. :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  203.  Set Background.Border=Set "Border=" ^& For %%n in (1 2)Do If %%n==2 ( %\n%
  204.    If "!Border!" == "" ( %\n%
  205.     Mode 1000 %\n%
  206.     Echo/Error in Level !lvl! !LF! Missing Args for: !LF! %%Background.Border%%!Border!!LF! Background.Border USAGE: %\n%
  207.     Echo/!Border.Usage! %\n%
  208.     Pause ^& Endlocal ^& Exit /B 0%\n%
  209.    ) %\n%
  210.   For /F "Tokens=1-7 Delims={}" %%G in ("!Border!")Do If not "%%~M" == "" ( %\n%
  211.   %COMMENT: {i}= Background.Border RETURN VARIABLES \n%
  212.    Set "Border.Color=%%~G" %\n%
  213.    Set ".Xmin=%%~H" %\n%
  214.    Set ".Xmax=%%~I" %\n%
  215.    Set ".Ymin=%%~J" %\n%
  216.    Set ".Ymax=%%~K" %\n%
  217.    Set ".Char=%%~L" %\n%
  218.    Set "?Border.Fatal=%%M" %\n%
  219.    Set /A "CNTRL=!.Xmax!+5,cols=!.Xmax!+CNTRL.Width+5,lines=!.Ymax!+2" 2^> nul %\n%
  220.    Set /A "Max{X}=Max{X}-(CNTRL.Width+5)" 2^> nul %\n%
  221.    Echo/!Border.Color!^| Findstr.exe /RX "[1234567890;]*" ^> nul %\n%
  222.    If Not !Errorlevel!==0 (    %error:#=1% {%%~G} - Accepted - Integer or Integer;Integer  ^& Pause ^> nul ^& Pause ^> nul ^& Exit /B ) %\n%
  223.    Echo/!.Xmin!^| Findstr.exe /RX "[1234567890]*" ^> nul %\n%
  224.    If Not !Errorlevel!==0 (    %error:#=1% {%%~H} - Accepted - Integer GEQ 1 LSS !Max{X}! ^& Pause ^> nul ^& Pause ^> nul ^& Exit /B ) %\n%
  225.    Echo/!.Xmax!^| Findstr.exe /RX "[1234567890]*" ^> nul %\n%
  226.    If Not !Errorlevel!==0 (    %error:#=1% {%%~I} - Accepted - Integer GEQ 1 LEQ !Max{X}! ^& Pause ^> nul ^& Pause ^> nul ^& Exit /B ) %\n%
  227.    Echo/!.Ymin!^| Findstr.exe /RX "[1234567890]*" ^> nul %\n%
  228.    If Not !Errorlevel!==0 (    %error:#=1% {%%~J} - Accepted - Integer GEQ 1 LSS !Max{Y}! ^& Pause ^> nul ^& Pause ^> nul ^& Exit /B ) %\n%
  229.    Echo/!.Ymax!^| Findstr.exe /RX "[1234567890]*" ^> nul %\n%
  230.    If Not !Errorlevel!==0 (    %error:#=1% {%%~K} - Accepted - Integer GEQ 1 LEQ !Max{Y}! ^& Pause ^> nul ^& Pause ^> nul ^& Exit /B ) %\n%
  231.    If !.Xmin! LEQ 0 (          %error:#=2% {%%~H} - Accepted - Integer GEQ 1 ^& Pause ^> nul ^& Pause ^> nul ^& Exit /B ) %\n%
  232.    If !.Xmax! GTR !Max{X}! (   %error:#=3% {%%~I} - Accepted - Integer GTR 1 LEQ !Max{X}! ^& Pause ^> nul ^& Pause ^> nul ^& Exit /B ) %\n%
  233.    If !.Ymin! LEQ 0 (          %error:#=4% {%%~J} - Accepted - Integer GEQ 1 ^& Pause ^> nul ^& Pause ^> nul ^& Exit /B ) %\n%
  234.    If !.Ymax! GTR !Max{Y}! (   %error:#=5% {%%~K} - Accepted - Integer GTR 1 LEQ !Max{Y}! ^& Pause ^> nul ^& Pause ^> nul ^& Exit /B ) %\n%
  235.    If Not "!.Char:~1,1!" == "" (%error:#=6% {%%~L} - Accepted - Singular ASCII character ^& Pause ^> nul ^& Pause ^> nul ^& Exit /B ) %\n%
  236.    If !?Border.Fatal! GTR 0 (  %error:#=7% {%%~M} - Accepted - "0" or "-1" ^& Pause ^> nul ^& Pause ^> nul ^& Exit /B ) %\n%
  237.    If !?Border.Fatal! LSS -1 ( %error:#=7% {%%~M} - Accepted - "0" or "-1" ^& Pause ^> nul ^& Exit /B ) %\n%
  238.    For %%w in (%%~H %%~I)Do for /L %%h in (%%~J,1,%%~K)Do ( %\n%
  239.     Set "}%%h;%%w=%\E%[%%h;%%wH%\E%[%%~Gm!.Char!" %\n%
  240.     For %%i in (%%~J %%~K)Do If %%h Equ %%i ( %\n%
  241.      For /L %%W in (%%~H 1 %%~I)Do ( %\n%
  242.       Set "}%%h;%%W=%\E%[%%h;%%WH%\E%[%%~Gm!.Char!" %\n%
  243.   ))))Else ( %\n%
  244.    Mode 1000 %\n%
  245.    Echo/Error in Level !lvl! !LF! Missing Args for: !LF! %%Background.Border%%!Border!!LF! Background.Border USAGE: %\n%
  246.    Echo/!Border.Usage! %\n%
  247.    Pause ^& Endlocal ^& Exit /B 0%\n%
  248.   ) %\n%
  249.   %!!%
  250.   mode !Cols!,!lines! %\n%
  251.  )Else Set Border=
  252.  
  253. =============================================================================
  254.  Set "UPDATE.Background=Set /A ".End=!.Ymax! + 1" & ((For /F "Tokens=2* Delims==" %%G in ('Set "}"')Do (< nul Set /P "=%%~G%\E%[0m") & < nul Set /P "=%\E%[!.END!;1H%\E%[0m%\E%[?25l")) >%Background% & Type %Background% > Con"
  255. =============================================================================
  256. rem /* Game macro Script timing */
  257.  
  258.  Set "Delay.Usage=%%Delay:#=Integer%%"
  259.  Set "Delay=If not "#" == "!HASH!" (If exist "%~dp0Components\Sleep.bat" ( Call "%~dp0Components\sleep.bat" # !time! )Else (For /L %%n in (1 1 10)Do ( Call :Delay 2> nul )))Else (Echo/Error in Delay macro - level !lvl!.!LF! Usage: !Delay.Usage!& Pause & Endlocal & Exit)"
  260.  
  261. =============================================================================
  262. ::: *** Key handling Macro's ***
  263. ::: Use Keytest_Game_Engine.Bat to Identify Ascii Integer values for the keys you wish to define
  264.  Set "Def.Key.Usage=%%Def.Key%%"Ascii.key.Integer=String" "Ascii.key.Integer=String" "Ascii.key.Integers=String""
  265.  Set "Def.Key=Set "input="&For %%n in (1 2)Do if %%n==2 (If "!input!" == "" (CLS & Mode 1000 & Echo/Echo/Error in Def.Key usage; Level !lvl!. Usage:!LF! !Def.Key.Usage! & Pause > nul & Endlocal & Exit )Else For %%I in (!input!)Do Set "k%%~I")Else Set input="
  266. ::: ?key# macro returns the string value of any key assigned using Def.Key when pressed in Variable: Key
  267.  Set "?Key#=For %%n in (1 2)Do if %%n==2 (For %%E in (!Errorlevel!) Do If not "!k%%E!" == "" (Set "Key=!k%%E!" & (If /I "!Key!" == "space" ( Pause > nul )) & (For %%d in (left right up down)Do If /I "!Key!" == "%%d" (Set "Obj.Dir=%%d")))Else If not "%%E" == "0" ( If /I "mode" == "dev" (TITLE Key Errorcode - %%E & Pause > nul )))Else Set Obj.prv.Dir="
  268.  
  269. ::: Hash vars used to test / confirm Substring modification is used where needed.
  270.  Set "HASH=#"
  271.  Set "oHASH=Obj"
  272.  
  273. =============================================================================
  274. ::: DEF.SPRITE : Converts Ascii art to objects [ a list ] with Defined Cordinates }Y;H=}Y;XHcharacter
  275. ::: Stores Arg 2 Vt Color Code to [Arg 1] SPRITEVARNAME.Color variable for use in Move.Sprite and Rotate.Sprite
  276.  Set "Def.Sprite.Usage=%%Def.Sprite:#=lineYpos%%{SPRITEVARNAME}{VTCOLORCODE}{characters for x positions of substituted Y line}"
  277. :::::::::::::::::::::::::::::::::::::::::::::::::::
  278.  Set Def.Sprite=For %%n in (1 2)Do if %%n==2 ( %\n%
  279.   If "!Cells!" == "" ( %\n%
  280.    CLS ^& Mode 1000 %\n%
  281.    Echo/Error in Level !lvl!!LF!Missing Args for -!LF!%%Def.Sprite%%!Cells!!LF! Def.Sprite USAGE: %\n%
  282.    Echo/!Def.Sprite.Usage!!LF!%%Def.Sprite%%{SPRITEVARNAME}{VTCOLORCODE}{characters for x positions of next Y line}%\n%
  283.    Pause ^& Endlocal ^& Exit /B 0%\n%
  284.   ) %\n%
  285.   Set "tMsg=Title Loading Level !lvl!" %\n%
  286.   !tMsg! %\n%
  287.   If Not "#" == "!HASH!" ( Set "{y}=#" ) %\n%
  288.   Set /A "{y}+=1 + 0" %\n%
  289.   If !{y}! LEQ !.Ymin! (CLS ^& Mode 1000 ^& Echo/Error in Def.Sprite - Level !lvl!!LF!Y Value - [!{y}!] Outside Border Boundary .YMin - [!.Ymin!]!LF! %%Def.Sprite%%!Cells!!LF!%%Background.Border%%!Border!!LF! Def.Sprite Usage:!LF!Echo/!Def.Sprite.Usage! ^& Pause ^& Endlocal ^& Exit /B 0) %\n%
  290.   If !{y}! GEQ !.Ymax! (CLS ^& Mode 1000 ^& Echo/Error in Def.Sprite - Level !lvl!!LF!Y Value - [!{y}!] Exceeds Border Boundary .Ymax - [!.Ymax!]!LF! %%Def.Sprite%%!Cells!!LF!%%Background.border%%!Border! ^& Pause ^& Endlocal ^& Exit /B 0) %\n%
  291.   For /F "Tokens=1,2,3 Delims={}" %%G in ("!Cells!")Do If not "%%~I" == "" ( %\n%
  292.    Set "cell=%%I" %\n%
  293.    Set "%%G.Color=%%~H" %\n%
  294.    For /L %%i in (2 1 !.Xmin!)Do Set "cell= !cell!" %\n%
  295.    For /L %%x in (0 1 !.Xmax!)Do If not "!cell:~%%x,1!" == "" ( %\n%
  296.     If not "!cell:~%%x,1!" == " " ( %\n%
  297.     Set "tMsg=!tMsg!." %\n%
  298.     !tMsg! %\n%
  299.     Set "tCell=!cell:~%%x,1!" %\n%
  300.     If not "!%%G!" == "" ( %\n%
  301.      For %%t in ("!tCell!")Do Set "t.%%G=!%%G:%%~t=!" %\n%
  302.      If "!t.%%G!" == "!%%G!" Set "%%G.C=!%%G.C! "!tCell!"" %\n%
  303.     ) Else (Set "Obj.C=!Obj.C! "!C.Tkn!"") %\n%
  304.      FOR /F "Delims=" %%X in ('Set /A "{x}=%%x+!.Xmin!+1"')Do ( %\n%
  305.       For %%C in ("H" ";" "[")Do If /I "!cell:~%%x,1!" == "%%~C" ( %\n%
  306.        CLS ^& Mode 1000 %\n%
  307.        Echo/Error in: %%Def.Sprite%%!Cells!!LF! [Invalid] - !Cells:%%~C=[%%~C]! %\n%
  308.        Echo/Delim character %%~C cannot be defined to a sprite. ^& Pause ^& Endlocal ^& Exit %\n%
  309.       ) %\n%
  310.       Set "}!{y}!;%%X=!{y}!;%%XH!cell:~%%x,1!" %\n%
  311.       %COMMENT:{i}= Define Sprite variable Arg 1 with converted Coordinates for non whitespace cells from Arg 2 \n%
  312.       Set "%%G=!%%G!"!{y}!;%%XH!cell:~%%x,1!"," %\n%
  313.    ))) %\n%
  314.    Set /A "%%G.lX=!.Xmax!,%%G.uX=!.Xmin!,%%G.lY=!.Ymax!,%%G.uY=!.Ymin!" %\n%
  315.    For %%S in (!%%G!)Do ( %\n%
  316.     For /F "tokens=1,2 Delims=;H" %%3 in ("%%~S") Do (%\n%
  317.      If %%3 GTR !%%G.uY! (Set "%%G.uY=%%3") %\n%
  318.      If %%3 LSS !%%G.lY! (Set "%%G.lY=%%3") %\n%
  319.      If %%4 GTR !%%G.uX! (Set "%%G.uX=%%4") %\n%
  320.      If %%4 LSS !%%G.lX! (Set "%%G.lX=%%4") %\n%
  321.     ) %\n%
  322.    ) %\n%
  323.    Set /A "%%G.mY=(!%%G.lY!+!%%G.uY!)/2,%%G.mX=(!%%G.lX!+!%%G.uX!)/2" %\n%
  324.    Set /A "%%G.Width=(!%%G.uX!-!%%G.lX!) + 1" %\n%
  325.   )Else ( %\n%
  326.    CLS ^& Mode 1000 %\n%
  327.    Echo/Error in Level !lvl!!LF!Missing Args for -!LF!%%Def.Sprite%%=!Cells!!LF! Def.Sprite USAGE: %\n%
  328.    Echo/!Def.Sprite.Usage!!LF!%%Def.Sprite%%{SPRITEVARNAME}{VTCOLORCODE}{characters for x positions of next Y line}%\n%
  329.    Pause ^& Endlocal ^& Exit /B 0%\n%
  330.   ) %\n%
  331.  )Else Set Cells=
  332. =============================================================================
  333. ::: Def.Multicol.Sprite : Converts list of strings to sprite Ascii art with Defined Cordinates }Y;H=}Y;XHVTCOLORCODEcharacter
  334. ::: Stores last supplied VTCOLORCODE to SPRITEVARNAME.Color
  335. ::: Defines Cell as }Y;X=Y;XH%\E%[VTCOLORCODEmCHARACTER
  336.  Set "Def.MC.Sprite.Usage=%%Def.Multicol.Sprite:Obj=SPRITEVARNAME%%"Y;XHVTCOLORCODECHARACTER" "Y;XHVTCOLORCODECHARACTER" "Y;XHVTCOLORCODECHARACTER" "
  337.  Set Def.Multicol.Sprite=For %%n in (1 2) Do if %%n==2 ( %\n%
  338.    If /I "!oHASH!" == "Obj" ( %\n%
  339.     Mode 1000 %\n%
  340.     Echo/Error in Level !lvl!!LF!Missing Substituion for -!LF! %%Def.MultiCol.Sprite:!oHASH!=obj%%!Sprite.String! !LF! Def.Multicol.Sprite USAGE: %\n%
  341.     Echo/!Def.MC.Sprite.Usage! %\n%
  342.     Pause ^& Endlocal ^& Exit /B 0 %\n%
  343.    ) %\n%
  344.   Set "Obj=" %\n%
  345.   For %%G in (!Sprite.String!)Do ( %\n%
  346.    Set "c.Tkn=%%~G" %\n%
  347.    For %%C in ("H" ";" "[")Do If /I "!c.Tkn:~-1!" == "%%~C" ( %\n%
  348.     CLS ^& Mode 1000 %\n%
  349.     Echo/Error in: %%Def.MultiCol.Sprite%%!Sprite.String!!LF! [Invalid] - !C.Tkn:~0,-1![%%~C]! %\n%
  350.     Echo/Delim character %%~C cannot be defined to a sprite. ^& Pause ^& Endlocal ^& Exit %\n%
  351.    ) %\n%
  352.    For /F "Tokens=1,2,3* Delims=;[H" %%1 in ("%%~G")Do ( %\n%
  353.     If "%%3" == "" (CLS ^& Mode 1000 ^& Echo/Missing Arg for Def.Multicol.Sprite.!LF! - Accepted - Integer;IntegerHIntegerCharacter!LF! Usage:!Def.MC.Sprite.Usage! ^& Pause ^> nul ^& Pause ^> nul ^& Exit /B ) %\n%
  354.     Set "Obj.Color=%%~G" %\n%
  355.     Set "c.Tkn=!Obj.Color:~-1!" %\n%
  356.     Set "Obj.Color=!Obj.Color:*H=!" %\n%
  357.     Set "Obj.Color=!Obj.Color:~0,-1!" %\n%
  358.     If not "!Obj.C!" == "" ( %\n%
  359.      For %%t in ("!c.Tkn!")Do Set "t.Obj=!Obj:%%~t=!" %\n%
  360.      If "!t.Obj!" == "!Obj!" Set "Obj.C=!Obj.C! "!C.Tkn!"" %\n%
  361.     ) Else (Set "Obj.C="!C.Tkn!"") %\n%
  362.    Echo/!Obj.Color!^| Findstr.exe /RX "[1234567890;]*" ^> nul %\n%
  363.    If Not !Errorlevel!==0 ( CLS ^& Mode 1000 ^& Echo/Invalid VTColorCode:!Obj.Color! !LF! for Def.Multicol.Sprite.!LF! - Accepted - Integer or Integer;Integer ^& Pause ^> nul ^& Pause ^> nul ^& Exit /B ) %\n%
  364.    Echo/%%1;%%2^| Findstr.exe /RX "[1234567890;]*[;][1234567890]*" ^> nul %\n%
  365.    If Not !Errorlevel!==0 ( CLS ^& Mode 1000 ^& Echo/Invalid Y;X - %%1;%%2 in:!LF! %%Def.Multicol.Sprite%%!Sprite.String! !LF! Accepted - Integer;Integer!LF! ^& Pause ^> nul ^& Pause ^> nul ^& Exit /B ) %\n%
  366.     Set "}%%1;%%2=%%1;%%2H%\E%[!Obj.Color!m!C.Tkn!" %\n%
  367.     Set "Obj=!Obj!,"%%1;%%2H%\E%[!Obj.Color!m!C.Tkn!"" %\n%
  368.    ) %\n%
  369.   ) %\n%
  370.   Set /A "Obj.lX=!.Xmax!,Obj.uX=!.Xmin!,Obj.lY=!.Ymax!,Obj.uY=!.Ymin!" %\n%
  371.   For %%S in (!Obj!)Do ( %\n%
  372.    For /F "tokens=1,2 Delims=;H" %%3 in ("%%~S") Do (%\n%
  373.     If %%3 GTR !Obj.uY! (Set "Obj.uY=%%3") %\n%
  374.     If %%3 LSS !Obj.lY! (Set "Obj.lY=%%3") %\n%
  375.     If %%4 GTR !Obj.uX! (Set "Obj.uX=%%4") %\n%
  376.     If %%4 LSS !Obj.lX! (Set "Obj.lX=%%4") %\n%
  377.    ) %\n%
  378.   ) %\n%
  379.   Set /A "obj.mY=(!obj.lY!+!obj.uY!)/2,obj.mX=(!obj.lX!+!obj.uX!)/2" %\n%
  380.   Set /A "Obj.Width=!Obj.uX!-!Obj.lX!+1" %\n%
  381.  )Else Set Sprite.String=
  382. =============================================================================
  383. ::: SHOW : Iterates over the list value of a substituted sprite variable and outputs value.
  384. =============================================================================
  385. rem /* USAGE: %Show:obj=SpriteVARNAME% */ [ Displays spritenames cells ]
  386.  Set Show=If /I "!oHASH!" == "Obj" (%\n%
  387.   ^<nul Set /P "=%\E%[!.End!;1HError in level !lvl!. Unknown Sprite not displayed.!LF!Usage: %%Show:!oHASH!=SpriteVARNAME%%"%\n%
  388.  )Else (%\n%
  389.   (For %%g in (!obj!)Do (%\n%
  390.    Set "oStr=%%~g"%\n%
  391.    ^< nul Set /P "=%\E%[?25l%\E%[!Obj.Color!m%\E%[!oStr!%\E%[0m"%\n%
  392.   )) ^>"%TEMP%\_Obj_.dat" %\n%
  393.   Type "%TEMP%\_Obj_.dat" ^> Con%\n%
  394.  )
  395. rem /* Variables used to convert Direction to Vector in Move.Sprite Macro*/
  396. =============================================================================
  397. rem /* Inverse Player movements for lazy AI control */
  398.  Set ".Left=Right"&Set ".Right=Left"&Set ".Up=Down"&Set ".Down=Up"
  399. rem /* Clockwise rotation for use with rotate.sprite macro */
  400.  Set "rLeft=up"&Set "rRight=down"&Set "rUp=right"&Set "rDown=left"
  401.  Set "Left={x}{-}"& Set "Right={x}{+}"& Set "Up={y}{-}"& Set "Down={y}{+}"
  402.  Set "{x}{-}=Left"& Set "{x}{+}=Right"& Set "{y}{-}=Up"& Set "{y}{+}=Down"
  403. ::: Move.Sprite macro will slow a gameloop cycle more as Sprite size and quantity of sprites to be moved increases.
  404. ::: rem /* Move.Sprite macro. Usage:
  405.  Set "Move.Sprite.Usage=%%Move.Sprite:Obj=SPRITEVARNAME%%{Y|X}{-|+}{Optional-Collision Chars}{Optional-Capture Characters}"
  406. ::: User info:
  407. ::: ** Collision Detection is CASE INSENSITIVE as substring modification is used to compare Characters assigned to
  408. :::  }Y;X array against Args for Collision and capture and the Border Character.
  409. :::  Y;X format of cmd.exe uses 1;1 as screen home
  410. :::  Moving a sprite adjusts the sprite 0;0 position along Y or X axis in +1|-1 increments for each cell
  411. :::   - 2 lists of cells are maintained with the obj {spritevarname} being iterated over to undefine each old cell after a valid move.
  412. ::      The Sub list is then iterated over, redefining each new cell with its value
  413. :::  Movement is constrained by the .Ymin;.Xmin amd .Ymax;.Xmax boundaries defined within the Background.Border macro.
  414. :::  When adjusting a sprites 0;0 Each cell is adjusted In accordance with:
  415. :::  Increase Y  ; Move Down
  416. :::  Decreases Y ; Move Up
  417. :::  Increase X  ; Moving Right
  418. :::  Decreases X ; Move Left
  419. :::  Movement is rejected if a collision character is encountered ; Valid=0 ; Obj.Coll=1 ; Obj.Coll=n number of collisions
  420. :::  Movement is allowed if only empty cells are encountered ; Valid=1
  421. :::  Movement is allowed if empty cells or Capture characters encountered ; Obj.capt=1 ; Obj.capt=n number of captures
  422. :::  Args 3 and 4 are optional; Allowing sprites that don't need collision or capture testing to be moved
  423. :::  To ensure correct results; Characters for {Collision}{Capture} testing should be unique to a single test {Collision} OR {Capture}
  424. :::   - Duplicate Characters are rejected.
  425. %=== Move.Sprite RETURN VARIABLES ==========================================%
  426. ::: Return Varname            : Source            : true : false : reference value / Description
  427. =============================================================================
  428. ::: Valid                     : Arg  3            : 1    : 0     : Move Valid [No Collisions] / Invalid [ Obj.Coll GEQ 1 ]
  429. ::: Obj.Coll                  : Arg  3            : 1;n  : 0     : If true ; Move Invalid - Number of Collision characters Object collided with
  430. ::: Obj.Capt                  : Arg  4            : 1;n  : 0     : Number of Capture characters Object captured
  431. ::: Obj.on.surface            : Arg  3            : 1    : 0     : Object is positioned immediately above a collision character
  432. :::                           :                   :      :       :  - Can be used to enact Gravity
  433. ::: Obj.Collide.Type          : Args 3+4          :     N/A      : Last Character Obj.Coll with / capture in defined cell
  434. ::: Obj.Collide.Type[Col][#]  : Arg  3            :     N/A      : Nth Character collided with in defined cell
  435. ::: Obj.Collide.Type[Cap][#]  : Arg  4            :     N/A      : Nth Character captured in defined cell
  436. ::: *** The following return values can be used to guide an NPC sprite to a PC's position
  437. :::     - values are unique to each sprite with the sprites name [ supplied via substring modification ]
  438. :::       used as a perfix
  439. ::: SPRITEVARNAME.mY          : Obj=SPRITEVARNAME :              : Sprite Median Y position of all cells
  440. ::: SPRITEVARNAME.mX          : Obj=SPRITEVARNAME :              : Sprite Median X position of all cells
  441. ::: SPRITEVARNAME.lY          : Obj=SPRITEVARNAME :              : Sprite lowest Y position of all cells
  442. ::: SPRITEVARNAME.lX          : Obj=SPRITEVARNAME :              : Sprite lowest X position of all cells
  443. ::: SPRITEVARNAME.uY          : Obj=SPRITEVARNAME :              : Sprite upper  Y position of all cells
  444. ::: SPRITEVARNAME.uX          : Obj=SPRITEVARNAME :              : Sprite upper  X position of all cells
  445. =============================
  446. :::: Notes regarding GRAVITY:
  447. =============================
  448. :::: Gravity is not built into move.sprite macro as the way gravity is implemented differs depending on a games design
  449. ::: A basic way to enact gravity [ Fall until a surface is encountered ] is supported using the return var SPRITEVARNAME.on.surface
  450. ::: Macros use collision character args of move.sprite and rotate.sprite and Obj.uY+1 position to test if a collision character is
  451. ::: immediately below the sprite and returns 1 {true} or 0 {false}
  452. ::: USAGE example:
  453. ::: Set "SPRITEVARNAME.prv.Dir=!SPRITEVARNAME.Dir!"
  454. ::: If !SPRITEVARNAME.on.Surface! EQU 0 %Move.Sprite:obj=SPRITEVARNAME%!down!{"collision" "characters"}{"capture" "characters"}
  455. ::: Set "SPRITEVARNAME.Dir=!SPRITEVARNAME.prv.Dir!"
  456. ::: saving / restoring sprite direction prior to enacting gravity allows horizontal momentum to be preserved
  457.  Set Move.Sprite=For %%n in (1 2) Do if %%n==2 ( %\n%
  458.   If /I "!Move.Args!" == "" ( %\n%
  459.    Mode 1000 %\n%
  460.    Echo/Error in Level !lvl!!LF!Missing Args for -!LF! %%move.Sprite:!oHASH!=obj%% !LF! Move.Sprite USAGE: %\n%
  461.    Echo/!Move.Sprite.Usage! %\n%
  462.    Pause ^& Endlocal ^& Exit /B 0 %\n%
  463.   ) %\n%
  464.   If /I "!oHASH!" == "Obj" ( %\n%
  465.    Mode 1000 %\n%
  466.    Echo/Error in Level !lvl!!LF!Missing Substituion for -!LF! %%move.Sprite:!oHASH!=obj%%!Move.Args! !LF! Move.Sprite USAGE: %\n%
  467.    Echo/!Move.Sprite.Usage! %\n%
  468.    Pause ^& Endlocal ^& Exit /B 0 %\n%
  469.   ) %\n%
  470.   If /I "!Obj!" == "" ( %\n%
  471.    Mode 1000 %\n%
  472.    Echo/Error in Level !lvl!!LF!Sprite: Obj Is not defined. !LF! %%move.Sprite:!oHASH!=obj%%!Move.Args! !LF! Move.Sprite USAGE: %\n%
  473.    Echo/!Move.Sprite.Usage! %\n%
  474.    Pause ^& Endlocal ^& Exit /B 0 %\n%
  475.   ) %\n%
  476.   Set "Sub=" %\n%
  477.   (For /F "Tokens=1 Delims==" %%l in ('Set Obj.Collide.Type')Do Set "%%l=") 2^> nul %\n%
  478.   Set /A "valid=1,Obj.capt=0,Obj.Coll=0" %\n%
  479.   For /F "Tokens=1,2,3,4,5 Delims={}" %%G in ("!Move.Args!")Do ( %\n%
  480.    Set "axis=%%~G" %\n%
  481.    If "%%~H" == "" ( %\n%
  482.     CLS ^& Mode 1000 %\n%
  483.     Echo/Error in Level !lvl!!LF!Missing Args for - !LF! %%move.Sprite:!oHASH!=Obj%%!Move.Args! !LF! Move.Sprite USAGE: %\n%
  484.     Echo/!Move.Sprite.Usage!%\n%
  485.     Pause ^& Endlocal ^& Exit /B 0 %\n%
  486.    ) %\n%
  487.    Set "vector=%%~H" %\n%
  488.    Set "nDir=!{%%~G}{%%~H}!" %\n%
  489.    If not "%%~I" == "" (Set "Collide=%%I")Else ( Set "Collide=" ) %\n%
  490.    If not "%%~J" == "" (Set "Flag=%%J")Else ( Set "Flag=" ) %\n%
  491.    If not "%%~k" == "" (Set "restore=%%~K")Else ( Set "restore=" ) %\n%
  492.   ) %\n%
  493.   For %%V in (!Collide!)Do For %%T in (!Flag!)Do If "%%~V" == "%%~T" ( %\n%
  494.     CLS ^& Mode 1000 %\n%
  495.     Echo/Error in Level !lvl! - duplicates NOT Permitted. Args 3 and 4 invalid for:!LF! %%move.Sprite:!oHASH!=obj%%!Move.Args!!LF!Arg 3:{!Collide!}!LF!Arg 4:{!Flag!}!LF! Move.Sprite USAGE: %\n%
  496.     Echo/!Move.Sprite.Usage!%\n%
  497.     Pause ^& Endlocal ^& Exit /B 0 %\n%
  498.   ) %\n%
  499.   Set "tArg=!Move.Args:~0,3!" %\n%
  500.   For %%r in ("x" "y")Do Set "tArg=!tArg:%%~r=!" %\n%
  501.   If not "!tArg!" == "{}" ( %\n%
  502.     CLS ^& Mode 1000 %\n%
  503.     Echo/Error in Level !lvl! - Arg 1 Move Axis - !Move.Args:~0,3! invalid for:!LF! %%move.Sprite:!oHASH!=Obj%%!Move.Args!!LF!Invalid Arg 1: {!Axis!}!LF! Move.Sprite USAGE: %\n%
  504.     Echo/!Move.Sprite.Usage! %\n%
  505.     Pause ^& Endlocal ^& Exit /B 0 %\n%
  506.   )%\n%
  507.   Set "tArg=!Move.Args:~3,3!" %\n%
  508.   For %%r in ("-" "+")Do Set "tArg=!tArg:%%~r=!" %\n%
  509.   If not "!tArg!" == "{}" ( %\n%
  510.     CLS ^& Mode 1000 %\n%
  511.     Echo/Error in Level !lvl! - Arg 2 Move Vector - !Move.Args:~0,3! invalid for:!LF! %%move.Sprite:!oHASH!=Obj%%!Move.Args!!LF!Invalid - Arg 2: {!Vector!}!LF! Move.Sprite USAGE: %\n%
  512.     Echo/!Move.Sprite.Usage! %\n%
  513.     Pause ^& Endlocal ^& Exit /B 0 %\n%
  514.   ) %\n%
  515.   If /I "!axis!" == "X" ( %\n%
  516.    For %%g in (!obj!) Do ( %\n%
  517.     For /F "Tokens=1,2,3 Delims=;H" %%i in ("%%~g") Do ( %\n%
  518.      Set /A "cx=%%j!vector!1,oy=%%i,ox=%%j" %\n%
  519.      Set "cTkn=%%~g" %\n%
  520.      Set "cTkn=!cTkn:*H=!" %\n%
  521.      For /F "Delims=" %%o in ("!cx!") Do ( %\n%
  522.       Set "q.cell=" %\n%
  523.       Set "q.cell=!}%%i;%%o!" %\n%
  524.       If not "!q.Cell!" == "" (Set "q.Cell=!q.cell:~-1!") %\n%
  525.       For /F "Delims=" %%K in ("!q.Cell!") Do ( %\n%
  526.        If not "!Collide:%%K=!" == "!Collide!" ( %\n%
  527.         Set "Valid=0" %\n%
  528.         Set /A "Obj.Coll+=1 + 0" %\n%
  529.         Set "Obj.Collide.Type[Col][!Obj.Coll!]=%%K" %\n%
  530.         Set "Obj.Collide.Type=%%~K" %\n%
  531.        ) %\n%
  532.        If "%%K" == "!.Char!" ( %\n%
  533.         Set "Valid=!?Border.Fatal!" %\n%
  534.         Set /A "Obj.Coll+=1 + 0" %\n%
  535.         Set "Obj.Collide.Type[Col][!Obj.Coll!]=%%K" %\n%
  536.         Set "Obj.Collide.Type=%%K" %\n%
  537.        ) %\n%
  538.        If not "!Flag:%%K=!" == "!Flag!" ( %\n%
  539.         %COMMENT:{i}= Resets capture variable to no capture if collision true ; move was rejected \n%
  540.         If "!Valid!" == "1" ( %\n%
  541.          Set /A "Obj.Capt+=1 + 0" %\n%
  542.          Set "Obj.Collide.Type[Cap][!Obj.Capt!]=%%K" %\n%
  543.          Set "Obj.Collide.Type=%%K" %\n%
  544.         )Else ( %\n%
  545.          Set "Obj.Capt=0" %\n%
  546.          (For /F "tokens=1,2 Delims==" %%1 in ('Set Obj.Collide.Type[Cap]')Do Set "%%1=") 2^> nul %\n%
  547.         ) %\n%
  548.        ) %\n%
  549.       ) %\n%
  550.       If "!valid!" == "1" (Set "Sub=!Sub!"%%i;%%oH!cTKN!",") %\n%
  551.    )))) ELSE ( %\n%
  552.    For %%g in (!obj!) Do ( %\n%
  553.     For /F "Tokens=1,2,3 Delims=;H" %%i in ("%%~g") Do ( %\n%
  554.      Set /A "cy=%%i!vector!1,oy=%%i,ox=%%j" %\n%
  555.      Set "cTkn=%%~g" %\n%
  556.      Set "cTkn=!cTkn:*H=!" %\n%
  557.      For /F "Delims=" %%o in ("!cy!") Do ( %\n%
  558.       Set "q.cell=" %\n%
  559.       Set "q.cell=!}%%o;%%j!" %\n%
  560.       If not "!q.Cell!" == "" (Set "q.Cell=!q.cell:~-1!") %\n%
  561.       For /F "Delims=" %%K in ("!q.Cell!") Do ( %\n%
  562.        If not "!Collide:%%K=!" == "!Collide!" ( %\n%
  563.         Set "Valid=0" %\n%
  564.         Set /A "Obj.Coll+=1 + 0" %\n%
  565.         Set "Obj.Collide.Type[Col][!Obj.Coll!]=%%K" %\n%
  566.         Set "Obj.Collide.Type=%%~K" %\n%
  567.        ) %\n%
  568.        If "%%K" == "!.Char!" ( %\n%
  569.         Set "Valid=!?Border.Fatal!" %\n%
  570.         Set /A "Obj.Coll+=1 + 0" %\n%
  571.         Set "Obj.Collide.Type[Col][!Obj.Coll!]=%%K" %\n%
  572.         Set "Obj.Collide.Type=%%K" %\n%
  573.        ) %\n%
  574.        If not "!Flag:%%K=!" == "!Flag!" ( %\n%
  575.         If "!Valid!" == "1" ( %\n%
  576.          Set /A "Obj.Capt+=1 + 0" %\n%
  577.          Set "Obj.Collide.Type[Cap][!Obj.Capt!]=%%K" %\n%
  578.          Set "Obj.Collide.Type=%%K" %\n%
  579.         )Else ( %\n%
  580.          Set "Obj.Capt=0" %\n%
  581.          (For /F "tokens=1,2 Delims==" %%1 in ('Set Obj.Collide.Type[Cap]')Do Set "%%1=") 2^> nul %\n%
  582.         ) %\n%
  583.        ) %\n%
  584.       ) %\n%
  585.       If "!valid!" == "1" (Set "Sub=!Sub!"%%o;%%jH!cTKN!",") %\n%
  586.   ))))%\n%
  587.   If "!valid!" == "1" (%\n%
  588.    Set /A "Obj.lX=!.Xmax!,Obj.uX=!.Xmin!,Obj.lY=!.Ymax!,Obj.uY=!.Ymin!" %\n%
  589.    (For %%Q in (!obj!)Do ( %\n%
  590.     For /F "tokens=1,2 Delims=;H" %%1 in ("%%~Q") Do (%\n%
  591.      If not "!}%%~1;%%~2:~-1!" == "!Restore:~-1!" (%\n%
  592.       Set "}%%~1;%%~2=" %\n%
  593.       ^< nul Set /P "=%\E%[%%~1;%%~2H %\E%[0m" %\n%
  594.      )Else ( %\n%
  595.       Set "}%%~1;%%~2=%%~1;%%~2H!Restore!" %\n%
  596.       ^< nul Set /P "=%\E%[%%~1;%%~2H%\E%[!Restore!" %\n%
  597.      ) %\n%
  598.    )))^>%Foreground% %\n%
  599.    Set "Obj.on.surface=0" %\n%
  600.    Set "Obj.Surface=" %\n%
  601.    Set "obj.on.fatal=" %\n%
  602.    (For %%S in (!Sub!)Do ( %\n%
  603.     For /F "tokens=1,2,3* Delims=;H" %%3 in ("%%~S") Do (%\n%
  604.      If %%3 GTR !Obj.uY! (Set "Obj.uY=%%3") %\n%
  605.      If %%3 LSS !Obj.lY! (Set "Obj.lY=%%3") %\n%
  606.      If %%4 GTR !Obj.uX! (Set "Obj.uX=%%4") %\n%
  607.      If %%4 LSS !Obj.lX! (Set "Obj.lX=%%4") %\n%
  608.      Set "cTKN=%%~S" %\n%
  609.      Set "cTKN=!cTKN:*H=!" %\n%
  610.      Set "}%%~3;%%~4=%%~3;%%~4H!cTKN!" %\n%
  611.      Echo/%\E%[%%~3;%%~4H%\E%[!Obj.Color!m!cTKN!%\E%[0m%\n%
  612.    ))) ^>^>%Foreground% %\n%
  613.    Set /A Below.Sprite=!Obj.uY!+1 %\n%
  614.    For /L %%a in (!Obj.lX! 1 !Obj.uX!)Do For %%b in (!Below.Sprite!)Do For %%c in (!.Char! !Collide! !Flag!)Do ( %\n%
  615.     If /I "!}%%b;%%a:~-1!" == "%%~c" ( %\n%
  616.      Set "Obj.on.surface=1" %\n%
  617.      %COMMENT:{i}= All cells sprite rests on returned in list var below. Use list to differentiate surface types - IE ground ; lava ; water \n%
  618.      Set "Obj.surface=!Obj.surface!"!}%%b;%%a!"," %\n%
  619.      %!!%
  620.      If "!fatal.%%c!" == "1" (Set /A "obj.on.fatal+=1 + 0") %\n%
  621.     ) %\n%
  622.    ) %\n%
  623.    If "!Obj.on.Fatal!" == "!Obj.Width!" (Set "obj.State=dead") %\n%
  624.    TYPE %Foreground% %\n%
  625.    If not "!Obj.Collide.Type!" == "!.Char!" Set "obj=!Sub!" %\n%
  626.    Set /A "obj.mY=(!obj.lY!+!obj.uY!)/2,obj.mX=(!obj.lX!+!obj.uX!)/2" %\n%
  627.    Set "Obj.Dir=!nDir!" %\n%
  628.   ) %\n%
  629.  )Else Set Move.Args=
  630. =============================================================================
  631.  Set Get.Cell.Adjacent=For %%n in (1)Do ( %\n%
  632.   If /I "!oHASH!" == "Obj" ( %\n%
  633.    Mode 1000 %\n%
  634.    Echo/Error in Level !lvl!!LF!Missing Substituion for -!LF! %%Get.Cell.Adjacent:!oHASH!=Obj%% !LF! Usage: %%Get.Cell.Adjacent:!oHASH!=SPRITEVARNAME%% %\n%
  635.    Pause ^& Endlocal ^& Exit /B 0 %\n%
  636.   ) %\n%
  637.   Set "Obj.Left=" %\n%
  638.   Set "Obj.Right=" %\n%
  639.   Set "Obj.Up=" %\n%
  640.   Set "Obj.Down=" %\n%
  641.   For %%z in (!Obj!)Do For /F "Tokens=1,2 Delims=;H" %%K in ("%%~z")Do ( %\n%
  642.    Set /A "alX=%%L-1,arX=%%L+1,auY=%%K-1,adY=%%K+1" %\n%
  643.    For %%v in ("%%K;!alX!")Do if not "!}%%~v!" == "" (Set "Obj.Left=!}%%~v:~-1!") %\n%
  644.    For %%v in ("%%K;!arX!")Do if not "!}%%~v!" == "" (Set "Obj.Right=!}%%~v:~-1!") %\n%
  645.    For %%v in ("!auY!;%%L")Do if not "!}%%~v!" == "" (Set "Obj.Up=!}%%~v:~-1!") %\n%
  646.    For %%v in ("!adY!;%%L")Do if not "!}%%~v!" == "" (Set "Obj.Down=!}%%~v:~-1!") %\n%
  647.   ) %\n%
  648.  )
  649. =============================================================================
  650. ::: Rotate.Sprite Macro - rotates a sprite cells and direction clockwise
  651. rem --- [ Horizontal flip followed by mirror to simulate 90 degree rotation. ]
  652.  Set "Rotate.Sprite.Usage=For %%%%D in ('!SPRITEVARNAME.Dir!')Do %%Rotate.Sprite:Obj=SPRITEVARNAME%%{!r%%%%D!}{Collision character list}{capture character list}"
  653.  Set Rotate.Sprite=For %%n in (1 2) Do if %%n==2 ( %\n%
  654.   (For %%s in ("cTkn" "ny" "nx" "oy" "ox" "iy" "ix" "Obj.Collide.Type") Do For /F "Tokens=1,2 Delims==" %%G in ('Set "%%~s"')Do Set "%%~G=") 2^> nul %\n%
  655.    If /I "!oHASH!" == "Obj" ( %\n%
  656.     Mode 1000 %\n%
  657.     Echo/Error in Level !lvl!!LF!Missing Substituion for -!LF! %%Rotate.Sprite:!oHASH!=Obj%%!rVector! !LF! Rotate.Sprite USAGE: %\n%
  658.     Echo/!Rotate.Sprite.Usage! %\n%
  659.     Pause ^& Endlocal ^& Exit /B 0 %\n%
  660.    ) %\n%
  661.    If /I "!Obj!" == "" ( %\n%
  662.     Mode 1000 %\n%
  663.     Echo/Error in Level !lvl!!LF!Sprite: Obj Is not defined. !LF! %%Rotate.Sprite:!oHASH!=obj%%!rVector! !LF! Move.Sprite USAGE: %\n%
  664.     Echo/!Rotate.Sprite.Usage! %\n%
  665.     Pause ^& Endlocal ^& Exit /B 0 %\n%
  666.    ) %\n%
  667.    If /I "!Obj.Dir!" == "" ( %\n%
  668.     CLS ^& Mode 1000 %\n%
  669.     Echo/Error in Level !lvl!!LF! Rotate.Sprite requires Obj.Dir to be defined prior to expansion!LF! %%Rotate.Sprite:!oHASH!=obj%%!rVector! !LF! Rotate.Sprite USAGE: %\n%
  670.     Echo/!Rotate.Sprite.Usage! %\n%
  671.     Pause ^& Endlocal ^& Exit /B 0 %\n%
  672.    ) %\n%
  673.   Set "Sub=" %\n%
  674.   %COMMENT:{i}= Determine lower mid and upper median values for each cells position in the sprite \n%
  675.   %COMMENT:{i}= Determine sprite centre offset according to odd / even spritewidth \n%
  676.   Set /A "midX=500,midY=500,{I}=0,rValid=1,Obj.Coll=0,Obj.capt=0" %\n%
  677.   For %%g in (!obj!) Do If not "%%~g" == "" ( %\n%
  678.    Set /A "{I}+=1 + 0" %\n%
  679.    For /F "Tokens=1,2,3* Delims=;H" %%I in ("%%~g") Do ( %\n%
  680.     Set /A "iy!{I}!=%%~I" %\n%
  681.     Set /A "ix!{I}!=%%~J" %\n%
  682.     Set "cTKN!{I}!=%%~g" %\n%
  683.     For %%z in (!{I}!)Do Set "cTKN!{I}!=!cTKN%%z:*H=!" %\n%
  684.    ) %\n%
  685.   ) %\n%
  686.   For /L %%i in (1 1 !{I}!) do For %%A in ("!iy%%i!;!ix%%i!")Do ( %\n%
  687.    For /F "Tokens=1,2 Delims=;" %%X in ("%%~A") Do ( %\n%
  688.     Set /A "oY=%%~X" %\n%
  689.     Set /A "oX=%%~Y" %\n%
  690.    ) %\n%
  691.    If !oY! LSS !midY! Set /A "midY=!oY!" %\n%
  692.    If !oX! LSS !midX! Set /A "midX=!oX!" %\n%
  693.   ) %\n%
  694.   Set "pixel=0" %\n%
  695.   For /L %%i in (1 1 !{I}!) do For %%B in ("!iy%%i!;!ix%%i!")Do ( %\n%
  696.    Set /A "pixel+=1" %\n%
  697.    For /F "Tokens=1,2 Delims=;" %%r in ("%%~B") Do ( %\n%
  698.     Set /A "ny!pixel!=(%%~s-!midX!)+!midY!,nx!pixel!=(%%~r-!midY!)+!midX!" %\n%
  699.    ) %\n%
  700.   ) %\n%
  701.   Set "pixel=0" %\n%
  702.   Set /A "lmidX=500,umidX=0" %\n%
  703.   For /L %%i in (1 1 !{I}!) do For %%C in (!nx%%i!) Do ( %\n%
  704.    If %%C LSS !lmidX! (Set /A "lmidX=%%C") %\n%
  705.    If %%C GTR !umidX! (Set /A "umidX=%%C") %\n%
  706.   ) %\n%
  707.   Set /A "Obj.Width=!umidX!-!lmidX!" %\n%
  708.   For /L %%i in (1 2 19)Do If !Obj.Width! EQU %%i Set "Centre=0" %\n%
  709.   For /L %%i in (0 2 20)Do If !Obj.Width! EQU %%i Set "Centre=1" %\n%
  710.   Set /A "Obj.Width+=1" %\n%
  711.   if !umidX!==!lmidX! Set "Centre=0" %\n%
  712.   Set /A "Mid.X=( !lmidX! + !umidX! ) / 2" %\n%
  713.   For /L %%i in (1 1 !{I}!) do For %%X in (!nx%%i!) Do ( %\n%
  714.    Set /A "pixel=!pixel! + 1" %\n%
  715.    Set /A "nx!pixel!=%%X + !centre!" %\n%
  716.    IF %%X LSS !Mid.X! (Set /A "nx!pixel!= %%X + ((!Mid.X!-%%X) * 2) + !centre!") %\n%
  717.    IF %%X GTR !Mid.X! (Set /A "nx!pixel!= %%X - ((%%X-!Mid.X!) * 2) + !centre!") %\n%
  718.   ) %\n%
  719.   For /F "Tokens=1,2,3,4 Delims={}" %%o in ("!rVector!") Do ( %\n%
  720.    Set "cDir=%%o" %\n%
  721.    Set "Flag=%%q" %\n%
  722.   ) %\n%
  723.   For /L %%i in (1 1 !{I}!)Do ( %\n%
  724.    for %%c in ("!ny%%i!;!nx%%i!")Do If not "!}%%~c!" == "" ( %\n%
  725.     %COMMENT:{i}= Perform collision arg character testing \n%
  726.     %COMMENT:{i}= Collision Character Args should be doubleqouted \n%
  727.     For /F "Tokens=2 Delims={}" %%m in ("!rVector!")Do Set "Collide=%%m" %\n%
  728.     For %%v in (!Collide!) Do If not "!}%%~c!" == "" ( %\n%
  729.      Set "KO=!}%%~c:%%~v=!" %\n%
  730.      If Not "!}%%~c!" == "!KO!" (%\n%
  731.       Set "rValid=0" %\n%
  732.       Set "Obj.Collide.Type=%%~v" %\n%
  733.       Set /A "Obj.Coll+=1" %\n%
  734.       Set "Obj.Collide.Type[Col][!Obj.Coll!]=%%~v" %\n%
  735.      ) %\n%
  736.     ) %\n%
  737.    ) %\n%
  738.   ) %\n%
  739.   If "!rValid!" == "1" ( %\n%
  740.    Set "Obj.Dir=!cDir!"%\n%
  741.    %COMMENT:{i}= Rebuild Object cell string on succesful move ; test cells for flagged capture characters \n%
  742.    For /L %%i in (1 1 !{I}!) do ( %\n%
  743.     Set "Sub=!Sub!"!ny%%i!;!nx%%i!H!cTkn%%i!"," %\n%
  744.     %COMMENT:{i}= Perform capture arg character testing \n%
  745.     For %%P in (!Flag!)Do for %%v in ("!ny%%i!;!nx%%i!")Do If Not "!}%%~v!" == "" ( %\n%
  746.      Set "flag.C=!}%%~v:%%~P=!" %\n%
  747.      Set "flag.Cell=!}%%~v!" %\n%
  748.      If Not "!flag.Cell!" == "!flag.C!" ( %\n%
  749.       Set /A "Obj.capt+=1 + 0" %\n%
  750.       Set "Obj.Collide.Type=!cTkn%%i:~-1!" %\n%
  751.       Set "Obj.Collide.Type[Cap][!Obj.capt!]=!cTkn%%i:~-1!" %\n%
  752.      ) %\n%
  753.     ) %\n%
  754.    ) %\n%
  755.    %COMMENT:{i}= Output whitespace to clear Objects previous cell positions from screen to foreground file [overwrite] \n%
  756.    (For %%Q in (!obj!)Do ( %\n%
  757.     For /F "tokens=1,2 Delims=;H" %%1 in ("%%~Q") Do (%\n%
  758.      Set "}%%1;%%2=" %\n%
  759.      Echo/%\E%[%%1;%%2H %\n%
  760.    )))^>%Foreground% %\n%
  761.    Set "Obj.on.surface=0" %\n%
  762.    Set "Obj.Surface=" %\n%
  763.    Set "obj.on.fatal=" %\n%
  764.    %COMMENT:{i}= Output [append] Objects new Cell positions to foreground file \n%
  765.    (For %%S in (!Sub!)Do ( %\n%
  766.     For /F "tokens=1,2,3 Delims=;H" %%3 in ("%%~S") Do (%\n%
  767.      Set "cTKN=%%~S" %\n%
  768.      Set "cTKN=!cTKN:*H=!" %\n%
  769.      Set "}%%3;%%4=%%3%!!%%4H!cTKN!" %\n%
  770.      Echo/%\E%[%%3;%%4H%\E%[!Obj.Color!m!cTKN!%\E%[0m%\n%
  771.    ))) ^>^>%Foreground% %\n%
  772.    %COMMENT:{i}= type the output file to console \n%
  773.    TYPE %Foreground% %\n%
  774.    Set /A Below.Sprite=!Obj.uY!+1 %\n%
  775.    For /L %%a in (!Obj.lX! 1 !Obj.uX!)Do For %%b in (!Below.Sprite!)Do For %%c in (!.Char! !Collide! !Flag!)Do ( %\n%
  776.     If /I "!}%%b;%%a:~-1!" == "%%~c" ( %\n%
  777.      Set "Obj.on.surface=1" %\n%
  778.      %COMMENT:{i}= All cells sprite rests on returned in list var below. Use list to differentiate surface types - IE ground ; lava ; water \n%
  779.      Set "Obj.surface=!Obj.surface!"!}%%b;%%a!"," %\n%
  780.      %!!%
  781.      If "!fatal.%%c!" == "1" (Set /A "obj.on.fatal+=1 + 0") %\n%
  782.     ) %\n%
  783.    ) %\n%
  784.    If "!Obj.on.Fatal!" == "!Obj.Width!" (Set "obj.State=dead") %\n%
  785.    %COMMENT:{i}= Update Object value \n%
  786.    Set "obj=!Sub!" %\n%
  787.    Set "Sub=" %\n%
  788.   ) %\n%
  789.  )Else Set rVector=
  790. ========================================================================================================
  791. ::: Macro's for using the Music system included in the Games_By_T3RRY archive
  792. ::: PlayMusic.Bat creates a vbs file to launch music files using valid parameters for track path, volume and loop t/f [1/0]
  793. ::: StopMusic.Bat uses taskkill to end any active vbs Wscripts
  794. ::: GameMonitor.bat creates a vbs that monitors the cmd.exe process and launches StopMusic.Bat when the console is closed
  795. ::: ensuring the music is stopped even when the user closes the console with the close button
  796. ::: Once launched, StopMusic.bat Deletes any vbs scripts in the game folder, except Monitor.vbs if the game is still running
  797.  Set "Play.Music=If Exist "%~dp0Components\PlayMusic.bat" For %%n in (1 2)Do if %%n==2 (For /F "Tokens=1,2,3 Delims={}" %%G in ("!Music.Args!")Do (Call "%~dp0Components\PlayMusic.bat" "%%~G" %%H %%I ))else Set Music.Args="
  798.  Set "Stop.Music=If Exist "%~dp0Components\StopMusic.bat" (Call "%~dp0Components\StopMusic.Bat" running 2> nul )"
  799.  Set "Monitor.Game=Call "%~dp0Components\Gamemonitor.bat" start 2> nul"
  800. ========================================================================================================
  801. ::: Coming Soon?
  802. ::: Set "Sprite.Shoot.Usage=%%Sprite.Shoot:Obj=SPRITEVARNAME%%{Y|X}{-|+}{INTEGER-Shot.Len}{Collision Characters}{ASCII_Character}"
  803. ::: Use Array Macros to define Bullet Origin ; Vector. IE... For %%D in (!Dir!)Do !Shot.%%D!
  804. :# Shot is orientation dependent ; Shoots along Arg 1 {Y|X} from:
  805. :# Up = {Obj.lY - 1;Obj.mX} ; Down = {Obj.uY + 1;Obj.mX} ; Left = {Obj.uX - 1;Obj.mY} ; Right = {Obj.uX + 1;Obj.mX}
  806. :# Test macro input and substitution
  807. :# Clear definitions of l} ; r} ; Shot.Obj.Collide.Type ; Collide
  808. :# For each cell in shot.len Do If not collide = true ;
  809. :#  If defined l}Y;X assign to r}Y;X ; clone next }Y;X in dir to l}Y;X
  810. :#  Advance shot and display of Arg 5 character ;  replace r}Y;X cell output [ previous cells state ] ; define l}Y;X
  811. :#  test collision against arg 4 characters ; Flag if true
  812. :# ;Else Return Shot.Obj.Collide.Type
  813. ::: Alternate approach create a macro that on keypress for shoot is expanded to:
  814. ::: Calculate a positive offset according to the above orientation
  815. ::: Use Calculated Y;X offset to define a Bullet Sprite with Def.Multicol.Sprite
  816. ::: Use a loop... :
  817. ::: For /L in (1 1 Shot.Len)Do If not "!Valid!" == "0" (
  818. ::: Test next Cell Coordinates ; Flag - Valid - Obj.capt - Obj.Coll states
  819. ::: %Move.Sprite:Obj=Bullet%!SHOOTINGSPRITESVARNAME.Dir!{Collide Characters}{Capture Characters}
  820. :::  If Not "!Obj.capt!" == "" (
  821. :::   REM ON CAPTURE COMMANDS
  822. :::   REM The bullet has hit a capture target
  823. :::   REM ? options:
  824. :::    - Terminate bullet travel ?
  825. :::    - Continue travel up to ? 2 cells [ piercing fire ]
  826. :::    - Flag Capture cell as hit [ Cell specific hit count ; Flag shot.capture = true ]
  827. :::    - Flag Collide cell as hit [ Cell specific hit count ; Flag shot.collide = true ]
  828. :::    - ? Modify Move.Sprite / Rotate.Sprite to test Cell hit state and transfer state to new cell
  829. :::  )
  830. ::: ) Else ( REM ON COLLIDE COMMANDS - [ The bullet Can Travel no futher. Undefine Bullet Sprite ; Clear Cell ] )
  831. ::: ... to Move.Sprite Obj=Bullet n times supplying collision / capture args
  832. ::: Within the for /L loop enact conditional tests on Obj.Collide.Type variable
  833. ========================================================================================================
  834. If "%~1" == "/Q" Exit /B 0
  835.  CLS & Mode 1000 & Title %~n0 by T3RRY
  836.  Echo/%\E%[7;33m%~1%\E%[0m%\E%!!%\E%!!%\E%!!%~nx0%\E%[0m%\E%[48;2;100;0;70m by T3RRY.%\E%[K
  837.  Echo/%\E%[31m%\E%[48;2;0;120;60m ** An object oriented Game engine for Batch games **%\E%[K
  838.  Echo/%\E%[0m      %\E%[37myoutube: %\E%[36mhttps://www.youtube.com/channel/UCo3tS26Eg-ITbdNgWhB0MRQ
  839.  Echo/      %\E%[37mDosTips: %\E%[34mhttps://www.dostips.com/forum/memberlist.php?mode=viewprofile^&u=10296
  840.  Echo/ %\E%[37mStackoveflow: %\E%[36mhttps://stackoverflow.com/users/12343998/t3rr0r
  841.  Echo/     %\E%[37mpastebin: %\E%[34mhttps://pastebin.com/u/T3RRYT3RR0R%\E%[0m
  842.  Endlocal
  843.  Timeout /T 3 /Nobreak > nul
  844.  Pause
  845. ::: Errorlevel must be reset to 0 when exiting after Getfontsize is invoked
  846. Exit /B 0
  847.  
  848. :TestVT
  849.  Set "VTsupport="
  850.  2> nul (
  851.   More < "%~f0:VTsupport" > nul && (
  852.    Exit /b 0
  853.   ) || (
  854.    <Nul Set /P "=Verifying Compatability %\E%[2D"
  855.    for /F "delims=" %%a in ('"PowerShell $console=$Host.UI.RawUI; $curPos=$console.CursorPosition; $rect=new-object System.Management.Automation.Host.Rectangle $curPos.X,$curPos.Y,$curPos.X,$curPos.Y; $BufCellArray=$console.GetBufferContents($rect); Write-Host $BufCellArray[0,0].Character;"') do (
  856.     Cls
  857.     If "%%a" == "y" (
  858.      (Echo(true) >"%~f0:VTsupport"
  859.      Exit /b 0
  860.     )else (
  861.      Echo(Virtual terminal sequences not enabled on your system. This program will not execute as intended.
  862.      Exit /b 1
  863.  ))))
  864. Exit /b 2
Add Comment
Please, Sign In to add comment