diff --git a/Data/Map329.rxdata b/Data/Map329.rxdata index 97e201e3b..1aca2bdf9 100644 Binary files a/Data/Map329.rxdata and b/Data/Map329.rxdata differ diff --git a/Data/Scripts/011_Battle/001_Battler/005_Battler_StatStages.rb b/Data/Scripts/011_Battle/001_Battler/005_Battler_StatStages.rb index 17058879c..150de1282 100644 --- a/Data/Scripts/011_Battle/001_Battler/005_Battler_StatStages.rb +++ b/Data/Scripts/011_Battle/001_Battler/005_Battler_StatStages.rb @@ -92,7 +92,7 @@ class PokeBattle_Battler return true end - def pbRaiseStatStageByAbility(stat,increment,user,splashAnim=true) + def pbRaiseStatStageByAbility(stat,increment,user,splashAnim=true, abilityName=nil) return false if fainted? ret = false @battle.pbShowAbilitySplash(user) if splashAnim diff --git a/Data/Scripts/050_AddOns/DoubleAbilities.rb b/Data/Scripts/050_AddOns/DoubleAbilities.rb new file mode 100644 index 000000000..691b48871 --- /dev/null +++ b/Data/Scripts/050_AddOns/DoubleAbilities.rb @@ -0,0 +1,249 @@ +class PokeBattle_Battler + attr_accessor :ability_id + attr_accessor :ability2_id + + #Primary ability utility methods for battlers class + def ability + return GameData::Ability.try_get(@ability_id) + end + + def ability=(value) + new_ability = GameData::Ability.try_get(value) + @ability_id = (new_ability) ? new_ability.id : nil + end + + def abilityName + abil = self.ability + return (abil) ? abil.name : "" + end + + #Secondary ability utility methods for battlers class + def ability2 + return GameData::Ability.try_get(@ability2_id) + end + + def ability2=(value) + new_ability = GameData::Ability.try_get(value) + @ability2_id = (new_ability) ? new_ability.id : nil + end + + def ability2Name + abil = self.ability2 + return (abil) ? abil.name : "" + end + + #Ability logic overrides + + def hasActiveAbility?(check_ability, ignore_fainted = false) + return hasActiveAbilityDouble?(check_ability, ignore_fainted) if $game_switches[SWITCH_DOUBLE_ABILITIES] + return false if !abilityActive?(ignore_fainted) + return check_ability.include?(@ability_id) if check_ability.is_a?(Array) + return self.ability == check_ability + end + + def hasActiveAbilityDouble?(check_ability, ignore_fainted = false) + return false if !abilityActive?(ignore_fainted) + if check_ability.is_a?(Array) + return check_ability.include?(@ability_id) || check_ability.include?(@ability2_id) + end + return self.ability == check_ability || self.ability2 == check_ability + end + + def triggerAbilityEffectsOnHit(move, user, target) + # Target's ability + if target.abilityActive?(true) + oldHP = user.hp + BattleHandlers.triggerTargetAbilityOnHit(target.ability, user, target, move, @battle) + BattleHandlers.triggerTargetAbilityOnHit(target.ability2, user, target, move, @battle) if $game_switches[SWITCH_DOUBLE_ABILITIES] && target.ability2 + user.pbItemHPHealCheck if user.hp < oldHP + end + # User's ability + if user.abilityActive?(true) + BattleHandlers.triggerUserAbilityOnHit(user.ability, user, target, move, @battle) + BattleHandlers.triggerUserAbilityOnHit(user.ability2, user, target, move, @battle) if $game_switches[SWITCH_DOUBLE_ABILITIES] && user.ability2 + user.pbItemHPHealCheck + end + end + + def pbCheckDamageAbsorption(user, target) + # Substitute will take the damage + if target.effects[PBEffects::Substitute] > 0 && !ignoresSubstitute?(user) && + (!user || user.index != target.index) + target.damageState.substitute = true + return + end + # Disguise will take the damage + if !@battle.moldBreaker && target.isFusionOf(:MIMIKYU) && + target.form == 0 && (target.ability == :DISGUISE || target.ability2 == :DISGUISE) + target.damageState.disguise = true + return + end + end + + # Called when a Pokémon (self) enters battle, at the end of each move used, + # and at the end of each round. + def pbContinualAbilityChecks(onSwitchIn = false) + # Check for end of primordial weather + @battle.pbEndPrimordialWeather + # Trace + if $game_switches[SWITCH_DOUBLE_ABILITIES] && onSwitchIn + displayOpponentDoubleAbilities() + else + if hasActiveAbility?(:TRACE) + # NOTE: In Gen 5 only, Trace only triggers upon the Trace bearer switching + # in and not at any later times, even if a traceable ability turns + # up later. Essentials ignores this, and allows Trace to trigger + # whenever it can even in the old battle mechanics. + choices = [] + @battle.eachOtherSideBattler(@index) do |b| + next if b.ungainableAbility? || + [:POWEROFALCHEMY, :RECEIVER, :TRACE].include?(b.ability_id) + choices.push(b) + end + if choices.length > 0 + choice = choices[@battle.pbRandom(choices.length)] + @battle.pbShowAbilitySplash(self) + self.ability = choice.ability + @battle.pbDisplay(_INTL("{1} traced {2}'s {3}!", pbThis, choice.pbThis(true), choice.abilityName)) + @battle.pbHideAbilitySplash(self) + if !onSwitchIn && (unstoppableAbility? || abilityActive?) + BattleHandlers.triggerAbilityOnSwitchIn(self.ability, self, @battle) + end + end + end + end + end + + def displayOpponentDoubleAbilities() + @battle.eachOtherSideBattler(@index) do |battler| + @battle.pbShowPrimaryAbilitySplash(battler,true) + @battle.pbShowSecondaryAbilitySplash(battler,true) if battler.isFusion?() + @battle.pbHideAbilitySplash(battler) + end + end + +end + + + + +class Pokemon + attr_writer :ability_index + attr_writer :ability2_index + + #Primary ability utility methods for pokemon class + def ability_index + @ability_index = (@personalID & 1) if !@ability_index + return @ability_index + end + + def ability + return GameData::Ability.try_get(ability_id()) + end + + def ability=(value) + return if value && !GameData::Ability.exists?(value) + @ability = (value) ? GameData::Ability.get(value).id : value + end + + #Secondary ability utility methods for pokemon class + def ability2_index + @ability2_index = (@personalID & 1) if !@ability2_index + return @ability2_index + end + + def ability2 + return GameData::Ability.try_get(ability2_id()) + end + + def ability2=(value) + return if value && !GameData::Ability.exists?(value) + @ability2 = (value) ? GameData::Ability.get(value).id : value + end + + def ability2_id + if !@ability2 + sp_data = species_data + abil_index = ability2_index() + if abil_index >= 2 # Hidden ability + @ability2 = sp_data.hidden_abilities[abil_index - 2] + abil_index = (@personalID & 1) if !@ability2 + end + if !@ability2 # Natural ability or no hidden ability defined + @ability2 = sp_data.abilities[abil_index] || sp_data.abilities[0] + end + end + return @ability2 + end + + def ability2_id + if !@ability2 + sp_data = species_data + abil_index = ability_index + if abil_index >= 2 # Hidden ability + @ability2 = sp_data.hidden_abilities[abil_index - 2] + abil_index = (@personalID & 1) if !@ability2 + end + if !@ability2 # Natural ability or no hidden ability defined + @ability2 = sp_data.abilities[abil_index] || sp_data.abilities[0] + end + end + return @ability2 + end + + def adjustHPForWonderGuard(stats) + return self.ability == :WONDERGUARD ? 1 : stats[:HP] || ($game_switches[SWITCH_DOUBLE_ABILITIES] && self.ability2 == :WONDERGUARD) + end + +end + + + +class PokemonFusionScene + + def pbChooseAbility(poke, hidden1 = false, hidden2 = false) + abilityList = poke.getAbilityList + + if $game_switches[SWITCH_DOUBLE_ABILITIES] + abID1 = @pokemon1.ability + abID2 = @pokemon2.ability + else + abID1 = hidden1 ? abilityList[4][0] : abilityList[0][0] + abID2 = hidden2 ? abilityList[5][0] : abilityList[1][0] + end + availableNatures = [] + availableNatures << @pokemon1.nature + availableNatures << @pokemon2.nature + + setAbilityAndNatureAndNickname([GameData::Ability.get(abID1), GameData::Ability.get(abID2)], availableNatures) + end + + def setAbilityAndNatureAndNickname(abilitiesList, naturesList) + clearUIForMoves + if $game_switches[SWITCH_DOUBLE_ABILITIES] + scene = FusionSelectOptionsScene.new(nil, naturesList, @pokemon1, @pokemon2) + screen = PokemonOptionScreen.new(scene) + screen.pbStartScreen + + @pokemon1.ability = abilitiesList[0] + @pokemon1.ability2 = abilitiesList[1] + else + scene = FusionSelectOptionsScene.new(abilitiesList, naturesList, @pokemon1, @pokemon2) + screen = PokemonOptionScreen.new(scene) + screen.pbStartScreen + @pokemon1.ability = scene.selectedAbility + end + + @pokemon1.nature = scene.selectedNature + if scene.hasNickname + @pokemon1.name = scene.nickname + end + + p @pokemon1.ability.real_name + p @pokemon1.ability2.real_name + + end + +end + + diff --git a/Data/Scripts/050_AddOns/DoubleAbilities_UI.rb b/Data/Scripts/050_AddOns/DoubleAbilities_UI.rb new file mode 100644 index 000000000..095acf425 --- /dev/null +++ b/Data/Scripts/050_AddOns/DoubleAbilities_UI.rb @@ -0,0 +1,124 @@ +# +# class AbilitySplashBar < SpriteWrapper +# def refresh +# self.bitmap.clear +# return if !@battler +# textPos = [] +# textX = (@side==0) ? 10 : self.bitmap.width-8 +# # Draw Pokémon's name +# textPos.push([_INTL("{1}'s",@battler.name),textX,-4,@side==1, +# TEXT_BASE_COLOR,TEXT_SHADOW_COLOR,true]) +# # Draw Pokémon's ability +# textPos.push([@battler.abilityName,textX,26,@side==1, +# TEXT_BASE_COLOR,TEXT_SHADOW_COLOR,true]) +# pbDrawTextPositions(self.bitmap,textPos) +# +# #2nd ability +# if $game_switches[SWITCH_DOUBLE_ABILITIES] +# textPos.push([@battler.ability2Name,textX,26,@side==1, +# TEXT_BASE_COLOR,TEXT_SHADOW_COLOR,true]) +# pbDrawTextPositions(self.bitmap,textPos) +# end +# end +# end + + +class AbilitySplashDisappearAnimation < PokeBattle_Animation + def initialize(sprites,viewport,side) + @side = side + super(sprites,viewport) + end + + def createProcesses + return if !@sprites["abilityBar_#{@side}"] + bar = addSprite(@sprites["abilityBar_#{@side}"]) + bar2 = addSprite(@sprites["ability2Bar_#{@side}"]) if @sprites["ability2Bar_#{@side}"] + + dir = (@side==0) ? -1 : 1 + bar.moveDelta(0,8,dir*Graphics.width/2,0) + bar2.moveDelta(0,8,dir*Graphics.width/2,0) if bar2 + + bar.setVisible(8,false) + bar2.setVisible(8,false) if bar2 + end +end + +class PokeBattle_Scene + def pbShowAbilitySplash(battler,secondAbility=false) + return if !PokeBattle_SceneConstants::USE_ABILITY_SPLASH + side = battler.index%2 + if secondAbility + pbHideAbilitySplash(battler) if @sprites["ability2Bar_#{side}"].visible + else + pbHideAbilitySplash(battler) if @sprites["abilityBar_#{side}"].visible + end + @sprites["abilityBar_#{side}"].battler = battler + @sprites["ability2Bar_#{side}"].battler = battler if @sprites["ability2Bar_#{side}"] + + abilitySplashAnim = AbilitySplashAppearAnimation.new(@sprites,@viewport,side,secondAbility) + loop do + abilitySplashAnim.update + pbUpdate + break if abilitySplashAnim.animDone? + end + abilitySplashAnim.dispose + end +end + +class PokeBattle_Battle + + def pbShowSecondaryAbilitySplash(battler,delay=false,logTrigger=true) + return if !PokeBattle_SceneConstants::USE_ABILITY_SPLASH + @scene.pbShowAbilitySplash(battler,true) + if delay + Graphics.frame_rate.times { @scene.pbUpdate } # 1 second + end + end + + def pbShowPrimaryAbilitySplash(battler,delay=false,logTrigger=true) + return if !PokeBattle_SceneConstants::USE_ABILITY_SPLASH + @scene.pbShowAbilitySplash(battler,false) + if delay + Graphics.frame_rate.times { @scene.pbUpdate } # 1 second + end + end + +end + + + +class FusionSelectOptionsScene < PokemonOption_Scene + def pbGetOptions(inloadscreen = false) + + options = [] + if shouldSelectNickname + options << EnumOption.new(_INTL("Nickname"), [_INTL(@pokemon1.name), _INTL(@pokemon2.name)], + proc { 0 }, + proc { |value| + if value ==0 + @nickname = @pokemon1.name + else + @nickname = @pokemon2.name + end + }, "Select the Pokémon's nickname") + end + + if @abilityList != nil + options << EnumOption.new(_INTL("Ability"), [_INTL(getAbilityName(@abilityList[0])), _INTL(getAbilityName(@abilityList[1]))], + proc { 0 }, + proc { |value| + @selectedAbility=@abilityList[value] + }, [getAbilityDescription(@abilityList[0]), getAbilityDescription(@abilityList[1])] + ) + end + + options << EnumOption.new(_INTL("Nature"), [_INTL(getNatureName(@natureList[0])), _INTL(getNatureName(@natureList[1]))], + proc { 0 }, + proc { |value| + @selectedNature=@natureList[value] + }, [getNatureDescription(@natureList[0]), getNatureDescription(@natureList[1])] + ) + return options + end +end + diff --git a/Data/System.rxdata b/Data/System.rxdata index efa83d99e..35b4c0783 100644 Binary files a/Data/System.rxdata and b/Data/System.rxdata differ