(Batch) Is there a way to make clickable buttons? - batch-file

Hi I was wondering if there is a easy way to make a clickable text buttons in a batch file. I seen people using them so i'm quite sure it is possible.
I would like to make a button to simply activate a goto test1 command.

Yes. It is.There are few options.I'll start with the first one and will edit the answer with more.
1) Using IExpress. Here's a link to example Yes/No pop-up.You can handle the result with FOR /F and decide what to do. At the beginning of the script you can set a title and question :
for /f %%a in ('iexpYNButton.bat') do set ans=%%a
if %ans% equ yes (
do something
)
2) With MSHTA - this is again Yes/No pop-up
for /f "tokens=3 delims=: " %%a in ('choose.bat') do #set ans=%%a
if %ans% equ yep (
do something
)

Here's a method that uses Carlos Aguilera's BG.exe (included) to wait for and read mouse clicks.
A number of functions and macros are included to simplify creation of custom buttons and their use. A usage example is included at the :main label at the end of the script.
#Echo off & CD /d "%~dp0"
CLS
:# Based on: https://www.dostips.com/forum/viewtopic.php?f=3&t=9222
:# example begins at 'main' label at end of file
If not exist "%TEMP%\Games_By_T3RRY\" MD "%TEMP%\Games_By_T3RRY"
If not exist "%TEMP%\Games_By_T3RRY\BG.exe" Certutil -decode "%~f0" "%TEMP%\Games_By_T3RRY\BG.exe" > nul
Set BG.exe="%TEMP%\Games_By_T3RRY\BG.exe"
Set "reg.restore=(Call )"
:# disable QuickEdit if enabled. Restored at :end label if disabled by script
reg query HKEY_CURRENT_USER\console\ /v Quickedit | findstr.exe /l "0x1" > nul && (
(Reg add HKEY_CURRENT_USER\console\ /v QuickEdit /t REG_DWORD /d 0x0 /f) > nul
Set "reg.restore=Reg add HKEY_CURRENT_USER\console\ /v QuickEdit /t REG_DWORD /d 0x1 /f"
)
For /f "tokens=4 Delims=: " %%C in ('CHCP')Do Set "active.cp=%%C"
chcp 65001 > nul
For /f %%e in ('echo prompt $E^|cmd')Do Set \E=%%e
If "!!" == "" (Echo DelayedExpansion must not be enabled before macro definitions&Pause & Exit /B 1)
:# Alt: %Buffer:#=Alt% Main: %Buffer:#=Main%
Set "Buffer=<nul set /p "=%\E%[?1049!#!""
Set "Alt=h"
Set "Main=l"
:# button sound fx. disable by undefining buttonsfx below ; prior to definition of OnCLick macro
Set "buttonsfx=On"
%BG.exe% Play "%WINDIR%\Media\Windows Feed Discovered.wav"
Set "OnClick=(Call )"
Set "OnType=(Call )"
If defined buttonsfx (
For /f "Delims=" %%G in ('Dir /b /s "%WINDIR%\SystemApps\*KbdKeyTap.wav"')Do If exist "%%~G" Set "OnClick=(Start /b "" %BG.exe% Play "%%~G")"
Set "OnType=(start /b "" %BG.exe% Play "%WINDIR%\Media\Windows Feed Discovered.wav")"
)
:# return button click coords in c{pos} variable n Y;X format
Set "GetClick=Set "Clicked="& Set "ValidClick="& for /f "tokens=1,2" %%X in ('%BG.exe% mouse')Do (Set /A "c{pos}=%%X+1"&Set "c{pos}=%%Y;!c{Pos}!")"
:# test substituted button # if click is within btn[#][coords] defines variables: Clicked [value eq string] ; ValidClick [value eq button number / undefined]; btn{State}[#] [value eq true/false]
Set "If.Button=For /f "Tokens=1,2 Delims=;" %%X in ("!c{pos}!")Do If not "!btn[#][Coords]:[%%Y;%%X]=!" == "!btn[#][Coords]!" Set "Clicked=!btn[#][string]!"& Set "ValidClick=#"& (If defined btn[#]{t} Call :Toggle #)& "
:# tests all buttons in same way as if.clicked ; exclude a button via substring modification substituting 'exc' for 'button#'
Set "qClicked=(For /l %%i in (1 1 !btns[i]!)Do If not "%%i"=="Exc" For /f "Tokens=1,2 Delims=;" %%X in ("!c{pos}!")Do If not "!btn[%%i][Coords]:[%%Y;%%X]=!" == "!btn[%%i][Coords]!" Set "Clicked=!btn[%%i][string]!"& Set "ValidClick=%%i"& %OnClick% & (If defined btn[%%i]{t} Call :Toggle %%i))& "
:# Id if button is an input bar. Requires additional Args. Optional -f switch forces input
:# Usage: %qInput% <Prompt> [-f]
Set qInput=Set "Input="^& Echo({!Clicked!}^|findstr /RC:"\<[{][ ]*[}]\>" ^> nul ^&^& Call :InputBar !ValidClick!
:# display all buttons
Set "dButtons=For /l %%i In (1 1 !btns[i]!)Do <nul Set /P "=!btn[%%i]!""
:# Undefine all buttons. Use substring modification to exclude a specific button or states from being undefined.
:# IE Preserve button 1: %clrButtons:$EXC=btn[1]%
Set "clrButtons=(For /f "tokens=1 Delims==" %%G In ('Set btn')Do Echo("%%G"|findstr /Lic:"$EXC" || Set "%%G=") 2> nul & CLS"
:# displays all selected button or input values
Set "dValues=For /l %%i in (1 1 !btns[i]!)Do if defined btn{State}[%%i] (set "value=%\E%[0;7m!btn{State}[%%i]:true=%\E%[0;32mtrue!"& Echo(%\E%[33mButton[%%i]%\E%[36m=!value:false=%\E%[0;90mfalse!%\E%[0m)"
:# menu macro for easily creating multiple buttons simultaneously
Set "CHash=Col"
set "menu=Set "m{\c}="& For %%n in (1 2)Do if %%n==2 ((If "!CHash!"=="Col" (Set "m{\c}="&Call:createmenu !Params! 2> nul )Else (Set /A "m{\c}=Col"&Call :Createmenu ^!Params^! 2> nul ))& Set "m{\c}="&Set "m{x}=2")Else Set Params="
==========
Goto :Main
==========
:# FUNCTIONS
====
:end
(%Reg.Restore%) > nul
(Title )
<nul set /p "=%\E%[?25h"
CHCP %active.cp% > nul
Endlocal
Goto :Eof
=================
:Toggle <button#>
If "!btn{State}[%~1]!"=="true" (
<nul set /P "=!btn[%~1]!"
Set "btn{State}[%~1]=false"
)Else (
<nul set /P "=!btn[%~1]:48=7;48!"
Set "btn{State}[%~1]=true"
)
Exit /b 0
:createGrid <Character> <Min> <Max> <FGcol> <BGcol> <BTNcol>
Set "Char=%~1"
For /L %%Y in (%~2 3 %~3)Do For /L %%X in (%~2 3 %~3)Do Call:CreateButton "!Char:~0,1!" %%Y %%X "%~4" "%~5" "%~6" -t
Goto :Eof
==========================================================
:createbutton <string> <y> <x> <FGcol> <BGcol> <BTNcol> -t
:# Arg Structure: 1,2,3 = Mandatory ; 4,5,6 = Optional ; -t = Optional switch. Must be Last arg if present.
:# Button Border ; Recommended font: Lucida Console
:# Codepage: 65001
:# alt 201 alt 205 alt 187 ╔═╗
:# alt 186 space alt 186 ║ ║
:# alt 200 alt 205 alt 188 ╚═╝
Set "l[Y]=!btn[Y]!"
If not "%~2"=="!btn[Y]!" Set /A "btn[Y]=%~2+3"
If "%~3" == "" Exit /b 1
Set /a "btns[i]+=1+0"
Set "btn[%btns[i]%][p]=%~2;%~3"
Set "btn[%btns[i]%][string]=%~1"
If /I "%~4" == "-t" (set "btn[BG]=%\E%[48;2;230;230;200m")Else (If "%~4" == "" (set "btn[BG]=%\E%[48;2;230;230;200m")Else set "btn[BG]=%\E%[38;2;%~4m")
If /I "%~5" == "-t" (set "btn[FG]=%\E%[38;2;;;m")Else (If "%~5" == "" (set "btn[FG]=%\E%[38;2;;;m")Else set "btn[FG]=%\E%[48;2;%~5m")
If /I "%~6" == "-t" (set "btn[Col]=%\E%[90m")Else (If "%~6" == "" (set "btn[Col]=%\E%[90m")Else set "btn[Col]=%\E%[%~6m")
:# defines variable identifying button as toggle button; used by %If.Button% and %qClicked% macros
Echo("%*"|findstr /lic:"-t" > nul && Set "btn[%btns[i]%]{t}=true" || Set "btn[%btns[i]%]{t}="
:# Constrain button creation to console dimensions
For /f "Tokens=1,2 Delims=: " %%G in ('Mode^|findstr /lic:"Columns" /lic:"Lines"')Do (
Set /A "%%G=%%H"
If /I "%%G"=="Columns" ( Set /A "%%G[max]=%%H+%~3+2" )Else Set /A "%%G[max]=%%H"
)
Set "len="& set "s=#%~1" & ( for %%P in (8192 4096 2048 1024 512 256 128 64 32 16 8 4 2 1) do ( if "!s:~%%P,1!" NEQ "" ( set /a "len+=%%P" & set "s=!s:~%%P!" ))) & set /a "btn[%btns[i]%][Len]=len" 2>nul
If !len! GTR !Columns[Max]! (
Echo(Button length exceeds display width. Button width must be LSS than console Columns
Pause
Exit
)
If %~2 GEQ !Lines[Max]! (
Echo(Button height exceeds display height. Button height must be LSS than console Lines
Pause
Exit
)
:# define button click coords and button Upper / lower border display values
:# - border is not defined as clickable.
Set /A "btn{Xmin}=%3+1", "btn{Xmax}=%3+len", "l[X]=btn{Xmax}+2"
Set "btn[%btns[i]%][Len]=" & Set "btn[%btns[i]%][S]=" & Set "btn[%btns[i]%][coords]="
For /l %%i in (!btn{Xmin}! 1 !btn{Xmax}!)Do (
Set /A "btn[%btns[i]%][Len]=%%i-3", "Xoffset=%%i-1"
Set "btn[%btns[i]%][coords]=!btn[%btns[i]%][coords]![%2;!Xoffset!]"
Set "btn[%btns[i]%][Bar]=!btn[%btns[i]%][Bar]!═"
Set "btn[%btns[i]%][S]=!btn[%btns[i]%][S]! "
)
:# define toggle state variable
If defined btn[%btns[i]%]{t} Set "btn{State}[%btns[i]%]=false"
:# Button Graphic. Toggle is effected by substituting Background color VT code 48 with 7;48 to invert button text color.
Set "btn[%btns[i]%]=%\E%[%2;%3H%Btn[col]%%\E%7║%\E%8%\E%A╔!btn[%btns[i]%][Bar]!╗%\E%8%\E%B╚!btn[%btns[i]%][Bar]!╝%\E%8%\E%C%\E%[0m!btn[FG]!!btn[BG]!!btn[%btns[i]%][String]!%\E%[0m%btn[col]%║%\E%[0m%\E%[2E%\E%7"
Set "btn[%btns[i]%][t]=%\E%[0m!btn[FG]!!btn[BG]!!btn[%btns[i]%][String]!%\E%[0m%btn[col]%║%\E%[0m%\E%[K"
Exit /b 0
==========================================
:createMenu <"list" "of" "button strings">
:# Associated Macro: %Menu%
:# - Uses default values for button color schemes m{fg} m{bg} and m{olc}
:# - Define the value of those variables prior to calling :createMenu
:# to the desired color scheme if you wish to override default values.
:# - Defaults to Row 3 [button base] unless m{yo} defined with value to overide default
:# - Defaults to Column 1 if m{x} is not defined with a column value.
:# - m{\c} overides m{x} to value of the new column. %Menu% macro resets m{x} to 2 as default x pos after use.
:# - Button count is reset unless m{\c} is defined using substring modification of
:# - %menu% macro: Ie: %Menu:Col=15% list of options
:# - Int X pos value for new column
:# ! Note: Columns are not automatically padded for options of different lengths.
:# - Use white space in options list to pad options for buttons of equal size.
:# IE: %Menu% " short button " "A Very Much Longer Button"
If not defined m{\c} (
cls
Set "btns[i]="
Set "display.menu=Call Echo("
Set "b{i}=0"
)
If not defined m{yo} (Set "m{y}=3")Else Set /A "m{y}=m{yo}"
If not defined m{fg} (Set "m{fg}=;160;200")
If not defined m{bg} (Set "m{bg}=150;;150")
If not defined m{olc} (Set "m{olc}=33")
If defined m{\c} (Set "m{x}=!m{\c}!")
If not defined m{x} (Set "m{x}=2")
For %%v in (%*)Do (
Call :CreateButton "%%~v" !m{y}! !m{x}! "!m{fg}!" "!m{bg}!" !m{olc}! -t 2> nul
Set "display.menu=!display.menu!%%button[!b{i}!]%%"
Set /a "m{y}+=3", "b{i}+=1"
)
%display.menu%
Exit /b 0
=================================
:InputBar <button#> <Prompt> [-f]
:# Force Input via switch -f
:# Constrains display of input to the dimensions of the inout bar. Longer input may still be entered; input display
:# is limited to the last n characters, where 'n' is the length of the input bar
set "input="
Set /A "CurrIn=0", "MaxIn=!btn[%1][Len]!"
<nul Set /P "=%\E%[!btn[%1][p]!H%\E%C%\E%7"
For /f "delims=" %%v in ('Set /A "MaxIn+1"')Do <nul Set /P "=%\E%[%%vX%\E%8%\E%[?25h%\E%[?12h"
%BG.exe% cursor 100
:entryloop
Title %~2
%BG.exe% kbd
Set "key=!k[%Errorlevel%]!"
If not "!Key!" == "" (
If not "!Key!"=="Enter" (
If "!Key!"=="Backspace" (
If not !CurrIn!==0 (
%OnType%
Set "Input=!Input:~0,-1!"
Set /A "CurrIn-=1"
<nul set /p "=%\E%D %\E%D"
)Else Start /b "" %BG.exe% play "%WINDIR%\Media\Windows critical stop.wav"
)Else (
If not "!Key!"=="?" (
Echo("!Key!"|findstr.exe /lic:"home" /lic:"end" /lic:"pageup" /lic:"pagedown" /lic:"space" /lic:"tab" /lic:"left" /lic:"right" /lic:"up" /lic:"down" /lic:"delete" /lic:"escape" > nul && (
If /I "!Key!"=="escape" (Start /b "" %BG.exe% play "%WINDIR%\Media\Windows critical stop.wav")
If /I "!Key!"=="delete" (
Start /b "" %BG.exe% play "%WINDIR%\Media\recycle.wav"
Goto :InputBar
)
If /I "!Key!"=="Space" (
Set "Input=!Input! "
Set /A "CurrIn+=1"
)
) || (
Set "Input=!Input!!Key!"
Set /A "CurrIn+=1"
)
)Else (%= ? Cannot be Echoed to findstr; results in help output. =%
Set "Input=!Input!?"
Set /A "CurrIn+=1"
)
%OnType%
)
If not "!input!"=="" <nul set /p "=%\E%8!Input:~-%MaxIn%!"
Goto :entryloop
)
)
:# Key is Enter. Test -f force input switch; force input if true
If /I "%~3" == "-f" If "!input!" == "" (
Start /b "" %BG.exe% play "%WINDIR%\Media\Windows Error.wav"
Goto :InputBar
)
<nul Set /P "=%\E%[?25l%\E%8%\E%[K!btn[%1][t]:255;255;255=180;180;250!"
%BG.exe% play "%WINDIR%\Media\Windows Navigation Start.wav"
<nul Set /P "=%\E%8!btn[%1][t]!%\E%[?25l%\E%[?12l"
Set "btn{State}[%1]="
If not "!Input!"=="" Set "btn{State}[%1]=!Input!"
:# 255 char title length limit
If "!Input:~0,237!"=="" (%= Double Quote string at output to prevent code insertion =%
Title You Entered: "!Input!"
)Else If not "!Input!"=="" (
Title You Entered: "!Input:~0,239!"
)Else Title ^^! No input entered.
Exit /B 0
========
:DefKeys
Set "k[8]=Backspace"
(Set LF=^
%= empty lines above are required. =%)
rem For /l %%i in (9)Do For /F eol^=^%LF%%LF%^ delims^= %%A in ('forfiles /p "%~dp0." /m "%~nx0" /c "cmd /c echo(0x09"') do Set "k[9]=%%A"
Set "k[13]=Enter"& Set "k[27]=Escape"& Set "k[32]=Space"& Set "k[33]=^!"& Set ^"k[34]=""
set "i=35"
For %%k in (
"#" "$" "%%" "&" "'" "(" ")" "ASsub" "+" "," "-" "." "/"^
"0" "1" "2" "3" "4" "5" "6" "7" "8" "9"^
":" ";" "<" "=" ">" "QMsub" "#"^
A B C D E F G H I J K L M N O P Q R S T U V W X Y Z^
"[" "\" "]" "^^" "_" "`"^
a b c d e f g h i j k l m n o p q r s t u v w x y z^
)Do (
Set "k[!i!]=%%~k"
Set /A "i+=1"
)
Set "k[42]=*"& Set "k[63]=?"& Set "k[123]={"& Set "k[124]=|"& Set "k[125]=}"
Set "k[126]=~"& Set "k[339]=Delete"& Set "k[327]=Home"& Set "k[328]=Up"
Set "k[329]=PageUp"& Set "k[331]=Left"& Set "k[333]=Right"& Set "k[335]=End"
Set "k[336]=Down"& Set "k[337]=PageDown"
Exit /b 0
:# REQUIRED UTILITY
===============
/* BG.exe V 3.9
https://github.com/carlos-montiers/consolesoft-mirror/blob/master/bg/README.md
Copyright (C) 2010-2018 Carlos Montiers Aguilera
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
Carlos Montiers Aguilera
cmontiers#gmail.com
*/
-----BEGIN CERTIFICATE-----
TVqQAAMAAAAEAAAA//8AALgAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAgAAAAA4fug4AtAnNIbgBTM0hVGhpcyBwcm9ncmFtIGNhbm5v
dCBiZSBydW4gaW4gRE9TIG1vZGUuDQ0KJAAAAAAAAABQRQAATAEEAG3tp1sAAAAA
AAAAAOAADwMLAQIZABoAAAAIAAAAAgAAcCcAAAAQAAAAAMD/AABAAAAQAAAAAgAA
BAAAAAEAAAAEAAAAAAAAAABgAAAABAAAu00AAAMAAAAAACAAABAAAAAAEAAAEAAA
AAAAABAAAAAAAAAAAAAAAABQAABMBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAD4UAAAlAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC50ZXh0AAAA
IBkAAAAQAAAAGgAAAAQAAAAAAAAAAAAAAAAAACAAUGAucmRhdGEAALgBAAAAMAAA
AAIAAAAeAAAAAAAAAAAAAAAAAABAAGBALmJzcwAAAACMAAAAAEAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAgABgwC5pZGF0YQAATAQAAABQAAAABgAAACAAAAAAAAAAAAAA
AAAAAEAAMMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
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
/yU8UUAAkJD/JThRQACQkP8lNFFAAJCQ/yUwUUAAkJD/JSxRQACQkP8lKFFAAJCQ
/yUkUUAAkJD/JSBRQACQkP8lHFFAAJCQ/yUYUUAAkJD/JRRRQACQkP8lEFFAAJCQ
/yUMUUAAkJD/JQhRQACQkP8lBFFAAJCQ/yUAUUAAkJD/JfxQQACQkP8l+FBAAJCQ
/////wAAAAD/////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
QwBPAE4ATwBVAFQAJAAAAEsARQBSAE4ARQBMADMAMgAuAEQATABMAAAAU2V0Q3Vy
cmVudENvbnNvbGVGb250RXgAVABlAHIAbQBpAG4AYQBsAAAAJQBkACAAJQBkACAA
JQBkACAAJQBkACAAJQBkACAAJQBkACAAJQBkACAAJQBkAAoAAABDAE8ATgBJAE4A
JAAAACUAZAAgACUAZAAKAAAAAABQAFIASQBOAFQAAABGAEMAUABSAEkATgBUAAAA
QwBPAEwATwBSAAAATABPAEMAQQBUAEUAAABMAEEAUwBUAEsAQgBEAAAASwBCAEQA
AABNAE8AVQBTAEUAAABEAEEAVABFAFQASQBNAEUAAABTAEwARQBFAFAAAABDAFUA
UgBTAE8AUgAAAEYATwBOAFQAAABQAEwAQQBZAAAAAACkMEAAACZAALAwQACAG0AA
wDBAANAaQADMMEAAwBlAANowQABgGUAA6jBAABAZQADyMEAAIBhAAP4wQACwF0AA
EDFAAGAXQAAcMUAAYBZAACoxQAAwFEAANDFAAIATQABHQ0M6ICh0ZG02NC0xKSA1
LjEuMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABkUAAAAAAAAAAAAADcUwAA
+FAAALBQAAAAAAAAAAAAACBUAABEUQAA6FAAAAAAAAAAAAAAMFQAAHxRAADwUAAA
AAAAAAAAAABAVAAAhFEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAjFEAAJpRAACoUQAA
tlEAAMRRAADcUQAA7lEAAAxSAAAcUgAALlIAAD5SAABSUgAAalIAAIZSAACYUgAA
qlIAAMRSAADMUgAAAAAAAOJSAAD0UgAA/lIAAAhTAAAQUwAAGlMAACZTAAAyUwAA
PFMAAEhTAABUUwAAXlMAAGhTAAAAAAAAclMAAAAAAACEUwAAAAAAAIxRAACaUQAA
qFEAALZRAADEUQAA3FEAAO5RAAAMUgAAHFIAAC5SAAA+UgAAUlIAAGpSAACGUgAA
mFIAAKpSAADEUgAAzFIAAAAAAADiUgAA9FIAAP5SAAAIUwAAEFMAABpTAAAmUwAA
MlMAADxTAABIUwAAVFMAAF5TAABoUwAAAAAAAHJTAAAAAAAAhFMAAAAAAABTAENs
b3NlSGFuZGxlAJIAQ3JlYXRlRmlsZVcAGgFFeGl0UHJvY2VzcwBkAUZyZWVMaWJy
YXJ5AKQBR2V0Q29uc29sZUN1cnNvckluZm8AALABR2V0Q29uc29sZU1vZGUAALYB
R2V0Q29uc29sZVNjcmVlbkJ1ZmZlckluZm8AAAQCR2V0TG9jYWxUaW1lAABFAkdl
dFByb2NBZGRyZXNzAAAsA0xvYWRMaWJyYXJ5VwAApQNSZWFkQ29uc29sZUlucHV0
VwDzA1NldENvbnNvbGVDdXJzb3JJbmZvAAD1A1NldENvbnNvbGVDdXJzb3JQb3Np
dGlvbgAA9wNTZXRDb25zb2xlRm9udAAAAQRTZXRDb25zb2xlTW9kZQAACgRTZXRD
b25zb2xlVGV4dEF0dHJpYnV0ZQB0BFNsZWVwAOwEV3JpdGVDb25zb2xlT3V0cHV0
VwB3AF9fd2dldG1haW5hcmdzAAAFAV9maWxlbm8AOwFfZ2V0Y2gAAGEBX2lvYgAA
xAFfa2JoaXQAALUCX3NldG1vZGUAAI0DX3djc2ljbXAAAEsEZnB1dHdjAAB1BGlz
d2N0eXBlAACqBHNldGxvY2FsZQD0BHdjc2NweQAABwV3Y3N0b2wAAA4Fd3ByaW50
ZgDIAU9lbVRvQ2hhckJ1ZmZXAAAJAFBsYXlTb3VuZFcAAAAAAFAAAABQAAAAUAAA
AFAAAABQAAAAUAAAAFAAAABQAAAAUAAAAFAAAABQAAAAUAAAAFAAAABQAAAAUAAA
AFAAAABQAAAAUAAAS0VSTkVMMzIuZGxsAAAAABRQAAAUUAAAFFAAABRQAAAUUAAA
FFAAABRQAAAUUAAAFFAAABRQAAAUUAAAFFAAABRQAABtc3ZjcnQuZGxsAAAoUAAA
VVNFUjMyLmRsbAAAPFAAAFdJTk1NLkRMTAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
-----END CERTIFICATE-----
=================
:Main script body
Setlocal EnableDelayedExpansion
Call :DefKeys
:# USAGE EXAMPLES // Your script below
%BG.exe% Font 9
:# buttons containing only whitespace in their text string are identified by qInput macro as Input bars
:# using findstr regex.
Call :createButton " " 2 2 "0;0;0" "255;255;255" "36" -t
Set /A "m{yo}=5", "m{\C}=2" %= define initial Y;X values of menu column =%
%Menu:Col=2% "Option 1" "Option 2" "Option 3"
%Menu:Col=l[X]% "Option 4" "Option 5" "Option 6"
%Menu:Col=l[X]% "Option 7" "Option 8" "Option 9"
Call :createButton "Click Me" 14 2 -t
Call :createButton "{ Or Me }" !l[Y]! !l[X]! -t
Call :createButton "Exit" 17 2 "200;;" "155;155;255" "48;2;60;;"
Call :createButton "Reset" 17 !l[X]! "200;;" "155;155;255" "48;2;;;100"
Call :createButton "Show Values" 17 !l[X]! "200;;" "155;155;255" "48;2;;90;"
<nul set /p "=%\E%[?25l"
:refresh
%dButtons%
:loop
%GetClick%
%qClicked% If defined ValidClick (
Title Clicked Button !ValidClick! : "!Clicked: =!"
If "!Clicked!"=="Exit" (
<nul Set /P "=%\E%[!btn[Y]!d%\E%[G"
Goto :End
)
If "!Clicked!"=="Reset" (
Endlocal
Goto :main
)
If "!Clicked!"=="Show Values" (
%Buffer:#=Alt%
%dValues%
Pause
%Buffer:#=Main%
Goto :loop
)
%qInput% "Enter something:" -f
)Else Title Clicked: !C{Pos}!
Goto :loop

Related

Batch file - would like to display a menu of folders in 3 columns

1-column code is below. I'd like to expand "char" to 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz and then be able to display the options in 3 columns (21 items, 21 items, 20 items). Folder names over a certain length would have to be truncated. With 3 columns and potentially long folder names, long folder names would have to be truncated in the menu.
rem Set the number of lines per page, max 29
set "pageSize=29"
set "char=0123456789ACDEFGHIJKLMNOPQRSTUVWXYZ"
rem Load current directory contents
set "numNames=1"
for /D %%a in (*.) do (
set /A numNames+=1
set "name[!numNames!]= %%a"
)
cd ..
set /A numPages=(numNames-1)/pageSize+1
rem Show directory contents, one page at a time
set start=2
:ShowPage
set /A page=start/pageSize+1, end=start+pageSize-1
if %end% gtr %numNames% set end=%numNames%
cls
cd %folder%
echo Page %page%/%numPages% of %CD%
echo/
set "base=1"
set /A lastOpt=pageSize+base, j=base
for /L %%i in (%start%,1,%end%) do (
for %%j in (!j!) do echo !char:~%%j,1! - !name[%%i]!
set /A j+=1
)
rem Assemble the get option message
set "mssg= (B - Back): "
if %end% lss %numNames% (
if "%mssg%" equ " (B - Back): " (set "mssg= (") else set "mssg=%mssg%, "
set "mssg=!mssg!Z=Next page"
)
if "%mssg%" neq " (B - Back): " set "mssg=%mssg%): "
:GetOption
choice /C 0123456789ACDEFGHIJKLMNOPQRSTUVWXYZB /N /M "Choice%mssg%"
I've found batch file solutions to browse files/folders with GUI, but I don't want to do a call to GUI (Explorer) because I'd like to keep everything on the keyboard (slows progress down to switch back and forth between mouse and keyboard all the time).
#ECHO OFF
SETLOCAL ENABLEDELAYEDEXPANSION
rem Set the number of lines per page, max 29
set /a pageSize=29
:: my pagewidth
SET /a pagewidth=120
SET "choicenames=z0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxy"
:: remove variables starting #
FOR /F "delims==" %%e In ('set # 2^>Nul') DO SET "%%e="
FOR /L %%e IN (1,1,%pagewidth%) DO SET "#spaces=!#spaces! "
:: Read dirnames to #nn, count to #entries
FOR /d %%e IN ("%~1\*.") DO SET /a #entries+=1&SET "#!#entries!=%%e"
SET /a #entries+=1&SET "#!#entries!=z Quit."
SET /a #columns=(#entries + pagesize - 1) / pagesize
SET /a #rows=(#entries + #columns - 1)/#columns
SET /a #columnwidth=(pagewidth/#columns) - 3
SET "#choices=z"
FOR /L %%e IN (1,1,%#entries%) DO (
rem column contents - max length + terminal spaces
IF %%e neq %#entries% (
SET "#%%e=!#%%e:~-%#columnwidth%!%#spaces%"
SET "#%%e=!choicenames:~%%e,1! !#%%e:~0,%#columnwidth%!"
SET "#choices=!#choices!!choicenames:~%%e,1!"
)
)
FOR /L %%e IN (1,1,%#rows%) DO (
SET /a cols=%%e + %#rows%
SET /a #line=%%e + (%#rows% * 2^)
SET "cols=!cols! !#line!"
SET "#line=!#%%e!"
FOR %%y IN (!cols!) DO IF DEFINED #%%y SET "#line=!#line! !#%%y!"
ECHO !#line!
)
IF %#entries% gtr 36 (
choice /cs /c %#choices%
) ELSE (
choice /c %#choices%
)
IF ERRORLEVEL 2 (
ECHO ERRORLEVEL is %ERRORLEVEL%
SET /a #choices=%ERRORLEVEL%-1
CALL SET "userchoice=%%#!#choices!%%"
ECHO choice made : !userchoice:~2!
) ELSE ECHO QUIT!
GOTO :EOF
This should be a self-adjusting menu.
I chose to make the QUIT choice consistently z

How do I put double spaces in batch file variables?

So, I've been trying to write games using batch files, and typically I write something like
set a-1-1= &set a-1-2=
set a-2-1= &set a-2-2=
, then to access it I use
set a-%x%-%y%=11
The problem is I can't store a double space in these variables.
It would be very helpful to know what your use case is - the type of game you are attempting to make, the output you are trying to achieve, how you intend to use the array.
Is it just for output? For Collision Detection?
As regards to options for defining and using arrays in batch, familiarise yourself with Delayed expansion, For loops and substring modificiation - as they are batches best tools for the job.
Open cmd.exe and read the output of:
Setlocal /?
Set /?
for /?
Delayed expansion allows for a neat little trick where you can define commands that reference array values before the values are actually assigned by Defining them with ! expansion prior to actually enabling Delayed Expansion. Such Commands as variables in Batch are refered to as Macros.
Here's an example of using defining and using arrays via batch macro's within a game of Tic Tac Toe.
:start ::: [ * Author: T3RRY * ] Creation Date - 12/01/2021 ::: WINDOWS 10 only
#Echo off & mode 50,11
:# Define Virtual Termnal Escape Character. Requires Windows 10
For /F %%a in ('echo prompt $E ^| cmd')do Set "\E=%%a"
Set LF=^
%= ! linefeed var. Do not remove or modify this line or above 2 lines ! =%
:# Clear the screen and Define the GRID macro for display of the playfield
CLS & Set "Grid=<nul Set /P "=%\E%[2;13H%\E%[37mDraw %\E%[34mWin %\E%[33mLose%\E%[5;1H!Spacer!%\E%[?25l%\E%[0m%\E%[35m%\E%[0m%\E%[35m[%\E%[90m!c7:7=%\E%[7m7!%\E%[0m%\E%[35m][%\E%[90m!c8:8=%\E%[7m8!%\E%[0m%\E%[35m][%\E%[90m!c9:9=%\E%[7m9!%\E%[0m%\E%[35m]!LF!!Spacer![%\E%[90m!c4:4=%\E%[7m4!%\E%[0m%\E%[35m][%\E%[90m!c5:5=%\E%[7m5!%\E%[0m%\E%[35m][%\E%[90m!c6:6=%\E%[7m6!%\E%[0m%\E%[35m]!LF!!Spacer![%\E%[90m!c1:1=%\E%[7m1!%\E%[0m%\E%[35m][%\E%[90m!c2:2=%\E%[7m2!%\E%[0m%\E%[35m][%\E%[90m!c3:3=%\E%[7m3!%\E%[0m%\E%[35m]%\E%[0m""
:# Define reset macro used to flag game end state and reset the enviroment for next game
Set "Reset=( Title #. Game over. ) & Timeout /t 3 /Nobreak > nul & Endlocal & Goto :start"
:# Defines a Macro to Iterate over winning cells ; used in assesing moves and gamestate
Set "?.Cells=For %%V in ("!c1!!c4!!c7!" "!c2!!c5!!c8!" "!c3!!c6!!c9!" "!c1!!c2!!c3!" "!c4!!c5!!c6!" "!c7!!c8!!c9!" "!c3!!c5!!c7!" "!c1!!c5!!c9!")Do "
:# Enable Environment for Macro Expansion
Setlocal EnableExtensions EnableDelayedExpansion
:# Define custom or Default Characters for Player 1 and AI
If not "%~2" == "" (
Set "P1=%~1"& Set "P2=%~2"& Set "P1=!P1:~-1!"& Set "P2=!P2:~-1!"
)Else ( Set "P1=X"& Set "P2=O" )
:# Define Move List 'Cho' and initial Cell state for c1 - c9
Set "Cho= 123456789"& Set "turn=9"& For /L %%n in (1 1 9)Do Set "c%%n=%%n"
:# Offset playfield from screen Edge [used in Grid Macro]
For /L %%n in (1 1 20)Do Set "Spacer= !Spacer!"
:# Randomise starting Player
For /F "Delims=" %%v in ('set /A "!random! %%2 + 1"')Do Goto p%%v
:p1
%GRID% & TITLE Enter a number - Available: %Cho% or [E]xit
For /F "Delims=" %%G in ('Choice /N /C:%Cho: =%e')Do (
Set "c%%G=!P1!"
Set "Cho=!Cho:%%G=!"
Set /A turn-=1
If %%G == E Exit /b 0
)
%GRID:90=32% & Call :Delay 2> nul
:p2
TITLE Tic Tac Toe & %?.Cells% If "%%~V" == "!p1!!p1!!p1!" Goto :Win
Set "move=" & Set "line="
%?.Cells% For %%c in (!P1! !P2!)Do (
Set "line=%%~V"
For /L %%n in (1 1 9)Do ( :# Test ideal move; Priority - Take win ; block player
Set "line=!line:%%n%%c%%c=!"
If not "!line!" == "" Set "line=!line:%%c%%n%%c=!"
If not "!line!" == "" Set "line=!line:%%c%%c%%n=!"
If "!line!" == "" (Set "move=%%n")
))
Call :AI "!P2!" && %GRID:90=31% & Call :Delay 2> nul
%?.Cells% If "%%~V" == "!p2!!p2!!p2!" Goto :Lose
If !turn! LEQ 0 ( %GRID:90=37% & %Reset:#=Draw% )Else Goto p1
:AI [ Enact best available move option win; block player win; centre; random ]
If not "%move%" == "" (
Set "c%move%=%~1"
Set "Cho=!Cho:%move%=!"
Set /A "turn-=1"
Exit /B 0
)
Set "tCho=!Cho:5=!"
If Not "!tCho!" == "!Cho!" (
Set "c5=%~1"
Set "Cho=!Cho:5=!"
Set /A "turn-=1"
Exit /B 0
)
For /F "Delims=" %%v in ('set /A "!random! %%!turn! + 1" 2^> nul ')Do (
For %%i in ("!Cho:~%%v,1!")Do If not "!Cho:~%%v,1!" == " " If "!c%%~i!" == "%%~i" (
Set "c%%~i=%~1" & Set "Cho=!Cho:%%~i=!" & Set /A "turn-=1"
Exit /B 0
))
If !turn! EQU 0 (Exit /B 0)Else Goto :AI
:Win
%Grid:90=34% & %Reset:#=You Won%
:Lose
%Grid:90=33% & %Reset:#=You Lost%
The Display macro Grid Is defined referencing the array variables for the Grid Move state. As Moves are made, Occupied cells c1 to c9 are redifined. Because the macro is defined using delayed expansion to expand the variables, but before to Delayed Expansion is actually enabled, when the macro is expanded, it expands with the current value of the c1 to c9 cel array.
Substring modification is used to update the information displayed in the Grid Array after each change.
Substring modification is also used in conjunction with An if condition to compare winning cell lines Defined in the ?Cells macro against the definitions of the current cell array to see if lines are complete or alost complete as a means of determining move action and gamestate.

How to make an Inventory in Batch game

I am trying to create a Batch Game, where it has an inventory similiar to Skyrim, Oblivion, and other well known Games similiar. The ides is that there is not a fixed number of Inventory slots, but rather, the game creates a new slot if the existing slots are occupied. I already know how to make the game check for them, ish.
if '%item1%'=='blank' (set item1=%item%) else (if '%item1%'=='%item%' set /A item1qua=%item1qua%+1)
if '%item2%'=='blank' (set item2=%item%) else (if '%item2%'=='%item%' set /A item2qua=%item2qua%+1)
I also dont know how to create a batch script that changes the number each time until the inventory slot is found as blank.
Then the Game has to save all the Inventory slots when done. My current method is this:
( Echo #echo off
Echo set item1=%item1%
Echo set item1qua=%item1qua%
Echo set item2=%item2%
Echo set item2qua=%item2qua%
Echo set item3=%item3%
Echo set item3qua=%item3qua%
Echo set item4=%item4%
Echo set item4qua=%item4qua%)>>%playername%.bat
The term "qua" simply refers to the Quantity.
I have tried this code:
set num=1
:inv
if '%item%num%%'=='blank' (set %item%num%%=%item% && goto next) else (set /a num=%num%+1)
goto inv
In short, this would expand the inventory as the player gets more items.
The items would have a weight, just like in Elder scrolls and other games, I want to add that sacred annoyance to players (hehe), however, I would also want the code to remove the extra 'blank' itemslots, without leaving a gap in the numbering system, example:
item1, item2 item4, item7, item8
My previous method was to copy an existing .bat file with thw item data on form the mother folder, and place it in a folder elsewhere which the player could veiw their items using the dir command.
As you can imagine, not very productive.
My second method was more in the Alpha stage of the game, when it was basically a life simulator, which sort of got abondoned, but left in the game folder just incase i picked it up again:
>>Users\%fname%.bat Echo set weed=%weed%
>>Users\%fname%.bat Echo set money=%money%
>>Users\%fname%.bat Echo set water=%water%
>>Users\%fname%.bat Echo set lighters=%lighters%
>>Users\%fname%.bat Echo set cigarettes=%cigarettes%
>>Users\%fname%.bat Echo set lightbulbs=%lightbulbs%
EDITS
Thanks to the link provided by Chris Schaller, I found a Code that could work, and edited to what I needed.
#echo off
set len=11
set obj[0]=Gold
set obj[1]=Silver
set obj[2]=Sword
set obj[3]=Knife
set obj[4]=Greenfelt
set obj[5]=Amulet
set obj[6]=Chickenleg
set obj[7]=Necklace
set obj[8]=StolenItem
set obj[9]=GoldIngot
set obj[10]=Statuette
set obj[11]=Seeds
set i=0
:loop
if /i %i% equ %len% goto :eof
for /f "usebackq delims== tokens=2" %%j in (`set obj[%i%]`) do (
echo %%j
)
pause
set /a i=%i%+1
goto loop
The code works good for some aspects, however how would I allow obj[0] increase each time?
A.S.C
The easiset way would be to have all variables that have to be saved starting with a special character (like #or # or ~ or _ or ...) or string (like obj[ in your Edit). Saving them then is as easy as:
>Users\%fname%.sav set #
(or with the example in your Edit: >Users\%fname%.sav set obj[)
and to read them again with:
for /f "delims=" %%a in ("users\%fname%.sav") do set "%%a"
What your aiming to do is increment a count as new items are added to the inventory.
For this task type, I'd suggest using a function as inventory management is a highly repetative task in batch rpg games.
Functions in batch scripting are labels that are called with parameters repetative actions are performed upon.
In the context of game design for an RPG, you'll want to allow for use accross different situations, such as adding loot, purchases or rewards to inventory.
For a more complex game that supports a variety of items of a similar type, using itemtype arrays can makes things easier - Think menu tabs where you selcet weapons and get a list of just the weapons in your inventory.
Below is an example of how to approach scripting a function for adding items to inventory that tests 2 conditions are valid prior to adding the item - 1) The cost does not exceed funds, 2) The weight of the item does not push the total carry weight over the maximum.
itemweight and itemcost values default to 0 if no paramter is supplied when calling to allow items with no weight or that are found / given to be added to inventory.
#Echo off & Cls
For /F "Tokens=1 Delims==" %%G in (' Set "#" 2^> nul ')Do Set "%%G="
Set /A "#Money=100,Maxweight=25000,#weight=0"
::: redirect output of inventory to nul to suppress output of item added to inventory notifcation as desired
For %%G in ("Healing Potion" "Old Key" "Map")DO Call :Inventory %%G Miscellaneous 10 >nul
For %%G in ("Vambraces" "Boots of Luck" "Helm")DO Call :Inventory %%G Armor 1000 >nul
Call :Inventory "Dagger" OneHandedWeapon 250 >nul
Call :Inventory "Short sword" OneHandedWeapon 4000 >nul
Call :Inventory "Katana" OneHandedWeapon 4750 > nul
Set #
Endlocal
Goto :Eof
:Inventory <itemname> <itemtype> <itemweight> <itemcost>
::: Remove item: <itemname> /R
::: undefines all array elements containing itemname in varname or value. Use unique and descriptive Item names.
If /I "%~2" == "/R" (
For /F "Tokens=1,2* Delims==" %%G in (' Set "#" 2^> nul ^|%__Appdir__%\findstr.exe /LIC:"%~1" ')Do Set "%%G="
Goto :getweight
)
Set "Itemname=%~1"
Set "Itemtype=%~2"
If "%~4"=="" (Set "cost=0")Else (
Set "cost=%~4"
For /F %%G in ('Set /A #money-%~4')Do if %%G LSS 0 (
Echo(You cannot afford %itemname%
Goto :Eof
)
)
If "%~3" == "" (Set "itemweight=0")Else (
Set "itemweight=%~3"
For /F %%G in ('Set /A maxweight-%~3-#weight')Do if %%G LSS 0 (
Echo/You are carrying too much.
Goto :Eof
)
)
Set /A "#money-=cost"
Set "#%itemname%[grams]=%itemweight%"
Set /A #Inv{i}+=1+0
Set "#Inventory[%#Inv{i}%]=%itemname%"
If Defined Itemtype (
Set /A #%ItemType%{i}+=1+0
Call Set "#%ItemType%[%%#%ItemType%{i}%%]=%itemname%"
)
Echo(%~1 added to Inventory.
:getweight
::: Updates the current weight of all inventory items by summing all itemname[grams] definitions
Set "#weight=0"
For /F "Tokens=2 Delims==" %%G in (' Set "#" ^| Findstr /LIC:"[grams]"')Do Set /A #weight+=%%G
Goto :Eof
Note: The above is intended to example a method for adding items to inventory after assessing if they Can / should be added. The itemname /R 'remove item' component of the function is a minimal example of undefining an element from the inventory array/s however this approach does not shift array variable indexes to fill the gap left by the undefined variable - Something to be mindful of if you were to loop through the array using a for /L loop.
The below is an example of Incorporating a character login and save system that takes advantage of the use of # perfixed variables.
::: AUTHOR: T3RRY Created: 06/03/2021 Version: 1.3 Filename: RPGInventorySystem
:# Purpose: Provide an easy to use, ready to go Template for creating Batch RPG Games
:# Features:
:# - :Login Function
:# - remembers last played character; offers single key login for that character.
:# - flags if character is New or Returning
:# - :Getin Input function to restrict and validate player Input
:# - Example Template of Creating Classes with Starting Inventory { :Knight function }
:# - Multipurpose :Inventory Funtion That Saves Inventory changes Immediately
:# - :ManageInventory Function to allow players to well... manage their inventory.
:# - Menu Macro for easy menus.
#Echo off & Goto Prep
=======================================================================:# FUNCTIONS
:# Inventory Arguments and Usage Info:
:# Arg order Mandatory
======================:# ADDING ITEMS TO INVENTORY: Initial Inventory; Loot; Gifts / Rewards; Purchases
:Inventory <ItemName> <ItemType> <ItemSubType> <ItemWeight> <ItemCost> {Optional:"ModifierType=Value"} {Optional:/F}
::::::::::::::::::::::::::::::::::::::::::::::::::
:# Optional Arg "/F": Must be last Arg; Flags the Item as free; Does not Subtract ItemCost from Players #Money
:# Allows Items to be Looted / Gifted / Rewarded that have value stored for use when Selling Items. See Below
======================:# REMOVING / SELLING ITEMS:
:# Remove item: <ItemName> /R <ItemSubType>
:# Optional third Arg is used when selling an Item. May be a Sum, Integer Value or use Array: !#ItemName.Value!
:# /R - Undefines all array elements containing ItemName in varname or value. Use unique and descriptive Item names.
:::::::::::::::::::::::::::::::::::::::::::::::::::
:# Sell item: <ItemName> /R <ItemSubType> <ItemSaleValue>
======================:# EQUIPPING ITEMS:
:# Equip an item : <Itemname> /E <ItemSubtype>
======================:# CHECKPOINTS:
:# Save a Checkpoint: <LabelName> /L
:::::::::::::::::::::::::::::::::::::::::::::::::::
:# IMPORTANT - RESERVED VARIABLES - The above Parameter names; #%1.Grams #%1.Value #Display.Weight #%3{i} #Weight List? Count
:# - Arrays: #%ItemName%.Grams #%ItemName%.Value #Equipped.%ItemSubType%
:# - Lists: #Inventory.Types #Inventory.%ItemType% #Inventory.%ItemType%.%ItemSubType%
:# RECOMMENDATION: Use a selection of Category names for ItemTypes that will be Equipped.
:# - Only one of Each ItemSubType may be Equipped at A time.
:# - It is appropriate that only 1 pair of Boots may be worn, but multiple pieces of different Armor may be equipped:
:# - Instead of just Defining all armors to the ItemType Armor:
:# - Define Type Armor and Subtypes: Helm Mantle Gloves Vambraces Pauldrons Boots Pants
:# DEPENDENCIES - Defined in ':Login': #Name Game.Save
If /I "%~2" == "/L" (
Set "#Location=%~1"
Goto :Save
)
:# Removes or Sell ItemName From Inventory; Removes ItemName From ItemSubtype List
If /I "%~2" == "/R" (
Set "Value="
If not "%~5" == "" Set "Value=%~5"
For /F "Tokens=1,2* Delims==" %%G in (' Set "#" 2^> nul ^|%__Appdir__%findstr.exe /LIC:"%~1" ')Do (
rem /* Test if Variable is a List Variable; If Not Undefines Variable */
Set "List?=%%G"
If not "!List?:~0,10!" == "#Inventory" (
Set "%%G="
)Else (
rem /* If Variable is a List Variable; Remove ItemName from ItemSubType List */
Set "%%G=!%%G: "%~1"=!"
Rem /* If ItemSubType List is Empty; Remove ItemSubtype from ItemType List */
If "!%%G!" == "" (Set "#Inventory.%~3=!#Inventory.%~3: "%~4"=!")
)
)
rem /* If Item SaleValue provided; Increment #Money by Value */
Set /A "#Money+=!Value!+0"
Goto :Save
)
:# Build Itemtype Arrays and List Using Parameters
Set "ItemName=%~1"
Set "ItemType=%~2"
Set "ItemSubtype=%~3"
Set "Count=0"
:# Limit ItemTypes to 36 max supported by Menu macro
If Not "!#Inventory.%ItemType%!" == "" (
For %%G in (!#Inventory.%ItemType%!)Do Set /A "Count+=1"
If !Count! GTR 36 (
Echo(You own too many types of %ItemType%. !ItemName! cannot be Acquired.
Exit /B 3
)
)
Set "Count=0"
:# Limit Subtypes to 36 max supported by Menu macro
If Not "!#Inventory.%ItemType%.%ItemSubType%!" == "" (
For %%G in (!#Inventory.%ItemType%.%ItemSubType%!)Do Set /A "Count+=1"
If !Count! GTR 36 (
Echo(You own too many types of %ItemSubtype%. !ItemName! cannot be Acquired.
Exit /B 3
)
)
If "%~4" == "" (Set "ItemWeight=0")Else (
Set "ItemWeight=%~4"
For /F %%G in ('Set /A #MaxWeight-%~4-#weight')Do if %%G LSS 0 (
Echo/You are carrying too much.
Exit /B 2
))
:# Determine Value of Item and If item is To be Free or Paid For
Set "Free.Item="
Echo(%*|%__APPDIR__%findstr.exe /LIC:"/F" > Nul && Set "Free.Item=Y"
If "%~5"=="" (Set "ItemCost=0")Else (
Set "ItemCost=%~5"
If Not Defined Free.Item (
For /F %%G in ('Set /A #money-%~5')Do if %%G LSS 0 (
Echo(You cannot afford %ItemName%
Exit /B 1
)
)
)
:# Define a Modifier To ItemName.modname For Items With Stat Modifiers If supplied
If not "%~6" == "" If /I not "%~6" == "/F" (
Set "#%ItemName%.%~6" 2> Nul || (
Echo(Invalid Argument "[%~6]" In %*
Echo(Required: "ModifierType=Value"
Timeout /T 3 /NoBreak
Pause
Endlocal & Goto :Eof
)
)
:# Define #ItemName Arrays for Grams and Value
Set "#%ItemName%.Grams=%Itemweight%"
Set "#%ItemName%.Value=%ItemCost%"
Echo(!ItemName! added to Inventory.
:# Search savefile for Itemtype; Itemsubtype; and Itemname; Append to relevant list if not present
%__APPDIR__%findstr.exe /LIC:"!ItemType!" "%Game.Save%" > nul 2> nul || Set "#Inventory.Types=!#Inventory.Types! "!ItemType!""
%__APPDIR__%findstr.exe /LIC:"!ItemSubType!" "%Game.Save%" > nul 2> nul || Set "#Inventory.%ItemType%=!#Inventory.%ItemType%! "!ItemSubType!""
%__APPDIR__%findstr.exe /LIC:"!ItemName!" "%Game.Save%" > nul 2> nul || Set "#Inventory.%ItemType%.%ItemSubType%=!#Inventory.%ItemType%.%ItemSubType%! "!ItemName!""
=================================================
:Save
:# Remove Item Categories from #Inventory.Types list when all Category sub items are sold / dropped.
For %%G in (!#Inventory.Types!)Do If "!#Inventory.%%~G!" == "" Set "#Inventory.Types=!#Inventory.Types: "%%~G"=!"
Set /A "#Def=#Dmg=#weight=0"
:# Updates the below Modifiers of all equipped inventory items by summing all ItemName.%%M definitions
For %%M in (DEF DMG)Do For /F "Tokens=1,2* Delims==" %%G in ('Set "#Equipped" 2^> nul')Do (
For /F "Tokens=2 Delims==" %%i in ('Set "#%%H"^|%__APPDIR__%Findstr.exe /LIC:".%%M"')Do (
Set /A "#%%M+=%%i+0"
)
)
:# Updates the current weight of all inventory items by summing all ItemName.Grams definitions
For /F "Tokens=2 Delims==" %%G in (' Set "#" ^| Findstr /LIC:".Grams"')Do Set /A #weight+=%%G
Set "#Display.weight=%#weight:~0,-3%.%#weight:~-3%"
:# Enact Save for # prefixed variables
:# Saves Game Variables prefixed by # to Game.Save cmd file to be called on Login
(For /F "tokens=1,2* Delims==" %%G in ('Set "#"')Do Echo(Set "%%G=%%H") >"%Game.Save%"
Echo(%#Name%>"%~f0:Last_Char"
Exit /B 0
=================================================
:ManageInventory {Optional:/E /S /D}
:# Control Available Inventory options by Calling ManageInventory with the Options you wish
:# to allow according to the current Gamestate.
Set "MI.Options="
If not "%~1" == "" Echo/%*|Findstr /LIC:"E" > Nul && Set "MI.Options=!MI.Options! Equip"
If not "%~1" == "" Echo/%*|Findstr /LIC:"S" > Nul && Set "MI.Options=!MI.Options! Sell"
If not "%~1" == "" Echo/%*|Findstr /LIC:"D" > Nul && Set "MI.Options=!MI.Options! Drop"
:# /R - Removes the Sell option from Invetory Action
:# RESERVED VARIABLES - Type; SubType; Action; All Menu Macro Reserved Variables
:# DEPENDENCIES -Functions: Inventory; Save -Macro: Menu -Variables: #Money #Equipped
:# Inventory Function Defines Lists used with Each Submenu.
:# This function returns no Errorlevels.
CLS
Echo( Credit: !#Money! Damage: !#Dmg! Defence: !#Def! Burden: !#Display.Weight! kg /!#MaxWeight:~0,-3!.!#MaxWeight:~-3! kg.
Echo( Equipped Items:
(Set "#Equipped" 2> nul > nul ) || Echo( No items equipped.
(For /F "Delims=" %%# in ('Set #Equipped 2^> nul') Do For /F "Tokens=1,2 Delims==" %%C in ("%%#")Do (
Set "[item]=%%C"
Set "[item]=![item]:*.=!"
Set "[item]=![item]:.=: !"
<nul set /P "=> ![item]! = %%D!LF!"
)) 2> nul
:# Choose Action Type or Exit ManageInventory Function; Each Submenu can abort to this Primary Menu
%Menu% Exit !MI.Options!
CLS
Set "Action=!Option!"
Echo(Select Inventory Category:
%Menu% Return !#Inventory.Types!
If "!Option!" == "Return" (Goto :ManageInventory)Else CLS
Set "Type=!Option!"
Echo(Select a type of !Type! to !Action!:
%Menu% Return !#Inventory.%Type%!
If "!Option!" == "Return" (Goto :ManageInventory)Else CLS
Set "SubType=%Option%"
:# Apply action type to selected ItemName
:# If Equipping; Handle Two Handed / [One Handed/Off Hand] Equipment Conflict
Echo(Selecting a !Subtype! from your !Type! Will !Action! it. Return [0] To cancel.
%Menu% Return !#Inventory.%Type%.%SubType%!
If Not "!Option!" == "Return" (
If "!Action!" == "Equip" (
Set "#Equipped.%Type%.%Subtype%=%Option%"
If /I "%SubType%" == "Two Handed" (Set "#Equipped.Weapons.One Handed="&Set "#Equipped.Weapons.Off Hand=")
If /I "%SubType%" == "One Handed" (Set "#Equipped.Weapons.Two Handed=")
If /I "%SubType%" == "Off Hand" (Set "#Equipped.Weapons.Two Handed=")
Call :Save
)
If "!Action!" == "Sell" (
Echo(Sell Value: $!#%Option%.Value!. Confirm [Y/N]
For /F "Delims=" %%O in ('Choice /N /C:YN')Do If %%O==Y Call :Inventory "%Option%" /R "!Type!" "!SubType!" "!#%Option%.Value!"
)
If "!Action!" == "Drop" Call :Inventory "%Option%" /R "!Type!" "!SubType!"
)
Goto :ManageInventory
=================================================
:login
:# clear any preexisting definitions
(For /F "tokens=1,2* Delims==" %%G in ('Set "#"')Do Set "%%G=") 2> nul
:# check Alternate data stream 'Last_Char' of this file; offer single key login for last played character.
more < "%~f0:Last_Char" 2>nul >nul && For /F "Delims=" %%G in ('more ^< "%~f0:Last_Char"')Do (
Echo(Continue as %%G Y/N
For /F "Delims=" %%C in ('Choice /N /C:YN')Do if "%%C"=="Y" (
Set "Game.Save=%TEMP%\%~n0_%%G_Save.cmd"
CALL "%TEMP%\%~n0_%%G_Save.cmd"
Exit /B 0
)
)
(For /F "tokens=1,2* Delims==" %%G in ('Set "#"')Do Set "%%G=") 2> nul
:# Login Errorlevels: [2:User quit during Login.] [1:New Character] [0:Existing Character]
:# IMPORTANT - RESERVED VARIABLES:
:# - #Name #Pass Verify
:# #Name used to create a .cmd file that is called when the user logs back in to the character to reassign
:# # prefixed variables.
CLS
Echo(Existing Characters:
(Dir /B "%TEMP%\%~n0_*_Save.cmd" > Nul 2> nul || Echo(None. )
For /F "Tokens=2 Delims=_" %%G in (' Dir /B "%TEMP%\%~n0_*_Save.cmd" 2^> nul ')Do Echo(%%G
rem /* example definitions */
Call :GetIn #Name "[a-zA-Z ]*" /C /S /P:Enter your characters name
If Not "%Errorlevel%" == "0" Goto :login
Call :GetIn #Pass "[0-9][0-9][0-9][0-9]" /S /P:Enter your four Digit Pin
If Not "%Errorlevel%" == "0" Goto :login
Set "Verify=%#Pass%"
Set "Game.Save=%TEMP%\%~n0_%#Name%_Save.cmd"
rem /* load saved values */
If Exist "%Game.Save%" Call "%Game.Save%"
If /I not "%Verify%" == "%#Pass%" (
Echo(Invalid Password
%Menu% Exit Retry
rem /* Flag quit program */
Goto :Login
)
rem /* offer delete/ login if exists */
If Exist "%Game.Save%" (
rem /* Flag Existing Character Errorlevel 0 */
%Menu% "Remove Character" "Continue"
If /I "!Option!"=="Continue" Exit /b 0
%Menu% "Abort" "Proceed"
If /I "!Option!"=="Abort" Goto :Login
Del "%Game.Save%"
Goto :Login
) Else (
rem /* Flag New Character Errorlevel 1 */
Exit /B 1
)
=====================================================
:strlen <resultVar> <stringVar>
(
setlocal EnableDelayedExpansion
(set^ tmp=!%~2!)
if defined tmp (
set "len=1"
for %%P in (4096 2048 1024 512 256 128 64 32 16 8 4 2 1) do (
if "!tmp:~%%P,1!" NEQ "" (
set /a "len+=%%P"
set "tmp=!tmp:~%%P!"
)
)
) ELSE (
set len=0
)
)
(
endlocal
set "%~1=%len%"
exit /b
)
=====================================================
:GetIn [ReturnVar] ["qouted findstr search pattern"] [Optional:"/C" - required for patterns with spaces] [Optional "/S" - Suppress input accepted] [/P:Custom Prompt]
:# Input validation function for restricting input to desired character classes or [limited] Regex Patterns.
:# -IMPORTANT - RESERVED VARIABLES: InputParams /C /P /S rVar Pattern Exit.Code
:# - GetIn Errorlevels:
:# - Errorlevel 3 - User has failed to provide valid input * OR * regex pattern is
:# invalid * OR * GetIn is a called label in a file that has recieved input
:# from a pipe that has not been handeled before the call.
:# - Errorlevel 2 - GetIn is a script that has been invoked by a pipe
:# - Errorlevel 1 - GetIn has been called without Arg 2 for Regex Pattern
:# - Errorlevel 0 - Input has been assigned that matches the Regex Pattern
:# GetIn Usage Examples - Description is replaced with Arg 1-ReturnVar:
:# Call :GetIn Pin "[0-9][0-9][0-9][0-9]" /S /P:Enter a four Digit Pin Number
:# Call :GetIn Alphanumeric-String "[0-9a-zA-Z]*"
:# Call :GetIn semicolon-delimited-hexadecimal-String "[0-9a-fA-F][0-9a-fA-F][:][0-9a-fA-F][0-9a-fA-F]"
:# Call :GetIn AlphaString-with-3-Digit-Numeric-suffix "[a-zA-Z]*[0-9][0-9][0-9]"
:# Call :GetIn list-of-delimited-words "[a-zA-Z, ]*" /C
:# Call :GetIn pair-of-delimited-numbers "[0-9]*[, ][0-9]*" /C
SETLOCAL EnableExtensions EnableDelayedExpansion
Set "/C=" & Set "/P=" & Set "/S="
Set InputParams=%*
If Not "!InputParams:/C=!" == "!InputParams!" Set "/C=_"
If Not "!InputParams:/S=!" == "!InputParams!" Set "/S=_"
If Not "!InputParams:/P=!" == "!InputParams!" (
Set "/P=!InputParams:*/P:=!"
Set "/P=!/P:"=!"
)
rem [ test if standalone script - if so test if accessed by pipe; reject execution if true ]
If "%~0" == "%~n0" For %%G in (!cmdcmdline!)Do Echo/%%~G|Findstr.exe /LIC:"/S" > nul 2> nul && (Set "Exit.Code=2" & Goto :Getin.Err)
:GetInRetry
Del /Q "%TEMP%\%~n0_validate.~tmp" 2> nul
If !Exit.Code! GTR 5 Goto :Getin.Err
Set "rVar="
If "%~2" == "" GOTO :Getin.Err
Setlocal DISABLEdelayedExpansion & rem ::: display occurances of carets [^] in pattern
Endlocal & Set "Pattern=%~2"
If Not Defined /P (
Set /P "rVar=Input Format for %1:!LF!!Pattern!!LF!!LF!Enter %1: "
)Else Set /P "rVar=!/P!: "
If "!rVar!" == "" (Set /A "Exit.Code+=1" & <nul Set /P"= ^! Invalid value.!LF!" & Goto :GetInRetry)
> "%TEMP%\%~n0_validate.~tmp" (Echo/!rVar!)
If Defined /C (
Type "%TEMP%\%~n0_validate.~tmp" | %__APPDIR__%findstr.exe /RXC:"%~2" >nul || (Set /A "Exit.Code+=1" & <nul Set /P"= ^! Invalid value. !LF!" & Goto :GetInRetry)
) Else (
Type "%TEMP%\%~n0_validate.~tmp" | %__APPDIR__%findstr.exe /RX "^%~2$" >nul || (Set /A "Exit.Code+=1" & <nul Set /P"=- ^! Invalid value. !LF!" & Goto :GetInRetry)
)
If not defined /S Echo/%1: [!rVar!] Accepted
ENDLOCAL & Set "%~1=%rVar%"
Del /Q "%TEMP%\%~n0_validate.~tmp"
Exit /B 0
:GetIn.Err
Exit /B %Exit.Code%
===========================:# DEFINE INITIAL INVENTORY - EXAMPLE Only
:Knight Starter Pack
:# Example of defining initial variables for a new character prior to commencing gameplay
:# IMPORTANT - Inventory function is Dependant on #Money #MaxWeight and #Weight variables.
Set /A "#Money=500,#MaxWeight=25000,#Weight=0"
:# suppress output of Inventory added notifcation by redirecting to nul as desired.
Call :Inventory "Dagger" Weapons "Off Hand" 250 50 "DMG=5" /F > nul
Call :Inventory "Buckler" Weapons "Off Hand" 400 40 "DEF=6" /F > nul
Call :Inventory "Short sword" Weapons "One Handed" 4000 250 "DMG=10" /F > nul
Call :Inventory "Twin Bladed Katana" Weapons "Two Handed" 5500 350 "DMG=12" /F > nul
Call :Inventory "Leather Cap" Armor Helm 500 25 "DEF=3" /F > nul
Call :Inventory "Faded Map" Miscellaneous Maps 20 "DEF=5" /F > nul
Call :Inventory "Healing Potion" Potions Restorative 10 25 "Heal=30" /F > nul
Call :Inventory "Old Key" Miscellaneous Keys 10 1 /F > nul
Call :Inventory "Worn Leather Vambraces" Armor Vambraces 1000 15 "DEF=2" /F > nul
Call :Inventory "Boots of Luck" Armor Boots 1500 50 "DEF=4" /F > nul
Goto :Eof
===========================:# END OF FUNCTIONS
:Prep
=====================================================:# MACRO DEFINITIONS
===================================:# MENU macro prep and Definition :::
:# IMPORTANT - RESERVED VARIABLES:
:# - LF \N Game.Save
(Set LF=^
%= Linefeed var used for multi-line output in GetIn macro - Do not modify. =%)
(Set \n=^^^
%= Newline var \n for multi-line macro definition - Do not modify. =%)
:# Enable environment for macro expansion, Arrays and code block variable operations
Setlocal EnableExtensions EnableDelayedExpansion
==================================================================
:# Menu macro escaped for Definition with DelayedExpansion Enabled
:# IMPORTANT - RESERVED VARIABLES: Menu CH# CHCS Options Option Opt[i] Option.Output Cholist DIV
:# Key index list Allows 36 menu options. Component of Menu Macro
Set "ChoList=0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
rem /* Get console width for dividing line. */
for /F "usebackq tokens=2* delims=: " %%W in (`mode con ^| %__APPDIR__%findstr.exe /LIC:"Columns"`) do Set /A "Console_Width=%%W"
:# Build dividing line for menu output.
Set "DIV="&For /L %%i in (2 1 %Console_Width%)Do Set "DIV=!DIV!-"
:# Menu macro Usage: %Menu% "quoted" "list of" "options"
==== Set Menu=For %%n in (1 2)Do if %%n==2 (%\n%
%= Output Dividing Line =% Echo(^^!DIV^^!%\n%
%= Reset CH# index value for Opt[#] =% Set "CH#=0"%\n%
%= Undefine choice option key list =% Set "CHCS="%\n%
%= For Each in list; =% For %%G in (^^!Options^^!)Do (%\n%
%= For Option Index value =% For %%i in (^^!CH#^^!)Do (%\n%
%= Build the Choice key list and Opt[#] =% Set "CHCS=^!CHCS^!^!ChoList:~%%i,1^!"%\n%
%= array using the character at the =% Set "Opt[^!ChoList:~%%i,1^!]=%%~G"%\n%
%= current substring index. =% Set "option.output=%%~G"%\n%
%= Display ; removing # variable prefix =% Echo([^^!ChoList:~%%i,1^^!] ^^!Option.output:#=^^!%\n%
%= Increment Opt[#] Index var 'CH#' =% Set /A "CH#+=1"%\n%
%= Close CH# loop =% )%\n%
%= Close Options loop =% )%\n%
%= Output Dividing Line =% Echo(^^!DIV^^!%\n%
%= Select option by character index =% For /F "Delims=" %%o in ('Choice /N /C:^^!CHCS^^!')Do (%\n%
%= Assign return var 'OPTION' with the =% Set "Option=^!Opt[%%o]^!"%\n%
%= value selected from Opt[CH#] array. =% If /I "^!Option^!" == "Exit" Exit /B 2%\n%
%= Return to previous script on Exit =% )%\n%
%= Capture Macro input - Options List =% )Else Set Options=
========================================== ::: End Menu Definition
:StartGame
:# Make the Session Local
Setlocal
==========================================:# MAIN GAME SCRIPT [ EXAMPLE ]
:# To Create / Continue a Character; Call Login. Errorlevel 0 = Returning Character
:# Modify The reponse to Errorlevel 1 [New Character] As you Wish to facilitate Creation of Character Classes.
:# Suggested: Use the Menu Macro with a list of Character Classes corresponding to functions and Call the selected class Label (IE - Call :Rogue)
Call :Login
If Errorlevel 2 Goto :Eof
If Errorlevel 1 (
Echo(Select your Class:
%Menu% Exit "Knight" "Rogue"
Call :!Option! 2>nul || (
Echo(The !Option! Class has not been created yet. Use the example of the :Knight function to create your own Classes.
Timeout /T 3 /NoBreak > Nul
Pause
Endlocal
Goto :StartGame
)
)
:# Use Labels as checkpoints by Defining them to the Variable #Location
If Errorlevel 0 If Defined #Location (Goto :!#Location!)
:# To [S]ell [E]quip or [D]rop Inventory:
:# If the Player is not in a Town / Shop; Use: Call :ManageInventory /ED to Lock out Sale of Items
Call :ManageInventory /ESD
:Home This and below Label locations are examples of using Label Checkpoints
CLS
Call :Inventory Home /L
:# Use last selected option to prevent recursive calls.
If not "!Option!" == "Home" (
%Menu% Exit "Manage Inventory" "Travel"
)Else %Menu% Exit "Manage Inventory"
If "!Option!" == "Manage Inventory" (
Call :!Option: =! /ESD
Goto :Home
)
If not "!Option!" == "Travel" Goto :Eof
:Travel
CLS
Call :Inventory Travel /L
Echo(Choose a Direction:
%Menu% Exit Home East West North South
Call :!Option: =! 2> Nul || If not Errorlevel 2 (
Echo That Direction has not been Scripted yet. You'll have to make your own Adventure.
Pause
)
Goto :Travel

Why is an exclamation mark not passed when calling other script?

This is the output of my two scripts. The first one calls the other and delivers a filename as %1
D:\VIDEOS\SHORTS>for %v in (*) do call namer "%v"
D:\VIDEOS\SHORTS>call namer "10 Products You’ll Never Buy Again Knowing How They Are Made!.mp4"
D:\VIDEOS\SHORTS>echo "10 Products You’ll Never Buy Again Knowing How They Are Made.mp4" | find /i ".tmp" 1>nul && exit /b
The echo uses "%~nx1".
My question is: Why does the exclamation mark disappear?
This started happening yesterday, but I'm not sure what I could've done to cause this. It's part of a massive batch script cluster, all of which I can't post here due to size limits so ask for additional details or generalize.
edit: requested file namer.cmd
set "full=" & set "file=" & set "name=" & set "type=" & set "year=" & set "episode=" & set "strict=" & set "loose="
echo "%~nx1" | find /i ".tmp" >nul && exit /b
set "file=%~n1"
:: =============================================================================================================================
:: 1. file VALIDATOR
:: =============================================================================================================================
set "original=%file%"
set "file=%file:!=%"
set "file=%file:#=%"
set "file=%file: _ = - %"
set "file=%file:’='%"
set "file=%file:“='%"
set "file=%file:”='%"
set "file=%file:[=(%"
set "file=%file:]=)%"
set "file=%file:_= %"
set "file=%file:—=-%"
set "file=%file: = %"
set "file=%file: = %"
set "file=%file:&=and%"
:: exclamation point has to be removed before we enable delayed expansion
if not "%file%"=="%original%" ren "%~1" "%file%%~x1" 2>nul && echo validated "%file%%~x1"
if not "%file%"=="%original%" if exist "%original%" ren "%~1" "%file% - copy%~x1" && echo validated "%file% - copy%~x1"
if not "%file%"=="%original%" if exist "%original%" ren "%~1" "%file% - copy 2%~x1" && echo validated "%file% - copy 2%~x1"
setlocal enabledelayedexpansion
set "original=!file!"
set "file=!file:%%=_percent!"
if not "%file%"=="%original%" ren "%~dp1%original%%~x1" "for /f "delims=" %%v in ('where /r "d:\videos" "%strict%*" 2^>nul') do" && echo validated "%original%"
set "original=!file!"
:: this needs to separated in order to add s01 tag if no season tag present
for /l %%s in (0,1,9) do set "file=!file:series.%%s.=S0%%s!"
for /l %%e in (0,1,9) do set "file=!file:%%eof2=E0%%e!"
for /l %%e in (0,1,9) do set "file=!file:%%eof3=E0%%e!"
for /l %%e in (0,1,9) do set "file=!file:%%eof4=E0%%e!"
for /l %%e in (0,1,9) do set "file=!file:%%eof5=E0%%e!"
for /l %%e in (0,1,9) do set "file=!file:%%eof6=E0%%e!"
for /l %%e in (0,1,9) do set "file=!file:%%eof7=E0%%e!"
for /l %%e in (0,1,9) do set "file=!file:%%eof8=E0%%e!"
for /l %%e in (0,1,9) do set "file=!file:%%eof9=E0%%e!"
:: if file has changed but no season tag present add s01
if not "%file%"=="%original%" echo "%file%" | find /i "s0" >nul || set "file=!file:E0=S01E0!"
if not "%file%"=="%original%" ren "%~dp1%original%%~x1" "%file%%~x1" && echo validated "%original%"
:: =============================================================================================================================
:: 2. EXTRAPOLATOR
:: =============================================================================================================================
:extrapolate
set "type=" & set "year=" & set "ss=" & set "ep=" & set "episode="
set "name=%file%"
echo "%name%"| find " " >nul || set "name=%name:.= %" & rem if no spaces then then safer to replace dots
:: if short do complete skip of movie/series extrapolator breakdown
echo "%~n1" | find /i "trailer" >nul && set "type=misc" && goto skipyear
echo "%~p1" | find /i "\shorts\" >nul && set "type=misc" && goto skipyear
echo "%~p1" | find /i "\movies\" >nul && set "type=film" && goto skipss
echo "%~p1" | find /i "\series\" >nul && set "type=show"
:: episode number: last tag first
FOR /L %%e IN (100,1,199) DO (
SET "modname=!name:E%%e=!"
IF "!modname!" neq "%name%" (
SET "setcmd=set name=!name:E%%e=& set ep=E%%e& set type=show& rem !"
GOTO gotep
)
)
FOR /L %%e IN (10,1,99) DO (
SET "modname=!name:E%%e=!"
IF "!modname!" neq "%name%" (
SET "setcmd=set name=!name:E%%e=& set ep=E%%e& set type=show& rem !"
GOTO gotep
)
SET "modname=!name:E0%%e=!"
IF "!modname!" neq "%name%" (
SET "setcmd=set name=!name:E0%%e=& set ep=E0%%e& set type=show& rem !"
GOTO gotep
)
)
FOR /L %%e IN (0,1,9) DO (
SET "modname=!name:E0%%e=!"
IF "!modname!" neq "%name%" (
SET "setcmd=set name=!name:E0%%e=& set ep=E0%%e& set type=show& rem !"
GOTO gotep
)
SET "modname=!name:E00%%e=!"
IF "!modname!" neq "%name%" (
SET "setcmd=set name=!name:E00%%e=& set ep=E00%%e& set type=show& rem !"
GOTO gotep
)
SET "modname=!name:%%eof=!"
IF "!modname!" neq "%name%" (
SET "setcmd=set name=!name:%%eof=& set ep=E0%%e& set type=show& rem !"
GOTO gotep
)
SET "modname=!name:x0%%e=!"
IF "!modname!" neq "%name%" (
SET "setcmd=set name=!name:x0%%e=& set ep=E0%%e& set type=show& rem !"
GOTO gotep
)
)
GOTO skipep
:gotep
%setcmd%
:skipep
:: season number: second to last tag second
FOR /L %%e IN (0,1,9) DO (
SET "modname=!name:S0%%e=!"
IF "!modname!" neq "%name%" (
SET "setcmd=set name=!name:S0%%e=& set ss=S0%%e& set type=show& rem !"
GOTO gotss
)
)
FOR /L %%e IN (10,1,99) DO (
SET "modname=!name:S%%e=!"
IF "!modname!" neq "%name%" (
SET "setcmd=set name=!name:S%%e=& set ss=S%%e& set type=show& rem !"
GOTO gotss
)
)
FOR /L %%e IN (0,1,9) DO (
SET "modname=!name:series.%%e=!"
IF "!modname!" neq "%name%" (
SET "setcmd=set name=!name:series.%%e=& set ss=S0%%e& set type=show& rem !"
GOTO gotss
)
)
GOTO skipss
:gotss
%setcmd%
:skipss
if defined ep if not defined ss set ss=S01
set "episode=%ss%%ep%"
:: year number: first tag last (first with brackets so not to confuse with imdb tag)
FOR /L %%e IN (1960,1,2020) DO (
SET "modname=!name:(%%e)=!"
IF "!modname!" neq "%name%" (
SET "setcmd=set name=!name:(%%e)=& set year=%%e& if not defined type set type=film& rem !"
GOTO gotyear
)
)
FOR /L %%e IN (1960,1,2020) DO (
SET "modname=!name:%%e=!"
IF "!modname!" neq "%name%" (
SET "setcmd=set name=!name:%%e=& set year=%%e& if not defined type set type=film& rem !"
GOTO gotyear
)
)
GOTO skipyear
:gotyear
%setcmd%
:skipyear
if not defined type set type=misc
:: other trimming for misc etc
set name=%name: - copy=&rem %
set name=%name: (1)=&rem %
set name=%name: (2)=&rem %
set name=%name: (3)=&rem %
set name=%name: [1]=&rem %
set name=%name: [2]=&rem %
set name=%name:360p=&rem %
set name=%name:480p=&rem %
set name=%name:720p=&rem %
set name=%name:1080p=&rem %
set name=%name:2160p=&rem %
:: changes for general use
set "name=%name: - = %"
set "name=%name: = %"
:: trim last useless letter from name
set "name=%name%endtrimmer"
set "name=%name:(endtrimmer=endtrimmer%"
set "name=%name:[endtrimmer=endtrimmer%"
set "name=%name:.endtrimmer=endtrimmer%"
set "name=%name:-endtrimmer=endtrimmer%"
set "name=%name: endtrimmer=endtrimmer%"
set "name=%name: endtrimmer=%"
set "name=%name:_endtrimmer=%"
set "name=%name:endtrimmer=%"
:: set strings
if "%type%"=="misc" set "strict=%name: =?%"
if "%type%"=="film" if defined year set "strict=%name: =?%?(%year%)"
:: caution: this allows movie to be renamed without year tag
:: if "%type%"=="film" if not defined year set "strict=%name: =?%"
if "%type%"=="show" if defined year set "strict=%name: =?%?(%year%)?%episode%"
if "%type%"=="show" if not defined year set "strict=%name: =?%?%episode%"
if "%type%"=="show" if defined year set "loose=%name: =?%?(%year%)?s"
if "%type%"=="show" if not defined year set "loose=%name: =?%?s"
FOR %%a IN (A B C D E F G H I J K L M N O P Q R S T U V W X Y Z) DO SET "name=!name:%%a=%%a!"
endlocal & set "full=%~dp1%file%%~x1" & set "file=%file%%~x1" & set "name=%name%" & set "type=%type%" & set "year=%year%" & set "episode=%ss%%ep%" & set "strict=%strict%" & set "loose=%loose%"
:: declare (disable never delete)
echo extrapolated %type% "%strict:?= %"
:: =============================================================================================================================
:: 3. FILEBOT MODERATOR
:: =============================================================================================================================
:: if rename not needed exit
if "%type%"=="misc" exit /b
if "%~2"=="-norename" exit /b
:: if already renamed we are done here
echo "%file%" | find /i " tt" >nul && exit /b
:: prep fake temp file
set tempdir=%temp%\%date:~3,2%%date:~6,2%%date:~11,2%%time:~1,1%%time:~3,2%%time:~6,2%%time:~9,2%
mkdir "%tempdir%" && copy /y nul "%tempdir%\%file%" >nul
:: variables (to shorten lines)
if "%type%"=="film" set cf=--db TheMovieDb --format "{n} ({y}) {director} {genres} r{rating} {vf} {vc} {ac} {imdbid}"
if "%type%"=="show" set cf=--db TheTVDb --format "{n} {s00e00} {t} {vf} {vc} {ac}-mallSanta"
:: rename fake temp file
filebot -rename "%tempdir%\%file%" --q "%name% %year%" %cf% >nul 2>nul
:: new name into variable
for /r "%tempdir%" %%i in (*) do set "new=%%~nxi"
:: declare failure
if "%file%"=="%new%" echo failed, reason: && filebot -rename "%tempdir%\%file%" --log warning --q "%name% %year%" %cf% & exit /b
:: check all strings against renamed orphan fake file and if successful rename 4real
for /f "delims=" %%v in ('where "%tempdir%:%strict%*" 2^>nul') do goto 4real
for /f "delims=" %%v in ('where "%tempdir%:%strict:s?='s?%*" 2^>nul') do goto 4real
for /f "delims=" %%v in ('where "%tempdir%:%strict:?-?=?%*" 2^>nul') do goto 4real
:: declare failure and confirm override
echo.
echo file "%file%" was renamed
echo to a "%new%", which was unexpected,
:: try the interactive command prompt mode in filebot?
choice /t 20 /c yn /n /d n /m "override and approve this rename? [Y]es or [N]o: "
if "%errorlevel%"=="1" goto 4real
exit /b
:4real
filebot -rename "%~dp1%file%" --q "%name% %year%" %cf% >nul 2>nul
if not exist "%~dp1%file%" echo successfully renamed "%file%"
:: validate the new file (maybe just send to validate with a -norename? takes longer but clearer code
set "original=%file%"
set "file=%file:!=%"
set "file=%file:#=%"
set "file=%file: _ = - %"
set "file=%file:’='%"
set "file=%file:“='%"
set "file=%file:”='%"
set "file=%file:_= %"
set "file=%file:—=-%"
set "file=%file: = %"
set "file=%file: = %"
set "file=%file:&=and%"
if not "%file%"=="%original%" ren "%~1" "%file%" && echo validated "%original%"
setlocal enabledelayedexpansion
set "original=!file!"
set "file=!file:%%= percent!"
if not "%file%"=="%original%" ren "%~dp1%original%%~x1" "%file%" && echo validated "%original%"
endlocal
exit /b
it (1.) removes problematic characters from the filename (2.) from filename extrapolates video name, year, other variables, then (3.) does a supervised filebot rename. the setlocal and endlocal bits look good. could it be the problem is inherited from yet another script?
You have enabled delay environment variable expansion with setlocal EnableDelayedExpansion somewhere above the ECHO line in batch script namer.
Therefore the exclamation mark is not further interpreted as literal character, but as begin/end of a variable reference expanded delayed.
We would need the batch code of namer batch file to help you solving this issue.
It looks like the line is for checking if the file contains .tmp, i.e. has the file extension .tmp and if this is the case, ignore the file.
I suggest to change in your first batch file
for %%v in (*) do call namer "%%v"
to
for %%I in (*) do if /I not "%%~xI" == ".tmp" call "%~dp0namer.cmd" "%%I"
Then files with file extension .tmp are not processed at all by namer batch file.
Run in a command prompt window set /? for more information about delayed expansion and for /? for help on %~xI (file extension of file) as well as if /? for help on command IF and call /? for help on %~dp0.
It is also possible to use in namer.cmd:
if /I "%~x1" == ".tmp" goto :EOF
This exits processing of the batch file namer.cmd if the file extension of first argument is .tmp (compared case-insensitive). For this comparison it does not matter if delayed expansion is enabled or not. See also answer on Where does GOTO :EOF return to?
If .tmp is not the file extension of the file, but is just somewhere within file name, it is possible to use an IF with string substitution.
Example for batch file namer.cmd.
set "FileName=%~nx1"
if not "%FileName:.tmp=%" == "%FileName%" goto :EOF
The first line assigns file name with extension but without path to environment variable FileName.
The second line compares case-sensitive the file name string in which all occurrences of .tmp are replaced case-insensitive with an empty string with the file name string not modified at all. The two compared strings are not equal if the file name string really contains .tmp 1 or more times resulting in exiting processing of the batch file.
In other words the IF condition checks if a string assigned to an environment variable contains case-insensitive the string specified between : and =.
That is similar to using in C:
#include <string.h>
int main(int argc, char *argv[])
{
if(argc > 1)
{
/* Does first argument contain the string ".tmp"? */
if(strstr(argv[1],".tmp") != NULL) return 1;
}
return 0;
}
Function strstr is case-sensitive.
here is a method where you can use delayedexpansion without the use of escape characters.
#echo off
setlocal disabledelayedexpansion
set myfile="10 Products You’ll Never Buy Again Knowing How They Are Made!.mp4"
echo %DB_password%
setlocal enabledelayedexpansion
echo !myfile!

Coping with for loop batch file issues when splitting a text file

Good Afternoon!
Long time reader, first time poster! I have been having a lovely time trying to modify a working batch file to account for variability. The situation is that I have a variable-size text document that normally would be able to be split into sections of 252 lines. The code below worked like a champ:
#echo off & setlocal EnableDelayedExpansion
set param=%*
if not defined param (
echo.
echo. Usage: batchsplit [device:][pathname]filename
goto :EOF
)
set param=%param:"=%
if not exist "%param%" (
echo.
echo. File "%param%" not found
goto :EOF
)
for %%j in ("%param%") do (
set name=%%~dpnj
set ext=%%~xj
)
for /F %%j in ('type "%param%" ^| find /V /C ""') do set Full=%%j
set /A Split=%Full%/252
for /L %%G in (1,1,%Split%) do type nul > "%name%_%%G%.new"
set X=1
set N=1
set Q=1
set limit = 252
for /F "tokens=1* delims=]" %%j in ('type "%param%" ^| find /V /N ""') do (
set /A N+=1
set /A Q+=1
echo.%%k>> "%name%_!X!%.new"
if !Q! gtr 252 (
set /A X+=1
set /A Q=1
) else if !N! gtr Full (goto theend
)
)
:theend
echo split into %split% files with 252 lines each
rem pause
However, there were some changes to the formatting of the text, and now instead of four pages of 63 lines per split file, it can be completely variable. The only constant is this final line, which precedes the remaining space for a 63 line page:
ON THIS FORM IS COMPLETE AND CORRECT AS NOTED:___________________
Note that there is a single space in front of it, as well as multiple spaces, a colon, and underscore characters. Being the meathead that I am, I thought I could insert an if-then statement into the for loop to trigger the batch to split to the next page. However, I could be further from that right now. This is the code I have been smashing my head with:
rem #echo off & setlocal EnableDelayedExpansion
setlocal EnableDelayedExpansion
set param=%*
if not defined param (
echo.
echo. Usage: textsplit [device:][pathname]filename
goto :EOF
)
set param=%param:"=%
if not exist "%param%" (
echo.
echo. File "%param%" not found
goto :EOF
)
for %%j in ("%param%") do (
set Name=%%~dpnj
set ext=%%~xj
)
for /F %%j in ('type "%param%" ^| find /V /C ""') do set Full=%%j
set stopvar= ON THIS FORM IS COMPLETE AND CORRECT AS NOTED:___________________
set Split=1
echo %stopvar%
set X=1
type nul > "%name%_!X!%.new"
set N=1
set Q=1
set S=0
set L=63
for /F "tokens=1* delims=]" %%j in ('type "%param%" ^| find /V /N ""') do (
set /A N+=1
echo %N%
set /A Q+=1
echo %Q%
echo.%%k>> "%name%_!X!%.new"
if ["%%k%" == "!stopvar!"] (
set /A S+=1
)
if !Q! gtr !L! (
if !S! == 1 (
set /A X+=1
set /A Q=1
type nul > "%name%_!X!%.new"
set /A Split+=1
set S=0
)
else set /A L+=63
else if !N! gtr Full goto theend
)
:theend
echo Split into %split% files!
pause
The premise is that every 63 lines, the stop variable (S) is checked. If it is off (0) then the batch will continue to write for another 63 lines (one page). If the stopvar matches the line that is being read by the for loop, S becomes 1. When the program checks again, it will create a new file and begin writing to that new file. Right now, based on turning off #echo off the hangup is at the for loop. See below:
C:\Users\theangryasiancp\Desktop\TEXT_Split_Test>rrtextsplit texttest.txt
C:\Users\theangryasiancp\Desktop\TEXT_Split_Test>rem #echo off & setlocal Enabl
eDelayedExpansion
C:\Users\theangryasiancp\Desktop\TEXT_Split_Test>setlocal EnableDelayedExpansio
n
C:\Users\theangryasiancp\Desktop\TEXT_Split_Test>set param=texttest.txt
C:\Users\theangryasiancp\Desktop\TEXT_Split_Test>if not defined param (
echo.
echo. Usage: rrtextsplit [device:][pathname]filename
goto :EOF
)
C:\Users\theangryasiancp\Desktop\TEXT_Split_Test>set param=texttest.txt
C:\Users\theangryasiancp\Desktop\TEXT_Split_Test>if not exist "texttest.txt" (
echo.
echo. File "texttest.txt" not found
goto :EOF
)
C:\Users\theangryasiancp\Desktop\TEXT_Split_Test>for %j in ("texttest.txt") do
(
set Name=%~dpnj
set ext=%~xj
)
C:\Users\theangryasiancp\Desktop\TEXT_Split_Test>(
set Name=C:\Users\theangryasiancp\Desktop\TEXT_Split_Test\texttest
set ext=.txt
)
C:\Users\theangryasiancp\Desktop\TEXT_Split_Test>for /F %j in ('type "texttest.
txt" | find /V /C ""') do set Full=%j
C:\Users\theangryasiancp\Desktop\TEXT_Split_Test>set Full=567
C:\Users\theangryasiancp\Desktop\TEXT_Split_Test>set stopvar= ON THIS FORM IS C
OMPLETE AND CORRECT AS NOTED:___________________
C:\Users\theangryasiancp\Desktop\TEXT_Split_Test>set Split=1
C:\Users\theangryasiancp\Desktop\TEXT_Split_Test>echo ON THIS FORM IS COMPLETE
AND CORRECT AS NOTED:___________________
ON THIS FORM IS COMPLETE AND CORRECT AS NOTED:___________________
C:\Users\theangryasiancp\Desktop\TEXT_Split_Test>set X=1
C:\Users\theangryasiancp\Desktop\TEXT_Split_Test>type nul 1>"C:\Users\theangry
asiancp\Desktop\RRRR_Split_Test\texttest_!X!.new"
C:\Users\theangryasiancp\Desktop\TEXT_Split_Test>set N=1
C:\Users\theangryasiancp\Desktop\TEXT_Split_Test>set Q=1
C:\Users\theangryasiancp\Desktop\TEXT_Split_Test>set S=0
C:\Users\theangryasiancp\Desktop\TEXT_Split_Test>set L=63
C:\Users\theangryasiancp\Desktop\TEXT_Split_Test>
What are your thoughts? Where am I going wrong with the batch? I wish I could use something different, but alas I cannot, for internal company reasons. Thanks for your help!
#ECHO OFF
SETLOCAL ENABLEDELAYEDEXPANSION
SET "name=q23396663"
SET "ext=.txt"
SET /a pagelength=10
SET "targetstring= ON THIS FORM IS COMPLETE AND CORRECT AS NOTED:___________________"
SET /a filenum=0
SET /a linecount=pagelength + 1
FOR /f "tokens=1*delims=]" %%a IN (
'find /v /n "" "%name%%ext%"') DO (
IF !linecount! GEQ %pagelength% (
SET /a linecount=0
SET /a filenum+=1
)
>>U:\%name%_!filenum!.new ECHO(%%b
IF "%%b"=="%targetstring%" SET /a linecount=pagelength
SET /a linecount+=1
)
GOTO :EOF
For testing purposes, I set up a file q23396663.txt containing your trigger data. I've left the destination directory as U:\ which suits me, and the pagelength at 10 which makes my testing easier.
#echo off
setlocal EnableDelayedExpansion
REM ------------------THIS SECTION SPECIFIES THE FILE-------------------------
set param=%*
if not defined param (
echo.
echo. Usage: filesplit [device:][pathname]filename
goto :EOF
)
set param=%param:"=%
if not exist "%param%" (
echo.
echo. File "%param%" not found
GOTO :EOF
)
for %%j in ("%param%") do (
set name=%%~dpnj
set ext=%%~xj
)
ECHO SPLITTING %name%.%ext% .................
REM ----------------THIS SECTION SETS THE VARIABLES---------------------------
set "trigger= ON THIS FORM IS COMPLETE AND CORRECT AS NOTED:___________________"
set /a pagelength=63
set /a filenum=0
set split=1
set /a linecount=pagelength
set stopvar=0
REM ------------------THIS SECTION IS THE FOR LOOP----------------------------
FOR /f "skip=2 tokens=1* delims=]" %%a IN (
'find /v /n "" "%name%%ext%"') DO (
SET /a linecount-=1
IF !linecount! LEQ 0 (
IF !stopvar! EQU 1 (
SET /a "linecount=pagelength"
SET /a filenum+=1
SET /a split+=1
SET /a stopvar-=1
) else set /a "linecount=pagelength"
)
echo.%%b>> "%name%_!filenum!.new"
IF "%%b"=="%trigger%" (
set /a "stopvar+=1"
REM THIS TRIGGERS TO CHANGE OUTPUT
set /a linecount+=1
REM THIS WILL ADJUST THE OUTPUT EOF
)
)
REM ----------------THIS SECTION ENDS THE FOR LOOP----------------------------
ECHO Split into %split% files!
ping 1.1.1.1 -n 1 -w 2500 > nul
REM THIS PAUSES THE BATCH FOR A SEC
As I posted in the comment above, this is just a variation of the first answer that accounts for blank spaces if they are needed to keep the output files from having unnecessary whitespace on top. This is especially helpful when a print manager is just spitting out whitespace until the end of the page before starting the next part instead of going straight to the next portion.

Resources