-- loads legacy raids from data/raids/raids.xml local messageTypes = { ["warning"] = MESSAGE_STATUS_WARNING, ["event"] = MESSAGE_EVENT_ADVANCE, ["default"] = MESSAGE_EVENT_DEFAULT, ["description"] = MESSAGE_INFO_DESCR, ["smallstatus"] = MESSAGE_STATUS_SMALL, ["blueconsole"] = MESSAGE_STATUS_CONSOLE_BLUE, ["redconsole"] = MESSAGE_STATUS_CONSOLE_RED, } local defaultMessageType = "event" local function parseAnnounce(node, filename) local message = node:attribute("message") if not message then io.write("[Error] Missing message attribute, check data/raids/" .. filename .. "\n") end local type = node:attribute("type") if not type then io.write("[Notice] Missing type for announce event in " .. filename .. ". Using default: " .. defaultMessageType .. ".\n") type = defaultMessageType end local messageType = messageTypes[type:lower()] if not messageType then io.write("[Notice] Unknown type " .. type .. " for announce event in " .. filename .. ". Using default: " .. messageTypes[defaultMessageType] .. ".\n") messageType = messageTypes[defaultMessageType] end return function() Game.broadcastMessage(message, messageType) end end local function parseAreaSpawn(node, filename) local fromx, fromy, fromz, tox, toy, toz local radius = tonumber(node:attribute("radius")) if radius then local centerx, centery, centerz = tonumber(node:attribute("centerx")), tonumber(node:attribute("centery")), tonumber(node:attribute("centerz")) if not centerx or not centery or not centerz then io.write("[Error] Missing one of: centerx, centery, centerz, check data/raids/" .. filename .. "\n") end fromx, fromy, fromz = centerx - radius, centery - radius, z tox, toy, toz = centerx + radius, centery + radius, z else fromx, fromy, fromz = tonumber(node:attribute("fromx")), tonumber(node:attribute("fromy")), tonumber(node:attribute("fromz")) if not fromx or not fromy or not fromz then io.write("[Error] Missing one of: fromx, fromy, fromz, check data/raids/" .. filename .. "\n") end tox, toy, toz = tonumber(node:attribute("tox")), tonumber(node:attribute("toy")), tonumber(node:attribute("toz")) if not tox or not toy or not toz then io.write("[Error] Missing one of: tox, toy, toz, check data/raids/" .. filename .. "\n") end end local spawns = {} for spawnNode in node:children() do local name = spawnNode:attribute("name") if not name then io.write("[Error] Missing attribute name, check data/raids/" .. filename .. "\n") return nil end local minAmount, maxAmount = tonumber(spawnNode:attribute("minamount")), tonumber(spawnNode:attribute("maxamount")) if not minAmount and not maxAmount then local amount = tonumber(spawnNode:attribute("amount")) if not amount then io.write("[Error] Missing attributes minamount/maxamount or amount, check data/raids/" .. filename .. "\n") end minAmount, maxAmount = amount, amount elseif not minAmount then io.write("[Warning] Missing attribute minamount in " .. filename .. ", using maxamount as default.\n") minAmount = maxAmount elseif not maxAmount then io.write("[Warning] Missing attribute maxamount in " .. filename .. ", using minamount as default.\n") maxAmount = minAmount end spawns[#spawns] = { monsterName = name, minAmount = minAmount, maxAmount = maxAmount } end return function() for _, spawn in ipairs(spawns) do for _ = 1, math.random(spawn.minAmount, spawn.maxAmount) do local x, y = math.random(fromx, tox), math.random(fromy, toy) Game.createMonster(spawns.name, Position(x, y, z)) end end end end local function parseScript(node) local script = node:attribute("script") if not script then io.write("[Error] Missing attribute script, check data/raids/" .. filename .. "\n") return nil end local scriptFile = "data/raids/scripts/" .. script dofile(script) if not onRaid then io.write("[Error] Can not load raid script, check " .. scriptFile .. " for a missing onRaid callback\n") return nil end local callback = onRaid -- let it be garbage collected onRaid = nil return callback end local function parseSingleSpawn(node, filename) local name = node:attribute("name") if not name then io.write("[Error] Missing attribute name, check data/raids/" .. filename .. "\n") return nil end local x, y, z = tonumber(node:attribute("x")), tonumber(node:attribute("y")), tonumber(node:attribute("z")) if not x or not y or not z then io.write("[Error] Missing one of: x, y, z, check data/raids/" .. filename .. "\n") end return function() Game.createMonster(spawns.name, Position(x, y, z)) end end local eventParsers = { ["announce"] = parseAnnounce, ["areaspawn"] = parseAreaSpawn, ["script"] = parseScript, ["singlespawn"] = parseSingleSpawn, } local function parseRaid(filename) local doc = XMLDocument("data/raids/" .. filename) local eventNodes = doc:child("raid") local events = {} for eventNode in eventNodes:children() do local parse = eventParsers[eventNode:name()] if not parse then io.write("[Error] Unknown event type: " .. eventNode:name() .. ".\n") return nil end local delay = tonumber(eventNode:attribute("delay")) if not delay then io.write("[Error] Missing attribute delay, check data/raids/" .. filename .. "\n") return nil end local callback = parse(eventNode, filename) if not callback then return nil end events[#events] = { delay = delay, callback = callback } end return events end local function configureRaidEvent(node) local name = node:attribute("name") if not name then io.write("[Error] Missing attribute name for raid.\n") return nil end local filename = node:attribute("file") if not filename then io.write('[Warning] file attribute missing for raid "' .. name .. '". Using default: "' .. name .. '.xml"\n') filename = name .. ".xml" end -- using filename instead of name because name can be duplicate, but filename cannot local raid = Raid("data/raids/" .. filename) local interval = tonumber(node:attribute("interval2")) if not interval or interval == 0 then io.write("[Error] interval2 attribute missing or zero (would divide by 0), check raid " .. name .. " in data/raids/raids.xml\n") return nil end raid.interval = interval local margin = tonumber(node:attribute("margin")) if margin and margin > 0 then raid.margin = margin * 60 * 1000 else io.write("[Warning] margin attribute missing for raid " .. name .. ". Using default: 0\n") end local repeats = tobool(node:attribute("repeat")) if repeats then raid.repeats = repeats end local events = parseRaid(filename) if not events then return nil end for _, event in ipairs(events) do raid:addEvent(event.delay, event.callback) end return raid end local function loadXMLRaids() local doc = XMLDocument("data/raids/raids.xml") if not doc then io.write("[Warning - Scripts::XML::loadXMLRaids] Could not load raids.xml.\n") return end local raids = doc:child("raids") io.write(">> Loading legacy XML raids from data/raids/raids.xml...\n") local loaded, start = 0, os.mtime() for node in raids:children() do local enabled = node:attribute("enabled") if enabled == nil or tobool(enabled) then local raid = configureRaidEvent(node) if raid then raid:register() loaded = loaded + 1 end end end io.write(">> Loaded " .. loaded .. " raids in " .. os.mtime() - start .. "ms.\n") end loadXMLRaids()