batch file - 'The Syntax of the command is incorrect' - batch-file

I've been making a text-adventure, but towards the end of my coding it came up with this error. Every time I try to continue from scene 5 to scene 5.1 it goes to a different scene and skips through it. Help?
Here is my code:
cls
echo You walk in through the doorframe, and into the dark room. You can't see a thing in the gloom, but when you put your hand on the wall you recognise the shape of a lightswitch.
echo.
pause
goto scene5.1
cls
echo You walk in through the doorframe, and into the dark room. You can't see a thing in the gloom, but when you put your hand on the wall you recognise the shape of a lightswitch.
echo.
pause
goto scene5.1
:scene5.1
cls
echo You flip the lightswitch down, and slowly the glowing bulbs switch on; illuminating the living room. In the gradually increasing light you see a table in the corner, and a large sofa that streches across the back wall. A few metres in front of the couch is a fireplace.
echo.
echo 1) Table
echo 2) Sofa
echo 3) Fireplace
echo 4) Go back
set /p type
if %type%==1 goto scene5.1.1
if %type%==2 goto scene5.1.2
if %type%==3 goto scene5.1.3
if %type%==4 goto scene5.1.4

C:\Windows\system32>echo 4) Go back
4) Go back
C:\Windows\system32>set /p type
The syntax of the command is incorrect.
goto was unexpected at this time.
It's probably the lack of an equals sign in set /p (well I know it is).
PS: Set /p var = PromptText is not the best command. It doesn't prevent wrong entry, and you don't check for it. Use Choice command instead. It only takes allowed entry.
The reason most examples use set /p is because choice was dropped from one windows version 15 years ago. That was along time ago.
CHOICE [/C choices] [/N] [/CS] [/T timeout /D choice] [/M text]
Description:
This tool allows users to select one item from a list
of choices and returns the index of the selected choice.
Parameter List:
/C choices Specifies the list of choices to be created.
Default list is "YN".
/N Hides the list of choices in the prompt.
The message before the prompt is displayed
and the choices are still enabled.
/CS Enables case-sensitive choices to be selected.
By default, the utility is case-insensitive.
/T timeout The number of seconds to pause before a default
choice is made. Acceptable values are from 0 to
9999. If 0 is specified, there will be no pause
and the default choice is selected.
/D choice Specifies the default choice after nnnn seconds.
Character must be in the set of choices specified
by /C option and must also specify nnnn with /T.
/M text Specifies the message to be displayed before
the prompt. If not specified, the utility
displays only a prompt.
/? Displays this help message.
NOTE:
The ERRORLEVEL environment variable is set to the index of the
key that was selected from the set of choices. The first choice
listed returns a value of 1, the second a value of 2, and so on.
If the user presses a key that is not a valid choice, the tool
sounds a warning beep. If tool detects an error condition,
it returns an ERRORLEVEL value of 255. If the user presses
CTRL+BREAK or CTRL+C, the tool returns an ERRORLEVEL value
of 0. When you use ERRORLEVEL parameters in a batch program, list
them in decreasing order.
Examples:
CHOICE /?
CHOICE /C YNC /M "Press Y for Yes, N for No or C for Cancel."
CHOICE /T 10 /C ync /CS /D y
CHOICE /C ab /M "Select a for option 1 and b for option 2."
CHOICE /C ab /N /M "Select a for option 1 and b for option 2."
As help says use errorlevels in descending order
if errorlevel 4 dosomething
if errorlevel 3 dosomething
if errorlevel 2 dosomething
if errorlevel 1 dosomething
if errorlevel 0 UserPressedCtrl+C
or in any order
if errorlevel 1 if not errorlevel 2 dosomething for 1
Do not use %errorlevel% as it can be overwritten by other programs.

#ECHO OFF
SETLOCAL
:scene4.6.1
:scene5.1
SET "scene=5.1"
cls
echo You flip the lightswitch down, and slowly the glowing bulbs switch on; illuminating the living room. In the gradually increasing light you see a table in the corner, and a large sofa that streches across the back wall. A few metres in front of the couch is a fireplace.
echo.
CALL :addchoice Table Sofa Fireplace "Go back"
GOTO makechoice
:scene5.1.1
ECHO AT table
goto :eof
:scene5.1.2
ECHO AT sofa
goto :eof
:scene5.1.3
ECHO AT fireplace
goto :eof
:scene5.1.4
:scene4.6
SET "scene=4.6"
echo You are IN a dank corridor dimly lit by sputtering torches
echo.
CALL :addchoice Doorway Corridor
GOTO makechoice
:makechoice
CHOICE /C %choices%
SET "scene=%scene%.%errorlevel%"
SET /a choicecount=0
SET "choices="
GOTO scene%scene%
:addchoice
SET /a choicecount+=1
ECHO %choicecount%) %~1
SET "choices=%choices%%choicecount%"
SHIFT
IF "%~1" neq "" GOTO addchoice
GOTO :EOF
This may save you a heap of programming. Please do not accept it as an answer since bgalea's answer actually answers your question. This is just an approach to make the construct-an-adventure exercise faster and easier.
For each scene, describe the scene and call :addchoice with parameters of the available choices. If a choice is multiple words, "enclose them in quotes".
The routine assigns 1 to the first choice in the list, 2 to the next and so on. The available choices are then recorded in choices.
go to makechoice. This prompts for an entry using the list in choices. Then append dot+the errorlevel of the response to the current scene number, clear the choices and goto scene+the calculated scene number.
Note that you can use an empy command-sequence to move between scenes by using the structure like in scene5.1.4 to scene4.6 (iow, scene 5.1+choice4 moves to 4.6)
This way, your response-sets become one line after your scene description and you never need to use a series of if-commands to move between scenes.

Related

Is it possible to create an interactive notepad within batch script that saves users input

I'm in the process of creating a mini-game using batch and one of the useful tool ideas was to have an interactive notepad so that users could store information throughout the game and refer back to it later. So far I have created the option to goto a notepad within an In-game pause menu but wasn't sure if it was possible to save results without outputting to new file on the desktop
:PauseMenu
cls
echo.
echo %Alias%
echo.
echo Notepad
echo Stats
echo Untitled2
echo Untitled3
echo Untitled4
echo Untitled5
echo Untitled6
set/p PauseMenu="N, S"
IF ["%PauseMenu%"]==["N"] goto Notepad
IF ["%PauseMenu%"]==["S"] goto Stats
IF ["%PauseMenu%"]==["N"] goto
IF ["%PauseMenu%"]==["N"] goto
IF ["%PauseMenu%"]==["N"] goto
IF ["%PauseMenu%"]==["N"] goto
IF ["%PauseMenu%"]==["N"] goto
Any help would be appreciated, thanks.
PS is it possible to go back to the previous page from a menu?
Simplicity itself.
First, some renaming may be in order. notepad is a supplied utility and pausemenu is being used both as a variable and as a label. This is not invalid, but can be a little confusing.
Further, if you are choosing between a set of keys, I'd suggest you investigate choice. choice has a number of advantages, like it only accepts one character, no enter is required and it's not necessary to analyse the entry.
So: revising your code:
:p_pausemenu
pause
:PauseMenu
cls
echo.
echo %Alias%
echo.
echo N Notepad
echo S Stats
echo 1 Untitled2
echo Z Untitled3
echo Q Untitled4
echo J Untitled5
echo X Untitled6
:: Note that the processing of ERRORLEVEL must be in reverse order
choice /c ns1zqjx
if errorlevel 7 goto labelx
if errorlevel 6 goto labelj
if errorlevel 5 goto labelq
if errorlevel 4 goto labelz
if errorlevel 3 goto label1
if errorlevel 2 goto stats
if errorlevel 1 goto unotepad
:unotepad
start "Notes for %alias%" notepad "c:\gamedirectory\%alias%.txt"
goto pausemenu
:stats
:: List your stats here
echo Stats for %alias%
goto p_pausemenu
Here, a menu with a number of unimplemented options is presented and the choice command (see choice /? from the prompt for more options) waits for a choice to be made.
errorlevel is set according to the choice made - but since if errorlevel n means if errorlevel is n OR GREATER THAN n you need to process errorlevel in reverse order.
Then each selection is processed. n will start a notepad instance and load the alias.txt file from the game directory, then present the menu again as it returns to pausemenu. s will show the stats (idk what you need for that) and then return to p_pausemenu which will pause and then proceed to show the menu when the user signals to do so.

How do I save variables from a batch file then load them to use them?

I'm a pretty inexperienced coder and I love batch because its one of the more straight forward coding languages but I want to save multiple variables to a txt file or other format then "load" those same variables to the batch file not to type so the player can see but so that I can use it
This is what I have so far for loading:
:nick
cls
color 02
set /p nick= Enter your nickname:
if exist ((savegame%nick%.txt) goto load)
goto instructions
:load
for /f "blevel=" %%a in (savegame%nick%.txt) do set blevel=%%a&goto loadexist
for /f "mlevel=" %%a in (savegame%nick%.txt) do set mlevel=%%a&goto loadexist
for /f "alevel=" %%a in (savegame%nick%.txt) do set alevel=%%a&goto loadexist
this is what I have for saving:
:save
cls
echo Saving please wait...
(echo blevel=%blevel%)> savegame%nick%.txt
(echo mlevel=%mlevel%)>> savegame%nick%.txt
(echo alevel=%alevel%)>> savegame%nick%.txt
timeout /t 5 /nobreak >nul
exit
Like I said I'm very inexperienced and my goal is to create a game please feel free to point out any flaws. In my game I have 3 characters Brutus, Mediana, and Achilles. blevel, mlevel, and alevel refers to the place in the game where you are and the character you chose to play as so you don't have to play the whole game to get to where you were.
As this is obviously still a work in progress I only have one instance where you can save and its in the first Brutus promt:
:brutus 1
set blevel=1
cls
echo.
echo.
echo.
echo You chose brutus good choice but are you sure this is who you want?
echo 1) go back and choose
echo 2) continue
echo 0) save
set /p c=C:\
if "%c%" == 1 goto choose character
if "%c%" == 2 goto brutus 2
if "%c%" == 0 goto save
goto brutus 1
So when you get to a choice like this your respective level goes up. Every time I reopen the game it either closes cmd when I type the nickname I used to save the file or it doesn't work and skips over it like the file or the variables in it don't exist. My intention is to do this with all three characters at every crucial choice so in the end I will probably have at least 100 per character.
your "save" logic is ok.
For loading, you need just a single line:
for /f "delims=" %%i in (savegame%nick%.txt) do set "%%i"
When you run it with echo on, you see that it processes every line and sets your variables.

Real time keyboard inputs in batch

This link
https://www.youtube.com/watch?v=eULe3DNS8DM
Shows a game made in batch. The game, called viewpoint, allows you to move around and shoot at enemies. This game seems to accept keyboard input in real time to perform actions. Is there any way I can get my batch file to accept keyboard input in real time as well?
(Guessing by the "Core" folder I saw in the game folder, there might be some other program or command involved.)
You could use the choice command (which is what snake.bat uses) however it can only take alpha-numeric input one at a time.
Here is a quick program I whipped up which uses choice to take WASD input.
#setlocal enableextensions enabledelayedexpansion
#echo off
prompt $$$G
title movement
color 0a
set length=
for %%a in (1 2 3) do (
set "length=!length! "
)
:controls
cls
echo Use WASD to move your character ([]).
echo.
echo %length%[]
choice /c wasd /n
if %errorlevel% equ 1 call:up
if %errorlevel% equ 2 call:left
if %errorlevel% equ 3 call:down
if %errorlevel% equ 4 call:right
:left
set length=!length:~0,-1!
goto controls
:right
set "length= %length%"
goto controls
:up
set length=!length:~0,-80!
goto controls
:down
set "length= %length%"
goto controls
The main thing you should focus on is the :controls label and how it uses the choice command to read input.

batch file sub routine

I'm trying to re-use the batch file code in order to perform a similar tasks in a menu pages.
The main menu consists of 10+ options.
When I go inside the each menu items, I need to display a following in text
Press [C] to Continue or [X] to exit [C/X]: _
I created labels in each menu time and re-direct to the code which is responsible for prompting the message and do necessary actions.
How can I use this following code as a subroutine, so that I don't have to re-write the code several times.At the moment I hard code it in each menu item. It would have been easy to call it as a sub routine.
:MiniMenu1
SET INPUT1=
SET /P INPUT1=Press [Y] to Continue Installation or [N] to go back [Y/N]:
IF /I '%INPUT1%'=='y' GOTO Mini_cont1
IF /I '%INPUT1%'=='n' GOTO Mini_back1
ECHO ============INVALID INPUT============
ECHO Please select a number from the Menu Options
ECHO -------------------------------------
ECHO ======PRESS ANY KEY TO CONTINUE======
PAUSE > NUL
GOTO MiniMenu1
Where as my code for main menu item pages are
:Selection1
:: MAin menu item 1
GOTO MiniMenu1
:Mini_cont1
:: xCopy update.zip C:\python27\ /y
#echo Update Completed.
pause
:Mini_back1
:: end
GOTO MENU
Ah - thinking along the right lines. Very good.
#echo off
setlocal
call :ask Question number one
if errorlevel 2 goto Q1X
call :ask Question number two
if errorlevel 2 goto Q2X
::get here for Q1Q2 responses both C
goto :eof
:ask
choice /c CX /N /M "%*"
goto :eof
Here's a basic template. From the prompt, type choice /? for instructions about options.
Hint: set "choices=wqzk" then in the subroutine choice /c %choices% /N /M "%*" would allow you to change the choices available. /n prompts with the available choices, so you've no need to specify that in the text, just make it obvious - Whatever, Quit, Zap, Kill should be obvious for wqzk for instance.
The return in %errorlevel% will the the sequence-number of the character chosen. W==>1, Q==>2..K==>4. In the traditional construct, if errorlevel n the comparison is true if errorlevel is n or greater than n so it would be traditional to use
if errorlevel 4 goto QnA4
if errorlevel 3 goto QnA3
if errorlevel 2 goto QnA2
:: if it gets here, errorlevel is 1 hence choice was first character.
which is shorter than the "modern" way
if %errorlevel%==1 goto QnA1
if %errorlevel%==2 goto QnA2
if %errorlevel%==3 goto QnA3
:: if it gets here, errorlevel is 4 or more hence choice was fourth or later character.
Note: %* means all of the arguments passed to the subroutine so /m "%*" neatly shows the arguments passed as a prompt. There's no voodoo about that. But be careful - text only and a few symbols if you like. Symbols with a special meaning to cmd may cause unexpected results
Variables created/changed/deleted after a setlocal will be deleted/restored/resurrected when a matching endlocal is encountered. Consequently, setlocal is often used as the first "action statement" in a batch - the environment is restored to pristine when the batch ends.
To remove variables within a batch using a subroutine, you could use
call :zap we dont want these variables
:zap
if "%1" neq "" set "%1="&shift&goto zap
goto :eof
(to delete variables we dont want these and variables
or :zap version 2
:zap
for %%a in (%*) do set "%%a="
goto :eof
To remove variables which all start with an identical character-pattern, use
FOR /F "delims==" %%a In ('set $ 2^>Nul') DO SET "%%a="
(which will remove all variables starting $. $ isn't holy - you could substitute xyz for $ here and zap xyz123 xyz789 and xyzylofone for instance)
Naturally, you could also combine the techniques...
But - it's not expensive to ask a new question on SO. Not expensive at all. Cheap even. Asking a new question rather than tagging more issues onto an existing one makes finding a solution easier (like.. someone wanting to know how to delete variables possibly wouldn't expect to find it under a question titled "batch file sub routine" for instance. It also prevents the question from becoming a saga.

Goto not working correctly in batch?

I have a few things set up in a batch game. Instead of going where it is supposed to when the sure enters an option and hits "Enter" it goes to the next thing that starts with a : (I don't know what it is called).
Instead of it going to "Youtube" when the user types "Y".
:visitoption
echo Would you like to visit the RST Garry's mod gaming community website?
set /p option=Y or N:
if %option%==Y start chrome (Censored link)
if %option%==N cls goto :youtube
if %option%==y start chrome (Censored link)
if %option%==n cls goto :youtube
:version
cls
#echo off
echo.
echo[
#echo off
echo.
echo[
echo --Version--
echo Lightup Demo
#echo off
echo.
echo[
#echo off
echo.
echo[
#echo off
echo.
echo[
pause
goto :versionwhite
:youtube
echo Would you like to visit the Creator's Youtube channel?
echo Gameplay commentarys and such.
set /p option=Y or N:
if %option%==Y start chrome (Censored link)
if %option%==N goto :Beginning
if %option%==y start chrome (Censored link)
if %option%==n goto :Beginning
Essentially you were missing a command separator after the CLS but I've made some other changes such as /i case insensitive comparing and made the checking routines more robust to spaces or no input.
:visitoption
echo Would you like to visit the RST Garry's mod gaming community website?
set /p option=Y or N:
if /i "%option%"=="Y" start "" chrome "(Censored link)"
if /i "%option%"=="N" cls & goto :youtube
goto :visitoption
The "thing" is called a label
Since you have no control over what the user types, you should use
if "%option%"=="Y" start chrome (Censored link)
that is, quote both sides of the comparison (this is not bullet-proof, but serves adequately where the user is not deliberately trying to break your system.)
Adding the /i switch to the if will make the comparison case-insensitive.
if defined option set "option=%option:~0,1%"
will set option to just the first character.
Note that if the user replies simply Enter then the value of the variable remains unchanged. You can use this characteristic to your advantage
set "option=defaultvalue"
set /p option=Y or N:
will set option to defaultvalue if the user replies simply Enter.
start will start a process independently. The batch simply carries on to the next statement. You are probably beter off using start "window title for this instance" ... - it's a quirk of start that the first "quoted parameter" is used as the window title where you may be expecting it to be used as a parameter.
To concatenate a series of commands in a single line, you need to separate the individual commands with an ampersand &
Once you've turned echo off once, you don't need to do it again (unless you execute echo on, which you can do during debugging to show the program flow.) The leading # means don't echo this command - without it, the initial ECHO OFF would be reproduced.
You can use call :label to execute a subroutine that starts at :label in this batch file. If you use call label then the "subroutine" executed is the executable label. This is a very important distinction.
For this reason, I eschew the use of goto :label - although it works - because the colon is not necessary and for congruence between the goto and call commands.
The one exception to this omit-the-colons approach is where the colon actually does have an effect - goto :eof very specifically means 'goto the physical end of this batch file' - the label :eof is understood by cmd to have that meaning, and should not be defined in the batch.
You've set it so that it goes to youtube when the user presses n, not when the user enters y like you said your trying to in the question:
if %option%==N cls goto :youtube
Please try seeing what the cod eyour using is doing before you post a question on it.
And SO has one of the worlds easiest CodeSlabing systems. HOW BLOODY HARD IS IT TO PRESS SPACE 4 TIMES OR HIGHLIGHT AND PRESS THE "Code Sample" BUTTON?
Mona.

Resources