- 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
endFinally, 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)
endIn 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
    endIn 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
    endUsing 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 = :VOLCANOYou 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
    endI 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
    endi%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
    endDebug 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 = newtimesRelated Resources
Prodigy3332 has a pack of badges in the Gen 3 style here!- Credits
- TechSkylander1518
 Smithereens - Bug fixes
 
	







