- Pokémon Essentials Version
- v20.1 ➖
Script to let players earn badges in any order they like. Badges will be displayed in the order received.
This is currently only written for default Essentials UI. It's totally possible to adapt it for another layout, you'll just need to work to integrate it into the other script.
Code
If you prefer plug-and-play scripts, you can paste this in a new script section above Main.
Ruby:
class GameStats
alias oldinitialize initialize
def initialize
oldinitialize
@times_to_get_badges = {} # Set with set_time_to_badge(number) in Gym Leader events
end
end
class Player < Trainer
alias oldinitialize initialize
def initialize(name, trainer_type)
oldinitialize(name, trainer_type)
@badges = []
end
# @return [Integer] the number of Gym Badges owned by the player
def badge_count
return @badges.length
end
end
def pbGiveBadge(badge)
raise "#{badge.to_s.capitalize} Badge has no graphic" if !pbResolveBitmap("Graphics/Pictures/Trainer Card/#{badge.to_s}")
$player.badges.push(badge)
end
def pbHasBadge?(badge)
return $player.badges.include?(badge)
end
def pbCheckHiddenMoveBadge(badge = -1, showmsg = true)
if (badge.is_a?(Integer))
return true if badge < 0 # No badge requirement
end
return true if $DEBUG
if (badge.is_a?(Symbol)) ? $player.badges.include?(badge) : $player.badge_count >= badge
return true
end
msg = (badge.is_a?(Symbol)) ? _INTL("Sorry, a new Badge is required.") : _INTL("Sorry, more Badges are required.")
pbMessage(msg) if showmsg
return false
end
class PokemonTrainerCard_Scene
def pbDrawTrainerCardFront
overlay = @sprites["overlay"].bitmap
overlay.clear
baseColor = Color.new(72, 72, 72)
shadowColor = Color.new(160, 160, 160)
totalsec = $stats.play_time.to_i
hour = totalsec / 60 / 60
min = totalsec / 60 % 60
time = (hour > 0) ? _INTL("{1}h {2}m", hour, min) : _INTL("{1}m", min)
$PokemonGlobal.startTime = pbGetTimeNow if !$PokemonGlobal.startTime
starttime = _INTL("{1} {2}, {3}",
pbGetAbbrevMonthName($PokemonGlobal.startTime.mon),
$PokemonGlobal.startTime.day,
$PokemonGlobal.startTime.year)
textPositions = [
[_INTL("Name"), 34, 70, 0, baseColor, shadowColor],
[$player.name, 302, 70, 1, baseColor, shadowColor],
[_INTL("ID No."), 332, 70, 0, baseColor, shadowColor],
[sprintf("%05d", $player.public_ID), 468, 70, 1, baseColor, shadowColor],
[_INTL("Money"), 34, 118, 0, baseColor, shadowColor],
[_INTL("${1}", $player.money.to_s_formatted), 302, 118, 1, baseColor, shadowColor],
[_INTL("Pokédex"), 34, 166, 0, baseColor, shadowColor],
[sprintf("%d/%d", $player.pokedex.owned_count, $player.pokedex.seen_count), 302, 166, 1, baseColor, shadowColor],
[_INTL("Time"), 34, 214, 0, baseColor, shadowColor],
[time, 302, 214, 1, baseColor, shadowColor],
[_INTL("Started"), 34, 262, 0, baseColor, shadowColor],
[starttime, 302, 262, 1, baseColor, shadowColor]
]
pbDrawTextPositions(overlay, textPositions)
x = 72
for i in 0...$player.badges.length
badge = $player.badges[i].to_s
@sprites["badge#{i}"] = IconSprite.new(x, 310, @viewport)
@sprites["badge#{i}"].setBitmap("Graphics/Pictures/Trainer Card/#{badge}")
x += 48
end
end
end
MenuHandlers.add(:debug_menu, :set_badges, {
"name" => _INTL("Set Badges"),
"parent" => :player_menu,
"description" => _INTL("Toggle possession of Gym Badges."),
"effect" => proc {
badgecmd = 0
loop do
badgecmds = []
badgecmds.push(_INTL("Give individual Badge"))
badgecmds.push(_INTL("Remove all"))
badgecmd = pbShowCommands(nil, badgecmds, -1, badgecmd)
break if badgecmd < 0
case badgecmd
when 0 # Give specific badge
badge = pbMessageFreeText("Give which Badge?",_INTL(""),false,20)
badge = badge.upcase
if pbResolveBitmap("Graphics/Pictures/Trainer Card/#{badge}")
pbGiveBadge(badge.to_sym)
pbMessage(_INTL("Gave the {1} Badge.", badge.capitalize))
else
pbMessage(_INTL("{1} Badge does not exist.", badge.capitalize))
end
when 1 # Remove all
$player.badges = []
pbMessage(_INTL("Cleared all Badges."))
end
end
}
})
Instructions
If you'd prefer to add this by editing the scripts yourself. (Useful if you're worried about conflicting plugins/external scripts)These instructions will be broken into four parts -
In Game_Stats, change line 134 -
to
In Player, change lines 84-86
to
And change line 108 -
to
In Overworld_FieldMoves, find lines 55-63.
Change them to
Finally, paste these utilities anywhere. (Simplest thing would be in their own script section)
Ruby:
@times_to_get_badges = []
Ruby:
@times_to_get_badges = {}
Ruby:
def badge_count
return @badges.count { |badge| badge == true }
end
Ruby:
def badge_count
return @badges.length
end
Ruby:
@badges = [false] * 8
Ruby:
@badges = []
In Overworld_FieldMoves, find lines 55-63.
Ruby:
def pbCheckHiddenMoveBadge(badge = -1, showmsg = true)
return true if badge < 0 # No badge requirement
return true if $DEBUG
if (Settings::FIELD_MOVES_COUNT_BADGES) ? $player.badge_count >= badge : $player.badges[badge]
return true
end
pbMessage(_INTL("Sorry, a new Badge is required.")) if showmsg
return false
end
Ruby:
def pbCheckHiddenMoveBadge(badge = -1, showmsg = true)
if (badge.is_a?(Integer))
return true if badge < 0 # No badge requirement
end
return true if $DEBUG
if (badge.is_a?(Symbol)) ? $player.badges.include?(badge) : $player.badge_count >= badge
return true
end
msg = (badge.is_a?(Symbol)) ? _INTL("Sorry, a new Badge is required.") : _INTL("Sorry, more Badges are required.")
pbMessage(msg) if showmsg
return false
end
Finally, paste these utilities anywhere. (Simplest thing would be in their own script section)
Ruby:
def pbGiveBadge(badge)
raise "#{badge.to_s.capitalize} Badge has no graphic" if !pbResolveBitmap("Graphics/Pictures/Trainer Card/#{badge.to_s}")
$player.badges.push(badge)
end
def pbHasBadge?(badge)
return $player.badges.include?(badge)
end
In UI_TrainerCard, find this section -
Replace it with this -
Ruby:
x = 72
region = pbGetCurrentRegion(0) # Get the current region
imagePositions = []
8.times do |i|
if $player.badges[i + (region * 8)]
imagePositions.push(["Graphics/Pictures/Trainer Card/icon_badges", x, 310, i * 32, region * 32, 32, 32])
end
x += 48
end
pbDrawImagePositions(overlay, imagePositions)
Ruby:
x = 72
for i in 0...$player.badges.length
badge = $player.badges[i].to_s
@sprites["badge#{i}"] = IconSprite.new(x, 310, @viewport)
@sprites["badge#{i}"].setBitmap("Graphics/Pictures/Trainer Card/#{badge}")
x += 48
end
In Debug_MenuCommands, find this section -
Replace it with -
Ruby:
MenuHandlers.add(:debug_menu, :set_badges, {
"name" => _INTL("Set Badges"),
"parent" => :player_menu,
"description" => _INTL("Toggle possession of each Gym Badge."),
"effect" => proc {
badgecmd = 0
loop do
badgecmds = []
badgecmds.push(_INTL("Give all"))
badgecmds.push(_INTL("Remove all"))
24.times do |i|
badgecmds.push(_INTL("{1} Badge {2}", $player.badges[i] ? "[Y]" : "[ ]", i + 1))
end
badgecmd = pbShowCommands(nil, badgecmds, -1, badgecmd)
break if badgecmd < 0
case badgecmd
when 0 # Give all
24.times { |i| $player.badges[i] = true }
when 1 # Remove all
24.times { |i| $player.badges[i] = false }
else
$player.badges[badgecmd - 2] = !$player.badges[badgecmd - 2]
end
end
}
})
Ruby:
MenuHandlers.add(:debug_menu, :set_badges, {
"name" => _INTL("Set Badges"),
"parent" => :player_menu,
"description" => _INTL("Toggle possession of Gym Badges."),
"effect" => proc {
badgecmd = 0
loop do
badgecmds = []
badgecmds.push(_INTL("Give individual Badge"))
badgecmds.push(_INTL("Remove all"))
badgecmd = pbShowCommands(nil, badgecmds, -1, badgecmd)
break if badgecmd < 0
case badgecmd
when 0 # Give specific badge
badge = pbMessageFreeText("Give which Badge?",_INTL(""),false,20)
badge = badge.upcase
if pbResolveBitmap("Graphics/Pictures/Trainer Card/#{badge}")
pbGiveBadge(badge.to_sym)
pbMessage(_INTL("Gave the {1} Badge.", badge.capitalize))
else
pbMessage(_INTL("{1} Badge does not exist.", badge.capitalize))
end
when 1 # Remove all
$player.badges = []
pbMessage(_INTL("Cleared all Badges."))
end
end
}
})
In Move_UsageCalculations, find this section -
At each point where it checks
In the script section AI_Move_Utilities, you'll do the same thing with this section here:
It should look like this:
And in the script section Battle_Battler, you'll do the same with this line -
It should now look like this -
Ruby:
if @battle.internalBattle
if user.pbOwnedByPlayer?
if physicalMove? && @battle.pbPlayer.badge_count >= Settings::NUM_BADGES_BOOST_ATTACK
multipliers[:attack_multiplier] *= 1.1
elsif specialMove? && @battle.pbPlayer.badge_count >= Settings::NUM_BADGES_BOOST_SPATK
multipliers[:attack_multiplier] *= 1.1
end
end
if target.pbOwnedByPlayer?
if physicalMove? && @battle.pbPlayer.badge_count >= Settings::NUM_BADGES_BOOST_DEFENSE
multipliers[:defense_multiplier] *= 1.1
elsif specialMove? && @battle.pbPlayer.badge_count >= Settings::NUM_BADGES_BOOST_SPDEF
multipliers[:defense_multiplier] *= 1.1
end
end
end
@battle.pbPlayer.badge_count >= Settings::NUM_BADGES_BOOST_(STAT)
, you're going to change it so that it instead checks @battle.pbPlayer.badges.include?(Settings::NUM_BADGES_BOOST_(STAT))
, like so -
Ruby:
if @battle.internalBattle
if user.pbOwnedByPlayer?
if physicalMove? && @battle.pbPlayer.badges.include?(Settings::NUM_BADGES_BOOST_ATTACK)
multipliers[:attack_multiplier] *= 1.1
elsif specialMove? && @battle.pbPlayer.badges.include?(Settings::NUM_BADGES_BOOST_SPATK)
multipliers[:attack_multiplier] *= 1.1
end
end
if target.pbOwnedByPlayer?
if physicalMove? && @battle.pbPlayer.badges.include?(Settings::NUM_BADGES_BOOST_DEFENSE)
multipliers[:defense_multiplier] *= 1.1
elsif specialMove? && @battle.pbPlayer.badges.include?(Settings::NUM_BADGES_BOOST_SPDEF)
multipliers[:defense_multiplier] *= 1.1
end
end
end
Ruby:
# Badge multipliers
if skill >= PBTrainerAI.highSkill && @battle.internalBattle && target.pbOwnedByPlayer?
if move.physicalMove?(type) && @battle.pbPlayer.badge_count >= Settings::NUM_BADGES_BOOST_DEFENSE
multipliers[:defense_multiplier] *= 1.1
elsif move.specialMove?(type) && @battle.pbPlayer.badge_count >= Settings::NUM_BADGES_BOOST_SPDEF
multipliers[:defense_multiplier] *= 1.1
end
end
Ruby:
# Badge multipliers
if skill >= PBTrainerAI.highSkill && @battle.internalBattle && target.pbOwnedByPlayer?
if move.physicalMove?(type) && @battle.pbPlayer.badges.include?(Settings::NUM_BADGES_BOOST_DEFENSE)
multipliers[:defense_multiplier] *= 1.1
elsif move.specialMove?(type) && @battle.pbPlayer.badges.include?(Settings::NUM_BADGES_BOOST_SPDEF)
multipliers[:defense_multiplier] *= 1.1
end
end
Ruby:
# Badge multiplier
if @battle.internalBattle && pbOwnedByPlayer? &&
@battle.pbPlayer.badge_count >= Settings::NUM_BADGES_BOOST_SPEED
speedMult *= 1.1
end
Ruby:
# Badge multiplier
if @battle.internalBattle && pbOwnedByPlayer? &&
@battle.pbPlayer.badges.include?(Settings::NUM_BADGES_BOOST_SPEED)
speedMult *= 1.1
end
Using this Script
Badges are no longer on one spritesheet all together. Instead, they're going to be their own individual sprites, with their name in all caps, just like how items and Pokémon are named now. (Just the badge name, not the word "Badge") For example, the Boulder Badge would be a file named "BOULDER.png". They'll still be placed in Graphics/Pictures/Trainer Card.
The script checks to see that the graphic exists when giving the player a badge - if it doesn't, it'll give an error saying "(Name) Badge has no graphic".
Instead of
$player.badges[0] = true
, you'll do pbGiveBadge(:BADGE)
. Wherever you refer to a badge, you'll do so with a symbol (all caps, : in front) rather than a number.For example, in the default maps' Brock event, instead of doing this -
Ruby:
$stats.set_time_to_badge(0)
$player.badges[0] = true
Ruby:
$stats.set_time_to_badge(:BOULDER)
pbGiveBadge(:BOULDER)
FIELD_MOVES_COUNT_BADGES is no longer used. Your settings for HM use/stat boost can depend on the player's total number of badges or whether they have a specific badge - a number requires a total of badges, a symbol requires a specific badge.
For example, this is how the settings are in default Essentials -
Ruby:
BADGE_FOR_CUT = 1
BADGE_FOR_FLASH = 2
BADGE_FOR_ROCKSMASH = 3
BADGE_FOR_SURF = 4
BADGE_FOR_FLY = 5
BADGE_FOR_STRENGTH = 6
BADGE_FOR_DIVE = 7
BADGE_FOR_WATERFALL = 8
Ruby:
BADGE_FOR_CUT = 1
BADGE_FOR_FLASH = :THUNDER
BADGE_FOR_ROCKSMASH = :BOULDER
BADGE_FOR_SURF = :CASCADE
BADGE_FOR_FLY = 2
BADGE_FOR_STRENGTH = :EARTH
BADGE_FOR_DIVE = 5
BADGE_FOR_WATERFALL = :VOLCANO
You can check
$player.badge_count >= badge
to see if the player has a total number of badges, and you can check pbHasBadge?(:badge)
to see if the player has a specific badge.Badge mechanics for obedience and losing money have not changed, they're still just the total number of badges.
You can actually earn duplicate badges with this script, since they're no longer true/false.
You can have more than 8 badges, but you'll need to tweak the trainer card display to get them to appear properly.
Graphics
Since badges aren't all on a spritesheet together, you don't need to worry about having a specific badge size anymore! The game will just display the image for the badge at the given coordinates. Currently, that's at (x,310), where x is 72+(48*(Badge number - 1)). Don't let that formula scare you - all that means is that the first badge is at (72,310), the second is at (120,310), the third at (168,310), and so on.If you want to adjust this, you're going to be looking at this section of code:
Ruby:
x = 72
for i in 0...$player.badges.length
badge = $player.badges[i].to_s
@sprites["badge#{i}"] = IconSprite.new(x, 310, @viewport)
@sprites["badge#{i}"].setBitmap("Graphics/Pictures/Trainer Card/#{badge}")
x += 48
end
I tried to break the code up here a bit to make it easier to adjust values - x = 72 is where the first badge is displayed, and x +=48 is the space between badges. If you'd like to have multiple rows of badges, you'll just have to add something similar for the Y value - but you'll need to do a bit more math to set the coordinates right.
For example, say I want to just add an extra row of badges 48 pixels below the first one. I'm going to start by making Y a value set before the badges are drawn, just like X.
Ruby:
x = 72
y = 310
for i in 0...$player.badges.length
badge = $player.badges[i].to_s
@sprites["badge#{i}"] = IconSprite.new(x, y, @viewport)
@sprites["badge#{i}"].setBitmap("Graphics/Pictures/Trainer Card/#{badge}")
x += 48
end
Ruby:
x = 72
y = 310
for i in 0...$player.badges.length
badge = $player.badges[i].to_s
@sprites["badge#{i}"] = IconSprite.new(x, y, @viewport)
@sprites["badge#{i}"].setBitmap("Graphics/Pictures/Trainer Card/#{badge}")
x += 48
y += 48 if i == 8
end
i%8 == 0
- that would check if i could be divided by 8 with no remainder. )But wait, there's one more step! X is increasing with each badge, so I need to move X back to the beginning if I'm starting a new row!
Ruby:
x = 72
y = 310
for i in 0...$player.badges.length
badge = $player.badges[i].to_s
@sprites["badge#{i}"] = IconSprite.new(x, y, @viewport)
@sprites["badge#{i}"].setBitmap("Graphics/Pictures/Trainer Card/#{badge}")
x += 48
y += 48 if i == 8
x = 72 if i == 8
end
Debug Menu
Right now, there's no option to give the player all badges at once. I could, hypothetically, change things up so that the badges are in a subfolder, and then the game goes through each file in the subfolder. I'm not going to bother with that now, because you can only do this in Debug, and Debug is going to override all badge requirements anyways, but if someone's interested in the idea, I might try to do it.
Adding to a Released Game
I really recommend you do this at the start of development - adding this partway through is going to shake up a lot of gameplay and story. But if you really want to introduce it midway, you can take an extra step to let past saves remain compatible.The way Essentials is currently set up, player badges are stored as an array of true/false Booleans. You're going to take that and create an array of symbols based on the order the badges would normally be obtained in. That sounds complicated, but all that means is that you're going to go through the current array, check if each entry is true, and add the badge to a new array if it is, like this -
Ruby:
newbadges = []
newbadges.push(:BOULDER) if $player.badges[0] == true
newbadges.push(:CASCADE) if $player.badges[1] == true
Ruby:
$player.badges = newbadges
Ruby:
newtimes = {}
newtimes[:BOULDER] = $stats.times_to_get_badges[0]
newtimes[:CASCADE] = $stats.times_to_get_badges[1]
Ruby:
$stats.times_to_get_badges = newtimes
Related Resources
Prodigy3332 has a pack of badges in the Gen 3 style here!- Credits
- TechSkylander1518
Smithereens - Bug fixes