diff --git a/Data/Scripts/002_BattleSettings.rb b/Data/Scripts/002_BattleSettings.rb index 6e675f726..f5e717cc2 100644 --- a/Data/Scripts/002_BattleSettings.rb +++ b/Data/Scripts/002_BattleSettings.rb @@ -28,6 +28,18 @@ module Settings #============================================================================= + # Whether Pokémon with high happiness will gain more Exp from battles, have a + # chance of avoiding/curing negative effects by themselves, resisting + # fainting, etc. + AFFECTION_EFFECTS = false + # Whether a Pokémon's happiness is limited to 179, and can only be increased + # further with friendship-raising berries. Related to AFFECTION_EFFECTS by + # default as affection effects only start applying above a happiness of 179. + # Also lowers the happiness evolution threshold to 160. + APPLY_HAPPINESS_SOFT_CAP = AFFECTION_EFFECTS + + #============================================================================= + # Whether X items (X Attack, etc.) raise their stat by 2 stages (true) or 1 # (false). X_STAT_ITEMS_RAISE_BY_TWO_STAGES = (MECHANICS_GENERATION >= 7) diff --git a/Data/Scripts/010_Data/001_Hardcoded data/007_Evolution.rb b/Data/Scripts/010_Data/001_Hardcoded data/007_Evolution.rb index 25a10152e..21bf84c26 100644 --- a/Data/Scripts/010_Data/001_Hardcoded data/007_Evolution.rb +++ b/Data/Scripts/010_Data/001_Hardcoded data/007_Evolution.rb @@ -279,7 +279,7 @@ GameData::Evolution.register({ :id => :Happiness, :minimum_level => 1, # Needs any level up :level_up_proc => proc { |pkmn, parameter| - next pkmn.happiness >= 220 + next pkmn.happiness >= (Settings::APPLY_HAPPINESS_SOFT_CAP) ? 160 : 220 } }) @@ -287,7 +287,7 @@ GameData::Evolution.register({ :id => :HappinessMale, :minimum_level => 1, # Needs any level up :level_up_proc => proc { |pkmn, parameter| - next pkmn.happiness >= 220 && pkmn.male? + next pkmn.happiness >= ((Settings::APPLY_HAPPINESS_SOFT_CAP) ? 160 : 220) && pkmn.male? } }) @@ -295,7 +295,7 @@ GameData::Evolution.register({ :id => :HappinessFemale, :minimum_level => 1, # Needs any level up :level_up_proc => proc { |pkmn, parameter| - next pkmn.happiness >= 220 && pkmn.female? + next pkmn.happiness >= ((Settings::APPLY_HAPPINESS_SOFT_CAP) ? 160 : 220) && pkmn.female? } }) @@ -303,7 +303,7 @@ GameData::Evolution.register({ :id => :HappinessDay, :minimum_level => 1, # Needs any level up :level_up_proc => proc { |pkmn, parameter| - next pkmn.happiness >= 220 && PBDayNight.isDay? + next pkmn.happiness >= ((Settings::APPLY_HAPPINESS_SOFT_CAP) ? 160 : 220) && PBDayNight.isDay? } }) @@ -311,7 +311,7 @@ GameData::Evolution.register({ :id => :HappinessNight, :minimum_level => 1, # Needs any level up :level_up_proc => proc { |pkmn, parameter| - next pkmn.happiness >= 220 && PBDayNight.isNight? + next pkmn.happiness >= ((Settings::APPLY_HAPPINESS_SOFT_CAP) ? 160 : 220) && PBDayNight.isNight? } }) @@ -320,7 +320,7 @@ GameData::Evolution.register({ :parameter => :Move, :minimum_level => 1, # Needs any level up :level_up_proc => proc { |pkmn, parameter| - if pkmn.happiness >= 220 + if pkmn.happiness >= (Settings::APPLY_HAPPINESS_SOFT_CAP) ? 160 : 220 next pkmn.moves.any? { |m| m && m.id == parameter } end } @@ -331,7 +331,7 @@ GameData::Evolution.register({ :parameter => :Type, :minimum_level => 1, # Needs any level up :level_up_proc => proc { |pkmn, parameter| - if pkmn.happiness >= 220 + if pkmn.happiness >= (Settings::APPLY_HAPPINESS_SOFT_CAP) ? 160 : 220 next pkmn.moves.any? { |m| m && m.type == parameter } end } @@ -342,7 +342,7 @@ GameData::Evolution.register({ :parameter => :Item, :minimum_level => 1, # Needs any level up :level_up_proc => proc { |pkmn, parameter| - next pkmn.item == parameter && pkmn.happiness >= 220 + next pkmn.item == parameter && pkmn.happiness >= (Settings::APPLY_HAPPINESS_SOFT_CAP) ? 160 : 220 }, :after_evolution_proc => proc { |pkmn, new_species, parameter, evo_species| next false if evo_species != new_species || !pkmn.hasItem?(parameter) @@ -443,7 +443,7 @@ GameData::Evolution.register({ :parameter => :Item, :minimum_level => 1, # Needs any level up :level_up_proc => proc { |pkmn, parameter| - next pkmn.item == parameter && pkmn.happiness >= 220 + next pkmn.item == parameter && pkmn.happiness >= (Settings::APPLY_HAPPINESS_SOFT_CAP) ? 160 : 220 }, :after_evolution_proc => proc { |pkmn, new_species, parameter, evo_species| next false if evo_species != new_species || !pkmn.hasItem?(parameter) @@ -555,7 +555,7 @@ GameData::Evolution.register({ :id => :ItemHappiness, :parameter => :Item, :use_item_proc => proc { |pkmn, parameter, item| - next item == parameter && pkmn.happiness >= 220 + next item == parameter && pkmn.happiness >= (Settings::APPLY_HAPPINESS_SOFT_CAP) ? 160 : 220 } }) diff --git a/Data/Scripts/011_Battle/001_Battler/001_PokeBattle_Battler.rb b/Data/Scripts/011_Battle/001_Battler/001_PokeBattle_Battler.rb index 6e4eab6d3..71327daef 100644 --- a/Data/Scripts/011_Battle/001_Battler/001_PokeBattle_Battler.rb +++ b/Data/Scripts/011_Battle/001_Battler/001_PokeBattle_Battler.rb @@ -128,9 +128,10 @@ class PokeBattle_Battler #============================================================================= # Properties from Pokémon #============================================================================= - def happiness; return @pokemon ? @pokemon.happiness : 0; end - def nature; return @pokemon ? @pokemon.nature : 0; end - def pokerusStage; return @pokemon ? @pokemon.pokerusStage : 0; end + def happiness; return @pokemon ? @pokemon.happiness : 0; end + def affection_level; return @pokemon ? @pokemon.affection_level : 2; end + def nature; return @pokemon ? @pokemon.nature : 0; end + def pokerusStage; return @pokemon ? @pokemon.pokerusStage : 0; end #============================================================================= # Mega Evolution, Primal Reversion, Shadow Pokémon diff --git a/Data/Scripts/011_Battle/001_Battler/009_Battler_UseMove_SuccessChecks.rb b/Data/Scripts/011_Battle/001_Battler/009_Battler_UseMove_SuccessChecks.rb index 21f7fb441..d20eb682f 100644 --- a/Data/Scripts/011_Battle/001_Battler/009_Battler_UseMove_SuccessChecks.rb +++ b/Data/Scripts/011_Battle/001_Battler/009_Battler_UseMove_SuccessChecks.rb @@ -571,7 +571,9 @@ class PokeBattle_Battler # Message shown when a move fails the per-hit success check above. #============================================================================= def pbMissMessage(move,user,target) - if move.pbTarget(user).num_targets > 1 + if target.damageState.affection_missed + @battle.pbDisplay(_INTL("{1} avoided the move in time with your shout!", target.pbThis)) + elsif move.pbTarget(user).num_targets > 1 @battle.pbDisplay(_INTL("{1} avoided the attack!",target.pbThis)) elsif target.effects[PBEffects::TwoTurnAttack] @battle.pbDisplay(_INTL("{1} avoided the attack!",target.pbThis)) diff --git a/Data/Scripts/011_Battle/002_Move/002_Move_Usage.rb b/Data/Scripts/011_Battle/002_Move/002_Move_Usage.rb index 570499e2c..a23131f1d 100644 --- a/Data/Scripts/011_Battle/002_Move/002_Move_Usage.rb +++ b/Data/Scripts/011_Battle/002_Move/002_Move_Usage.rb @@ -208,6 +208,13 @@ class PokeBattle_Move elsif target.hasActiveItem?(:FOCUSBAND) && @battle.pbRandom(100)<10 target.damageState.focusBand = true damage -= 1 + elsif Settings::AFFECTION_EFFECTS && @battle.internalBattle && + target.pbOwnedByPlayer? && !target.mega? + chance = [0, 0, 0, 10, 15, 25][target.affection_level] + if chance > 0 && @battle.pbRandom(100) < chance + target.damageState.affection_endured = true + damage -= 1 + end end end end @@ -282,10 +289,19 @@ class PokeBattle_Move end if target.damageState.critical $game_temp.party_critical_hits_dealt[user.pokemonIndex] += 1 if user.pbOwnedByPlayer? - if numTargets>1 - @battle.pbDisplay(_INTL("A critical hit on {1}!",target.pbThis(true))) + if target.damageState.affection_critical + if numTargets > 1 + @battle.pbDisplay(_INTL("{1} landed a critical hit on {2}, wishing to be praised!", + user.pbThis, target.pbThis(true))) + else + @battle.pbDisplay(_INTL("{1} landed a critical hit, wishing to be praised!", user.pbThis)) + end else - @battle.pbDisplay(_INTL("A critical hit!")) + if numTargets > 1 + @battle.pbDisplay(_INTL("A critical hit on {1}!", target.pbThis(true))) + else + @battle.pbDisplay(_INTL("A critical hit!")) + end end end # Effectiveness message, for moves with 1 hit @@ -333,6 +349,8 @@ class PokeBattle_Move elsif target.damageState.focusBand @battle.pbCommonAnimation("UseItem",target) @battle.pbDisplay(_INTL("{1} hung on using its Focus Band!",target.pbThis)) + elsif target.damageState.affection_endured + @battle.pbDisplay(_INTL("{1} toughed it out so you wouldn't feel sad!", target.pbThis)) end end diff --git a/Data/Scripts/011_Battle/002_Move/003_Move_Usage_Calculations.rb b/Data/Scripts/011_Battle/002_Move/003_Move_Usage_Calculations.rb index 029c02e7e..4c557825d 100644 --- a/Data/Scripts/011_Battle/002_Move/003_Move_Usage_Calculations.rb +++ b/Data/Scripts/011_Battle/002_Move/003_Move_Usage_Calculations.rb @@ -115,8 +115,16 @@ class PokeBattle_Move accuracy = (accuracy * modifiers[:accuracy_multiplier]).round evasion = (evasion * modifiers[:evasion_multiplier]).round evasion = 1 if evasion < 1 + threshold = modifiers[:base_accuracy] * accuracy / evasion # Calculation - return @battle.pbRandom(100) < modifiers[:base_accuracy] * accuracy / evasion + r = @battle.pbRandom(100) + if Settings::AFFECTION_EFFECTS && @battle.internalBattle && + target.pbOwnedByPlayer? && target.affection_level == 5 && !target.mega? + return true if r < threshold - 10 + target.damageState.affection_missed = true if r < threshold + return false + end + return r < threshold end def pbCalcAccuracyModifiers(user,target,modifiers) @@ -199,7 +207,15 @@ class PokeBattle_Move c += 1 if user.inHyperMode? && @type == :SHADOW c = ratios.length-1 if c>=ratios.length # Calculation - return @battle.pbRandom(ratios[c])==0 + return true if ratio[c] == 1 + r = @battle.pbRandom(ratios[c]) + return true if r == 0 + if r == 1 && Settings::AFFECTION_EFFECTS && @battle.internalBattle && + user.pbOwnedByPlayer? && user.affection_level == 5 && !target.mega? + target.damageState.affection_critical = true + return true + end + return false end #============================================================================= diff --git a/Data/Scripts/011_Battle/003_Battle/004_Battle_ExpAndMoveLearning.rb b/Data/Scripts/011_Battle/003_Battle/004_Battle_ExpAndMoveLearning.rb index e2c7ed4b2..8b6b90104 100644 --- a/Data/Scripts/011_Battle/003_Battle/004_Battle_ExpAndMoveLearning.rb +++ b/Data/Scripts/011_Battle/003_Battle/004_Battle_ExpAndMoveLearning.rb @@ -152,6 +152,11 @@ class PokeBattle_Battle i = BattleHandlers.triggerExpGainModifierItem(@initialItems[0][idxParty],pkmn,exp) end exp = i if i>=0 + # Boost Exp gained with high affection + if Settings::AFFECTION_EFFECTS && @internalBattle && pkmn.affection_level >= 4 && !pkmn.mega? + exp = exp * 6 / 5 + isOutsider = true # To show the "boosted Exp" message + end # Make sure Exp doesn't exceed the maximum expFinal = growth_rate.add_exp(pkmn.exp, exp) expGained = expFinal-pkmn.exp diff --git a/Data/Scripts/011_Battle/003_Battle/012_Battle_Phase_EndOfRound.rb b/Data/Scripts/011_Battle/003_Battle/012_Battle_Phase_EndOfRound.rb index d041f3450..59b68b202 100644 --- a/Data/Scripts/011_Battle/003_Battle/012_Battle_Phase_EndOfRound.rb +++ b/Data/Scripts/011_Battle/003_Battle/012_Battle_Phase_EndOfRound.rb @@ -283,6 +283,28 @@ class PokeBattle_Battle # Black Sludge, Leftovers BattleHandlers.triggerEORHealingItem(b.item,b,self) if b.itemActive? end + # Self-curing of status due to affection + if Settings::AFFECTION_EFFECTS && @internalBattle + priority.each do |b| + next if b.fainted? || b.status == :NONE + next if !b.pbOwnedByPlayer? || b.affection_level < 4 || b.mega? + next if pbRandom(100) < 80 + old_status = b.status + b.pbCureStatus(false) + case old_status + when :SLEEP + pbDisplay(_INTL("{1} shook itself awake so you wouldn't worry!", b.pbThis)) + when :POISON + pbDisplay(_INTL("{1} managed to expel the poison so you wouldn't worry!", b.pbThis)) + when :BURN + pbDisplay(_INTL("{1} healed its burn with its sheer determination so you wouldn't worry!", b.pbThis)) + when :PARALYSIS + pbDisplay(_INTL("{1} gathered all its energy to break through its paralysis so you wouldn't worry!", b.pbThis)) + when :FROZEN + pbDisplay(_INTL("{1} melted the ice with its fiery determination so you wouldn't worry!", b.pbThis)) + end + end + end # Aqua Ring priority.each do |b| next if !b.effects[PBEffects::AquaRing] diff --git a/Data/Scripts/011_Battle/007_PokeBattle_DamageState.rb b/Data/Scripts/011_Battle/007_PokeBattle_DamageState.rb index 9c59a7c8b..fd8569265 100644 --- a/Data/Scripts/011_Battle/007_PokeBattle_DamageState.rb +++ b/Data/Scripts/011_Battle/007_PokeBattle_DamageState.rb @@ -8,10 +8,12 @@ class PokeBattle_DamageState attr_accessor :fainted # Whether battler was knocked out by the move attr_accessor :missed # Whether the move failed the accuracy check + attr_accessor :affection_missed attr_accessor :invulnerable # If the move missed due to two turn move invulnerability attr_accessor :calcDamage # Calculated damage attr_accessor :hpLost # HP lost by opponent, inc. HP lost by a substitute attr_accessor :critical # Critical hit flag + attr_accessor :affection_critical attr_accessor :substitute # Whether a substitute took the damage attr_accessor :focusBand # Focus Band used attr_accessor :focusSash # Focus Sash used @@ -19,34 +21,38 @@ class PokeBattle_DamageState attr_accessor :disguise # Disguise ability used attr_accessor :iceFace # Ice Face ability used attr_accessor :endured # Damage was endured + attr_accessor :affection_endured attr_accessor :berryWeakened # Whether a type-resisting berry was used def initialize; reset; end def reset - @typeMod = Effectiveness::INEFFECTIVE - @unaffected = false - @protected = false - @missed = false - @invulnerable = false - @magicCoat = false - @magicBounce = false - @totalHPLost = 0 - @fainted = false + @typeMod = Effectiveness::INEFFECTIVE + @unaffected = false + @protected = false + @missed = false + @affection_missed = false + @invulnerable = false + @magicCoat = false + @magicBounce = false + @totalHPLost = 0 + @fainted = false resetPerHit end def resetPerHit - @calcDamage = 0 - @hpLost = 0 - @critical = false - @substitute = false - @focusBand = false - @focusSash = false - @sturdy = false - @disguise = false - @iceFace = false - @endured = false - @berryWeakened = false + @calcDamage = 0 + @hpLost = 0 + @critical = false + @affection_critical = false + @substitute = false + @focusBand = false + @focusSash = false + @sturdy = false + @disguise = false + @iceFace = false + @endured = false + @affection_endured = false + @berryWeakened = false end end diff --git a/Data/Scripts/014_Pokemon/001_Pokemon.rb b/Data/Scripts/014_Pokemon/001_Pokemon.rb index 5616bf4ef..7cf1b02ba 100644 --- a/Data/Scripts/014_Pokemon/001_Pokemon.rb +++ b/Data/Scripts/014_Pokemon/001_Pokemon.rb @@ -884,6 +884,17 @@ class Pokemon return ret end + def affection_level + case @happiness + when 0...100 then return 0 + when 100...150 then return 1 + when 150...200 then return 2 + when 200...230 then return 3 + when 230...255 then return 4 + end + return 5 # 255 + end + # Changes the happiness of this Pokémon depending on what happened to change it. # @param method [String] the happiness changing method (e.g. 'walking') def changeHappiness(method) @@ -921,6 +932,9 @@ class Pokemon gain += 1 if @obtain_map == $game_map.map_id gain += 1 if @poke_ball == :LUXURYBALL gain = (gain * 1.5).floor if hasItem?(:SOOTHEBELL) + if Settings::APPLY_HAPPINESS_SOFT_CAP && method != "evberry" + gain = gain.clamp(0, 179 - @happiness) + end end @happiness = (@happiness + gain).clamp(0, 255) end diff --git a/Data/Scripts/Gen 8 notes.txt b/Data/Scripts/Gen 8 notes.txt index face03194..240035807 100644 --- a/Data/Scripts/Gen 8 notes.txt +++ b/Data/Scripts/Gen 8 notes.txt @@ -7,8 +7,45 @@ Other notes: - If a battle ends because of Rocky Helmet damage, the side that the Rocky Helmet holder is on should lose (Gen 7+) or win (Gen 6-). +- If Neutralizing Gas switches in and negates Unnerve, should it cause an + immediate triggering of held berries? Probably. +- Emergency Exit/Wimp Out should NOT trigger if the bearer gained that ability + part-way through the move's usage (i.e. via Wandering Spirit swapping + abilities). +- Imposter should only trigger upon being sent in, and not by any re-triggering + of switch-in abilities. +- The messages for a held item boosting stats are slightly different to what + they currently are: + "The Weakness Policy sharply raised {1}'s Attack!" + "The Weakness Policy sharply raised {1}'s Sp. Atk!" + "The Weakness Policy was used up..." -Make example event that combines the Gen 8 fossils. +New evolution methods: +- Milcery: spinning while holding an item. (Doesn't suit our control scheme. + We're not adding a way to easily spin on the spot just for this, cf. + not having to turn your computer upside-down to evolve Inkay.) +- Galarian Yamask: going to a particular spot after a battle in which it lost + 49+ HP from a single attack and hasn't fainted since then; + healing doesn't affect this. (Utter nonsense, find a better + way - just evolve after a battle in which the damage was + taken.) Confirmed that the damage has to be dealt in a single + attack, not spread across multiple ones. + +- Ask whether a captured Pokémon, or an added Pokémon, should be put in storage + or added to the party if the party is full. Also provide the option to look at + its Pokédex entry. Have a way to force adding it to the party for plot + purposes (battle rule?). + +- If two Pokémon of the same species are in the Day Care, and one knows an egg + move(s) the other doesn't, and the other has an empty move slot(s), the other + will learn the egg move(s) from the one after a time. Egg moves are checked in + the order they're known by the one Pokémon. No egg moves are learned if the + other Pokémon doesn't have an empty move slot. Volt Tackle cannot be learned + this way. Gender is irrelevant. This is a feature of a Pokémon Nursery, which + is like the Day Care but is only for breeding and the deposited Pokémon don't + gain Exp (the fee is $500 per Pokémon up-front). The time it takes to do this + is apparently the same as egg generation (e.g. a chance every 255 steps), but + the parents don't need to be able to breed in order to learn egg moves. #=============================================================================== # Low priority or ignorable @@ -21,19 +58,6 @@ toggled. (Probably don't bother implementing.) Bicycle that can work on water. -Remote access to storage boxes via the party screen if you have the Pokémon Box -Link item (and it's allowed to be used - in Gyms and some other places it's -forbidden). - -New evolution methods: -- Milcery: spinning while holding an item. (Doesn't suit our control scheme. - We're not adding a way to easily spin on the spot just for this, cf. - not having to turn your computer upside-down to evolve Inkay.) -- Galarian Yamask: going to a particular spot after a battle in which it lost - 49+ HP from a single attack and hasn't fainted since then; - healing doesn't affect this. (Utter nonsense, find a better - way.) - I think there are some alternate forms which don't have a hidden ability while their base forms do. I don't think the compiler supports this, and instead treats Abilities and HiddenAbilities separately. Can work around this by setting @@ -48,14 +72,6 @@ Maybe have multiple sets of Pickup items for multiple Gens. Probably not. Gens Add a newer type of berry tree mechanics? Have a separate setting that prevents deterioration? -The happiness evolution threshold value has lowered from 220 to 160. This is -because, in Gen 8, you have to use Pokémon Camp or berries to raise a Pokémon's -happiness above 179, which in turn is because affection effects have been added -(chance of resisting a KO, chance of shaking off a status problem, etc.) that -apply above 179 happiness. Pokémon Camp will not be added. Affection effects and -the 179 soft cap/160 evolution threshold may be added (the latter two should be -treated as related rather than separate settings). - Some abilities have changed effects: - 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 @@ -172,4 +188,18 @@ Some moves have changed properties/effects: by Mirror Armor. Throat Spray is triggered and applies before the switch. (The Throat Spray part is done by default). All this already works this way. +Remote access to storage boxes via the party screen if you have the Pokémon Box +Link item (and it's allowed to be used - in Gyms and some other places it's +forbidden). + +Make example event that combines the Gen 8 fossils. + +The happiness evolution threshold value has lowered from 220 to 160. This is +because, in Gen 8, you have to use Pokémon Camp or berries to raise a Pokémon's +happiness above 179, which in turn is because affection effects have been added +(chance of resisting a KO, chance of shaking off a status problem, etc.) that +apply above 179 happiness. Pokémon Camp will not be added. Affection effects and +the 179 soft cap/160 evolution threshold may be added (the latter two should be +treated as related rather than separate settings). + =end