Advertisement
TechSkylander1518

Gen 8 Safari Zone

Aug 22nd, 2022
1,483
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Ruby 17.77 KB | None | 0 0
  1. #===============================================================================
  2. # Simple battler class for the wild Pokémon in a Safari Zone battle
  3. #===============================================================================
  4. class PokeBattle_FakeBattler
  5.   attr_reader :battle
  6.   attr_reader :index
  7.   attr_reader :pokemon
  8.   attr_reader :owned
  9.  
  10.   def initialize(battle,index)
  11.     @battle  = battle
  12.     @pokemon = battle.party2[0]
  13.     @index   = index
  14.   end
  15.  
  16.   def pokemonIndex;   return 0;                      end
  17.   def species;        return @pokemon.species;       end
  18.   def gender;         return @pokemon.gender;        end
  19.   def status;         return @pokemon.status;        end
  20.   def hp;             return @pokemon.hp;            end
  21.   def level;          return @pokemon.level;         end
  22.   def name;           return @pokemon.name;          end
  23.   def totalhp;        return @pokemon.totalhp;       end
  24.   def displayGender;  return @pokemon.gender;        end
  25.   def shiny?;         return @pokemon.shiny?;        end
  26.   def square_shiny?;  return @pokemon.square_shiny?; end
  27.   alias isShiny? shiny?
  28.  
  29.   def isSpecies?(check_species)
  30.     return @pokemon && @pokemon.isSpecies?(check_species)
  31.   end
  32.  
  33.   def fainted?;       return false; end
  34.   alias isFainted? fainted?
  35.   def shadowPokemon?; return false; end
  36.   alias isShadow? shadowPokemon?
  37.   def hasMega?;       return false; end
  38.   def mega?;          return false; end
  39.   alias isMega? mega?
  40.   def hasPrimal?;     return false; end
  41.   def primal?;        return false; end
  42.   alias isPrimal? primal?
  43.   def captured;       return false; end
  44.   def captured=(value); end
  45.  
  46.   def owned?
  47.     return $Trainer.owned?(pokemon.species)
  48.   end
  49.  
  50.   def pbThis(lowerCase=false)
  51.     return (lowerCase) ? _INTL("the wild {1}",name) : _INTL("The wild {1}",name)
  52.   end
  53.  
  54.   def opposes?(i)
  55.     i = i.index if i.is_a?(PokeBattle_FakeBattler)
  56.     return (@index&1)!=(i&1)
  57.   end
  58.  
  59.   def pbReset; end
  60. end
  61.  
  62.  
  63.  
  64. #===============================================================================
  65. # Data box for safari battles
  66. #===============================================================================
  67. class SafariDataBox < SpriteWrapper
  68.   attr_accessor :selected
  69.  
  70.   def initialize(battle,viewport=nil)
  71.     super(viewport)
  72.     @selected    = 0
  73.     @battle      = battle
  74.     @databox     = AnimatedBitmap.new("Graphics/Pictures/Battle/databox_safari")
  75.     self.x       = Graphics.width - 232
  76.     self.y       = Graphics.height - 184
  77.     @contents    = BitmapWrapper.new(@databox.width,@databox.height)
  78.     self.bitmap  = @contents
  79.     self.visible = false
  80.     self.z       = 50
  81.     pbSetSystemFont(self.bitmap)
  82.     refresh
  83.   end
  84.  
  85.   def refresh
  86.     self.bitmap.clear
  87.     self.bitmap.blt(0,0,@databox.bitmap,Rect.new(0,0,@databox.width,@databox.height))
  88.     base   = Color.new(72,72,72)
  89.     shadow = Color.new(184,184,184)
  90.     textpos = []
  91.     textpos.push([_INTL("Safari Balls"),30,2,false,base,shadow])
  92.     textpos.push([_INTL("Left: {1}",@battle.ballCount),30,32,false,base,shadow])
  93.     pbDrawTextPositions(self.bitmap,textpos)
  94.   end
  95.  
  96.   def update(frameCounter=0)
  97.     super()
  98.   end
  99. end
  100.  
  101.  
  102.  
  103. #===============================================================================
  104. # Shows the player throwing bait at a wild Pokémon in a Safari battle.
  105. #===============================================================================
  106. class ThrowBaitAnimation < PokeBattle_Animation
  107.   include PokeBattle_BallAnimationMixin
  108.  
  109.   def initialize(sprites,viewport,battler)
  110.     @battler = battler
  111.     @trainer = battler.battle.pbGetOwnerFromBattlerIndex(battler.index)
  112.     super(sprites,viewport)
  113.   end
  114.  
  115.   def createProcesses
  116.     # Calculate start and end coordinates for battler sprite movement
  117.     batSprite = @sprites["pokemon_#{@battler.index}"]
  118.     traSprite = @sprites["player_1"]
  119.     ballPos = PokeBattle_SceneConstants.pbBattlerPosition(@battler.index,batSprite.sideSize)
  120.     ballStartX = traSprite.x
  121.     ballStartY = traSprite.y-traSprite.bitmap.height/2
  122.     ballMidX   = 0   # Unused in arc calculation
  123.     ballMidY   = 122
  124.     ballEndX   = ballPos[0]-40
  125.     ballEndY   = ballPos[1]-4
  126.     # Set up trainer sprite
  127.     trainer = addSprite(traSprite,PictureOrigin::Bottom)
  128.     # Set up bait sprite
  129.     ball = addNewSprite(ballStartX,ballStartY,
  130.        "Graphics/Battle animations/safari_bait",PictureOrigin::Center)
  131.     ball.setZ(0,batSprite.z+1)
  132.     # Trainer animation
  133.     if traSprite.bitmap.width>=traSprite.bitmap.height*2
  134.       ballStartX, ballStartY = trainerThrowingFrames(ball,trainer,traSprite)
  135.     end
  136.     delay = ball.totalDuration   # 0 or 7
  137.     # Bait arc animation
  138.     ball.setSE(delay,"Battle throw")
  139.     createBallTrajectory(ball,delay,12,
  140.        ballStartX,ballStartY,ballMidX,ballMidY,ballEndX,ballEndY)
  141.     ball.setZ(9,batSprite.z+1)
  142.     delay = ball.totalDuration
  143.     ball.moveOpacity(delay+8,2,0)
  144.     ball.setVisible(delay+10,false)
  145.     # Set up battler sprite
  146.     battler = addSprite(batSprite,PictureOrigin::Bottom)
  147.     # Show Pokémon jumping before eating the bait
  148.     delay = ball.totalDuration+3
  149.     2.times do
  150.       battler.setSE(delay,"player jump")
  151.       battler.moveDelta(delay,3,0,-16)
  152.       battler.moveDelta(delay+4,3,0,16)
  153.       delay = battler.totalDuration+1
  154.     end
  155.     # Show Pokémon eating the bait
  156.     delay = battler.totalDuration+3
  157.     2.times do
  158.       battler.moveAngle(delay,7,5)
  159.       battler.moveDelta(delay,7,0,6)
  160.       battler.moveAngle(delay+7,7,0)
  161.       battler.moveDelta(delay+7,7,0,-6)
  162.       delay = battler.totalDuration
  163.     end
  164.   end
  165. end
  166.  
  167.  
  168.  
  169. #===============================================================================
  170. # Shows the player throwing a rock at a wild Pokémon in a Safari battle.
  171. #===============================================================================
  172. class ThrowRockAnimation < PokeBattle_Animation
  173.   include PokeBattle_BallAnimationMixin
  174.  
  175.   def initialize(sprites,viewport,battler)
  176.     @battler = battler
  177.     @trainer = battler.battle.pbGetOwnerFromBattlerIndex(battler.index)
  178.     super(sprites,viewport)
  179.   end
  180.  
  181.   def createProcesses
  182.     # Calculate start and end coordinates for battler sprite movement
  183.     batSprite = @sprites["pokemon_#{@battler.index}"]
  184.     traSprite = @sprites["player_1"]
  185.     ballStartX = traSprite.x
  186.     ballStartY = traSprite.y-traSprite.bitmap.height/2
  187.     ballMidX   = 0   # Unused in arc calculation
  188.     ballMidY   = 122
  189.     ballEndX   = batSprite.x
  190.     ballEndY   = batSprite.y-batSprite.bitmap.height/2
  191.     # Set up trainer sprite
  192.     trainer = addSprite(traSprite,PictureOrigin::Bottom)
  193.     # Set up bait sprite
  194.     ball = addNewSprite(ballStartX,ballStartY,
  195.        "Graphics/Battle animations/safari_rock",PictureOrigin::Center)
  196.     ball.setZ(0,batSprite.z+1)
  197.     # Trainer animation
  198.     if traSprite.bitmap.width>=traSprite.bitmap.height*2
  199.       ballStartX, ballStartY = trainerThrowingFrames(ball,trainer,traSprite)
  200.     end
  201.     delay = ball.totalDuration   # 0 or 7
  202.     # Bait arc animation
  203.     ball.setSE(delay,"Battle throw")
  204.     createBallTrajectory(ball,delay,12,
  205.        ballStartX,ballStartY,ballMidX,ballMidY,ballEndX,ballEndY)
  206.     ball.setZ(9,batSprite.z+1)
  207.     delay = ball.totalDuration
  208.     ball.setSE(delay,"Battle damage weak")
  209.     ball.moveOpacity(delay+2,2,0)
  210.     ball.setVisible(delay+4,false)
  211.     # Set up anger sprite
  212.     anger = addNewSprite(ballEndX-42,ballEndY-36,
  213.        "Graphics/Battle animations/safari_anger",PictureOrigin::Center)
  214.     anger.setVisible(0,false)
  215.     anger.setZ(0,batSprite.z+1)
  216.     # Show anger appearing
  217.     delay = ball.totalDuration+5
  218.     2.times do
  219.       anger.setSE(delay,"Player jump")
  220.       anger.setVisible(delay,true)
  221.       anger.moveZoom(delay,3,130)
  222.       anger.moveZoom(delay+3,3,100)
  223.       anger.setVisible(delay+6,false)
  224.       anger.setDelta(delay+6,96,-16)
  225.       delay = anger.totalDuration+3
  226.     end
  227.   end
  228. end
  229.  
  230.  
  231.  
  232. #===============================================================================
  233. # Safari Zone battle scene (the visuals of the battle)
  234. #===============================================================================
  235. class PokeBattle_Scene
  236.   def pbSafariStart
  237.     @briefMessage = false
  238.     @sprites["dataBox_0"] = SafariDataBox.new(@battle,@viewport)
  239.     dataBoxAnim = DataBoxAppearAnimation.new(@sprites,@viewport,0)
  240.     loop do
  241.       dataBoxAnim.update
  242.       pbUpdate
  243.       break if dataBoxAnim.animDone?
  244.     end
  245.     dataBoxAnim.dispose
  246.     pbRefresh
  247.   end
  248.  
  249.   def pbSafariCommandMenu(index)
  250.     pbCommandMenuEx(index,[
  251.        _INTL("What will\n{1} throw?",@battle.pbPlayer.name),
  252.        _INTL("Ball"),
  253.        _INTL("Bait"),
  254.        _INTL("Rock"),
  255.        _INTL("Run")
  256.     ],3)
  257.   end
  258.  
  259.   def pbThrowBait
  260.     @briefMessage = false
  261.     baitAnim = ThrowBaitAnimation.new(@sprites,@viewport,@battle.battlers[1])
  262.     loop do
  263.       baitAnim.update
  264.       pbUpdate
  265.       break if baitAnim.animDone?
  266.     end
  267.     baitAnim.dispose
  268.   end
  269.  
  270.   def pbThrowRock
  271.     @briefMessage = false
  272.     rockAnim = ThrowRockAnimation.new(@sprites,@viewport,@battle.battlers[1])
  273.     loop do
  274.       rockAnim.update
  275.       pbUpdate
  276.       break if rockAnim.animDone?
  277.     end
  278.     rockAnim.dispose
  279.   end
  280.  
  281.   alias __safari__pbThrowSuccess pbThrowSuccess
  282.   def pbThrowSuccess
  283.     __safari__pbThrowSuccess
  284.     pbWildBattleSuccess if @battle.is_a?(PokeBattle_SafariZone)
  285.   end
  286. end
  287.  
  288.  
  289.  
  290. #===============================================================================
  291. # Safari Zone battle class
  292. #===============================================================================
  293. class PokeBattle_SafariZone
  294.   attr_reader   :battlers         # Array of fake battler objects
  295.   attr_accessor :sideSizes        # Array of number of battlers per side
  296.   attr_accessor :backdrop         # Filename fragment used for background graphics
  297.   attr_accessor :backdropBase     # Filename fragment used for base graphics
  298.   attr_accessor :time             # Time of day (0=day, 1=eve, 2=night)
  299.   attr_accessor :environment      # Battle surroundings (for mechanics purposes)
  300.   attr_reader   :weather
  301.   attr_reader   :player
  302.   attr_accessor :party2
  303.   attr_accessor :canRun           # True if player can run from battle
  304.   attr_accessor :canLose          # True if player won't black out if they lose
  305.   attr_accessor :switchStyle      # Switch/Set "battle style" option
  306.   attr_accessor :showAnims        # "Battle scene" option (show anims)
  307.   attr_accessor :expGain          # Whether Pokémon can gain Exp/EVs
  308.   attr_accessor :moneyGain        # Whether the player can gain/lose money
  309.   attr_accessor :rules
  310.   attr_accessor :ballCount
  311.  
  312.   include PokeBattle_BattleCommon
  313.  
  314.   def pbRandom(x); return rand(x); end
  315.  
  316.   #=============================================================================
  317.   # Initialize the battle class
  318.   #=============================================================================
  319.   def initialize(scene,player,party2)
  320.     @scene         = scene
  321.     @peer          = PokeBattle_BattlePeer.create()
  322.     @backdrop      = ""
  323.     @backdropBase  = nil
  324.     @time          = 0
  325.     @environment   = :None   # e.g. Tall grass, cave, still water
  326.     @weather       = :None
  327.     @decision      = 0
  328.     @caughtPokemon = []
  329.     @player        = [player]
  330.     @party2        = party2
  331.     @sideSizes     = [1,1]
  332.     @battlers      = [
  333.        PokeBattle_FakeBattler.new(self,0),
  334.        PokeBattle_FakeBattler.new(self,1)
  335.     ]
  336.     @rules         = {}
  337.     @ballCount     = 0
  338.   end
  339.  
  340.   def defaultWeather=(value); @weather = value; end
  341.   def defaultTerrain=(value); end
  342.  
  343.   #=============================================================================
  344.   # Information about the type and size of the battle
  345.   #=============================================================================
  346.   def wildBattle?;    return true;  end
  347.   def trainerBattle?; return false; end
  348.  
  349.   def setBattleMode(mode); end
  350.  
  351.   def pbSideSize(index)
  352.     return @sideSizes[index%2]
  353.   end
  354.  
  355.   #=============================================================================
  356.   # Trainers and owner-related
  357.   #=============================================================================
  358.   def pbPlayer; return @player[0]; end
  359.   def opponent; return nil;        end
  360.  
  361.   def pbGetOwnerFromBattlerIndex(idxBattler); return pbPlayer; end
  362.  
  363.   #=============================================================================
  364.   # Get party info (counts all teams on the same side)
  365.   #=============================================================================
  366.   def pbParty(idxBattler)
  367.     return (opposes?(idxBattler)) ? @party2 : nil
  368.   end
  369.  
  370.   def pbAllFainted?(idxBattler=0); return false; end
  371.  
  372.   #=============================================================================
  373.   # Battler-related
  374.   #=============================================================================
  375.   def opposes?(idxBattler1,idxBattler2=0)
  376.     idxBattler1 = idxBattler1.index if idxBattler1.respond_to?("index")
  377.     idxBattler2 = idxBattler2.index if idxBattler2.respond_to?("index")
  378.     return (idxBattler1&1)!=(idxBattler2&1)
  379.   end
  380.  
  381.   def pbRemoveFromParty(idxBattler,idxParty); end
  382.   def pbGainExp; end
  383.  
  384.   #=============================================================================
  385.   # Messages and animations
  386.   #=============================================================================
  387.   def pbDisplay(msg,&block)
  388.     @scene.pbDisplayMessage(msg,&block)
  389.   end
  390.  
  391.   def pbDisplayPaused(msg,&block)
  392.     @scene.pbDisplayPausedMessage(msg,&block)
  393.   end
  394.  
  395.   def pbDisplayBrief(msg)
  396.     @scene.pbDisplayMessage(msg,true)
  397.   end
  398.  
  399.   def pbDisplayConfirm(msg)
  400.     return @scene.pbDisplayConfirmMessage(msg)
  401.   end
  402.  
  403.   #=============================================================================
  404.   # Pokedex Registration
  405.   #=============================================================================
  406.   def pbSetBattled(battler)
  407.     return if !battler || !@internalBattle
  408.     if battler.respond_to?(:opposes?)
  409.       return if battler.opposes?
  410.       pbPlayer.pokedex.register_battled(battler.displaySpecies)
  411.     else
  412.       pbPlayer.pokedex.register_battled(battler.species)
  413.     end
  414.   end
  415.  
  416.  
  417.  
  418.   class BattleAbortedException < Exception; end
  419.  
  420.   def pbAbort
  421.     raise BattleAbortedException.new("Battle aborted")
  422.   end
  423.  
  424.   #=============================================================================
  425.   # Safari battle-specific methods
  426.   #=============================================================================
  427.   def pbEscapeRate(catch_rate)
  428.     return 125 if catch_rate <= 45   # Escape factor 9 (45%)
  429.     return 100 if catch_rate <= 60   # Escape factor 7 (35%)
  430.     return 75 if catch_rate <= 120   # Escape factor 5 (25%)
  431.     return 50 if catch_rate <= 250   # Escape factor 3 (15%)
  432.     return 25                        # Escape factor 2 (10%)
  433.   end
  434.  
  435.   def pbStartBattle
  436.     begin
  437.       pkmn = @party2[0]
  438.       self.pbPlayer.pokedex.register(pkmn)
  439.       @scene.pbStartBattle(self)
  440.       pbDisplayPaused(_INTL("Wild {1} appeared!",pkmn.name))
  441.       @scene.pbSafariStart
  442.       weather_data = GameData::BattleWeather.try_get(@weather)
  443.       @scene.pbCommonAnimation(weather_data.animation) if weather_data
  444.       safariBall = GameData::Item.get(:SAFARIBALL).id
  445.       catch_rate = pkmn.species_data.catch_rate
  446.       catchFactor  = (catch_rate*100)/1275
  447.       catchFactor  = [[catchFactor,3].max,20].min
  448.       escapeFactor = (pbEscapeRate(catch_rate)*100)/1275
  449.       escapeFactor = [[escapeFactor,2].max,20].min
  450.       loop do
  451.         cmd = @scene.pbSafariCommandMenu(0)
  452.         case cmd
  453.         when 0   # Ball
  454.           if pbBoxesFull?
  455.             pbDisplay(_INTL("The boxes are full! You can't catch any more Pokémon!"))
  456.             next
  457.           end
  458.           @ballCount -= 1
  459.           @scene.pbRefresh
  460.           rare = (catchFactor*1275)/100
  461.           if safariBall
  462.             pbThrowPokeBall(1,safariBall,rare,true)
  463.             if @caughtPokemon.length>0
  464.               pbRecordAndStoreCaughtPokemon
  465.               @decision = 4
  466.             end
  467.           end
  468.         when 1   # Bait
  469.           pbDisplayBrief(_INTL("{1} threw some bait at the {2}!",self.pbPlayer.name,pkmn.name))
  470.           @scene.pbThrowBait
  471.           catchFactor  /= 2 if pbRandom(100)<90   # Harder to catch
  472.           escapeFactor /= 2                       # Less likely to escape
  473.         when 2   # Rock
  474.           pbDisplayBrief(_INTL("{1} threw a rock at the {2}!",self.pbPlayer.name,pkmn.name))
  475.           @scene.pbThrowRock
  476.           catchFactor  *= 2                       # Easier to catch
  477.           escapeFactor *= 2 if pbRandom(100)<90   # More likely to escape
  478.         when 3   # Run
  479.           pbSEPlay("Battle flee")
  480.           pbDisplayPaused(_INTL("You got away safely!"))
  481.           @decision = 3
  482.         end
  483.         catchFactor  = [[catchFactor,3].max,20].min
  484.         escapeFactor = [[escapeFactor,2].max,20].min
  485.         # End of round
  486.         if @decision==0
  487.           if @ballCount<=0
  488.             pbDisplay(_INTL("PA: You have no Safari Balls left! Game over!"))
  489.             @decision = 2
  490.           elsif pbRandom(100)<5*escapeFactor
  491.             pbSEPlay("Battle flee")
  492.             pbDisplay(_INTL("{1} fled!",pkmn.name))
  493.             @decision = 3
  494.           elsif cmd==1   # Bait
  495.             pbDisplay(_INTL("{1} is eating!",pkmn.name))
  496.           elsif cmd==2   # Rock
  497.             pbDisplay(_INTL("{1} is angry!",pkmn.name))
  498.           else
  499.             pbDisplay(_INTL("{1} is watching carefully!",pkmn.name))
  500.           end
  501.           # Weather continues
  502.           weather_data = GameData::BattleWeather.try_get(@weather)
  503.           @scene.pbCommonAnimation(weather_data.animation) if weather_data
  504.         end
  505.         break if @decision > 0
  506.       end
  507.       @scene.pbEndBattle(@decision)
  508.     rescue BattleAbortedException
  509.       @decision = 0
  510.       @scene.pbEndBattle(@decision)
  511.     end
  512.     return @decision
  513.   end
  514. end
  515.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement