Calling an IF statement | Batch - batch-file

Error Code:
If was unexpected at this time
The code sets the stats for each player then it calls the function to determine the amount of damage based on the stats and other variables
What I want to do is call a function with two IF statements within it
Example:
#echo off
set /a level=5
set /a opponentLevel=5
set /a movePower=50
set moveType=physical
goto player
:damageCalculator
if %moveType%==physical (
pause
set /a damage=(((( 2 * %level% / 5 + 2) * %attackStat% * %movePower% / %opponentDefenceStat%) / 50) + 2)
set /a opponentHealth-=%damage%
) else if %moveType%==special (
set /a damage=(((( 2 * %level% / 5 + 2) * %spAttackStat% * %movePower% / %opponentSpDefenceStat%) / 50) + 2)
set /a opponentHealth-=%damage%
)
goto :eof
:player
set type=fire
set/a health=19
set/a attackStat=10
set/a defenceStat=10
set/a spAttackStat=11
set/a spDefenceStat=10
set/a speedStat=12
:opponent
set /a opponentHealth=18
set /a opponentAttackStat=10
set /a opponentDefenceStat=9
set /a opponentSpAttackStat=8
set /a opponentSpDefenceStat=9
set /a opponentSpeedStat=13
:attack
pause
cls
call :damageCalculator
echo It did %damage% Damage!!
pause>nul
Is this just one of those things that batch can't do?

update per edited question
Your script has a few small issues. Firstly, I'll point out that it's often helpful to rem out #echo off when trying to track down the cause of a problem. Doing so in this case shows that the line causing your error is your first set /a line.
The reason your if statements are failing is because the parentheses within your math are being treated as the end of your code block. As soon as the closing parenthesis of ...5 + 2) is encountered, the batch interpreter treats that as the end of your if statement, and therefore gets confused when there's more stuff on the line. You need to quote your set /a statements to prevent this.
set /a "damage=(((( 2 * level / 5 + 2) * attackStat * movePower / opponentDefenceStat) / 50) + 2)"
See how I did set /a "variable=value" there? You could also escape the closing parentheses with a caret -- e.g. ^), but quoting the "var=value" is a little easier to read I think. The quotation marks keep the contents within the context of the command. They're basically saying, "This is a single token. It's a distinct part of the set command, not the code block as a whole." As a bonus, you can also see that the % signs aren't needed to retrieve variable values within a set /a command. Neat, huh?
You've got another problem. Since you're setting the %damage% variable within the same parenthetical code block as you're retrieving it, %damage% is going to be evaluated too early. You could setlocal enabledelayedexpansion and retrieve it as !damage!, and that would certainly work. But there's a simpler fix. Just put it outside the if statements. You're doing set /a opponentHealth-=damage regardless of whether the move type is physical or special, anyway, right?
:damageCalculator
if "%moveType%"=="physical" (
set /a "damage=(((( 2 * level / 5 + 2) * attackStat * movePower / opponentDefenceStat) / 50) + 2)"
) else if "%moveType%"=="special" (
set /a "damage=(((( 2 * level / 5 + 2) * spAttackStat * movePower / opponentSpDefenceStat) / 50) + 2)"
)
set /a opponentHealth-=damage
goto :eof
But still, you should include setlocal just below #echo off to keep from junking up your environment with variables that have no meaning outside the scope of this script.
Here's another tip. You can combine many statements within a single set /a line.
Before:
set /a level=5
set /a opponentLevel=5
set /a movePower=50
set "moveType=physical"
After:
set /a level=5, opponentLevel=5, movePower=50
set "moveType=physical"
original answer
Change your second if to else if or add a carriage return before it (after the preceding parenthesis). Also, move your goto :EOF to the next line after the closing parenthesis.
The explanation for this is that the cmd interpreter treats a parenthetical code block as a single command. So in essense,
if [true condition] (
action
) second command
is being evaluated as
if [true condition] (action) second command
which results in an error because there's no line break or other separator between the first command (the if) and the second. Here's an example of a valid compound command:
#echo off & setlocal
Compound command need:
unconditional AND (& -- right side always executes after the left)
example: endlocal & goto :EOF
logical AND (&& -- right side executes only if the preceding command exited zero)
example: find /i "text" "textfile.txt" >NUL && echo Text was found
pipe (| -- makes the command on the right do something with the output generated by the command on the left)
example: dir /s /b | more
logical OR (|| -- right side executes only if the preceding command exited non-zero)
example: tasklist | find /i "iexplore.exe" >NUL || echo Internet Explorer not running
... or in the case of an if statement, else.
if condition 1 (
action 1
) else if condition 2 (
action 2
) else (
action 3
)
Or if you want to check that two conditions are true:
if %var% leq 10 if %var% geq 5 (
echo Variable is between 5 and 10.
)
Of course, you don't have to use compound statements. There's no reason why a function can't have multiple if statements that aren't compound.
:fn <str>
if "%~1"=="fish" (echo Bloop.)
if "%~1"=="cats" (echo Meow.)
if "%~1"=="dogs" (echo Grrrr.)
goto :EOF
... is perfectly valid.

Related

batch if variable is less than variable doesn't work

Have I done something wrong or why this isn't working? I am quite new with batch. It says "The syntax of the command is incorrect."
if %nm1% lss %nm2% (
echo voitit:%voitat%
set /p "tupla=Voitonmaksu.1 tuplaus.2 (1/2)."
)
if %nm1%==%nm2% (
set /a voitat=%voitat% / 2
echo voitit:%voitat%
set /a voitot=%voitot% + %voitat%
pause
goto peli
)
if %nm2% lss %nm1%(
echo voitit:0
pause
goto peli
)
if %tupla%==1 (
set /a voitot=%voitot% + %voitat%
pause
goto peli
)
if %tupla%==2 goto tuplaus
set /a voitat=%voitat% / 2
set /a voitot=%voitot% + %voitat%
These commands won't work as expected because of delayedexpansion (many many SO articles on this - use the search facility in the top bar)
BUT since you are using set/a - the syntax allows the variables to be expressed "nude" - without the % delimiters, when the delayedexpansion quirk becomes irrelevant (but you should read up on it anyway - to obviate the inevitable follow-up question.)
if %nm2% lss %nm1%(
There must be a space between %nm1% and (
If either argument is non-numeric (probably not, given their names) then the arguments must be "quoted" (applies to any if where the arguments may contain spaces)

Batch - Set /a "Missing Operator"

How come when I do this in my game it works
set /a Monster=%random% * 2 / 32768 + 1
But this one doesn't
(Note: MHP = 10 and DamageDealt = 5)
set /a MHP=%MHP% - %DamageDealt%
And when I run the second one it says "Missing Operator".
But it only says it once if I run the thing twice...
Here's a bigger snippit:
:FightExplora
if %HP%=<0 goto GAMEOVERExplora
if %MHP%=<0 goto FightEndExplora
cls
echo HP: %HP%/%MaxHP% Str: %Strength% XP:%XP%/%LVUP% LV: %LV%
$%Money%
echo.
echo You encountered a %Monster%!
echo Monster -- HP: %MHP%/%MaxMHP% Str: %MonsterSTR%
echo.
echo [1-Attack] [2-Heal]
set /p Action="What will you do? > "
echo.
if %Action%==1 (
set /a DamageDealt=%random% * %Strength% / 32768 + 1
set /a MHP=%MHP% - %DamageDealt%
echo You did %DamageDealt% to the %Monster%
goto EnemyTurnExplora
)
if %Action%==2 (
set /a HealAMT=%random% * %MaxHP% / 32768 + (%MaxHP% / %Strength%)
set HP=%HealAMT%
if %HP% => %MaxHP% set %HP%=%MaxHP%
echo You healed %HealAMT% HP
goto EnemyTurnExplora
)
:EnemyTurnExplora
echo.
pause >nul
::Enemy Damage
echo.
set /a DamageTaken=%random% * %MonsterSTR% / 32768 + 1
set /a HP=%HP% - %DamageTaken%
echo The %Monster% dealt %DamageTaken% to you.
echo.
pause >nul
goto FightExplora
Also, when you say to heal, then the command window closes and I don't know why...
Do not expand environment variables within an arithmetic expression using %Variable% syntax as this does not work within command blocks when the referenced environment variable is defined or modified within same command block. Also delayed expansion with reference syntax !Variable! is not needed within an arithmetic expression.
Run in a command prompt window set /? and read carefully the output help explaining arithmetic expressions as well as delayed expansion. As you can read on studying the help you can simply use:
set /A MHP-=DamageDealt
Any non-numeric strings in the expression are treated as environment variable names whose values are converted to numbers before using them. If an environment variable name is specified but is not defined in the current environment, then a value of zero is used. This allows you to do arithmetic with environment variable values without having to type all those % signs to get their values.
The reason for the error on using:
set /a MHP=%MHP% - %DamageDealt%
Either environment variable MHP or DamageDealt or both were not defined on expanding the environment variables and the result was the execution of one of those 3 command lines:
set /a MHP= - 50
set /a MHP= 200 -
set /a MHP= -
This can't happen with using:
set /A MHP=MHP - DamageDealt
set /A MHP-=DamageDealt
Each environment variable name on right side of the equal sign is replaced with 0 if the referenced environment variable does not exist at all on evaluation of the expression.

Batch '+ unexpected' error

I'm trying to code a collatz conjecture tester in batch (it's math stuff). The point of the file is to test whether a number is even, and if it is divide by two. If the number is odd, it's supposed to multiply by three and add one. This should loop over and over. Every time I try and run this file, it allows me to input the number, then it says '+ was unexpected at this time.' What is my error here?
#echo off
color f0
title Collatz Conjecture Tester
echo/
echo Enter the number you want to test.
echo/
echo/
set /p number=
:start
set /a test=%number% %% 2
if %test% EQU 0 (
set /a number=%number% * 1/2
) else (
set /a number=(%number% * 3) + 1
)
echo/
echo Result: %number%
timeout /t 1 >nul
goto start
When you have parentheses inside of if statements, for loops, or other code blocks, it's important that you escape any other inner closing parentheses so that the batch interpreter knows you aren't done yet.
Right now, batch is reading your if statement like this:
else (
set /a number=(%number% * 3
)
+ 1
And so it thinks you're terminating the else early and throwing a + 1 in there for some reason. To get around this, you can escape the inner close parenthesis with a ^.
if %test% EQU 0 (
set /a number=%number% * 1/2
) else (
set /a number=(%number% * 3^) + 1
)
SomethingDark already found the root cause of the problem and showed a proper solution in their answer.
An alternative way to avoid trouble with parentheses and also some operators like &, |, ^, <<, >>, etc. is to enclose the entire expression of set /A within a pair of quotation marks:
if %test% EQU 0 (
set /A "number=%number% * 1/2"
) else (
set /A "number=(%number% * 3) + 1"
)
If you do that consequently, you do not have to think of proper escaping any more.
Note that the % operator always needs to be escaped like %% in a batch file.
In case delayed expansion is enabled, the ! operator needs to be escaped like ^! in case the expression is placed within "", and by ^^! otherwise.

I'm not able to create 10 files with following batch code

Following is the code in which I want to create 10 files if the counter reach 10 but the comparison is not working am I missing something or am I doing something wrong? It creates only one file and prints as following in that one file
10 == 0 set
#echo off
set limit=10
set count=0
:start
set count = %count% + 1
echo %limit% == %count% set > YouAreAnIdiot%random%.txt
if %count%==%limit%
exit 0
else
goto start
two errors in one line: set count = %count% + 1:
a) the space between count and = is part of your variable name. (It would be %count %)
b) to calculate with set, you need the /a parameter:
set /a count=%count% + 1
Surprisingly, set /a doesn't care for the additional space, but get used to the syntax without spaces around the = - this keeps life simple.
set /a doesn't need the percent signs with variables, so set /a count=count+1 also works.
There is a short form to do that:
set /a count+=1
Also your if statement will not work. The complete construct has to be on one (logical) line:
if %count%==%limit% (
exit 0
) else (
goto start
)
(note the spaces around the parantheses - they are critical)

Rpg batch level system error?

So i seem to find it difficult to put an 'if' statement inside another 'if' statement. I have the labels for gotos set up correctly the error occurs when the code goes to the levelstats
The code is meant, once the player has met the max exp, to go to the next level. The lvlguage checks to see if the exp requirements are met. That works fine. It goes to levelstats and then the prompt closes.
:LvlGuage
If %CharExp% GEQ %CharMaxExp% (
Goto LevelStats
)
Goto MENU
:LevelStats
::the error starts here
If %CharLevel%==1 (
Goto Level2
)
Goto MENU
If %CharLevel%==2 (
Goto Level3
)
Goto MENU
:: This goes on till level 10
:Level2
If %CharExp% GEQ 100 (
Set /a CharExp=%CharExp% -100
Set CharMaxExp=280
Set CharLevel=2
Set /a CharAttack=(%CharAttack% * 1.5) + 1
Goto LEVELUP
)
Goto MENU
:Level3
If %CharExp% GEQ 280 (
Set /a CharExp=%CharExp% -280
Set CharMaxExp=784
Set CharLevel=3
Set /a CharAttack=(%CharAttack% * 1.5) + 1
Goto LEVELUP
)
Goto MENU
:LEVELUP
Cls
Echo You Have Leveled Up.
Timeout 2 >nul
Goto MENU
Your variables are calculated once just when your script starts. Take a look ath this: http://www.ss64.com/nt/delayedexpansion.html
You need to add Setlocal EnableDelayedExpansion at the beginning at your script and adress to your vars with !varname! instead of %varname% when you want to get the changed values. This will always give you the last set value of the variable instead of the first assigned value.

Resources