--[[ MACRO FORMAT: (8 byte head) (4 byte size of MACRO DATA [currently 1288])(4 byte NUM OF MACROS) (1288 byte MACRO DATA) LOOP: (4 byte INDEX[0-55])(4byte ICON) (256 byte UNKNOWN) (256 byte MACRO TEXT) (768 byte PADDING?) ENDLOOP --]] local MACRO_SIZE = 1288; local MACRO_COUNT = 56; local MACRO_UNKNOWNSIZE = 0x100; local MACRO_TEXTSIZE = 0x100; -- Size including NULL terminator local MACRO_PADDINGSIZE = 0x300; local MACRO_ICONMAX = 60; local MACRO_NULLICON = 0XFFFFFFFF; local userprofilePath = os.getenv("USERPROFILE"); local documentPaths = { userprofilePath .. "\\My Documents\\" .. "Runes of Magic", -- English userprofilePath .. "\\Eigene Dateien\\" .. "Runes of Magic", -- German userprofilePath .. "\\Mes Documents\\" .. "Runes of Magic", -- French userprofilePath .. "\\Omat tiedostot\\" .. "Runes of Magic", -- Finish userprofilePath .. "\\Belgelerim\\" .. "Runes of Magic", -- Turkish userprofilePath .. "\\Mina Dokument\\" .. "Runes of Magic", -- Swedish userprofilePath .. "\\Dokumenter\\" .. "Runes of Magic", -- Danish userprofilePath .. "\\Documenti\\" .. "Runes of Magic", -- Italian userprofilePath .. "\\Mijn documenten\\" .. "Runes of Magic", -- Dutch userprofilePath .. "\\Moje dokumenty\\" .. "Runes of Magic", -- Polish userprofilePath .. "\\Mis documentos\\" .. "Runes of Magic", -- Spanish }; -- Select the first path that exists function findMacroBsd(charName) for i,v in pairs(documentPaths) do if( string.sub(v, -1 ) ~= "\\" and string.sub(v, -1 ) ~= "/" ) then v = v .. "\\"; -- Append the trailing backslash if necessary. end local filename = v .. charName .. "/Macro.bsd"; if( fileExists(filename) ) then return filename; end end return nil; end -- Convert a Lua number to 4 bytes function intToBytes(int) --int = tonumber( string.format("%u", int), 10); local a,b,c,d = math.mod(int, 256), math.mod(int, 65536) / 256, math.mod(int, 16777216) / 65536, int / 16777216; -- Some weird Lua bug with unsigned ints... -- It pretends it's positive, but will cause -- errors for being negitive in some functions (ie. string.char) -- This is a hackish work-around. if( a < 0 ) then a = math.max(a, 0); end; if( a > 255 ) then a = math.min(a, 255); end; if( b < 0 ) then b = math.max(b, 0); end; if( b > 255 ) then b = math.min(b, 255); end; if( c < 0 ) then c = math.max(c, 0); end; if( c > 255 ) then c = math.min(c, 255); end; if( d < 0 ) then d = math.max(d, 0); end; if( d > 255 ) then d = math.min(d, 255); end; return string.char(a, b, c, d); end function bytesToInt(a, b, c, d) return tonumber( string.format("%02x%02x%02x%02x", d, c, b, a), 16); end local macroData; function initializeMacroData() macroData = {}; for i = 1,MACRO_COUNT do macroData[i - 1] = { ["icon"] = intToBytes(MACRO_NULLICON); ["unknown"] = string.rep( string.char(0x0), MACRO_UNKNOWNSIZE ); ["text"] = string.rep( string.char(0x0), MACRO_TEXTSIZE ); ["padding"] = string.rep( string.char(0x0), MACRO_PADDINGSIZE ); }; end end function readMacroData(fname) local infile = io.open(fname, "rb"); -- Read (but discard) the header; assume our own values --MACRO_SIZE = bytesToInt(string.byte(infile:read(4), 1, 4)); infile:read(4); infile:read(4); for i = 1,MACRO_COUNT do local index = i - 1; local icon, unknown, text, padding; -- Read (and discard) index infile:read(4); -- Read icon icon = bytesToInt(string.byte(infile:read(4), 1, 4)); -- Force it to a valid value if( icon ~= MACRO_NULLICON ) then icon = math.min(icon, MACRO_ICONMAX); icon = math.max(icon, 0); end -- Read (and discard) UNKNOWN data infile:read(MACRO_UNKNOWNSIZE); unknown = string.rep(string.char(0x0), MACRO_UNKNOWNSIZE); -- Read macro text text = infile:read(MACRO_TEXTSIZE); -- Force a NULL terminator text = string.sub(text, 1, text:len()-1) .. string.char(0x0); -- Read (and discard) padding infile:read(MACRO_PADDINGSIZE); padding = string.rep(string.char(0x0), MACRO_PADDINGSIZE); macroData[index].icon = icon; macroData[index].unknown = unknown; macroData[index].text = text; macroData[index].padding = padding; end infile:close(); end function writeMacroData(fname) local outfile = io.open(fname, "wb"); -- Write the header outfile:write( intToBytes(MACRO_SIZE) ); outfile:write( intToBytes(MACRO_COUNT) ); -- Write each macro for i = 1,MACRO_COUNT do local index = i - 1; outfile:write( intToBytes(i - 1) ); -- Write index outfile:write( intToBytes(macroData[index].icon) ); outfile:write( macroData[index].unknown ); outfile:write( macroData[index].text ); outfile:write( macroData[index].padding ); end outfile:close(); end -- Prompt for character name local charName, fname; cprintf(cli.red, "MAKE SURE YOU ARE LOGGED OFF BEFORE RUNNING THIS SCRIPT!\n"); printf("Please input the character's name.\n>"); charName = string.gsub(io.read("*l"), "([%w%s%p]+)\n", "%0"); printf("Char name: \'%s\'\n", charName); fname = findMacroBsd(charName); if( fname == nil ) then printf("We were unable to find your Macro.bsd file.\n" .. "Try manually deleting Macro.bsd from My Documents/CharacterName/Macro.bsd"); else initializeMacroData(); readMacroData(fname); writeMacroData("Macro.bsd"); printf("Macro.bsd file rewritten. You can log in now.\n"); end