Nuevos Métodos de Encuentro

Pokémon Essentials incluye un conjunto de métodos de encuentro predefinidos: Land (Hierba), Cave (Cueva), Water (Surf), OldRod, GoodRod, SuperRod, RockSmash, HeadbuttLow y HeadbuttHigh, entre otros. Sin embargo, es posible que tu proyecto necesite métodos de encuentro personalizados que no existen en el sistema base.

Este artículo explica la arquitectura del sistema de tipos de encuentro, cómo crear nuevos tipos personalizados, cómo registrarlos en el motor y cómo definir encuentros para ellos en los archivos PBS.

Entendiendo el Sistema de Encuentros

El sistema de encuentros salvajes en Pokémon Essentials se compone de varios elementos interconectados:

Estructura de GameData::EncounterType

Cada tipo de encuentro se registra en GameData::EncounterType y contiene las siguientes propiedades:

Propiedad Tipo Descripción
id Symbol Identificador interno único del tipo de encuentro.
real_name String Nombre visible para las herramientas y depuración.
type Symbol Categoría general (:land, :water, :fishing, :contest, etc.).
trigger_chance Integer Probabilidad base de activar un encuentro por paso (ej: 21 para hierba).
old_slots Array Distribución de probabilidades para cada slot de la tabla de encuentros.

Tipos de Encuentro Predefinidos

Los tipos de encuentro estándar en Pokémon Essentials son:

ID Nombre Categoría Descripción
Land Hierba :land Encuentros caminando por hierba alta.
LandDay Hierba (Día) :land Encuentros en hierba durante el día.
LandNight Hierba (Noche) :land Encuentros en hierba durante la noche.
LandMorning Hierba (Mañana) :land Encuentros en hierba por la mañana.
Cave Cueva :cave Encuentros caminando dentro de cuevas.
Water Surf :water Encuentros surfeando en agua.
OldRod Caña Vieja :fishing Pesca con Caña Vieja.
GoodRod Caña Buena :fishing Pesca con Caña Buena.
SuperRod Supercaña :fishing Pesca con Supercaña.
RockSmash Golpe Roca :none Encuentros al romper rocas.
HeadbuttLow Cabezazo (Bajo) :none Encuentros al golpear árboles (frecuentes).
HeadbuttHigh Cabezazo (Alto) :none Encuentros al golpear árboles (raros).
BugContest Concurso de Insectos :contest Encuentros durante el concurso de insectos.

Crear un Nuevo Tipo de Encuentro

Veamos paso a paso cómo crear un nuevo tipo de encuentro personalizado. Como ejemplo, crearemos un tipo "Excavación" (_Digging_) que permite encontrar Pokémon bajo tierra al usar una pala.

Paso 1: Registrar el tipo en GameData::EncounterType

En tu archivo de scripts personalizado (en la sección de Plugins o antes de Main), registra el nuevo tipo de encuentro:

# Registrar nuevo tipo de encuentro: Excavación (Digging)
GameData::EncounterType.register({
  :id             => :Digging,
  :real_name      => "Excavación",
  :type           => :none,        # Categoría personalizada
  :trigger_chance => 0,            # 0 porque se activa manualmente, no al caminar
  :old_slots      => [30, 25, 20, 15, 10]  # 5 slots con distribución personalizada
})

Desglose de los parámetros:

Paso 2: Definir encuentros en PBS

Una vez registrado el tipo, puedes usarlo en PBS/encounters.txt para definir qué Pokémon aparecen al usar este método en cada mapa:

# PBS/encounters.txt — Mapa 035 (Cueva Minera)

[035]
Cave,10
  ZUBAT,15,20
  GEODUDE,15,20
  ONIX,18,22
Digging,0
  DIGLETT,10,18
  DUGTRIO,20,25
  ONIX,15,22
  SANDSHREW,12,18
  TRAPINCH,15,20

El tipo Digging aparece como una sección más de encuentros para el mapa 035. Como trigger_chance es 0, estos encuentros no ocurren al caminar; debes activarlos manualmente.

Paso 3: Crear el disparador del encuentro

Ahora necesitas crear el código que activa el encuentro cuando el jugador realiza la acción correspondiente. En nuestro ejemplo, esto sería usar una pala:

# Definir el objeto "Pala" con uso en el campo
# En PBS/items.txt:
# [SHOVEL]
# Name = Pala
# NamePlural = Palas
# Pocket = 8
# Price = 0
# FieldUse = Direct
# Flags = KeyItem
# Description = Una pala resistente. Permite excavar en suelos blandos.

# Handler para usar la Pala en el campo
ItemHandlers::UseFromBag.add(:SHOVEL, proc { |item|
  # Verificar que el tile actual permite excavación
  terrain = $game_map.terrain_tag($game_player.x, $game_player.y)
  if terrain == :Diggable  # Terrain tag personalizado para suelo excavable
    next 2  # 2 = usar objeto y cerrar mochila
  else
    pbMessage("No puedes excavar aquí.")
    next 0  # 0 = no usar
  end
})

ItemHandlers::UseInField.add(:SHOVEL, proc { |item|
  terrain = $game_map.terrain_tag($game_player.x, $game_player.y)
  if terrain != :Diggable
    pbMessage("El suelo aquí es demasiado duro para excavar.")
    next false
  end

  pbMessage("Has empezado a excavar...")
  pbWait(40)

  # Intentar generar un encuentro del tipo Digging
  encounter = $PokemonEncounters.choose_wild_pokemon(:Digging)
  if encounter
    species, level = encounter
    pbMessage("¡Has encontrado un Pokémon bajo tierra!")
    pbWildBattle(species, level)
  else
    # Si no hay encuentro, encontrar un objeto aleatorio
    pbMessage("No has encontrado ningún Pokémon, pero...")
    items = [:NUGGET, :STARDUST, :REVIVE, :RARECANDY, :HARDSTONE]
    found_item = items.sample
    pbReceiveItem(found_item)
  end
  next true
})

Paso 4: Crear el terrain tag personalizado (opcional)

Si tu método de encuentro depende de un terrain tag específico (como "suelo excavable"), debes registrarlo:

# En PBS/terrain_tags.txt, añade:
# [Diggable]
# ID = 13
# CanEncounter = false

# O regístralo por código:
GameData::TerrainTag.register({
  :id   => :Diggable,
  :id_number => 13
})

Ejemplo Completo: Encuentros Nocturnos Especiales

Veamos otro ejemplo: un tipo de encuentro que solo se activa durante la noche en zonas boscosas, simulando Pokémon nocturnos que salen de sus escondites.

Registro del tipo

GameData::EncounterType.register({
  :id             => :NightForest,
  :real_name      => "Bosque Nocturno",
  :type           => :land,
  :trigger_chance => 15,     # Probabilidad base de encuentro al caminar
  :old_slots      => [20, 20, 15, 15, 10, 10, 5, 5]  # 8 slots
})

Disparador automático

Como este tipo tiene :type => :land y un trigger_chance mayor que 0, necesitamos modificar el sistema de encuentros para que lo use en las condiciones correctas:

# Sobrescribir el método que elige el tipo de encuentro al caminar
module EncounterModifier
  class << self
    alias_method :original_encounter_type, :encounter_type
  end

  def self.encounter_type
    # Si es de noche y estamos en un mapa con NightForest definido
    if PBDayNight.isNight? && $PokemonEncounters.has_encounter_type?(:NightForest)
      return :NightForest
    end
    # Si no, usar el tipo de encuentro original
    return original_encounter_type
  end
end

PBS

# PBS/encounters.txt — Mapa 022 (Bosque Misterioso)
[022]
Land,21
  CATERPIE,6,8
  WEEDLE,6,8
  PIKACHU,8,10
  ODDISH,8,10
NightForest,15
  HOOTHOOT,8,12
  SPINARAK,8,10
  MURKROW,10,14
  MISDREAVUS,10,14
  SHUPPET,12,15
  DUSKULL,12,15
  HOUNDOUR,10,14
  ABSOL,15,18

Ejemplo: Encuentros por Enjambre

Los enjambres (swarms) son otro tipo de encuentro personalizable. Aquí tienes una implementación simplificada:

GameData::EncounterType.register({
  :id             => :Swarm,
  :real_name      => "Enjambre",
  :type           => :land,
  :trigger_chance => 40,     # Alta probabilidad de encuentro durante enjambres
  :old_slots      => [50, 30, 20]  # 3 slots, el enjambre domina
})

# Activar un enjambre en un mapa
def pbStartSwarm(map_id, species, duration_hours = 24)
  $PokemonGlobal.swarm = {
    map_id:   map_id,
    species:  species,
    end_time: pbGetTimeNow + (duration_hours * 3600)
  }
  pbMessage("¡Se ha reportado un enjambre de #{GameData::Species.get(species).name}!")
end

# Detener el enjambre actual
def pbStopSwarm
  $PokemonGlobal.swarm = nil
end

# Verificar si hay enjambre activo en el mapa actual
def pbSwarmActive?
  swarm = $PokemonGlobal.swarm
  return false if !swarm
  return false if swarm[:map_id] != $game_map.map_id
  return false if pbGetTimeNow > swarm[:end_time]
  return true
end

Registrar Tipos con Variaciones Horarias

Si quieres que tu tipo de encuentro tenga variaciones según la hora del día (como Land tiene LandDay, LandNight, LandMorning), puedes registrar múltiples tipos relacionados:

# Tipo base y variaciones horarias
GameData::EncounterType.register({
  :id => :Desert, :real_name => "Desierto",
  :type => :land, :trigger_chance => 18,
  :old_slots => [25, 20, 20, 15, 10, 10]
})
GameData::EncounterType.register({
  :id => :DesertDay, :real_name => "Desierto (Día)",
  :type => :land, :trigger_chance => 18,
  :old_slots => [25, 20, 20, 15, 10, 10]
})
GameData::EncounterType.register({
  :id => :DesertNight, :real_name => "Desierto (Noche)",
  :type => :land, :trigger_chance => 12,  # Menos encuentros de noche
  :old_slots => [25, 20, 20, 15, 10, 10]
})

# En PBS/encounters.txt:
# [050]  # Mapa: Gran Desierto
# Desert,18
#   SANDSHREW,20,25
#   TRAPINCH,20,25
#   CACNEA,22,28
#   BALTOY,22,26
#   SANDILE,20,25
#   HIPPOPOTAS,24,28
# DesertNight,12
#   SANDSHREW,20,25
#   TRAPINCH,20,25
#   SKORUPI,22,28
#   SANDILE,22,26
#   KROKOROK,26,30
#   KROOKODILE,30,35

Probar Tus Nuevos Tipos de Encuentro

Después de crear un nuevo tipo de encuentro, es importante probarlo exhaustivamente:

  1. Compilar los PBS: Ejecuta el juego en modo debug y deja que compile los archivos PBS. Si hay errores en el formato de encounters.txt, aparecerán aquí.
  2. Verificar el registro: En la consola de debug, comprueba que el tipo existe:
    # En la consola de debug (F9)
    p GameData::EncounterType.exists?(:Digging)  # Debería imprimir true
  3. Probar en el mapa: Ve al mapa donde definiste los encuentros y activa el método correspondiente.
  4. Verificar distribución: Usa el modo debug para verificar que la distribución de especies es la esperada.

Compatibilidad y Buenas Prácticas

Resolución de Problemas

Error al compilar PBS: tipo de encuentro desconocido

Los encuentros no se activan

Distribución de Pokémon incorrecta