Added affection effects

This commit is contained in:
Maruno17
2021-10-31 20:43:16 +00:00
parent ee16c22388
commit 0ec67f78fa
11 changed files with 187 additions and 61 deletions

View File

@@ -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)

View File

@@ -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
}
})

View File

@@ -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

View File

@@ -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))

View File

@@ -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

View File

@@ -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
#=============================================================================

View File

@@ -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

View File

@@ -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]

View File

@@ -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

View File

@@ -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

View File

@@ -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