mirror of
https://github.com/infinitefusion/infinitefusion-e18.git
synced 2025-12-07 21:24:59 +00:00
Added Marin's AI as a reference
This commit is contained in:
1316
AI references/Marin's AI/AI_BattlerProjection.rb
Normal file
1316
AI references/Marin's AI/AI_BattlerProjection.rb
Normal file
File diff suppressed because it is too large
Load Diff
209
AI references/Marin's AI/AI_Compatibility.rb
Normal file
209
AI references/Marin's AI/AI_Compatibility.rb
Normal file
@@ -0,0 +1,209 @@
|
||||
class PokeBattle_Battle
|
||||
attr_reader :battleAI
|
||||
|
||||
alias mkai_initialize initialize
|
||||
def initialize(*args)
|
||||
mkai_initialize(*args)
|
||||
@battleAI = MKAI.new(self, self.wildBattle?)
|
||||
@battleAI.sides[0].set_party(@party1)
|
||||
@battleAI.sides[0].set_trainers(@player)
|
||||
@battleAI.sides[1].set_party(@party2)
|
||||
@battleAI.sides[1].set_trainers(@opponent)
|
||||
end
|
||||
|
||||
def pbRecallAndReplace(idxBattler, idxParty, batonPass = false)
|
||||
if !@battlers[idxBattler].fainted?
|
||||
@scene.pbRecall(idxBattler)
|
||||
@battleAI.sides[idxBattler % 2].recall(idxBattler)
|
||||
end
|
||||
@battlers[idxBattler].pbAbilitiesOnSwitchOut # Inc. primordial weather check
|
||||
@scene.pbShowPartyLineup(idxBattler & 1) if pbSideSize(idxBattler) == 1
|
||||
pbMessagesOnReplace(idxBattler, idxParty)
|
||||
pbReplace(idxBattler, idxParty, batonPass)
|
||||
end
|
||||
|
||||
# Bug fix (used b instead of battler)
|
||||
def pbMessageOnRecall(battler)
|
||||
if battler.pbOwnedByPlayer?
|
||||
if battler.hp<=battler.totalhp/4
|
||||
pbDisplayBrief(_INTL("Good job, {1}! Come back!",battler.name))
|
||||
elsif battler.hp<=battler.totalhp/2
|
||||
pbDisplayBrief(_INTL("OK, {1}! Come back!",battler.name))
|
||||
elsif battler.turnCount>=5
|
||||
pbDisplayBrief(_INTL("{1}, that’s enough! Come back!",battler.name))
|
||||
elsif battler.turnCount>=2
|
||||
pbDisplayBrief(_INTL("{1}, come back!",battler.name))
|
||||
else
|
||||
pbDisplayBrief(_INTL("{1}, switch out! Come back!",battler.name))
|
||||
end
|
||||
else
|
||||
owner = pbGetOwnerName(battler.index)
|
||||
pbDisplayBrief(_INTL("{1} withdrew {2}!",owner,battler.name))
|
||||
end
|
||||
end
|
||||
|
||||
alias mkai_pbEndOfRoundPhase pbEndOfRoundPhase
|
||||
def pbEndOfRoundPhase
|
||||
mkai_pbEndOfRoundPhase
|
||||
@battleAI.end_of_round
|
||||
end
|
||||
|
||||
alias mkai_pbShowAbilitySplash pbShowAbilitySplash
|
||||
def pbShowAbilitySplash(battler, delay = false, logTrigger = true)
|
||||
mkai_pbShowAbilitySplash(battler, delay, logTrigger)
|
||||
@battleAI.reveal_ability(battler)
|
||||
end
|
||||
end
|
||||
|
||||
class PokeBattle_Move
|
||||
attr_reader :statUp
|
||||
attr_reader :statDown
|
||||
|
||||
alias mkai_pbReduceDamage pbReduceDamage
|
||||
def pbReduceDamage(user, target)
|
||||
mkai_pbReduceDamage(user, target)
|
||||
@battle.battleAI.register_damage(self, user, target, target.damageState.hpLost)
|
||||
end
|
||||
|
||||
def pbCouldBeCritical?(user, target)
|
||||
return false if target.pbOwnSide.effects[PBEffects::LuckyChant] > 0
|
||||
# Set up the critical hit ratios
|
||||
ratios = (NEWEST_BATTLE_MECHANICS) ? [24,8,2,1] : [16,8,4,3,2]
|
||||
c = 0
|
||||
# Ability effects that alter critical hit rate
|
||||
if c >= 0 && user.abilityActive?
|
||||
c = BattleHandlers.triggerCriticalCalcUserAbility(user.ability, user, target, c)
|
||||
end
|
||||
if c >= 0 && target.abilityActive? && !@battle.moldBreaker
|
||||
c = BattleHandlers.triggerCriticalCalcTargetAbility(target.ability, user, target, c)
|
||||
end
|
||||
# Item effects that alter critical hit rate
|
||||
if c >= 0 && user.itemActive?
|
||||
c = BattleHandlers.triggerCriticalCalcUserItem(user.item, user, target, c)
|
||||
end
|
||||
if c >= 0 && target.itemActive?
|
||||
c = BattleHandlers.triggerCriticalCalcTargetItem(target.item, user, target, c)
|
||||
end
|
||||
return false if c < 0
|
||||
# Move-specific "always/never a critical hit" effects
|
||||
return false if pbCritialOverride(user,target) == -1
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
class MKAI
|
||||
def pbAIRandom(x)
|
||||
return rand(x)
|
||||
end
|
||||
|
||||
def pbDefaultChooseEnemyCommand(idxBattler)
|
||||
sideIndex = idxBattler % 2
|
||||
index = MKAI.battler_to_proj_index(idxBattler)
|
||||
side = @sides[sideIndex]
|
||||
projection = side.battlers[index]
|
||||
# Choose move
|
||||
data = projection.choose_move
|
||||
if data.nil?
|
||||
# Struggle
|
||||
@battle.pbAutoChooseMove(idxBattler)
|
||||
elsif data[0] == :ITEM
|
||||
# [:ITEM, item_id, target&]
|
||||
item = data[1]
|
||||
# Determine target of item (always the Pokémon choosing the action)
|
||||
useType = pbGetItemData(item, ITEM_BATTLE_USE)
|
||||
if data[2]
|
||||
target_index = data[2]
|
||||
else
|
||||
target_index = idxBattler
|
||||
if useType && (useType == 1 || useType == 6) # Use on Pokémon
|
||||
target_index = @battle.battlers[target_index].pokemonIndex # Party Pokémon
|
||||
end
|
||||
end
|
||||
# Register our item
|
||||
@battle.pbRegisterItem(idxBattler, item, target_index)
|
||||
elsif data[0] == :SWITCH
|
||||
# [:SWITCH, pokemon_index]
|
||||
@battle.pbRegisterSwitch(idxBattler, data[1])
|
||||
else
|
||||
# [move_index, move_target]
|
||||
move_index, move_target = data
|
||||
# Mega evolve if we determine that we should
|
||||
@battle.pbRegisterMegaEvolution(idxBattler) if projection.should_mega_evolve?(idxBattler)
|
||||
# Register our move
|
||||
@battle.pbRegisterMove(idxBattler, move_index, false)
|
||||
# Register the move's target
|
||||
@battle.pbRegisterTarget(idxBattler, move_target)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
#=============================================================================
|
||||
# Choose a replacement Pokémon
|
||||
#=============================================================================
|
||||
def pbDefaultChooseNewEnemy(idxBattler, party)
|
||||
proj = self.battler_to_projection(@battle.battlers[idxBattler])
|
||||
scores = proj.get_optimal_switch_choice
|
||||
scores.each do |_, _, proj|
|
||||
pkmn = proj.pokemon
|
||||
index = @battle.pbParty(idxBattler).index(pkmn)
|
||||
if @battle.pbCanSwitchLax?(idxBattler, index)
|
||||
return index
|
||||
end
|
||||
end
|
||||
return -1
|
||||
end
|
||||
end
|
||||
|
||||
class PokeBattle_Battler
|
||||
alias mkai_pbInitialize pbInitialize
|
||||
def pbInitialize(pkmn, idxParty, batonPass = false)
|
||||
mkai_pbInitialize(pkmn, idxParty, batonPass)
|
||||
ai = @battle.battleAI
|
||||
sideIndex = @index % 2
|
||||
ai.sides[sideIndex].send_out(@index, self)
|
||||
end
|
||||
|
||||
alias mkai_pbFaint pbFaint
|
||||
def pbFaint(*args)
|
||||
mkai_pbFaint(*args)
|
||||
@battle.battleAI.faint_battler(self)
|
||||
end
|
||||
end
|
||||
|
||||
class PokeBattle_PoisonMove
|
||||
attr_reader :toxic
|
||||
end
|
||||
|
||||
class Array
|
||||
def sum
|
||||
n = 0
|
||||
self.each { |e| n += e }
|
||||
n
|
||||
end
|
||||
end
|
||||
|
||||
# Overwrite Frisk to show the enemy held item
|
||||
BattleHandlers::AbilityOnSwitchIn.add(:FRISK,
|
||||
proc { |ability,battler,battle|
|
||||
foes = []
|
||||
battle.eachOtherSideBattler(battler.index) do |b|
|
||||
foes.push(b) if b.item > 0
|
||||
end
|
||||
if foes.length > 0
|
||||
battle.pbShowAbilitySplash(battler)
|
||||
if NEWEST_BATTLE_MECHANICS
|
||||
foes.each do |b|
|
||||
battle.pbDisplay(_INTL("{1} frisked {2} and found its {3}!",
|
||||
battler.pbThis, b.pbThis(true), PBItems.getName(b.item)))
|
||||
battle.battleAI.reveal_item(b)
|
||||
end
|
||||
else
|
||||
foe = foes[battle.pbRandom(foes.length)]
|
||||
battle.pbDisplay(_INTL("{1} frisked the foe and found one {2}!",
|
||||
battler.pbThis, PBItems.getName(foe.item)))
|
||||
battle.battleAI.reveal_item(foe)
|
||||
end
|
||||
battle.pbHideAbilitySplash(battler)
|
||||
end
|
||||
}
|
||||
)
|
||||
133
AI references/Marin's AI/AI_Main.rb
Normal file
133
AI references/Marin's AI/AI_Main.rb
Normal file
@@ -0,0 +1,133 @@
|
||||
class MKAI
|
||||
attr_reader :battle
|
||||
attr_reader :sides
|
||||
|
||||
def initialize(battle, wild_battle)
|
||||
@battle = battle
|
||||
@sides = [Side.new(self, 0), Side.new(self, 1, wild_battle)]
|
||||
MKAI.log("AI initialized")
|
||||
end
|
||||
|
||||
def self.battler_to_proj_index(battlerIndex)
|
||||
if battlerIndex % 2 == 0 # Player side: 0, 2, 4 -> 0, 1, 2
|
||||
return battlerIndex / 2
|
||||
else # Opponent side: 1, 3, 5 -> 0, 1, 2
|
||||
return (battlerIndex - 1) / 2
|
||||
end
|
||||
end
|
||||
|
||||
def self.weighted_rand(weights)
|
||||
num = rand(weights.sum)
|
||||
for i in 0...weights.size
|
||||
if num < weights[i]
|
||||
return i
|
||||
else
|
||||
num -= weights[i]
|
||||
end
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
def self.get_weights(factor, weights)
|
||||
avg = weights.sum / weights.size.to_f
|
||||
newweights = weights.map do |e|
|
||||
diff = e - avg
|
||||
next [0, ((e - diff * factor) * 100).round].max
|
||||
end
|
||||
return newweights
|
||||
end
|
||||
|
||||
def self.weighted_factored_rand(factor, weights)
|
||||
avg = weights.sum / weights.size.to_f
|
||||
newweights = weights.map do |e|
|
||||
diff = e - avg
|
||||
next [0, ((e - diff * factor) * 100).round].max
|
||||
end
|
||||
return weighted_rand(newweights)
|
||||
end
|
||||
|
||||
def self.log(msg)
|
||||
echoln msg
|
||||
end
|
||||
|
||||
def battler_to_projection(battler)
|
||||
@sides.each do |side|
|
||||
side.battlers.each do |projection|
|
||||
if projection && projection.pokemon == battler.pokemon
|
||||
return projection
|
||||
end
|
||||
end
|
||||
side.party.each do |projection|
|
||||
if projection && projection.pokemon == battler.pokemon
|
||||
return projection
|
||||
end
|
||||
end
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
def pokemon_to_projection(pokemon)
|
||||
@sides.each do |side|
|
||||
side.battlers.each do |projection|
|
||||
if projection && projection.pokemon == pokemon
|
||||
return projection
|
||||
end
|
||||
end
|
||||
side.party.each do |projection|
|
||||
if projection && projection.pokemon == pokemon
|
||||
return projection
|
||||
end
|
||||
end
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
def register_damage(move, user, target, damage)
|
||||
user = battler_to_projection(user)
|
||||
target = battler_to_projection(target)
|
||||
user.register_damage_dealt(move, target, damage)
|
||||
target.register_damage_taken(move, user, damage)
|
||||
end
|
||||
|
||||
def faint_battler(battler)
|
||||
# Remove the battler from the AI's list of the active battlers
|
||||
@sides.each do |side|
|
||||
side.battlers.each_with_index do |proj, index|
|
||||
if proj && proj.battler == battler
|
||||
# Decouple the projection from the battler
|
||||
side.recall(battler.index)
|
||||
side.battlers[index] = nil
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def end_of_round
|
||||
@sides.each { |side| side.end_of_round }
|
||||
end
|
||||
|
||||
def reveal_ability(battler)
|
||||
@sides.each do |side|
|
||||
side.battlers.each do |proj|
|
||||
if proj && proj.battler == battler && !proj.revealed_ability
|
||||
proj.revealed_ability = true
|
||||
MKAI.log("#{proj.pokemon.name}'s ability was revealed.")
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def reveal_item(battler)
|
||||
@sides.each do |side|
|
||||
side.battlers.each do |proj|
|
||||
if proj.battler == battler && !proj.revealed_item
|
||||
proj.revealed_item = true
|
||||
MKAI.log("#{proj.pokemon.name}'s item was revealed.")
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
1491
AI references/Marin's AI/AI_ScoreHandler.rb
Normal file
1491
AI references/Marin's AI/AI_ScoreHandler.rb
Normal file
File diff suppressed because it is too large
Load Diff
68
AI references/Marin's AI/AI_Side.rb
Normal file
68
AI references/Marin's AI/AI_Side.rb
Normal file
@@ -0,0 +1,68 @@
|
||||
class MKAI
|
||||
class Side
|
||||
attr_reader :ai
|
||||
attr_reader :index
|
||||
attr_reader :battlers
|
||||
attr_reader :party
|
||||
attr_reader :trainers
|
||||
attr_reader :flags
|
||||
|
||||
def initialize(ai, index, wild_pokemon = false)
|
||||
@ai = ai
|
||||
@index = index
|
||||
@battle = @ai.battle
|
||||
@wild_pokemon = wild_pokemon
|
||||
@battlers = []
|
||||
@party = []
|
||||
@flags = {}
|
||||
end
|
||||
|
||||
def effects
|
||||
return @battle.sides[@index].effects
|
||||
end
|
||||
|
||||
def set_party(party)
|
||||
@party = party.map { |pokemon| BattlerProjection.new(self, pokemon, @wild_pokemon) }
|
||||
end
|
||||
|
||||
def set_trainers(trainers)
|
||||
@trainers = trainers
|
||||
end
|
||||
|
||||
def opposing_side
|
||||
return @ai.sides[1 - @index]
|
||||
end
|
||||
|
||||
def recall(battlerIndex)
|
||||
index = MKAI.battler_to_proj_index(battlerIndex)
|
||||
proj = @battlers[index]
|
||||
if proj.nil?
|
||||
raise "Battler to be recalled was not found in the active battlers list."
|
||||
end
|
||||
if !proj.active?
|
||||
raise "Battler to be recalled was not active."
|
||||
end
|
||||
@battlers[index] = nil
|
||||
proj.battler = nil
|
||||
end
|
||||
|
||||
def send_out(battlerIndex, battler)
|
||||
proj = @party.find { |proj| proj && proj.pokemon == battler.pokemon }
|
||||
if proj.nil?
|
||||
raise "Battler to be sent-out was not found in the party list."
|
||||
end
|
||||
if proj.active?
|
||||
raise "Battler to be sent-out was already sent out before."
|
||||
end
|
||||
index = MKAI.battler_to_proj_index(battlerIndex)
|
||||
@battlers[index] = proj
|
||||
proj.ai_index = index
|
||||
proj.battler = battler
|
||||
end
|
||||
|
||||
def end_of_round
|
||||
@battlers.each { |proj| proj.end_of_round if proj }
|
||||
@flags = {}
|
||||
end
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user