Advertisement
NettoHikari1131

Nuzlocke Permadeath

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