[XP] Design a HUD

Started by ThallionDarkshine, February 11, 2013, 06:49:18 pm

Previous topic - Next topic

ThallionDarkshine

February 11, 2013, 06:49:18 pm Last Edit: February 12, 2013, 07:17:19 am by ThallionDarkshine
Design a HUD
Authors: ThallionDarkshine
Version: 0.1
Type: Heads Up Display (HUD)
Key Term: Misc Add-on



Introduction

Have you ever seen some beautiful HUD and thought "I wish I knew how to script well enough to make something like that"? Well, now you don't need to. This is a framework allowing non-scripters to create stunning heads-up-displays using a simple (sort-of), html-based language. The HUD that you create can have custom pictures, icons, and gradient bars, as well as formatted text. You can align text, make it bold or italic, change its color, font, or size. The possibilities are endless (not quite) with the new Design a HUD framework.


Features


  • Create amazing HUDs easily with no scripting knowledge.

  • Display the values of variables in the HUD.

  • Display gradient bars for actors in the HUD.

  • Absolutely position elements or align them to different sides of the HUD.




Screenshots

Spoiler: ShowHide



Demo

No demo yet.


Script

Spoiler: ShowHide


module DesignHUD
  # This HUD uses an easy to use format for configuration much like html
  #   it has many types of tags, each inserting different information into the
  #   HUD, such as icons, hp/sp/xp bars, and different information about the
  #   actors.
  #
  # Tags:
  #
  #  Formatting Elements:
  #   * <i></i>
  #     - italicizes text
  #   * <b></b>
  #     - bolds text
  #   * <c=R:G:B[:A]></c>
  #     - changes the color to Color.new(R, G, B, A) (A is unnecessary)
  #   * <font=NAME:SIZE></font>
  #     - changes the font to NAME and the font size to SIZE
  #  Graphical Elements:
  #   * <ico=FILENAME>
  #     - inserts the icon named FILENAME
  #   * <pic=FILENAME>
  #     - inserts the picture named FILENAME
  #   * <bar style=STYLE type=TYPE cstyle=COLORSTYLE1:COLORSTYLE2... text=TEXT
  #      neaten=NEATEN lines=LINES shape=SHAPE dimensions=WIDTH:HEIGHT>
  #     - inserts a gradient bar with certain parameters that you can customize
  #     - types: :hp, :mp, :exp, :lvl
  #     - styles: 0 - 34
  #         0-6 - Linear top-to-bottom
  #           some are ease in or ease out or bilinear (starts from center)
  #         7-13 - Linear top-to-bottom stripes
  #           same as 0-6 except it uses stripes defined by four color styles
  #             instead of 2
  #         14-34 - Linear left-to-right
  #           some are ease in or ease out or bilinear or fade out on the top
  #             and bottom
  #     - shapes: 0 - 3
  #         0 - Rectangular
  #         1 - Slant Left
  #         2 - Rounded
  #         3 - Slant Right
  #     - color styles: 0 - 12
  #         color styles define the two endpoints of the gradient's colors
  #           for styles 7 - 13 use four color styles
  #         main two colors defined by the type
  #           :hp - Red and Green
  #           :mp - Red and Blue
  #           :exp - Orange and Yellow
  #           :lvl - Blue and Purple
  #         two mixed colors are defined by the percentage of the bar remaining
  #           Mixed1 - At 0% full, Color1, at 100% full, Color2
  #           Mixed2 - At 0% full, Color2, at 100% full, Color1
  #         real colors defined by color style
  #           0 - Color1
  #           1 - Color2
  #           2 - Black
  #           3 - Mixed1
  #           4 - Mixed2
  #           5 - Highlight of Color1
  #           6 - Highlight of Color2
  #           7 - Highlight of Mixed1
  #           8 - Highlight of Mixed2
  #           9 - Shadow of Color1
  #           10 - Shadow of Color2
  #           11 - Shadow of Mixed1
  #           12 - Shadow of Mixed2
  #  Positioning Elements:
  #   * <pos x=VALX y=VALY></pos>
  #     - positions the contents at an x position of VALX and
  #         at a y position of VALY
  #   * <offset x=VALX y=VALY></offset>
  #     - adds VALX and VALY to the position of the contents
  #   * <table></table>
  #     - starts a table
  #   * <tr></tr>
  #     - adds a row to a table
  #   * <td></td>
  #     - adds a cell to a row of a table
  #   * <left></left>
  #     - aligns the contents to the left
  #   * <center></center>
  #     - aligns the contents in the center
  #   * <right></right>
  #     - aligns the contents to the right
  #   * <ln></ln>
  #     - denotes one line in the HUD
  #   * <width=VAL></width>
  #     - sets the width of the contents to VAL
  #   * <height=VAL></height>
  #     - sets the height of the contents to VAL
  #  HUD Properties:
  #   * <hud>
  #     - this tag has many properties, listed below
  #   * windowskin='FILENAME'
  #     - sets the windowskin of the HUD to the windowskin named FILENAME
  #   * bg='FILENAME'
  #     - sets the background image of the HUD to the picture named FILENAME
  #   * align=ALIGN
  #     - sets the align of the HUD to ALIGN
  #     - possible aligns: TL, TC, TR, ML, MC, MR, BL, BC, BR (top-left,
  #         top-center, top-right, middle-left, middle-center, middle-right,
  #         bottom-left, bottom-center, bottom-right)
  #   * offsetx=VAL
  #     - sets the xoffset of the HUD to VAL
  #   * offsety=VAL
  #     - and the yoffset of the HUD to VAL
  #   * width=VAL
  #     - sets the width of the HUD to VAL
  #   * height=VAL
  #     - sets the height of the HUD to VAL
  #   * back_opacity=VAL
  #     - sets the back opacity of the HUD to VAL
  #   * contents_opacity=VAL
  #     - sets the contents opacity of the HUD to VAL
  #   * opacity=VAL
  #     - sets the opacity of the HUD to VAL
 
  HUD = <<-HUD
    <hud width=220 align=TL offsetx=16 offsety=16 opacity=0>
    <ln><center><var=name></center></ln>
    <ln>HP: <right><bar neaten=true lines=true text=false style=20 cstyle=0:3 shape=2></right></ln>
    <ln>SP: <right><bar type=:mp neaten=true lines=true text=false style=20 cstyle=0:3 shape=2></right></ln>
    <ln>EXP: <right><bar type=:exp neaten=true lines=true text=false style=20 cstyle=0:3 shape=2></right></ln>
    <ln>Level: <right><bar type=:lvl neaten=true lines=true text=false style=20 cstyle=0:3 shape=2></right></ln>
  HUD
 
  NO_END = ['ico', 'pic', 'hud', 'var', 'bar', 'shape']
 
  BLOCK_ELS = ['ln']
 
  def self.var_expression(name)
    case name
    when 'gold' then return proc { $game_party.gold }
    when 'name' then return proc { $game_party.actors[0].name }
    else return proc {}
    end
  end
 
  SPATTERN = /<([\w\-]+)(?:\s*=\s*([\w\"\'\-\_\:\$\.\s\+]+))?((?:\s*\w+\s*=\s*[\w\"\'\-\_\:\$\.\s\+]+)*)>/
end
class HUD < Window_Base
  attr_accessor :tmp_attrs
  def initialize(text)
    super(0, 0, 33, 33)
    self.contents = Bitmap.new(1, 1)
    self.visible = false
    @align = 'TL'
    @xoffset, @yoffset = 0, 0
    @tmp_attrs = {}
    @text = text
    Element.reset_id
    parse_text
    setup_hud
    setup_align
    @dom.delete_if { |el| el.el_type == 'hud' }
    self.width = [self.width, 33].max
    self.height = [self.height, 33].max
    self.contents = Bitmap.new(width - 32, height - 32)
    tmp = self.contents
    render_hud
  end
 

  def update
    redim = []
    vars = []
    redraw = []
    @var_nodes.each { |el|
      val = el.val
      if val != el.attrs[:val]
        vars.push(el)
        redim |= [el.last_line]
        pos = el.attrs[:pos]
        rect = el.attrs[:size]
        rect.x, rect.y = *pos
        rect.x += el.attrs[:ox]
        rect.y += el.attrs[:oy]
        self.contents.fill_rect(rect, Color.new(0, 0, 0, 0))
        el.attrs[:val] = val
      end
    }
    @dom.each { |el|
      comp = false
      el.each_child_ex2(proc { |child|
        comp = false
      }) { |child|
        if child.attrs[:size] and !comp
          pos = child.attrs[:pos]
          rect = child.attrs[:size]
          rect.x, rect.y = *pos
          rect.x += child.attrs[:ox] if child.attrs[:ox]
          rect.y += child.attrs[:oy] if child.attrs[:oy]
          if vars.select { |el|
            pos = el.attrs[:pos]
            tmp = el.attrs[:size]
            tmp.x, tmp.y = *pos
            tmp.x += el.attrs[:ox] if el.attrs[:ox]
            tmp.y += el.attrs[:oy] if el.attrs[:oy]
            tmp.intersect?(rect)
          }.length > 0
            redraw.push(child)
            self.contents.fill_rect(rect, Color.new(0, 0, 0, 0))
            comp = true
          end
        end
      }
    }
    redraw ||= vars
   
    if redim.length > 0
      redetermine_size(redim)
      setup_align
    end
    if redraw.length > 0
      redraw_hud(redraw)
    end
  end
 
  def redetermine_size(els)
    @tmp_attrs[:ox] = 0
    @tmp_attrs[:oy] = 0
   
    pos = [0, 0]
   
    @dom.each { |el|
      ln_height = ln_width = 0
   
      if els.include?(el)
        pos = el.attrs[:pos].clone unless @tmp_attrs[:tmp]
        if @tmp_attrs[:tmp]
          @tmp_attrs[:tmp].push(true)
        else
          @tmp_attrs[:tmp] = [true]
        end
      end

      case el.el_type
      when 'ln'
        el.each_child_ex(proc { |child|
          if @tmp_attrs[:tmp]
            unless child.attrs[:size].nil?
              rect = child.attrs[:size]
              rect.x, rect.y = *child.attrs[:pos]
              self.contents.fill_rect(rect, Color.new(0, 0, 0, 0))
            end
            if @tmp_attrs[:abs_pos]
              child.attrs[:pos] = [@tmp_attrs[:abs_pos].last[0], @tmp_attrs[:abs_pos].last[1]]
            else
              child.attrs[:pos] = [pos[0], pos[1]]
            end
            child.attrs[:ox], child.attrs[:oy] = @tmp_attrs[:ox], @tmp_attrs[:oy]
          end
          if els.include?(child)
            pos = child.attrs[:pos].clone unless @tmp_attrs[:tmp]
            if @tmp_attrs[:tmp]
              @tmp_attrs[:tmp].push(true)
            else
              @tmp_attrs[:tmp] = [true]
            end
          end
          case child
          when FormatNode
            tmp = child.attrs[:start].call(child, self)
            child.attrs = tmp if tmp and tmp.is_a?(Hash)
          end
        },
        proc { |child|
          case child
          when FormatNode
            tmp = child.attrs[:finish].call(child, self)
            child.attrs = tmp if tmp and tmp.is_a?(Hash)
          end
          if @tmp_attrs[:tmp]
            if els.include?(child)
              @tmp_attrs[:tmp].pop
              @tmp_attrs.delete(:tmp) if @tmp_attrs[:tmp].length == 0
            end
          end
          unless child.children.empty?
            resize(child)
          end
        }) { |child|
          if @tmp_attrs[:tmp]
            case child
            when TextNode
              size = self.contents.text_size(child.attrs[:val])
              child.attrs[:size] = size
              ln_height = [size.height, ln_height].max
              if @tmp_attrs[:abs_pos]
                tmp = @tmp_attrs[:abs_pos]
                ln_width = [tmp.last[0] + @tmp_attrs[:ox] + size.width, ln_width].max
                @tmp_attrs[:abs_pos][tmp.length - 1][0] += size.width
              else
                ln_width = [pos[0] + @tmp_attrs[:ox] + size.width, ln_width].max
                pos[0] += size.width
              end
            when VariableNode
              size = self.contents.text_size(child.val.to_s)
              child.attrs[:size] = size
              ln_height = [size.height, ln_height].max
              if @tmp_attrs[:abs_pos]
                tmp = @tmp_attrs[:abs_pos]
                ln_width = [tmp.last[0] + @tmp_attrs[:ox] + size.width, ln_width].max
                @tmp_attrs[:abs_pos][tmp.length - 1][0] += size.width
              else
                ln_width = [pos[0] + @tmp_attrs[:ox] + size.width, ln_width].max
                pos[0] += size.width
              end
            when IconNode, PictureNode, ShapeNode
              size = child.attrs[:bitmap].rect
              child.attrs[:size] = size
              ln_height = [size.height, ln_height].max
              if @tmp_attrs[:abs_pos]
                tmp = @tmp_attrs[:abs_pos]
                ln_width = [tmp.last[0] + @tmp_attrs[:ox] + size.width, ln_width].max
                @tmp_attrs[:abs_pos][tmp.length - 1][0] += size.width
              else
                ln_width = [pos[0] + @tmp_attrs[:ox] + size.width, ln_width].max
                pos[0] += size.width
              end
            when BarNode
              size = Rect.new(0,0,*child.attrs[:dimensions])
              child.attrs[:size] = size
              ln_height = [size.height, ln_height].max
              if @tmp_attrs[:abs_pos]
                tmp = @tmp_attrs[:abs_pos]
                ln_width = [tmp.last[0] + @tmp_attrs[:ox] + size.width, ln_width].max
                @tmp_attrs[:abs_pos][tmp.length - 1][0] += size.width
              else
                ln_width = [pos[0] + @tmp_attrs[:ox] + size.width, ln_width].max
                pos[0] += size.width
              end
            end
          end
        }
      end
     
      if @tmp_attrs[:tmp]
        if els.include?(el)
          @tmp_attrs[:tmp].pop
          @tmp_attrs.delete(:tmp) if @tmp_attrs[:tmp].length == 0
        end
      end
    }
    @dom.each { |child|
      if child.block?
        child.attrs[:size].width = self.width - 32
        child.attrs[:size].height = child.attrs[:height] || child.attrs[:size].height
        child.attrs[:size].width = child.attrs[:width] || child.attrs[:size].width
      end
    }
  end
 
  def redraw_hud(els)
    @tmp_attrs = {}
   
    @dom.each { |el|
   
      align = 0
     
      case el.el_type
      when 'ln'
        if els.include?(el)
          pos = el.attrs[:pos].clone unless @tmp_attrs[:tmp]
          if @tmp_attrs[:tmp]
            @tmp_attrs[:tmp].push(true)
          else
            @tmp_attrs[:tmp] = [true]
          end
        end
        el.each_child_ex(proc { |child|
          if els.include?(child)
            pos = child.attrs[:pos].clone unless @tmp_attrs[:tmp]
            if @tmp_attrs[:tmp]
              @tmp_attrs[:tmp].push(true)
            else
              @tmp_attrs[:tmp] = [true]
            end
          end
          case child
          when FormatNode
            child.attrs[:start].call(child, self)
          end
        },
        proc { |child|
          case child
          when FormatNode
            child.attrs[:finish].call(child, self)
          end
          if @tmp_attrs[:tmp]
            if els.include?(child)
              @tmp_attrs[:tmp].pop
              @tmp_attrs.delete(:tmp) if @tmp_attrs[:tmp].length == 0
            end
          end
        }) { |child|
          if @tmp_attrs[:tmp]
            draw_node(child)
          end
        }
      end
    }
  end
 
  def draw_node(node)
    case node
    when TextNode
      pos = node.attrs[:pos]
      ox, oy = node.attrs[:ox], node.attrs[:oy]
      text = node.attrs[:val]
      size = node.attrs[:size]
      self.contents.draw_text(Rect.new(pos[0] + ox, pos[1] + oy, size.width, size.height), text)
    when VariableNode
      pos = node.attrs[:pos]
      ox, oy = node.attrs[:ox], node.attrs[:oy]
      text = node.val.to_s
      size = node.attrs[:size]
      self.contents.draw_text(Rect.new(pos[0] + ox, pos[1] + oy, size.width, size.height), text)
    when IconNode, PictureNode, ShapeNode
      pos = node.attrs[:pos]
      ox, oy = node.attrs[:ox], node.attrs[:oy]
      bitmap = node.attrs[:bitmap]
      self.contents.blt(pos[0] + ox, pos[1] + oy, bitmap, bitmap.rect)
    when BarNode
      ln = node.last_line
      pos = node.attrs[:pos]
      ox, oy = node.attrs[:ox], node.attrs[:oy]
      size = node.attrs[:size]
      oy += (ln.attrs[:size].height - size.height) / 2
      type = node.attrs[:type]
      style = node.attrs[:style]
      shape = node.attrs[:shape]
      cstyle = node.attrs[:cstyle]
      text = node.attrs[:text]
      lines = node.attrs[:lines]
      neaten = node.attrs[:neaten]
      actor = node.attrs[:actor]
      self.contents.gradient_bar(type, style, shape, cstyle, actor, pos[0] + ox, pos[1] + oy, size.width, size.height, text, lines, neaten)
    end
  end
 
  def parse_text
    text = @text.clone
    @dom, @var_nodes = [], []
    index = 0
    current_id = -1
    current_el = nil
    parent = nil
    parent_els = []
    spattern = /<([\w\-]+)(?:\s*=\s*([\w\"\'\-\_\:\$\.\s\+]+))?((?:\s*\w+\s*=\s*[\w\"\'\-\_\:\$\.\s]+)*)>/
    epattern = /<\/[\w\-]+>/
    while text.length != 0
      s_ind = text.index(DesignHUD::SPATTERN)
      if s_ind != nil
        contents = nil
        el_name = $1
        el_val = $2 || ''
        el_attrs = {}
        tmp = $3.strip
        tmp.gsub(/(\w+)\s+=\s+([\w\"\'\-\:\+]+)/, "\\1=\\2").split(/\s+/).each { |el| el_attrs[el.split('=')[0].to_sym] = get_val(el.split('=')[1]) }
        el_val.gsub!(/[\'\"]/, '') if el_val
        el_attrs[:val] = el_val
        level, tmp_name, tmp_ind = 0, '', s_ind
        if !DesignHUD::NO_END.include?(el_name)
          loop do
            text.sub!(DesignHUD::SPATTERN, '')
            tmp = [text.index(/(<#{el_name}(?:=[\w\"\'\-\:]+)?(?:\s*\w+=[\w\"\'\-\:]+)*>)/, tmp_ind)]
            tmp.push(text.index(/<\/#{el_name}>/, tmp_ind))
            if !tmp[1]
              contents = text[s_ind...text.length - 4 - el_name.length]
              text = ''
            elsif !tmp[0]
              contents = text[s_ind...text.length - 4 - el_name.length]
              text = ''
            elsif tmp[1] < tmp[0]
              contents = text[s_ind...tmp[1]]
              text = text[tmp[1]...text.length]
            else
              level += 1
              tmp_ind = tmp[0] + 2 + el_name.length
            end
            break if contents != nil
          end
          case el_name
          when 'ln'
            element = ContainerNode.new('ln', el_attrs, nil, contents)
            @dom.push(element)
          end
        else
          text.sub!(DesignHUD::SPATTERN, '')
          case el_name
          when 'hud'
            element = HudNode.new('hud', el_attrs)
            @dom.push(element)
          end
        end
      end
    end
  end
 
  def setup_hud
    @bg = Sprite.new
    @bg.z = self.z - 1
    @bg.visible = false
    @dom.each { |el|
      el.each_child { |tmp|
        if tmp.el_type == 'hud'
          self.width = tmp.attrs[:width].to_i if tmp.attrs[:width]
          self.height = tmp.attrs[:height].to_i if tmp.attrs[:height]
          @align = tmp.attrs[:align] if tmp.attrs[:align]
          @xoffset = tmp.attrs[:offsetx].to_i if tmp.attrs[:offsetx]
          @yoffset = tmp.attrs[:offsety].to_i if tmp.attrs[:offsety]
          self.opacity = tmp.attrs[:opacity].to_i if tmp.attrs[:opacity]
          self.back_opacity = tmp.attrs[:back_opacity].to_i if tmp.attrs[:back_opacity]
          self.contents_opacity = tmp.attrs[:contents_opacity].to_i if tmp.attrs[:contents_opacity]
          begin
            self.windowskin = ((tmp.attrs[:windowskin] == '') ? Bitmap.new(1, 1) : RPG::Cache.windowskin(tmp.attrs[:windowskin])) if tmp.attrs[:windowskin]
          rescue
            self.windowskin = Bitmap.new(1, 1)
          end
          if tmp.attrs[:bg]
            @bg.bitmap = RPG::Cache.picture(tmp.attrs[:bg])
            @bg.visible = true
          end
        end
      }
    }
   
    tmp_width, tmp_height = get_dimensions
   
    if self.width == 33
      self.width = [tmp_width, 1].max + 32
    end
    if self.height == 33
      self.height = [tmp_height, 1].max + 32
    end
    amnt = 0
    @dom.each_with_index { |child, ind|
      if child.block?
        child.attrs[:size].width = self.width - 32
        #child.attrs[:size].height = child.attrs[:height] || child.attrs[:size].height
        child.attrs[:size].width = child.attrs[:width] || child.attrs[:size].width
        if child.attrs[:height]
          tmp = child.attrs[:size].height
          amnt += child.attrs[:height] - tmp
          child.attrs[:size].height = child.attrs[:height]
          unless ind == @dom.length - 1
            @dom[ind + 1...@dom.length].each { |i|
              i.attrs[:pos][1] += child.attrs[:height] - tmp
            }
          end
        end
      end
    }
    self.height += amnt
    @align.downcase!
    xmod = (['l','c'].include?(@align[1..1]) ? 1 : -1)
    ymod = (['t','m'].include?(@align[0..0]) ? 1 : -1)
    xstrt = case @align[1..1]
    when 'l' then 0
    when 'r' then 640 - self.width
    when 'c' then (640 - self.width) / 2
    end
    ystrt = case @align[0..0]
    when 't' then 0
    when 'b' then 480 - self.height
    when 'm' then (480 - self.height) / 2
    end
    self.x = xstrt + xmod * @xoffset
    self.y = ystrt + ymod * @yoffset
    if @bg.visible
      @bg.x = self.x + (self.width - @bg.bitmap.width) / 2
      @bg.y = self.y + (self.height - @bg.bitmap.height) / 2
    end
    self.visible = true
  end
 
  def get_dimensions
    ln_widths = []
    height = 0
    @tmp_attrs[:ox] = 0
    @tmp_attrs[:oy] = 0
    @tmp_attrs[:align] = 0
   
    pos = [0, 0]
   
    @dom.each { |el|
   
      pos[0] = 0
      ln_width = 0
      ln_height = 0
     
      case el.el_type
      when 'ln'
        el.attrs[:pos] = pos.clone
        el.attrs[:align] = @tmp_attrs[:abs_pos]
        el.attrs[:abs] = 0
        el.each_child_ex(proc { |child| # start proc
          child.attrs[:align] = (@tmp_attrs[:abs_pos] ? 0 : @tmp_attrs[:align])
          if @tmp_attrs[:abs_pos]
            child.attrs[:pos] = @tmp_attrs[:abs_pos].last.clone
            child.attrs[:abs] = @tmp_attrs[:abs_pos].length
          else
            child.attrs[:pos] = pos.clone
            child.attrs[:abs] = 0
          end
          child.attrs[:ox], child.attrs[:oy] = @tmp_attrs[:ox], @tmp_attrs[:oy]
          case child
          when FormatNode
            tmp = child.attrs[:start].call(child, self)
            child.attrs = tmp if tmp and tmp.is_a?(Hash)
          end
        },
        proc { |child| # end proc
          case child
          when FormatNode
            tmp = child.attrs[:finish].call(child, self)
            child.attrs = tmp if tmp and tmp.is_a?(Hash)
          end
          if !child.children.empty?
            resize(child)
          elsif child.block? or ![TextNode, VariableNode, IconNode, PictureNode, BarNode, ShapeNode].include?(child.class)
            child.attrs[:size] = Rect.new(0, 0, 0, 0)
          end
        }) { |child| # main proc
          case child
          when TextNode
            size = self.contents.text_size(child.attrs[:val])
            child.attrs[:size] = size
            ln_height = [size.height, ln_height].max
            if @tmp_attrs[:abs_pos]
              tmp = @tmp_attrs[:abs_pos]
              ln_width = [tmp.last[0] + @tmp_attrs[:ox] + size.width, ln_width].max
              @tmp_attrs[:abs_pos][tmp.length - 1][0] += size.width
            else
              ln_width = [pos[0] + @tmp_attrs[:ox] + size.width, ln_width].max
              pos[0] += size.width
            end
          when VariableNode
            size = self.contents.text_size(child.val.to_s)
            child.attrs[:size] = size
            ln_height = [size.height, ln_height].max
            if @tmp_attrs[:abs_pos]
              tmp = @tmp_attrs[:abs_pos]
              ln_width = [tmp.last[0] + @tmp_attrs[:ox] + size.width, ln_width].max
              @tmp_attrs[:abs_pos][tmp.length - 1][0] += size.width
            else
              ln_width = [pos[0] + @tmp_attrs[:ox] + size.width, ln_width].max
              pos[0] += size.width
            end
            @var_nodes.push(child)
          when IconNode, PictureNode, ShapeNode
            size = child.attrs[:bitmap].rect
            child.attrs[:size] = size
            ln_height = [size.height, ln_height].max
            if @tmp_attrs[:abs_pos]
              tmp = @tmp_attrs[:abs_pos]
              ln_width = [tmp.last[0] + @tmp_attrs[:ox] + size.width, ln_width].max
              @tmp_attrs[:abs_pos][tmp.length - 1][0] += size.width
            else
              ln_width = [pos[0] + @tmp_attrs[:ox] + size.width, ln_width].max
              pos[0] += size.width
            end
          when BarNode
            size = Rect.new(0,0,*child.attrs[:dimensions])
            child.attrs[:size] = size
            ln_height = [size.height, ln_height].max
            if @tmp_attrs[:abs_pos]
              tmp = @tmp_attrs[:abs_pos]
              ln_width = [tmp.last[0] + @tmp_attrs[:ox] + size.width, ln_width].max
              @tmp_attrs[:abs_pos][tmp.length - 1][0] += size.width
            else
              ln_width = [pos[0] + @tmp_attrs[:ox] + size.width, ln_width].max
              pos[0] += size.width
            end
            @var_nodes.push(child)
          end
        }
      end
     
      pos[1] += ln_height + @tmp_attrs[:oy]
      ln_widths.push(ln_width)
    }
   
    height = pos[1]
    width = ln_widths.max
    return width, height
  end
 
  def resize(el)
    size = Rect.new(0, 0, 0, 0)
    x1, y1 = 640, 480
    x2 = y2 = 0
    len = el.attrs[:abs]
    el.children.each { |i|
      next if i.attrs[:abs] > len
      x, y = *i.attrs[:pos]
      ns = i.attrs[:size]
      x1 = [x1, x].min
      y1 = [y1, y].min
      x2 = [x2, x + ns.width].max
      y2 = [y2, y + ns.height].max
    }
    size.width = x2 - x1
    size.height = y2 - y1
    pos = el.block? ? el.attrs[:pos] : [x1, y1]
    el.attrs[:pos], el.attrs[:size] = pos, size
  end
 
  def setup_align
    aligned = nil
    la = 0
    blocks = []
    @dom.each { |el|
      case el.el_type
      when 'ln'
        el.each_child_ex(proc{|child|},proc{|child|
          if child.attrs[:tmp]
            child.attrs.delete_if { |i| i[0] == :tmp }
            aligned = nil
          end
        }) { |child|
          unless child.attrs[:abs] > 0 or !aligned.nil?
            aligned = true
            child.attrs[:tmp] = true
            la = child.attrs[:align]
            blocks |= [child.last_block]
            child.last_block.attrs[:aels] = (child.last_block.attrs[:aels] || []).concat([child])
          end
        }
      end
    }
    blocks.each { |el|
      rw = el.attrs[:aels].inject(0) { |s, n| s + (n.attrs[:align] == 2 ? n.attrs[:size].width : 0) }
      cw = el.attrs[:aels].inject(0) { |s, n| s + (n.attrs[:align] == 1 ? n.attrs[:size].width : 0) }
      lx = el.attrs[:pos][0]
      rx = el.attrs[:pos][0] + el.attrs[:size].width - rw
      cx = el.attrs[:pos][0] + (el.attrs[:size].width) / 2
      el.attrs[:aels].each { |child|
        case child.attrs[:align]
        when 0
          ox = child.attrs[:pos][0]
          child.attrs[:pos][0] = lx
          child.each_child_ex(proc{},proc{}) { |i|
            i.attrs[:pos][0] += lx - ox
          }
          lx += child.attrs[:size].width
        when 1
          cx -= child.attrs[:size].width / 2
        when 2
          ox = child.attrs[:pos][0]
          child.attrs[:pos][0] = rx
          child.each_child_ex(proc{},proc{}) { |i|
            i.attrs[:pos][0] += rx - ox
          }
          rx += child.attrs[:size].width
        end
      }
      el.attrs[:aels].select { |i| i.attrs[:align] == 1 }.each { |child|
        ox = child.attrs[:pos][0]
        child.attrs[:pos][0] = cx
        child.each_child_ex(proc{},proc{}) { |i|
          i.attrs[:pos][0] += cx - ox
        }
        cx += child.attrs[:size].width
      }
      el.attrs.delete(:aels)
    }
  end
 
  def render_hud
   
    @dom.each { |el|
   
      align = 0
   
      case el.el_type
      when 'ln'
        el.each_child_ex(proc { |child|
          case child
          when FormatNode
            child.attrs[:start].call(child, self)
          end
        },
        proc { |child|
          case child
            when FormatNode
              child.attrs[:finish].call(child, self)
          end
        }) { |child|
          draw_node(child)
        }
      end
    }
  end
 
  def get_val(str)
    separators = [':', '.', ',']
    val = nil
    vp = []
    sp = []
    loop do
      tmpstr = eval('str' + sp.map{|i|'['+i.to_s+']'}.join(''))
      if tmpstr.nil?
        sp.pop
        vp.pop
        if vp.length == 0
          break
        end
        sp[-1] += 1
        vp[-1] += 1
        next
      end
      if tmpstr.index(separators[sp.length]) != nil
        begin
          eval('val' + vp.map{|i|'['+i.to_s+']'}.join('') + "=eval('#{tmpstr}')")
          if sp.length > 0 and sp.last < eval('str' + sp[0..sp.length - 2].map{|i|'['+i.to_s+']'}.join('')).length
            sp[-1] += 1
            vp[-1] += 1
          else
            break if vp.length == 0
            vp.pop
            sp.pop
            break if vp.length == 0
            sp[-1] += 1
            vp[-1] += 1
          end
        rescue Exception
          eval('str' + sp.map{|i|'['+i.to_s+']'}.join('') + '=tmpstr.split(separators[sp.length])')
          eval('val' + vp.map{|i|'['+i.to_s+']'}.join('') + '=[]')
          vp.push(0)
          sp.push(0)
        end
      else
        begin
          eval('val' + vp.map{|i|'['+i.to_s+']'}.join('') + "=eval('#{tmpstr}')")
        rescue Exception
          eval('val' + vp.map{|i|'['+i.to_s+']'}.join('') + '=tmpstr')
        end
        etxt = 'str'
        etxt += sp[0..sp.length - 2].map{|i|'['+i.to_s+']'}.join('') if sp.length > 1
        if sp.length > 0 and sp.last < eval(etxt).length
          sp[-1] += 1
          vp[-1] += 1
        else
          break if vp.length == 0
          vp.pop
          sp.pop
          break if vp.length == 0
          sp[-1] += 1
          vp[-1] += 1
        end
      end
    end
    val
  end
 
  def get_el(path)
    el = @dom[path[0]]
    if path.length > 1
      path[1..path.length - 1].each { |tmp|
        el = el.children[tmp]
      }
    end
    el
  end
end

class Element
  @@id = 0
  attr_accessor :children, :el_type, :attrs, :el_id, :parent
 
  def initialize(el_type, attrs, parent)
    @children = []
    @el_type = el_type.downcase
    @attrs = attrs
    @parent = parent
    @contents = ''
    @el_id = @@id
    @@id += 1
  end
 
  def get_val(str)
    separators = [':', '.', ',']
    val = nil
    vp = []
    sp = []
    loop do
      tmpstr = eval('str' + sp.map{|i|'['+i.to_s+']'}.join(''))
      if tmpstr.nil?
        sp.pop
        vp.pop
        if vp.length == 0
          break
        end
        sp[-1] += 1
        vp[-1] += 1
        next
      end
      if tmpstr.index(separators[sp.length]) != nil
        begin
          eval('val' + vp.map{|i|'['+i.to_s+']'}.join('') + "=eval('#{tmpstr}')")
          if sp.length > 0 and sp.last < eval('str' + sp[0..sp.length - 2].map{|i|'['+i.to_s+']'}.join('')).length
            sp[-1] += 1
            vp[-1] += 1
          else
            break if vp.length == 0
            vp.pop
            sp.pop
            break if vp.length == 0
            sp[-1] += 1
            vp[-1] += 1
          end
        rescue Exception
          eval('str' + sp.map{|i|'['+i.to_s+']'}.join('') + '=tmpstr.split(separators[sp.length])')
          eval('val' + vp.map{|i|'['+i.to_s+']'}.join('') + '=[]')
          vp.push(0)
          sp.push(0)
        end
      else
        begin
          eval('val' + vp.map{|i|'['+i.to_s+']'}.join('') + "=eval('#{tmpstr}')")
        rescue Exception
          eval('val' + vp.map{|i|'['+i.to_s+']'}.join('') + '=tmpstr')
        end
        etxt = 'str'
        etxt += sp[0..sp.length - 2].map{|i|'['+i.to_s+']'}.join('') if sp.length > 1
        if sp.length > 0 and sp.last < eval(etxt).length
          sp[-1] += 1
          vp[-1] += 1
        else
          break if vp.length == 0
          vp.pop
          sp.pop
          break if vp.length == 0
          sp[-1] += 1
          vp[-1] += 1
        end
      end
    end
    val
  end
 
  def block?
    return DesignHUD::BLOCK_ELS.include?(@el_type)
  end
 
  def inline?
    return !DesignHUD::BLOCK_ELS.include?(@el_type)
  end
 
  def self.reset_id
    @@id = 0
  end
 
  def parents
    if @parent != nil
      parents = [@parent]
      parent = @parent
      while parent.parent != nil
        parents.push(parent.parent)
        parent = parent.parent
      end
      return parents
    else
      return []
    end
  end
 
  def last_block
    if @parent != nil
      last = self
      parent = @parent
      while last.inline?
        last = parent
        parent = parent.parent
        break if parent.nil?
      end
      return last
    else
      return nil
    end
  end
 
  def last_line
    if @parent != nil
      last = self
      parent = @parent
      while last.el_type != 'ln'
        last = parent
        parent = parent.parent
        break if parent.nil?
      end
      return last
    else
      return nil
    end
  end
 
  def each_child(&block)
    block.call(self)
    path = [0]
    cur = self
    loop {
      child = cur.children[path.last]
      if child
        block.call(child)
        cur = child
        path.push(0)
      else
        cur = cur.parent
        path.pop
        break unless cur
        path[path.length - 1] += 1
      end
    }
  end
 
  def each_child_ex(start, finish, &block)
    path = [0]
    cur = self
    loop {
      child = cur.children[path.last]
      if child
        start.call(child)
        block.call(child)
        cur = child
        path.push(0)
      else
        finish.call(cur)
        cur = cur.parent
        path.pop
        break unless cur and path.length > 0
        path[path.length-1] += 1
      end
    }
  end
 
  def each_child_ex2(finish, &block)
    block.call(self)
    path = [0]
    cur = self
    loop {
      child = cur.children[path.last]
      if child
        block.call(child)
        cur = child
        path.push(0)
      else
        finish.call(cur)
        cur = cur.parent
        path.pop
        break unless cur
        path[path.length - 1] += 1
      end
    }
  end
 
  def parse_contents(text)
    @tmp_attrs = {}
    spattern = /<([\w\-]+)(?:\s*=\s*([\w\"\'\-\_\:\$\.\s]+))?((?:\s*\w+\s*=\s*[\w\"\'\-\_\:\$\.\s]+)*)>/
    epattern = /<\/[\w\-]+>/
    while text != ''
      s_ind = text.index(DesignHUD::SPATTERN)
      if s_ind != nil
        if s_ind > 0
          contents = text[0...s_ind]
          text = text[s_ind...text.length]
          element = TextNode.new('', self, contents)
          @children.push(element)
        end
        contents = nil
        el_name = $1
        el_val = $2 || ''
        el_attrs = {}
        tmp = $3.strip
        tmp.gsub(/(\w+)\s+=\s+([\w\"\'\-\:]+)/, "\\1=\\2").split(/\s+/).each { |el| el_attrs[el.split('=')[0].to_sym] = get_val(el.split('=')[1]) }
        el_val.gsub!(/[\'\"]/, '') if el_val
        el_attrs[:val] = el_val
        level, tmp_name, tmp_ind = 0, '', 0
        if !DesignHUD::NO_END.include?(el_name)
          text.sub!(DesignHUD::SPATTERN, '')
          last_ind = nil
          loop do
            tmp = [text.index(/(<#{el_name}(?:=[\w\"\'\-\:]+)?(?:\s*\w+=[\w\"\'\-\:]+)*>)/, tmp_ind)]
            tmp2 = tmp_ind
            (level+1).times {
              i = text.index(/<\/#{el_name}>/, tmp2)
              tmp2 = i + 2 + el_name.length unless i.nil?
            }
            tmp.push(tmp2 - 2 - el_name.length)
            if !tmp[1]
              contents = text[0...text.length]
              text = ''
            elsif !tmp[0]
              contents = text[0...tmp[1]]
              text = text[tmp[1] + 3 + el_name.length...text.length]
              level = [level - 1, 0].max
            elsif tmp[1] < tmp[0]
              contents = text[0...tmp[1]]
              text = text[tmp[1] + 3 + el_name.length...text.length]
              level = [level - 1, 0].max
            else
              level += 1 unless last_ind != nil and tmp[0] > last_ind[1]
              tmp_ind = tmp[0] + 2 + el_name.length
            end
            last_ind = tmp
            break if contents != nil
          end
          case el_name
          when 'ln'
            element = ContainerNode.new('ln', el_attrs, self, contents)
            @children.push(element)
          when 'b'
            element = FormatNode.new('b', self, contents, proc { |child, hud|
              if !@tmp_attrs[:tmpb]
                @tmp_attrs[:tmpb] = [hud.contents.font.bold]
              else
                @tmp_attrs[:tmpb].push(hud.contents.font.bold)
              end
              hud.contents.font.bold = true
            },
            proc { |child, hud|
              hud.contents.font.bold = @tmp_attrs[:tmpb].pop
            })
            @children.push(element)
          when 'i'
            element = FormatNode.new('i', self, contents, proc { |child, hud|
              if !@tmp_attrs[:tmpi]
                @tmp_attrs[:tmpi] = [hud.contents.font.italic]
              else
                @tmp_attrs[:tmpi].push(hud.contents.font.italic)
              end
              hud.contents.font.italic = true
            },
            proc { |child, hud|
              hud.contents.font.italic = @tmp_attrs[:tmpi].pop
            })
            @children.push(element)
          when 'c'
            element = FormatNode.new('c', self, contents, proc { |child, hud|
              if !hud.tmp_attrs[:tmpc]
                hud.tmp_attrs[:tmpc] = [hud.contents.font.color.clone]
              else
                hud.tmp_attrs[:tmpc].push(hud.contents.font.color.clone)
              end
              hud.contents.font.color = Color.new(*child.attrs[:val].split(':').map { |i| i.to_i })
            },
            proc { |child, hud|
              hud.contents.font.color = hud.tmp_attrs[:tmpc].pop
            }, el_val)
            @children.push(element)
          when 'font'
            element = FormatNode.new('font', self, contents, proc { |child, hud|
              if !@tmp_attrs[:tmpfn]
                hud.tmp_attrs[:tmpfn] = [[hud.contents.font.name.clone, hud.contents.font.size]]
              else
                hud.tmp_attrs[:tmpfn].push([hud.contents.font.name.clone, hud.contents.font.size])
              end
              if Font.exist?(child.attrs[:val].split(':')[0])
                hud.contents.font.name = child.attrs[:val].split(':')[0]
                hud.contents.font.size = child.attrs[:val].split(':')[1].to_i
              end
            },
            proc { |child, hud|
              hud.contents.font.name, hud.contents.font.size = *hud.tmp_attrs[:tmpfn].pop
            }, el_val)
            @children.push(element)
          when 'pos'
            element = FormatNode.new('pos', self, contents, proc { |child, hud|
            if !hud.tmp_attrs[:abs_pos]
                hud.tmp_attrs[:abs_pos] = [[child.attrs[:x], child.attrs[:y]]]
              else
                hud.tmp_attrs[:abs_pos].push([child.attrs[:x], child.attrs[:y]])
              end
            },
            proc { |child, hud|
              hud.tmp_attrs[:abs_pos].pop
              hud.tmp_attrs.delete(:abs_pos) if hud.tmp_attrs[:abs_pos].length == 0
            }, el_val, el_attrs)
            @children.push(element)
          when 'offset'
            element = FormatNode.new('offset', self, contents, proc { |child, hud|
              if !hud.tmp_attrs[:tmpofst]
                hud.tmp_attrs[:tmpofst] = [[hud.tmp_attrs[:ox], hud.tmp_attrs[:oy]]]
              else
                hud.tmp_attrs[:tmpofst].push([hud.tmp_attrs[:ox], hud.tmp_attrs[:oy]])
              end
              hud.tmp_attrs[:ox], hud.tmp_attrs[:oy] = child.attrs[:x], child.attrs[:y]
            },
            proc { |child, hud|
              hud.tmp_attrs[:ox], hud.tmp_attrs[:oy] = *hud.tmp_attrs[:tmpofst].pop
            }, el_val, el_attrs)
            @children.push(element)
          when 'right'
            element = FormatNode.new('right', self, contents, proc { |child, hud|
              if !hud.tmp_attrs[:tmpalign]
                hud.tmp_attrs[:tmpalign] = [hud.tmp_attrs[:align]]
              else
                hud.tmp_attrs[:tmpalign].push(hud.tmp_attrs[:align])
              end
              hud.tmp_attrs[:align] = 2
              child.attrs[:align] = 2
            },
            proc { |child, hud|
              hud.tmp_attrs[:align] = hud.tmp_attrs[:tmpalign].pop
            }, el_val, el_attrs)
            @children.push(element)
          when 'center'
            element = FormatNode.new('center', self, contents, proc { |child, hud|
              if !hud.tmp_attrs[:tmpalign]
                hud.tmp_attrs[:tmpalign] = [hud.tmp_attrs[:align]]
              else
                hud.tmp_attrs[:tmpalign].push(hud.tmp_attrs[:align])
              end
              hud.tmp_attrs[:align] = 1
              child.attrs[:align] = 1
            },
            proc { |child, hud|
              hud.tmp_attrs[:align] = hud.tmp_attrs[:tmpalign].pop
            }, el_val, el_attrs)
            @children.push(element)
          when 'left'
            element = FormatNode.new('left', self, contents, proc { |child, hud|
              if !hud.tmp_attrs[:tmpalign]
                hud.tmp_attrs[:tmpalign] = [hud.tmp_attrs[:align]]
              else
                hud.tmp_attrs[:tmpalign].push(hud.tmp_attrs[:align])
              end
              hud.tmp_attrs[:align] = 0
              child.attrs[:align] = 0
            },
            proc { |child, hud|
              hud.tmp_attrs[:align] = hud.tmp_attrs[:tmpalign].pop
            }, el_val, el_attrs)
            @children.push(element)
          end
        else
          text.sub!(DesignHUD::SPATTERN, '')
          case el_name
          when 'hud'
            element = HudNode.new('hud', el_attrs, self)
            @children.push(element)
          when 'var'
            element = VariableNode.new(self, el_val)
            @children.push(element)
          when 'ico'
            element = IconNode.new(self, el_val)
            @children.push(element)
          when 'pic'
            element = PictureNode.new(self, el_val)
            @children.push(element)
          when 'bar'
            element = BarNode.new(self, el_attrs)
            @children.push(element)
          when 'shape'
            element = ShapeNode.new(self, el_attrs)
            @children.push(element)
          end
        end
      else
        contents = text
        text = ''
        element = TextNode.new('', self, contents)
        @children.push(element)
      end
    end
  end
end

class TextNode < Element
  def initialize(type, parent, text)
    super(type, {}, parent)
    @attrs[:val] = text
  end
end

class PictureNode < Element
  def initialize(parent, val)
    super('pic', {}, parent)
    @attrs[:bitmap] = RPG::Cache.picture(val)
  end
end

class IconNode < Element
  def initialize(parent, val)
    super('ico', {}, parent)
    @attrs[:bitmap] = RPG::Cache.icon(el_val).clone
  end
end

class VariableNode < Element
  def initialize(parent, name)
    super('var', {}, parent)
    @attrs[:expr] = DesignHUD.var_expression(name)
    @attrs[:val] = @attrs[:expr].call || 0
  end
 
  def val
    tmp = @attrs[:expr].call
    return (tmp.nil? ? 0 : tmp)
  end
end

class ShapeNode < Element
  def initialize(parent, attrs)
    super('shape', attrs, parent)
    @attrs[:width] ||= 50
    @attrs[:height] ||= 50
    bitmap = Bitmap.new(@attrs[:width], @attrs[:height])
    case @attrs[:type].to_s.downcase
    when 'rect'
      @attrs[:color] ||= [0, 0, 0]
      bitmap.fill_rect(bitmap.rect, Color.new(*@attrs[:color]))
    when 'hgrect'
      @attrs[:color] ||= [[0, 0, 0], [255, 255, 255]]
      tmp = @attrs[:color]
      bitmap.width.times { |i|
        r = tmp[0][0] * (bitmap.width - 1 - i) / (bitmap.width - 1) + tmp[1][0] * i / (bitmap.width - 1)
        g = tmp[0][1] * (bitmap.width - 1 - i) / (bitmap.width - 1) + tmp[1][1] * i / (bitmap.width - 1)
        b = tmp[0][2] * (bitmap.width - 1 - i) / (bitmap.width - 1) + tmp[1][2] * i / (bitmap.width - 1)
        bitmap.fill_rect(i, 0, 1, bitmap.height, Color.new(r, g, b))
      }
    when 'vgrect'
      @attrs[:color] ||= [[0, 0, 0], [255, 255, 255]]
      tmp = @attrs[:color]
      bitmap.height.times { |i|
        r = tmp[0][0] * (bitmap.height - 1 - i) / (bitmap.height - 1) + tmp[1][0] * i / (bitmap.height - 1)
        g = tmp[0][1] * (bitmap.height - 1 - i) / (bitmap.height - 1) + tmp[1][1] * i / (bitmap.height - 1)
        b = tmp[0][2] * (bitmap.height - 1 - i) / (bitmap.height - 1) + tmp[1][2] * i / (bitmap.height - 1)
        bitmap.fill_rect(0, i, bitmap.width, 1, Color.new(r, g, b))
      }
    end
    @attrs[:bitmap] = bitmap
  end
end

class BarNode < Element
  def initialize(parent, attrs)
    super('bar', attrs, parent)
    @attrs[:type] ||= :hp
    @attrs[:style] ||= 0
    @attrs[:shape] ||= 0
    @attrs[:cstyle] ||= [3, 2, 4, 2]
    @attrs[:lines] = false if @attrs[:lines].nil?
    @attrs[:neaten] = true if @attrs[:neaten].nil?
    @attrs[:dimensions] ||= [120, 16]
    @attrs[:text] = true if @attrs[:text].nil?
    @attrs[:actor] ||= 1
    @attrs[:actor] = $game_actors[@attrs[:actor]]
    @attrs[:val] = val
  end
 
  def val
    case @attrs[:type]
    when :hp
      return [@attrs[:actor].hp, @attrs[:actor].maxhp]
    when :mp
      return [@attrs[:actor].sp, @attrs[:actor].maxsp]
    when :exp
      return @attrs[:actor].exp
    when :lvl
      return @attrs[:actor].level
    end
  end
end

class HudNode < Element
  def initialize(type, attrs, parent = nil)
    super('hud', attrs, parent)
  end
end

class ContainerNode < Element
  def initialize(type, attrs, parent, contents)
    super(type, attrs, parent)
   
    parse_contents(contents)
  end
end

class FormatNode < Element
  def initialize(type, parent, contents, start, finish, val=nil, attrs = {})
    super(type, attrs, parent)
   
    parse_contents(contents)
    @attrs[:val] = val if val
    @attrs[:start] = start
    @attrs[:finish] = finish
  end
end

class Rect
  def intersect?(rect)
    return false if rect.width * rect.height == 0 or self.width * self.height == 0
    return true if (self.x.between?(rect.x - 1, rect.x + rect.width) or
                   (self.x + self.width).between?(rect.x - 1, rect.x + rect.width)) and
                   (self.y.between?(rect.y - 1, rect.y + rect.height) or
                   (self.y + self.height).between?(rect.y - 1, rect.y + rect.height))
    return false
  end
end

class Bitmap
  def get_colors(type, actor, cstyle)
    bc = Color.new(0, 0, 0)
    case type
    when :hp
      c1 = Color.new(200, 0, 0)
      c2 = Color.new(0, 200, 0)
      p = actor.hp * 100 / actor.maxhp
    when :mp
      c1 = Color.new(200, 0, 0)
      c2 = Color.new(0, 0, 200)
      p = actor.sp * 100 / actor.maxsp
    when :exp
      c1 = Color.new(170, 85, 0)
      c2 = Color.new(150, 150, 0)
      elist = actor.instance_variable_get(:@exp_list)
      if elist[actor.level + 1]
        nexp = elist[actor.level + 1] - elist[actor.level]
        cexp = actor.exp - elist[actor.level]
        p = (nexp <= 0 ? 100 : cexp * 100 / nexp)
      else
        p = 100
      end
    when :lvl
      c1 = Color.new(0, 85, 170)
      c2 = Color.new(150, 0, 150)
      p = actor.level * 100 / (actor.respond_to?(:final_level) ? actor.final_level : $data_actors[actor.id].final_level)
    end
    r = c2.red * p / 100 + c1.red * (100 - p) / 100
    g = c2.green * p / 100 + c1.green * (100 - p) / 100
    b = c2.blue * p / 100 + c1.blue * (100 - p) / 100
    pc1 = Color.new(r, g, b)
    r = c1.red * p / 100 + c2.red * (100 - p) / 100
    g = c1.green * p / 100 + c2.green * (100 - p) / 100
    b = c1.blue * p / 100 + c2.blue * (100 - p) / 100
    pc2 = Color.new(r, g, b)
    c = cstyle.map { |i|
      case i
      when 0 then c1
      when 1 then c2
      when 2 then bc
      when 3 then pc1
      when 4 then pc2
      when 5 then lcol(c1)
      when 6 then lcol(c2)
      when 7 then lcol(pc1)
      when 8 then lcol(pc2)
      when 9 then dcol(c1)
      when 10 then dcol(c2)
      when 11 then dcol(pc1)
      when 12 then dcol(pc2)
      end
    }
    return c, bc
  end
 
  def lcol(c)
    return Color.new(c.red * 1.3, c.green * 1.3, c.blue * 1.3)
  end
 
  def dcol(c)
    return Color.new(c.red * 0.7, c.green * 0.7, c.blue * 0.7)
  end
 
  def gradient_bar_back(color, shape, x, y, w, h, lines, extend = true)
    rw = w
    w += 10 if extend
    fill_rect(x, y, w, h, color)
    case shape
    when 0
      unless lines
        fill_rect(x + 1, y + 1, rw - 2, 1, Color.new(255, 255, 255))
        fill_rect(x + 1, y + h - 2, rw - 2, 1, Color.new(255, 255, 255))
        fill_rect(x + 1, y + 1, 1, h - 2, Color.new(255, 255, 255))
        fill_rect(x + w - 2, y + 1, 1, h - 2, Color.new(255, 255, 255))
      end
    when 1
      h.times { |i|
        fill_rect(x + i, y + i + 1, 1, h - 1 - i, Color.new(0, 0, 0, 0))
        fill_rect(x + w - 1 - i, y, 1, h - 1 - i, Color.new(0, 0, 0, 0))
        set_pixel(x + i + 1, y + i, Color.new(255, 255, 255)) unless i == 0 or i == h - 1
      }
      fill_rect(x + h, y + h - 2, rw - 2 - h, 1, Color.new(255, 255, 255))
    when 2
      fill_rect(x, y, w, 1, Color.new(0, 0, 0, 127))
      fill_rect(x, y + h - 1, w, 1, Color.new(0, 0, 0, 127))
      t = (h / 2.0).floor
      h.times { |i|
        v = ((t + 1) * (1 - Math.sin(Math::PI * (i + 1) / (h + 1)))).floor
        unless v == 0
          fill_rect(x, y + i, v, 1, Color.new(0, 0, 0, 0))
          fill_rect(x + w - v, y + i, v, 1, Color.new(0, 0, 0, 0))
        end
        unless [0, h - 1].include?(i)
          set_pixel(x + v, y + i, Color.new(0, 0, 0, 85))
          set_pixel(x + w - v, y + i, Color.new(0, 0, 0, 85))
        end
      }
    when 3
      h.times { |i|
        fill_rect(x + i, y, 1, h - 1 - i, Color.new(0, 0, 0, 0))
        fill_rect(x + w - 1 - i, y + i + 1, 1, h - 1 - i, Color.new(0, 0, 0, 0))
        set_pixel(x + h - i, y + i, Color.new(255, 255, 255)) unless i == 0 or i == h - 1
      }
      fill_rect(x + 2, y + h - 2, w - (extend ? 7 : 2) - h, 1, Color.new(255, 255, 255))
      #w -= h - 1
    end
    if extend
      tmp = self.clone
      fill_rect(x + w - 20, y, 20, h, Color.new(0, 0, 0, 0))
      20.times { |i|
        blt(x + w - 20 + i, y, tmp, Rect.new(x + w - 20 + i, y, 1, h), 255 * (19 - i) / 19)
      }
    end
  end
 
  def gradient_bar_front(colors, bgcolor, style, shape, sx, sy, w, h, rate)
    sbmap = self.clone
    t = (h / 2.0).ceil
    if style.between?(0, 6)
      h.times { |i|
        rect = Rect.new(sx, sy + i, w * rate, 1)
        case shape
        when 1
          rect.width -= h - 1
          rect.x += i
        when 2
          t = (h / 2.0).floor
          v = ((t + 1) * (1 - Math.sin(Math::PI * (i + 1) / (h + 1)))).floor
          rect.x += v
          rect.width -= 2 * v
        when 3
          rect.width -= h - 1
          rect.x += h - 1 - i
        end
        case style
        when 0
          r = colors[1].red * i / (h - 1) + colors[0].red * (h - 1 - i) / (h - 1)
          g = colors[1].green * i / (h - 1) + colors[0].green * (h - 1 - i) / (h - 1)
          b = colors[1].blue * i / (h - 1) + colors[0].blue * (h - 1 - i) / (h - 1)
        when 1
          t = (h / 2.0).ceil
          if i >= t
            d = i - t + (h % 2 == 1 ? 1 : 0)
          else
            d = t - i - 1
          end
          t -= 1 if h % 2 == 1
          r = colors[1].red * d / (t) + colors[0].red * (t - d) / (t)
          g = colors[1].green * d / (t) + colors[0].green * (t - d) / (t)
          b = colors[1].blue * d / (t) + colors[0].blue * (t - d) / (t)
        when 2
          s = Math.sin(Math::PI * i / (h - 1) / 2)
          r = colors[1].red * s + colors[0].red * (1 - s)
          g = colors[1].green * s + colors[0].green * (1 - s)
          b = colors[1].blue * s + colors[0].blue * (1 - s)
        when 3
          s = 2 * Math.sin(Math::PI * i / (h - 1) / 6)
          r = colors[1].red * s + colors[0].red * (1 - s)
          g = colors[1].green * s + colors[0].green * (1 - s)
          b = colors[1].blue * s + colors[0].blue * (1 - s)
        when 4
          s = 1 - 2 * Math.sin(Math::PI * i / (h - 1) / 6)
          r = colors[0].red * s + colors[1].red * (1 - s)
          g = colors[0].green * s + colors[1].green * (1 - s)
          b = colors[0].blue * s + colors[1].blue * (1 - s)
        when 5
          s = Math.sin(Math::PI * i / (h - 1))
          r = colors[0].red * s + colors[1].red * (1 - s)
          g = colors[0].green * s + colors[1].green * (1 - s)
          b = colors[0].blue * s + colors[1].blue * (1 - s)
        when 6
          s = Math.sin(Math::PI / 2 + Math::PI * i / (h - 1)).abs
          r = colors[1].red * s + colors[0].red * (1 - s)
          g = colors[1].green * s + colors[0].green * (1 - s)
          b = colors[1].blue * s + colors[0].blue * (1 - s)
        end
        fill_rect(rect, Color.new(r, g, b))
      }
    elsif style.between?(7, 13)
      amnt = 8
      case shape
      when 1, 3
        w -= h - 1
      end
      at = (w.to_f * rate / amnt).ceil
      h.times { |i|
        at.times { |e|
          rect = Rect.new(sx + amnt * e, sy + i, amnt, 1)
          dw = w * rate
          case shape
          when 0
            rect.width = [rect.width, sx + dw - rect.x].min
          when 1
            rect.x += i
            rect.width = [rect.width, sx + dw + i - rect.x].min
          when 2
            v = ((t + 1) * (1 - Math.sin(Math::PI * (i + 1) / (h + 1)))).floor
            rect.x += v if e == 0
            tmp = 0
            if e == 0
              rect.width -= v
              tmp += v
            end
            if e == at - 1
              rect.width -= v
              tmp += v
            end
            rect.width = [rect.width, sx + dw - tmp - rect.x].min
          when 3
            rect.x += h - 1 - i
            rect.width = [rect.width, sx + dw + h - 1 - i - rect.x].min
          end
          tmpcolors = (e % 2 == 0 ? colors[0..1] : colors[2..3])
          case style
          when 7
            r = tmpcolors[1].red * i / (h - 1) + tmpcolors[0].red * (h - 1 - i) / (h - 1)
            g = tmpcolors[1].green * i / (h - 1) + tmpcolors[0].green * (h - 1 - i) / (h - 1)
            b = tmpcolors[1].blue * i / (h - 1) + tmpcolors[0].blue * (h - 1 - i) / (h - 1)
          when 8
            if i >= t
              d = i - t + (h % 2 == 1 ? 1 : 0)
            else
              d = t - i - 1
            end
            t -= 1 if h % 2 == 1
            r = tmpcolors[1].red * d / (t) + tmpcolors[0].red * (t - d) / (t)
            g = tmpcolors[1].green * d / (t) + tmpcolors[0].green * (t - d) / (t)
            b = tmpcolors[1].blue * d / (t) + tmpcolors[0].blue * (t - d) / (t)
          when 9
            s = Math.sin(Math::PI * i / (h - 1) / 2)
            r = tmpcolors[1].red * s + tmpcolors[0].red * (1 - s)
            g = tmpcolors[1].green * s + tmpcolors[0].green * (1 - s)
            b = tmpcolors[1].blue * s + tmpcolors[0].blue * (1 - s)
          when 10
            s = 2 * Math.sin(Math::PI * i / (h - 1) / 6)
            r = tmpcolors[1].red * s + tmpcolors[0].red * (1 - s)
            g = tmpcolors[1].green * s + tmpcolors[0].green * (1 - s)
            b = tmpcolors[1].blue * s + tmpcolors[0].blue * (1 - s)
          when 11
            s = 1 - 2 * Math.sin(Math::PI * i / (h - 1) / 6)
            r = tmpcolors[0].red * s + tmpcolors[1].red * (1 - s)
            g = tmpcolors[0].green * s + tmpcolors[1].green * (1 - s)
            b = tmpcolors[0].blue * s + tmpcolors[1].blue * (1 - s)
          when 12
            s = Math.sin(Math::PI * i / (h - 1))
            r = tmpcolors[0].red * s + tmpcolors[1].red * (1 - s)
            g = tmpcolors[0].green * s + tmpcolors[1].green * (1 - s)
            b = tmpcolors[0].blue * s + tmpcolors[1].blue * (1 - s)
          when 13
            s = Math.sin(Math::PI / 2 + Math::PI * i / (h - 1)).abs
            r = tmpcolors[1].red * s + tmpcolors[0].red * (1 - s)
            g = tmpcolors[1].green * s + tmpcolors[0].green * (1 - s)
            b = tmpcolors[1].blue * s + tmpcolors[0].blue * (1 - s)
          end
          fill_rect(rect, Color.new(r, g, b))
        }
      }
    elsif style.between?(14, 34)
      case shape
      when 2
        t = (h / 2.0).floor
        v = []
        h.times { |i|
          v.push(((t + 1) * (1 - Math.sin(Math::PI * (i + 1) / (h + 1)))).floor)
        }
      end
      dw = (w * rate).to_i
      dw.times { |i|
        rect = Rect.new(sx + i, sy, 1, h)
        case shape
        when 1
          if i < h
            rect.height -= h - 1 - i
          end
          if i > dw - h
            rect.y += i - dw + h
            rect.height -= i - dw + h
          end
        when 2
          if i <= v.max
            ind = v.index(v.detect { |val| val <= i })
            rect.y += ind
            rect.height -= ind * 2
          elsif w - 1 - i <= v.max
            ind = v.index(v.detect { |val| val <= w - 1 - i })
            rect.y += ind
            rect.height -= ind * 2
          end
        when 3
          if i < h
            rect.y += h - 1 - i
            rect.height -= h - 1 - i
          end
          if i > w - h
            rect.height -= i - w + h
          end
        end
        case style
        when 14, 17, 20, 23, 26, 29, 32
          r = colors[1].red * i / (w - 1) + colors[0].red * (w - 1 - i) / (w - 1)
          g = colors[1].green * i / (w - 1) + colors[0].green * (w - 1 - i) / (w - 1)
          b = colors[1].blue * i / (w - 1) + colors[0].blue * (w - 1 - i) / (w - 1)
        when 15, 18, 21, 24, 27, 30, 33
          s = Math.sin(Math::PI * i / (w - 1) / 2)
          r = colors[1].red * s + colors[0].red * (1 - s)
          g = colors[1].green * s + colors[0].green * (1 - s)
          b = colors[1].blue * s + colors[0].blue * (1 - s)
        when 16, 19, 22, 25, 28, 31, 34
          s = 2 * Math.sin(Math::PI * i / (w - 1) / 6)
          r = colors[1].red * s + colors[0].red * (1 - s)
          g = colors[1].green * s + colors[0].green * (1 - s)
          b = colors[1].blue * s + colors[0].blue * (1 - s)
        end
        fill_rect(rect, Color.new(r, g, b))
      }
      if style.between?(17, 34)
        bmap = self.clone
        h.times { |i|
          case style
          when 17, 18, 19
            t = (h / 2.0).ceil
            if i >= t
              d = i - t + (h % 2 == 1 ? 1 : 0)
            else
              d = t - i - 1
            end
            t -= 1 if h % 2 == 1
            a = 255 * (t - d) / t
          when 20, 21, 22
            s = Math.sin(Math::PI * i / (h - 1))
            a = 255 * s
          when 23, 24, 25
            s = 1 - Math.sin(Math::PI / 2 + Math::PI * i / (h - 1)).abs
            a = 255 * s
          when 26, 27, 28
            a = 255 * (h - 1 - i) / (h - 1)
          when 29, 30, 31
            s = 1 - Math.sin(Math::PI * i / (h - 1) / 2)
            a = 255 * s
          when 32, 33, 34
            s = 1 - 2 * Math.sin(Math::PI * i / (h - 1) / 6)
            a = 255 * s
          end
          r = Rect.new(sx, sy + i, w, 1)
          blt(r.x, r.y, sbmap, r)
          blt(r.x, r.y, bmap, r, a)
        }
      end
    end
    case shape
    when 2
      bmap = self.clone
      t.times { |i|
        r = Rect.new(sx + i, sy, 1, h)
        blt(r.x, r.y, sbmap, r)
        blt(r.x, r.y, bmap, r, 255 * i / t)
        r = Rect.new(sx + w * rate - 1 - i, sy, 1, h)
        blt(r.x, r.y, sbmap, r)
        blt(r.x, r.y, bmap, r, 255 * i / t)
        bmap = self.clone
      }
    end
  end
 
  def gradient_bar(type, style, shape, cstyle, actor, x, y, w, h, text = false, lines = false, fix = true)
    colors, bgcolor = get_colors(type, actor, cstyle)
    if fix
      case shape
      when 0
        w = (w - (lines ? 2 : 4)) / 8 * 8 + (lines ? 2 : 4)
      when 1
        w = (w - 3 - h + 1)
        w = w / 8 * 8
        w = w + h - 1 + 3
      when 2
        w = (w - 4) / 8 * 8 + 4
      when 3
        w = (w - 2 - h + 1)
        w = w / 8 * 8
        w = w + h - 1 + 2
      end
    end
    gradient_bar_back(bgcolor, shape, x, y, w, h, lines, false)
    case shape
    when 0
      x += (lines ? 1 : 2)
      y += (lines ? 1 : 2)
      w -= (lines ? 2 : 4)
      h -= (lines ? 2 : 4)
    when 1
      x += 3
      y += 1
      w -= 6
      h -= 3
    when 2
      x += 2
      y += 2
      w -= 4
      h -= 4
    when 3
      x += 3
      y += 1
      w -= 5
      h -= 3
    end
    case type
    when :hp
      rate = actor.hp.to_f / actor.maxhp
      str = actor.hp.to_s + '/' + actor.maxhp.to_s
    when :mp
      rate = actor.sp.to_f / actor.maxsp
      str = actor.sp.to_s + '/' + actor.maxsp.to_s
    when :exp
      elist = actor.instance_variable_get(:@exp_list)
      if elist[actor.level + 1]
        nexp = elist[actor.level + 1] - elist[actor.level]
        cexp = actor.exp - elist[actor.level]
        rate = (nexp <= 0 ? 1 : cexp.to_f / nexp)
      else
        rate = 1
      end
      str = actor.exp_s + '/' + actor.next_exp_s
    when :lvl
      rate = actor.level.to_f / (actor.respond_to?(:final_level) ? actor.final_level : $data_actors[actor.id].final_level)
      str = actor.level.to_s + '/' + (actor.respond_to?(:final_level) ? actor.final_level : $data_actors[actor.id].final_level).to_s
    end
    bgcolors = get_bgcolors(type, cstyle)
    gradient_bar_front(bgcolors, bgcolor, style, shape, x, y, w, h, 1)
    gradient_bar_front(colors, bgcolor, style, shape, x, y, w, h, rate)
    draw_lines(bgcolor, shape, x, y, w, h) if lines
    psize, pcol = font.size, font.color
    font.size = h
    font.color = Color.new(255, 255, 255)
    draw_text(x, y, w, h, str, 1) if text
    font.size, font.color = psize, pcol
  end
 
  def draw_lines(color, shape, x, y, w, h)
    case shape
    when 1, 3
      w -= h - 1
    when 2
      t = (h / 2.0).floor
      v = []
      h.times { |i|
        v.push(((t + 1) * (1 - Math.sin(Math::PI * (i + 1) / (h + 1)))).floor)
      }
    end
    w.times { |i|
      if [0, 7].include?(i % 8)
        case shape
        when 0
          fill_rect(x + i, y, 1, h, color)
        when 1
          h.times { |e|
            set_pixel(x + i + e, y + e, color)
          }
        when 2
          if i <= v.max
            ind = v.index(v.detect { |val| val <= i })
          elsif w - 1 - i <= v.max
            ind = v.index(v.detect { |val| val <= w - 1 - i })
          else
            ind = 0
          end
          fill_rect(x + i, y + ind, 1, h - (ind) * 2, color)
        when 3
          h.times { |e|
            set_pixel(x + i + h - 1 - e, y + e, color)
          }
        end
      end
    }
  end
 
  def get_bgcolors(type, cstyle)
    bc = Color.new(0, 0, 0)
    case type
    when :hp
      c1 = Color.new(100, 30, 30)
      c2 = Color.new(30, 100, 30)
    when :mp
      c1 = Color.new(100, 30, 30)
      c2 = Color.new(30, 30, 100)
    when :exp
      c1 = Color.new(100, 47, 22)
      c2 = Color.new(80, 80, 22)
    when :lvl
      c1 = Color.new(22, 47, 100)
      c2 = Color.new(80, 22, 80)
    end
    c = cstyle.map { |i|
      case i
      when 0 then c1
      when 1 then c2
      when 2 then bc
      when 3 then c2
      when 4 then c1
      when 5 then lcol(c1)
      when 6 then lcol(c2)
      when 7 then lcol(c2)
      when 8 then lcol(c1)
      when 9 then dcol(c1)
      when 10 then dcol(c2)
      when 11 then dcol(c2)
      when 12 then dcol(c1)
      end
    }
    return c
  end
end


class Scene_Map
  alias tdks_hud_main main
  def main
    @hud = HUD.new(DesignHUD::HUD)
    tdks_hud_main
    @hud.dispose
  end
 
  alias tdks_hud_updt update
  def update
    @hud.update
    tdks_hud_updt
  end
end



Instructions

Just set up the HUD text and start creating amazing HUDs. And read about the different elements in the script.


Compatibility

None known.


Credits and Thanks


  • ThallionDarkshine




Author's Notes

None.

KK20

Looks like you need to redo the post.  :evil:

Other Projects
RPG Maker XP Ace  Upgrade RMXP to RMVXA performance!
XPA Tilemap  Tilemap rewrite with many features, including custom resolution!

Nintendo Switch Friend Code: 8310-1917-5318
Discord: KK20 Tyler#8901

Join the CP Discord Server!

ThallionDarkshine