Files
infinitefusion-e18/Data/Scripts/016_Pokemon/004_Pokemon_ShadowPokemon.rb
2020-11-19 21:00:29 +00:00

705 lines
21 KiB
Ruby

=begin
All types except Shadow have Shadow as a weakness.
Shadow has Shadow as a resistance.
On a side note, the Shadow moves in Colosseum will not be affected by Weaknesses
or Resistances, while in XD the Shadow-type is Super-Effective against all other
types.
2/5 - display nature
XD - Shadow Rush -- 55, 100 - Deals damage.
Colosseum - Shadow Rush -- 90, 100
If this attack is successful, user loses half of HP lost by opponent due to this
attack (recoil). If user is in Hyper Mode, this attack has a good chance for a
critical hit.
=end
#===============================================================================
# Purify a Shadow Pokémon.
#===============================================================================
def pbPurify(pokemon,scene)
return if pokemon.heartgauge!=0 || !pokemon.shadow
return if !pokemon.savedev && !pokemon.savedexp
pokemon.shadow = false
pokemon.giveRibbon(PBRibbons::NATIONAL)
scene.pbDisplay(_INTL("{1} opened the door to its heart!",pokemon.name))
old_moves = []
pokemon.moves.each { |m| old_moves.push(m.id) }
pokemon.pbUpdateShadowMoves
pokemon.moves.each_with_index do |m, i|
next if m == old_moves[i]
scene.pbDisplay(_INTL("{1} regained the move {2}!", pokemon.name, m.name))
end
pokemon.pbRecordFirstMoves
if pokemon.savedev
for i in 0...6
pbApplyEVGain(pokemon,i,pokemon.savedev[i])
end
pokemon.savedev = nil
end
newexp = PBExperience.pbAddExperience(pokemon.exp,pokemon.savedexp||0,pokemon.growthrate)
pokemon.savedexp = nil
newlevel = PBExperience.pbGetLevelFromExperience(newexp,pokemon.growthrate)
curlevel = pokemon.level
if newexp!=pokemon.exp
scene.pbDisplay(_INTL("{1} regained {2} Exp. Points!",pokemon.name,newexp-pokemon.exp))
end
if newlevel==curlevel
pokemon.exp = newexp
pokemon.calcStats
else
pbChangeLevel(pokemon,newlevel,scene) # for convenience
pokemon.exp = newexp
end
speciesname = PBSpecies.getName(pokemon.species)
if scene.pbConfirm(_INTL("Would you like to give a nickname to {1}?",speciesname))
newname = pbEnterPokemonName(_INTL("{1}'s nickname?",speciesname),
0, Pokemon::MAX_NAME_SIZE, "", pokemon)
pokemon.name = newname if newname!=""
end
end
def pbApplyEVGain(pokemon,ev,evgain)
totalev = 0
for i in 0...6
totalev += pokemon.ev[i]
end
if totalev+evgain>Pokemon::EV_LIMIT # Can't exceed overall limit
evgain -= totalev+evgain-Pokemon::EV_LIMIT
end
if pokemon.ev[ev]+evgain>Pokemon::EV_STAT_LIMIT
evgain -= totalev+evgain-Pokemon::EV_STAT_LIMIT
end
if evgain>0
pokemon.ev[ev] += evgain
end
end
def pbReplaceMoves(pkmn, new_moves)
return if !pkmn
new_moves.each do |move|
next if !move || pkmn.hasMove?(move)
# Find a move slot to put move into
for i in 0...Pokemon::MAX_MOVES
if i >= pkmn.numMoves
# Empty slot; add the new move there
pkmn.pbLearnMove(move)
break
elsif !new_moves.include?(pkmn.moves[i].id)
# Known move that isn't a move to be relearned; replace it
pkmn.moves[i].id = move
break
end
end
end
end
#===============================================================================
# Relic Stone scene.
#===============================================================================
class RelicStoneScene
def pbPurify
end
def pbUpdate
pbUpdateSpriteHash(@sprites)
end
def pbEndScene
pbFadeOutAndHide(@sprites) { pbUpdate }
pbDisposeSpriteHash(@sprites)
@viewport.dispose
end
def pbDisplay(msg,brief=false)
UIHelper.pbDisplay(@sprites["msgwindow"],msg,brief) { pbUpdate }
end
def pbConfirm(msg)
UIHelper.pbConfirm(@sprites["msgwindow"],msg) { pbUpdate }
end
def pbStartScene(pokemon)
@sprites = {}
@viewport = Viewport.new(0,0,Graphics.width,Graphics.height)
@viewport.z = 99999
@pokemon = pokemon
addBackgroundPlane(@sprites,"bg","relicstonebg",@viewport)
@sprites["msgwindow"] = Window_AdvancedTextPokemon.new("")
@sprites["msgwindow"].viewport = @viewport
@sprites["msgwindow"].x = 0
@sprites["msgwindow"].y = Graphics.height-96
@sprites["msgwindow"].width = Graphics.width
@sprites["msgwindow"].height = 96
@sprites["msgwindow"].text = ""
@sprites["msgwindow"].visible = true
pbDeactivateWindows(@sprites)
pbFadeInAndShow(@sprites) { pbUpdate }
end
end
class RelicStoneScreen
def initialize(scene)
@scene = scene
end
def pbDisplay(x)
@scene.pbDisplay(x)
end
def pbConfirm(x)
@scene.pbConfirm(x)
end
def pbUpdate; end
def pbRefresh; end
def pbStartScreen(pokemon)
@scene.pbStartScene(pokemon)
@scene.pbPurify
pbPurify(pokemon,self)
@scene.pbEndScene
end
end
def pbRelicStoneScreen(pkmn)
retval = true
pbFadeOutIn {
scene = RelicStoneScene.new
screen = RelicStoneScreen.new(scene)
retval = screen.pbStartScreen(pkmn)
}
return retval
end
#===============================================================================
#
#===============================================================================
def pbIsPurifiable?(pkmn)
return false if !pkmn
return false if pkmn.isSpecies?(:LUGIA)
return false if !pkmn.shadowPokemon? || pkmn.heartgauge>0
return true
end
def pbHasPurifiableInParty?
return $Trainer.party.any? { |pkmn| pbIsPurifiable?(pkmn) }
end
def pbRelicStone
if !pbHasPurifiableInParty?
pbMessage(_INTL("You have no Pokémon that can be purified."))
return
end
pbMessage(_INTL("There's a Pokémon that may open the door to its heart!"))
# Choose a purifiable Pokemon
pbChoosePokemon(1,2,proc { |pkmn|
!pkmn.egg? && pkmn.hp>0 && pkmn.shadowPokemon? && pkmn.heartgauge==0
})
if $game_variables[1]>=0
pbRelicStoneScreen($Trainer.party[$game_variables[1]])
end
end
def pbReadyToPurify(pkmn)
return unless pkmn && pkmn.shadowPokemon?
pkmn.pbUpdateShadowMoves
if pkmn.heartgauge==0
pbMessage(_INTL("{1} can now be purified!",pkmn.name))
end
end
#===============================================================================
# Pokémon class.
#===============================================================================
class Pokemon
attr_writer :heartgauge
attr_accessor :shadow
attr_writer :hypermode
attr_accessor :savedev
attr_accessor :savedexp
attr_accessor :shadowmoves
attr_accessor :shadowmovenum
HEARTGAUGESIZE = 3840
alias :__shadow_expeq :exp=
def exp=(value)
if shadowPokemon?
@savedexp += value-self.exp
else
__shadow_expeq(value)
end
end
alias :__shadow_hpeq :hp=
def hp=(value)
__shadow_hpeq(value)
@hypermode = false if value<=0
end
def hypermode
return (self.heartgauge==0 || self.hp==0) ? false : @hypermode
end
def heartgauge
return @heartgauge || 0
end
def heartStage
return 0 if !@shadow
hg = HEARTGAUGESIZE/5.0
return ([self.heartgauge,HEARTGAUGESIZE].min/hg).ceil
end
def adjustHeart(value)
return if !@shadow
@heartgauge = 0 if !@heartgauge
@heartgauge += value
@heartgauge = HEARTGAUGESIZE if @heartgauge>HEARTGAUGESIZE
@heartgauge = 0 if @heartgauge<0
end
def shadowPokemon?
return @shadow && @heartgauge && @heartgauge>=0
end
alias :isShadow? :shadowPokemon?
def makeShadow
self.shadow = true
self.heartgauge = HEARTGAUGESIZE
self.savedexp = 0
self.savedev = [0,0,0,0,0,0]
self.shadowmoves = []
# Retrieve Shadow moveset for this Pokémon
shadow_moveset = pbLoadShadowMovesets[self.fSpecies]
shadow_moveset = pbLoadShadowMovesets[self.species] if !shadow_moveset || shadow_moveset.length == 0
# Record this Pokémon's Shadow moves
if shadow_moveset && shadow_moveset.length > 0
for i in 0...[shadow_moveset.length, MAX_MOVES].min
self.shadowmoves[i] = shadow_moveset[i]
end
self.shadowmovenum = shadow_moveset.length
else
# No Shadow moveset defined; just use Shadow Rush
self.shadowmoves[0] = :SHADOWRUSH if GameData::Move.exists?(:SHADOWRUSH)
self.shadowmovenum = 1
end
# Record this Pokémon's original moves
@moves.each_with_index { |m, i| self.shadowmoves[MAX_MOVES + i] = m.id }
# Update moves
pbUpdateShadowMoves
end
def pbUpdateShadowMoves(relearn_all_moves = false)
return if !@shadowmoves
# Not a Shadow Pokémon (any more); relearn all its original moves
if !@shadow
if @shadowmoves.length > MAX_MOVES
new_moves = []
@shadowmoves.each_with_index { |m, i| new_moves.push(m) if m && i >= MAX_MOVES }
pbReplaceMoves(self, new_moves)
end
@shadowmoves = nil
return
end
# Is a Shadow Pokémon; ensure it knows the appropriate moves depending on its heart stage
m = @shadowmoves
# Start with all Shadow moves
new_moves = []
@shadowmoves.each_with_index { |m, i| new_moves.push(m) if m && i < MAX_MOVES }
# Add some original moves (skipping ones in the same slot as a Shadow Move)
num_original_moves = (relearn_all_moves) ? 3 : [3, 3, 2, 1, 1, 0][self.heartStage]
if num_original_moves > 0
relearned_count = 0
@shadowmoves.each_with_index do |m, i|
next if !m || i < MAX_MOVES + @shadowmovenum
new_moves.push(m)
relearned_count += 1
break if relearned_count >= num_original_moves
end
end
# Relearn Shadow moves plus some original moves (may not change anything)
pbReplaceMoves(self, new_moves)
end
alias :__shadow_clone :clone
def clone
ret = __shadow_clone
ret.savedev = self.savedev.clone if self.savedev
ret.shadowmoves = self.shadowmoves.clone if self.shadowmoves
return ret
end
end
#===============================================================================
# Shadow Pokémon in battle.
#===============================================================================
class PokeBattle_Battle
alias __shadow__pbCanUseItemOnPokemon? pbCanUseItemOnPokemon?
def pbCanUseItemOnPokemon?(item,pkmn,battler,scene,showMessages=true)
ret = __shadow__pbCanUseItemOnPokemon?(item,pkmn,battler,scene,showMessages)
if ret && pkmn.hypermode && ![:JOYSCENT, :EXCITESCENT, :VIVIDSCENT].include?(item)
scene.pbDisplay(_INTL("This item can't be used on that Pokémon."))
return false
end
return ret
end
end
class PokeBattle_Battler
alias __shadow__pbInitPokemon pbInitPokemon
def pbInitPokemon(*arg)
if self.pokemonIndex>0 && inHyperMode?
# Called out of Hyper Mode
self.pokemon.hypermode = false
self.pokemon.adjustHeart(-50)
end
__shadow__pbInitPokemon(*arg)
# Called into battle
if shadowPokemon?
if hasConst?(PBTypes,:SHADOW)
self.type1 = getID(PBTypes,:SHADOW)
self.type2 = getID(PBTypes,:SHADOW)
end
self.pokemon.adjustHeart(-30) if pbOwnedByPlayer?
end
end
def shadowPokemon?
p = self.pokemon
return p && p.respond_to?("shadowPokemon?") && p.shadowPokemon?
end
alias isShadow? shadowPokemon?
def inHyperMode?
return false if fainted?
p = self.pokemon
return p && p.respond_to?("hypermode") && p.hypermode
end
def pbHyperMode
return if fainted? || !shadowPokemon? || inHyperMode?
p = self.pokemon
if @battle.pbRandom(p.heartgauge)<=Pokemon::HEARTGAUGESIZE/4
p.hypermode = true
@battle.pbDisplay(_INTL("{1}'s emotions rose to a fever pitch!\nIt entered Hyper Mode!",self.pbThis))
end
end
def pbHyperModeObedience(move)
return true if !inHyperMode?
return true if !move || isConst?(move.type,PBTypes,:SHADOW)
return rand(100)<20
end
end
#===============================================================================
# Shadow item effects.
#===============================================================================
def pbRaiseHappinessAndReduceHeart(pokemon,scene,amount)
if !pokemon.shadowPokemon?
scene.pbDisplay(_INTL("It won't have any effect."))
return false
end
if pokemon.happiness==255 && pokemon.heartgauge==0
scene.pbDisplay(_INTL("It won't have any effect."))
return false
elsif pokemon.happiness==255
pokemon.adjustHeart(-amount)
scene.pbDisplay(_INTL("{1} adores you!\nThe door to its heart opened a little.",pokemon.name))
pbReadyToPurify(pokemon)
return true
elsif pokemon.heartgauge==0
pokemon.changeHappiness("vitamin")
scene.pbDisplay(_INTL("{1} turned friendly.",pokemon.name))
return true
else
pokemon.changeHappiness("vitamin")
pokemon.adjustHeart(-amount)
scene.pbDisplay(_INTL("{1} turned friendly.\nThe door to its heart opened a little.",pokemon.name))
pbReadyToPurify(pokemon)
return true
end
end
ItemHandlers::UseOnPokemon.add(:JOYSCENT,proc { |item,pokemon,scene|
pbRaiseHappinessAndReduceHeart(pokemon,scene,500)
})
ItemHandlers::UseOnPokemon.add(:EXCITESCENT,proc { |item,pokemon,scene|
pbRaiseHappinessAndReduceHeart(pokemon,scene,1000)
})
ItemHandlers::UseOnPokemon.add(:VIVIDSCENT,proc { |item,pokemon,scene|
pbRaiseHappinessAndReduceHeart(pokemon,scene,2000)
})
ItemHandlers::UseOnPokemon.add(:TIMEFLUTE,proc { |item,pokemon,scene|
if !pokemon.shadowPokemon?
scene.pbDisplay(_INTL("It won't have any effect."))
next false
end
pokemon.heartgauge = 0
pbReadyToPurify(pokemon)
next true
})
ItemHandlers::CanUseInBattle.add(:JOYSCENT,proc { |item,pokemon,battler,move,firstAction,battle,scene,showMessages|
if !battler || !battler.shadowPokemon? || !battler.inHyperMode?
scene.pbDisplay(_INTL("It won't have any effect.")) if showMessages
next false
end
next true
})
ItemHandlers::CanUseInBattle.copy(:JOYSCENT,:EXCITESCENT,:VIVIDSCENT)
ItemHandlers::BattleUseOnBattler.add(:JOYSCENT,proc { |item,battler,scene|
battler.pokemon.hypermode = false
battler.pokemon.adjustHeart(-500)
scene.pbDisplay(_INTL("{1} came to its senses from the {2}!",battler.pbThis,GameData::Item.get(item).name))
next true
})
ItemHandlers::BattleUseOnBattler.add(:EXCITESCENT,proc { |item,battler,scene|
battler.pokemon.hypermode = false
battler.pokemon.adjustHeart(-1000)
scene.pbDisplay(_INTL("{1} came to its senses from the {2}!",battler.pbThis,GameData::Item.get(item).name))
next true
})
ItemHandlers::BattleUseOnBattler.add(:VIVIDSCENT,proc { |item,battler,scene|
battler.pokemon.hypermode = false
battler.pokemon.adjustHeart(-2000)
scene.pbDisplay(_INTL("{1} came to its senses from the {2}!",battler.pbThis,GameData::Item.get(item).name))
next true
})
#===============================================================================
# No additional effect. (Shadow Blast, Shadow Blitz, Shadow Break, Shadow Rave,
# Shadow Rush, Shadow Wave)
#===============================================================================
class PokeBattle_Move_126 < PokeBattle_Move_000
end
#===============================================================================
# Paralyzes the target. (Shadow Bolt)
#===============================================================================
class PokeBattle_Move_127 < PokeBattle_Move_007
end
#===============================================================================
# Burns the target. (Shadow Fire)
#===============================================================================
class PokeBattle_Move_128 < PokeBattle_Move_00A
end
#===============================================================================
# Freezes the target. (Shadow Chill)
#===============================================================================
class PokeBattle_Move_129 < PokeBattle_Move_00C
end
#===============================================================================
# Confuses the target. (Shadow Panic)
#===============================================================================
class PokeBattle_Move_12A < PokeBattle_Move_013
end
#===============================================================================
# Decreases the target's Defense by 2 stages. (Shadow Down)
#===============================================================================
class PokeBattle_Move_12B < PokeBattle_Move_04C
end
#===============================================================================
# Decreases the target's evasion by 2 stages. (Shadow Mist)
#===============================================================================
class PokeBattle_Move_12C < PokeBattle_TargetStatDownMove
def initialize(battle,move)
super
@statDown = [PBStats::EVASION,2]
end
end
#===============================================================================
# Power is doubled if the target is using Dive. (Shadow Storm)
#===============================================================================
class PokeBattle_Move_12D < PokeBattle_Move_075
end
#===============================================================================
# Two turn attack. On first turn, halves the HP of all active Pokémon.
# Skips second turn (if successful). (Shadow Half)
#===============================================================================
class PokeBattle_Move_12E < PokeBattle_Move
def pbMoveFailed?(user,targets)
failed = true
@battle.eachBattler do |b|
next if b.hp==1
failed = false
break
end
if failed
@battle.pbDisplay(_INTL("But it failed!"))
return true
end
return false
end
def pbEffectGeneral(user)
@battle.eachBattler do |b|
next if b.hp==1
b.pbReduceHP(i.hp/2,false)
end
@battle.pbDisplay(_INTL("Each Pokémon's HP was halved!"))
@battle.eachBattler { |b| b.pbItemHPHealCheck }
user.effects[PBEffects::HyperBeam] = 2
user.currentMove = @id
end
end
#===============================================================================
# Target can no longer switch out or flee, as long as the user remains active.
# (Shadow Hold)
#===============================================================================
class PokeBattle_Move_12F < PokeBattle_Move_0EF
end
#===============================================================================
# User takes recoil damage equal to 1/2 of its current HP. (Shadow End)
#===============================================================================
class PokeBattle_Move_130 < PokeBattle_RecoilMove
def pbRecoilDamage(user,target)
return (target.damageState.totalHPLost/2.0).round
end
def pbEffectAfterAllHits(user,target)
return if user.fainted? || target.damageState.unaffected
# NOTE: This move's recoil is not prevented by Rock Head/Magic Guard.
amt = pbRecoilDamage(user,target)
amt = 1 if amt<1
user.pbReduceHP(amt,false)
@battle.pbDisplay(_INTL("{1} is damaged by recoil!",user.pbThis))
user.pbItemHPHealCheck
end
end
#===============================================================================
# Starts shadow weather. (Shadow Sky)
#===============================================================================
class PokeBattle_Move_131 < PokeBattle_WeatherMove
def initialize(battle,move)
super
@weatherType = PBWeather::ShadowSky
end
end
#===============================================================================
# Ends the effects of Light Screen, Reflect and Safeguard on both sides.
# (Shadow Shed)
#===============================================================================
class PokeBattle_Move_132 < PokeBattle_Move
def pbEffectGeneral(user)
for i in @battle.sides
i.effects[PBEffects::AuroraVeil] = 0
i.effects[PBEffects::Reflect] = 0
i.effects[PBEffects::LightScreen] = 0
i.effects[PBEffects::Safeguard] = 0
end
@battle.pbDisplay(_INTL("It broke all barriers!"))
end
end
#===============================================================================
#
#===============================================================================
class PokemonTemp
attr_accessor :heartgauges
end
Events.onStartBattle += proc { |_sender|
# Record current heart gauges of Pokémon in party, to see if they drop to zero
# during battle and need to say they're ready to be purified afterwards
$PokemonTemp.heartgauges = []
for i in 0...$Trainer.party.length
$PokemonTemp.heartgauges[i] = $Trainer.party[i].heartgauge
end
}
Events.onEndBattle += proc { |_sender,_e|
for i in 0...$PokemonTemp.heartgauges.length
pokemon = $Trainer.party[i]
if pokemon && $PokemonTemp.heartgauges[i] &&
$PokemonTemp.heartgauges[i]!=0 && pokemon.heartgauge==0
pbReadyToPurify(pokemon)
end
end
}
Events.onStepTaken += proc {
for pkmn in $Trainer.ablePokemonParty
if pkmn.heartgauge>0
pkmn.adjustHeart(-1)
pbReadyToPurify(pkmn) if pkmn.heartgauge==0
end
end
if ($PokemonGlobal.purifyChamber rescue nil)
$PokemonGlobal.purifyChamber.update
end
for i in 0...2
pkmn = $PokemonGlobal.daycare[i][0]
next if !pkmn
pkmn.adjustHeart(-1)
pkmn.pbUpdateShadowMoves
end
}