- 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:
pbGet(x) >= 3
Ruby:
pbGet(x).shiny?
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:
if condition
#run if true
end
Just like branches in an event, you can add an
else
branch for if the condition is false.
Ruby:
if condition
#run if true
else
#run if false
end
Scripting in Ruby also lets you use
elsif
branches, for when your initial if
is false but another condition is true.
Ruby:
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:
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:
code if condition
Ruby:
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:
Battle::PokeBallEffects::IsUnconditional.add(:MASTERBALL, proc { |ball, battle, battler|
next true
})
next true
if the switch was on, and next false
if it was off.)
Ruby:
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:
when [5, 5, 5], [6, 6, 6] # Red 777, blue 777
payout += 300
bonus = 2 if bonus < 2
Ruby:
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:
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
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:
@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:
# 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:
@pic.name = "Graphics/Titles/" + TITLE_BG_IMAGE
Ruby:
@pic.name = "Graphics/Titles/" + TITLE_BG_IMAGE + $game_variables[69]
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:
save_data = SaveData.get_data_from_file(SaveData::FILE_PATH)
Ruby:
save_data[:variables][69]
Ruby:
save_data = SaveData.get_data_from_file(SaveData::FILE_PATH)
@pic.name = "Graphics/Titles/" + TITLE_BG_IMAGE + save_data[:variables][69]
.to_s
at the end.
Ruby:
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:
Battle::PokeBallEffects::IsUnconditional.add(:POKEBALL, proc { |ball, battle, battler|
next !$bag.has?(:POKEBALL)
})
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
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)