Moonicorn
Moonicorn

Reputation: 91

Calling an IF statement | Batch

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?

Upvotes: 1

Views: 375

Answers (1)

rojo
rojo

Reputation: 24466

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.

Upvotes: 3

Related Questions