Been messing with this a bit.
NOTE: If you are confused by this, it may be because you are confusing two layers of data.
1. Alias definitions and expansions.
2. XML.
You need to separate these mentally to make sense of what's happening.
XML is the stuff with <Foo/> and <Foo></Foo>. The rules are (oversimplified):
1. Tags are either <Foo></Foo> or <Foo/>.
2. Tags can have attributes, which look like name="value".
3. The contents of attributes need to have <>&" encoded.
Basically, once you're in the right hunk of the UI layout file, an alias entry looks like:
Code:
<Alias String="STRING" Value="VALUE"/>
As to the contents of VALUE, start with the string you actually want, then:
1. Replace every ampersand (&) with "&".
2. Replace every double quote (") with """.
3. Replace every less-than (<) with "<".
3. Replace every greater-than (>) with ">". Yes, I know, it sometimes works if you don't, but don't rely on that. Consistency is king with fussy file formats...
Aliases are the DDO aliasing stuff. The rules are:
1. Each alias has a name and a value. The name is introduced with a semicolon, the value is any string.
2. After an alias is expanded, it's rescanned for more aliases.
3. All the letters after an alias are treated as an alias name. If you have an alias named ";this", and you write ";thisandthat", you won't get the alias expanded.
4. The main thing you likely care about is colors, which are done as <rgb=#XXXXXX>text</rgb>.
5. Note that this requires encoding; see above.
So if you want to create an alias with the name ";redred" and the value "<rgb=#ff0000>RED</rgb>", the XML code looks like:
Code:
<Alias String=";redred" Value="<rgb=#ff0000>RED</rgb>"/>
As you can see, the <rgb=...> turned into "<rgb=...>".
For most of this, I'll be showing the raw alias strings and values, because they're more legible.
Aliases are expanded recursively (the result of each expansion is reviewed again for more expansions). So:
Code:
;red = "ff0000"
;redred = "<rgb=#;red>RED</rgb>"
produces the same effect as the above.
There are limits to this. Each alias's expansion is looked at separately. For instance:
Code:
;red = "ff0000"
;semi = ";"
;color = "red"
;redred = ";semi;color"
Given these definitions, ";redred" expands to a literal ";red" which is not further expanded.
Let's say you wanted to string stuff together. Like, say, alternating colors for a stupendously obnoxious holiday greeting:
Code:
<rgb=#ff0000>M</rgb><rgb=#00ff00>e</rgb><rgb=#ff0000>r</rgb>...
And you have:
Code:
;red = "<rgb=#ff0000>"
;green = "<rgb=#00ff00>"
;end = "</rgb>"
You might want to do:
Code:
;redM;end;greene;end;redr;end...
But this obviously won't work.
You can do:
Code:
;red M;end;green e;end;red r;end
and it will work, but it'll be "s p a c e d o u t".
Well, long story short: You can't make an alias expand immediately followed by a letter. And you can't have enough aliases to just make, say, aliases for every letter:
Code:
;a = "a"
;b = "b"
..
What you can do is move the > out of the alias:
Code:
# leave the trailing > so it can be part of the caller's string.
;red = "<rgb=#ff0000"
;green = "<rgb=#00ff00"
Now, ";red>M;green>e;red>r..." will do what you want.
Of course, since the aliases are now stored in an XML file, that becomes unwieldy; you have to write something like:
Code:
<Alias String=";merry" Value=";red>M;green>e;red>r..."/>
So don't do that.
Having a hard time getting your XML right? I've enclosed Lua and Ruby scripts to take aliases in the form I've been using above and generate an output file that can be loaded with "/ui layout load". If the file only has an Aliases section, it doesn't appear to overwrite any other settings (though I'm not 100% sure of this yet).
I have no idea whether or how these would work with a DOS prompt, I use MinGW. With MinGW:
Code:
$ lua.exe aliases.lua < myaliases.in > myaliases.txt
OR
$ ruby aliases.rb < myaliases.in > myaliases.txt
$ cp myaliases.txt /c/users/$LOGNAME/Documents/Dungeon*/ui/layouts
And then in game:
Code:
/ui layout load myaliases.txt
Ruby version:
Code:
header = <<EOH
<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
<UI>
<Version Value="1.0"/>
<Aliases>
EOH
footer = <<EOH
</Aliases>
</UI>
EOH
aliases = []
$<.lines do |line|
next if line.match(%r{^\s*#})
line.chomp!
match = line.match(%r{^\s*;(\w*)\s*=\s*"(.*)"\s*$})
if not match
STDERR.puts("Can't match '#{line}'.")
next
end
aliases << [ match[1], match[2] ]
end
print header
aliases.each do |a|
value = a[1]
value.gsub!('&', '&')
value.gsub!('<', '<')
value.gsub!('>', '>')
value.gsub!('"', '"')
puts " <Alias String=\";#{a[0]}\" Value=\"#{value}\"/>"
end
print footer
Lua version:
Code:
local header = [[<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
<UI>
<Version Value="1.0"/>
<Aliases>]]
local footer = [[ </Aliases>
</UI>]]
local aliases = {}
while true do
local line = io.read()
if line == nil then
break
end
if not string.find(line, '^%s*#') then
local name, value
name, value = string.match(line, ';(%a+)%s*=%s*"(.*)"%s*$')
if not value then
print("Can't parse line: " .. line)
else
aliases[#aliases + 1] = { name, value }
end
end
end
print(header)
for _, alias in ipairs(aliases) do
name, value = unpack(alias)
value = string.gsub(value, '&', '&')
value = string.gsub(value, '<', '<')
value = string.gsub(value, '>', '>')
value = string.gsub(value, '"', '"')
print(' <Alias String=";' .. name .. '" Value="' .. value .. '"/>')
end
print(footer)