The save system in Pokémon Essentials BES handles persisting game state between play sessions. It uses Ruby’s Marshal serialization to save and load complex game objects.
class PokemonGlobal attr_accessor :bridge # Bridge state attr_accessor :bicycle # Has bicycle attr_accessor :surfing # Currently surfing attr_accessor :diving # Currently diving attr_accessor :sliding # Currently sliding on ice attr_accessor :repel # Repel steps remaining attr_accessor :flashUsed # Flash used flag attr_accessor :encounter # Current encounter data attr_accessor :nextBattleBGM # BGM for next battle attr_accessor :nextBattleME # ME for next battle attr_accessor :nextBattleBack # Background for next battle attr_accessor :pokecenterMapId # Last Pokémon Center map attr_accessor :pokecenterX # Last Pokémon Center X attr_accessor :pokecenterY # Last Pokémon Center Y attr_accessor :pokecenterDirection # Facing direction at center attr_accessor :healingSpot # Current healing location attr_accessor :visitedMaps # Maps player has visited attr_accessor :partner # Partner trainer for double battles attr_accessor :challenge # Battle Challenge data attr_accessor :lastbattle # Last battle recording def initialize @repel = 0 @bridge = 0 @bicycle = false @surfing = false @diving = false @visitedMaps = [] endend
class PokemonStorage attr_reader :boxes # Array of PC boxes attr_accessor :currentBox # Currently selected box def initialize(maxBoxes=24, maxPokemon=30) @boxes = [] @maxBoxes = maxBoxes @maxPokemon = maxPokemon for i in 0...maxBoxes @boxes[i] = [] end @currentBox = 0 end def pbStoreCaught(pokemon) # Find box with space for i in 0...@maxBoxes box = (@currentBox + i) % @maxBoxes if @boxes[box].length < @maxPokemon @boxes[box].push(pokemon) return box end end return -1 # No space end def full? for box in @boxes return false if box.length < @maxPokemon end return true endend
Organized battles (Battle Tower, etc.) use special save logic:
class BattleChallengeData def pbStart(t,numRounds) @inProgress=true @resting=false @decision=0 @swaps=t.currentSwaps @wins=t.currentWins @battleNumber=1 @trainers=[] @numRounds=numRounds # Generate trainers btTrainers=pbGetBTTrainers(pbBattleChallenge.currentChallenge) while @trainers.length<@numRounds newtrainer=pbBattleChallengeTrainer(@wins+@trainers.length,btTrainers) @trainers.push(newtrainer) end # Save starting position @start=[$game_map.map_id,$game_player.x,$game_player.y] @oldParty=$Trainer.party $Trainer.party=@party if @party pbSave(true) # Safe save end def pbSaveInProgress # Save at starting position (not current position) oldmapid=$game_map.map_id oldx=$game_player.x oldy=$game_player.y olddirection=$game_player.direction $game_map.map_id=@start[0] $game_player.moveto2(@start[1],@start[2]) $game_player.direction=8 # facing up pbSave(true) # Restore actual position $game_map.map_id=oldmapid $game_player.moveto2(oldx,oldy) $game_player.direction=olddirection end def pbEnd $Trainer.party=@oldParty return if !@inProgress save=(@decision!=0) reset $game_map.need_refresh=true if save pbSave(true) end endend
Why Battle Challenges Save Differently
Battle Challenges save at the entrance rather than the player’s current location:
Consistent State: Always resume at challenge start
No Exploits: Can’t save in the middle to retry battles
Clean Exit: Properly restores party after challenge
Progress Tracking: Saves wins/losses separately from main game
Pokémon Essentials BES doesn’t have auto-save by default, but you can implement it.
Example auto-save implementation:
def pbAutoSave return if !$Trainer return if $game_temp.in_battle return if $game_temp.in_menu # Don't auto-save in certain maps return if pbGetMetadata($game_map.map_id, MetadataDisableSaving) # Check if enough time has passed if !$PokemonGlobal.lastAutoSave $PokemonGlobal.lastAutoSave = Time.now end time_since_last = Time.now - $PokemonGlobal.lastAutoSave return if time_since_last < 300 # 5 minutes # Perform auto-save pbMessage("Saving...") pbSave(true) $PokemonGlobal.lastAutoSave = Time.nowend
class PBPokemon def _dump(depth) # Convert to array for serialization return [@species,@item,@nature,@move1,@move2, @move3,@move4,@ev].pack("vvCvvvvC") end def self._load(str) # Reconstruct from serialized data data=str.unpack("vvCvvvvC") return self.new( data[0],data[1],data[2],data[3], data[4],data[5],data[6],data[7] ) endend