diff --git a/Data/Scripts/001_Settings.rb b/Data/Scripts/001_Settings.rb index f924cfaaf..6eafee312 100644 --- a/Data/Scripts/001_Settings.rb +++ b/Data/Scripts/001_Settings.rb @@ -14,7 +14,7 @@ module Settings # Note that this isn't perfect. Essentials doesn't accurately replicate every # single generation's mechanics. It's considered to be good enough. Only # generations 5 and later are reasonably supported. - MECHANICS_GENERATION = 7 + MECHANICS_GENERATION = 8 #============================================================================= diff --git a/Data/Scripts/011_Battle/001_Battler/006_Battler_AbilityAndItem.rb b/Data/Scripts/011_Battle/001_Battler/006_Battler_AbilityAndItem.rb index 3db70f397..16afbb75e 100644 --- a/Data/Scripts/011_Battle/001_Battler/006_Battler_AbilityAndItem.rb +++ b/Data/Scripts/011_Battle/001_Battler/006_Battler_AbilityAndItem.rb @@ -91,6 +91,12 @@ class PokeBattle_Battler end end + # Used for Rattled's Gen 8 effect. Called when Intimidate is triggered. + def pbAbilitiesOnIntimidated + return if !abilityActive? + BattleHandlers.triggerAbilityOnIntimidated(self.ability, self, @battle) + end + #============================================================================= # Ability curing #============================================================================= diff --git a/Data/Scripts/011_Battle/001_Battler/007_Battler_UseMove.rb b/Data/Scripts/011_Battle/001_Battler/007_Battler_UseMove.rb index 9e19d4f61..9dede31bb 100644 --- a/Data/Scripts/011_Battle/001_Battler/007_Battler_UseMove.rb +++ b/Data/Scripts/011_Battle/001_Battler/007_Battler_UseMove.rb @@ -522,14 +522,16 @@ class PokeBattle_Battler next if idxMove<0 oldLastRoundMoved = b.lastRoundMoved @battle.pbDisplay(_INTL("{1} used the move instructed by {2}!",b.pbThis,user.pbThis(true))) - PBDebug.logonerr{ - b.effects[PBEffects::Instructed] = true - b.pbUseMoveSimple(b.lastMoveUsed,b.lastRegularMoveTarget,idxMove,false) - b.effects[PBEffects::Instructed] = false - } - b.lastRoundMoved = oldLastRoundMoved - @battle.pbJudge - return if @battle.decision>0 + b.effects[PBEffects::Instructed] = true + if b.pbCanChooseMove?(@moves[idxMove], false) + PBDebug.logonerr{ + b.pbUseMoveSimple(b.lastMoveUsed,b.lastRegularMoveTarget,idxMove,false) + } + b.lastRoundMoved = oldLastRoundMoved + @battle.pbJudge + return if @battle.decision>0 + end + b.effects[PBEffects::Instructed] = false end # Dancer if !@effects[PBEffects::Dancer] && !user.lastMoveFailed && realNumHits>0 && @@ -556,16 +558,18 @@ class PokeBattle_Battler @battle.pbDisplay(_INTL("{1} kept the dance going with {2}!", nextUser.pbThis,nextUser.abilityName)) end - PBDebug.logonerr{ - nextUser.effects[PBEffects::Dancer] = true - nextUser.pbUseMoveSimple(move.id,preTarget) - nextUser.effects[PBEffects::Dancer] = false - } - nextUser.lastRoundMoved = oldLastRoundMoved - nextUser.effects[PBEffects::Outrage] = oldOutrage - nextUser.currentMove = oldCurrentMove - @battle.pbJudge - return if @battle.decision>0 + nextUser.effects[PBEffects::Dancer] = true + if nextUser.pbCanChooseMove?(move, false) + PBDebug.logonerr{ + nextUser.pbUseMoveSimple(move.id,preTarget) + } + nextUser.lastRoundMoved = oldLastRoundMoved + nextUser.effects[PBEffects::Outrage] = oldOutrage + nextUser.currentMove = oldCurrentMove + @battle.pbJudge + return if @battle.decision>0 + end + nextUser.effects[PBEffects::Dancer] = false end end end diff --git a/Data/Scripts/011_Battle/002_BattleHandlers.rb b/Data/Scripts/011_Battle/002_BattleHandlers.rb index 5e6b66d57..a39d3ad09 100644 --- a/Data/Scripts/011_Battle/002_BattleHandlers.rb +++ b/Data/Scripts/011_Battle/002_BattleHandlers.rb @@ -90,6 +90,7 @@ module BattleHandlers AbilityOnSwitchOut = AbilityHandlerHash.new AbilityChangeOnBattlerFainting = AbilityHandlerHash.new AbilityOnBattlerFainting = AbilityHandlerHash.new # Soul-Heart + AbilityOnIntimidated = AbilityHandlerHash.new # Rattled (Gen 8) # Running from battle RunFromBattleAbility = AbilityHandlerHash.new # Run Away RunFromBattleItem = ItemHandlerHash.new # Smoke Ball @@ -463,6 +464,10 @@ module BattleHandlers AbilityOnBattlerFainting.trigger(ability,battler,fainted,battle) end + def self.triggerAbilityOnIntimidated(ability,battler,battle) + AbilityOnIntimidated.trigger(ability,battler,battle) + end + #============================================================================= def self.triggerRunFromBattleAbility(ability,battler) diff --git a/Data/Scripts/011_Battle/002_Move/006_Move_Effects_080-0FF.rb b/Data/Scripts/011_Battle/002_Move/006_Move_Effects_080-0FF.rb index 6d812749b..769cb24bf 100644 --- a/Data/Scripts/011_Battle/002_Move/006_Move_Effects_080-0FF.rb +++ b/Data/Scripts/011_Battle/002_Move/006_Move_Effects_080-0FF.rb @@ -2983,20 +2983,43 @@ end #=============================================================================== -# User flees from battle. Fails in trainer battles. (Teleport) +# User flees from battle (but in Gen 8+, only when user is a wild Pokémon). +# In Gen 8+, user switches out (except if user is a wild Pokémon). (Teleport) #=============================================================================== class PokeBattle_Move_0EA < PokeBattle_Move def pbMoveFailed?(user,targets) - if !@battle.pbCanRun?(user.index) + if Settings::MECHANICS_GENERATION < 8 || (@battle.wildBattle? && user.opposes?) + if !@battle.pbCanRun?(user.index) + @battle.pbDisplay(_INTL("But it failed!")) + return true + end + elsif !@battle.pbCanChooseNonActive?(user.index) @battle.pbDisplay(_INTL("But it failed!")) return true end return false end + def pbEndOfMoveUsageEffect(user,targets,numHits,switchedBattlers) + return if Settings::MECHANICS_GENERATION < 8 || (@battle.wildBattle? && user.opposes?) + @battle.pbDisplay(_INTL("{1} went back to {2}!",user.pbThis, + @battle.pbGetOwnerName(user.index))) + @battle.pbPursuit(user.index) + return if user.fainted? + newPkmn = @battle.pbGetReplacementPokemonIndex(user.index) # Owner chooses + return if newPkmn<0 + @battle.pbRecallAndReplace(user.index,newPkmn) + @battle.pbClearChoice(user.index) # Replacement Pokémon does nothing this round + @battle.moldBreaker = false + switchedBattlers.push(user.index) + user.pbEffectsOnSwitchIn(true) + end + def pbEffectGeneral(user) - @battle.pbDisplay(_INTL("{1} fled from battle!",user.pbThis)) - @battle.decision = 3 # Escaped + if Settings::MECHANICS_GENERATION < 8 || (@battle.wildBattle? && user.opposes?) + @battle.pbDisplay(_INTL("{1} fled from battle!",user.pbThis)) + @battle.decision = 3 # Escaped + end end end diff --git a/Data/Scripts/011_Battle/002_Move/007_Move_Effects_100-17F.rb b/Data/Scripts/011_Battle/002_Move/007_Move_Effects_100-17F.rb index 881a5ec3f..111c9b3ba 100644 --- a/Data/Scripts/011_Battle/002_Move/007_Move_Effects_100-17F.rb +++ b/Data/Scripts/011_Battle/002_Move/007_Move_Effects_100-17F.rb @@ -269,7 +269,10 @@ class PokeBattle_Move_10D < PokeBattle_Move def ignoresSubstitute?(user); return true; end def pbTarget(user) - return GameData::Target.get(:NearFoe) if user.pbHasType?(:GHOST) + if user.pbHasType?(:GHOST) + ghost_target = (Settings::MECHANICS_GENERATION >= 8) ? :RandomNearFoe : :NearFoe + return GameData::Target.get(ghost_target) + end return super end @@ -375,9 +378,14 @@ end #=============================================================================== # Removes trapping moves, entry hazards and Leech Seed on user/user's side. -# (Rapid Spin) +# Raises user's Speed by 1 stage (Gen 8+). (Rapid Spin) #=============================================================================== -class PokeBattle_Move_110 < PokeBattle_Move +class PokeBattle_Move_110 < PokeBattle_StatUpMove + def initialize(battle,move) + super + @statUp = [:SPEED, 1] + end + def pbEffectAfterAllHits(user,target) return if user.fainted? || target.damageState.unaffected if user.effects[PBEffects::Trapping]>0 @@ -409,6 +417,10 @@ class PokeBattle_Move_110 < PokeBattle_Move @battle.pbDisplay(_INTL("{1} blew away sticky webs!",user.pbThis)) end end + + def pbAdditionalEffect(user,target) + super if Settings::MECHANICS_GENERATION >= 8 + end end diff --git a/Data/Scripts/011_Battle/003_Battle/011_Battle_Phase_Attack.rb b/Data/Scripts/011_Battle/003_Battle/011_Battle_Phase_Attack.rb index 01d9890f7..b2dbe3dc8 100644 --- a/Data/Scripts/011_Battle/003_Battle/011_Battle_Phase_Attack.rb +++ b/Data/Scripts/011_Battle/003_Battle/011_Battle_Phase_Attack.rb @@ -129,19 +129,29 @@ class PokeBattle_Battle return if @decision>0 next if advance # Quashed - quashLevel = 0 - loop do - quashLevel += 1 - moreQuash = false + if Settings::MECHANICS_GENERATION >= 8 priority.each do |b| - moreQuash = true if b.effects[PBEffects::Quash]>quashLevel - next unless b.effects[PBEffects::Quash]==quashLevel && !b.fainted? + next unless b.effects[PBEffects::Quash] > 0 && !b.fainted? next unless @choices[b.index][0]==:UseMove || @choices[b.index][0]==:Shift next if b.movedThisRound? advance = b.pbProcessTurn(@choices[b.index]) - break + break if advance + end + else + quashLevel = 0 + loop do + quashLevel += 1 + moreQuash = false + priority.each do |b| + moreQuash = true if b.effects[PBEffects::Quash]>quashLevel + next unless b.effects[PBEffects::Quash]==quashLevel && !b.fainted? + next unless @choices[b.index][0]==:UseMove || @choices[b.index][0]==:Shift + next if b.movedThisRound? + advance = b.pbProcessTurn(@choices[b.index]) + break + end + break if advance || !moreQuash end - break if advance || !moreQuash end return if @decision>0 next if advance diff --git a/Data/Scripts/011_Battle/003_BattleHandlers_Abilities.rb b/Data/Scripts/011_Battle/003_BattleHandlers_Abilities.rb index 699001d2d..547b7a291 100644 --- a/Data/Scripts/011_Battle/003_BattleHandlers_Abilities.rb +++ b/Data/Scripts/011_Battle/003_BattleHandlers_Abilities.rb @@ -2285,7 +2285,8 @@ BattleHandlers::AbilityOnSwitchIn.add(:INTIMIDATE, else check_item = false if b.statStageAtMin?(:ATTACK) end - b.pbLowerAttackStatStageIntimidate(battler) + check_ability = b.pbLowerAttackStatStageIntimidate(battler) + b.pbAbilitiesOnIntimidated if check_ability b.pbItemOnIntimidatedCheck if check_item end battle.pbHideAbilitySplash(battler) @@ -2474,6 +2475,17 @@ BattleHandlers::AbilityOnBattlerFainting.add(:SOULHEART, } ) +#=============================================================================== +# AbilityOnIntimidated handlers +#=============================================================================== + +BattleHandlers::AbilityOnIntimidated.add(:RATTLED, + proc { |ability,battler,battle| + next if Settings::MECHANICS_GENERATION < 8 + battler.pbRaiseStatStageByAbility(:SPEED, 1, battler) + } +) + #=============================================================================== # RunFromBattleAbility handlers #=============================================================================== diff --git a/Data/Scripts/011_Battle/004_AI/004_AI_Move.rb b/Data/Scripts/011_Battle/004_AI/004_AI_Move.rb index b7d2629e4..c17f2761c 100644 --- a/Data/Scripts/011_Battle/004_AI/004_AI_Move.rb +++ b/Data/Scripts/011_Battle/004_AI/004_AI_Move.rb @@ -191,7 +191,8 @@ class PokeBattle_AI score -= 80 if miss end # Pick a good move for the Choice items - if user.hasActiveItem?([:CHOICEBAND,:CHOICESPECS,:CHOICESCARF]) + if user.hasActiveItem?([:CHOICEBAND,:CHOICESPECS,:CHOICESCARF]) || + user.hasActiveAbility?(:GORILLATACTICS) if move.baseDamage>=60; score += 60 elsif move.damagingMove?; score += 30 elsif move.function=="0F2"; score += 70 # Trick diff --git a/Data/Scripts/011_Battle/004_AI/006_AI_Move_Utilities.rb b/Data/Scripts/011_Battle/004_AI/006_AI_Move_Utilities.rb index 68a537110..1780a94ce 100644 --- a/Data/Scripts/011_Battle/004_AI/006_AI_Move_Utilities.rb +++ b/Data/Scripts/011_Battle/004_AI/006_AI_Move_Utilities.rb @@ -269,6 +269,8 @@ class PokeBattle_AI atk = pbRoughStat(user,:ATTACK,skill) if move.function=="121" # Foul Play atk = pbRoughStat(target,:ATTACK,skill) + elsif move.function=="197" # Body Press + atk = pbRoughStat(user,:DEFENSE,skill) elsif move.specialMove?(type) if move.function=="121" # Foul Play atk = pbRoughStat(target,:SPECIAL_ATTACK,skill) diff --git a/Data/Scripts/011_Battle/004_AI/007_AI_Move_EffectScores_Gen8.rb b/Data/Scripts/011_Battle/004_AI/007_AI_Move_EffectScores_Gen8.rb new file mode 100644 index 000000000..87307d483 --- /dev/null +++ b/Data/Scripts/011_Battle/004_AI/007_AI_Move_EffectScores_Gen8.rb @@ -0,0 +1,373 @@ +class PokeBattle_AI + #============================================================================= + # Get a score for the given move based on its effect + #============================================================================= + alias gen8_pbGetMoveScoreFunctionCode pbGetMoveScoreFunctionCode + def pbGetMoveScoreFunctionCode(score,move,user,target,skill = 100) + score = gen8_pbGetMoveScoreFunctionCode(score,move,user,target,skill) + case move.function + when "176" + score += 5 if target.pbCanPoison?(user, false) + #--------------------------------------------------------------------------- + when "177" + if target.pbCanBurn?(user, false) + score += 40 + if skill >= PBTrainerAI.highSkill + score -= 40 if target.hasActiveAbility?([:GUTS, :MARVELSCALE, :QUICKFEET, :FLAREBOOST]) + end + else + score -= 90 + end + #--------------------------------------------------------------------------- + when "178" + score += 20 if user.stages[:SPEED] <= 0 + #--------------------------------------------------------------------------- + when "179" + if user.effects[PBEffects::NoRetreat] + score -= 100 + elsif user.hasActiveAbility?(:CONTRARY) + score -= 100 + else + stats_maxed = true + GameData::Stat.each_main_battle do |s| + next if user.statStageAtMax?(s.id) + stats_maxed = false + break + end + if stats_maxed + score -= 100 + else + if skill >= PBTrainerAI.highSkill + score -= 50 if user.hp <= user.totalhp / 2 + score += 30 if user.trappedInBattle? + end + GameData::Stat.each_main_battle { |s| score += 10 if user.stages[s.id] <= 0 } + if skill >= PBTrainerAI.mediumSkill + hasDamagingAttack = user.moves.any? { |m| next m && m.damagingMove? } + score += 20 if hasDamagingAttack + end + end + end + #--------------------------------------------------------------------------- + when "17A" + if user.hp <= user.totalhp / 2 + score -= 100 + elsif user.hasActiveAbility?(:CONTRARY) + score -= 100 + else + stats_maxed = true + GameData::Stat.each_main_battle do |s| + next if user.statStageAtMax?(s.id) + stats_maxed = false + break + end + if stats_maxed + score -= 100 + else + if skill >= PBTrainerAI.highSkill && user.hp >= user.totalhp * 0.75 + score += 30 + end + GameData::Stat.each_main_battle { |s| score += 10 if user.stages[s.id] <= 0 } + if skill >= PBTrainerAI.mediumSkill + hasDamagingAttack = user.moves.any? { |m| next m && m.damagingMove? } + score += 20 if hasDamagingAttack + end + end + end + #--------------------------------------------------------------------------- + when "17B" + has_ally = false + user.eachAlly do |b| + next if !b.pbCanLowerStatStage?(:ATTACK, user) && + !b.pbCanLowerStatStage?(:SPECIAL_ATTACK, user) + has_ally = true + if skill >= PBTrainerAI.mediumSkill && b.hasActiveAbility?(:CONTRARY) + score -= 90 + else + score += 40 + score -= b.stages[:ATTACK] * 20 + score -= b.stages[:SPECIAL_ATTACK] * 20 + end + end + score = 0 if !has_ally + #--------------------------------------------------------------------------- + when "17C" + if target.opposes?(user) + score -= 100 + elsif skill >= PBTrainerAI.mediumSkill && target.hasActiveAbility?(:CONTRARY) + score -= 90 + else + score -= target.stages[:ATTACK] * 20 + score -= target.stages[:SPECIAL_ATTACK] * 20 + end + #--------------------------------------------------------------------------- + when "17D" + if !target.pbCanLowerStatStage?(:DEFENSE, user) + score -= 90 + else + score += 20 + score += target.stages[:DEFENSE] * 20 + end + score += 30 if @battle.field.effects[PBEffects::Gravity] > 0 + #--------------------------------------------------------------------------- + when "17E" + if !target.pbCanLowerStatStage?(:SPEED, user) && target.effects[PBEffects::TarShot] + score -= 100 + else + score += target.stages[:SPEED] * 10 + if skill >= PBTrainerAI.highSkill + aspeed = pbRoughStat(user, :SPEED, skill) + ospeed = pbRoughStat(target, :SPEED, skill) + score += 50 if aspeed < ospeed && aspeed * 2 > ospeed + end + end + score += 20 if user.moves.any? { |m| m.damagingMove? && m.pbCalcType(user) == :FIRE } + #--------------------------------------------------------------------------- + when "17F" + if target.pbHasOtherType?(:PSYCHIC) + score -= 90 + elsif !target.canChangeType? + score -= 90 + end + #--------------------------------------------------------------------------- + when "180" + score += 40 if @battle.field.terrain == :Electric && target.affectedByTerrain? + #--------------------------------------------------------------------------- + when "181" + score += 40 if @battle.field.terrain == :Psychic && user.affectedByTerrain? + #--------------------------------------------------------------------------- + when "182" + score += 40 if @battle.field.terrain != :None + #--------------------------------------------------------------------------- + when "183" + #--------------------------------------------------------------------------- + when "184" + #--------------------------------------------------------------------------- + when "185" + if skill >= PBTrainerAI.mediumSkill && @battle.field.terrain == :Grassy + aspeed = pbRoughStat(user, :SPEED, skill) + ospeed = pbRoughStat(target, :SPEED, skill) + score += 40 if aspeed < ospeed + end + #--------------------------------------------------------------------------- + when "186" + if user.effects[PBEffects::ProtectRate] > 1 || + target.effects[PBEffects::HyperBeam] > 0 + score -= 90 + else + if skill >= PBTrainerAI.mediumSkill + score -= user.effects[PBEffects::ProtectRate] * 40 + end + score += 50 if user.turnCount == 0 + score += 30 if target.effects[PBEffects::TwoTurnAttack] + end + #--------------------------------------------------------------------------- + when "187" + redirection = false + user.eachOpposing do |b| + next if b.index == target.index + if b.effects[PBEffects::RagePowder] || + b.effects[PBEffects::Spotlight] > 0 || + b.effects[PBEffects::FollowMe] > 0 || + (b.hasActiveAbility?(:LIGHTNINGROD) && move.pbCalcType == :ELECTRIC) || + (b.hasActiveAbility?(:STORMDRAIN) && move.pbCalcType == :WATER) + redirection = true + break + end + end + score += 50 if redirection && skill >= PBTrainerAI.mediumSkill + #--------------------------------------------------------------------------- + when "188" + #--------------------------------------------------------------------------- + when "189" + if skill >= PBTrainerAI.highSkill + stat = (move.physicalMove?)? :DEFENSE : :SPECIAL_DEFENSE + score += 50 if targets.stages[stat] > 1 + end + #--------------------------------------------------------------------------- + when "18A" + aspeed = pbRoughStat(user, :SPEED, skill) + ospeed = pbRoughStat(target, :SPEED, skill) + if aspeed > ospeed && aspeed * 2 / 3 < ospeed + score -= 50 + elsif aspeed < ospeed && aspeed * 1.5 > ospeed + score += 50 + end + score += user.stages[:DEFENSE] * 30 + #--------------------------------------------------------------------------- + when "18B" + aspeed = pbRoughStat(user, :SPEED, skill) + ospeed = pbRoughStat(target, :SPEED, skill) + if (aspeed > ospeed && user.hp > user.totalhp / 3) || user.hp > user.totalhp / 2 + score += 60 + else + score -= 90 + end + score += user.stages[:SPECIAL_ATTACK] * 20 + #--------------------------------------------------------------------------- + when "18C" + ally_amt = 30 + @battle.eachSameSideBattler(user.index) do |b| + if b.hp == b.totalhp || (skill >= PBTrainerAI.mediumSkill && !b.canHeal?) + score -= ally_amt / 2 + elsif b.hp < b.totalhp * 3 / 4 + score += ally_amt + end + end + #--------------------------------------------------------------------------- + when "18D" + ally_amt = 80 / @battle.pbSideSize(user.index) + @battle.eachSameSideBattler(user.index) do |b| + if b.hp == b.totalhp || (skill >= PBTrainerAI.mediumSkill && !b.canHeal?) + score -= ally_amt + elsif b.hp < b.totalhp * 3 / 4 + score += ally_amt + end + score += ally_amt / 2 if b.pbHasAnyStatus? + end + #--------------------------------------------------------------------------- + when "18E" + reserves = @battle.pbAbleNonActiveCount(user.idxOwnSide) + foes = @battle.pbAbleNonActiveCount(user.idxOpposingSide) + if @battle.pbCheckGlobalAbility(:DAMP) + score -= 100 + elsif skill >= PBTrainerAI.mediumSkill && reserves == 0 && foes > 0 + score -= 100 # don't want to lose + elsif skill >= PBTrainerAI.highSkill && reserves == 0 && foes == 0 + score += 40 # want to draw + score += 40 if @battle.field.terrain == :Misty + else + score -= user.hp * 100 / user.totalhp + score += 20 if @battle.field.terrain == :Misty + end + #--------------------------------------------------------------------------- + when "18F" + if target.effects[PBEffects::Octolock] >= 0 + score -= 100 + else + score += 30 if !target.trappedInBattle? + score -= 100 if !target.pbCanLowerStatStage?(:DEFENSE, user, move) && + !target.pbCanLowerStatStage?(:SPECIAL_DEFENSE, user, move) + end + #--------------------------------------------------------------------------- + when "190" + if target.effects[PBEffects::JawLock] < 0 + score += 40 if !user.trappedInBattle? && !target.trappedInBattle? + end + #--------------------------------------------------------------------------- + when "191" + if !user.item || !user.item.is_berry? || !user.itemActive? + score -= 100 + else + if skill >= PBTrainerAI.highSkill + useful_berries = [ + :ORANBERRY, :SITRUSBERRY, :AGUAVBERRY, :APICOTBERRY, :CHERIBERRY, + :CHESTOBERRY, :FIGYBERRY, :GANLONBERRY, :IAPAPABERRY, :KEEBERRY, + :LANSATBERRY, :LEPPABERRY, :LIECHIBERRY, :LUMBERRY, :MAGOBERRY, + :MARANGABERRY, :PECHABERRY, :PERSIMBERRY, :PETAYABERRY, :RAWSTBERRY, + :SALACBERRY, :STARFBERRY, :WIKIBERRY + ] + score += 30 if useful_berries.include?(user.item_id) + end + if skill >= PBTrainerAI.mediumSkill + score += 20 if user.canHeal? && user.hp < user.totalhp / 3 && user.hasActiveAbility?(:CHEEKPOUCH) + score += 20 if user.hasActiveAbility?([:HARVEST, :RIPEN]) || + user.pbHasMoveFunction?("0F6") # Recycle + score += 20 if !user.canConsumeBerry? + end + score -= user.stages[:DEFENSE] * 20 + end + #--------------------------------------------------------------------------- + when "192" + useful_berries = [ + :ORANBERRY, :SITRUSBERRY, :AGUAVBERRY, :APICOTBERRY, :CHERIBERRY, + :CHESTOBERRY, :FIGYBERRY, :GANLONBERRY, :IAPAPABERRY, :KEEBERRY, + :LANSATBERRY, :LEPPABERRY, :LIECHIBERRY, :LUMBERRY, :MAGOBERRY, + :MARANGABERRY, :PECHABERRY, :PERSIMBERRY, :PETAYABERRY, + :RAWSTBERRY, :SALACBERRY, :STARFBERRY, :WIKIBERRY + ] + @battle.eachSameSideBattler(user.index) do |b| + if !b.item || !b.item.is_berry? || !b.itemActive? + score -= 100 / @battle.pbSideSize(user.index) + else + if skill >= PBTrainerAI.highSkill + amt = 30 / @battle.pbSideSize(user.index) + score += amt if useful_berries.include?(b.item_id) + end + if skill >= PBTrainerAI.mediumSkill + amt = 20 / @battle.pbSideSize(user.index) + score += amt if b.canHeal? && b.hp < b.totalhp / 3 && b.hasActiveAbility?(:CHEEKPOUCH) + score += amt if b.hasActiveAbility?([:HARVEST, :RIPEN]) || + b.pbHasMoveFunction?("0F6") # Recycle + score += amt if !b.canConsumeBerry? + end + end + end + if skill >= PBTrainerAI.highSkill + @battle.eachOtherSideBattler(user.index) do |b| + amt = 10 / @battle.pbSideSize(target.index) + score -= amt if b.hasActiveItem?(useful_berries) + score -= amt if b.canHeal? && b.hp < b.totalhp / 3 && b.hasActiveAbility?(:CHEEKPOUCH) + score -= amt if b.hasActiveAbility?([:HARVEST, :RIPEN]) || + b.pbHasMoveFunction?("0F6") # Recycle + score -= amt if !b.canConsumeBerry? + end + end + #--------------------------------------------------------------------------- + when "193" + if @battle.corrosiveGas[target.index % 2][target.pokemonIndex] + score -= 100 + elsif !target.item || !target.itemActive? || target.unlosableItem?(target.item) || + target.hasActiveAbility?(:STICKYHOLD) + score -= 90 + elsif target.effects[PBEffects::Substitute] > 0 + score -= 90 + else + score += 50 + end + #--------------------------------------------------------------------------- + when "194" + score -= 100 if user.hp <= user.totalhp / 2 + #--------------------------------------------------------------------------- + when "195" + last_move = target.pbGetMoveWithID(target.lastRegularMoveUsed) + if last_move && last_move.total_pp > 0 && last_move.pp <= 3 + score += 50 + end + #--------------------------------------------------------------------------- + when "196" + if skill >= PBTrainerAI.mediumSkill + if !target.item || !target.itemActive? + score -= 90 + else + score += 50 + end + end + #--------------------------------------------------------------------------- + when "197" + #--------------------------------------------------------------------------- + when "198" + if skill >= PBTrainerAI.mediumSkill + good_effects = [:Reflect, :LightScreen, :AuroraVeil, :SeaOfFire, + :Swamp, :Rainbow, :Mist, :Safeguard, + :Tailwind].map! { |e| PBEffects.const_get(e) } + bad_effects = [:Spikes, :StickyWeb, :ToxicSpikes, :StealthRock].map! { |e| PBEffects.const_get(e) } + bad_effects.each do |e| + score += 10 if ![0, false, nil].include?(user.pbOwnSide.effects[e]) + score -= 10 if ![0, 1, false, nil].include?(user.pbOpposingSide.effects[e]) + end + if skill >= PBTrainerAI.highSkill + good_effects.each do |e| + score += 10 if ![0, 1, false, nil].include?(user.pbOpposingSide.effects[e]) + score -= 10 if ![0, false, nil].include?(user.pbOwnSide.effects[e]) + end + end + end + #--------------------------------------------------------------------------- + when "199" + score -= 100 if @battle.field.terrain == :None + #--------------------------------------------------------------------------- + end + return score + end +end diff --git a/Data/Scripts/011_Battle/004_BattleHandlers_Items.rb b/Data/Scripts/011_Battle/004_BattleHandlers_Items.rb index 172578713..3181b8bc7 100644 --- a/Data/Scripts/011_Battle/004_BattleHandlers_Items.rb +++ b/Data/Scripts/011_Battle/004_BattleHandlers_Items.rb @@ -1283,26 +1283,27 @@ BattleHandlers::UserItemAfterMoveUse.add(:SHELLBELL, BattleHandlers::EndOfMoveItem.add(:LEPPABERRY, proc { |item,battler,battle,forced| next false if !forced && !battler.canConsumeBerry? - found = [] - battler.pokemon.moves.each_with_index do |m,i| - next if m.total_pp<=0 || m.pp==m.total_pp - next if !forced && m.pp>0 - found.push(i) + found_empty_moves = [] + found_partial_moves = [] + battler.pokemon.moves.each_with_index do |move, i| + next if move.total_pp <= 0 || move.pp == move.total_pp + (move.pp == 0) ? found_empty_moves.push(i) : found_partial_moves.push(i) end - next false if found.length==0 + next false if found_empty_moves.empty? && (!forced || found_partial_moves.empty?) itemName = GameData::Item.get(item).name PBDebug.log("[Item triggered] #{battler.pbThis}'s #{itemName}") if forced - battle.pbCommonAnimation("EatBerry",battler) if !forced - choice = found[battle.pbRandom(found.length)] + battle.pbCommonAnimation("EatBerry", battler) if !forced + choice = found_empty_moves.first + choice = found_partial_moves.first if forced && choice.nil? pkmnMove = battler.pokemon.moves[choice] pkmnMove.pp += 10 - pkmnMove.pp = pkmnMove.total_pp if pkmnMove.pp>pkmnMove.total_pp + pkmnMove.pp = pkmnMove.total_pp if pkmnMove.pp > pkmnMove.total_pp battler.moves[choice].pp = pkmnMove.pp moveName = pkmnMove.name if forced - battle.pbDisplay(_INTL("{1} restored its {2}'s PP.",battler.pbThis,moveName)) + battle.pbDisplay(_INTL("{1} restored its {2}'s PP.", battler.pbThis, moveName)) else - battle.pbDisplay(_INTL("{1}'s {2} restored its {3}'s PP!",battler.pbThis,itemName,moveName)) + battle.pbDisplay(_INTL("{1}'s {2} restored its {3}'s PP!", battler.pbThis, itemName, moveName)) end next true } diff --git a/Data/Scripts/013_Items/Gen 8 items.rb b/Data/Scripts/013_Items/Gen 8 items.rb index e4a7ea5d1..05ad76480 100644 --- a/Data/Scripts/013_Items/Gen 8 items.rb +++ b/Data/Scripts/013_Items/Gen 8 items.rb @@ -272,7 +272,7 @@ ItemHandlers::UseOnPokemon.add(:ABILITYPATCH, proc { |item, pkmn, scene| abils = pkmn.getAbilityList new_ability_id = nil abils.each { |a| new_ability_id = a[0] if a[1] == 2 } - if !new_ability_id || pkmn.hasHiddenAbility? + if !new_ability_id || pkmn.hasHiddenAbility? || pkmn.isSpecies?(:ZYGARDE) scene.pbDisplay(_INTL("It won't have any effect.")) next false end diff --git a/Data/Scripts/Gen 8 notes.txt b/Data/Scripts/Gen 8 notes.txt index dfbad9593..9b23d1972 100644 --- a/Data/Scripts/Gen 8 notes.txt +++ b/Data/Scripts/Gen 8 notes.txt @@ -7,32 +7,22 @@ The game records, for each species, how many have been caught or defeated (counts both wild and trainer battles), and the shiny chance increases for that species because of this. This value is also shown in the Pokédex entry screen. +(Will be implemented by me in the next PR) Some moves have changed properties/effects: -- Rapid Spin now raises the user's Speed by 1 stage (100% additional effect - chance). - Howl's target changed to UserAndAllies, and is now a sound move. It is now blocked by Soundproof (I don't know if it should be checking the allies for pbImmunityByAbility, but leaning towards yes; will Volt Absorb block an Electrified Howl?). Needs a new function code, since it now affects targets rather than the user. -- Teleport switches the user out. If the user is a wild Pokémon, ends the battle - instead. -- Curse's Ghost effect now targets a random foe (don't know if it can be non- - adjacent); the target cannot be chosen by the player (it appears to target the - user). -- Look at the moves Nature Power turns into. - Healing Wish's effect and Lunar Dance's effect are no longer used up if a Pokémon that switches to the targeted position can't make use of it. Each - position can only have one of each effect applied at once. -- Multiple Quashed Pokémon now move in order from fastest to slowest, rather - than the order in which they were Quashed. + position can only have one of each effect applied at once. (Will be implemented by me in the next PR) - Parting Shot is able to make the user switch out if its effect is redirected by Mirror Armor. Throat Spray is triggered and applies before the switch. + (The Throat Spray part is done by default) Some abilities have changed effects: -- Intimidate now triggers Rattled. Rattled needs a new ability handler just for - triggering this way. - If another Pokémon faints before a Pokémon with Analytic makes its move, Analytic calculates whether it would have moved before or after the fainted Pokémon. In Gen 8, speed- and priority-modifying effects aren't considered, @@ -40,23 +30,15 @@ Some abilities have changed effects: Some items have changed properties/effects: - Zygarde Cube now changes a Zygarde's ability. -- Ability Capsule/Ability Patch should fail if used on Zygarde. -- If Leppa Berry is forced to be consumed, it will first try to work on a move - with 0 PP left (preferring the earliest such move in the list of moves), and - failing that, the earliest move in the list of moves which has any PP missing - (no matter how much). -- Ensure that Choice items cause different moves to fail (without subtracting - PP) if they were forced to be used by Instruct/Dancer. -- Iron Ball shouldn't modify the effectiveness of Ground moves against a Flying - holder if the holder is grounded by another effect that isn't Iron Ball. Other notes: - In Gen 7+, Shaymin/Hoopa revert their form when withdrawn from storage rather than when deposited. It still also reverts under other conditions. Shaymin reverts its form when deposited in the Day Care (all Gens). - Look at Sweet Scent's out of battle effect, namely whether it should try to - cause a horde battle (and what does that mean in Essentials?). -- Maybe have multiple sets of Pickup items for multiple Gens. + cause a horde battle (and what does that mean in Essentials? Maybe 1v3). +- Maybe have multiple sets of Pickup items for multiple Gens. Probably not. + Gens 7+ seem to have different item probability calculations - investigate. - Add a newer type of berry tree mechanics? Have a separate setting that prevents deterioration? - If a battle ends because of Rocky Helmet damage, the side that the Rocky @@ -68,14 +50,10 @@ Other notes: is probably fine. Can use Fly from within the Town Map if possible. (Good QoL, add if possible.) +(Will be implemented by me in the next PR) Make example event that combines the Gen 8 fossils. -Add AI for new moves/items/abilities. - -What happens to the PP of Iron Head when turned into/from Behemoth Blade/Bash -for Zacian/Zamazenta? - #=============================================================================== # Low priority or ignorable #=============================================================================== @@ -131,6 +109,37 @@ Escape Rope's code now supports both consumable and non-consumable versions, depending on whether it is a key item. All it needs is a proper definition in items.txt. +Add AI for new moves/items/abilities. + +Ability Effect Changes +- Intimidate now triggers Rattled. Rattled needs a new ability handler just for + triggering this way. + +Move Effect Changes +- Teleport switches the user out. If the user is a wild Pokémon, ends the battle + instead. +- Look at the moves Nature Power turns into. (Unchanged since Gen 7) +- Curse's Ghost effect now targets a random foe (don't know if it can be non- + adjacent); the target cannot be chosen by the player (it appears to target the + user). +- Multiple Quashed Pokémon now move in order from fastest to slowest, rather + than the order in which they were Quashed. +- Ensure that Choice items cause different moves to fail (without subtracting + PP) if they were forced to be used by Instruct/Dancer. +- Rapid Spin now raises the user's Speed by 1 stage (100% additional effect + chance). + +Item Effect Changes +- If Leppa Berry is forced to be consumed, it will first try to work on a move + with 0 PP left (preferring the earliest such move in the list of moves), and + failing that, the earliest move in the list of moves which has any PP missing + (no matter how much). +- Ability Capsule/Ability Patch should fail if used on Zygarde. +- Iron Ball shouldn't modify the effectiveness of Ground moves against a Flying + holder if the holder is grounded by another effect that isn't Iron Ball. + Opted to ignore this effect, and to modify the holder's effectiveness no matter + what. + - Multi-Attack's power changed to 120. - Rapid Spin's power changed to 50. - Vice Grip renamed to Vise Grip. @@ -151,4 +160,8 @@ items.txt. - Changes to evolutions due to removal of moss rock/ice rock/magnetic field. - Form differences. +What happens to the PP of Iron Head when turned into/from Behemoth Blade/Bash +for Zacian/Zamazenta? It gets decreased to the total PP if it is higher than the +total PP of the new move, but cannot increase. This is already what happens. + =end diff --git a/PBS/Gen 8/moves.txt b/PBS/Gen 8/moves.txt index 5ec25c95c..33e0c26da 100644 --- a/PBS/Gen 8/moves.txt +++ b/PBS/Gen 8/moves.txt @@ -5389,6 +5389,7 @@ TotalPP = 40 Target = NearOther FunctionCode = 110 Flags = Contact,CanProtect,CanMirrorMove +EffectChance = 100 Description = A spin attack that can also eliminate such moves as Bind, Wrap, Leech Seed, and Spikes. #------------------------------- [SPIKECANNON] @@ -7682,6 +7683,7 @@ Type = PSYCHIC Category = Status Accuracy = 0 TotalPP = 20 +Priority = -6 Target = User FunctionCode = 0EA Description = Use it to flee from any wild Pokémon. It can also warp to the last Pokémon Center visited. diff --git a/PBS/moves.txt b/PBS/moves.txt index 5ec25c95c..916a03d97 100644 --- a/PBS/moves.txt +++ b/PBS/moves.txt @@ -5388,6 +5388,7 @@ Accuracy = 100 TotalPP = 40 Target = NearOther FunctionCode = 110 +EffectChance = 100 Flags = Contact,CanProtect,CanMirrorMove Description = A spin attack that can also eliminate such moves as Bind, Wrap, Leech Seed, and Spikes. #------------------------------- @@ -7683,6 +7684,7 @@ Category = Status Accuracy = 0 TotalPP = 20 Target = User +Priority = -6 FunctionCode = 0EA Description = Use it to flee from any wild Pokémon. It can also warp to the last Pokémon Center visited. #-------------------------------