Chaos Project

RPG Maker => RPG Maker Scripts => Topic started by: ThallionDarkshine on December 29, 2012, 04:53:22 pm

Title: [VXA] Design a HUD (WIP)
Post by: ThallionDarkshine on December 29, 2012, 04:53:22 pm
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.

I have finished the first version of the RMXP script, and it will be ported back to Ace soon. However, in the meantime you can check out the pure awesomeness of the new RMXP version, which I will be posting shortly.

Spoiler: ShowHide


module DesignHUD
 # This HUD uses an easy to use format for configuration much like html
 #   it has many types of tags, each inserting different information into the
 #   HUD, such as icons, hp/sp/xp bars, and different information about the
 #   actors.
 #
 # Tags:
 #
 #  Formatting Elements:
 #   * <i></i>
 #     - italicizes text
 #   * <b></b>
 #     - bolds text
 #   * <c=R:G:B[:A]></c>
 #     - changes the color to Color.new(R, G, B, A) (A is unnecessary)
 #   * <font=NAME:SIZE></font>
 #     - changes the font to NAME and the font size to SIZE
 #  Graphical Elements:
 #   * <ico=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

         


 And apparently the first time I tried to post this, something went wrong and the entire list of tags that I had created vanished. So, here it is (notes on what each element/property does is in the script header, this is just a list of what's implemented):


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

Title: Re: [VXA] Design a HUD (WIP)
Post by: winkio on December 29, 2012, 05:39:49 pm
I'm sort of confused as to the purpose of this.  Is it for faster development, or for easier configuration/modification?  Either way I don't see the problem it solves, but maybe I'm missing something.
Title: Re: [VXA] Design a HUD (WIP)
Post by: ThallionDarkshine on December 29, 2012, 05:45:29 pm
It allows users to easily create their own customized HUD using an easy HTML-like language. It's just a tool to empower non-scripters, allowing them to make really awesome things easily.

Edit - Here's a screenie of some of the types and color schemes of gradient bars (these are all hp bars).
(http://i.imgur.com/OS8bK.png)

Edit2 - I've been working more on the gradient bars. I thought mine were decent, but then I opened up my test project with Tons, and Blizz's bars are so much more awesome than mine. Long story short, I didn't use any of his code, but I used his idea for the white accents for slant bars, and so he will be credited. However, I also made a really cool (I think) new shape for the bars, with rounded ends. And I have succeeded in creating 35 unique (at least somewhat) bar styles, not including color variations, shapes, or whether to draw lines across the bar. A screenie showing these new styles will be up soon.
Title: Re: [VXA][XP] Design a HUD (WIP)
Post by: Various on January 08, 2013, 09:40:18 am
thats pretty usefull :P my scripting knowledge is 0% but i know allot of html, now i can create a hud that fits my game :P level up