Advertisement
Wavescripts

Wave's Enhanced Random Targets

Jul 7th, 2015
593
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Ruby 25.91 KB | None | 0 0
  1. ############################################
  2. #                                          #
  3. #     ENHANCED RANDOM TARGETS SCRIPT       #
  4. #                                          #
  5. #       v1.1 for RPG Maker VX Ace          #
  6. #                                          #
  7. # Created by Jason "Wavelength" Commander  #
  8. #                                          #
  9. ############################################
  10.  
  11. # "Hit me once, shame on you.  Hit me four times with a
  12. #   '4 Random Enemies' spell... still, shame on you."
  13. #                                       ~ Succubus
  14.  
  15.  
  16. ############################################
  17. #                                          #
  18. #           ABOUT THIS SCRIPT              #
  19. #                                          #
  20. ############################################
  21.  
  22. # This script provides a significant expansion to VX Ace's
  23. #      "Random Targets" functionality for Skills and Items,
  24. #      and gives you greater control over how random targeting
  25. #      works.  Among the types of behavior you can set for any
  26. #      Skill or Item in your game:
  27. #
  28. #     * The skill/item can be used on random allies
  29. #
  30. #     * The skill/item can avoid hitting the same target more
  31. #           than once
  32. #
  33. #     * The skill/item can hit as many random targets as you
  34. #           like - not limited to 4
  35. #
  36. #     * The skill/item can hit one target the player selects,
  37. #           PLUS any number of additional random targets
  38. #
  39. #     * The skill/item can be guaranteed to hit a specified
  40. #           number of different enemies
  41.  
  42. # Note that this is NOT a script that changes the AI's choices
  43. #      in battle - it is a script that expands and improves the
  44. #      way that skills with Random Target scopes work.
  45.  
  46. # This script is compatible with most other scripts.  Be careful
  47. #      about using it with other scripts that change how targeting
  48. #      or random scopes work.
  49.  
  50. # Thank you to everyone who encouraged me to write and publish
  51. #      this script!
  52.  
  53.  
  54. ############################################
  55. #                                          #
  56. #              TERMS OF USE                #
  57. #                                          #
  58. ############################################
  59.  
  60. #  Free to use for non-commercial projects - just credit me
  61.  
  62. #  A license is required to use this script in commercial or
  63. #       semi-commercial projects.  Please visit my website
  64. #       wavescripts.wordpress.com for more info about obtaining
  65. #       a license for my scripts.
  66.  
  67. #  You may freely share or modify this script, but you cannot
  68. #       sell it (even if modified) without my written permission
  69.  
  70. #  Please preserve the header (with version #) and terms of use;
  71. #       besides that, feel free to remove any commenting you please
  72.  
  73.  
  74. ############################################
  75. #                                          #
  76. #         HOW TO USE THIS SCRIPT           #
  77. #                                          #
  78. ############################################
  79.  
  80. # This script should be placed in the "Materials" section
  81. #      of the script editor.  For maximum compatibility,
  82. #      I recommend placing this script above all of your
  83. #      other scripts.
  84.  
  85. # Then, simply add notetags to the "Note" box for Skills or Items
  86. #     in your database to determine their Random Targeting behavior.
  87. #     You can also choose not to add a notetag to allow the Skill/Item
  88. #     to use its default targeting behavior.
  89.  
  90. # Use the following format for a notetag:
  91. #
  92. #     <random targets: #(, full)(, multi)>
  93. #
  94. #     "#" is the total number of times you want VX Ace to 'roll' for a target
  95. #     "full" indicates that you want # different targets to be hit
  96. #     "multi" indicates it's okay for the same target to be hit multiple times
  97.  
  98. # See below for examples of notetags and what the corresponding skill/item
  99. #     would do.
  100.  
  101. # IMPORTANT: If you want to have skills that choose random allies to target
  102. #     (without giving the player the chance to select the first ally to be
  103. #     targeted), then scroll down to the "Random Allies Section" near the
  104. #     bottom of this script and follow the instructions there.
  105.  
  106.  
  107. ############################################
  108. #                                          #
  109. #      EXAMPLES AND NOTES ON USAGE         #
  110. #                                          #
  111. ############################################
  112.  
  113. # Here are some examples of notetags that you might use on skills/items to
  114. #     achieve different effects:
  115.  
  116.  
  117. #   <random targets: 3>
  118. #
  119. #       * If the Scope of this skill is "1 Random Enemy", VX Ace will select
  120. #           a random enemy 3 times, then remove any duplicates that were
  121. #           selected.  A total of 1-3 random enemies will be hit, and none
  122. #           will be hit more than once.
  123. #
  124. #       * If the Scope of this skill is "One Enemy", the player will get to
  125. #           select the first enemy to hit, then VX Ace will select a random
  126. #           enemy twice (for a total of 3 targets).  Again, duplicates will
  127. #           be removed, so a total of 1-3 enemies will be hit and none will
  128. #           be hit more than once.
  129. #
  130. #       * If the Scope of this skill is "One Ally", the player will get to
  131. #           select the first ally to hit, then VX Ace will select a random
  132. #           ally twice.  Duplicates are removed, 1-3 allies hit, none more
  133. #           than once.  Similar behavior for "One Ally (KOed)" except that
  134. #           KOed allies will be targeted instead of alive ones.
  135. #
  136. #       * If the Scope of this skill is "None", VX Ace will select a random
  137. #           ally 3 times, then remove duplicates.  1-3 allies will be hit,
  138. #           none more than once.  Note that this particular behavior requires
  139. #           the "Random Allies Section" of the script to be enabled.
  140. #
  141. #       * Technically you can use "2 Random Enemies", etc. Scopes with this
  142. #           skill, but there's no reason to, since you can easily control
  143. #           the number of enemies to target (in this case 3) using the notetag.
  144.  
  145.  
  146. #   <random targets: 3, full>
  147. #
  148. #       * This is the same as the above, except instead of 3 attempted targets,
  149. #           VX Ace will keep targeting random battlers (allies or enemies, as
  150. #           appropriate) until 3 UNIQUE battlers have been selected.
  151. #           So instead of 1-3 enemies being hit, you will be assured that 3
  152. #           enemies will be hit (unless there are fewer than 3 enemies alive).
  153. #           Like above, no battlers can be hit more than once.
  154. #
  155. #       * All scopes listed above can be used with this tag.
  156.  
  157.  
  158. #   <random targets: 3, multi>
  159. #
  160. #       * This will generate 3 attempted targets but will allow a battler to
  161. #           be hit multiple times.  So a total of 3 hits will be landed, but
  162. #           that might mean one battler being hit 3 times, or 3 battlers being
  163. #           hit once.  This is basically default VX Ace behavior, but this tag
  164. #           might still be useful if you want to randomly target allies or to
  165. #           raise the number of targets above 4.
  166. #          
  167. #       * All scopes listed above can be used with this tag.
  168.  
  169.  
  170. #   <random targets: 3, full, multi>
  171. #
  172. #       * This will cause VX Ace to generate targets over and over UNTIL
  173. #           3 unique battlers (or the entire party/troop) has been targeted.
  174. #           Because the multi tag allows a battler to be hit multiple times,
  175. #           this means that some battlers might be hit 5-10 times or even more!
  176. #
  177. #       * Use a large number and a small enemy troop for some funny results!
  178. #
  179. #       * All scopes listed above can be used with this tag.
  180.  
  181.  
  182. # Instead of "random targets" you may use the shorcut phrases "random hits"
  183. #     or "randoms" instead.
  184.  
  185. # Syntax is important; capitalization is not.  You may use the "full" and
  186. #     "multi" keywords in any order, just remember to properly separate each
  187. #     field with a comma.
  188.  
  189. # NOTE: When I say "no battler (enemy/ally) can be hit more than once", I am
  190. #     referring to the way that this script targets battlers.  You can still
  191. #     use the standard "Repeats" field on the skill/item to have it hit each
  192. #     target more than once.  This script won't change that behavior.
  193.  
  194.  
  195.  
  196. ############################################
  197. #                                          #
  198. #               ICKY CODE!                 #
  199. #                                          #
  200. ############################################
  201.  
  202. # Everything from here on represents the inner workings of the script.
  203. #       Please don't alter anything from here on unless you are an
  204. #       advanced scripter yourself (in which case, have at it!)  
  205.  
  206. # (The "Random Allies" section is much further down, near the bottom
  207. #       of the script.)
  208.  
  209.  
  210. module RPG
  211.  
  212.   class UsableItem < RPG::BaseItem
  213.  
  214.     #--------------------------------------------------------------------------
  215.     # * Add extra Parameters to RPG::Skill and RPG::Item items
  216.     #--------------------------------------------------------------------------
  217.     def init_randoms
  218.      
  219.       @randoms = false          # Whether the skill uses Enhanced Random hits
  220.       @random_hits = 0          # The total number of hits dealt by the skill
  221.       @random_full = false      # true: will keep picking until the number of
  222.                                 #       unique enemies hit equals "random_hits"
  223.                                 # false: will only pick a number of times equal
  224.                                 #       to "random hits"
  225.       @random_multi = false     # Whether the same enemy can be hit multiple times
  226.      
  227.       # Set the Random Targets values from the item's notetag
  228.       get_multi_hit_info(@note)
  229.      
  230.     end
  231.    
  232.     #--------------------------------------------------------------------------
  233.     # * Public Instance Variables
  234.     #--------------------------------------------------------------------------
  235.     attr_accessor :randoms
  236.     attr_accessor :random_hits
  237.     attr_accessor :random_full
  238.     attr_accessor :random_multi
  239.    
  240.     #--------------------------------------------------------------------------
  241.     # * Set the Random Targets values from the item's notetag
  242.     #--------------------------------------------------------------------------
  243.     def get_multi_hit_info(note)
  244.      
  245.       newnote = @note.downcase
  246.       newnote.gsub!($/, "@LINE@")
  247.       if newnote =~ /<randoms:(.*)>/
  248.         splitter = $1.split(",")
  249.       else
  250.         splitter = []
  251.       end
  252.       if newnote =~ /<random hits:(.*)>/
  253.         splitter = $1.split(",")
  254.       end
  255.       if newnote =~ /<random targets:(.*)>/
  256.         splitter = $1.split(",")
  257.       end
  258.      
  259.       # If the splitter isn't empty, set the other Attributes
  260.       if splitter != []
  261.        
  262.         # If the splitter is not empty, we know that Random Hits is true
  263.         #   (Not currently using this variable for anything)
  264.         @randoms = true
  265.        
  266.         # Get rid of spaces - they're only there for visual clarity
  267.         for item in splitter
  268.           while item.include?(" ")
  269.             item.slice!(" ")
  270.           end
  271.           ok = true
  272.           the_number = item.to_i rescue ok = false
  273.           if ok == true
  274.             if the_number > 0
  275.               @random_hits = the_number - 1
  276.             end
  277.           end
  278.           if item.is_a?(String)
  279.             if item.start_with?("full") or item.end_with?("full")
  280.               @random_full = true
  281.             end
  282.             if item.start_with?("multi") or item.end_with?("multi")
  283.               @random_multi = true
  284.             end
  285.           end
  286.         end
  287.          
  288.       end
  289.      
  290.     end
  291.    
  292.   end
  293.  
  294. end
  295.  
  296.  
  297.  
  298. module DataManager
  299.  
  300.   class << self
  301.  
  302.     #--------------------------------------------------------------------------
  303.     # * Load Normal Database
  304.     #--------------------------------------------------------------------------
  305.     alias :load_normals_with_randoms :load_normal_database
  306.     def load_normal_database
  307.       load_normals_with_randoms
  308.       for item in $data_items
  309.         item.init_randoms if item != nil
  310.       end
  311.       for skill in $data_skills
  312.         skill.init_randoms if skill != nil
  313.       end
  314.     end
  315.    
  316.     #--------------------------------------------------------------------------
  317.     # * Load Battle Test Database
  318.     #--------------------------------------------------------------------------
  319.     alias :load_btest_with_randoms :load_battle_test_database
  320.     def load_battle_test_database
  321.       load_btest_with_randoms
  322.       for item in $data_items
  323.         item.init_randoms if item != nil
  324.       end
  325.       for skill in $data_skills
  326.         skill.init_randoms if skill != nil
  327.       end
  328.     end
  329.  
  330.   end
  331.  
  332. end
  333.  
  334.  
  335.  
  336.  
  337. class Game_Action
  338.  
  339.   #--------------------------------------------------------------------------
  340.   # * Targets for Opponents
  341.   #--------------------------------------------------------------------------
  342.   def targets_for_opponents
  343.     extra_hits = item.random_hits
  344.     targets_array = []
  345.     # Item for Random Enemies Processing Starts Here - this is used when you
  346.     #   don't want enemy selection
  347.     if item.for_random?
  348.       # First, create the standard "random enemies" target array
  349.       targets_array = (Array.new(item.number_of_targets) { opponents_unit.random_target })
  350.       # Then fill the array with additional random hits, per the notetags
  351.       if extra_hits > 0
  352.         ok = false
  353.         while (ok == false)
  354.           targets_array.push(opponents_unit.random_target)
  355.           # If the "Full" option is selected, check the Unique Array...
  356.           if item.random_full == true
  357.             unique_newyork = targets_array.uniq # Try saying "Unique New York"
  358.             if unique_newyork.size > extra_hits #   ten times fast!
  359.               ok = true
  360.             end
  361.             # To avoid hangs/freezes, move on if every alive enemy is selected
  362.             if unique_newyork.size == opponents_unit.alive_members.size
  363.               ok = true
  364.             end
  365.           # If the "Full" option is not selected, check the Total Array...
  366.           else
  367.             if targets_array.size > extra_hits
  368.               ok = true
  369.             end
  370.           end
  371.         end
  372.       end
  373.       # Find the list of unique random targets; allow multiple selections of the
  374.       #   same target only if 'Multi' is true.  Allow multi-hits on the same
  375.       #   target, though.
  376.       unless item.random_multi == true
  377.         targets_array.uniq!
  378.       end
  379.       # Return the array now that it's been filtered for uniqueness
  380.       targets_array
  381.     # Item For One Enemy Processing Starts Here - this can be used for random
  382.     #   targets processing when you want the player to select the 1st enemy
  383.     elsif item.for_one?
  384.       num = 1 + (attack? ? subject.atk_times_add.to_i : 0)
  385.       if @target_index < 0
  386.         # Keep pushing in targets until it equals the number of hits
  387.         ok = false
  388.         while (ok == false)
  389.         #for i in 0..extra_hits
  390.           targets_array.push([opponents_unit.random_target] * num)
  391.           # If the "Full" option is selected, check the Unique Array...
  392.           if item.random_full == true
  393.             unique_newyork = targets_array.uniq { |small| small.first }
  394.             if unique_newyork.size > extra_hits
  395.               ok = true
  396.             end
  397.             # To avoid hangs/freezes, move on if every alive enemy is selected
  398.             if unique_newyork.size == opponents_unit.alive_members.size
  399.               ok = true
  400.             end
  401.           # If the "Full" option is not selected, check the Total Array...
  402.           else
  403.             if targets_array.size > extra_hits
  404.               ok = true
  405.             end
  406.           end
  407.         end
  408.       else
  409.         # First, push the selected target into the Targets Array
  410.         targets_array.push([opponents_unit.smooth_target(@target_index)] * num)
  411.         # Then, if there are any extra Random Hits to be made, select them the
  412.         #   same way as we did above.
  413.         if extra_hits > 0
  414.           ok = false
  415.           while (ok == false)
  416.             targets_array.push([opponents_unit.random_target] * num)
  417.             if item.random_full == true
  418.               unique_newyork = targets_array.uniq { |small| small.first }
  419.               if unique_newyork.size > extra_hits
  420.                 ok = true
  421.               end
  422.               if unique_newyork.size == opponents_unit.alive_members.size
  423.                 ok = true
  424.               end
  425.             else
  426.               if targets_array.size > extra_hits
  427.                 ok = true
  428.               end
  429.             end
  430.           end
  431.         end
  432.       end
  433.       # Find the list of unique random targets; allow multiple selections of the
  434.       #   same target only if 'Multi' is true.  Allow multi-hits on the same
  435.       #   target, though.
  436.       unless item.random_multi == true
  437.         targets_array.uniq! { |small| small.first }
  438.       end
  439.       # Finally, combine all the small arrays into one large array that can be
  440.       #   worked with by Scene_Battle
  441.       combined_targets = []
  442.       for small_array in targets_array
  443.         for element in small_array
  444.           combined_targets.push(element)
  445.         end
  446.       end
  447.       # Return the large array
  448.       combined_targets
  449.     else
  450.       # All Enemies Processing is exactly the same as default
  451.       opponents_unit.alive_members
  452.     end
  453.   end
  454.  
  455.   #--------------------------------------------------------------------------
  456.   # * Targets for Allies
  457.   #--------------------------------------------------------------------------
  458.   def targets_for_friends
  459.     extra_hits = item.random_hits
  460.     targets_array = []
  461.     # Scope: The User processing starts here - this can be used for random
  462.     #   targets processing when you want additional random allies to be targeted
  463.     if item.for_user?
  464.       # Push the User into the targets array
  465.       targets_array.push(subject)
  466.       # Then fill the array with additional random hits, per the notetags
  467.       if extra_hits > 0
  468.         ok = false
  469.         while (ok == false)
  470.           targets_array.push(friends_unit.random_target)
  471.           # If the "Full" option is selected, check the Unique Array...
  472.           if item.random_full == true
  473.             unique_newyork = targets_array.uniq # Try saying "Unique New York"
  474.             if unique_newyork.size > extra_hits #   ten times fast!
  475.               ok = true
  476.             end
  477.             # To avoid hangs/freezes, move on if every alive enemy is selected
  478.             if unique_newyork.size == friends_unit.alive_members.size
  479.               ok = true
  480.             end
  481.           # If the "Full" option is not selected, check the Total Array...
  482.           else
  483.             if targets_array.size > extra_hits
  484.               ok = true
  485.             end
  486.           end
  487.         end
  488.       end
  489.       # Find the list of unique random targets; allow multiple selections of the
  490.       #   same target only if 'Multi' is true.  Allow multi-hits on the same
  491.       #   target, though.
  492.       unless item.random_multi == true
  493.         targets_array.uniq!
  494.       end
  495.       # Finally, return the filtered (unique, if appropriate) array
  496.       targets_array
  497.     elsif item.for_dead_friend?
  498.       # Scope: One KOed Ally - this can be used for random targets processing
  499.       #   when you want add'l random KOed allies to also be targeted
  500.       if item.for_one?
  501.         # First, push the selected KOed target into the targets array
  502.         targets_array.push(friends_unit.smooth_dead_target(@target_index))
  503.         # Then fill the array with additional random hits, per the notetags
  504.         if extra_hits > 0
  505.           ok = false
  506.           while (ok == false)
  507.             targets_array.push(friends_unit.random_dead_target)
  508.             if item.random_full == true
  509.               unique_newyork = targets_array.uniq
  510.               if unique_newyork.size > extra_hits
  511.                 ok = true
  512.               end
  513.               # To avoid hangs/freezes, move on if every *KOed* enemy is selected
  514.               if unique_newyork.size >= friends_unit.dead_members.size
  515.                 ok = true
  516.               end
  517.             else
  518.               if targets_array.size > extra_hits
  519.                 ok = true
  520.               end
  521.               # Additional check in the Non-Full branch: if there are no dead
  522.               #   members, move on, to avoid hangs/freezes
  523.               if friends_unit.dead_members.size == 0
  524.                 ok = true
  525.               end
  526.             end
  527.           end
  528.         end
  529.         # Find the list of unique random targets; allow multiple selections of the
  530.         #   same target only if 'Multi' is true.  Allow multi-hits on the same
  531.         #   target, though.
  532.         unless item.random_multi == true
  533.           targets_array.uniq!
  534.         end
  535.         # Check to see whether all battlers in this array are nil
  536.         all_nil = true
  537.         if targets_array.size > 0
  538.           for entry in targets_array
  539.             if entry != nil
  540.               all_nil = false
  541.             end
  542.           end
  543.         end
  544.         # If there are no valid (non-nil) battlers in the array, return 'nil'
  545.         if all_nil == true
  546.           []
  547.         else
  548.           # Otherwise, return the filtered (unique, if appropriate) array
  549.           targets_array
  550.         end
  551.       else
  552.         # All KOed Allies Processing is exactly the same as default
  553.         friends_unit.dead_members
  554.       end
  555.     elsif item.for_friend?
  556.       # Scope: One Ally - this can be used for random targets processing when
  557.       #   you want additional random allies to also be targeted
  558.       if item.for_one?
  559.         # First, push the selected target into the targets array
  560.         targets_array.push(pick_target_for_one_friend)
  561.         # Then fill the array with additional random hits, per the notetags
  562.         if extra_hits > 0
  563.           ok = false
  564.           while (ok == false)
  565.             targets_array.push(friends_unit.random_target)
  566.             if item.random_full == true
  567.               unique_newyork = targets_array.uniq
  568.               if unique_newyork.size > extra_hits
  569.                 ok = true
  570.               end
  571.               if unique_newyork.size == friends_unit.alive_members.size
  572.                 ok = true
  573.               end
  574.             else
  575.               if targets_array.size > extra_hits
  576.                 ok = true
  577.               end
  578.             end
  579.           end
  580.         end
  581.         unless item.random_multi == true
  582.           targets_array.uniq!
  583.         end
  584.         targets_array
  585.       else
  586.         # All Allies Processing is exactly the same as default
  587.         friends_unit.alive_members
  588.       end
  589.     end
  590.   end
  591.  
  592.   #--------------------------------------------------------------------------
  593.   # * This method is a copy of the "smooth target" selection from the
  594.   #     targets_for_friends method; the only reason I've separated it
  595.   #     into its own separate method is to enable a Compatibility Patch
  596.   #     with lonewolf's Randomized Enemy Targeting fix.
  597.   #--------------------------------------------------------------------------
  598.   def pick_target_for_one_friend
  599.     friends_unit.smooth_target(@target_index)
  600.   end
  601.  
  602. ############################################
  603. #                                          #
  604. #          RANDOM ALLIES SECTION           #
  605. #                                          #
  606. ############################################
  607.  
  608. =begin
  609.  
  610. # This section is used for additional methods to allow you to create
  611. #   skills which target random (alive) Allies without requiring a
  612. #   target selection.  To make such a skill, simply tag a skill with
  613. #   a scope of "None" with the Random Targets notetag.
  614.  
  615. # The reason this section is disabled by default is to maximize
  616. #   compatibility with other scripts.  Therefore, you should only
  617. #   enable this section if you plan to use the functionality
  618. #   described above, especially if you have other scripts that
  619. #   overwrite or alias the "make_targets" method.
  620.  
  621. # If you're sure you want to enable this section, remove the tags
  622. #   that read "=begin" and "=end" lines at the top and bottom of
  623. #   this section.
  624.  
  625.  #--------------------------------------------------------------------------
  626.  # * Create Target Array
  627.  #--------------------------------------------------------------------------
  628.  def make_targets
  629.    if !forcing && subject.confusion?
  630.      [confusion_target]
  631.    elsif item.for_opponent?
  632.      targets_for_opponents
  633.    elsif item.for_friend?
  634.      targets_for_friends
  635.    elsif item.scope == 0
  636.      random_friendly_targets
  637.    else
  638.      []
  639.    end
  640.  end
  641.  
  642.  #--------------------------------------------------------------------------
  643.  # * Assign Random (Alive) Allies without a Target Selection
  644.  #--------------------------------------------------------------------------
  645.  def random_friendly_targets
  646.    extra_hits = item.random_hits
  647.    targets_array = []
  648.    # Fill the array with random hits, per the notetags
  649.    if extra_hits > 0
  650.      ok = false
  651.      while (ok == false)
  652.        targets_array.push(friends_unit.random_target)
  653.        # If the "Full" option is selected, check the Unique Array...
  654.        if item.random_full == true
  655.          unique_newyork = targets_array.uniq
  656.          if unique_newyork.size > extra_hits
  657.            ok = true
  658.          end
  659.          # To avoid hangs/freezes, move on if every alive enemy is selected
  660.          if unique_newyork.size == friends_unit.alive_members.size
  661.            ok = true
  662.          end
  663.        # If the "Full" option is not selected, check the Total Array...
  664.        else
  665.          if targets_array.size > extra_hits
  666.            ok = true
  667.          end
  668.        end
  669.      end
  670.    end
  671.    # Find the list of unique random targets; allow multiple selections of the
  672.    #   same target only if 'Multi' is true.  Allow multi-hits on the same
  673.    #   target, though.
  674.    unless item.random_multi == true
  675.      targets_array.uniq!
  676.    end
  677.    # Return the array now that it's been filtered for uniqueness
  678.    targets_array
  679.  end
  680.  
  681. =end
  682.  
  683. # (RANDOM ALLIES SECTION ENDS HERE)
  684.  
  685. end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement