Envision, Create, Share

Welcome to HBGames, a leading amateur game development forum and Discord server. All are welcome, and amongst our ranks you will find experts in their field from all aspects of video game design and development.

[XP][VXA] Design a HUD (WIP)

Alright, so I'm working on a really customizable HUD framework. It uses a language sort of like HTML, only not as great. Right now I'm working on adding new features and elements and stuff like that, but if anyone would like to try it out, here's the script. This is basically a tool for non-scripters to create awesome-looking huds that look exactly how they want them to look.

Code:
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=X:Y>

  #  - inserts the icon in the iconset with an offset of X, Y

  #   * <pic='FILENAME'>

  #  - inserts the picture named FILENAME

  #   * <bar='TYPE:STYLE:WIDTH'>

  #  - inserts the blizzart bar (if using blizzart bars) in style STYLE

  #      and with colors corresponding to the stat TYPE with width WIDTH

  #  - types: HP, SP, EXP

  #  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

  #   * skin_tone=R:G:B

  #  - sets the tone of the windowskin

  #   * 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 bg=Cdd1I windowskin=Window skin_tone=255:-127:10 align='Bc' width=128 offsetx=0 offsety=0 opacity=0 contents_opacity=255>

    <ln><right><c=255:255:0><var=gold>G</c></right></ln>

    <ln><font=Times New Roman:24>Test</font></ln>

  HUD

  

  NO_END = ['ico', 'pic', 'hud', 'var']

  

  BLOCK_ELS = ['ln']

  

  def self.var_expression(name)

    case name

    when 'gold' then return proc { $game_party.gold }

    else return proc {}

    end

  end

end

 

class HUD < Window_Base

  attr_accessor :tmp_attrs

  def initialize(text)

    super(0, 0, 33, 33)

    create_contents

    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' }

    create_contents

    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

        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

          if vars.select { |el| pos = el.attrs[:pos];tmp = el.attrs[:size];tmp.x, tmp.y = *pos;tmp.intersect?(rect) }.length > 0

            redraw.push(child)

            comp = true

          end

        end

      }

    }

    redraw ||= vars

    

    redetermine_size(redim) if redim.length > 0

    setup_align

    redraw_hud(redraw) if redraw.length > 0

  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[:ox], @tmp_attrs[:abs_pos].last[1] + @tmp_attrs[:oy]]

            else

              child.attrs[:pos] = [pos[0] + @tmp_attrs[:ox], pos[1] + @tmp_attrs[:oy]]

            end

          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)

              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

              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

            end

          end

        }

      end

      

      #pos[1] += ln_height + @tmp_attrs[:oy]

      #ln_widths.push(ln_width)

      

      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 - padding * 2

      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]

            case child

            when TextNode

              pos = child.attrs[:pos]

              text = child.attrs[:val]

              size = child.attrs[:size]#self.contents.text_size(text)

              #ln_height = [size.height, ln_height].max

              self.contents.draw_text(Rect.new(pos[0], pos[1], size.width, size.height), text)

            when VariableNode

              pos = child.attrs[:pos]

              text = child.val

              size = child.attrs[:size]

              self.contents.draw_text(Rect.new(pos[0], pos[1], size.width, size.height), text)

            when IconNode, PictureNode

              pos = child.attrs[:pos]

              bitmap = child.attrs[:bitmap]

              self.contents.blt(pos[0], pos[1], bitmap, bitmap.rect)

            end

          end

        }

        #if ind <= text.length - 1

        #  text[ind..text.length - 1].each { |i|

        #   self.contents.draw_text(Rect.new(x, y, self.width, 32), i)

        #   x += self.contents.text_size(i).width

        #  }

        #end

      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\-]+)(?:=([\w\"\'\-\_\:\$\.]+))?((?:\s*\w+=[\w\"\'\-\_\:\$\.]+)*)>/

    epattern = /<\/[\w\-]+>/

    while text.length != 0

      s_ind = text.index(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] = el.split('=')[1].gsub(/[\'\"]/, '') }

        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!(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!(spattern, '')

          case el_name

          when 'hud'

            element = HudNode.new('hud', el_attrs)

            @dom.push(element)

          end

        end

      end

    end

  end

  

  def setup_hud

    @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) : Cache.system(tmp.attrs[:windowskin])) if tmp.attrs[:windowskin]

          rescue

            self.windowskin = Bitmap.new(1, 1)

          end

          self.tone = Tone.new(*tmp.attrs[:skin_tone].split(':').map{|i|i.to_f}) if tmp.attrs[:skin_tone]

          @bg = Sprite.new

          @bg.z = self.z - 1

          if tmp.attrs[:bg]

            @bg.bitmap = Cache.picture(tmp.attrs[:bg])

          else

            @bg.visible = false

          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

    @dom.each { |child|

      if child.block?

        child.attrs[:size].width = self.width - padding * 2

      end

    }

    @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 Graphics.width - self.width

    when 'c' then (Graphics.width - self.width) / 2

    end

    ystrt = case @align[0..0]

    when 't' then 0

    when 'b' then Graphics.height - self.height

    when 'm' then (Graphics.height - 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[0] + @tmp_attrs[:ox], @tmp_attrs[:abs_pos].last[1] + @tmp_attrs[:oy]]

            child.attrs[:abs] = @tmp_attrs[:abs_pos].length

          else

            child.attrs[:pos] = [pos[0] + @tmp_attrs[:ox], pos[1] + @tmp_attrs[:oy]]

            child.attrs[:abs] = 0

          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| # 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?

            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

            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

          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 = [x1, y1]

    el.attrs[:pos], el.attrs[:size] = pos, size

  end

  

  def setup_align

    aligned = nil

    @dom.each { |el|

      case el.el_type

      when 'ln'

        el.each_child_ex(proc {|child|},

        proc { |child| # end proc

          case child

          when FormatNode

            if child.attrs[:tmp]

              child.attrs.delete_at(:tmp)

              aligned.pop

              aligned = nil if aligned.empty?

            end

          end

        }) { |child| # main proc

          break unless aligned.nil?

          if ['right', 'left', 'center'].include?(child.el_type)

            child.attrs[:tmp] = true

            if aligned

              aligned.push(true)

            else

              aligned = [true]

            end

          end

          case child.attrs[:align]

          when 0

            pos = child.attrs[:pos]

            fb = child.last_block

            np = fb.attrs[:pos]

            child.attrs[:pos] = np.clone

            child.each_child_ex(proc{},proc{}) { |i|

              i.attrs[:pos][0] += np[0] - pos[0]

              i.attrs[:pos][1] += np[1] - pos[1]

            }

          when 1

            pos = child.attrs[:pos]

            fb = child.last_block

            fbw = fb.attrs[:size].width

            fbp = fb.attrs[:pos]

            w = child.attrs[:size].width

            np = [(fbw - w) / 2, pos[1]]

            child.attrs[:pos] = np.clone

            child.each_child_ex(proc{},proc{}) { |i|

              i.attrs[:pos][0] += np[0] - pos[0]

              i.attrs[:pos][1] += np[1] - pos[1]

            }

          when 2

            pos = child.attrs[:pos]

            fb = child.last_block

            fbw = fb.attrs[:size].width

            fbp = fb.attrs[:pos]

            w = child.attrs[:size].width

            np = [fbw - w, pos[1]]

            child.attrs[:pos] = np.clone

            child.each_child_ex(proc{},proc{}) { |i|

              i.attrs[:pos][0] += np[0] - pos[0]

              i.attrs[:pos][1] += np[1] - pos[1]

            }

          end

        }

      end

    }

  end

  

#~   def realign

#~   aligned = nil

#~   @dom.each { |el|

#~     case el.el_type

#~     when 'ln'

#~       el.each_child_ex(proc { |child| # start proc

#~         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)

#~           if child.attrs[:tmp]

#~             child.attrs.delete_at(:tmp)

#~             aligned.pop

#~             aligned = nil if aligned.empty?

#~           end

#~         end

#~       }) { |child| # main proc

#~         break unless aligned.nil?

#~         if ['right', 'left', 'center'].include?(child.el_type)

#~           child.attrs[:tmp] = true

#~           if aligned

#~             aligned.push(true)

#~           else

#~             aligned = [true]

#~           end

#~         end

#~         case child.attrs[:align]

#~         when 0

#~           pos = child.attrs[:pos]

#~           fb = child.last_block

#~           np = fb.attrs[:pos]

#~           child.attrs[:pos] = np.clone

#~           child.each_child_ex(proc{},proc{}) { |i|

#~             i.attrs[:pos][0] += np[0] - pos[0]

#~             i.attrs[:pos][1] += np[1] - pos[1]

#~           }

#~         when 1

#~           pos = child.attrs[:pos]

#~           fb = child.last_block

#~           fbw = fb.attrs[:size].width

#~           fbp = fb.attrs[:pos]

#~           w = child.attrs[:size].width

#~           np = [(fbw - w) / 2, pos[1]]

#~           child.attrs[:pos] = np.clone

#~           child.each_child_ex(proc{},proc{}) { |i|

#~             i.attrs[:pos][0] += np[0] - pos[0]

#~             i.attrs[:pos][1] += np[1] - pos[1]

#~           }

#~         when 2

#~           pos = child.attrs[:pos]

#~           fb = child.last_block

#~           fbw = fb.attrs[:size].width

#~           fbp = fb.attrs[:pos]

#~           w = child.attrs[:size].width

#~           np = [fbw - w, pos[1]]

#~           child.attrs[:pos] = np.clone

#~           child.each_child_ex(proc{},proc{}) { |i|

#~             i.attrs[:pos][0] += np[0] - pos[0]

#~             i.attrs[:pos][1] += np[1] - pos[1]

#~           }

#~         end

#~       }

#~     end

#~   }

#~   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|

          case child

          when TextNode

            pos = child.attrs[:pos]

            text = child.attrs[:val]

            size = child.attrs[:size]#self.contents.text_size(text)

            #ln_height = [size.height, ln_height].max

#~           if @tmp_attrs[:tmpalign]

#~             case @tmp_attrs[:tmpalign].last

#~             when 'r'

#~               pos = pos.clone

#~               pos[0] = contents.width - pos[0] - size.width

#~             end

#~           end

            self.contents.draw_text(Rect.new(pos[0], pos[1], size.width, size.height), text)

          when VariableNode

            pos = child.attrs[:pos]

            text = child.val.to_s

            size = child.attrs[:size]

#~           if @tmp_attrs[:tmpalign]

#~             case @tmp_attrs[:tmpalign].last

#~             when 'r'

#~               pos = pos.clone

#~               pos[0] = contents.width - pos[0] - size.width

#~             end

#~           end

            self.contents.draw_text(Rect.new(pos[0], pos[1], size.width, size.height), text)

          when IconNode, PictureNode

            pos = child.attrs[:pos]

            bitmap = child.attrs[:bitmap]

            self.contents.blt(pos[0], pos[1], bitmap, bitmap.rect)

          end

        }

      end

    }

  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 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\-]+)(?:=([\w\"\'\-\_\:\$\.\s]+))?((?:\s*\w+=[\w\"\'\-\_\:\$\.]+)*)>/

    epattern = /<\/[\w\-]+>/

    while text != ''

      s_ind = text.index(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] = eval(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!(spattern, '')

          last_ind = nil

          loop do

            tmp = [text.index(/(<#{el_name}(?:=[\w\"\'\-\:]+)?(?:\s*\w+=[\w\"\'\-\:]+)*>)/, tmp_ind)]

            tmp2 = tmp_ind

            for i in 0..level

              tmp2 = text.index(/<\/#{el_name}>/, tmp2) + 2 + el_name.length

            end

            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!(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)

          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] = Cache.picture(val)

  end

end

 

class IconNode < Element

  def initialize(parent, val)

    super('ico', {}, parent)

    offset = val.split(':').map { |i| i.to_i * 24 }

    @attrs[:bitmap] = Bitmap.new(24, 24)

    iconset = Cache.system('IconSet')

    @attrs[:bitmap].blt(0, 0, iconset, Rect.new(offset[0], offset[1], 24, 24))

  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 BarNode < Element

  

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

I originally started making this in RMXP, but ported it over to RMVXA when it appeared that I had found a bug in RMXP's ruby interpreter. However, I just tried back-porting it to RMXP, and it worked. So now, I will resume development in RMXP. Here is the current RMXP version of the script:
Code:
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='TYPE:STYLE:WIDTH'>

  #  - inserts the blizzart bar (if using blizzart bars) in style STYLE

  #      and with colors corresponding to the stat TYPE with width WIDTH

  #  - types: HP, SP, EXP

  #  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 bg=Cdd1I windowskin=Window align='Bc' width=128 offsetx=0 offsety=0 opacity=0 contents_opacity=255>

    <ln><right><c=255:255:0><var=gold>G</c></right></ln>

    <ln><font=Times New Roman:24>Test</font></ln>

  HUD

  

  NO_END = ['ico', 'pic', 'hud', 'var']

  

  BLOCK_ELS = ['ln']

  

  def self.var_expression(name)

    case name

    when 'gold' then return proc { $game_party.gold }

    else return proc {}

    end

  end

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.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

        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

          if vars.select { |el| pos = el.attrs[:pos];tmp = el.attrs[:size];tmp.x, tmp.y = *pos;tmp.intersect?(rect) }.length > 0

            redraw.push(child)

            comp = true

          end

        end

      }

    }

    redraw ||= vars

    

    redetermine_size(redim) if redim.length > 0

    setup_align

    redraw_hud(redraw) if redraw.length > 0

  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[:ox], @tmp_attrs[:abs_pos].last[1] + @tmp_attrs[:oy]]

            else

              child.attrs[:pos] = [pos[0] + @tmp_attrs[:ox], pos[1] + @tmp_attrs[:oy]]

            end

          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

              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

            end

          end

        }

      end

      

      #pos[1] += ln_height + @tmp_attrs[:oy]

      #ln_widths.push(ln_width)

      

      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

      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]

            case child

            when TextNode

              pos = child.attrs[:pos]

              text = child.attrs[:val]

              size = child.attrs[:size]#self.contents.text_size(text)

              #ln_height = [size.height, ln_height].max

              self.contents.draw_text(Rect.new(pos[0], pos[1], size.width, size.height), text)

            when VariableNode

              pos = child.attrs[:pos]

              text = child.val.to_s

              size = child.attrs[:size]

              self.contents.draw_text(Rect.new(pos[0], pos[1], size.width, size.height), text)

            when IconNode, PictureNode

              pos = child.attrs[:pos]

              bitmap = child.attrs[:bitmap]

              self.contents.blt(pos[0], pos[1], bitmap, bitmap.rect)

            end

          end

        }

        #if ind <= text.length - 1

        #  text[ind..text.length - 1].each { |i|

        #   self.contents.draw_text(Rect.new(x, y, self.width, 32), i)

        #   x += self.contents.text_size(i).width

        #  }

        #end

      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\-]+)(?:=([\w\"\'\-\_\:\$\.]+))?((?:\s*\w+=[\w\"\'\-\_\:\$\.]+)*)>/

    epattern = /<\/[\w\-]+>/

    while text.length != 0

      s_ind = text.index(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] = el.split('=')[1].gsub(/[\'\"]/, '') }

        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!(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!(spattern, '')

          case el_name

          when 'hud'

            element = HudNode.new('hud', el_attrs)

            @dom.push(element)

          end

        end

      end

    end

  end

  

  def setup_hud

    @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) : Cache.system(tmp.attrs[:windowskin])) if tmp.attrs[:windowskin]

          rescue

            self.windowskin = Bitmap.new(1, 1)

          end

          @bg = Sprite.new

          @bg.z = self.z - 1

          if tmp.attrs[:bg]

            @bg.bitmap = RPG::Cache.picture(tmp.attrs[:bg])

          else

            @bg.visible = false

          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

    @dom.each { |child|

      if child.block?

        child.attrs[:size].width = self.width - 32

      end

    }

    @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[0] + @tmp_attrs[:ox], @tmp_attrs[:abs_pos].last[1] + @tmp_attrs[:oy]]

            child.attrs[:abs] = @tmp_attrs[:abs_pos].length

          else

            child.attrs[:pos] = [pos[0] + @tmp_attrs[:ox], pos[1] + @tmp_attrs[:oy]]

            child.attrs[:abs] = 0

          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| # 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?

            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

            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

          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 = [x1, y1]

    el.attrs[:pos], el.attrs[:size] = pos, size

  end

  

  def setup_align

    aligned = nil

    @dom.each { |el|

      case el.el_type

      when 'ln'

        el.each_child_ex(proc {|child|},

        proc { |child| # end proc

          case child

          when FormatNode

            if child.attrs[:tmp]

              child.attrs.delete_at(:tmp)

              aligned.pop

              aligned = nil if aligned.empty?

            end

          end

        }) { |child| # main proc

          break unless aligned.nil?

          if ['right', 'left', 'center'].include?(child.el_type)

            child.attrs[:tmp] = true

            if aligned

              aligned.push(true)

            else

              aligned = [true]

            end

          end

          case child.attrs[:align]

          when 0

            pos = child.attrs[:pos]

            fb = child.last_block

            np = fb.attrs[:pos]

            child.attrs[:pos] = np.clone

            child.each_child_ex(proc{},proc{}) { |i|

              i.attrs[:pos][0] += np[0] - pos[0]

              i.attrs[:pos][1] += np[1] - pos[1]

            }

          when 1

            pos = child.attrs[:pos]

            fb = child.last_block

            fbw = fb.attrs[:size].width

            fbp = fb.attrs[:pos]

            w = child.attrs[:size].width

            np = [(fbw - w) / 2, pos[1]]

            child.attrs[:pos] = np.clone

            child.each_child_ex(proc{},proc{}) { |i|

              i.attrs[:pos][0] += np[0] - pos[0]

              i.attrs[:pos][1] += np[1] - pos[1]

            }

          when 2

            pos = child.attrs[:pos]

            fb = child.last_block

            fbw = fb.attrs[:size].width

            fbp = fb.attrs[:pos]

            w = child.attrs[:size].width

            np = [fbw - w, pos[1]]

            child.attrs[:pos] = np.clone

            child.each_child_ex(proc{},proc{}) { |i|

              i.attrs[:pos][0] += np[0] - pos[0]

              i.attrs[:pos][1] += np[1] - pos[1]

            }

          end

        }

      end

    }

  end

  

#~   def realign

#~   aligned = nil

#~   @dom.each { |el|

#~     case el.el_type

#~     when 'ln'

#~       el.each_child_ex(proc { |child| # start proc

#~         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)

#~           if child.attrs[:tmp]

#~             child.attrs.delete_at(:tmp)

#~             aligned.pop

#~             aligned = nil if aligned.empty?

#~           end

#~         end

#~       }) { |child| # main proc

#~         break unless aligned.nil?

#~         if ['right', 'left', 'center'].include?(child.el_type)

#~           child.attrs[:tmp] = true

#~           if aligned

#~             aligned.push(true)

#~           else

#~             aligned = [true]

#~           end

#~         end

#~         case child.attrs[:align]

#~         when 0

#~           pos = child.attrs[:pos]

#~           fb = child.last_block

#~           np = fb.attrs[:pos]

#~           child.attrs[:pos] = np.clone

#~           child.each_child_ex(proc{},proc{}) { |i|

#~             i.attrs[:pos][0] += np[0] - pos[0]

#~             i.attrs[:pos][1] += np[1] - pos[1]

#~           }

#~         when 1

#~           pos = child.attrs[:pos]

#~           fb = child.last_block

#~           fbw = fb.attrs[:size].width

#~           fbp = fb.attrs[:pos]

#~           w = child.attrs[:size].width

#~           np = [(fbw - w) / 2, pos[1]]

#~           child.attrs[:pos] = np.clone

#~           child.each_child_ex(proc{},proc{}) { |i|

#~             i.attrs[:pos][0] += np[0] - pos[0]

#~             i.attrs[:pos][1] += np[1] - pos[1]

#~           }

#~         when 2

#~           pos = child.attrs[:pos]

#~           fb = child.last_block

#~           fbw = fb.attrs[:size].width

#~           fbp = fb.attrs[:pos]

#~           w = child.attrs[:size].width

#~           np = [fbw - w, pos[1]]

#~           child.attrs[:pos] = np.clone

#~           child.each_child_ex(proc{},proc{}) { |i|

#~             i.attrs[:pos][0] += np[0] - pos[0]

#~             i.attrs[:pos][1] += np[1] - pos[1]

#~           }

#~         end

#~       }

#~     end

#~   }

#~   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|

          case child

          when TextNode

            pos = child.attrs[:pos]

            text = child.attrs[:val]

            size = child.attrs[:size]#self.contents.text_size(text)

            #ln_height = [size.height, ln_height].max

#~           if @tmp_attrs[:tmpalign]

#~             case @tmp_attrs[:tmpalign].last

#~             when 'r'

#~               pos = pos.clone

#~               pos[0] = contents.width - pos[0] - size.width

#~             end

#~           end

            self.contents.draw_text(Rect.new(pos[0], pos[1], size.width, size.height), text)

          when VariableNode

            pos = child.attrs[:pos]

            text = child.val.to_s

            size = child.attrs[:size]

#~           if @tmp_attrs[:tmpalign]

#~             case @tmp_attrs[:tmpalign].last

#~             when 'r'

#~               pos = pos.clone

#~               pos[0] = contents.width - pos[0] - size.width

#~             end

#~           end

            self.contents.draw_text(Rect.new(pos[0], pos[1], size.width, size.height), text)

          when IconNode, PictureNode

            pos = child.attrs[:pos]

            bitmap = child.attrs[:bitmap]

            self.contents.blt(pos[0], pos[1], bitmap, bitmap.rect)

          end

        }

      end

    }

  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 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\-]+)(?:=([\w\"\'\-\_\:\$\.\s]+))?((?:\s*\w+=[\w\"\'\-\_\:\$\.]+)*)>/

    epattern = /<\/[\w\-]+>/

    while text != ''

      s_ind = text.index(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] = eval(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!(spattern, '')

          last_ind = nil

          loop do

            tmp = [text.index(/(<#{el_name}(?:=[\w\"\'\-\:]+)?(?:\s*\w+=[\w\"\'\-\:]+)*>)/, tmp_ind)]

            tmp2 = tmp_ind

            for i in 0..level

              tmp2 = text.index(/<\/#{el_name}>/, tmp2) + 2 + el_name.length

            end

            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!(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)

          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 BarNode < Element

  

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

And here's a list of the elements and properties that I've already added:
<hud>
Properties Implemented:
windowskin=FILENAME
bg=FILENAME
width=WIDTH
height=HEIGHT
align=ALIGN
offsetx=OFFSETX
offsety=OFFSETY
back_opacity=OPACITY
contents_opacity=OPACITY
opacity=OPACITY
skin_tone=R:G:B (VXA only)
<ln></ln>
<right></right>
<left></left>
<center></center>
<pos x=X y=Y></pos>
<offset x=X y=Y></pos>
<ico=X:Y> (VXA only)
<ico=FILENAME> (XP only)
<pic=FILENAME>
<b></b>
<i></i>
<c=R:G:B[:A]></c>
<font=NAME:SIZE></font>


Edit - Here's a screenie of some of the different types of gradient bars.
OS8bK.png
 
this is looking like a really cool project.

the different types of gradient bars are looking really shitty, the way you presented them, but it gives a representation of what cán be done, which is nice.
this was something I could've used back when I was using RMXP, nice job!
 
I know that they suck right now, but once I've finished making them look better you'll be able to choose the style, shape, and color scheme of the bar. So the user will basically be able to decide whether to make their bars look awful or good.
 
Thanks, I'm not working on it at the moment but soon I'll go back to work and try to finish up the tags. By the way, does anyone have an idea for any tags that I should add?
 

Thank you for viewing

HBGames is a leading amateur video game development forum and Discord server open to all ability levels. Feel free to have a nosey around!

Discord

Join our growing and active Discord server to discuss all aspects of game making in a relaxed environment. Join Us

Content

  • Our Games
  • Games in Development
  • Emoji by Twemoji.
    Top