Advertisement
NettoHikari1131

Nuzlocke Permadeath (v17.2)

Sep 5th, 2020 (edited)
3,886
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Ruby 13.19 KB | None | 0 0
  1. ################################################################################
  2. # Nuzlocke Permadeath v1.1
  3. # by NettoHikari
  4. #
  5. # June 16, 2020
  6. #
  7. # NOTE: This is the v17.2 version of Nuzlocke Permadeath. If you are using
  8. # v18, you will need to get the updated version.
  9. #
  10. # This script allows the developer to enable a Nuzlocke-style permadeath for
  11. # Pokemon battles, where any Pokemon that faints is immediately removed from the
  12. # player's party. The difference between this and other Nuzlocke scripts is that
  13. # Pokemon get removed DURING battle instead of after.
  14. #
  15. # Credits MUST BE GIVEN to NettoHikari
  16. # You should also credit the authors of Pokemon Essentials itself.
  17. #
  18. #-------------------------------------------------------------------------------
  19. # INSTALLATION
  20. #-------------------------------------------------------------------------------
  21. # Copy this script, place it somewhere between "Compiler" and "Main" in the
  22. # script sections, and name it "Nuzlocke Permadeath".
  23. #
  24. # Before using this script, make sure to start a new save file when testing.
  25. # Since it adds new stored data, the script will probably throw errors when used
  26. # with saves where the script wasn't present before. In addition, if you decide
  27. # to release your game in segments, it is important to have this script
  28. # installed in the very first version itself, so as not to cause any problems to
  29. # the player.
  30. #
  31. #-------------------------------------------------------------------------------
  32. # SCRIPT USAGE
  33. #-------------------------------------------------------------------------------
  34. # This script offers two types of permadeath modes: SOFT and NUZLOCKE. In SOFT
  35. # mode, any Pokemon that faint are sent to the Pokemon Storage after the battle,
  36. # while in NUZLOCKE mode, they are lost forever (except for their held items).
  37. # To switch between permadeath modes, call "pbSetPermadeath(mode)" at the start
  38. # of your game (it is set to NORMAL by default at the beginning), replacing
  39. # "mode" with one of three modes: :NORMAL, :SOFT, or :NUZLOCKE. For example,
  40. # to enable the standard permadeath mode, use:
  41. #
  42. # pbSetPermadeath(:NUZLOCKE)
  43. #
  44. # and to disable it, use:
  45. #
  46. # pbSetPermadeath(:NORMAL)
  47. #
  48. # These can be called at anytime throughout your game, so for example, you can
  49. # change modes for specific event battles. To find out if the current permadeath
  50. # mode is either SOFT or NUZLOCKE use the function "pbPermadeathActive?". To
  51. # find out if a specific mode is enabled, use the function
  52. # "pbPermadeathModeIs?(mode)", replacing "mode" with what you're checking for.
  53. #
  54. # I highly suggest reading the "Additional Notes" section below for more
  55. # information on what the script does.
  56. #
  57. #-------------------------------------------------------------------------------
  58. # ADDITIONAL NOTES
  59. #-------------------------------------------------------------------------------
  60. # - On the outside, every time a Pokemon faints in SOFT or NUZLOCKE mode, it
  61. #   LOOKS like it's been removed from the party immediately. However, what
  62. #   happens internally is that all fainted Pokemon are hidden from the player's
  63. #   view until the end of the round (so technically, they are still part of the
  64. #   player's party). Then, at the end of each round, the player's party is
  65. #   swept for fainted Pokemon, and they are removed and placed into another
  66. #   list called "@faintedlist" (defined in PokeBattle_Battle below). Think of
  67. #   this list as a sort of "purgatory", meaning that the Pokemon here still
  68. #   exist as long as the battle is active, just not in the main party.
  69. # - At the very end of the battle in SOFT mode, @faintedlist is swept and all
  70. #   Pokemon in it are stored in the Pokemon Storage (unless the storage is full,
  71. #   in which case they are simply lost like NUZLOCKE mode).
  72. # - Any battles marked as "can lose", meaning that the game will continue
  73. #   even if the player loses the battle, automatically have NORMAL mode on.
  74. # - When a Pokemon dies in NUZLOCKE mode, it drops its held item into the
  75. #   player's bag.
  76. # - Pokemon can die from fainting in field due to poison if both NUZLOCKE and
  77. #   POISONINFIELD are enabled. For SOFT mode, the Pokemon get stored in the
  78. #   Pokemon Storage.
  79. # - When the player loses a battle with permadeath enabled, meaning that the
  80. #   trainer's entire party is dead, the game simply returns to the title screen
  81. #   with a "GAME OVER" screen, going back to the player's last save.
  82. #
  83. #-------------------------------------------------------------------------------
  84. # I hope you enjoy this script!
  85. # - NettoHikari
  86. ################################################################################
  87.  
  88. module PBPermadeath
  89.   NORMAL   = 0 # Standard mode
  90.   SOFT     = 1 # "Soft" nuzlocke (fainted Pokemon get transferred to Pokemon Storage)
  91.   NUZLOCKE = 2 # "Hard" nuzlocke (fainted Pokemon get deleted at the end of battle)
  92. end
  93.  
  94. class PokemonGlobalMetadata
  95.   # Sets battles to NORMAL, SOFT, or NUZLOCKE
  96.   attr_accessor :permadeathmode
  97. end
  98.  
  99. def pbSetPermadeath(mode)
  100.   if mode.is_a?(Symbol)
  101.     mode = getConst(PBPermadeath, mode)
  102.   end
  103.   return if mode < 0 || mode > 2
  104.   $PokemonGlobal.permadeathmode = mode
  105. end
  106.  
  107. def pbPermadeathModeIs?(mode)
  108.   if mode.is_a?(Symbol)
  109.     mode = getConst(PBPermadeath, mode)
  110.   end
  111.   return $PokemonGlobal.permadeathmode == mode
  112. end
  113.  
  114. def pbPermadeathActive?
  115.   return !pbPermadeathModeIs?(:NORMAL)
  116. end
  117.  
  118. class PokeBattle_Battle
  119.   # Keeps track of whether or not battle can be lost
  120.   attr_accessor :canlose
  121.   # Stores fainted Pokemon until end of battle (like a "purgatory")
  122.   attr_accessor :faintedlist
  123.  
  124.   alias permadeath_pbStartBattle pbStartBattle
  125.   def pbStartBattle(canlose=false)
  126.     @canlose = canlose
  127.     @faintedlist = []
  128.     permadeath_pbStartBattle(canlose)
  129.   end
  130.  
  131.   alias permadeath_pbReplace pbReplace
  132.   def pbReplace(index,newpoke,batonpass=false)
  133.     oldpoke=@battlers[index].pokemonIndex
  134.     permadeath_pbReplace(index,newpoke,batonpass)
  135.     # Party order is already changed in pbFaint, so undo party order change here
  136.     if pbPermadeathBattle? && pbOwnedByPlayer?(index) &&
  137.           oldpoke < $Trainer.party.length && $Trainer.party[oldpoke].fainted?
  138.       bpo=-1; bpn=@party1order.length-1
  139.       for i in 0...6
  140.         bpo=i if @party1order[i] > 5 && @party1order[i] < 12
  141.       end
  142.       p=@party1order[bpo]; @party1order[bpo]=@party1order[bpn]; @party1order[bpn]=p
  143.     end
  144.   end
  145.  
  146.   alias permadeath_pbEndOfRoundPhase pbEndOfRoundPhase
  147.   def pbEndOfRoundPhase
  148.     # Cancel effect of Future Sight from dead Pokemon
  149.     if pbPermadeathBattle?
  150.       priority = pbPriority
  151.       for i in priority
  152.         next if !i || i.fainted?
  153.         next if i.effects[PBEffects::FutureSightUserPos] < 0
  154.         next if pbIsOpposing?(i.effects[PBEffects::FutureSightUserPos])
  155.         attacker = @party1[i.effects[PBEffects::FutureSightUser]]
  156.         if attacker.fainted?
  157.           i.effects[PBEffects::FutureSight]        = 0
  158.           i.effects[PBEffects::FutureSightMove]    = 0
  159.           i.effects[PBEffects::FutureSightUser]    = -1
  160.           i.effects[PBEffects::FutureSightUserPos] = -1
  161.         end
  162.       end
  163.     end
  164.     permadeath_pbEndOfRoundPhase
  165.     pbRemoveFainted
  166.   end
  167.  
  168.   alias permadeath_pbEndOfBattle pbEndOfBattle
  169.   def pbEndOfBattle(canlose=false)
  170.     pbRemoveFainted
  171.     permadeath_pbEndOfBattle(canlose)
  172.     if pbPermadeathBattle? && pbPermadeathModeIs?(:SOFT)
  173.       for i in @faintedlist
  174.         storedbox = $PokemonStorage.pbStoreCaught(i)
  175.       end
  176.     end
  177.   end
  178.  
  179.   def pbPermadeathBattle?
  180.     return pbPermadeathActive? && !@canlose
  181.   end
  182.  
  183.   def pbRemoveFainted
  184.     return if !pbPermadeathBattle?
  185.     pokeindex = 0
  186.     # Loop through Trainer's party
  187.     loop do
  188.       break if pokeindex >= $Trainer.party.length
  189.       if @party1[pokeindex] && @party1[pokeindex].isFainted?
  190.         # Begin by deleting Pokemon from party entirely
  191.         @faintedlist.push($Trainer.party[pokeindex])
  192.         $Trainer.party.delete_at(pokeindex)
  193.         $PokemonTemp.evolutionLevels.delete_at(pokeindex)
  194.         $PokemonTemp.heartgauges.delete_at(pokeindex) if $PokemonTemp.heartgauges
  195.         # Remove from double battle party as well
  196.         if @doublebattle && $PokemonGlobal.partner
  197.           @party1[pokeindex] = nil
  198.           for i in pokeindex...5
  199.             @party1[i] = @party1[i + 1]
  200.           end
  201.           @party1[5] = nil
  202.         end
  203.         # Fix party positions of current battlers
  204.         if @battlers[0].pokemonIndex == pokeindex
  205.           @battlers[0].pokemonIndex = $Trainer.party.length
  206.         elsif @battlers[0].pokemonIndex > pokeindex
  207.           @battlers[0].pokemonIndex -= 1
  208.         end
  209.         if @doublebattle && !$PokemonGlobal.partner
  210.           if @battlers[2].pokemonIndex == pokeindex
  211.             @battlers[2].pokemonIndex = $Trainer.party.length
  212.             @battlers[2].pokemonIndex += 1 if @battlers[2].pokemonIndex == @battlers[0].pokemonIndex
  213.           elsif @battlers[2].pokemonIndex > pokeindex
  214.             @battlers[2].pokemonIndex -= 1
  215.           end
  216.         end
  217.         # Fix participants for exp gains
  218.         for i in [1, 3]
  219.           next if !@battlers[i]
  220.           participants = @battlers[i].participants
  221.           for j in 0...participants.length
  222.             next if !participants[j]
  223.             participants[j] -= 1 if participants[j] > pokeindex
  224.           end
  225.         end
  226.         pokeindex -= 1
  227.       end
  228.       pokeindex += 1
  229.     end
  230.     # Reset party order as shown on summary screen
  231.     for i in 0...6
  232.       @party1order[i] = i
  233.     end
  234.     # Put left side (or only) battler in first spot
  235.     if @battlers[0].pokemonIndex != @party1order[0] &&
  236.             @battlers[0].pokemonIndex < $Trainer.party.length
  237.       oldpokeindex = @party1order.index(@battlers[0].pokemonIndex)
  238.       oldpoke = @party1order[0]
  239.       @party1order[0] = @battlers[0].pokemonIndex
  240.       @party1order[oldpokeindex] = oldpoke
  241.     end
  242.     # If right side battler exists, put in second spot
  243.     # unless left side battler is gone, then put in first spot
  244.     if @doublebattle && !$PokemonGlobal.partner
  245.       poi = $Trainer.ablePokemonCount > 1 ? 1 : 0
  246.       if @battlers[2].pokemonIndex != @party1order[poi] &&
  247.               @battlers[2].pokemonIndex < $Trainer.party.length
  248.         oldpokeindex = @party1order.index(@battlers[2].pokemonIndex)
  249.         oldpoke = @party1order[poi]
  250.         @party1order[poi] = @battlers[2].pokemonIndex
  251.         @party1order[oldpokeindex] = oldpoke
  252.       end
  253.     end
  254.     # End battle if player's entire party is gone
  255.     @decision = 2 if $Trainer.ablePokemonCount == 0
  256.   end
  257. end
  258.  
  259. class PokeBattle_Battler
  260.   alias permadeath_pbFaint pbFaint
  261.   def pbFaint(showMessage=true)
  262.     return true if @fainted || !fainted?
  263.     ret = permadeath_pbFaint(showMessage)
  264.     if @battle.pbPermadeathBattle? && @battle.pbOwnedByPlayer?(@index)
  265.       if showMessage && pbPermadeathModeIs?(:NUZLOCKE)
  266.         if @battle.party1[@pokemonIndex].hasItem?
  267.           # Informs player that fainted's held item was transferred to bag
  268.           @battle.pbDisplayPaused(_INTL("{1} is dead! You picked up its {2}.",
  269.               pbThis, PBItems.getName(@battle.party1[@pokemonIndex].item)))
  270.         else
  271.           @battle.pbDisplayPaused(_INTL("{1} is dead!",pbThis))
  272.         end
  273.       end
  274.       # Remove fainted from party order
  275.       pokeindex = @battle.party1order.index(@pokemonIndex)
  276.       for i in pokeindex...5
  277.         @battle.party1order[i] = @battle.party1order[i + 1]
  278.       end
  279.       @battle.party1order[5] = 100
  280.       # Remove fainted from opposing participants arrays
  281.       @battle.battlers[1].participants.delete(@pokemonIndex)
  282.       if @battle.doublebattle && @battle.battlers[3].participants
  283.         @battle.battlers[3].participants.delete(@pokemonIndex)
  284.       end
  285.       # Add held item to bag
  286.       if @battle.party1[@pokemonIndex].hasItem? && pbPermadeathModeIs?(:NUZLOCKE)
  287.         $PokemonBag.pbStoreItem(@battle.party1[@pokemonIndex].item)
  288.       end
  289.     end
  290.     return ret
  291.   end
  292. end
  293.  
  294. # Removes Pokemon fainted by poison
  295. Events.onStepTakenTransferPossible+=proc {|sender,e|
  296.   if $PokemonGlobal.stepcount%4==0 && POISONINFIELD
  297.     $Trainer.party.delete_if{|poke|
  298.       if pbPermadeathActive? && poke.fainted?
  299.         if pbPermadeathModeIs?(:SOFT)
  300.           $PokemonStorage.pbStoreCaught(poke)
  301.         else
  302.           if poke.hasItem?
  303.             # Informs player that fainted's held item was transferred to bag
  304.             Kernel.pbMessage(_INTL("{1} is dead... You picked up its {2}.",
  305.                 poke.name, PBItems.getName(poke.item)))
  306.           else
  307.             Kernel.pbMessage(_INTL("{1} is dead...",poke.name))
  308.           end
  309.           $PokemonBag.pbStoreItem(poke.item) if poke.hasItem?
  310.         end
  311.         true
  312.       end
  313.     }
  314.   end
  315. }
  316.  
  317. # Sends player back to title screen if all Pokemon lost
  318. module Kernel
  319.   class << Kernel
  320.     alias permadeath_pbStartOver pbStartOver
  321.   end
  322.  
  323.   def self.pbStartOver(gameover=false)
  324.     if pbPermadeathActive?
  325.       if pbInBugContest?
  326.         Kernel.pbBugContestStartOver
  327.         return
  328.       end
  329.       Kernel.pbMessage(_INTL("\\w[]\\wm\\c[8]\\l[3]GAME OVER!"))
  330.       Kernel.pbCancelVehicles
  331.       pbRemoveDependencies
  332.       $game_temp.to_title = true
  333.     else
  334.       self.permadeath_pbStartOver(gameover)
  335.     end
  336.   end
  337. end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement