ForeverZer0 44 Report post Posted May 15, 2011 Hunger & Thirst Authors: ForeverZer0 Version: 1.1 Type: Party/Actor Add-On Introduction Basically the title says it all. This script will add a Hunger/Thirst dynamic to your game. Actor's hunger/thirst will decrease over time or by stepcount. Has configuration for food/drink items and for states that will be added to actors whose hunger/thirst falls within specified ranges. Features Easy to use Hunger/Thirst can decrease by time, stepcount, or both. Can have the player's max hunger/thirst capacity increase with levels Easy script offer complet manipulation of system and actors' hunger/thirst Automatically applies states (configurable) Hunger/Thirst recovery can be by either percent or by absolute value Screenshots None. Demo None. Script Click here for the script. #:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=: # Hunger/Thirst # Author: ForeverZer0 # Date: 5.14.2010 # Version: 1.0 #:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=: # # Features: # - Easy to use # - MUCH less complicated than many other similar scripts, yet it has more # features and less code # - Can have hunger and thirst decrease by time intervals or by steps walked # by the player # - Ability to have each character's 'Max Hunger' increase so that they can go # longer in between food and drinks as they gain in power # - Can use script calls to easily change hunger/thirst values, and to disable # the system for long cutscenes, etc. so that nothing decreases while the # player does not have control # - Automatically added states if hunger/thirst is at specific rates. # # Compatibility: # - If using Zero Add-On Collection, place this script below it. There is a # minor issue with the Chemist Class script, but placing this script below # it will solve the problem. # # Instructions: # - Place script below debug, and above main (below Zer0 Add-Ons, if present) # - All configuration is below and described fully in its respective section # - The following script calls can be used in game: # # ? Zer0.hunger_system(true/false) # - If false, hunger/thirst rates will not decrease. Good for long scenes # where the player is not in control, etc. The system will remain ON/OFF # until it is changed. # # ? Zer0.set_hunger(ACTOR_ID, AMOUNT) # ? Zer0.set_thirst(ACTOR_ID, AMOUNT) # - Sets the hunger/thirst of actor in your database with ACTOR_ID to the # number specified by AMOUNT # # ? Zer0.set_max_hunger(ACTOR_ID, AMOUNT) # ? Zer0.set_max_thirst(ACTOR_ID, AMOUNT) # - Sets the MAX hunger/thirst of actor in your database with ACTOR_ID to # the number specified by AMOUNT # # ? Zer0.recover_hunger(ACTOR_ID) # - Will recover all hunger/thirst to actor with ACTOR_ID. If you omit the # ( ) at the end of the script call, it will recover the entire party. # # ? Zer0.actor_hunger_id(ACTOR_ID) # - Returns the current hunger of actor with ACTOR_ID # # ? Zer0.actor_thirst_id(ACTOR_ID) # - Returns the current thirst of actor with ACTOR_ID # # ? Zer0.actor_hunger_pos(POSITION) # - Return the current hunger of actor at party POSITION # (0 is the leader, 1 is actor 2, etc) # # ? Zer0.actor_thirst_pos(POSITION) # - Return the current thist of actor at party POSITION # (0 is the leader, 1 is actor 2, etc) # # ? Zer0.hunger_debugger # - Displays info on-screen of each characters hunger/thirst, current # count for steps and time, and shows which features are currently ON. # # Special Thanks: # - kukusu, whose request gave me the inspiration for the script # - SBR*, for pointing out a stupid error I made with the stepcount # #:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=: #:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=: # BEGIN CONFIGURATION #:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=: module Zer0 DEFAULT_HUNGER = 100 DEFAULT_THIRST = 100 # Default max hunger/thirst players will begin with. This can be increased as # the player becomes more powerful, through items, etc. if desired. BY_TIME = true BY_STEPS = true # There are two ways hunger and thirst can be calculated; one by just how many # seconds pass, and the other by how many steps have been taken. You can use # both if you like, but I would suggest that if you do to try to keep it more # skewed to one or the other as the main method of decreasing, and use the # other as a minor added dynamic. STEPS_HUNGER_DOWN = 100 STEPS_THIRST_DOWN = 80 # Only if using 'BY_STEPS', otherwise ignore these. These are the amount # of steps before hunger/thirst decrease. SECS_HUNGER_DOWN = 120 SECS_THIRST_DOWN = 120 # Only if using 'BY_TIME', otherwise ignore these. These are the amount # of seconds before hunger/thirst decrease. LVL_UP_INCREASE = true # If true, will increase max hunger/thirst at each level up, the amount of # increase is defined just below. LVL_UP_AMOUNT = 5 # This will be added to the actor's max hunger/thirst at each level up, only # if LVL_UP_INCREASE is true. #------------------------------------------------------------------------------- # Food/Drink Items: # # Set up your food/drink items recovery rates here. Food and drink are each in # their own section. Use this syntax to set them up: # # when ITEM_ID the return RECOVERY_AMOUNT # # For example, in the first example below, it means that the item in your # database with ID(1) will cure hunger by 15. If RECOVER_BY_PERCENT (below) is # set to true, it will recover 15% of that actors MAX hunger/thirst. # # You can also create items that have negative effects by making the # RECOVERY_AMOUNT a negative number. DO NOT have food/drink items do anything # other than recover hunger/thirst and/or add/remove states. Anything else, # such has HP/MP recovery, will have no effect. # #------------------------------------------------------------------------------- RECOVER_BY_PERCENT = true # Recovery can be by either absolute value, or by percent. Setting this to # true will make it by percent. def self.food(item_id) case item_id when 1 then return 15 when 2 then return 25 when 3 then return 35 when 4 then return 50 when 5 then return 75 when 6 then return 100 end end def self.drink(item_id) case item_id when 1 then return 15 when 2 then return 25 when 3 then return 35 when 4 then return 50 when 5 then return 75 when 6 then return 100 end end #------------------------------------------------------------------------------- # Hunger/Thirst States # # Set up states that will be applied when an actors hunger/thirst fall within # a defined range, such as 'Starvation', 'Dehydration', etc. # Configure like this: # # when MIN..MAX then return STATE_ID # # If actor's hunger/thirst is equal to or between MIN and MAX, the state with # STATE_ID will be applied. This method is refreshed everytime the system # decreases hunger/thirst. # # Keep in mind that these states will NOT be automatically cured if the actor's # hunger/thirst rise above. Create your food/drink items to cure these states. # #------------------------------------------------------------------------------- def self.hunger_states(current_hunger) case current_hunger when 0 then return 1 when 1..9 then return 2 when 10..15 then return 3 end end def self.thirst_states(current_thirst) case current_thirst when 0 then return 1 when 1..9 then return 2 when 10..15 then return 3 end end #:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=: # END CONFIGURATION #:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=: def self.hunger_system(value) $game_party.hunger = value return true end def self.set_hunger(actor_id, amount) $game_party.actors.each {|a| a.hunger = amount if a.id == actor_id} end def self.set_thirst(actor_id, amount) $game_party.actors.each {|a| a.thirst = amount if a.id == actor_id} end def self.set_max_hunger(actor_id, amount) $game_party.actors.each {|a| a.max_hunger = amount if a.id == actor_id} end def self.set_max_thirst(actor_id, amount) $game_party.actors.each {|a| a.max_thirst = amount if a.id == actor_id} end def self.actor_hunger_id(actor_id) $game_party.actors.each {|a| return a.hunger if a.id == actor_id} end def self.actor_thirst_id(actor_id) $game_party.actors.each {|a| return a.thirst if a.id == actor_id} end def self.actor_hunger_pos(pos = 0) return $game_party.actors[pos].hunger if $game_party.actors[pos] != nil end def self.actor_thist_pos(position = 0) return $game_party.actors[pos].thirst if $game_party.actors[pos] != nil end def self.recover_hunger(actor_id = nil) $game_party.actors.each {|actor| if actor_id == nil actor.hunger = actor.max_hunger actor.thirst = actor.max_thirst elsif actor.id == actor_id actor.hunger = actor.max_hunger actor.thirst = actor.max_thirst end } end def self.hunger_debugger sys = "System ON: #{$game_party.hunger}\n\n" + "By Time: #{BY_TIME}\n" + "By Steps: #{BY_STEPS}\n\n" actors = '' $game_party.actors.each {|actor| actors += "#{actor.name}\nHunger: #{actor.hunger}\\#{actor.max_hunger}\n" + "Thirst: #{actor.thirst}\\#{actor.max_thirst}\n\n"} ht = "HungerTime: #{$game_party.time_hunger/40}\\#{SECS_HUNGER_DOWN}\n" tt = "ThirstTime: #{$game_party.time_thirst/40}\\#{SECS_THIRST_DOWN}\n" hs = "HungerStep: #{$game_party.steps}\\#{$game_party.step_hunger}\n" ts = "ThirstStep: #{$game_party.steps}\\#{$game_party.step_thirst}\n" print(sys + actors + ht + tt + hs + ts) end end #------------------------------------------------------------------------------- # ** Game_Actor #------------------------------------------------------------------------------- class Game_Actor < Game_Battler attr_accessor :hunger attr_accessor :max_hunger attr_accessor :thirst attr_accessor :max_thirst alias zer0_hunger_setup setup def setup(actor_id) zer0_hunger_setup(actor_id) @hunger = @max_hunger = Zer0::DEFAULT_HUNGER @thirst = @max_thirst = Zer0::DEFAULT_THIRST if Zer0::LVL_UP_INCREASE && @level > 1 increase = Zer0::LVL_UP_AMOUNT @hunger = @max_hunger = (@level - 1) * increase + Zer0::DEFAULT_HUNGER @thirst = @max_thirst = (@level - 1) * increase + Zer0::DEFAULT_THIRST end end alias zer0_hunger_level_up exp= def exp=(exp) level = @level zer0_hunger_level_up(exp) if Zer0::LVL_UP_INCREASE && level != @level lvls = @level - level @max_hunger += (Zer0::LVL_UP_AMOUNT * lvls) @max_thirst += (Zer0::LVL_UP_AMOUNT * lvls) end end end #------------------------------------------------------------------------------- # ** Game_Battler #------------------------------------------------------------------------------- class Game_Battler alias test item_effect def item_effect(item) food_item = false hunger_plus = Zer0.food(item.id) thirst_plus = Zer0.drink(item.id) if hunger_plus != nil if Zer0::RECOVER_BY_PERCENT hunger_plus = (self.max_hunger * (hunger_plus * 0.01)).ceil end self.hunger += hunger_plus self.hunger = [[self.hunger, self.max_hunger].min, 0].max food_item = true end if thirst_plus != nil if Zer0::RECOVER_BY_PERCENT thirst_plus = (self.max_thirst * (thirst_plus * 0.01)).ceil end self.thirst += thirst_plus self.thirst = [[self.thirst, self.max_thirst].min, 0].max food_item = true end if food_item states_plus(item.plus_state_set) states_minus(item.minus_state_set) return true end test(item) end end #------------------------------------------------------------------------------- # ** Game_Party #------------------------------------------------------------------------------- class Game_Party attr_accessor :hunger attr_accessor :time_hunger attr_accessor :time_thirst attr_accessor :step_hunger attr_accessor :step_thirst alias zer0_hunger_system_init initialize def initialize zer0_hunger_system_init @hunger = true @time_hunger = @time_thirst = 0 @step_hunger = Zer0::STEPS_HUNGER_DOWN @step_thirst = Zer0::STEPS_THIRST_DOWN end def check_hunger_states @actors.each {|actor| state_id = Zer0.hunger_states(actor.hunger) actor.add_state(state_id) if state_id != nil} end def check_thirst_states @actors.each {|actor| state_id = Zer0.thirst_states(actor.thirst) actor.add_state(state_id) if state_id != nil} end end #------------------------------------------------------------------------------- # ** Scene_Map #------------------------------------------------------------------------------- class Scene_Map alias zer0_hunger_map_upd update def update zer0_hunger_map_upd if $game_party.hunger update_hunger end end def update_hunger if Zer0::BY_TIME $game_party.time_hunger += 1 $game_party.time_thirst += 1 if $game_party.time_hunger == (Zer0::SECS_HUNGER_DOWN * 40) $game_party.actors.each {|actor| actor.hunger -= 1 unless actor.dead? || actor.hunger == 0} $game_party.check_hunger_states $game_party.time_hunger = 0 end if $game_party.time_thirst == (Zer0::SECS_THIRST_DOWN * 40) $game_party.actors.each {|actor| actor.thirst -= 1 unless actor.dead? || actor.thirst == 0} $game_party.check_thirst_states $game_party.time_thirst = 0 end end if Zer0::BY_STEPS if $game_party.steps == $game_party.step_hunger $game_party.actors.each {|actor| actor.hunger -= 1 unless actor.dead? || actor.hunger == 0} $game_party.check_hunger_states $game_party.step_hunger = $game_party.steps + Zer0::STEPS_HUNGER_DOWN end if $game_party.steps == $game_party.step_thirst $game_party.actors.each {|actor| actor.thirst -= 1 unless actor.dead? || actor.thirst == 0} $game_party.check_thirst_states $game_party.step_thirst = $game_party.steps + Zer0::STEPS_THIRST_DOWN end end end end Here is also an Add-On I made for the system. It is a HUD that displays hunger/thirst rates using gradient bars for the party. There are a few instructions in the script, but most are self-explanatory. As of the moment, there are only two styles of bars, but both have fully configurable width, height, gradient colors, etc. I may end up doing more with the Gradient Bars script in the future, but for the moment, it is what it is. #=============================================================================== # ** Hunger_HUD #=============================================================================== class Hunger_HUD < Window_Base #====================================================================# # BEGIN CONFIGURATION # #====================================================================# # Define the colors used for each of the bars. HUNGER_EMPTY = Color.new(255, 0, 0) HUNGER_FULL = Color.new(0, 255, 0) THIRST_EMPTY = Color.new(96, 96, 96) THIRST_FULL = Color.new(128, 128, 255) BACKGROUND_COLOR = Color.new(0, 0, 0) # Define the type of bar used. (0 = Gradient, 1 = Transitional) # It would take longer to explain the differences than to just try each out. # There's only two as of the moment. BAR_STYLE = 1 # Define the width and height, in pixels, of the bars. BAR_WIDTH = 128 BAR_HEIGHT = 8 #====================================================================# # END CONFIGURATION # #====================================================================# def initialize(y = -12) super(0, y, 640, 96) # Set the windowskin's opacity to 0. self.windowskin = nil @colors1 = [HUNGER_EMPTY, HUNGER_FULL, BACKGROUND_COLOR] @colors2 = [THIRST_EMPTY, THIRST_FULL, BACKGROUND_COLOR] @actors = $game_party.actors @stats = stats refresh end def refresh # Dispose the contents of the HUD. if self.contents != nil self.contents.dispose self.contents = nil end # Adjust width and location of window. self.width = @actors.size * (BAR_WIDTH + 48) self.x = (640 - self.width) / 2 self.contents = Bitmap.new(self.width, self.height) # Iterate actors. @actors.each_index {|i| actor = @actors[i] # Calculate locations for each actor's bars. x = i * (BAR_WIDTH + 48) # Draw actor's name. self.contents.font.size = 16 self.contents.draw_text(x, 0, BAR_WIDTH, 16, actor.name) # Draw hunger bars. w, h, rate, max = BAR_WIDTH, BAR_HEIGHT, @stats[i][0], @stats[i][1] self.contents.draw_bar(x, 16, w, h, rate, max, BAR_STYLE, @colors1) # Draw thirst bars. rate, max, height = @stats[i][2], @stats[i][3], 16+BAR_HEIGHT+4 self.contents.draw_bar(x, height, w, h, rate, max, BAR_STYLE, @colors2) } end def stats return @actors.collect {|a| [a.hunger, a.max_hunger, a.thirst, a.max_thirst]} end def update if (@stats != stats) || (@actors != $game_party.actors) @stats, @actors = stats, $game_party.actors refresh end end end #=============================================================================== # ** Gradient_Bar #=============================================================================== class Bitmap def draw_bar(x, y, w, h, rate, max, style, colors = nil) # Set required instance variables. @bar_rect = Rect.new(x, y, w, h) @rate, @max, @style, @colors = rate, max, style, colors # Define default colors if not defined. (RED <--> GREEN) if @colors == nil @colors = [Color.new(255, 0, 0), Color.new(0, 255, 0), Color.new(0, 0, 0)] end # Draw the background color. self.fill_rect(@bar_rect, @colors[2]) # Branch by what style is being used. case @style when 0 then gradient when 1 then transition end end #------------------------------------------------------------------------------- def gradient # Get the bar from the cache. key = [@style, @bar_rect.width-2, @bar_rect.height-2, @colors[0], @colors[1]] bar = RPG::Cache.gradient_bar(*key) # Draw the gradient bar using rectangular transfer. rect = Rect.new(0, 0, fill_width, @bar_rect.height) self.blt(@bar_rect.x+1, @bar_rect.y+1, bar, rect) end #------------------------------------------------------------------------------- def transition # Returns the color for current rate. c1 = [@colors[0].red, @colors[0].green, @colors[0].blue, @colors[0].alpha] c2 = [@colors[1].red, @colors[1].green, @colors[1].blue, @colors[1].alpha] rgba, rate = [], 1 - (@rate.to_f / @max) c1.each_index {|i| rgba[i] = c2[i] - ((c2[i] - c1[i]) * rate) } # Set the bars fill rate and color depending on value. rect = Rect.new(@bar_rect.x+1, @bar_rect.y+1, fill_width, @bar_rect.height-2) self.fill_rect(rect, Color.new(*rgba)) end #------------------------------------------------------------------------------- def fill_width # Calculate the difference, in percentage, of the min and max rates. return ((@rate / @max.to_f) * (@bar_rect.width - 2)).round end #------------------------------------------------------------------------------- end #=============================================================================== # ** Scene_Map #=============================================================================== class Scene_Map alias zer0_hunger_hud_main main def main # Add the bars to Scene_Map. @hunger_hud = Hunger_HUD.new zer0_hunger_hud_main @hunger_hud.dispose unless @hunger_hud.disposed? || @hunger_hud == nil end alias zer0_hunger_hud_upd update def update # Update the bars as needed. @hunger_hud.update zer0_hunger_hud_upd end end #=============================================================================== # ** RPG::Cache #=============================================================================== module RPG::Cache def self.gradient_bar(style, width, height, color1, color2) # Create a unique key to call the bar back with. path = [style, width, height, color1, color2] # Check if cache already has bitmap defined, if not create it now. if !@cache.include?(path) || @cache[path].disposed? bitmap, rates = Bitmap.new(width, height), [] # Iterate through each pixel horizontally, setting a gradient color. c1 = [color1.red, color1.green, color1.blue, color1.alpha] c2 = [color2.red, color2.green, color2.blue, color2.alpha] # Draw the bar, having in transition from the first color to the second. c1.each_index {|i| rates[i] = (c1[i] - c2[i]).to_f / width } (0...width).each {|i| values = [0, 1, 2, 3].collect {|j| c1[j] - (i * rates[j]) } # Set the color incrementally. This will be used later. bitmap.fill_rect(i, 0, 1, height, Color.new(*values)) } @cache[path] = bitmap end # Return the created bitmap. return @cache[path] end end Instructions Place below default scripts, and above Main. If Zer0 Add-On Collection is present, place below it. Compatibility There is an issue with the Chemist Class Script within Zer0 Add-Ons, but placing this script below it will solve the problem. Credits and Thanks ForeverZer0, for writing the script. kukusu, for requesting the script. SBR*, for pointing out an error I made. swick, for requesting the HUD. Author's Notes Please report any bug/issues you may find, and I'll be happy to fix them. Enjoy! Share this post Link to post Share on other sites