Submit Your Article


 
RPG Maker

Welcome Guest ( Log In | Register )


  Games Resources RPG Maker VX RPG Maker XP Scripts Tutorials Downloads

> [XP][VXA] Design a HUD (WIP), A easy-to-use HUD framework using a simple HTML-like language.
Thallion
post Dec 30 2012, 09:08 AM
Post #1


Level 5
Group Icon

Group: Member
Posts: 68
Type: Scripter
RM Skill: Skilled
Rev Points: 10




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>
Go to the top of the page
 
+Quote Post
   
 
Start new topic
Replies
Jonnie19
post Jan 2 2013, 03:15 PM
Post #2


Are you trying to rise from your lullaby?
Group Icon

Group: Global Mod
Posts: 1,311
Type: Developer
RM Skill: Intermediate
Rev Points: 45




Would you consider porting it into VX also? As there are a good number of VX'ers still around smile.gif


__________________________

Finished Projects:
Slenderman's Army:


Go to the top of the page
 
+Quote Post
   



Reply to this topicStart new topic
1 User(s) are reading this topic (1 Guests and 0 Anonymous Users)
0 Members:

 

Lo-Fi Version Time is now: 22nd May 2013 - 11:47 PM
RPG RPG Revolution is an Privacy Policy and Legal
eXTReMe Tracker