• 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.
  • Reminder: AI-generated content is not allowed on the forums per the Rules and Regulations. Please contact us if you have any questions!
Resource icon

Resource Box Ranch System 2025-04-01

[Pokémon Essentials version 21.1]
[v21.1 Hotfixes 1.0.9]

Exception: NoMethodError
Message: undefined method `disposeSpritsets' for #<Scene_DebugIntro>

Backtrace:
[Box Ranch System] main.rb:419:in `clear_ranch_pokemon'
[Box Ranch System] main.rb:183:in `setup_ranch_pokemon'
[Box Ranch System] main.rb:176:in `setup'
[Box Ranch System] main.rb:73:in `setup'
Game_MapFactory:24:in `setup'
StartGame:82:in `load_map'
StartGame:68:in `load'
[Auto Multi Save] Auto Multi Save.rb:300:in `block (2 levels) in pbStartLoadScreen'
[Auto Multi Save] Auto Multi Save.rb:293:in `loop'
[Auto Multi Save] Auto Multi Save.rb:293:in `block in pbStartLoadScreen'

This exception was logged in
C:\Users\USERNAME\AppData\Roaming\Pokemon path of champions\errorlog.txt.
Hold Ctrl when closing this message to copy it to the clipboard.
help
I got this exact error. It didn't happen initially, I'd save and for the next hour it seemed to keep working, but when i left for over an hour or shut down for the night it would give me this. Tried several times. I did save on the Map I used as the ranch, so i'll try a save in another map and see if it does anything later. So far save file doesn't want to load no matter what i do.

EDIT: So far it seem to only happen when I save on the ranch map. been working fine ever since. I might just give the player a warning until the issue is resolved.
 
Last edited:
Here is a working version of the script. Only replace the main script.

Ruby:
Expand Collapse Copy
#===============================================================================
# * Box Ranch System - Optimized Version
#===============================================================================

# Configuration is loaded automatically from config.rb

# Constants
module BoxRanchConstants
  RANCH_EVENT_ID_START = 1000  # Starting ID for ranch events
  DEFAULT_SPRITE = "Graphics/Characters/Followers/000"
end

# Helper function to get the correct event name based on configuration
def get_ranch_event_name(species, in_water = false)
  if BoxRanchConfig::USE_REFLECTION_NAMES
    prefix = in_water ? BoxRanchConfig::WATER_EVENT_PREFIX_REFLECTION : BoxRanchConfig::LAND_EVENT_PREFIX_REFLECTION
  else
    prefix = in_water ? BoxRanchConfig::WATER_EVENT_PREFIX : BoxRanchConfig::LAND_EVENT_PREFIX
  end
  return "#{prefix}_#{species}"
end

# Helper function to load the correct Pokémon graphic
def box_ranch_sprite_filename(species, form = 0, gender = 0, shiny = false, in_water = false, levitates = false)
  folder_extra = if in_water
    shiny ? "Swimming Shiny" : "Swimming"
  elsif levitates
    shiny ? "Levitates Shiny" : "Levitates"
  else
    shiny ? "Followers shiny" : "Followers"
  end
 
  # Try to get the graphic file
  fname = nil
  begin
    fname = GameData::Species.check_graphic_file("Graphics/Characters/", species, form, gender, shiny, false, folder_extra)
  rescue
    # Ignore and use fallback
  end
 
  # Fallback chain
  if nil_or_empty?(fname)
    species_name = species.to_s
    fname = "Graphics/Characters/#{folder_extra}/#{species_name}"
   
    if !pbResolveBitmap(fname)
      # Try standard Followers folder
      fname = "Graphics/Characters/Followers/#{species_name}"
      fname = BoxRanchConstants::DEFAULT_SPRITE if !pbResolveBitmap(fname)
    end
  end
 
  return fname
end

# Helper function to check if a Pokémon is a Water type
def is_water_pokemon?(pokemon)
  return false if !pokemon
  return pokemon.types.include?(:WATER)
end

# Helper function to check if a Pokémon can levitate
def is_levitating_pokemon?(pokemon)
  return false if !pokemon
 
  levitating_species = [
    :GASTLY, :HAUNTER, :GENGAR, :KOFFING, :WEEZING, :PORYGON,
    :MISDREAVUS, :UNOWN, :NATU, :XATU, :ESPEON, :MURKROW, :WOBBUFFET,
    :GIRAFARIG, :PINECO, :DUNSPARCE, :GLIGAR, :LUGIA, :CELEBI,
    :DUSTOX, :SHEDINJA, :NINJASK, :WHISMUR, :LOUDRED, :EXPLOUD,
    :VOLBEAT, :ILLUMISE, :FLYGON, :BALTOY, :CLAYDOL, :LUNATONE, :SOLROCK,
    :CASTFORM, :SHUPPET, :BANETTE, :DUSKULL, :CHIMECHO, :GLALIE, :DEOXYS,
    :BRONZOR, :BRONZONG, :DRIFLOON, :DRIFBLIM, :CHINGLING,
    :SPIRITOMB, :CARNIVINE, :ROTOM, :UXIE, :MESPRIT, :AZELF,
    :GIRATINA, :CRESSELIA, :DARKRAI,
    :YAMASK, :SIGILYPH, :SOLOSIS, :DUOSION, :REUNICLUS, :VANILLITE,
    :VANILLISH, :VANILLUXE, :EMOLGA, :TYNAMO, :EELEKTRIK, :EELEKTROSS,
    :CRYOGONAL, :HYDREIGON, :VOLCARONA,
    :VIKAVOLT, :CUTIEFLY, :RIBOMBEE, :COMFEY, :DHELMISE, :LUNALA,
    :NIHILEGO, :CELESTEELA, :KARTANA, :XURKITREE, :PHEROMOSA
  ]
 
  levitating_abilities = [:LEVITATE, :AIRLOCK, :MAGNETRISE, :TELEPATHY]
 
  return levitating_species.include?(pokemon.species) ||
         levitating_abilities.include?(pokemon.ability.id)
end

# Helper function to check if a tile is water
def is_water_tile?(x, y)
  return false if !$game_map
  terrain_tag = $game_map.terrain_tag(x, y)
  return [5, 6, 7].include?(terrain_tag)
end

# Helper function to find water tiles on the map
def find_water_tiles
  return [] if !$game_map
 
  water_tiles = []
  $game_map.width.times do |x|
    $game_map.height.times do |y|
      water_tiles.push([x, y]) if is_water_tile?(x, y)
    end
  end
 
  return water_tiles
end

# Helper function to find land tiles on the map
def find_land_tiles
  return [] if !$game_map
 
  land_tiles = []
  $game_map.width.times do |x|
    $game_map.height.times do |y|
      land_tiles.push([x, y]) if !is_water_tile?(x, y) && $game_map.passable?(x, y, 0)
    end
  end
 
  return land_tiles
end

# Helper function to play the Pokémon's cry
def play_pokemon_cry(pokemon, volume = 90)
  return if !pokemon
 
  if pokemon.is_a?(Pokemon)
    GameData::Species.play_cry_from_pokemon(pokemon, volume) if !pokemon.egg?
  else
    GameData::Species.play_cry_from_species(pokemon, 0, volume)
  end
end

class BoxRanch
  attr_reader :pokemon_events
  attr_accessor :pending_swap_data  # For deferred swap completion

  def initialize
    @pokemon_events = {}
    @pokemon_locations = {}
    @map_id = BoxRanchConfig::MAP_ID
    @water_tiles = []
    @land_tiles = []
    @is_setting_up = false
    @pending_swap_data = nil
  end

  def setup
    return if @is_setting_up || !$game_map
    return if $game_map.map_id != @map_id
    return unless $scene.is_a?(Scene_Map) || $scene.is_a?(Scene_DebugIntro)
   
    @is_setting_up = true
    echoln("BoxRanch: Starting setup on map #{@map_id}")
   
    begin
      setup_ranch_pokemon
    rescue => e
      echoln("BoxRanch Error during setup: #{e.message}")
      echoln(e.backtrace.join("\n"))
    ensure
      @is_setting_up = false
    end
  end

  def update
    # Check if we have a pending swap to complete
    complete_pending_swap if @pending_swap_data
  end

  private

  def setup_ranch_pokemon
    block_autosave(true)
   
    clear_ranch_pokemon
    scan_map_tiles
    load_pokemon_from_boxes
    create_all_events
    refresh_following_pokemon
   
    echoln("BoxRanch: Setup complete! Total events: #{@pokemon_events.size}")
   
    block_autosave(false)
  end

  def block_autosave(state)
    return unless $game_temp && $game_temp.respond_to?(:no_autosave=)
    $game_temp.no_autosave = state
  end

  def scan_map_tiles
    @water_tiles = find_water_tiles
    @land_tiles = find_land_tiles
    echoln("BoxRanch: Found #{@water_tiles.length} water tiles and #{@land_tiles.length} land tiles")
  end

  def load_pokemon_from_boxes
    @pokemon_locations.clear
    pokemon_list = []
   
    $PokemonStorage.maxBoxes.times do |i|
      $PokemonStorage.maxPokemon(i).times do |j|
        pkmn = $PokemonStorage[i, j]
        next unless pkmn
       
        pokemon_list.push(pkmn)
        @pokemon_locations[pkmn] = [i, j]
      end
    end
   
    echoln("BoxRanch: Found #{pokemon_list.length} Pokemon in boxes")
   
    # Create test Pokemon if needed
    pokemon_list = create_test_pokemon if pokemon_list.empty? && BoxRanchConfig::CREATE_TEST_POKEMON
   
    categorize_pokemon(pokemon_list)
  end

  def create_test_pokemon
    test_list = []
    test_list.push(Pokemon.new(BoxRanchConfig::TEST_LAND_SPECIES, BoxRanchConfig::TEST_LEVEL))
   
    if !@water_tiles.empty?
      test_list.push(Pokemon.new(BoxRanchConfig::TEST_WATER_SPECIES, BoxRanchConfig::TEST_LEVEL))
    end
   
    echoln("BoxRanch: Created #{test_list.length} test Pokemon")
    return test_list
  end

  def categorize_pokemon(pokemon_list)
    @water_pokemon = []
    @land_pokemon = []
   
    pokemon_list.each do |pkmn|
      if is_water_pokemon?(pkmn) && !@water_tiles.empty?
        @water_pokemon.push(pkmn)
      else
        @land_pokemon.push(pkmn)
      end
    end
   
    echoln("BoxRanch: #{@land_pokemon.length} land, #{@water_pokemon.length} water Pokemon")
  end

  def create_all_events
    max_land = [@land_pokemon.size, BoxRanchConfig::MAX_LAND_POKEMON].min
    @land_pokemon[0...max_land].each_with_index { |pkmn, i| create_pokemon_event(pkmn, i, false) }
   
    max_water = [@water_pokemon.size, BoxRanchConfig::MAX_WATER_POKEMON].min
    @water_pokemon[0...max_water].each_with_index { |pkmn, i| create_pokemon_event(pkmn, i, true) }
  end

  def create_pokemon_event(pkmn, index, in_water)
    x, y = get_spawn_position(index, in_water)
    event = build_event(pkmn, x, y, in_water)
    game_event = spawn_event(event, x, y)
   
    @pokemon_events[event.id] = pkmn
    echoln("BoxRanch: Created event #{event.id} for #{pkmn.name} at (#{x}, #{y})")
  end

  def get_spawn_position(index, in_water)
    tiles = in_water ? @water_tiles : @land_tiles
   
    if !tiles.empty?
      pos = tiles.sample
      tiles.delete(pos)
      return pos
    end
   
    # Fallback to grid positioning
    return calculate_grid_position(index)
  end

  def calculate_grid_position(index)
    area = { x_start: 30, y_start: 30, width: 15, height: 15, columns: 3, rows: 4 }
   
    column = index % area[:columns]
    row = (index / area[:columns]) % area[:rows]
   
    cell_width = area[:width] / area[:columns]
    cell_height = area[:height] / area[:rows]
   
    x = area[:x_start] + (column * cell_width) + rand(cell_width / 2)
    y = area[:y_start] + (row * cell_height) + rand(cell_height / 2)
   
    return [x, y]
  end

  def build_event(pkmn, x, y, in_water)
    event = RPG::Event.new(x, y)
    event.id = generate_event_id
    event.name = get_ranch_event_name(pkmn.species, in_water)
   
    setup_event_graphic(event, pkmn, in_water)
    setup_event_movement(event, pkmn, in_water)
    setup_event_commands(event, pkmn, in_water)
   
    return event
  end

  def generate_event_id
    existing_ids = $game_map.events.keys
    return existing_ids.empty? ? BoxRanchConstants::RANCH_EVENT_ID_START : [existing_ids.max + 1, BoxRanchConstants::RANCH_EVENT_ID_START].max
  end

  def setup_event_graphic(event, pkmn, in_water)
    levitates = is_levitating_pokemon?(pkmn)
    sprite_path = box_ranch_sprite_filename(pkmn.species, pkmn.form || 0, pkmn.gender, pkmn.shiny?, in_water, levitates)
   
    event.pages[0].graphic.character_name = sprite_path.gsub("Graphics/Characters/", "")
    event.pages[0].graphic.character_hue = 0
    event.pages[0].graphic.direction = 2
  end

  def setup_event_movement(event, pkmn, in_water)
    event.pages[0].through = false
    event.pages[0].always_on_top = false
    event.pages[0].step_anime = true
    event.pages[0].trigger = 0
    event.pages[0].move_type = 1
   
    # Nature-based movement
    nature_value = pkmn.nature.id.to_s.hash.abs
   
    if in_water
      speed_range = BoxRanchConfig::WATER_SPEED_MAX - BoxRanchConfig::WATER_SPEED_MIN + 1
      event.pages[0].move_speed = BoxRanchConfig::WATER_SPEED_MIN + (nature_value % speed_range)
    else
      speed_range = BoxRanchConfig::LAND_SPEED_MAX - BoxRanchConfig::LAND_SPEED_MIN + 1
      event.pages[0].move_speed = BoxRanchConfig::LAND_SPEED_MIN + (nature_value % speed_range)
    end
   
    freq_range = BoxRanchConfig::FREQUENCY_MAX - BoxRanchConfig::FREQUENCY_MIN + 1
    event.pages[0].move_frequency = BoxRanchConfig::FREQUENCY_MIN + (nature_value % freq_range)
   
    event.pages[0].move_route = RPG::MoveRoute.new
    event.pages[0].move_route.repeat = true
    event.pages[0].move_route.skippable = false
    event.pages[0].move_route.list = []
  end

  def setup_event_commands(event, pkmn, in_water)
    event.pages[0].list = []
   
    Compiler::push_script(event.pages[0].list, "play_pokemon_cry(:#{pkmn.species}, 100)")
    Compiler::push_script(event.pages[0].list, "pbMessage(\"#{pkmn.name} looks at you friendly!\")")
   
    if pkmn.shiny?
      Compiler::push_script(event.pages[0].list, "pbMessage(\"#{pkmn.name} shines conspicuously in the sunlight.\")")
    end
   
    nature_text = get_nature_text(pkmn.nature)
    Compiler::push_script(event.pages[0].list, "pbMessage(\"#{nature_text}\")")
   
    if in_water
      Compiler::push_script(event.pages[0].list, "pbMessage(\"It swims happily in the water!\")")
    elsif is_levitating_pokemon?(pkmn)
      Compiler::push_script(event.pages[0].list, "pbMessage(\"It floats elegantly in the air!\")")
    end
   
    Compiler::push_script(event.pages[0].list, "pbMessage(\"Level: #{pkmn.level}\\nAbility: #{pkmn.ability.name}\")")
    Compiler::push_script(event.pages[0].list, "show_pokemon_interaction_menu(:#{pkmn.species}, #{pkmn.level}, #{event.id})")
   
    Compiler::push_end(event.pages[0].list)
  end

  def spawn_event(event, x, y)
    game_event = Game_Event.new($game_map.map_id, event)
    game_event.moveto(x, y)
    game_event.refresh
    $game_map.events[event.id] = game_event
    return game_event
  end

  def get_nature_text(nature)
    nature_texts = {
      :JOLLY => "It dances around cheerfully.",
      :NAIVE => "It is very playful.",
      :HASTY => "It can't stand still and is constantly running around.",
      :CALM => "It rests peacefully.",
      :CAREFUL => "It attentively observes its surroundings.",
      :QUIET => "It enjoys the tranquility of the ranch.",
      :BRAVE => "It bravely shows itself off.",
      :ADAMANT => "It trains its muscles.",
      :NAUGHTY => "It seems to be up to something."
    }
   
    return nature_texts[nature.id] || "It feels very comfortable on the ranch."
  end

  public

  def clear_ranch_pokemon
    echoln("BoxRanch: Clearing #{@pokemon_events.size} ranch events")
   
    # Remove tracked events
    @pokemon_events.keys.each do |event_id|
      $game_map.events.delete(event_id) if $game_map.events[event_id]
    end
   
    @pokemon_events.clear
    @pokemon_locations.clear
    refresh_following_pokemon
  end

  def remove_pokemon_event(event_id)
    block_autosave(true)
   
    echoln("BoxRanch: Removing event #{event_id}")
   
    # Remove the event from the map
    $game_map.events.delete(event_id)
    @pokemon_events.delete(event_id)
   
    # SOLUTION ULTIME: Map transfer pour force un refresh complet
    force_map_reload
   
    block_autosave(false)
  end

  def force_map_reload
    echoln("BoxRanch: Forcing complete map reload to eliminate ghost sprites")
   
    # Sauvegarder la position actuelle
    current_map_id = $game_map.map_id
    current_x = $game_player.x
    current_y = $game_player.y
    current_direction = $game_player.direction
   
    echoln("BoxRanch: Player position: Map #{current_map_id}, (#{current_x}, #{current_y}), Dir #{current_direction}")
   
    # Sauvegarder l'état du Following Pokemon
    follower_toggled = $PokemonGlobal.follower_toggled if $PokemonGlobal
   
    # Préparer le transfert vers la même position
    $game_temp.player_transferring = true
    $game_temp.player_new_map_id = current_map_id
    $game_temp.player_new_x = current_x
    $game_temp.player_new_y = current_y
    $game_temp.player_new_direction = current_direction
   
    # Effectuer le transfert immédiatement
    if $scene.is_a?(Scene_Map)
      $scene.transfer_player
     
      # Petit délai pour que le transfert soit complété
      Graphics.update
      Input.update
      pbUpdateSceneMap
    end
   
    # Restaurer l'état du Following Pokemon
    if $PokemonGlobal && follower_toggled != nil
      $PokemonGlobal.follower_toggled = follower_toggled
    end
   
    # Rafraîchir le Following Pokemon
    if defined?(FollowingPkmn)
      FollowingPkmn.refresh(false)
    end
   
    echoln("BoxRanch: Map reload complete")
    pbWait(0.05)
  end

  def refresh_following_pokemon
    return unless defined?(FollowingPkmn)
    FollowingPkmn.refresh(false)
  end

  # Public method for creating event at specific position (used by swap)
  def create_pokemon_event_at(pkmn, x, y, in_water)
    event = build_event(pkmn, x, y, in_water)
    game_event = spawn_event(event, x, y)
    @pokemon_events[event.id] = pkmn
    echoln("BoxRanch: Created event #{event.id} for #{pkmn.name} at (#{x}, #{y})")
  end

  def get_pokemon_location(pokemon)
    @pokemon_locations[pokemon]
  end

  def set_pokemon_location(pokemon, box_index, slot_index)
    @pokemon_locations[pokemon] = [box_index, slot_index]
  end

  def remove_pokemon_location(pokemon)
    @pokemon_locations.delete(pokemon)
  end
 
  # Store swap data to be completed after event finishes
  def prepare_swap(party_pokemon, x, y, in_water)
    @pending_swap_data = {
      pokemon: party_pokemon,
      x: x,
      y: y,
      in_water: in_water
    }
    echoln("BoxRanch: Swap prepared for #{party_pokemon.name}, will complete after event")
  end
 
  def complete_pending_swap
    return unless @pending_swap_data
    return if $game_system.map_interpreter.running?  # Wait until event is done
   
    echoln("BoxRanch: Completing pending swap")
    data = @pending_swap_data
    @pending_swap_data = nil
   
    # Create the new event
    create_pokemon_event_at(data[:pokemon], data[:x], data[:y], data[:in_water])
   
    # Force a complete refresh
    force_map_reload
  end
end

#===============================================================================
# Interaction Functions
#===============================================================================

def show_pokemon_interaction_menu(species, level, event_id = nil)
  return unless event_id && $box_ranch && $box_ranch.pokemon_events[event_id]
 
  commands = [_INTL("Pet"), _INTL("Feed"), _INTL("Play")]
 
  if $player && $player.party
    party_size = $player.party.length
    if party_size < Settings::MAX_PARTY_SIZE
      commands.push(_INTL("Take to team"))
      commands.push(_INTL("Swap with team")) if party_size > 0
    else
      commands.push(_INTL("Swap with team"))
    end
  end
 
  commands.push(_INTL("Back"))
 
  choice = pbMessage(_INTL("What would you like to do?"), commands, commands.length)
 
  case choice
  when 0  # Pet
    pbMessage(_INTL("You gently pet the Pokémon. It seems to enjoy that!"))
    play_pokemon_cry(species, 70)
  when 1  # Feed
    pbMessage(_INTL("You give the Pokémon some food. It eats happily!"))
  when 2  # Play
    pbMessage(_INTL("You play with the Pokémon for a while. It has fun!"))
    play_pokemon_cry(species, 100)
  else
    action = commands[choice]
    take_to_party(event_id) if action == _INTL("Take to team")
    swap_with_party_pokemon(event_id) if action == _INTL("Swap with team")
  end
end

def take_to_party(event_id)
  return unless $box_ranch && $box_ranch.pokemon_events[event_id] && $player
 
  ranch_pokemon = $box_ranch.pokemon_events[event_id]
 
  if $player.party.length >= Settings::MAX_PARTY_SIZE
    pbMessage(_INTL("Your team is full. You can't take more Pokémon."))
    return
  end
 
  msg = _INTL("Do you want to take {1} (Lv. {2}) to your team?", ranch_pokemon.name, ranch_pokemon.level)
  return unless pbConfirmMessage(msg)
 
  # Add to party
  $player.party.push(ranch_pokemon)
 
  # Remove from box if it came from there
  ranch_box_location = $box_ranch.get_pokemon_location(ranch_pokemon)
  if ranch_box_location
    box_index, slot_index = ranch_box_location
    $PokemonStorage[box_index, slot_index] = nil
    $box_ranch.remove_pokemon_location(ranch_pokemon)
  end
 
  # Remove event (uses force_map_reload internally - this works fine)
  $box_ranch.remove_pokemon_event(event_id)
 
  pbMessage(_INTL("{1} joined your team!", ranch_pokemon.name))
end

def swap_with_party_pokemon(event_id)
  return unless $box_ranch && $box_ranch.pokemon_events[event_id] && $player
  return if !$player.party || $player.party.empty?
 
  ranch_pokemon = $box_ranch.pokemon_events[event_id]
 
  pbMessage(_INTL("Choose a Pokémon from your team to swap with."))
 
  pbChoosePokemon(1, 2)
  chosen_index = $game_variables[1]
 
  if chosen_index < 0 || chosen_index >= $player.party.length
    pbMessage(_INTL("Swap cancelled."))
    return
  end
 
  party_pokemon = $player.party[chosen_index]
  msg = _INTL("Do you want to swap {1} (Lv. {2}) with {3} (Lv. {4})?",
    ranch_pokemon.name, ranch_pokemon.level, party_pokemon.name, party_pokemon.level)
 
  return unless pbConfirmMessage(msg)
 
  # Save event position
  event = $game_map.events[event_id]
  x, y = event.x, event.y
  in_water = event.name.include?("InWater")
 
  # Get box location
  ranch_box_location = $box_ranch.get_pokemon_location(ranch_pokemon)
 
  # Perform swap in data
  $player.party[chosen_index] = ranch_pokemon
 
  if ranch_box_location
    box_index, slot_index = ranch_box_location
    $PokemonStorage[box_index, slot_index] = party_pokemon
    $box_ranch.set_pokemon_location(party_pokemon, box_index, slot_index)
    $box_ranch.remove_pokemon_location(ranch_pokemon)
  end
 
  # Remove the old event (without map reload)
  $game_map.events.delete(event_id)
  $box_ranch.pokemon_events.delete(event_id)
 
  # Show success message FIRST
  pbMessage(_INTL("Swap successful! {1} is now in your team, and {2} is on the Ranch.",
    ranch_pokemon.name, party_pokemon.name))
 
  # AFTER the message, prepare the swap to be completed
  $box_ranch.prepare_swap(party_pokemon, x, y, in_water)
end

#===============================================================================
# Event Handlers
#===============================================================================

# Initialize BoxRanch singleton
EventHandlers.add(:on_game_start, :init_box_ranch, proc {
  $box_ranch = BoxRanch.new
})

EventHandlers.add(:on_game_load, :reload_box_ranch, proc {
  $box_ranch = BoxRanch.new
 
  if $game_map && $game_map.map_id == BoxRanchConfig::MAP_ID
    $game_map.need_refresh = true
    pbWait(0.05)
    $box_ranch.setup
  end
})

EventHandlers.add(:on_map_change, :setup_box_ranch, proc { |_old_map_id|
  $box_ranch ||= BoxRanch.new
  $box_ranch.setup
})

EventHandlers.add(:on_box_change, :sync_box_ranch, proc { |_old_box|
  if $box_ranch && $game_map && $game_map.map_id == BoxRanchConfig::MAP_ID
    $box_ranch.setup
  end
})

#===============================================================================
# Game_Map integration
#===============================================================================

class Game_Map
  alias box_ranch_setup setup
  def setup(map_id)
    box_ranch_setup(map_id)
    $box_ranch ||= BoxRanch.new
    $box_ranch.setup if map_id == BoxRanchConfig::MAP_ID
  end
end

#===============================================================================
# Scene_Map integration
#===============================================================================

class Scene_Map
  alias box_ranch_update update
  def update
    box_ranch_update
    $box_ranch.update if $box_ranch
  end
end
 
Here is a working version of the script. Only replace the main script.

Ruby:
Expand Collapse Copy
#===============================================================================
# * Box Ranch System - Optimized Version
#===============================================================================

# Configuration is loaded automatically from config.rb

# Constants
module BoxRanchConstants
  RANCH_EVENT_ID_START = 1000  # Starting ID for ranch events
  DEFAULT_SPRITE = "Graphics/Characters/Followers/000"
end

# Helper function to get the correct event name based on configuration
def get_ranch_event_name(species, in_water = false)
  if BoxRanchConfig::USE_REFLECTION_NAMES
    prefix = in_water ? BoxRanchConfig::WATER_EVENT_PREFIX_REFLECTION : BoxRanchConfig::LAND_EVENT_PREFIX_REFLECTION
  else
    prefix = in_water ? BoxRanchConfig::WATER_EVENT_PREFIX : BoxRanchConfig::LAND_EVENT_PREFIX
  end
  return "#{prefix}_#{species}"
end

# Helper function to load the correct Pokémon graphic
def box_ranch_sprite_filename(species, form = 0, gender = 0, shiny = false, in_water = false, levitates = false)
  folder_extra = if in_water
    shiny ? "Swimming Shiny" : "Swimming"
  elsif levitates
    shiny ? "Levitates Shiny" : "Levitates"
  else
    shiny ? "Followers shiny" : "Followers"
  end
 
  # Try to get the graphic file
  fname = nil
  begin
    fname = GameData::Species.check_graphic_file("Graphics/Characters/", species, form, gender, shiny, false, folder_extra)
  rescue
    # Ignore and use fallback
  end
 
  # Fallback chain
  if nil_or_empty?(fname)
    species_name = species.to_s
    fname = "Graphics/Characters/#{folder_extra}/#{species_name}"
 
    if !pbResolveBitmap(fname)
      # Try standard Followers folder
      fname = "Graphics/Characters/Followers/#{species_name}"
      fname = BoxRanchConstants::DEFAULT_SPRITE if !pbResolveBitmap(fname)
    end
  end
 
  return fname
end

# Helper function to check if a Pokémon is a Water type
def is_water_pokemon?(pokemon)
  return false if !pokemon
  return pokemon.types.include?(:WATER)
end

# Helper function to check if a Pokémon can levitate
def is_levitating_pokemon?(pokemon)
  return false if !pokemon
 
  levitating_species = [
    :GASTLY, :HAUNTER, :GENGAR, :KOFFING, :WEEZING, :PORYGON,
    :MISDREAVUS, :UNOWN, :NATU, :XATU, :ESPEON, :MURKROW, :WOBBUFFET,
    :GIRAFARIG, :PINECO, :DUNSPARCE, :GLIGAR, :LUGIA, :CELEBI,
    :DUSTOX, :SHEDINJA, :NINJASK, :WHISMUR, :LOUDRED, :EXPLOUD,
    :VOLBEAT, :ILLUMISE, :FLYGON, :BALTOY, :CLAYDOL, :LUNATONE, :SOLROCK,
    :CASTFORM, :SHUPPET, :BANETTE, :DUSKULL, :CHIMECHO, :GLALIE, :DEOXYS,
    :BRONZOR, :BRONZONG, :DRIFLOON, :DRIFBLIM, :CHINGLING,
    :SPIRITOMB, :CARNIVINE, :ROTOM, :UXIE, :MESPRIT, :AZELF,
    :GIRATINA, :CRESSELIA, :DARKRAI,
    :YAMASK, :SIGILYPH, :SOLOSIS, :DUOSION, :REUNICLUS, :VANILLITE,
    :VANILLISH, :VANILLUXE, :EMOLGA, :TYNAMO, :EELEKTRIK, :EELEKTROSS,
    :CRYOGONAL, :HYDREIGON, :VOLCARONA,
    :VIKAVOLT, :CUTIEFLY, :RIBOMBEE, :COMFEY, :DHELMISE, :LUNALA,
    :NIHILEGO, :CELESTEELA, :KARTANA, :XURKITREE, :PHEROMOSA
  ]
 
  levitating_abilities = [:LEVITATE, :AIRLOCK, :MAGNETRISE, :TELEPATHY]
 
  return levitating_species.include?(pokemon.species) ||
         levitating_abilities.include?(pokemon.ability.id)
end

# Helper function to check if a tile is water
def is_water_tile?(x, y)
  return false if !$game_map
  terrain_tag = $game_map.terrain_tag(x, y)
  return [5, 6, 7].include?(terrain_tag)
end

# Helper function to find water tiles on the map
def find_water_tiles
  return [] if !$game_map
 
  water_tiles = []
  $game_map.width.times do |x|
    $game_map.height.times do |y|
      water_tiles.push([x, y]) if is_water_tile?(x, y)
    end
  end
 
  return water_tiles
end

# Helper function to find land tiles on the map
def find_land_tiles
  return [] if !$game_map
 
  land_tiles = []
  $game_map.width.times do |x|
    $game_map.height.times do |y|
      land_tiles.push([x, y]) if !is_water_tile?(x, y) && $game_map.passable?(x, y, 0)
    end
  end
 
  return land_tiles
end

# Helper function to play the Pokémon's cry
def play_pokemon_cry(pokemon, volume = 90)
  return if !pokemon
 
  if pokemon.is_a?(Pokemon)
    GameData::Species.play_cry_from_pokemon(pokemon, volume) if !pokemon.egg?
  else
    GameData::Species.play_cry_from_species(pokemon, 0, volume)
  end
end

class BoxRanch
  attr_reader :pokemon_events
  attr_accessor :pending_swap_data  # For deferred swap completion

  def initialize
    @pokemon_events = {}
    @pokemon_locations = {}
    @map_id = BoxRanchConfig::MAP_ID
    @water_tiles = []
    @land_tiles = []
    @is_setting_up = false
    @pending_swap_data = nil
  end

  def setup
    return if @is_setting_up || !$game_map
    return if $game_map.map_id != @map_id
    return unless $scene.is_a?(Scene_Map) || $scene.is_a?(Scene_DebugIntro)
 
    @is_setting_up = true
    echoln("BoxRanch: Starting setup on map #{@map_id}")
 
    begin
      setup_ranch_pokemon
    rescue => e
      echoln("BoxRanch Error during setup: #{e.message}")
      echoln(e.backtrace.join("\n"))
    ensure
      @is_setting_up = false
    end
  end

  def update
    # Check if we have a pending swap to complete
    complete_pending_swap if @pending_swap_data
  end

  private

  def setup_ranch_pokemon
    block_autosave(true)
 
    clear_ranch_pokemon
    scan_map_tiles
    load_pokemon_from_boxes
    create_all_events
    refresh_following_pokemon
 
    echoln("BoxRanch: Setup complete! Total events: #{@pokemon_events.size}")
 
    block_autosave(false)
  end

  def block_autosave(state)
    return unless $game_temp && $game_temp.respond_to?(:no_autosave=)
    $game_temp.no_autosave = state
  end

  def scan_map_tiles
    @water_tiles = find_water_tiles
    @land_tiles = find_land_tiles
    echoln("BoxRanch: Found #{@water_tiles.length} water tiles and #{@land_tiles.length} land tiles")
  end

  def load_pokemon_from_boxes
    @pokemon_locations.clear
    pokemon_list = []
 
    $PokemonStorage.maxBoxes.times do |i|
      $PokemonStorage.maxPokemon(i).times do |j|
        pkmn = $PokemonStorage[i, j]
        next unless pkmn
     
        pokemon_list.push(pkmn)
        @pokemon_locations[pkmn] = [i, j]
      end
    end
 
    echoln("BoxRanch: Found #{pokemon_list.length} Pokemon in boxes")
 
    # Create test Pokemon if needed
    pokemon_list = create_test_pokemon if pokemon_list.empty? && BoxRanchConfig::CREATE_TEST_POKEMON
 
    categorize_pokemon(pokemon_list)
  end

  def create_test_pokemon
    test_list = []
    test_list.push(Pokemon.new(BoxRanchConfig::TEST_LAND_SPECIES, BoxRanchConfig::TEST_LEVEL))
 
    if !@water_tiles.empty?
      test_list.push(Pokemon.new(BoxRanchConfig::TEST_WATER_SPECIES, BoxRanchConfig::TEST_LEVEL))
    end
 
    echoln("BoxRanch: Created #{test_list.length} test Pokemon")
    return test_list
  end

  def categorize_pokemon(pokemon_list)
    @water_pokemon = []
    @land_pokemon = []
 
    pokemon_list.each do |pkmn|
      if is_water_pokemon?(pkmn) && !@water_tiles.empty?
        @water_pokemon.push(pkmn)
      else
        @land_pokemon.push(pkmn)
      end
    end
 
    echoln("BoxRanch: #{@land_pokemon.length} land, #{@water_pokemon.length} water Pokemon")
  end

  def create_all_events
    max_land = [@land_pokemon.size, BoxRanchConfig::MAX_LAND_POKEMON].min
    @land_pokemon[0...max_land].each_with_index { |pkmn, i| create_pokemon_event(pkmn, i, false) }
 
    max_water = [@water_pokemon.size, BoxRanchConfig::MAX_WATER_POKEMON].min
    @water_pokemon[0...max_water].each_with_index { |pkmn, i| create_pokemon_event(pkmn, i, true) }
  end

  def create_pokemon_event(pkmn, index, in_water)
    x, y = get_spawn_position(index, in_water)
    event = build_event(pkmn, x, y, in_water)
    game_event = spawn_event(event, x, y)
 
    @pokemon_events[event.id] = pkmn
    echoln("BoxRanch: Created event #{event.id} for #{pkmn.name} at (#{x}, #{y})")
  end

  def get_spawn_position(index, in_water)
    tiles = in_water ? @water_tiles : @land_tiles
 
    if !tiles.empty?
      pos = tiles.sample
      tiles.delete(pos)
      return pos
    end
 
    # Fallback to grid positioning
    return calculate_grid_position(index)
  end

  def calculate_grid_position(index)
    area = { x_start: 30, y_start: 30, width: 15, height: 15, columns: 3, rows: 4 }
 
    column = index % area[:columns]
    row = (index / area[:columns]) % area[:rows]
 
    cell_width = area[:width] / area[:columns]
    cell_height = area[:height] / area[:rows]
 
    x = area[:x_start] + (column * cell_width) + rand(cell_width / 2)
    y = area[:y_start] + (row * cell_height) + rand(cell_height / 2)
 
    return [x, y]
  end

  def build_event(pkmn, x, y, in_water)
    event = RPG::Event.new(x, y)
    event.id = generate_event_id
    event.name = get_ranch_event_name(pkmn.species, in_water)
 
    setup_event_graphic(event, pkmn, in_water)
    setup_event_movement(event, pkmn, in_water)
    setup_event_commands(event, pkmn, in_water)
 
    return event
  end

  def generate_event_id
    existing_ids = $game_map.events.keys
    return existing_ids.empty? ? BoxRanchConstants::RANCH_EVENT_ID_START : [existing_ids.max + 1, BoxRanchConstants::RANCH_EVENT_ID_START].max
  end

  def setup_event_graphic(event, pkmn, in_water)
    levitates = is_levitating_pokemon?(pkmn)
    sprite_path = box_ranch_sprite_filename(pkmn.species, pkmn.form || 0, pkmn.gender, pkmn.shiny?, in_water, levitates)
 
    event.pages[0].graphic.character_name = sprite_path.gsub("Graphics/Characters/", "")
    event.pages[0].graphic.character_hue = 0
    event.pages[0].graphic.direction = 2
  end

  def setup_event_movement(event, pkmn, in_water)
    event.pages[0].through = false
    event.pages[0].always_on_top = false
    event.pages[0].step_anime = true
    event.pages[0].trigger = 0
    event.pages[0].move_type = 1
 
    # Nature-based movement
    nature_value = pkmn.nature.id.to_s.hash.abs
 
    if in_water
      speed_range = BoxRanchConfig::WATER_SPEED_MAX - BoxRanchConfig::WATER_SPEED_MIN + 1
      event.pages[0].move_speed = BoxRanchConfig::WATER_SPEED_MIN + (nature_value % speed_range)
    else
      speed_range = BoxRanchConfig::LAND_SPEED_MAX - BoxRanchConfig::LAND_SPEED_MIN + 1
      event.pages[0].move_speed = BoxRanchConfig::LAND_SPEED_MIN + (nature_value % speed_range)
    end
 
    freq_range = BoxRanchConfig::FREQUENCY_MAX - BoxRanchConfig::FREQUENCY_MIN + 1
    event.pages[0].move_frequency = BoxRanchConfig::FREQUENCY_MIN + (nature_value % freq_range)
 
    event.pages[0].move_route = RPG::MoveRoute.new
    event.pages[0].move_route.repeat = true
    event.pages[0].move_route.skippable = false
    event.pages[0].move_route.list = []
  end

  def setup_event_commands(event, pkmn, in_water)
    event.pages[0].list = []
 
    Compiler::push_script(event.pages[0].list, "play_pokemon_cry(:#{pkmn.species}, 100)")
    Compiler::push_script(event.pages[0].list, "pbMessage(\"#{pkmn.name} looks at you friendly!\")")
 
    if pkmn.shiny?
      Compiler::push_script(event.pages[0].list, "pbMessage(\"#{pkmn.name} shines conspicuously in the sunlight.\")")
    end
 
    nature_text = get_nature_text(pkmn.nature)
    Compiler::push_script(event.pages[0].list, "pbMessage(\"#{nature_text}\")")
 
    if in_water
      Compiler::push_script(event.pages[0].list, "pbMessage(\"It swims happily in the water!\")")
    elsif is_levitating_pokemon?(pkmn)
      Compiler::push_script(event.pages[0].list, "pbMessage(\"It floats elegantly in the air!\")")
    end
 
    Compiler::push_script(event.pages[0].list, "pbMessage(\"Level: #{pkmn.level}\\nAbility: #{pkmn.ability.name}\")")
    Compiler::push_script(event.pages[0].list, "show_pokemon_interaction_menu(:#{pkmn.species}, #{pkmn.level}, #{event.id})")
 
    Compiler::push_end(event.pages[0].list)
  end

  def spawn_event(event, x, y)
    game_event = Game_Event.new($game_map.map_id, event)
    game_event.moveto(x, y)
    game_event.refresh
    $game_map.events[event.id] = game_event
    return game_event
  end

  def get_nature_text(nature)
    nature_texts = {
      :JOLLY => "It dances around cheerfully.",
      :NAIVE => "It is very playful.",
      :HASTY => "It can't stand still and is constantly running around.",
      :CALM => "It rests peacefully.",
      :CAREFUL => "It attentively observes its surroundings.",
      :QUIET => "It enjoys the tranquility of the ranch.",
      :BRAVE => "It bravely shows itself off.",
      :ADAMANT => "It trains its muscles.",
      :NAUGHTY => "It seems to be up to something."
    }
 
    return nature_texts[nature.id] || "It feels very comfortable on the ranch."
  end

  public

  def clear_ranch_pokemon
    echoln("BoxRanch: Clearing #{@pokemon_events.size} ranch events")
 
    # Remove tracked events
    @pokemon_events.keys.each do |event_id|
      $game_map.events.delete(event_id) if $game_map.events[event_id]
    end
 
    @pokemon_events.clear
    @pokemon_locations.clear
    refresh_following_pokemon
  end

  def remove_pokemon_event(event_id)
    block_autosave(true)
 
    echoln("BoxRanch: Removing event #{event_id}")
 
    # Remove the event from the map
    $game_map.events.delete(event_id)
    @pokemon_events.delete(event_id)
 
    # SOLUTION ULTIME: Map transfer pour force un refresh complet
    force_map_reload
 
    block_autosave(false)
  end

  def force_map_reload
    echoln("BoxRanch: Forcing complete map reload to eliminate ghost sprites")
 
    # Sauvegarder la position actuelle
    current_map_id = $game_map.map_id
    current_x = $game_player.x
    current_y = $game_player.y
    current_direction = $game_player.direction
 
    echoln("BoxRanch: Player position: Map #{current_map_id}, (#{current_x}, #{current_y}), Dir #{current_direction}")
 
    # Sauvegarder l'état du Following Pokemon
    follower_toggled = $PokemonGlobal.follower_toggled if $PokemonGlobal
 
    # Préparer le transfert vers la même position
    $game_temp.player_transferring = true
    $game_temp.player_new_map_id = current_map_id
    $game_temp.player_new_x = current_x
    $game_temp.player_new_y = current_y
    $game_temp.player_new_direction = current_direction
 
    # Effectuer le transfert immédiatement
    if $scene.is_a?(Scene_Map)
      $scene.transfer_player
   
      # Petit délai pour que le transfert soit complété
      Graphics.update
      Input.update
      pbUpdateSceneMap
    end
 
    # Restaurer l'état du Following Pokemon
    if $PokemonGlobal && follower_toggled != nil
      $PokemonGlobal.follower_toggled = follower_toggled
    end
 
    # Rafraîchir le Following Pokemon
    if defined?(FollowingPkmn)
      FollowingPkmn.refresh(false)
    end
 
    echoln("BoxRanch: Map reload complete")
    pbWait(0.05)
  end

  def refresh_following_pokemon
    return unless defined?(FollowingPkmn)
    FollowingPkmn.refresh(false)
  end

  # Public method for creating event at specific position (used by swap)
  def create_pokemon_event_at(pkmn, x, y, in_water)
    event = build_event(pkmn, x, y, in_water)
    game_event = spawn_event(event, x, y)
    @pokemon_events[event.id] = pkmn
    echoln("BoxRanch: Created event #{event.id} for #{pkmn.name} at (#{x}, #{y})")
  end

  def get_pokemon_location(pokemon)
    @pokemon_locations[pokemon]
  end

  def set_pokemon_location(pokemon, box_index, slot_index)
    @pokemon_locations[pokemon] = [box_index, slot_index]
  end

  def remove_pokemon_location(pokemon)
    @pokemon_locations.delete(pokemon)
  end
 
  # Store swap data to be completed after event finishes
  def prepare_swap(party_pokemon, x, y, in_water)
    @pending_swap_data = {
      pokemon: party_pokemon,
      x: x,
      y: y,
      in_water: in_water
    }
    echoln("BoxRanch: Swap prepared for #{party_pokemon.name}, will complete after event")
  end
 
  def complete_pending_swap
    return unless @pending_swap_data
    return if $game_system.map_interpreter.running?  # Wait until event is done
 
    echoln("BoxRanch: Completing pending swap")
    data = @pending_swap_data
    @pending_swap_data = nil
 
    # Create the new event
    create_pokemon_event_at(data[:pokemon], data[:x], data[:y], data[:in_water])
 
    # Force a complete refresh
    force_map_reload
  end
end

#===============================================================================
# Interaction Functions
#===============================================================================

def show_pokemon_interaction_menu(species, level, event_id = nil)
  return unless event_id && $box_ranch && $box_ranch.pokemon_events[event_id]
 
  commands = [_INTL("Pet"), _INTL("Feed"), _INTL("Play")]
 
  if $player && $player.party
    party_size = $player.party.length
    if party_size < Settings::MAX_PARTY_SIZE
      commands.push(_INTL("Take to team"))
      commands.push(_INTL("Swap with team")) if party_size > 0
    else
      commands.push(_INTL("Swap with team"))
    end
  end
 
  commands.push(_INTL("Back"))
 
  choice = pbMessage(_INTL("What would you like to do?"), commands, commands.length)
 
  case choice
  when 0  # Pet
    pbMessage(_INTL("You gently pet the Pokémon. It seems to enjoy that!"))
    play_pokemon_cry(species, 70)
  when 1  # Feed
    pbMessage(_INTL("You give the Pokémon some food. It eats happily!"))
  when 2  # Play
    pbMessage(_INTL("You play with the Pokémon for a while. It has fun!"))
    play_pokemon_cry(species, 100)
  else
    action = commands[choice]
    take_to_party(event_id) if action == _INTL("Take to team")
    swap_with_party_pokemon(event_id) if action == _INTL("Swap with team")
  end
end

def take_to_party(event_id)
  return unless $box_ranch && $box_ranch.pokemon_events[event_id] && $player
 
  ranch_pokemon = $box_ranch.pokemon_events[event_id]
 
  if $player.party.length >= Settings::MAX_PARTY_SIZE
    pbMessage(_INTL("Your team is full. You can't take more Pokémon."))
    return
  end
 
  msg = _INTL("Do you want to take {1} (Lv. {2}) to your team?", ranch_pokemon.name, ranch_pokemon.level)
  return unless pbConfirmMessage(msg)
 
  # Add to party
  $player.party.push(ranch_pokemon)
 
  # Remove from box if it came from there
  ranch_box_location = $box_ranch.get_pokemon_location(ranch_pokemon)
  if ranch_box_location
    box_index, slot_index = ranch_box_location
    $PokemonStorage[box_index, slot_index] = nil
    $box_ranch.remove_pokemon_location(ranch_pokemon)
  end
 
  # Remove event (uses force_map_reload internally - this works fine)
  $box_ranch.remove_pokemon_event(event_id)
 
  pbMessage(_INTL("{1} joined your team!", ranch_pokemon.name))
end

def swap_with_party_pokemon(event_id)
  return unless $box_ranch && $box_ranch.pokemon_events[event_id] && $player
  return if !$player.party || $player.party.empty?
 
  ranch_pokemon = $box_ranch.pokemon_events[event_id]
 
  pbMessage(_INTL("Choose a Pokémon from your team to swap with."))
 
  pbChoosePokemon(1, 2)
  chosen_index = $game_variables[1]
 
  if chosen_index < 0 || chosen_index >= $player.party.length
    pbMessage(_INTL("Swap cancelled."))
    return
  end
 
  party_pokemon = $player.party[chosen_index]
  msg = _INTL("Do you want to swap {1} (Lv. {2}) with {3} (Lv. {4})?",
    ranch_pokemon.name, ranch_pokemon.level, party_pokemon.name, party_pokemon.level)
 
  return unless pbConfirmMessage(msg)
 
  # Save event position
  event = $game_map.events[event_id]
  x, y = event.x, event.y
  in_water = event.name.include?("InWater")
 
  # Get box location
  ranch_box_location = $box_ranch.get_pokemon_location(ranch_pokemon)
 
  # Perform swap in data
  $player.party[chosen_index] = ranch_pokemon
 
  if ranch_box_location
    box_index, slot_index = ranch_box_location
    $PokemonStorage[box_index, slot_index] = party_pokemon
    $box_ranch.set_pokemon_location(party_pokemon, box_index, slot_index)
    $box_ranch.remove_pokemon_location(ranch_pokemon)
  end
 
  # Remove the old event (without map reload)
  $game_map.events.delete(event_id)
  $box_ranch.pokemon_events.delete(event_id)
 
  # Show success message FIRST
  pbMessage(_INTL("Swap successful! {1} is now in your team, and {2} is on the Ranch.",
    ranch_pokemon.name, party_pokemon.name))
 
  # AFTER the message, prepare the swap to be completed
  $box_ranch.prepare_swap(party_pokemon, x, y, in_water)
end

#===============================================================================
# Event Handlers
#===============================================================================

# Initialize BoxRanch singleton
EventHandlers.add(:on_game_start, :init_box_ranch, proc {
  $box_ranch = BoxRanch.new
})

EventHandlers.add(:on_game_load, :reload_box_ranch, proc {
  $box_ranch = BoxRanch.new
 
  if $game_map && $game_map.map_id == BoxRanchConfig::MAP_ID
    $game_map.need_refresh = true
    pbWait(0.05)
    $box_ranch.setup
  end
})

EventHandlers.add(:on_map_change, :setup_box_ranch, proc { |_old_map_id|
  $box_ranch ||= BoxRanch.new
  $box_ranch.setup
})

EventHandlers.add(:on_box_change, :sync_box_ranch, proc { |_old_box|
  if $box_ranch && $game_map && $game_map.map_id == BoxRanchConfig::MAP_ID
    $box_ranch.setup
  end
})

#===============================================================================
# Game_Map integration
#===============================================================================

class Game_Map
  alias box_ranch_setup setup
  def setup(map_id)
    box_ranch_setup(map_id)
    $box_ranch ||= BoxRanch.new
    $box_ranch.setup if map_id == BoxRanchConfig::MAP_ID
  end
end

#===============================================================================
# Scene_Map integration
#===============================================================================

class Scene_Map
  alias box_ranch_update update
  def update
    box_ranch_update
    $box_ranch.update if $box_ranch
  end
end
[Pokémon Essentials version 21.1]
[v21.1 Hotfixes 1.0.9]

Script error in Common Event, map 25 (Ranch)
Exception: NoMethodError
Message: undefined method `follower_toggled' for #<PokemonGlobalMetadata>

***Full script:
play_pokemon_cry(:PIDGEOTTO, 100)
pbMessage("Pidgeotto looks at you friendly!")
pbMessage("It feels very comfortable on the ranch.")
pbMessage("Level: 20\nAbility: Tangled Feet")
show_pokemon_interaction_menu(:PIDGEOTTO, 20, 1001)

Backtrace:
[Box Ranch System] main.rb:437:in `force_map_reload'
[Box Ranch System] main.rb:420:in `remove_pokemon_event'
[Box Ranch System] main.rb:586:in `take_to_party'
[Box Ranch System] main.rb:556:in `show_pokemon_interaction_menu'
(eval):5:in `execute_script'
033:Interpreter:138:in `eval'
033:Interpreter:138:in `execute_script'
034:Interpreter_Commands:1177:in `command_355'
034:Interpreter_Commands:116:in `execute_command'
033:Interpreter:130:in `block in update'



It crashes everytime i try to take or swap mons
 
[Pokémon Essentials version 21.1]
[v21.1 Hotfixes 1.0.9]

Script error in Common Event, map 25 (Ranch)
Exception: NoMethodError
Message: undefined method `follower_toggled' for #<PokemonGlobalMetadata>

***Full script:
play_pokemon_cry(:PIDGEOTTO, 100)
pbMessage("Pidgeotto looks at you friendly!")
pbMessage("It feels very comfortable on the ranch.")
pbMessage("Level: 20\nAbility: Tangled Feet")
show_pokemon_interaction_menu(:PIDGEOTTO, 20, 1001)

Backtrace:
[Box Ranch System] main.rb:437:in `force_map_reload'
[Box Ranch System] main.rb:420:in `remove_pokemon_event'
[Box Ranch System] main.rb:586:in `take_to_party'
[Box Ranch System] main.rb:556:in `show_pokemon_interaction_menu'
(eval):5:in `execute_script'
033:Interpreter:138:in `eval'
033:Interpreter:138:in `execute_script'
034:Interpreter_Commands:1177:in `command_355'
034:Interpreter_Commands:116:in `execute_command'
033:Interpreter:130:in `block in update'



It crashes everytime i try to take or swap mons
hope this version will solve your problem.

Ruby:
Expand Collapse Copy
#===============================================================================
# * Box Ranch System - Optimized Version
#===============================================================================

# Configuration is loaded automatically from config.rb

# Constants
module BoxRanchConstants
  RANCH_EVENT_ID_START = 1000  # Starting ID for ranch events
  DEFAULT_SPRITE = "Graphics/Characters/Followers/000"
end

# Helper function to get the correct event name based on configuration
def get_ranch_event_name(species, in_water = false)
  if BoxRanchConfig::USE_REFLECTION_NAMES
    prefix = in_water ? BoxRanchConfig::WATER_EVENT_PREFIX_REFLECTION : BoxRanchConfig::LAND_EVENT_PREFIX_REFLECTION
  else
    prefix = in_water ? BoxRanchConfig::WATER_EVENT_PREFIX : BoxRanchConfig::LAND_EVENT_PREFIX
  end
  return "#{prefix}_#{species}"
end

# Helper function to load the correct Pokémon graphic
def box_ranch_sprite_filename(species, form = 0, gender = 0, shiny = false, in_water = false, levitates = false)
  folder_extra = if in_water
    shiny ? "Swimming Shiny" : "Swimming"
  elsif levitates
    shiny ? "Levitates Shiny" : "Levitates"
  else
    shiny ? "Followers shiny" : "Followers"
  end
 
  # Try to get the graphic file
  fname = nil
  begin
    fname = GameData::Species.check_graphic_file("Graphics/Characters/", species, form, gender, shiny, false, folder_extra)
  rescue
    # Ignore and use fallback
  end
 
  # Fallback chain
  if nil_or_empty?(fname)
    species_name = species.to_s
    fname = "Graphics/Characters/#{folder_extra}/#{species_name}"
    
    if !pbResolveBitmap(fname)
      # Try standard Followers folder
      fname = "Graphics/Characters/Followers/#{species_name}"
      fname = BoxRanchConstants::DEFAULT_SPRITE if !pbResolveBitmap(fname)
    end
  end
 
  return fname
end

# Helper function to check if a Pokémon is a Water type
def is_water_pokemon?(pokemon)
  return false if !pokemon
  return pokemon.types.include?(:WATER)
end

# Helper function to check if a Pokémon can levitate
def is_levitating_pokemon?(pokemon)
  return false if !pokemon
 
  levitating_species = [
    :GASTLY, :HAUNTER, :GENGAR, :KOFFING, :WEEZING, :PORYGON,
    :MISDREAVUS, :UNOWN, :NATU, :XATU, :ESPEON, :MURKROW, :WOBBUFFET,
    :GIRAFARIG, :PINECO, :DUNSPARCE, :GLIGAR, :LUGIA, :CELEBI,
    :DUSTOX, :SHEDINJA, :NINJASK, :WHISMUR, :LOUDRED, :EXPLOUD,
    :VOLBEAT, :ILLUMISE, :FLYGON, :BALTOY, :CLAYDOL, :LUNATONE, :SOLROCK,
    :CASTFORM, :SHUPPET, :BANETTE, :DUSKULL, :CHIMECHO, :GLALIE, :DEOXYS,
    :BRONZOR, :BRONZONG, :DRIFLOON, :DRIFBLIM, :CHINGLING,
    :SPIRITOMB, :CARNIVINE, :ROTOM, :UXIE, :MESPRIT, :AZELF,
    :GIRATINA, :CRESSELIA, :DARKRAI,
    :YAMASK, :SIGILYPH, :SOLOSIS, :DUOSION, :REUNICLUS, :VANILLITE,
    :VANILLISH, :VANILLUXE, :EMOLGA, :TYNAMO, :EELEKTRIK, :EELEKTROSS,
    :CRYOGONAL, :HYDREIGON, :VOLCARONA,
    :VIKAVOLT, :CUTIEFLY, :RIBOMBEE, :COMFEY, :DHELMISE, :LUNALA,
    :NIHILEGO, :CELESTEELA, :KARTANA, :XURKITREE, :PHEROMOSA
  ]
 
  levitating_abilities = [:LEVITATE, :AIRLOCK, :MAGNETRISE, :TELEPATHY]
 
  return levitating_species.include?(pokemon.species) ||
         levitating_abilities.include?(pokemon.ability.id)
end

# Helper function to check if a tile is water
def is_water_tile?(x, y)
  return false if !$game_map
  terrain_tag = $game_map.terrain_tag(x, y)
  return [5, 6, 7].include?(terrain_tag)
end

# Helper function to find water tiles on the map
def find_water_tiles
  return [] if !$game_map
 
  water_tiles = []
  $game_map.width.times do |x|
    $game_map.height.times do |y|
      water_tiles.push([x, y]) if is_water_tile?(x, y)
    end
  end
 
  return water_tiles
end

# Helper function to find land tiles on the map
def find_land_tiles
  return [] if !$game_map
 
  land_tiles = []
  $game_map.width.times do |x|
    $game_map.height.times do |y|
      land_tiles.push([x, y]) if !is_water_tile?(x, y) && $game_map.passable?(x, y, 0)
    end
  end
 
  return land_tiles
end

# Helper function to play the Pokémon's cry
def play_pokemon_cry(pokemon, volume = 90)
  return if !pokemon
 
  if pokemon.is_a?(Pokemon)
    GameData::Species.play_cry_from_pokemon(pokemon, volume) if !pokemon.egg?
  else
    GameData::Species.play_cry_from_species(pokemon, 0, volume)
  end
end

class BoxRanch
  attr_reader :pokemon_events
  attr_accessor :pending_swap_data  # For deferred swap completion

  def initialize
    @pokemon_events = {}
    @pokemon_locations = {}
    @map_id = BoxRanchConfig::MAP_ID
    @water_tiles = []
    @land_tiles = []
    @is_setting_up = false
    @pending_swap_data = nil
  end

  def setup
    return if @is_setting_up || !$game_map
    return if $game_map.map_id != @map_id
    return unless $scene.is_a?(Scene_Map) || $scene.is_a?(Scene_DebugIntro)
    
    @is_setting_up = true
    echoln("BoxRanch: Starting setup on map #{@map_id}")
    
    begin
      setup_ranch_pokemon
    rescue => e
      echoln("BoxRanch Error during setup: #{e.message}")
      echoln(e.backtrace.join("\n"))
    ensure
      @is_setting_up = false
    end
  end

  def update
    # Check if we have a pending swap to complete
    complete_pending_swap if @pending_swap_data
  end

  private

  def setup_ranch_pokemon
    block_autosave(true)
    
    clear_ranch_pokemon
    scan_map_tiles
    load_pokemon_from_boxes
    create_all_events
    refresh_following_pokemon
    
    echoln("BoxRanch: Setup complete! Total events: #{@pokemon_events.size}")
    
    block_autosave(false)
  end

  def block_autosave(state)
    return unless $game_temp && $game_temp.respond_to?(:no_autosave=)
    $game_temp.no_autosave = state
  end

  def scan_map_tiles
    @water_tiles = find_water_tiles
    @land_tiles = find_land_tiles
    echoln("BoxRanch: Found #{@water_tiles.length} water tiles and #{@land_tiles.length} land tiles")
  end

  def load_pokemon_from_boxes
    @pokemon_locations.clear
    pokemon_list = []
    
    $PokemonStorage.maxBoxes.times do |i|
      $PokemonStorage.maxPokemon(i).times do |j|
        pkmn = $PokemonStorage[i, j]
        next unless pkmn
        
        pokemon_list.push(pkmn)
        @pokemon_locations[pkmn] = [i, j]
      end
    end
    
    echoln("BoxRanch: Found #{pokemon_list.length} Pokemon in boxes")
    
    # Create test Pokemon if needed
    pokemon_list = create_test_pokemon if pokemon_list.empty? && BoxRanchConfig::CREATE_TEST_POKEMON
    
    categorize_pokemon(pokemon_list)
  end

  def create_test_pokemon
    test_list = []
    test_list.push(Pokemon.new(BoxRanchConfig::TEST_LAND_SPECIES, BoxRanchConfig::TEST_LEVEL))
    
    if !@water_tiles.empty?
      test_list.push(Pokemon.new(BoxRanchConfig::TEST_WATER_SPECIES, BoxRanchConfig::TEST_LEVEL))
    end
    
    echoln("BoxRanch: Created #{test_list.length} test Pokemon")
    return test_list
  end

  def categorize_pokemon(pokemon_list)
    @water_pokemon = []
    @land_pokemon = []
    
    pokemon_list.each do |pkmn|
      if is_water_pokemon?(pkmn) && !@water_tiles.empty?
        @water_pokemon.push(pkmn)
      else
        @land_pokemon.push(pkmn)
      end
    end
    
    echoln("BoxRanch: #{@land_pokemon.length} land, #{@water_pokemon.length} water Pokemon")
  end

  def create_all_events
    max_land = [@land_pokemon.size, BoxRanchConfig::MAX_LAND_POKEMON].min
    @land_pokemon[0...max_land].each_with_index { |pkmn, i| create_pokemon_event(pkmn, i, false) }
    
    max_water = [@water_pokemon.size, BoxRanchConfig::MAX_WATER_POKEMON].min
    @water_pokemon[0...max_water].each_with_index { |pkmn, i| create_pokemon_event(pkmn, i, true) }
  end

  def create_pokemon_event(pkmn, index, in_water)
    x, y = get_spawn_position(index, in_water)
    event = build_event(pkmn, x, y, in_water)
    game_event = spawn_event(event, x, y)
    
    @pokemon_events[event.id] = pkmn
    echoln("BoxRanch: Created event #{event.id} for #{pkmn.name} at (#{x}, #{y})")
  end

  def get_spawn_position(index, in_water)
    tiles = in_water ? @water_tiles : @land_tiles
    
    if !tiles.empty?
      pos = tiles.sample
      tiles.delete(pos)
      return pos
    end
    
    # Fallback to grid positioning
    return calculate_grid_position(index)
  end

  def calculate_grid_position(index)
    area = { x_start: 30, y_start: 30, width: 15, height: 15, columns: 3, rows: 4 }
    
    column = index % area[:columns]
    row = (index / area[:columns]) % area[:rows]
    
    cell_width = area[:width] / area[:columns]
    cell_height = area[:height] / area[:rows]
    
    x = area[:x_start] + (column * cell_width) + rand(cell_width / 2)
    y = area[:y_start] + (row * cell_height) + rand(cell_height / 2)
    
    return [x, y]
  end

  def build_event(pkmn, x, y, in_water)
    event = RPG::Event.new(x, y)
    event.id = generate_event_id
    event.name = get_ranch_event_name(pkmn.species, in_water)
    
    setup_event_graphic(event, pkmn, in_water)
    setup_event_movement(event, pkmn, in_water)
    setup_event_commands(event, pkmn, in_water)
    
    return event
  end

  def generate_event_id
    existing_ids = $game_map.events.keys
    return existing_ids.empty? ? BoxRanchConstants::RANCH_EVENT_ID_START : [existing_ids.max + 1, BoxRanchConstants::RANCH_EVENT_ID_START].max
  end

  def setup_event_graphic(event, pkmn, in_water)
    levitates = is_levitating_pokemon?(pkmn)
    sprite_path = box_ranch_sprite_filename(pkmn.species, pkmn.form || 0, pkmn.gender, pkmn.shiny?, in_water, levitates)
    
    event.pages[0].graphic.character_name = sprite_path.gsub("Graphics/Characters/", "")
    event.pages[0].graphic.character_hue = 0
    event.pages[0].graphic.direction = 2
  end

  def setup_event_movement(event, pkmn, in_water)
    event.pages[0].through = false
    event.pages[0].always_on_top = false
    event.pages[0].step_anime = true
    event.pages[0].trigger = 0
    event.pages[0].move_type = 1
    
    # Nature-based movement
    nature_value = pkmn.nature.id.to_s.hash.abs
    
    if in_water
      speed_range = BoxRanchConfig::WATER_SPEED_MAX - BoxRanchConfig::WATER_SPEED_MIN + 1
      event.pages[0].move_speed = BoxRanchConfig::WATER_SPEED_MIN + (nature_value % speed_range)
    else
      speed_range = BoxRanchConfig::LAND_SPEED_MAX - BoxRanchConfig::LAND_SPEED_MIN + 1
      event.pages[0].move_speed = BoxRanchConfig::LAND_SPEED_MIN + (nature_value % speed_range)
    end
    
    freq_range = BoxRanchConfig::FREQUENCY_MAX - BoxRanchConfig::FREQUENCY_MIN + 1
    event.pages[0].move_frequency = BoxRanchConfig::FREQUENCY_MIN + (nature_value % freq_range)
    
    event.pages[0].move_route = RPG::MoveRoute.new
    event.pages[0].move_route.repeat = true
    event.pages[0].move_route.skippable = false
    event.pages[0].move_route.list = []
  end

  def setup_event_commands(event, pkmn, in_water)
    event.pages[0].list = []
    
    Compiler::push_script(event.pages[0].list, "play_pokemon_cry(:#{pkmn.species}, 100)")
    Compiler::push_script(event.pages[0].list, "pbMessage(\"#{pkmn.name} looks at you friendly!\")")
    
    if pkmn.shiny?
      Compiler::push_script(event.pages[0].list, "pbMessage(\"#{pkmn.name} shines conspicuously in the sunlight.\")")
    end
    
    nature_text = get_nature_text(pkmn.nature)
    Compiler::push_script(event.pages[0].list, "pbMessage(\"#{nature_text}\")")
    
    if in_water
      Compiler::push_script(event.pages[0].list, "pbMessage(\"It swims happily in the water!\")")
    elsif is_levitating_pokemon?(pkmn)
      Compiler::push_script(event.pages[0].list, "pbMessage(\"It floats elegantly in the air!\")")
    end
    
    Compiler::push_script(event.pages[0].list, "pbMessage(\"Level: #{pkmn.level}\\nAbility: #{pkmn.ability.name}\")")
    Compiler::push_script(event.pages[0].list, "show_pokemon_interaction_menu(:#{pkmn.species}, #{pkmn.level}, #{event.id})")
    
    Compiler::push_end(event.pages[0].list)
  end

  def spawn_event(event, x, y)
    game_event = Game_Event.new($game_map.map_id, event)
    game_event.moveto(x, y)
    game_event.refresh
    $game_map.events[event.id] = game_event
    return game_event
  end

  def get_nature_text(nature)
    nature_texts = {
      :JOLLY => "It dances around cheerfully.",
      :NAIVE => "It is very playful.",
      :HASTY => "It can't stand still and is constantly running around.",
      :CALM => "It rests peacefully.",
      :CAREFUL => "It attentively observes its surroundings.",
      :QUIET => "It enjoys the tranquility of the ranch.",
      :BRAVE => "It bravely shows itself off.",
      :ADAMANT => "It trains its muscles.",
      :NAUGHTY => "It seems to be up to something."
    }
    
    return nature_texts[nature.id] || "It feels very comfortable on the ranch."
  end

  public

  def clear_ranch_pokemon
    echoln("BoxRanch: Clearing #{@pokemon_events.size} ranch events")
    
    # Remove tracked events
    @pokemon_events.keys.each do |event_id|
      $game_map.events.delete(event_id) if $game_map.events[event_id]
    end
    
    @pokemon_events.clear
    @pokemon_locations.clear
    refresh_following_pokemon
  end

  def remove_pokemon_event(event_id)
    block_autosave(true)
    
    echoln("BoxRanch: Removing event #{event_id}")
    
    # Remove the event from the map
    $game_map.events.delete(event_id)
    @pokemon_events.delete(event_id)
    
    # SOLUTION ULTIME: Map transfer pour force un refresh complet
    force_map_reload
    
    block_autosave(false)
  end

  def force_map_reload
    echoln("BoxRanch: Forcing complete map reload to eliminate ghost sprites")
    
    # Sauvegarder la position actuelle
    current_map_id = $game_map.map_id
    current_x = $game_player.x
    current_y = $game_player.y
    current_direction = $game_player.direction
    
    echoln("BoxRanch: Player position: Map #{current_map_id}, (#{current_x}, #{current_y}), Dir #{current_direction}")
    
    # Sauvegarder l'état du Following Pokemon (uniquement si l'attribut existe)
    follower_toggled = nil
    if $PokemonGlobal && $PokemonGlobal.respond_to?(:follower_toggled)
      follower_toggled = $PokemonGlobal.follower_toggled
    end
    
    # Préparer le transfert vers la même position
    $game_temp.player_transferring = true
    $game_temp.player_new_map_id = current_map_id
    $game_temp.player_new_x = current_x
    $game_temp.player_new_y = current_y
    $game_temp.player_new_direction = current_direction
    
    # Effectuer le transfert immédiatement
    if $scene.is_a?(Scene_Map)
      $scene.transfer_player
      
      # Petit délai pour que le transfert soit complété
      Graphics.update
      Input.update
      pbUpdateSceneMap
    end
    
    # Restaurer l'état du Following Pokemon (uniquement si sauvegardé)
    if $PokemonGlobal && follower_toggled != nil && $PokemonGlobal.respond_to?(:follower_toggled=)
      $PokemonGlobal.follower_toggled = follower_toggled
    end
    
    # Rafraîchir le Following Pokemon
    if defined?(FollowingPkmn)
      FollowingPkmn.refresh(false)
    end
    
    echoln("BoxRanch: Map reload complete")
    pbWait(0.05)
  end

  def refresh_following_pokemon
    return unless defined?(FollowingPkmn)
    FollowingPkmn.refresh(false)
  end

  # Public method for creating event at specific position (used by swap)
  def create_pokemon_event_at(pkmn, x, y, in_water)
    event = build_event(pkmn, x, y, in_water)
    game_event = spawn_event(event, x, y)
    @pokemon_events[event.id] = pkmn
    echoln("BoxRanch: Created event #{event.id} for #{pkmn.name} at (#{x}, #{y})")
  end

  def get_pokemon_location(pokemon)
    @pokemon_locations[pokemon]
  end

  def set_pokemon_location(pokemon, box_index, slot_index)
    @pokemon_locations[pokemon] = [box_index, slot_index]
  end

  def remove_pokemon_location(pokemon)
    @pokemon_locations.delete(pokemon)
  end
 
  # Store swap data to be completed after event finishes
  def prepare_swap(party_pokemon, x, y, in_water)
    @pending_swap_data = {
      pokemon: party_pokemon,
      x: x,
      y: y,
      in_water: in_water
    }
    echoln("BoxRanch: Swap prepared for #{party_pokemon.name}, will complete after event")
  end
 
  def complete_pending_swap
    return unless @pending_swap_data
    return if $game_system.map_interpreter.running?  # Wait until event is done
    
    echoln("BoxRanch: Completing pending swap")
    data = @pending_swap_data
    @pending_swap_data = nil
    
    # Create the new event
    create_pokemon_event_at(data[:pokemon], data[:x], data[:y], data[:in_water])
    
    # Force a complete refresh
    force_map_reload
  end
end

#===============================================================================
# Interaction Functions
#===============================================================================

def show_pokemon_interaction_menu(species, level, event_id = nil)
  return unless event_id && $box_ranch && $box_ranch.pokemon_events[event_id]
 
  commands = [_INTL("Pet"), _INTL("Feed"), _INTL("Play")]
 
  if $player && $player.party
    party_size = $player.party.length
    if party_size < Settings::MAX_PARTY_SIZE
      commands.push(_INTL("Take to team"))
      commands.push(_INTL("Swap with team")) if party_size > 0
    else
      commands.push(_INTL("Swap with team"))
    end
  end
 
  commands.push(_INTL("Back"))
 
  choice = pbMessage(_INTL("What would you like to do?"), commands, commands.length)
 
  case choice
  when 0  # Pet
    pbMessage(_INTL("You gently pet the Pokémon. It seems to enjoy that!"))
    play_pokemon_cry(species, 70)
  when 1  # Feed
    pbMessage(_INTL("You give the Pokémon some food. It eats happily!"))
  when 2  # Play
    pbMessage(_INTL("You play with the Pokémon for a while. It has fun!"))
    play_pokemon_cry(species, 100)
  else
    action = commands[choice]
    take_to_party(event_id) if action == _INTL("Take to team")
    swap_with_party_pokemon(event_id) if action == _INTL("Swap with team")
  end
end

def take_to_party(event_id)
  return unless $box_ranch && $box_ranch.pokemon_events[event_id] && $player
 
  ranch_pokemon = $box_ranch.pokemon_events[event_id]
 
  if $player.party.length >= Settings::MAX_PARTY_SIZE
    pbMessage(_INTL("Your team is full. You can't take more Pokémon."))
    return
  end
 
  msg = _INTL("Do you want to take {1} (Lv. {2}) to your team?", ranch_pokemon.name, ranch_pokemon.level)
  return unless pbConfirmMessage(msg)
 
  # Add to party
  $player.party.push(ranch_pokemon)
 
  # Remove from box if it came from there
  ranch_box_location = $box_ranch.get_pokemon_location(ranch_pokemon)
  if ranch_box_location
    box_index, slot_index = ranch_box_location
    $PokemonStorage[box_index, slot_index] = nil
    $box_ranch.remove_pokemon_location(ranch_pokemon)
  end
 
  # Remove event (uses force_map_reload internally - this works fine)
  $box_ranch.remove_pokemon_event(event_id)
 
  pbMessage(_INTL("{1} joined your team!", ranch_pokemon.name))
end

def swap_with_party_pokemon(event_id)
  return unless $box_ranch && $box_ranch.pokemon_events[event_id] && $player
  return if !$player.party || $player.party.empty?
 
  ranch_pokemon = $box_ranch.pokemon_events[event_id]
 
  pbMessage(_INTL("Choose a Pokémon from your team to swap with."))
 
  pbChoosePokemon(1, 2)
  chosen_index = $game_variables[1]
 
  if chosen_index < 0 || chosen_index >= $player.party.length
    pbMessage(_INTL("Swap cancelled."))
    return
  end
 
  party_pokemon = $player.party[chosen_index]
  msg = _INTL("Do you want to swap {1} (Lv. {2}) with {3} (Lv. {4})?",
    ranch_pokemon.name, ranch_pokemon.level, party_pokemon.name, party_pokemon.level)
 
  return unless pbConfirmMessage(msg)
 
  # Save event position
  event = $game_map.events[event_id]
  x, y = event.x, event.y
  in_water = event.name.include?("InWater")
 
  # Get box location
  ranch_box_location = $box_ranch.get_pokemon_location(ranch_pokemon)
 
  # Perform swap in data
  $player.party[chosen_index] = ranch_pokemon
 
  if ranch_box_location
    box_index, slot_index = ranch_box_location
    $PokemonStorage[box_index, slot_index] = party_pokemon
    $box_ranch.set_pokemon_location(party_pokemon, box_index, slot_index)
    $box_ranch.remove_pokemon_location(ranch_pokemon)
  end
 
  # Remove the old event (without map reload)
  $game_map.events.delete(event_id)
  $box_ranch.pokemon_events.delete(event_id)
 
  # Show success message FIRST
  pbMessage(_INTL("Swap successful! {1} is now in your team, and {2} is on the Ranch.",
    ranch_pokemon.name, party_pokemon.name))
 
  # AFTER the message, prepare the swap to be completed
  $box_ranch.prepare_swap(party_pokemon, x, y, in_water)
end

#===============================================================================
# Event Handlers
#===============================================================================

# Initialize BoxRanch singleton
EventHandlers.add(:on_game_start, :init_box_ranch, proc {
  $box_ranch = BoxRanch.new
})

EventHandlers.add(:on_game_load, :reload_box_ranch, proc {
  $box_ranch = BoxRanch.new
 
  if $game_map && $game_map.map_id == BoxRanchConfig::MAP_ID
    $game_map.need_refresh = true
    pbWait(0.05)
    $box_ranch.setup
  end
})

EventHandlers.add(:on_map_change, :setup_box_ranch, proc { |_old_map_id|
  $box_ranch ||= BoxRanch.new
  $box_ranch.setup
})

EventHandlers.add(:on_box_change, :sync_box_ranch, proc { |_old_box|
  if $box_ranch && $game_map && $game_map.map_id == BoxRanchConfig::MAP_ID
    $box_ranch.setup
  end
})

#===============================================================================
# Game_Map integration
#===============================================================================

class Game_Map
  alias box_ranch_setup setup
  def setup(map_id)
    box_ranch_setup(map_id)
    $box_ranch ||= BoxRanch.new
    $box_ranch.setup if map_id == BoxRanchConfig::MAP_ID
  end
end

#===============================================================================
# Scene_Map integration 
#===============================================================================

class Scene_Map
  alias box_ranch_update update
  def update
    box_ranch_update
    $box_ranch.update if $box_ranch
  end
end
 
hope this version will solve your problem.

Ruby:
Expand Collapse Copy
#===============================================================================
# * Box Ranch System - Optimized Version
#===============================================================================

# Configuration is loaded automatically from config.rb

# Constants
module BoxRanchConstants
  RANCH_EVENT_ID_START = 1000  # Starting ID for ranch events
  DEFAULT_SPRITE = "Graphics/Characters/Followers/000"
end

# Helper function to get the correct event name based on configuration
def get_ranch_event_name(species, in_water = false)
  if BoxRanchConfig::USE_REFLECTION_NAMES
    prefix = in_water ? BoxRanchConfig::WATER_EVENT_PREFIX_REFLECTION : BoxRanchConfig::LAND_EVENT_PREFIX_REFLECTION
  else
    prefix = in_water ? BoxRanchConfig::WATER_EVENT_PREFIX : BoxRanchConfig::LAND_EVENT_PREFIX
  end
  return "#{prefix}_#{species}"
end

# Helper function to load the correct Pokémon graphic
def box_ranch_sprite_filename(species, form = 0, gender = 0, shiny = false, in_water = false, levitates = false)
  folder_extra = if in_water
    shiny ? "Swimming Shiny" : "Swimming"
  elsif levitates
    shiny ? "Levitates Shiny" : "Levitates"
  else
    shiny ? "Followers shiny" : "Followers"
  end
 
  # Try to get the graphic file
  fname = nil
  begin
    fname = GameData::Species.check_graphic_file("Graphics/Characters/", species, form, gender, shiny, false, folder_extra)
  rescue
    # Ignore and use fallback
  end
 
  # Fallback chain
  if nil_or_empty?(fname)
    species_name = species.to_s
    fname = "Graphics/Characters/#{folder_extra}/#{species_name}"
   
    if !pbResolveBitmap(fname)
      # Try standard Followers folder
      fname = "Graphics/Characters/Followers/#{species_name}"
      fname = BoxRanchConstants::DEFAULT_SPRITE if !pbResolveBitmap(fname)
    end
  end
 
  return fname
end

# Helper function to check if a Pokémon is a Water type
def is_water_pokemon?(pokemon)
  return false if !pokemon
  return pokemon.types.include?(:WATER)
end

# Helper function to check if a Pokémon can levitate
def is_levitating_pokemon?(pokemon)
  return false if !pokemon
 
  levitating_species = [
    :GASTLY, :HAUNTER, :GENGAR, :KOFFING, :WEEZING, :PORYGON,
    :MISDREAVUS, :UNOWN, :NATU, :XATU, :ESPEON, :MURKROW, :WOBBUFFET,
    :GIRAFARIG, :PINECO, :DUNSPARCE, :GLIGAR, :LUGIA, :CELEBI,
    :DUSTOX, :SHEDINJA, :NINJASK, :WHISMUR, :LOUDRED, :EXPLOUD,
    :VOLBEAT, :ILLUMISE, :FLYGON, :BALTOY, :CLAYDOL, :LUNATONE, :SOLROCK,
    :CASTFORM, :SHUPPET, :BANETTE, :DUSKULL, :CHIMECHO, :GLALIE, :DEOXYS,
    :BRONZOR, :BRONZONG, :DRIFLOON, :DRIFBLIM, :CHINGLING,
    :SPIRITOMB, :CARNIVINE, :ROTOM, :UXIE, :MESPRIT, :AZELF,
    :GIRATINA, :CRESSELIA, :DARKRAI,
    :YAMASK, :SIGILYPH, :SOLOSIS, :DUOSION, :REUNICLUS, :VANILLITE,
    :VANILLISH, :VANILLUXE, :EMOLGA, :TYNAMO, :EELEKTRIK, :EELEKTROSS,
    :CRYOGONAL, :HYDREIGON, :VOLCARONA,
    :VIKAVOLT, :CUTIEFLY, :RIBOMBEE, :COMFEY, :DHELMISE, :LUNALA,
    :NIHILEGO, :CELESTEELA, :KARTANA, :XURKITREE, :PHEROMOSA
  ]
 
  levitating_abilities = [:LEVITATE, :AIRLOCK, :MAGNETRISE, :TELEPATHY]
 
  return levitating_species.include?(pokemon.species) ||
         levitating_abilities.include?(pokemon.ability.id)
end

# Helper function to check if a tile is water
def is_water_tile?(x, y)
  return false if !$game_map
  terrain_tag = $game_map.terrain_tag(x, y)
  return [5, 6, 7].include?(terrain_tag)
end

# Helper function to find water tiles on the map
def find_water_tiles
  return [] if !$game_map
 
  water_tiles = []
  $game_map.width.times do |x|
    $game_map.height.times do |y|
      water_tiles.push([x, y]) if is_water_tile?(x, y)
    end
  end
 
  return water_tiles
end

# Helper function to find land tiles on the map
def find_land_tiles
  return [] if !$game_map
 
  land_tiles = []
  $game_map.width.times do |x|
    $game_map.height.times do |y|
      land_tiles.push([x, y]) if !is_water_tile?(x, y) && $game_map.passable?(x, y, 0)
    end
  end
 
  return land_tiles
end

# Helper function to play the Pokémon's cry
def play_pokemon_cry(pokemon, volume = 90)
  return if !pokemon
 
  if pokemon.is_a?(Pokemon)
    GameData::Species.play_cry_from_pokemon(pokemon, volume) if !pokemon.egg?
  else
    GameData::Species.play_cry_from_species(pokemon, 0, volume)
  end
end

class BoxRanch
  attr_reader :pokemon_events
  attr_accessor :pending_swap_data  # For deferred swap completion

  def initialize
    @pokemon_events = {}
    @pokemon_locations = {}
    @map_id = BoxRanchConfig::MAP_ID
    @water_tiles = []
    @land_tiles = []
    @is_setting_up = false
    @pending_swap_data = nil
  end

  def setup
    return if @is_setting_up || !$game_map
    return if $game_map.map_id != @map_id
    return unless $scene.is_a?(Scene_Map) || $scene.is_a?(Scene_DebugIntro)
   
    @is_setting_up = true
    echoln("BoxRanch: Starting setup on map #{@map_id}")
   
    begin
      setup_ranch_pokemon
    rescue => e
      echoln("BoxRanch Error during setup: #{e.message}")
      echoln(e.backtrace.join("\n"))
    ensure
      @is_setting_up = false
    end
  end

  def update
    # Check if we have a pending swap to complete
    complete_pending_swap if @pending_swap_data
  end

  private

  def setup_ranch_pokemon
    block_autosave(true)
   
    clear_ranch_pokemon
    scan_map_tiles
    load_pokemon_from_boxes
    create_all_events
    refresh_following_pokemon
   
    echoln("BoxRanch: Setup complete! Total events: #{@pokemon_events.size}")
   
    block_autosave(false)
  end

  def block_autosave(state)
    return unless $game_temp && $game_temp.respond_to?(:no_autosave=)
    $game_temp.no_autosave = state
  end

  def scan_map_tiles
    @water_tiles = find_water_tiles
    @land_tiles = find_land_tiles
    echoln("BoxRanch: Found #{@water_tiles.length} water tiles and #{@land_tiles.length} land tiles")
  end

  def load_pokemon_from_boxes
    @pokemon_locations.clear
    pokemon_list = []
   
    $PokemonStorage.maxBoxes.times do |i|
      $PokemonStorage.maxPokemon(i).times do |j|
        pkmn = $PokemonStorage[i, j]
        next unless pkmn
       
        pokemon_list.push(pkmn)
        @pokemon_locations[pkmn] = [i, j]
      end
    end
   
    echoln("BoxRanch: Found #{pokemon_list.length} Pokemon in boxes")
   
    # Create test Pokemon if needed
    pokemon_list = create_test_pokemon if pokemon_list.empty? && BoxRanchConfig::CREATE_TEST_POKEMON
   
    categorize_pokemon(pokemon_list)
  end

  def create_test_pokemon
    test_list = []
    test_list.push(Pokemon.new(BoxRanchConfig::TEST_LAND_SPECIES, BoxRanchConfig::TEST_LEVEL))
   
    if !@water_tiles.empty?
      test_list.push(Pokemon.new(BoxRanchConfig::TEST_WATER_SPECIES, BoxRanchConfig::TEST_LEVEL))
    end
   
    echoln("BoxRanch: Created #{test_list.length} test Pokemon")
    return test_list
  end

  def categorize_pokemon(pokemon_list)
    @water_pokemon = []
    @land_pokemon = []
   
    pokemon_list.each do |pkmn|
      if is_water_pokemon?(pkmn) && !@water_tiles.empty?
        @water_pokemon.push(pkmn)
      else
        @land_pokemon.push(pkmn)
      end
    end
   
    echoln("BoxRanch: #{@land_pokemon.length} land, #{@water_pokemon.length} water Pokemon")
  end

  def create_all_events
    max_land = [@land_pokemon.size, BoxRanchConfig::MAX_LAND_POKEMON].min
    @land_pokemon[0...max_land].each_with_index { |pkmn, i| create_pokemon_event(pkmn, i, false) }
   
    max_water = [@water_pokemon.size, BoxRanchConfig::MAX_WATER_POKEMON].min
    @water_pokemon[0...max_water].each_with_index { |pkmn, i| create_pokemon_event(pkmn, i, true) }
  end

  def create_pokemon_event(pkmn, index, in_water)
    x, y = get_spawn_position(index, in_water)
    event = build_event(pkmn, x, y, in_water)
    game_event = spawn_event(event, x, y)
   
    @pokemon_events[event.id] = pkmn
    echoln("BoxRanch: Created event #{event.id} for #{pkmn.name} at (#{x}, #{y})")
  end

  def get_spawn_position(index, in_water)
    tiles = in_water ? @water_tiles : @land_tiles
   
    if !tiles.empty?
      pos = tiles.sample
      tiles.delete(pos)
      return pos
    end
   
    # Fallback to grid positioning
    return calculate_grid_position(index)
  end

  def calculate_grid_position(index)
    area = { x_start: 30, y_start: 30, width: 15, height: 15, columns: 3, rows: 4 }
   
    column = index % area[:columns]
    row = (index / area[:columns]) % area[:rows]
   
    cell_width = area[:width] / area[:columns]
    cell_height = area[:height] / area[:rows]
   
    x = area[:x_start] + (column * cell_width) + rand(cell_width / 2)
    y = area[:y_start] + (row * cell_height) + rand(cell_height / 2)
   
    return [x, y]
  end

  def build_event(pkmn, x, y, in_water)
    event = RPG::Event.new(x, y)
    event.id = generate_event_id
    event.name = get_ranch_event_name(pkmn.species, in_water)
   
    setup_event_graphic(event, pkmn, in_water)
    setup_event_movement(event, pkmn, in_water)
    setup_event_commands(event, pkmn, in_water)
   
    return event
  end

  def generate_event_id
    existing_ids = $game_map.events.keys
    return existing_ids.empty? ? BoxRanchConstants::RANCH_EVENT_ID_START : [existing_ids.max + 1, BoxRanchConstants::RANCH_EVENT_ID_START].max
  end

  def setup_event_graphic(event, pkmn, in_water)
    levitates = is_levitating_pokemon?(pkmn)
    sprite_path = box_ranch_sprite_filename(pkmn.species, pkmn.form || 0, pkmn.gender, pkmn.shiny?, in_water, levitates)
   
    event.pages[0].graphic.character_name = sprite_path.gsub("Graphics/Characters/", "")
    event.pages[0].graphic.character_hue = 0
    event.pages[0].graphic.direction = 2
  end

  def setup_event_movement(event, pkmn, in_water)
    event.pages[0].through = false
    event.pages[0].always_on_top = false
    event.pages[0].step_anime = true
    event.pages[0].trigger = 0
    event.pages[0].move_type = 1
   
    # Nature-based movement
    nature_value = pkmn.nature.id.to_s.hash.abs
   
    if in_water
      speed_range = BoxRanchConfig::WATER_SPEED_MAX - BoxRanchConfig::WATER_SPEED_MIN + 1
      event.pages[0].move_speed = BoxRanchConfig::WATER_SPEED_MIN + (nature_value % speed_range)
    else
      speed_range = BoxRanchConfig::LAND_SPEED_MAX - BoxRanchConfig::LAND_SPEED_MIN + 1
      event.pages[0].move_speed = BoxRanchConfig::LAND_SPEED_MIN + (nature_value % speed_range)
    end
   
    freq_range = BoxRanchConfig::FREQUENCY_MAX - BoxRanchConfig::FREQUENCY_MIN + 1
    event.pages[0].move_frequency = BoxRanchConfig::FREQUENCY_MIN + (nature_value % freq_range)
   
    event.pages[0].move_route = RPG::MoveRoute.new
    event.pages[0].move_route.repeat = true
    event.pages[0].move_route.skippable = false
    event.pages[0].move_route.list = []
  end

  def setup_event_commands(event, pkmn, in_water)
    event.pages[0].list = []
   
    Compiler::push_script(event.pages[0].list, "play_pokemon_cry(:#{pkmn.species}, 100)")
    Compiler::push_script(event.pages[0].list, "pbMessage(\"#{pkmn.name} looks at you friendly!\")")
   
    if pkmn.shiny?
      Compiler::push_script(event.pages[0].list, "pbMessage(\"#{pkmn.name} shines conspicuously in the sunlight.\")")
    end
   
    nature_text = get_nature_text(pkmn.nature)
    Compiler::push_script(event.pages[0].list, "pbMessage(\"#{nature_text}\")")
   
    if in_water
      Compiler::push_script(event.pages[0].list, "pbMessage(\"It swims happily in the water!\")")
    elsif is_levitating_pokemon?(pkmn)
      Compiler::push_script(event.pages[0].list, "pbMessage(\"It floats elegantly in the air!\")")
    end
   
    Compiler::push_script(event.pages[0].list, "pbMessage(\"Level: #{pkmn.level}\\nAbility: #{pkmn.ability.name}\")")
    Compiler::push_script(event.pages[0].list, "show_pokemon_interaction_menu(:#{pkmn.species}, #{pkmn.level}, #{event.id})")
   
    Compiler::push_end(event.pages[0].list)
  end

  def spawn_event(event, x, y)
    game_event = Game_Event.new($game_map.map_id, event)
    game_event.moveto(x, y)
    game_event.refresh
    $game_map.events[event.id] = game_event
    return game_event
  end

  def get_nature_text(nature)
    nature_texts = {
      :JOLLY => "It dances around cheerfully.",
      :NAIVE => "It is very playful.",
      :HASTY => "It can't stand still and is constantly running around.",
      :CALM => "It rests peacefully.",
      :CAREFUL => "It attentively observes its surroundings.",
      :QUIET => "It enjoys the tranquility of the ranch.",
      :BRAVE => "It bravely shows itself off.",
      :ADAMANT => "It trains its muscles.",
      :NAUGHTY => "It seems to be up to something."
    }
   
    return nature_texts[nature.id] || "It feels very comfortable on the ranch."
  end

  public

  def clear_ranch_pokemon
    echoln("BoxRanch: Clearing #{@pokemon_events.size} ranch events")
   
    # Remove tracked events
    @pokemon_events.keys.each do |event_id|
      $game_map.events.delete(event_id) if $game_map.events[event_id]
    end
   
    @pokemon_events.clear
    @pokemon_locations.clear
    refresh_following_pokemon
  end

  def remove_pokemon_event(event_id)
    block_autosave(true)
   
    echoln("BoxRanch: Removing event #{event_id}")
   
    # Remove the event from the map
    $game_map.events.delete(event_id)
    @pokemon_events.delete(event_id)
   
    # SOLUTION ULTIME: Map transfer pour force un refresh complet
    force_map_reload
   
    block_autosave(false)
  end

  def force_map_reload
    echoln("BoxRanch: Forcing complete map reload to eliminate ghost sprites")
   
    # Sauvegarder la position actuelle
    current_map_id = $game_map.map_id
    current_x = $game_player.x
    current_y = $game_player.y
    current_direction = $game_player.direction
   
    echoln("BoxRanch: Player position: Map #{current_map_id}, (#{current_x}, #{current_y}), Dir #{current_direction}")
   
    # Sauvegarder l'état du Following Pokemon (uniquement si l'attribut existe)
    follower_toggled = nil
    if $PokemonGlobal && $PokemonGlobal.respond_to?(:follower_toggled)
      follower_toggled = $PokemonGlobal.follower_toggled
    end
   
    # Préparer le transfert vers la même position
    $game_temp.player_transferring = true
    $game_temp.player_new_map_id = current_map_id
    $game_temp.player_new_x = current_x
    $game_temp.player_new_y = current_y
    $game_temp.player_new_direction = current_direction
   
    # Effectuer le transfert immédiatement
    if $scene.is_a?(Scene_Map)
      $scene.transfer_player
     
      # Petit délai pour que le transfert soit complété
      Graphics.update
      Input.update
      pbUpdateSceneMap
    end
   
    # Restaurer l'état du Following Pokemon (uniquement si sauvegardé)
    if $PokemonGlobal && follower_toggled != nil && $PokemonGlobal.respond_to?(:follower_toggled=)
      $PokemonGlobal.follower_toggled = follower_toggled
    end
   
    # Rafraîchir le Following Pokemon
    if defined?(FollowingPkmn)
      FollowingPkmn.refresh(false)
    end
   
    echoln("BoxRanch: Map reload complete")
    pbWait(0.05)
  end

  def refresh_following_pokemon
    return unless defined?(FollowingPkmn)
    FollowingPkmn.refresh(false)
  end

  # Public method for creating event at specific position (used by swap)
  def create_pokemon_event_at(pkmn, x, y, in_water)
    event = build_event(pkmn, x, y, in_water)
    game_event = spawn_event(event, x, y)
    @pokemon_events[event.id] = pkmn
    echoln("BoxRanch: Created event #{event.id} for #{pkmn.name} at (#{x}, #{y})")
  end

  def get_pokemon_location(pokemon)
    @pokemon_locations[pokemon]
  end

  def set_pokemon_location(pokemon, box_index, slot_index)
    @pokemon_locations[pokemon] = [box_index, slot_index]
  end

  def remove_pokemon_location(pokemon)
    @pokemon_locations.delete(pokemon)
  end
 
  # Store swap data to be completed after event finishes
  def prepare_swap(party_pokemon, x, y, in_water)
    @pending_swap_data = {
      pokemon: party_pokemon,
      x: x,
      y: y,
      in_water: in_water
    }
    echoln("BoxRanch: Swap prepared for #{party_pokemon.name}, will complete after event")
  end
 
  def complete_pending_swap
    return unless @pending_swap_data
    return if $game_system.map_interpreter.running?  # Wait until event is done
   
    echoln("BoxRanch: Completing pending swap")
    data = @pending_swap_data
    @pending_swap_data = nil
   
    # Create the new event
    create_pokemon_event_at(data[:pokemon], data[:x], data[:y], data[:in_water])
   
    # Force a complete refresh
    force_map_reload
  end
end

#===============================================================================
# Interaction Functions
#===============================================================================

def show_pokemon_interaction_menu(species, level, event_id = nil)
  return unless event_id && $box_ranch && $box_ranch.pokemon_events[event_id]
 
  commands = [_INTL("Pet"), _INTL("Feed"), _INTL("Play")]
 
  if $player && $player.party
    party_size = $player.party.length
    if party_size < Settings::MAX_PARTY_SIZE
      commands.push(_INTL("Take to team"))
      commands.push(_INTL("Swap with team")) if party_size > 0
    else
      commands.push(_INTL("Swap with team"))
    end
  end
 
  commands.push(_INTL("Back"))
 
  choice = pbMessage(_INTL("What would you like to do?"), commands, commands.length)
 
  case choice
  when 0  # Pet
    pbMessage(_INTL("You gently pet the Pokémon. It seems to enjoy that!"))
    play_pokemon_cry(species, 70)
  when 1  # Feed
    pbMessage(_INTL("You give the Pokémon some food. It eats happily!"))
  when 2  # Play
    pbMessage(_INTL("You play with the Pokémon for a while. It has fun!"))
    play_pokemon_cry(species, 100)
  else
    action = commands[choice]
    take_to_party(event_id) if action == _INTL("Take to team")
    swap_with_party_pokemon(event_id) if action == _INTL("Swap with team")
  end
end

def take_to_party(event_id)
  return unless $box_ranch && $box_ranch.pokemon_events[event_id] && $player
 
  ranch_pokemon = $box_ranch.pokemon_events[event_id]
 
  if $player.party.length >= Settings::MAX_PARTY_SIZE
    pbMessage(_INTL("Your team is full. You can't take more Pokémon."))
    return
  end
 
  msg = _INTL("Do you want to take {1} (Lv. {2}) to your team?", ranch_pokemon.name, ranch_pokemon.level)
  return unless pbConfirmMessage(msg)
 
  # Add to party
  $player.party.push(ranch_pokemon)
 
  # Remove from box if it came from there
  ranch_box_location = $box_ranch.get_pokemon_location(ranch_pokemon)
  if ranch_box_location
    box_index, slot_index = ranch_box_location
    $PokemonStorage[box_index, slot_index] = nil
    $box_ranch.remove_pokemon_location(ranch_pokemon)
  end
 
  # Remove event (uses force_map_reload internally - this works fine)
  $box_ranch.remove_pokemon_event(event_id)
 
  pbMessage(_INTL("{1} joined your team!", ranch_pokemon.name))
end

def swap_with_party_pokemon(event_id)
  return unless $box_ranch && $box_ranch.pokemon_events[event_id] && $player
  return if !$player.party || $player.party.empty?
 
  ranch_pokemon = $box_ranch.pokemon_events[event_id]
 
  pbMessage(_INTL("Choose a Pokémon from your team to swap with."))
 
  pbChoosePokemon(1, 2)
  chosen_index = $game_variables[1]
 
  if chosen_index < 0 || chosen_index >= $player.party.length
    pbMessage(_INTL("Swap cancelled."))
    return
  end
 
  party_pokemon = $player.party[chosen_index]
  msg = _INTL("Do you want to swap {1} (Lv. {2}) with {3} (Lv. {4})?",
    ranch_pokemon.name, ranch_pokemon.level, party_pokemon.name, party_pokemon.level)
 
  return unless pbConfirmMessage(msg)
 
  # Save event position
  event = $game_map.events[event_id]
  x, y = event.x, event.y
  in_water = event.name.include?("InWater")
 
  # Get box location
  ranch_box_location = $box_ranch.get_pokemon_location(ranch_pokemon)
 
  # Perform swap in data
  $player.party[chosen_index] = ranch_pokemon
 
  if ranch_box_location
    box_index, slot_index = ranch_box_location
    $PokemonStorage[box_index, slot_index] = party_pokemon
    $box_ranch.set_pokemon_location(party_pokemon, box_index, slot_index)
    $box_ranch.remove_pokemon_location(ranch_pokemon)
  end
 
  # Remove the old event (without map reload)
  $game_map.events.delete(event_id)
  $box_ranch.pokemon_events.delete(event_id)
 
  # Show success message FIRST
  pbMessage(_INTL("Swap successful! {1} is now in your team, and {2} is on the Ranch.",
    ranch_pokemon.name, party_pokemon.name))
 
  # AFTER the message, prepare the swap to be completed
  $box_ranch.prepare_swap(party_pokemon, x, y, in_water)
end

#===============================================================================
# Event Handlers
#===============================================================================

# Initialize BoxRanch singleton
EventHandlers.add(:on_game_start, :init_box_ranch, proc {
  $box_ranch = BoxRanch.new
})

EventHandlers.add(:on_game_load, :reload_box_ranch, proc {
  $box_ranch = BoxRanch.new
 
  if $game_map && $game_map.map_id == BoxRanchConfig::MAP_ID
    $game_map.need_refresh = true
    pbWait(0.05)
    $box_ranch.setup
  end
})

EventHandlers.add(:on_map_change, :setup_box_ranch, proc { |_old_map_id|
  $box_ranch ||= BoxRanch.new
  $box_ranch.setup
})

EventHandlers.add(:on_box_change, :sync_box_ranch, proc { |_old_box|
  if $box_ranch && $game_map && $game_map.map_id == BoxRanchConfig::MAP_ID
    $box_ranch.setup
  end
})

#===============================================================================
# Game_Map integration
#===============================================================================

class Game_Map
  alias box_ranch_setup setup
  def setup(map_id)
    box_ranch_setup(map_id)
    $box_ranch ||= BoxRanch.new
    $box_ranch.setup if map_id == BoxRanchConfig::MAP_ID
  end
end

#===============================================================================
# Scene_Map integration
#===============================================================================

class Scene_Map
  alias box_ranch_update update
  def update
    box_ranch_update
    $box_ranch.update if $box_ranch
  end
end
Thanks, this works
Although when you use PC in the ranch it doesnt update the pokemon so you can take the mon out from pc and then go talk to it and get a duplicate :p
 
im actually new to this i started making my own game using pokemon essentials 2 days ago i really want to use this and i made a amazing map for this but i cant seem to get it to work any advice? i believe its all setup right but no pokemon are actually spawning?
 
im actually new to this i started making my own game using pokemon essentials 2 days ago i really want to use this and i made a amazing map for this but i cant seem to get it to work any advice? i believe its all setup right but no pokemon are actually spawning?
Because the Plugin is bugged at the moment, but an update is coming soon to fix it
 
Back
Top