mirror of
https://github.com/infinitefusion/infinitefusion-e18.git
synced 2025-12-08 13:44: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