Solistra

SES Dynamic Time

Nov 29th, 2012
802
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Ruby 26.68 KB | None | 0 0
  1. #═╦═════════════════════════════════════════════════════════════════════════════
  2. # ║ § Dynamic Time (1.3) by Solistra                     [License: CC BY-SA 3.0]
  3. # ║                                                            <RMVX Ace>
  4. #═╬═════════════════════════════════════════════════════════════════════════════
  5. # ║ § Change Log
  6. #─╫─────────────────────────────────────────────────────────────────────────────
  7. # ║ v1.3 (January 4th, 2013) - Removed the option for multiple time managers --
  8. # ║   honestly, it was obnoxious to use, and not commonly requested. Other
  9. # ║   portions of the script were rewritten, but there is no change for users.
  10. # ║   Saved games will be incompatible with this update, however.
  11. # ║ v1.2 (December 4th, 2012) - Rewrote large portions of the script to allow
  12. # ║   multiple time managers to run simultaneously. Changed the way in which
  13. # ║   these managers are updated as well (saved games will not be compatible).
  14. # ║ v1.1 (December 1st, 2012) - Added the methods [unit]_max and reset. Also
  15. # ║   added a configuration option to allow storing values in $game_variables.
  16. # ║ v1.0 (November 29th, 2012) - Initial release
  17. # ║
  18. #═╬═════════════════════════════════════════════════════════════════════════════
  19. # ║ § Summary
  20. #─╫─────────────────────────────────────────────────────────────────────────────
  21. # ║ This script allows you to use time in extraordinarily dynamic ways and makes
  22. # ║ almost no assumptions about how you want to set up or use time. Essentially,
  23. # ║ you define how much (or little) you want to use segmentations of time.
  24. # ║
  25. #═╬═════════════════════════════════════════════════════════════════════════════
  26. # ║ § Required Scripts
  27. #─╫─────────────────────────────────────────────────────────────────────────────
  28. # ║ None.
  29. # ║
  30. #═╬═════════════════════════════════════════════════════════════════════════════
  31. # ║ § Known Incompatibilities
  32. #─╫─────────────────────────────────────────────────────────────────────────────
  33. # ║ None.
  34. # ║
  35. #═╬═════════════════════════════════════════════════════════════════════════════
  36. # ║ § Installation
  37. #─╫─────────────────────────────────────────────────────────────────────────────
  38. # ║ For best compatibility, place this script below Materials, but above all
  39. # ║ other custom scripts.
  40. # ║
  41. #═╬═════════════════════════════════════════════════════════════════════════════
  42. # ║ § Configuration
  43. #─╫─────────────────────────────────────────────────────────────────────────────
  44. # ║ In this script, you define the segmentations of time and the maximum values
  45. # ║ for each segment. Once a segment has reached its maximum value, the next
  46. # ║ segment increases its value by 1 (so for every 60 seconds, one minute could
  47. # ║ be added, and for every 60 minutes, one hour could be added). For example,
  48. # ║ to create a game that uses minutes, hours, meridians, and days, you could
  49. # ║ set up the script as follows (units should always be symbols):
  50. # ║
  51. # ║   UNIT = [:minute, :hour, :meridian, :day]
  52. # ║   MAX  = [60,      12,    2,         nil]
  53. # ║
  54. # ║ A maximum value of "nil" means that there is no maximum -- this value will
  55. # ║ simply continue to increase. In this example, you can see that there are
  56. # ║ two meridians in a day, twelve hours in each meridian, and sixty minutes
  57. # ║ per hour.
  58. # ║
  59. # ║ Below this, you can define which segment will change the tone of the screen
  60. # ║ and the tone that each segment changes into. For instance, with the above
  61. # ║ example, we could set up a simple day and night system like so:
  62. # ║
  63. # ║   TONE_UNIT = :meridian
  64. # ║   TONE_LENGTH = 120
  65. # ║   TONES = [
  66. # ║     Tone.new(-68, -68, 0, 68), # Night (meridian 1)
  67. # ║     Tone.new(0, 0, 0, 0),      # Day   (meridian 2)
  68. # ║   ]
  69. # ║
  70. # ║ This will cause the tone to change over the course of 120 frames whenever
  71. # ║ the meridian changes. The current meridian will determine the tone used
  72. # ║ (remember to define tones in order from earliest to latest). Please note
  73. # ║ that the array of tones you want to use MUST be equal to the maximum value
  74. # ║ of whatever time unit you use to change the screen's tone!
  75. # ║
  76. # ║ Below this, you may configure any units of time that you wish to store in
  77. # ║ variables automatically (the kind you can manipulate with the Control
  78. # ║ Variables event command). This option is in the format of a hash: the key
  79. # ║ is the unit of time to store, and its value is the variable ID that you wish
  80. # ║ to store the value of the unit in. For example, to store the values for
  81. # ║ hours and days in variables 20 and 21 (respectively), you would do this:
  82. # ║
  83. # ║   VARIABLES = {:hour => 20, :day => 21}
  84. # ║
  85. #═╬═════════════════════════════════════════════════════════════════════════════
  86. # ║ § Tags
  87. #─╫─────────────────────────────────────────────────────────────────────────────
  88. # ║ ● Map
  89. # ║   <time no_tone>
  90. # ║     Suppresses tone changes on the map.
  91. # ║   <time stop>
  92. # ║     Explicitly stops time on the map (even if time is enabled).
  93. # ║   <time run>
  94. # ║     Explicitly runs time on the map (even if time is disabled).
  95. # ║
  96. #═╬═════════════════════════════════════════════════════════════════════════════
  97. # ║ § Script Calls
  98. #─╫─────────────────────────────────────────────────────────────────────────────
  99. # ║ You can access the current value of any unit of time by using the following
  100. # ║ script call:
  101. # ║   $game_system.time.[unit]
  102. # ║
  103. # ║ Using the previous example, you can access the current hour with the script
  104. # ║ call $game_system.time.hour. You can also explicitly set a unit's value like
  105. # ║ so:
  106. # ║   $game_system.time.[unit] = [value]
  107. # ║
  108. # ║ If you need to know the maximum value of any unit of game time, just use
  109. # ║ the following script call:
  110. # ║   $game_system.time.[unit]_max
  111. # ║
  112. # ║ For example, to get the maximum value for minutes, you'd use the script
  113. # ║ call $game_system.time.minute_max.
  114. # ║
  115. # ║ You may also start or stop game time with a number of different methods:
  116. # ║   $game_system.time.enable OR start OR run
  117. # ║   $game_system.time.disable OR stop OR pause
  118. # ║
  119. # ║ You can also get the current state of time with these calls:
  120. # ║   $game_system.time.running? AND $game_system.time.stopped?
  121. # ║
  122. # ║ Time can also move more quickly or slowly by modifying the value of the
  123. # ║ SES::Time module's @frame_skip instance variable. You can do this with the
  124. # ║ following script call:
  125. # ║   $game_system.time.frame_skip = [value]
  126. # ║
  127. # ║ To move back or forward through time, use the following script call with a
  128. # ║ positive value to move forward or a negative value to move backwards:
  129. # ║   $game_system.time.traverse([unit symbol], [value])
  130. # ║
  131. # ║ For example, to advance 12 hours, you'd call the following:
  132. # ║   $game_system.time.traverse(:hour, 12)
  133. # ║
  134. # ║ You may also save the current time values and restore these values with
  135. # ║ these script calls:
  136. # ║   $game_system.time.save
  137. # ║   $game_system.time.restore
  138. # ║
  139. # ║ Resetting time back to the initial values that you have set is easy, too:
  140. # ║   $game_system.time.reset
  141. # ║
  142. #═╬═════════════════════════════════════════════════════════════════════════════
  143. # ║ § Aliased Methods
  144. #─╫─────────────────────────────────────────────────────────────────────────────
  145. # ║ ● Game_System
  146. # ║     initialize
  147. # ║ ● Game_Map
  148. # ║     setup
  149. # ║ ● Scene_Base
  150. # ║     update
  151. # ║ ● Scene_Map
  152. # ║     post_transfer
  153. # ║
  154. #═╬═════════════════════════════════════════════════════════════════════════════
  155. # ║ § New Methods
  156. #─╫─────────────────────────────────────────────────────────────────────────────
  157. # ║ ● Game_Map
  158. # ║     no_tone?
  159. # ║     no_time?
  160. # ║     run_time?
  161. # ║
  162. #═╬═════════════════════════════════════════════════════════════════════════════
  163. # ║ ▼ module SES::Time
  164. #═╩═════════════════════════════════════════════════════════════════════════════
  165. module SES module Time
  166.   class << self; attr_reader :frame_skip end
  167.   #═╦═══════════════════════════════════════════════════════════════════════════
  168.   # ║ α BEGIN CONFIGURATION
  169.   #═╩═══════════════════════════════════════════════════════════════════════════
  170.   # Set whether or not time should start with a new game.
  171.   ENABLED = true
  172.  
  173.   # The number of frames to skip before the most basic unit of time is updated.
  174.   @frame_skip = 60
  175.  
  176.   # Scenes where time is updated.
  177.   UPDATE_SCENES = [Scene_Map, Scene_Battle]
  178.  
  179.   # Should the message window pause time while it is in use?
  180.   MSG_PAUSE = true
  181.  
  182.   # Units of game time in order of length. Note that these should all be
  183.   # symbols, not strings (so you would write :minute instead of "minute").
  184.   UNIT = [:minute, :hour, :time_of_day, :day]
  185.  
  186.   # Maximum values for each unit of game time. Must be the same size as the
  187.   # UNIT constant above. A value of "nil" means there is no maximum.
  188.   MAX = [60, 6, 4, nil]
  189.  
  190.   # Initial values for units of game time. Must be the same size as the UNIT
  191.   # and MAX constants above. (Note that this runs from 0 to MAX - 1, not 1
  192.   # to MAX.)
  193.   INIT = [0, 0, 0, 1]
  194.  
  195.   # The time unit to use for tone changes and the number of frames changes take.
  196.   TONE_UNIT = :time_of_day
  197.   TONE_LENGTH = 120
  198.  
  199.   # The array of tones. This must be the same length as the maximum value for
  200.   # the time unit used for tone changes. (If MAX is 4, create 4 tones.)
  201.   TONES = [
  202.     Tone.new(-68, -68, 0, 68),  # Night
  203.     Tone.new(17, -34, 17, 34),  # Morning
  204.     Tone.new(0, 0, 0, 0),       # Day
  205.     Tone.new(34, -34, -34, 34), # Evening
  206.   ]
  207.  
  208.   # The hash of time units to store in $game_variables. Use the unit you wish
  209.   # to store as the key and the ID of the desired variable as the value.
  210.   VARIABLES = {:hour => 1, :time_of_day => 2, :day => 3}
  211.   #═╦═══════════════════════════════════════════════════════════════════════════
  212.   # ║ Ω END CONFIGURATION
  213.   #─╫───────────────────────────────────────────────────────────────────────────
  214.   # ║ ▼ class Manager
  215.   #═╩═══════════════════════════════════════════════════════════════════════════
  216.   class Manager
  217.     # Initialize this manager.
  218.     def initialize
  219.       construct_methods
  220.       @time_enabled, @tone_temp = ENABLED, Tone.new
  221.     end
  222.    
  223.     # Create an instance variable and accessors for each unit of game time.
  224.     def construct_methods
  225.       UNIT.each do |u|
  226.         instance_variable_set("@#{u}", INIT[UNIT.index(u)])
  227.         self.class.send(:define_method, u){instance_variable_get("@#{u}")}
  228.         self.class.send(:define_method, "#{u}=".to_sym) do |value|
  229.           instance_variable_set("@#{u}", value) end
  230.         self.class.send(:define_method, "#{u}_max".to_sym) do
  231.           return MAX[UNIT.index(u)] end
  232.       end
  233.     end
  234.    
  235.     # Updates the most basic unit of game time (which initiates a potential
  236.     # chain of updates) and requests a tone update.
  237.     def update
  238.       return unless update_conditions_met?
  239.       self.send("update_#{UNIT[0]}")
  240.       update_tone
  241.     end
  242.    
  243.     # Defines the conditions under which time should or should not be updated.
  244.     def update_conditions_met?
  245.       return false if stopped? || !running?
  246.       return false unless Graphics.frame_count % SES::Time.frame_skip == 0
  247.       return false unless UPDATE_SCENES.include?(SceneManager.scene.class)
  248.       return false if $game_message.busy? && MSG_PAUSE
  249.       return true
  250.     end
  251.    
  252.     # Updates the tone if time is enabled or running, the tone has not been
  253.     # changed, and the map allows the tone to change.
  254.     def update_tone
  255.       return if (stopped? && !running?) || tone_changed? || $game_map.no_tone?
  256.       screen.start_tone_change(get_tone, TONE_LENGTH)
  257.       @tone_temp = get_tone
  258.     end
  259.    
  260.     # Gets the screen used for tone changes.
  261.     def screen
  262.       $game_party.in_battle ? $game_troop.screen : $game_map.screen
  263.     end
  264.    
  265.     # Gets the tone for this unit of game time by using the value of the
  266.     # TONE_UNIT instance variable as the index for the TONES array.
  267.     def get_tone() TONES[self.send(TONE_UNIT)] end
  268.    
  269.     # Check if the temporary tone is the currently requested tone.
  270.     def tone_changed?() @tone_temp == get_tone end
  271.    
  272.     # Convenience method that allows the user to travel back or forward through
  273.     # units of game time.
  274.     def traverse(unit, amount)
  275.       return if amount == 0 || UNIT.index(unit.to_sym).nil?
  276.       amount > 0 ? amount.times{self.send("update_#{unit}".to_sym)} :
  277.                    amount.abs.times{self.send("rollback_#{unit}".to_sym)}
  278.     end
  279.    
  280.     # Saves the state of all instance variables used by Manager. The @tone_temp
  281.     # instance variable is left out so tone changes will occur properly.
  282.     def save
  283.       @save_state = {}
  284.       instance_variables.each do |var|
  285.         next if var == :@save_state || var == :@tone_temp
  286.         @save_state[var] = instance_variable_get(var)
  287.       end
  288.     end
  289.    
  290.     # Restores the saved state of previously stored instance variables.
  291.     def restore
  292.       return unless @save_state
  293.       @save_state.keys.each{|var| instance_variable_set(var, @save_state[var])}
  294.     end
  295.    
  296.     # Resets time back to the initial values used.
  297.     def reset
  298.       UNIT.each{|u| instance_variable_set("@#{u}", INIT[UNIT.index(u)])}
  299.     end
  300.    
  301.     # Convenience method for storing the values of a unit of time into the
  302.     # $game_variables array.
  303.     def store_in_variables(u, v) $game_variables[v] = self.send(u.to_sym) end
  304.    
  305.     # This is the workhorse of the script; this method moves time forward or
  306.     # backward depending on the name of the method passed to it.
  307.     def method_missing(method)
  308.       if method =~ /^update_(\S+)$/
  309.         raise(NoMethodError) if UNIT.index($1.to_sym).nil?
  310.         # Increase the instance variable by 1.
  311.         instance_variable_set("@#{$1}", instance_variable_get("@#{$1}") + 1)
  312.         store_in_variables($1, VARIABLES[$1.to_sym]) if VARIABLES[$1.to_sym]
  313.         unless MAX[UNIT.index($1.to_sym)].nil?
  314.           if instance_variable_get("@#{$1}") < MAX[UNIT.index($1.to_sym)]
  315.             return
  316.           end
  317.         else return end
  318.         # This code is only run once the maximum value of time has been reached
  319.         # for the given unit of game time. Set the value of this unit to 0,
  320.         # then call the update method for the next unit of game time.
  321.         instance_variable_set("@#{$1}", 0)
  322.         store_in_variables($1, VARIABLES[$1.to_sym]) if VARIABLES[$1.to_sym]
  323.         unless UNIT[UNIT.index($1.to_sym) + 1].nil?
  324.           self.send("update_#{UNIT[UNIT.index($1.to_sym) + 1]}")
  325.         end
  326.       elsif method =~ /^rollback_(\S+)$/
  327.         raise(NoMethodError) if UNIT.index($1.to_sym).nil?
  328.         if instance_variable_get("@#{$1}") - 1 >= 0
  329.           # Rolls time back by 1 if doing so doesn't result in a negative value.
  330.           instance_variable_set("@#{$1}", instance_variable_get("@#{$1}") - 1)
  331.           store_in_variables($1, VARIABLES[$1.to_sym]) if VARIABLES[$1.to_sym]
  332.         else
  333.           # Rolling back would create a negative value, so set it to the maximum
  334.           # value for this unit of game time (which is MAX - 1).
  335.           instance_variable_set("@#{$1}", MAX[UNIT.index($1.to_sym)] - 1)
  336.           store_in_variables($1, VARIABLES[$1.to_sym]) if VARIABLES[$1.to_sym]
  337.           self.send("rollback_#{UNIT[UNIT.index($1.to_sym) + 1]}")
  338.         end
  339.       else raise(NoMethodError) end
  340.     end
  341.    
  342.     # Convenience methods to cleanly enable or disable time updates.
  343.     def enable() @time_enabled = true end
  344.     alias :start :enable; alias :run :start
  345.     def disable() @time_enabled = false end
  346.     alias :pause :disable; alias :stop :pause
  347.    
  348.     # This determines whether or not time is running. Note that this isn't
  349.     # necessarily whether or not time has been enabled, but if it's been told
  350.     # to run at all.
  351.     def running?()
  352.       return false if $game_map.no_time?
  353.       return true if $game_map.run_time?
  354.       return @time_enabled
  355.     end
  356.    
  357.     # Similarly, check if time is stopped (but not necessarily disabled).
  358.     def stopped?()
  359.       return true if $game_map.no_time?
  360.       return false if $game_map.run_time?
  361.       return !@time_enabled
  362.     end
  363.   end
  364.   #═╦═══════════════════════════════════════════════════════════════════════════
  365.   # ║ ▲ class Manager
  366.   #═╩═══════════════════════════════════════════════════════════════════════════
  367. end end
  368. #═╦═════════════════════════════════════════════════════════════════════════════
  369. # ║ ▲ module SES::Time
  370. #═╩═════════════════════════════════════════════════════════════════════════════
  371.                      ($imported ||= {})["SES - Time"] = 1.3
  372. #═╦═════════════════════════════════════════════════════════════════════════════
  373. # ║ ▼ class Game_System
  374. #═╩═════════════════════════════════════════════════════════════════════════════
  375. class Game_System
  376.   attr_reader :time
  377.  
  378.   alias :ses_time_gs_init :initialize
  379.   def initialize(*args, &block)
  380.     ses_time_gs_init(*args, &block)
  381.     @time = SES::Time::Manager.new
  382.   end
  383. end
  384. #═╦═════════════════════════════════════════════════════════════════════════════
  385. # ║ ▲ class Game_System
  386. #─╫─────────────────────────────────────────────────────────────────────────────
  387. # ║ ▼ class Game_Map
  388. #═╩═════════════════════════════════════════════════════════════════════════════
  389. class Game_Map
  390.   attr_reader :last_map
  391.  
  392.   # Aliasing setup to record the previous map's information whenever a new map
  393.   # is entered. This is done for the tone-changing code in Scene_Map below.
  394.   alias :ses_game_time_gm_setup :setup
  395.   def setup(*args, &block)
  396.     @last_map = @map unless @map.nil?
  397.     ses_game_time_gm_setup(*args, &block)
  398.   end
  399.  
  400.   # Methods to check for the presence of various note tags.
  401.   def no_tone?(map = @map) map.note =~ /\<time no\_tone\>/ unless map.nil? end
  402.   def no_time?(map = @map) map.note =~ /\<time stop\>/ unless map.nil? end
  403.   def run_time?(map = @map) map.note =~ /\<time run\>/ unless map.nil? end
  404. end
  405. #═╦═════════════════════════════════════════════════════════════════════════════
  406. # ║ ▲ class Game_Map
  407. #─╫─────────────────────────────────────────────────────────────────────────────
  408. # ║ ▼ class Scene_Base
  409. #═╩═════════════════════════════════════════════════════════════════════════════
  410. class Scene_Base
  411.   # Update the time in every Scene class (considering there's no reasonable way
  412.   # to know which scenes in particular the user is going to want time in).
  413.   alias :ses_game_time_sb_upd :update
  414.   def update(*args, &block)
  415.     ses_game_time_sb_upd(*args, &block)
  416.     $game_system.time.update
  417.   end
  418. end
  419. #═╦═════════════════════════════════════════════════════════════════════════════
  420. # ║ ▲ class Scene_Base
  421. #─╫─────────────────────────────────────────────────────────────────────────────
  422. # ║ ▼ class Scene_Map
  423. #═╩═════════════════════════════════════════════════════════════════════════════
  424. class Scene_Map < Scene_Base
  425.   # Aliasing post_transfer to cleanly change the tone of the map we're going to
  426.   # if the previous map requested no tone updates and the new map wants them.
  427.   # This is mostly cosmetic, and done before the original method is run.
  428.   alias :ses_game_time_sm_post :post_transfer
  429.   def post_transfer(*args, &block)
  430.     if $game_map.no_tone?($game_map.last_map)
  431.       unless $game_map.no_tone?
  432.         time = $game_system.time
  433.         return if time.stopped? && !time.running?
  434.         tone = SES::Time::TONES[time.send(SES::Time::TONE_UNIT)]
  435.         $game_map.screen.start_tone_change(tone, 1)
  436.       end
  437.     end
  438.     ses_game_time_sm_post(*args, &block)
  439.   end
  440. end
  441. #═╦═════════════════════════════════════════════════════════════════════════════
  442. # ║ ▲ class Scene_Map
  443. #═╩═════════════════════════════════════════════════════════════════════════════
Advertisement
Add Comment
Please, Sign In to add comment