Jump to content
kirip

Shared HP Battle System

Recommended Posts

Shared HP Battle System

rrFWQfJ.png

 

Hello everyone, this is my first script that I'm working on, still learning the ropes but I think I have somewhat of a grasp with Ruby. Feel free to laugh at my terrible code and give me pointers on how to improve upon it.

This system is functionally identical to the default battle system, but the difference is, everyone's HP is pooled together and when any member heals or takes damage, only the pool is affected.
Another thing to note is that this system adds to the default menu screen to show the party's current total HP.

This is still a work-in-progress so please don't mind the messiness. I actually would love input on how to improve upon updating the GUI to reflect this system.

Functionally, there shouldn't be any bugs, but please let me know if you run into any.

 

As far as I'm concerned, this is functionally complete.

 

All these are posted above Main.

 

 

UPDATE (4/29)

Just cleaned up some code for potential compatibility with other scripts in the future.

Also this is now compatible with Neo Gauge Ultimate Ace!

 

Shared_HP

 

 

#Values for Shared HP in Game_Party class

class Game_Party < Game_Unit
  
  alias :partyhealth    :initialize
  
  attr_reader   :partyhp
  attr_reader   :cappedhp
  
  
  def initalize
  partyhealth
  @partyhp = 0
  @cappedhp = 0
  end
  
  def pthealth(hp)
  @partyhp = hp
  end
  
  def cappedhealth(maxhp)
  @cappedhp = maxhp
  end
  
  def init_sharedHP
    
    partyhp = 0
    $game_party.battle_members.each do |actor|
    partyhp = partyhp + actor.mhp 
    end
    
    $game_party.pthealth(partyhp)
    $game_party.cappedhealth(partyhp)

  end
  
  
  
  #--------------------------------------------------------------------------
  # * Add an Actor
  #--------------------------------------------------------------------------
  def add_actor(actor_id)
  
  # affectedhp is the variable that stores the added actor's HP.
  #--------------------------------------------------------------------------
  affectedhp = 0

    
    is_dupe = @actors.include?(actor_id)
    @actors.push(actor_id) unless @actors.include?(actor_id)
    
    if (in_battle && !is_dupe)
    $game_party.battle_members.each do |actor|
    affectedhp = actor.hp if actor_id == actor.id
      end
      $game_party.cappedhealth($game_party.cappedhp + affectedhp) 
      $game_party.pthealth($game_party.cappedhp) if $game_party.cappedhp < $game_party.partyhp
      
    end
    
    
    $game_player.refresh
    $game_map.need_refresh = true
    
    

  end
  #--------------------------------------------------------------------------
  # * Remove Actor
  #--------------------------------------------------------------------------
  def remove_actor(actor_id)
    affectedhp = 0
    if (in_battle)
  
  # This checks for the removed actor to get their HP value.
  #--------------------------------------------------------------------------
    $game_party.battle_members.each do |actor|
    affectedhp = actor.hp if actor_id == actor.id
      end
      $game_party.cappedhealth($game_party.cappedhp - affectedhp) 
      $game_party.pthealth($game_party.cappedhp) if $game_party.cappedhp < $game_party.partyhp
      
    end
    
    @actors.delete(actor_id)
    $game_player.refresh
    $game_map.need_refresh = true

  end

end

module BattleManager


  #--------------------------------------------------------------------------
  # * Determine Win/Loss Results
  #--------------------------------------------------------------------------
  
  
  
  def self.judge_win_loss
    if @phase
      return process_abort   if $game_party.members.empty?
      return process_defeat  if $game_party.partyhp < 1
      return process_victory if $game_troop.all_dead?
      return process_abort   if aborting?
    end
    return false
  end
     
  class << self
    alias :sharedhpsetup :setup
  end
  
  #--------------------------------------------------------------------------
  # * Setup shared HP
  #--------------------------------------------------------------------------
  def self.setup(troop_id, can_escape = true, can_lose = false)
    sharedhpsetup(troop_id, can_escape, can_lose)
    $game_party.init_sharedHP
  end
     
  
end


class Game_Battler < Game_BattlerBase

#-------------------------------------------------------------------------------
# Modified so that total HP is affected instead of actor HP when taking damage.
#-------------------------------------------------------------------------------
def execute_damage(user)
  
  
    on_damage(@result.hp_damage) if @result.hp_damage > 0
    self.mp -= @result.mp_damage
    

# When actor takes damage, subtract it from pool of HP instead.
#-------------------------------------------------------------------------------
    if (actor?)
    $game_party.pthealth($game_party.partyhp - @result.hp_damage)
    $game_party.partyhp($game_party.cappedhp) if $game_party.partyhp > $game_party.cappedhp
    $game_party.pthealth(0) if $game_party.partyhp < 1
    else

# Normal operation
#-------------------------------------------------------------------------------
    self.hp -= @result.hp_damage
    end
    user.hp += @result.hp_drain
    user.mp += @result.mp_drain
    
    
  end
#-------------------------------------------------------------------------------  
# Modifies so that total HP is affected instead of actor HP when healing damage.
#-------------------------------------------------------------------------------
  
  def item_effect_recover_hp(user, item, effect)
    
    value = (mhp * effect.value1 + effect.value2) * rec
    value *= user.pha if item.is_a?(RPG::Item)
    value = value.to_i
    @result.hp_damage -= value
    @result.success = true
    
# When actor is healed, add it to pool of HP instead.
#-------------------------------------------------------------------------------   
    if (actor?)
    $game_party.pthealth($game_party.partyhp + value)
    $game_party.pthealth($game_party.cappedhp) if $game_party.partyhp > $game_party.cappedhp

# Normal operation
#-------------------------------------------------------------------------------
    else
    self.hp += value
    end

  end
  
  
end
  
  class Game_BattlerBase
#-------------------------------------------------------------------------------
# Modifies change HP to only affect sharedHP
# TODO: Make it so entire party HP is only applied once
#-------------------------------------------------------------------------------
    
    def change_hp(value, enable_death)
      if !enable_death && @hp + value <= 0
      self.hp = 1 if enemy?
      $game_party.pthealth(1) if actor?
      else
      self.hp += value if enemy?
      $game_party.pthealth($game_party.partyhp + value) if actor?
      end
    end
  
  end


 

 

Shared_HP_ValueDisplay

 

 

#Shared_HP_ValueDisplagy

class Window_Base < Window
  

  #--------------------------------------------------------------------------
  # * Draw HP
  #--------------------------------------------------------------------------
  def draw_actor_hp(actor, x, y, width = 124)
    change_color(system_color)
    draw_text(x, y, 30, line_height, Vocab::hp_a)
    change_color(normal_color)
    draw_text(x + 30, y, 42, line_height, actor.mhp, 2)

  end
 

  
end




  module SharedHP
    GAUGE_NAME = "HP" 
    MENU_HP_NAME = "TEAM HP"
    HPMAXSLASH = "/"
  end

  class Window_Party_HP < Window_Selectable
    
  alias :party_hp_display                               :draw_text_ex
    

  #--------------------------------------------------------------------------
  # * Object Initialization
  #--------------------------------------------------------------------------
  
  #---
  # Sets location of the shared HP Window
  #---
  
  def initialize
    super(0, 0, window_width, window_height)
    self.opacity = 0
    self.y = Graphics.height - fitting_height(6) + 14
    refresh
  end
  #--------------------------------------------------------------------------
  # * Get Window Width
  #--------------------------------------------------------------------------
  def window_width
    return Graphics.width
  end
  
  #--------------------------------------------------------------------------
  # * Window Height
  #--------------------------------------------------------------------------  
  def window_height
    return fitting_height(1)
  end
  
  #--------------------------------------------------------------------------
  # * Rate
  #--------------------------------------------------------------------------  
  def rate
    return $game_party.partyhp.to_f / $game_party.cappedhp
  end
  
  #--------------------------------------------------------------------------
  # * Gauge colors
  #--------------------------------------------------------------------------  
  def gaugecolor
    return text_color(10) if rate <= 0.2
    return text_color(6) if rate <= 0.4
    return text_color(1) if rate <= 0.6
    return text_color(4) if rate < 1
    return text_color(3) if rate >= 1
  end
  
  def draw_text_exHP(x, y, text)
    
    reset_font_settings
    change_color(gaugecolor)
    pos = {:x => x, :y => y, :new_x => x, :height => calc_line_height(text)}
    process_character(text.slice!(0, 1), text, pos) until text.empty?

  end
  
  #--------------------------------------------------------------------------
  # * Refresh
  #--------------------------------------------------------------------------
  def refresh
    contents.clear
  
  #--------------------------------------------------------------------------
  # * Gets max HP and HP values to display.
  #--------------------------------------------------------------------------
  
    hpcheck = $game_party.partyhp.to_s
    maxhpcheck = SharedHP::HPMAXSLASH + $game_party.cappedhp.to_s
  
  #--------------------------------------------------------------------------
  # * Handles position of the displayed HP values.
  #--------------------------------------------------------------------------  
    repositionhp = self.text_size(hpcheck)
    repositionmaxhp = self.text_size(maxhpcheck)
  #--------------------------------------------------------------------------
  # * Takes the width value of the window, then subtracts it by the width
  # of the max HP text to display it at the edge of the gauge properly.
  #-------------------------------------------------------------------------- 
    maxHpPos = item_width - repositionmaxhp.width
    currentHpPos = maxHpPos - repositionhp.width
    draw_gauge(0, 0, window_width, rate, gaugecolor, gaugecolor)
    
  #--------------------------------------------------------------------------
  # * Draws the HP values.
  #--------------------------------------------------------------------------  
    draw_text_ex(0, 0, SharedHP::GAUGE_NAME)
    draw_text_exHP(maxHpPos, 0, maxhpcheck)
    draw_text_exHP(currentHpPos, 0, hpcheck)
  end

  #--------------------------------------------------------------------------
  # * Open Window
  #--------------------------------------------------------------------------
  def open
    refresh
    super
  end
end


  #--------------------------------------------------------------------------
  # * Calls the window for the shared HP bar.
  #--------------------------------------------------------------------------  
class Scene_Battle < Scene_Base
  
  #--------------------------------------------------------------------------
  # * Aliased Methods
  #--------------------------------------------------------------------------  
  alias :party_hp_display                               :start
  alias :party_hp_update                                :refresh_status

  #--------------------------------------------------------------------------
  # * Start Processing
  #--------------------------------------------------------------------------
  def start
    party_hp_display
    display_party_hp
  end
  #--------------------------------------------------------------------------
  # * Show party HP
  #--------------------------------------------------------------------------  
  def display_party_hp
    @hp_gauge = Window_Party_HP.new
  end
  
  def refresh_status
    party_hp_update
    @hp_gauge.refresh
  end
  
  

end



 

 

Shared_HP_MenuWindow

 

 

#Shared_HP_ValueDisplay

class Window_Base < Window
 

  #--------------------------------------------------------------------------
  # * Draw HP
  #--------------------------------------------------------------------------
  def draw_actor_hp(actor, x, y, width = 124)
    change_color(system_color)
    draw_text(x, y, 30, line_height, Vocab::hp_a)
    change_color(normal_color)
    draw_text(x + 30, y, 42, line_height, actor.mhp, 2)

  end
 

 
end




  module SharedHP
    GAUGE_NAME = "HP"
    MENU_HP_NAME = "TEAM HP"
    HPMAXSLASH = "/"
    
    
    
  end

  class Window_Party_HP < Window_Base
    
  alias :party_hp_display                               :draw_text_ex
    

  #--------------------------------------------------------------------------
  # * Object Initialization
  #--------------------------------------------------------------------------
 
  #---
  # Sets location of the shared HP Window
  #---
 
  def initialize
    super(0, 0, window_width, window_height)
    self.opacity = 0
    self.y = Graphics.height - fitting_height(6) + 14
    refresh
  end
  #--------------------------------------------------------------------------
  # * Get Window Width
  #--------------------------------------------------------------------------
  def window_width
    return Graphics.width
    #return 400
  end
 
  #--------------------------------------------------------------------------
  # * Window Height
  #--------------------------------------------------------------------------  
  def window_height
    return fitting_height(1)
  end
 
  def item_width
    return window_width - 26
    end
 
 
  #--------------------------------------------------------------------------
  # * Rate
  #--------------------------------------------------------------------------  
  def rate
    return $game_party.partyhp.to_f / $game_party.cappedhp
  end
 
  #--------------------------------------------------------------------------
  # * Gauge colors
  #--------------------------------------------------------------------------  
  def gaugecolor
    return text_color(10) if rate <= 0.2
    return text_color(6) if rate <= 0.4
    return text_color(1) if rate <= 0.6
    return text_color(4) if rate < 1
    return text_color(3) if rate >= 1
  end
 
  def draw_text_exHP(x, y, text)
    
    reset_font_settings
    #----------------------------------------------------------------------
    #If you want to change the color of the text, uncomment the line below.
    #----------------------------------------------------------------------
    #change_color(gaugecolor)
    pos = {:x => x, :y => y, :new_x => x, :height => calc_line_height(text)}
    process_character(text.slice!(0, 1), text, pos) until text.empty?

  end
 
 
  def draw_hp_value
  #--------------------------------------------------------------------------
  # * Gets max HP and HP values to display.
  #--------------------------------------------------------------------------
    hpcheck = $game_party.partyhp.to_s
    maxhpcheck = SharedHP::HPMAXSLASH + $game_party.cappedhp.to_s
  #--------------------------------------------------------------------------
  # * Handles position of the displayed HP values.
  #--------------------------------------------------------------------------  
    repositionhp = self.text_size(hpcheck)
    repositionmaxhp = self.text_size(maxhpcheck)
  #--------------------------------------------------------------------------
  # * Takes the width value of the window, then subtracts it by the width
  # of the max HP text to display it at the edge of the gauge properly.
  #--------------------------------------------------------------------------
    maxHpPos = item_width - repositionmaxhp.width
    currentHpPos = maxHpPos - repositionhp.width
  #--------------------------------------------------------------------------
  # * Draws the HP values.
  #--------------------------------------------------------------------------
    draw_text_ex(0, 0, SharedHP::GAUGE_NAME)
    draw_text_exHP(maxHpPos, 0, maxhpcheck)
    draw_text_exHP(currentHpPos, 0, hpcheck)
  end
 
  #--------------------------------------------------------------------------
  # * Refresh
  #--------------------------------------------------------------------------
  def refresh
    contents.clear
    draw_gauge(0, 0, window_width, rate, gaugecolor, gaugecolor)
    draw_hp_value
  end

  #--------------------------------------------------------------------------
  # * Open Window
  #--------------------------------------------------------------------------
  def open
    refresh
    super
  end
end


  #--------------------------------------------------------------------------
  # * Calls the window for the shared HP bar.
  #--------------------------------------------------------------------------  
class Scene_Battle < Scene_Base
 
  #--------------------------------------------------------------------------
  # * Aliased Methods
  #--------------------------------------------------------------------------  
  alias :party_hp_display                               :start
  alias :party_hp_update                                :refresh_status

  #--------------------------------------------------------------------------
  # * Start Processing
  #--------------------------------------------------------------------------
  def start
    party_hp_display
    display_party_hp
  end
  #--------------------------------------------------------------------------
  # * Show party HP
  #--------------------------------------------------------------------------  
  def display_party_hp
    @hp_gauge = Window_Party_HP.new
  end
 
  def refresh_status
    party_hp_update
    @hp_gauge.refresh
  end
 
 

end




 

 

 

Also, for those that wish to use this with Yanfly's Ace Battle Engine, I've taken the liberty to make sure this is compatible with it.

 

I find the GUI of the system PERFECT for this.

 

Yanfly's Ace Battle Engine compatibility, instructions are in script

 

 

#-------------------------------------------------------------------------------------------------
# Shared_HP scripts go above YEA Ace Battle Engine, this script goes below YEA Ace Battle Engine.
#-------------------------------------------------------------------------------------------------
 
class Scene_Battle < Scene_Base
 
 
  #--------------------------------------------------------------------------
  # alias method: execute_action
  #--------------------------------------------------------------------------
  alias abe_shared_hp execute_action
  def execute_action
    abe_shared_hp
    refresh_status
  end  
 
  #--------------------------------------------------------------------------
  # overwrite method: refresh_status
  #--------------------------------------------------------------------------
  def refresh_status
    party_hp_update
    @hp_gauge.refresh
  end
 
 
 
end
 
class Window_BattleStatus < Window_Selectable
  #--------------------------------------------------------------------------
  # overwrite method: draw_actor_hp, HP doesn't show since you won't need that info
  #--------------------------------------------------------------------------
  def draw_actor_hp(actor, dx, dy, width = 124)
 
  end
 

 

 

NEO Gauge compatibility patch, instructions in script

 

 

#------------------------------------------------------------------------------
# This script goes below the Shared_HP scripts, while NEO Gauge goes above.
#------------------------------------------------------------------------------

class Window_Base < Window  
  
  
  USE_SHARED_HP_GAUGE = true # Uses NEO GAUGE for to displayed SHARED_HP instead

  
  
    
  def draw_shared_hp(x, y, width)
    gwidth = width * $game_party.partyhp / $game_party.cappedhp
    cg = neo_gauge_back_color
    c1, c2, c3 = cg[0], cg[1], cg[2]
    draw_neo_gauge(x + HPMP_GAUGE_X_PLUS, y + line_height - 8 +
      HPMP_GAUGE_Y_PLUS, width, HPMP_GAUGE_HEIGHT, c1, c2, c3)
    (1..3).each {|i| eval("c#{i} = HP_GCOLOR_#{i}")}
    draw_neo_gauge(x + HPMP_GAUGE_X_PLUS, y + line_height - 8 +
      HPMP_GAUGE_Y_PLUS, gwidth, HPMP_GAUGE_HEIGHT, c1, c2, c3, false, false,
      width, 30)
    draw_hp_value
  end  
  


end
  
  
$imported ||= {}
$imported[:neo_gauge_ultimate]

class Window_Party_HP < Window_Base
  if USE_SHARED_HP_GAUGE
    def refresh
    contents.clear
    draw_shared_hp(0, 0, window_width)
    end  
  end
  

end

 

 

This is my first time posting a script, if I messed up in some way, please let me know.

Edited by kirip

Share this post


Link to post
Share on other sites

So, could you do this for enemies? This would be nice for a multiple part enemy that you want to affect with states and attacks.

 

For instance, the head of a hydra can be "cut" by a slashing attack and in two turns it would grow 2 more heads. This would up allow the add-in of one more hydra head, more damage, but less health, while also sustaining the idea that you're fighting one creature.

 

--I am terribad at explaining things. Either way, good job.

Share this post


Link to post
Share on other sites

Nice script kirip, especially for a first! Were you looking for pointers on cleaning up/improving the code at all, or are you happy enough with it as-is? There's nothing wrong with it per-se, but I've noticed a few places it could be optimised. ^_^

Share this post


Link to post
Share on other sites

@Galdelonian: I could give that a try at some point, the idea did come across my head at one point.

 

@Trihan: I would love optimization/clean-up/improving tips!

Share this post


Link to post
Share on other sites

It is indeed a good concept, but calling it a battle system is a green apple for now. Is the font of the numbers denoting the value of the gauge really green? It could be confusing, so watch out for that part.

 

As for your window, you should hook it up more directly to window_base rather than going to Window_Selectable, especially if there's no big reason for you to inherit it there.

 

Overall though it is a good battle system and I am impressed that this is your first script. Good luck with your scripting :)

Share this post


Link to post
Share on other sites

It is indeed a good concept, but calling it a battle system is a green apple for now. Is the font of the numbers denoting the value of the gauge really green? It could be confusing, so watch out for that part.

 

As for your window, you should hook it up more directly to window_base rather than going to Window_Selectable, especially if there's no big reason for you to inherit it there.

 

Overall though it is a good battle system and I am impressed that this is your first script. Good luck with your scripting :)

Thank you very much! I'll see what I do about the window for the gauge sometime.

 

You do bring up a good point about the confusing colors, though. I was trying to go for the color matching the gauge to make it look nice.

 

I was inspired by the gauge in the mobile game, Puzzle and Dragons, if anyone was curious. I just realized that their gauge is a static color while the font is based on the percentage of health you have left. I ended up linking both the gauge and font color to the same thing.

Share this post


Link to post
Share on other sites

If I  get a moment I'll have a run through it and see what optimisations I can suggest, then. :)

Share this post


Link to post
Share on other sites

Here are my thoughts of the things you should allow the user of your script should have, not that it must...

 

  • Gauge Adjustment - adjust the size of the gauge
  • x and y dimensions for the text of the gauge - a part where they can easily adjust where the whole text are shown (it could go with the gauge as well).

It's not much but you can also research a bit and make an add on where you can change the width and height of the gauge or use a custom gauge. You know, these are little details, they sure are not something you should do, but just in case you want it to look better than it is now :)

Share this post


Link to post
Share on other sites

Is it compatible with the Neo Gauge?

I just made it compatible now, lemme know if it works out well.

 

@Galedelonian: I haven't forgotten about your request yet!

Edited by kirip

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

  • Recently Browsing   0 members

    No registered users viewing this page.

×