class Oakdex::Battle::ValidActionService

Generates all valid actions within the battle

Public Class Methods

new(battle) click to toggle source
# File lib/oakdex/battle/valid_action_service.rb, line 11
def initialize(battle)
  @battle = battle
end

Public Instance Methods

valid_actions_for(trainer) click to toggle source
# File lib/oakdex/battle/valid_action_service.rb, line 15
def valid_actions_for(trainer)
  return [] if no_actions_for?(trainer)
  growth_events = growth_event_actions(trainer)
  return growth_events unless growth_events.empty?
  valid_move_actions_for(trainer) +
    valid_recall_actions_for(trainer) +
    valid_item_actions_for(trainer)
end

Private Instance Methods

actions_for_trainer(trainer) click to toggle source
# File lib/oakdex/battle/valid_action_service.rb, line 26
def actions_for_trainer(trainer)
  actions.select { |a| a.trainer == trainer }
end
added_growth_action_already?(trainer) click to toggle source
# File lib/oakdex/battle/valid_action_service.rb, line 38
def added_growth_action_already?(trainer)
  growth_events = growth_event_actions(trainer)

  !growth_events.empty? && !actions_for_trainer(trainer).empty?
end
growth_event_actions(trainer) click to toggle source
# File lib/oakdex/battle/valid_action_service.rb, line 44
def growth_event_actions(trainer)
  while trainer.growth_event? && trainer.growth_event.read_only?
    @battle.add_to_log(trainer.growth_event.message)
    trainer.growth_event.execute
  end

  if trainer.growth_event?
    trainer.growth_event.possible_actions.map do |option|
      {
        'action' => 'growth_event',
        'option' => option
      }
    end
  else
    []
  end
end
no_actions_for?(trainer) click to toggle source
# File lib/oakdex/battle/valid_action_service.rb, line 30
def no_actions_for?(trainer)
  growth_events = growth_event_actions(trainer)
  sides.empty? ||
    (no_battle_pokemon?(trainer) && growth_events.empty?) ||
    (other_is_growing?(trainer) && growth_events.empty?) ||
    added_growth_action_already?(trainer)
end
no_battle_pokemon?(trainer) click to toggle source
# File lib/oakdex/battle/valid_action_service.rb, line 152
def no_battle_pokemon?(trainer)
  other_sides(trainer).all? { |s| s.active_in_battle_pokemon.empty? } &&
    own_battle_pokemon?(trainer)
end
other_is_growing?(trainer) click to toggle source
# File lib/oakdex/battle/valid_action_service.rb, line 62
def other_is_growing?(trainer)
  other_trainers = sides.flat_map(&:trainers) - [trainer]
  other_trainers.any? do |t|
    t.growth_event? && !t.growth_event.read_only?
  end
end
other_sides(trainer) click to toggle source
# File lib/oakdex/battle/valid_action_service.rb, line 161
def other_sides(trainer)
  sides.select { |s| !s.trainer_on_side?(trainer) }
end
own_battle_pokemon?(trainer) click to toggle source
# File lib/oakdex/battle/valid_action_service.rb, line 157
def own_battle_pokemon?(trainer)
  !side(trainer).active_in_battle_pokemon.empty?
end
pokemon_per_trainer() click to toggle source
# File lib/oakdex/battle/valid_action_service.rb, line 136
def pokemon_per_trainer
  sides.first.trainers.size
end
possible_item_actions(battle_pokemon, item_id, prevActions = []) click to toggle source
# File lib/oakdex/battle/valid_action_service.rb, line 91
def possible_item_actions(battle_pokemon, item_id, prevActions = [])
  dup_pokemon = battle_pokemon.pokemon.dup
  dup_pokemon.use_item(item_id, in_battle: true)
  e = dup_pokemon.growth_event
  return [[]] if !e || e.read_only?
  prevActions.each do |a|
    e.execute(a)
    e = dup_pokemon.growth_event
  end
  return [prevActions] if e.read_only?
  e.possible_actions.flat_map do |a|
    r = possible_item_actions(battle_pokemon, item_id, prevActions + [a])
    r
  end
end
recall_action(trainer, active_ibp, target) click to toggle source
# File lib/oakdex/battle/valid_action_service.rb, line 117
def recall_action(trainer, active_ibp, target)
  return if !recall_action_valid?(trainer, active_ibp, target) ||
            recall_action_for?(target)
  {
    'action' => 'recall',
    'pokemon' => active_ibp&.position || side(trainer).next_position,
    'target' => target.id
  }
end
recall_action_for?(target) click to toggle source
# File lib/oakdex/battle/valid_action_service.rb, line 140
def recall_action_for?(target)
  actions.any? do |action|
    action.type == 'recall' && action.target_id == target.id
  end
end
recall_action_for_position?(position) click to toggle source
# File lib/oakdex/battle/valid_action_service.rb, line 146
def recall_action_for_position?(position)
  actions.any? do |action|
    action.type == 'recall' && action.pokemon_position == position
  end
end
recall_action_valid?(trainer, active_in_battle_pokemon, _target) click to toggle source
# File lib/oakdex/battle/valid_action_service.rb, line 127
def recall_action_valid?(trainer, active_in_battle_pokemon, _target)
  if active_in_battle_pokemon
    !active_in_battle_pokemon.action_added?
  else
    next_position = side(trainer).next_position
    next_position && !recall_action_for_position?(next_position)
  end
end
side(trainer) click to toggle source
# File lib/oakdex/battle/valid_action_service.rb, line 165
def side(trainer)
  sides.find { |s| s.trainer_on_side?(trainer) }
end
valid_item_actions_for(trainer) click to toggle source
# File lib/oakdex/battle/valid_action_service.rb, line 73
def valid_item_actions_for(trainer)
  return [] if actions.select { |a| a.trainer == trainer }.size >= pokemon_per_trainer
  trainer.items.flat_map do |item_id|
    trainer.team.flat_map.with_index do |pokemon, i|
      next if actions.any? { |a| a.item_id == item_id }
      next unless pokemon.usable_item?(item_id, in_battle: true)
      possible_item_actions(pokemon, item_id).map do |item_actions|
        {
          'action' => 'use_item_on_pokemon',
          'pokemon_team_pos' => i,
          'item_id' => item_id,
          'item_actions' => item_actions
        }
      end
    end.compact
  end - actions
end
valid_move_actions_for(trainer) click to toggle source
# File lib/oakdex/battle/valid_action_service.rb, line 69
def valid_move_actions_for(trainer)
  trainer.active_in_battle_pokemon.flat_map(&:valid_move_actions)
end
valid_recall_actions_for(trainer) click to toggle source
# File lib/oakdex/battle/valid_action_service.rb, line 107
def valid_recall_actions_for(trainer)
  trainer.left_pokemon_in_team.flat_map do |pokemon|
    pokemon_per_trainer.times.map do |position|
      recall_action(trainer,
                    trainer.active_in_battle_pokemon[position],
                    pokemon)
    end.compact
  end
end