Files
infinitefusion-e18/Data/Scripts/011_Battle/005_AI/003_AI_Item.rb
2023-04-23 18:04:32 +01:00

225 lines
9.3 KiB
Ruby

class Battle::AI
HP_HEAL_ITEMS = {
:POTION => 20,
:SUPERPOTION => (Settings::REBALANCED_HEALING_ITEM_AMOUNTS) ? 60 : 50,
:HYPERPOTION => (Settings::REBALANCED_HEALING_ITEM_AMOUNTS) ? 120 : 200,
:MAXPOTION => 999,
:BERRYJUICE => 20,
:SWEETHEART => 20,
:FRESHWATER => (Settings::REBALANCED_HEALING_ITEM_AMOUNTS) ? 30 : 50,
:SODAPOP => (Settings::REBALANCED_HEALING_ITEM_AMOUNTS) ? 50 : 60,
:LEMONADE => (Settings::REBALANCED_HEALING_ITEM_AMOUNTS) ? 70 : 80,
:MOOMOOMILK => 100,
:ORANBERRY => 10,
:SITRUSBERRY => 1, # Actual amount is determined below (pkmn.totalhp / 4)
:ENERGYPOWDER => (Settings::REBALANCED_HEALING_ITEM_AMOUNTS) ? 60 : 50,
:ENERGYROOT => (Settings::REBALANCED_HEALING_ITEM_AMOUNTS) ? 120 : 200
}
HP_HEAL_ITEMS[:RAGECANDYBAR] = 20 if !Settings::RAGE_CANDY_BAR_CURES_STATUS_PROBLEMS
FULL_RESTORE_ITEMS = [
:FULLRESTORE
]
ONE_STATUS_CURE_ITEMS = [ # Preferred over items that heal all status problems
:AWAKENING, :CHESTOBERRY, :BLUEFLUTE,
:ANTIDOTE, :PECHABERRY,
:BURNHEAL, :RAWSTBERRY,
:PARALYZEHEAL, :PARLYZHEAL, :CHERIBERRY,
:ICEHEAL, :ASPEARBERRY
]
ALL_STATUS_CURE_ITEMS = [
:FULLHEAL, :LAVACOOKIE, :OLDGATEAU, :CASTELIACONE, :LUMIOSEGALETTE,
:SHALOURSABLE, :BIGMALASADA, :PEWTERCRUNCHIES, :LUMBERRY, :HEALPOWDER
]
ALL_STATUS_CURE_ITEMS.push(:RAGECANDYBAR) if Settings::RAGE_CANDY_BAR_CURES_STATUS_PROBLEMS
ONE_STAT_RAISE_ITEMS = {
:XATTACK => [:ATTACK, (Settings::X_STAT_ITEMS_RAISE_BY_TWO_STAGES) ? 2 : 1],
:XATTACK2 => [:ATTACK, 2],
:XATTACK3 => [:ATTACK, 3],
:XATTACK6 => [:ATTACK, 6],
:XDEFENSE => [:DEFENSE, (Settings::X_STAT_ITEMS_RAISE_BY_TWO_STAGES) ? 2 : 1],
:XDEFENSE2 => [:DEFENSE, 2],
:XDEFENSE3 => [:DEFENSE, 3],
:XDEFENSE6 => [:DEFENSE, 6],
:XDEFEND => [:DEFENSE, (Settings::X_STAT_ITEMS_RAISE_BY_TWO_STAGES) ? 2 : 1],
:XDEFEND2 => [:DEFENSE, 2],
:XDEFEND3 => [:DEFENSE, 3],
:XDEFEND6 => [:DEFENSE, 6],
:XSPATK => [:SPECIAL_ATTACK, (Settings::X_STAT_ITEMS_RAISE_BY_TWO_STAGES) ? 2 : 1],
:XSPATK2 => [:SPECIAL_ATTACK, 2],
:XSPATK3 => [:SPECIAL_ATTACK, 3],
:XSPATK6 => [:SPECIAL_ATTACK, 6],
:XSPECIAL => [:SPECIAL_ATTACK, (Settings::X_STAT_ITEMS_RAISE_BY_TWO_STAGES) ? 2 : 1],
:XSPECIAL2 => [:SPECIAL_ATTACK, 2],
:XSPECIAL3 => [:SPECIAL_ATTACK, 3],
:XSPECIAL6 => [:SPECIAL_ATTACK, 6],
:XSPDEF => [:SPECIAL_DEFENSE, (Settings::X_STAT_ITEMS_RAISE_BY_TWO_STAGES) ? 2 : 1],
:XSPDEF2 => [:SPECIAL_DEFENSE, 2],
:XSPDEF3 => [:SPECIAL_DEFENSE, 3],
:XSPDEF6 => [:SPECIAL_DEFENSE, 6],
:XSPEED => [:SPEED, (Settings::X_STAT_ITEMS_RAISE_BY_TWO_STAGES) ? 2 : 1],
:XSPEED2 => [:SPEED, 2],
:XSPEED3 => [:SPEED, 3],
:XSPEED6 => [:SPEED, 6],
:XACCURACY => [:ACCURACY, (Settings::X_STAT_ITEMS_RAISE_BY_TWO_STAGES) ? 2 : 1],
:XACCURACY2 => [:ACCURACY, 2],
:XACCURACY3 => [:ACCURACY, 3],
:XACCURACY6 => [:ACCURACY, 6]
}
ALL_STATS_RAISE_ITEMS = [
:MAXMUSHROOMS
]
REVIVE_ITEMS = {
:REVIVE => 5,
:MAXREVIVE => 7,
:REVIVALHERB => 7,
:MAXHONEY => 7
}
# TODO: Add more items for the AI to use from their Bag:
# Confusion healing (Yellow Flute, Persim Berry)
# Infatuation healing (Red Flute)
# PP (Either, Max Ether, Leppa Berry, Elixir, Max Elixir)
# Dire Hit (and 2 and 3)
# Guard Spec.
# Poké Flute (awakens all battlers)
#-----------------------------------------------------------------------------
# Decide whether the opponent should use an item on the Pokémon.
def pbChooseToUseItem
item = nil
idxTarget = nil # Party index (battle_use type 1/2/3) or battler index
idxMove = nil
item, idxTarget, idxMove = choose_item_to_use
return false if !item
# Register use of item
@battle.pbRegisterItem(@user.index, item, idxTarget, idxMove)
PBDebug.log_ai("#{@user.name} will use item #{GameData::Item.get(item).name}")
return true
end
# Return values are:
# item ID
# target index (party index for items with a battle use of 1/2/3, battler
# index otherwise)
# move index (for items usable on moves only)
def choose_item_to_use
return nil if !@battle.internalBattle
items = @battle.pbGetOwnerItems(@user.index)
return nil if !items || items.length == 0
# Find all items usable on the Pokémon choosing this action
pkmn = @user.battler.pokemon
usable_items = {}
items.each do |item|
usage = get_usability_of_item_on_pkmn(item, @user.party_index, @user.side)
usage.each_pair do |key, vals|
usable_items[key] ||= []
usable_items[key] += vals
end
end
# Prioritise using a HP restoration item
if usable_items[:hp_heal] && (pkmn.hp <= pkmn.totalhp / 4 ||
(pkmn.hp <= pkmn.totalhp / 2 && pbAIRandom(100) < 30))
usable_items[:hp_heal].sort! { |a, b| (a[2] == b[2]) ? a[3] <=> b[3] : a[2] <=> b[2] }
usable_items[:hp_heal].each do |item|
return item[0], item[1] if item[3] >= (pkmn.totalhp - pkmn.hp) * 0.75
end
return usable_items[:hp_heal].last[0], usable_items[:hp_heal].last[1]
end
# Next prioritise using a status-curing item
if usable_items[:status_cure] &&
([:SLEEP, :FROZEN].include?(pkmn.status) || pbAIRandom(100) < 40)
usable_items[:status_cure].sort! { |a, b| a[2] <=> b[2] }
return usable_items[:status_cure].first[0], usable_items[:status_cure].first[1]
end
# Next try using an item that raises all stats (Max Mushrooms)
if usable_items[:all_stats_raise] && pbAIRandom(100) < 30
return usable_items[:stat_raise].first[0], usable_items[:stat_raise].first[1]
end
# Next try using an X item
if usable_items[:stat_raise] && pbAIRandom(100) < 30
usable_items[:stat_raise].sort! { |a, b| (a[2] == b[2]) ? a[3] <=> b[3] : a[2] <=> b[2] }
return usable_items[:stat_raise].last[0], usable_items[:stat_raise].last[1]
end
# Find items usable on other Pokémon in the user's team
# NOTE: Currently only checks Revives.
usable_items = {}
@battle.eachInTeamFromBattlerIndex(@user.index) do |pkmn, i|
next if !pkmn.fainted? # Remove this line to check unfainted Pokémon too
items.each do |item|
usage = get_usability_of_item_on_pkmn(item, i, @user.side)
usage.each_pair do |key, vals|
usable_items[key] ||= []
usable_items[key] += vals
end
end
end
# Try using a Revive (prefer Max Revive-type items over Revive)
if usable_items[:revive] &&
(@battle.pbAbleNonActiveCount(@user.index) == 0 || pbAIRandom(100) < 40)
usable_items[:revive].sort! { |a, b| (a[2] == b[2]) ? a[1] <=> b[1] : a[2] <=> b[2] }
return usable_items[:revive].last[0], usable_items[:revive].last[1]
end
return nil
end
def get_usability_of_item_on_pkmn(item, party_index, side)
pkmn = @battle.pbParty(side)[party_index]
battler = @battle.pbFindBattler(party_index, side)
ret = {}
return ret if !@battle.pbCanUseItemOnPokemon?(item, pkmn, battler, @battle.scene, false)
return ret if !ItemHandlers.triggerCanUseInBattle(item, pkmn, battler, nil,
false, self, @battle.scene, false)
want_to_cure_status = (pkmn.status != :NONE)
if battler
if want_to_cure_status
want_to_cure_status = @battlers[battler.index].wants_status_problem?(pkmn.status)
want_to_cure_status = false if pkmn.status == :SLEEP && pkmn.statusCount <= 2
end
want_to_cure_status ||= (battler.effects[PBEffects::Confusion] > 0)
end
if HP_HEAL_ITEMS.include?(item)
if pkmn.hp < pkmn.totalhp
heal_amount = HP_HEAL_ITEMS[item]
heal_amount = pkmn.totalhp / 4 if item == :SITURUSBERRY
ret[:hp_heal] ||= []
ret[:hp_heal].push([item, party_index, 5, heal_amount])
end
elsif FULL_RESTORE_ITEMS.include?(item)
prefer_full_restore = (pkmn.hp <= pkmn.totalhp * 2 / 3 && want_to_cure_status)
if pkmn.hp < pkmn.totalhp
ret[:hp_heal] ||= []
ret[:hp_heal].push([item, party_index, (prefer_full_restore) ? 3 : 7, 999])
end
if want_to_cure_status
ret[:status_cure] ||= []
ret[:status_cure].push([item, party_index, (prefer_full_restore) ? 3 : 9])
end
elsif ONE_STATUS_CURE_ITEMS.include?(item)
if want_to_cure_status
ret[:status_cure] ||= []
ret[:status_cure].push([item, party_index, 5])
end
elsif ALL_STATUS_CURE_ITEMS.include?(item)
if want_to_cure_status
ret[:status_cure] ||= []
ret[:status_cure].push([item, party_index, 7])
end
elsif ONE_STAT_RAISE_ITEMS.include?(item)
stat_data = ONE_STAT_RAISE_ITEMS[item]
if battler && stat_raise_worthwhile?(@battlers[battler.index], stat_data[0])
ret[:stat_raise] ||= []
ret[:stat_raise].push([item, party_index, battler.stages[stat_data[0]], stat_data[1]])
end
elsif ALL_STATS_RAISE_ITEMS.include?(item)
if battler
ret[:all_stats_raise] ||= []
ret[:all_stats_raise].push([item, party_index])
end
elsif REVIVE_ITEMS.include?(item)
ret[:revive] ||= []
ret[:revive].push([item, party_index, REVIVE_ITEMS[item]])
end
return ret
end
end