• Do not use Discord to host any images you post, these links expire quickly! You can learn how to add images to your posts here.
Using Game Switches/Variables in Scripts

any version Using Game Switches/Variables in Scripts 2023-03-16

This resource does not pertain to any specific version of Pokémon Essentials.
Pokémon Essentials Version
Non-applicable


Just a quick tutorial to explain how to use Game Switches/Variables in the game's scripts. It's a simple trick to pick up that offers a lot of possibilities.

Switches and Variables​

First, a note about terms. You may sometimes see Game Switches/Variables referred to as Global Switches/Variables. I get the reasoning behind this, but there's a problem - a global variable in Ruby is its own separate thing. So to keep things clear, I'm only going to refer to these as Game Switches/Variables. (hopefully the capitalization helps it make more sense)

In scripts, Game Switches are referred to as [imath]game_switches[x], Variables as [/imath]game_variables[x], where X is the ID number. Do NOT put any 0s at the start of the number - that will cause the game to read it as an octal number instead of a decimal number.

Game Switches can only be true or false, and default to false if they haven’t been set already. You can only set them to true/false, or check if they’re true/false. (Technically, you could use script commands to set them to be some other object, but there’s no reason to do that when you can just as easily store objects in variables)

Remember - it’s one = to set, two to check.

$game_switches[1] = true sets Game Switch 1 to On.

$game_switches[1] == true checks if Game Switch 1 is On. (It’s usually used as part of a conditional branch)

But since switches are always either on or off, you can condense these commands a bit. Instead of checking if [imath]game_switches[1] == true, you can just check if[/imath]game_switches[1]. Putting a ! in front of a condition checks if it's false, so if you wanted to check if a switch was off, you could put if !$game_switches[1].

Game Variables are usually numbers when set via event commands, but they can actually store any object in them through a script command. They default to 0 if they haven’t been set already.

Because they can be so many things, Essentials comes with a couple utilities for variables. pbSet(x,y) is a shorthand version of $game_variables[x] = y.
pbGet(x) returns what’s stored in Game Variable X. It can be used as part of a check, or to store it in a local variable. (x = pbGet(y))

Since variables can be anything, you can use any method associated with the object class. For example, if an integer was stored in the variable, you could use it in inequalities…
Ruby:
Expand Collapse Copy
pbGet(x) >= 3
But if a Pokémon was stored in the variable, you could use it to check for properties like shininess.
Ruby:
Expand Collapse Copy
pbGet(x).shiny?
(For an example of this, see Shiny Starter Preview)

Conditional Branches​

If you’re familiar with conditional branches in events, you’ll pick up on conditional branches in scripts pretty quickly. The logic is largely the same, it's just how you create it that's different.

Conditional branches in a script are usually laid out like this:
Ruby:
Expand Collapse Copy
if condition
  #run if true
end
1678821787912.png
1678821777077.png

Just like branches in an event, you can add an else branch for if the condition is false.
Ruby:
Expand Collapse Copy
if condition
  #run if true
else
  #run if false
end
1678822234632.png
1678822218459.png


Scripting in Ruby also lets you use elsif branches, for when your initial if is false but another condition is true.
Ruby:
Expand Collapse Copy
if startchoice == :BULBASAUR
  #code for Bulbasaur
elsif startchoice == :CHARMANDER
  #code for Charmander
else
  #code for Squirtle
end

You can also do unless statements, which are basically inverted if branches. (The code runs if the condition is false)
Ruby:
Expand Collapse Copy
unless condition
  #code if false
end

If the code you want to run is only one line, you can also write these as in-line checks, like so:
Ruby:
Expand Collapse Copy
code if condition
Ruby:
Expand Collapse Copy
code unless condition

Examples​

Let's give a few simple ideas a whirl!

As I try each one out, I'm going to be following my steps to Thinking through a script, but for the sake of keeping things short, I'll only be writing out the research step here.

Poké Balls in a Pinch​

Maybe there's some case where I want a switch to make Poké Balls to have a 100% catch rate, to make sure the player can catch a Pokémon.

This is how the handler for the Master Ball is set up -
Ruby:
Expand Collapse Copy
Battle::PokeBallEffects::IsUnconditional.add(:MASTERBALL, proc { |ball, battle, battler|
  next true
})
I'll create a handler for the Poké Ball, but instead have it pass the switch. (Since switches are true/false, this would read next true if the switch was on, and next false if it was off.)
Ruby:
Expand Collapse Copy
Battle::PokeBallEffects::IsUnconditional.add(:POKEBALL, proc { |ball, battle, battler|
  next $game_switches[100]
})

Jackpot, and then some​

Let's say I want the player to be able to fight a special trainer in the arcade, but only if they've gotten the jackpot on the slots before.

The section Minigame_SlotMachine looks a little complicated, but thanks to the comments, I can see this section is for if the player lands on three sevens of matching colors.
Ruby:
Expand Collapse Copy
      when [5, 5, 5], [6, 6, 6]   # Red 777, blue 777
        payout += 300
        bonus = 2 if bonus < 2
I'll just add a line to turn the switch on.
Ruby:
Expand Collapse Copy
      when [5, 5, 5], [6, 6, 6]   # Red 777, blue 777
        payout += 300
        bonus = 2 if bonus < 2
        $game_switches[100] = true

Upgrading Trainer Card​

This is the idea I used in the video demo, based on how the trainer card changed in B2W2. After completing a major achievement (completing the dex, beating the Elite 4, winning the PWT, etc.), the trainer card would change its background. (One achievement meant a purple card, two an orange, etc.)

Since I want players to be able to do this in any order, I'm going to make it based on a variable rather than a switch.

In UI_TrainerCard, the code for setting up the card graphic is this:
Ruby:
Expand Collapse Copy
    cardexists = pbResolveBitmap(sprintf("Graphics/Pictures/Trainer Card/card_f"))
    @sprites["card"] = IconSprite.new(0, 0, @viewport)
    if $player.female? && cardexists
      @sprites["card"].setBitmap("Graphics/Pictures/Trainer Card/card_f")
    else
      @sprites["card"].setBitmap("Graphics/Pictures/Trainer Card/card")
    end
You can see that it's checking if the player is female and a file named "card_f" is in the Trainer Card folder. If both of these are true, it uses card_f as the graphic, otherwise, it uses card.

We're getting into some pretty open-ended territory here. Since I'm changing what graphics are used, I can decide to name them whatever I'd like. I could name them by color and make a bunch of case statements, telling the game to use "card_orange", "card_purple", etc. But that's not going to be very efficient - I'll have to write a new conditional branch for each color. Instead, what I'm going to do is name the files based on the value of the variable - card0 at the start of the game, card1 for the first achievement, and so on.

In Ruby, you can insert a variable into a string by writing #{value}. For the video above, I wrote the code as this:
Ruby:
Expand Collapse Copy
@sprites["card"].setBitmap("Graphics/Pictures/Trainer Card/card#{pbGet(69)}")

Updating Title Screen​

This is a feature you can see on some games like Rejuvenation or Infinity - when the player reaches some landmark in the game, graphics on the title or load screen change.

UI_SplashesAndTitleScreen has this section at the top -
Ruby:
Expand Collapse Copy
  # Splash screen images that appear for a few seconds and then disappear.
  SPLASH_IMAGES         = ["splash1", "splash2"]
  # The main title screen background image.
  TITLE_BG_IMAGE        = "title"
  TITLE_START_IMAGE     = "start"
  TITLE_START_IMAGE_X   = 0
  TITLE_START_IMAGE_Y   = 322
  SECONDS_PER_SPLASH    = 2
  TICKS_PER_ENTER_FLASH = 40   # 20 ticks per second
  FADE_TICKS            = 8    # 20 ticks per second

However, we actually will NOT be making any changes here. Variables in all caps like these are constants, and don't change while the game is running.

So, okay, let's look at where they're being used and see if we can make changes there.

I Ctrl+F for TITLE_BG_IMAGE and find this line -
Ruby:
Expand Collapse Copy
    @pic.name = "Graphics/Titles/" + TITLE_BG_IMAGE
I can see here that I can add to a string, so I'll just do like I did with the trainer card, and add the variable to the end of the name.
Ruby:
Expand Collapse Copy
    @pic.name = "Graphics/Titles/" + TITLE_BG_IMAGE + $game_variables[69]
But when I run my game...

1678829197184.png

What gives?

Well, game switches and variables aren't read until the game loads them from the save file - which means that we can't refer to them in our usual ways.

We're not totally out of luck, though! This just means that we have to look at how the game reads a save file so we can figure out how to read it. (And lucky for me, I'm already familiar with this because I've done it for another script)

This will store the save data in a hash named save_data...
Ruby:
Expand Collapse Copy
save_data = SaveData.get_data_from_file(SaveData::FILE_PATH)
So now I can get variable 69 from it like this:
Ruby:
Expand Collapse Copy
save_data[:variables][69]
So my code will look like this!
Ruby:
Expand Collapse Copy
    save_data = SaveData.get_data_from_file(SaveData::FILE_PATH)
    @pic.name = "Graphics/Titles/" + TITLE_BG_IMAGE + save_data[:variables][69]
...or, I thought it would, but I got an error about converting to a string, so I have to tack on a quick .to_s at the end.

Ruby:
Expand Collapse Copy
    save_data = SaveData.get_data_from_file(SaveData::FILE_PATH)
    @pic.name = "Graphics/Titles/" + TITLE_BG_IMAGE + save_data[:variables][69].to_s

Of course, this is just one approach to this issue - you might also be interested in wrigty12's Persistent Switches and Variables!

Alternatives​

If you're looking at this and wondering "Wait, aren't there other conditions I could be checking?" - you're absolutely right! I've tricked you into becoming more of a scripter than you intended! All you're doing here is running a check to see if it's true or false, or reading a variable, and you can do that in lots of different ways!

For example, let's look at that Poké Ball scenario again. Sometimes, games do a little behind-the-scenes trickery to make tense moments favor the player. (outsidxtra has some fun videos on the topic) So what if I wanted to make it so that the player's last Poké Ball always works?

The wiki article for Manipulating items says that I can check if the bag has an item with $bag.has?(:ITEM).
Ruby:
Expand Collapse Copy
Battle::PokeBallEffects::IsUnconditional.add(:POKEBALL, proc { |ball, battle, battler|
  next !$bag.has?(:POKEBALL)
})
And it works! My last Poké Ball never fails!

Or what about keeping track of new statistics, like with upgrading the Trainer Card? Essentials v20 is actually full of great examples - v20 introduced a lot of player-based stats, like how many times you've used repels, how many eggs you've hatched, how many times you've traded, etc. Rather than being stored in a bunch of game variables, they're all stored as attributes of $stats, an object with the GameStats class.

But clearly there's some practical differences between Game Switches/Variables and other methods like a global object, because vanilla Essentials uses both.

These switches all have effects that are only set up in the scripts - they don't affect any events on the maps.
  • 31 - Shiny Wild Pokémon
  • 32 - Fateful Wild Encounters
  • 33 - No money lost in battle
  • 34 - No Mega Evolution
  • 35 - Disable Box Link
  • 51 - Visited Berth Island
  • 52 - Visited Faraday Island
  • 53 - Latias/Latios Roaming
  • 54 - Kyogre Roaming
  • 55 - Entei Roaming
Additionally, the white-out event after losing in battle turns Game Switch 1 - Starting Over on, and Game Variable 7 is used to store the rival's name.

Let's look at some of the differences with using a Game Switch/Variable compared to other methods and see how we might decide which one to use.
  • Ease of Use - The obvious and simplest one. It's easier to click event commands to turn on a switch than it is to have a script command $game_switches[x] = true. If your switch/variable is going to be affected by an event a lot, you'll probably want to just use the commands to do it. (Especially if you're referring to it in messages, like with the rival's name)
    • This can be especially relevant when you're working with other people - if your teammates aren't as familiar with Ruby, using commands is going to be a lot more intuitive for them.
    • It's also easier for playtesting - switches and variables can be changed through the debug menu.
  • Organization - Sometimes the layout in the event editor is just easier! It helps to keep story-based checks in order, keep similar checks together, and make it easier to find the name of something.
    • Of course, both options have their pros and cons - imagine if you had to allocate another 70 Game Variables for all of v20's new stats. Aren't you glad they're stored separately?
  • Event functionality - Only Game Switches and Variables can be used in an event page's conditions. For example, after losing a battle, the player is transferred to a PMC and a scene plays of their Pokémon being healed. This is done by having the event set to autorun, which means it needs its own page with its own conditions, so it makes more sense to make starting over into a Game Switch rather than check it elsewhere.
    • Minor disclaimer - you could, technically, use the event's Self Switches for the page's conditions, which can be set via script. But that'd be a lot of extra work just to avoid using a Game Switch/Variable.
  • Data structure - A very niche issue, but worth mentioning all the same. If you decide to store information somewhere other than a Game Switch/Variable, like a global variable, an attribute of an object, etc., you might have trouble getting that information from another game. (For example, if Game A has an attribute "Trainer Rank" for the trainer class, and Game B doesn't, Game B couldn't get a trainer rank from Game A.) Game Switches/Variables, on the other hand, are read across all versions of Essentials.
Credits
None needed. (That includes the mini-scripts included, they're simple enough that I couldn't really call them unique)
Author
TechSkylander1518
Views
3,456
First release
Last update

Ratings

0.00 star(s) 0 ratings

More resources from TechSkylander1518

Back
Top