diff --git a/data/lib/compat/compat.lua b/data/lib/compat/compat.lua
index b1dc5f7b61..659bcc19af 100644
--- a/data/lib/compat/compat.lua
+++ b/data/lib/compat/compat.lua
@@ -237,6 +237,7 @@ do
self:onThink(value)
return
elseif key == "onTime" then
+ self:type("timer")
self:onTime(value)
return
elseif key == "onStartup" then
@@ -1350,8 +1351,10 @@ function doSetGameState(state)
end
function doExecuteRaid(raidName)
- return Game.startRaid(raidName)
+ debugPrint("Deprecated function, use Game.startEvent('" .. raidName .. "') instead.")
+ return Game.startEvent(raidName)
end
+Game.startRaid = doExecuteRaid
function Game.convertIpToString(ip)
print("[Warning - " .. debug.getinfo(2).source:match("@?(.*)") .. "] Function Game.convertIpToString is deprecated and will be removed in the future. Use the return value of player:getIp() instead.")
diff --git a/data/lib/core/raids.lua b/data/lib/core/raids.lua
new file mode 100644
index 0000000000..8891a4c3d4
--- /dev/null
+++ b/data/lib/core/raids.lua
@@ -0,0 +1,43 @@
+local raids = {}
+
+Raid = setmetatable({
+ getRaids = function() return raids end
+}, {
+ __call = function(self, name)
+ local events = {}
+
+ local obj = {
+ margin = 0,
+ name = name,
+ repeats = false,
+ }
+
+ function obj:__newindex(key, value)
+ if key == "interval" or key == "margin" or key == "repeats" then
+ rawset(self, key, value)
+ else
+ io.write("[Warning] Invalid attribute for raid: " .. key .. ". Ignoring...\n")
+ end
+ end
+
+ function obj:addEvent(delay, fn)
+ events[#events] = { delay = delay, fn = fn }
+ end
+
+ function obj:execute()
+ for _, event in ipairs(events) do
+ addEvent(event.delay, event.fn)
+ end
+ end
+
+ function obj:register()
+ raids[self.name] = self
+ end
+
+ function obj:unregister()
+ raids[self.name] = nil
+ end
+
+ return obj
+ end
+})
diff --git a/data/raids/raids.xml b/data/raids/raids.xml
deleted file mode 100644
index e61a5a6e49..0000000000
--- a/data/raids/raids.xml
+++ /dev/null
@@ -1,7 +0,0 @@
-
-
-
-
diff --git a/data/raids/testraid.xml b/data/raids/testraid.xml
deleted file mode 100644
index ebfe9d0c9c..0000000000
--- a/data/raids/testraid.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/data/scripts/globalevents/#testraid.lua b/data/scripts/globalevents/#testraid.lua
new file mode 100644
index 0000000000..6dcac09aaf
--- /dev/null
+++ b/data/scripts/globalevents/#testraid.lua
@@ -0,0 +1,51 @@
+local raid = GlobalEvent("Testraid")
+raid:interval(1800)
+
+local function event0()
+ Game.broadcastMessage("Rats are attacking near Trekolt Temple!", MESSAGE_STATUS_WARNING)
+end
+
+local function event1()
+ local center, radius, z = {x=94, y=126}, 5, 7
+ for _ = 1, 3 do
+ local x, y = math.random(center.x - radius, center.x + radius), math.random(center.y - radius, center.y + radius)
+ Game.createMonster("Rat", Position(x, y, z))
+ end
+end
+
+local function event2()
+ Game.createMonster("Cave Rat", Position(93, 123, 7))
+end
+
+local function event3()
+ Game.broadcastMessage("Rats attack continues!", MESSAGE_STATUS_WARNING)
+end
+
+local function event4()
+ local from, to, z = {x=89, y=122}, {x=99, y=130}, 7
+ for _ = 1, math.random(4, 10) do
+ local x, y = math.random(from.x, to.x), math.random(from.y, to.y)
+ Game.createMonster("Rat", Position(x, y, z))
+ end
+end
+
+local function event5()
+ Game.createMonster("Cave Rat", Position(98, 125, 7))
+end
+
+local function event6()
+ Game.createMonster("Cave Rat", Position(94, 128, 7))
+end
+
+function raid.onTime(interval)
+ addEvent(event0, 1000)
+ addEvent(event1, 2000)
+ addEvent(event2, 15000)
+ addEvent(event3, 25000)
+ addEvent(event4, 30000)
+ addEvent(event5, 30000)
+ addEvent(event6, 30000)
+ return true
+end
+
+raid:register()
diff --git a/data/scripts/globalevents/raids.lua b/data/scripts/globalevents/raids.lua
new file mode 100644
index 0000000000..0c1a26e0cb
--- /dev/null
+++ b/data/scripts/globalevents/raids.lua
@@ -0,0 +1,36 @@
+local event = GlobalEvent("raids")
+
+local CHECK_RAIDS_INTERVAL = 60
+local MAX_RAND_RANGE = 10000000
+
+event:interval(CHECK_RAIDS_INTERVAL)
+
+local running = nil
+local lastRaidEnd = 0
+
+function event.onTime(interval)
+ io.write("Executing raids event...\n")
+ if running then
+ return
+ end
+
+ local now = os.mtime()
+
+ local raids = Raid.getRaids()
+ for key, raid in pairs(raids) do
+ local chance = (MAX_RAND_RANGE * CHECK_RAIDS_INTERVAL) / raid.interval
+ if now >= lastRaidEnd + raid.margin and chance >= math.random(0, MAX_RAND_RANGE) then
+ running = key
+
+ io.write("Executing raid: " .. raid.name .. "\n")
+ raid:execute()
+
+ if not raid.repeats then
+ raids[key] = nil
+ end
+ break
+ end
+ end
+end
+
+event:register()
diff --git a/data/scripts/globalevents/raids_xml.lua b/data/scripts/globalevents/raids_xml.lua
new file mode 100644
index 0000000000..63c721e820
--- /dev/null
+++ b/data/scripts/globalevents/raids_xml.lua
@@ -0,0 +1,240 @@
+-- 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 event = GlobalEvent("load raids.xml")
+
+function event.onStartup()
+ local doc = XMLDocument("data/raids/raids.xml")
+ 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
+
+event:register()
diff --git a/data/scripts/talkactions/force_event.lua b/data/scripts/talkactions/force_event.lua
new file mode 100644
index 0000000000..e9f9e68000
--- /dev/null
+++ b/data/scripts/talkactions/force_event.lua
@@ -0,0 +1,25 @@
+local talk = TalkAction("/event", "!event")
+
+function talk.onSay(player, words, param)
+ if not player:getGroup():getAccess() then
+ return true
+ end
+
+ if player:getAccountType() < ACCOUNT_TYPE_GAMEMASTER then
+ return false
+ end
+
+ logCommand(player, words, param)
+
+ local returnValue = Game.startEvent(param)
+ if returnValue == nil then
+ player:sendTextMessage(MESSAGE_INFO_DESCR, "No such event exists.")
+ return false
+ end
+
+ player:sendTextMessage(MESSAGE_INFO_DESCR, "Event started.")
+ return returnValue
+end
+
+talk:separator(" ")
+talk:register()
diff --git a/data/talkactions/scripts/force_raid.lua b/data/talkactions/scripts/force_raid.lua
deleted file mode 100644
index 99dd2e9a4f..0000000000
--- a/data/talkactions/scripts/force_raid.lua
+++ /dev/null
@@ -1,20 +0,0 @@
-function onSay(player, words, param)
- if not player:getGroup():getAccess() then
- return true
- end
-
- if player:getAccountType() < ACCOUNT_TYPE_GAMEMASTER then
- return false
- end
-
- logCommand(player, words, param)
-
- local returnValue = Game.startRaid(param)
- if returnValue ~= RETURNVALUE_NOERROR then
- player:sendTextMessage(MESSAGE_INFO_DESCR, Game.getReturnMessage(returnValue))
- else
- player:sendTextMessage(MESSAGE_INFO_DESCR, "Raid started.")
- end
-
- return false
-end
diff --git a/data/talkactions/scripts/reload.lua b/data/talkactions/scripts/reload.lua
index b98c08902c..2ba4e88cd3 100644
--- a/data/talkactions/scripts/reload.lua
+++ b/data/talkactions/scripts/reload.lua
@@ -39,9 +39,6 @@ local reloadTypes = {
["quest"] = RELOAD_TYPE_QUESTS,
["quests"] = RELOAD_TYPE_QUESTS,
- ["raid"] = RELOAD_TYPE_RAIDS,
- ["raids"] = RELOAD_TYPE_RAIDS,
-
["spell"] = RELOAD_TYPE_SPELLS,
["spells"] = RELOAD_TYPE_SPELLS,
diff --git a/data/talkactions/talkactions.xml b/data/talkactions/talkactions.xml
index 11469b48d4..b3990d6636 100644
--- a/data/talkactions/talkactions.xml
+++ b/data/talkactions/talkactions.xml
@@ -33,7 +33,6 @@
-
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index e650b94b60..c24ab40b05 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -55,7 +55,6 @@ set(tfs_SRC
${CMAKE_CURRENT_LIST_DIR}/protocollogin.cpp
${CMAKE_CURRENT_LIST_DIR}/protocolold.cpp
${CMAKE_CURRENT_LIST_DIR}/protocolstatus.cpp
- ${CMAKE_CURRENT_LIST_DIR}/raids.cpp
${CMAKE_CURRENT_LIST_DIR}/rsa.cpp
${CMAKE_CURRENT_LIST_DIR}/scheduler.cpp
${CMAKE_CURRENT_LIST_DIR}/script.cpp
@@ -143,7 +142,6 @@ set(tfs_HDR
${CMAKE_CURRENT_LIST_DIR}/protocolold.h
${CMAKE_CURRENT_LIST_DIR}/protocolstatus.h
${CMAKE_CURRENT_LIST_DIR}/pugicast.h
- ${CMAKE_CURRENT_LIST_DIR}/raids.h
${CMAKE_CURRENT_LIST_DIR}/rsa.h
${CMAKE_CURRENT_LIST_DIR}/scheduler.h
${CMAKE_CURRENT_LIST_DIR}/script.h
diff --git a/src/const.h b/src/const.h
index 56484b1949..058da2a083 100644
--- a/src/const.h
+++ b/src/const.h
@@ -677,7 +677,6 @@ enum ReloadTypes_t : uint8_t
RELOAD_TYPE_MOVEMENTS,
RELOAD_TYPE_NPCS,
RELOAD_TYPE_QUESTS,
- RELOAD_TYPE_RAIDS,
RELOAD_TYPE_SCRIPTS,
RELOAD_TYPE_SPELLS,
RELOAD_TYPE_TALKACTIONS,
diff --git a/src/enums.h b/src/enums.h
index 3a05d77553..64606fb708 100644
--- a/src/enums.h
+++ b/src/enums.h
@@ -479,8 +479,6 @@ enum ReturnValue
RETURNVALUE_CANONLYUSEONESHIELD,
RETURNVALUE_NOPARTYMEMBERSINRANGE,
RETURNVALUE_YOUARENOTTHEOWNER,
- RETURNVALUE_NOSUCHRAIDEXISTS,
- RETURNVALUE_ANOTHERRAIDISALREADYEXECUTING,
RETURNVALUE_TRADEPLAYERFARAWAY,
RETURNVALUE_YOUDONTOWNTHISHOUSE,
RETURNVALUE_TRADEPLAYERALREADYOWNSAHOUSE,
diff --git a/src/game.cpp b/src/game.cpp
index 0700aa8850..ca2635a9f5 100644
--- a/src/game.cpp
+++ b/src/game.cpp
@@ -99,9 +99,6 @@ void Game::setGameState(GameState_t newState)
map.spawns.startup();
- raids.loadFromXml();
- raids.startup();
-
mounts.loadFromXml();
loadPlayersRecord();
@@ -4882,7 +4879,6 @@ void Game::shutdown()
g_databaseTasks.shutdown();
g_dispatcher.shutdown();
map.spawns.clear();
- raids.clear();
cleanup();
@@ -5931,9 +5927,6 @@ bool Game::reload(ReloadTypes_t reloadType)
return true;
}
- case RELOAD_TYPE_RAIDS:
- return raids.reload() && raids.startup();
-
case RELOAD_TYPE_SPELLS: {
if (!g_spells->reload()) {
std::cout << "[Error - Game::reload] Failed to reload spells." << std::endl;
@@ -5968,7 +5961,6 @@ bool Game::reload(ReloadTypes_t reloadType)
g_creatureEvents->removeInvalidEvents();
/*
Npcs::reload();
- raids.reload() && raids.startup();
Item::items.reload();
mounts.reload();
g_config.reload();
@@ -5993,7 +5985,6 @@ bool Game::reload(ReloadTypes_t reloadType)
g_monsters.reload();
g_moveEvents->reload();
Npcs::reload();
- raids.reload() && raids.startup();
g_talkActions->reload();
Item::items.reload();
g_weapons->reload();
diff --git a/src/game.h b/src/game.h
index 3eaab7e2f9..2a3d011ff9 100644
--- a/src/game.h
+++ b/src/game.h
@@ -9,7 +9,6 @@
#include "mounts.h"
#include "player.h"
#include "position.h"
-#include "raids.h"
#include "wildcardtree.h"
class Monster;
@@ -494,7 +493,6 @@ class Game
Groups groups;
Map map;
Mounts mounts;
- Raids raids;
std::forward_list- toDecayItems;
diff --git a/src/globalevent.cpp b/src/globalevent.cpp
index da28c3ac43..a164cb3804 100644
--- a/src/globalevent.cpp
+++ b/src/globalevent.cpp
@@ -117,7 +117,7 @@ void GlobalEvents::save() const { execute(GLOBALEVENT_SAVE); }
void GlobalEvents::timer()
{
- time_t now = time(nullptr);
+ auto now = OTSYS_TIME();
int64_t nextScheduledTime = std::numeric_limits::max();
@@ -140,7 +140,7 @@ void GlobalEvents::timer()
continue;
}
- nextExecutionTime = 86400;
+ nextExecutionTime = 86400000;
if (nextExecutionTime < nextScheduledTime) {
nextScheduledTime = nextExecutionTime;
}
@@ -152,7 +152,7 @@ void GlobalEvents::timer()
if (nextScheduledTime != std::numeric_limits::max()) {
timerEventId = g_scheduler.addEvent(
- createSchedulerTask(std::max(1000, nextScheduledTime * 1000), [this]() { timer(); }));
+ createSchedulerTask(std::max(1000, nextScheduledTime), [this]() { timer(); }));
}
}
@@ -282,7 +282,7 @@ bool GlobalEvent::configureEvent(const pugi::xml_node& node)
difference += 86400;
}
- nextExecution = current_time + difference;
+ nextExecution = (current_time + difference) * 1000;
eventType = GLOBALEVENT_TIMER;
} else if ((attr = node.attribute("type"))) {
const char* value = attr.value();
diff --git a/src/luascript.cpp b/src/luascript.cpp
index bdeaf88854..ed0bb6c8d5 100644
--- a/src/luascript.cpp
+++ b/src/luascript.cpp
@@ -41,6 +41,7 @@
extern Chat* g_chat;
extern Game g_game;
+extern GlobalEvents* g_globalEvents;
extern Monsters g_monsters;
extern ConfigManager g_config;
extern Vocations g_vocations;
@@ -2072,7 +2073,6 @@ void LuaScriptInterface::registerFunctions()
registerEnum(RELOAD_TYPE_MOVEMENTS);
registerEnum(RELOAD_TYPE_NPCS);
registerEnum(RELOAD_TYPE_QUESTS);
- registerEnum(RELOAD_TYPE_RAIDS);
registerEnum(RELOAD_TYPE_SCRIPTS);
registerEnum(RELOAD_TYPE_SPELLS);
registerEnum(RELOAD_TYPE_TALKACTIONS);
@@ -2262,7 +2262,7 @@ void LuaScriptInterface::registerFunctions()
registerMethod("Game", "createTile", LuaScriptInterface::luaGameCreateTile);
registerMethod("Game", "createMonsterType", LuaScriptInterface::luaGameCreateMonsterType);
- registerMethod("Game", "startRaid", LuaScriptInterface::luaGameStartRaid);
+ registerMethod("Game", "startEvent", LuaScriptInterface::luaGameStartEvent);
registerMethod("Game", "getClientVersion", LuaScriptInterface::luaGameGetClientVersion);
@@ -5050,25 +5050,17 @@ int LuaScriptInterface::luaGameCreateMonsterType(lua_State* L)
return 1;
}
-int LuaScriptInterface::luaGameStartRaid(lua_State* L)
+int LuaScriptInterface::luaGameStartEvent(lua_State* L)
{
- // Game.startRaid(raidName)
- const std::string& raidName = getString(L, 1);
+ // Game.startEvent(event)
+ const std::string& eventName = getString(L, 1);
- Raid* raid = g_game.raids.getRaidByName(raidName);
- if (!raid || !raid->isLoaded()) {
- lua_pushnumber(L, RETURNVALUE_NOSUCHRAIDEXISTS);
- return 1;
- }
-
- if (g_game.raids.getRunning()) {
- lua_pushnumber(L, RETURNVALUE_ANOTHERRAIDISALREADYEXECUTING);
- return 1;
+ const auto& eventMap = g_globalEvents->getEventMap(GLOBALEVENT_TIMER);
+ if (auto it = eventMap.find(eventName); it != eventMap.end()) {
+ pushBoolean(L, it->second.executeEvent());
+ } else {
+ lua_pushnil(L);
}
-
- g_game.raids.setRunning(raid);
- raid->startRaid();
- lua_pushnumber(L, RETURNVALUE_NOERROR);
return 1;
}
@@ -17504,6 +17496,8 @@ int LuaScriptInterface::luaGlobalEventType(lua_State* L)
global->setEventType(GLOBALEVENT_SHUTDOWN);
} else if (tmpStr == "record") {
global->setEventType(GLOBALEVENT_RECORD);
+ } else if (tmpStr == "timer") {
+ global->setEventType(GLOBALEVENT_TIMER);
} else if (tmpStr == "save") {
global->setEventType(GLOBALEVENT_SAVE);
} else {
diff --git a/src/luascript.h b/src/luascript.h
index 205c8d69dd..f2637a590d 100644
--- a/src/luascript.h
+++ b/src/luascript.h
@@ -551,7 +551,7 @@ class LuaScriptInterface
static int luaGameCreateTile(lua_State* L);
static int luaGameCreateMonsterType(lua_State* L);
- static int luaGameStartRaid(lua_State* L);
+ static int luaGameStartEvent(lua_State* L);
static int luaGameGetClientVersion(lua_State* L);
diff --git a/src/raids.cpp b/src/raids.cpp
deleted file mode 100644
index 053f40af30..0000000000
--- a/src/raids.cpp
+++ /dev/null
@@ -1,572 +0,0 @@
-// Copyright 2023 The Forgotten Server Authors. All rights reserved.
-// Use of this source code is governed by the GPL-2.0 License that can be found in the LICENSE file.
-
-#include "otpch.h"
-
-#include "raids.h"
-
-#include "configmanager.h"
-#include "game.h"
-#include "monster.h"
-#include "pugicast.h"
-#include "scheduler.h"
-
-extern Game g_game;
-extern ConfigManager g_config;
-
-Raids::Raids() { scriptInterface.initState(); }
-
-Raids::~Raids()
-{
- for (Raid* raid : raidList) {
- delete raid;
- }
-}
-
-bool Raids::loadFromXml()
-{
- if (isLoaded()) {
- return true;
- }
-
- pugi::xml_document doc;
- pugi::xml_parse_result result = doc.load_file("data/raids/raids.xml");
- if (!result) {
- printXMLError("Error - Raids::loadFromXml", "data/raids/raids.xml", result);
- return false;
- }
-
- for (auto raidNode : doc.child("raids").children()) {
- std::string name, file;
- uint32_t interval, margin;
-
- pugi::xml_attribute attr;
- if ((attr = raidNode.attribute("name"))) {
- name = attr.as_string();
- } else {
- std::cout << "[Error - Raids::loadFromXml] Name tag missing for raid" << std::endl;
- continue;
- }
-
- if ((attr = raidNode.attribute("file"))) {
- file = attr.as_string();
- } else {
- file = fmt::format("raids/{:s}.xml", name);
- std::cout << "[Warning - Raids::loadFromXml] File tag missing for raid " << name
- << ". Using default: " << file << std::endl;
- }
-
- interval = pugi::cast(raidNode.attribute("interval2").value()) * 60;
- if (interval == 0) {
- std::cout << "[Error - Raids::loadFromXml] interval2 tag missing or zero (would divide by 0) for raid: "
- << name << std::endl;
- continue;
- }
-
- if ((attr = raidNode.attribute("margin"))) {
- margin = pugi::cast(attr.value()) * 60 * 1000;
- } else {
- std::cout << "[Warning - Raids::loadFromXml] margin tag missing for raid: " << name << std::endl;
- margin = 0;
- }
-
- bool repeat;
- if ((attr = raidNode.attribute("repeat"))) {
- repeat = booleanString(attr.as_string());
- } else {
- repeat = false;
- }
-
- Raid* newRaid = new Raid(name, interval, margin, repeat);
- if (newRaid->loadFromXml("data/raids/" + file)) {
- raidList.push_back(newRaid);
- } else {
- std::cout << "[Error - Raids::loadFromXml] Failed to load raid: " << name << std::endl;
- delete newRaid;
- }
- }
-
- loaded = true;
- return true;
-}
-
-static constexpr int32_t MAX_RAND_RANGE = 10000000;
-
-bool Raids::startup()
-{
- if (!isLoaded() || isStarted()) {
- return false;
- }
-
- setLastRaidEnd(OTSYS_TIME());
-
- checkRaidsEvent =
- g_scheduler.addEvent(createSchedulerTask(CHECK_RAIDS_INTERVAL * 1000, [this]() { checkRaids(); }));
-
- started = true;
- return started;
-}
-
-void Raids::checkRaids()
-{
- if (!getRunning()) {
- uint64_t now = OTSYS_TIME();
-
- for (auto it = raidList.begin(), end = raidList.end(); it != end; ++it) {
- Raid* raid = *it;
- if (now >= (getLastRaidEnd() + raid->getMargin())) {
- if (((MAX_RAND_RANGE * CHECK_RAIDS_INTERVAL) / raid->getInterval()) >=
- static_cast(uniform_random(0, MAX_RAND_RANGE))) {
- setRunning(raid);
- raid->startRaid();
-
- if (!raid->canBeRepeated()) {
- raidList.erase(it);
- }
- break;
- }
- }
- }
- }
-
- checkRaidsEvent =
- g_scheduler.addEvent(createSchedulerTask(CHECK_RAIDS_INTERVAL * 1000, [this]() { checkRaids(); }));
-}
-
-void Raids::clear()
-{
- g_scheduler.stopEvent(checkRaidsEvent);
- checkRaidsEvent = 0;
-
- for (Raid* raid : raidList) {
- raid->stopEvents();
- delete raid;
- }
- raidList.clear();
-
- loaded = false;
- started = false;
- running = nullptr;
- lastRaidEnd = 0;
-
- scriptInterface.reInitState();
-}
-
-bool Raids::reload()
-{
- clear();
- return loadFromXml();
-}
-
-Raid* Raids::getRaidByName(const std::string& name)
-{
- for (Raid* raid : raidList) {
- if (caseInsensitiveEqual(raid->getName(), name)) {
- return raid;
- }
- }
- return nullptr;
-}
-
-Raid::~Raid()
-{
- for (RaidEvent* raidEvent : raidEvents) {
- delete raidEvent;
- }
-}
-
-bool Raid::loadFromXml(const std::string& filename)
-{
- if (isLoaded()) {
- return true;
- }
-
- pugi::xml_document doc;
- pugi::xml_parse_result result = doc.load_file(filename.c_str());
- if (!result) {
- printXMLError("Error - Raid::loadFromXml", filename, result);
- return false;
- }
-
- for (auto eventNode : doc.child("raid").children()) {
- RaidEvent* event;
- if (caseInsensitiveEqual(eventNode.name(), "announce")) {
- event = new AnnounceEvent();
- } else if (caseInsensitiveEqual(eventNode.name(), "singlespawn")) {
- event = new SingleSpawnEvent();
- } else if (caseInsensitiveEqual(eventNode.name(), "areaspawn")) {
- event = new AreaSpawnEvent();
- } else if (caseInsensitiveEqual(eventNode.name(), "script")) {
- event = new ScriptEvent(&g_game.raids.getScriptInterface());
- } else {
- continue;
- }
-
- if (event->configureRaidEvent(eventNode)) {
- raidEvents.push_back(event);
- } else {
- std::cout << "[Error - Raid::loadFromXml] In file (" << filename << "), eventNode: " << eventNode.name()
- << std::endl;
- delete event;
- }
- }
-
- // sort by delay time
- std::sort(raidEvents.begin(), raidEvents.end(),
- [](const RaidEvent* lhs, const RaidEvent* rhs) { return lhs->getDelay() < rhs->getDelay(); });
-
- loaded = true;
- return true;
-}
-
-void Raid::startRaid()
-{
- RaidEvent* raidEvent = getNextRaidEvent();
- if (raidEvent) {
- state = RAIDSTATE_EXECUTING;
- nextEventEvent = g_scheduler.addEvent(
- createSchedulerTask(raidEvent->getDelay(), [=, this]() { executeRaidEvent(raidEvent); }));
- }
-}
-
-void Raid::executeRaidEvent(RaidEvent* raidEvent)
-{
- if (raidEvent->executeEvent()) {
- nextEvent++;
- RaidEvent* newRaidEvent = getNextRaidEvent();
-
- if (newRaidEvent) {
- uint32_t ticks = static_cast(
- std::max(RAID_MINTICKS, newRaidEvent->getDelay() - raidEvent->getDelay()));
- nextEventEvent =
- g_scheduler.addEvent(createSchedulerTask(ticks, [=, this]() { executeRaidEvent(newRaidEvent); }));
- } else {
- resetRaid();
- }
- } else {
- resetRaid();
- }
-}
-
-void Raid::resetRaid()
-{
- nextEvent = 0;
- state = RAIDSTATE_IDLE;
- g_game.raids.setRunning(nullptr);
- g_game.raids.setLastRaidEnd(OTSYS_TIME());
-}
-
-void Raid::stopEvents()
-{
- if (nextEventEvent != 0) {
- g_scheduler.stopEvent(nextEventEvent);
- nextEventEvent = 0;
- }
-}
-
-RaidEvent* Raid::getNextRaidEvent()
-{
- if (nextEvent < raidEvents.size()) {
- return raidEvents[nextEvent];
- }
- return nullptr;
-}
-
-bool RaidEvent::configureRaidEvent(const pugi::xml_node& eventNode)
-{
- pugi::xml_attribute delayAttribute = eventNode.attribute("delay");
- if (!delayAttribute) {
- std::cout << "[Error] Raid: delay tag missing." << std::endl;
- return false;
- }
-
- delay = std::max(RAID_MINTICKS, pugi::cast(delayAttribute.value()));
- return true;
-}
-
-bool AnnounceEvent::configureRaidEvent(const pugi::xml_node& eventNode)
-{
- if (!RaidEvent::configureRaidEvent(eventNode)) {
- return false;
- }
-
- pugi::xml_attribute messageAttribute = eventNode.attribute("message");
- if (!messageAttribute) {
- std::cout << "[Error] Raid: message tag missing for announce event." << std::endl;
- return false;
- }
- message = messageAttribute.as_string();
-
- pugi::xml_attribute typeAttribute = eventNode.attribute("type");
- if (typeAttribute) {
- std::string tmpStrValue = boost::algorithm::to_lower_copy(typeAttribute.as_string());
- if (tmpStrValue == "warning") {
- messageType = MESSAGE_STATUS_WARNING;
- } else if (tmpStrValue == "event") {
- messageType = MESSAGE_EVENT_ADVANCE;
- } else if (tmpStrValue == "default") {
- messageType = MESSAGE_EVENT_DEFAULT;
- } else if (tmpStrValue == "description") {
- messageType = MESSAGE_INFO_DESCR;
- } else if (tmpStrValue == "smallstatus") {
- messageType = MESSAGE_STATUS_SMALL;
- } else if (tmpStrValue == "blueconsole" || tmpStrValue == "redconsole") {
- std::cout << "[Notice] Raid: Deprecated type tag for announce event. Using default: "
- << static_cast(messageType) << std::endl;
- } else {
- std::cout << "[Notice] Raid: Unknown type tag missing for announce event. Using default: "
- << static_cast(messageType) << std::endl;
- }
- } else {
- messageType = MESSAGE_EVENT_ADVANCE;
- std::cout << "[Notice] Raid: type tag missing for announce event. Using default: "
- << static_cast(messageType) << std::endl;
- }
- return true;
-}
-
-bool AnnounceEvent::executeEvent()
-{
- g_game.broadcastMessage(message, messageType);
- return true;
-}
-
-bool SingleSpawnEvent::configureRaidEvent(const pugi::xml_node& eventNode)
-{
- if (!RaidEvent::configureRaidEvent(eventNode)) {
- return false;
- }
-
- pugi::xml_attribute attr;
- if ((attr = eventNode.attribute("name"))) {
- monsterName = attr.as_string();
- } else {
- std::cout << "[Error] Raid: name tag missing for singlespawn event." << std::endl;
- return false;
- }
-
- if ((attr = eventNode.attribute("x"))) {
- position.x = pugi::cast(attr.value());
- } else {
- std::cout << "[Error] Raid: x tag missing for singlespawn event." << std::endl;
- return false;
- }
-
- if ((attr = eventNode.attribute("y"))) {
- position.y = pugi::cast(attr.value());
- } else {
- std::cout << "[Error] Raid: y tag missing for singlespawn event." << std::endl;
- return false;
- }
-
- if ((attr = eventNode.attribute("z"))) {
- position.z = pugi::cast(attr.value());
- } else {
- std::cout << "[Error] Raid: z tag missing for singlespawn event." << std::endl;
- return false;
- }
- return true;
-}
-
-bool SingleSpawnEvent::executeEvent()
-{
- Monster* monster = Monster::createMonster(monsterName);
- if (!monster) {
- std::cout << "[Error] Raids: Cant create monster " << monsterName << std::endl;
- return false;
- }
-
- if (!g_game.placeCreature(monster, position, false, true)) {
- delete monster;
- std::cout << "[Error] Raids: Cant place monster " << monsterName << std::endl;
- return false;
- }
- return true;
-}
-
-bool AreaSpawnEvent::configureRaidEvent(const pugi::xml_node& eventNode)
-{
- if (!RaidEvent::configureRaidEvent(eventNode)) {
- return false;
- }
-
- pugi::xml_attribute attr;
- if ((attr = eventNode.attribute("radius"))) {
- int32_t radius = pugi::cast(attr.value());
- Position centerPos;
-
- if ((attr = eventNode.attribute("centerx"))) {
- centerPos.x = pugi::cast(attr.value());
- } else {
- std::cout << "[Error] Raid: centerx tag missing for areaspawn event." << std::endl;
- return false;
- }
-
- if ((attr = eventNode.attribute("centery"))) {
- centerPos.y = pugi::cast(attr.value());
- } else {
- std::cout << "[Error] Raid: centery tag missing for areaspawn event." << std::endl;
- return false;
- }
-
- if ((attr = eventNode.attribute("centerz"))) {
- centerPos.z = pugi::cast(attr.value());
- } else {
- std::cout << "[Error] Raid: centerz tag missing for areaspawn event." << std::endl;
- return false;
- }
-
- fromPos.x = std::max(0, centerPos.getX() - radius);
- fromPos.y = std::max(0, centerPos.getY() - radius);
- fromPos.z = centerPos.z;
-
- toPos.x = std::min(0xFFFF, centerPos.getX() + radius);
- toPos.y = std::min(0xFFFF, centerPos.getY() + radius);
- toPos.z = centerPos.z;
- } else {
- if ((attr = eventNode.attribute("fromx"))) {
- fromPos.x = pugi::cast(attr.value());
- } else {
- std::cout << "[Error] Raid: fromx tag missing for areaspawn event." << std::endl;
- return false;
- }
-
- if ((attr = eventNode.attribute("fromy"))) {
- fromPos.y = pugi::cast(attr.value());
- } else {
- std::cout << "[Error] Raid: fromy tag missing for areaspawn event." << std::endl;
- return false;
- }
-
- if ((attr = eventNode.attribute("fromz"))) {
- fromPos.z = pugi::cast(attr.value());
- } else {
- std::cout << "[Error] Raid: fromz tag missing for areaspawn event." << std::endl;
- return false;
- }
-
- if ((attr = eventNode.attribute("tox"))) {
- toPos.x = pugi::cast(attr.value());
- } else {
- std::cout << "[Error] Raid: tox tag missing for areaspawn event." << std::endl;
- return false;
- }
-
- if ((attr = eventNode.attribute("toy"))) {
- toPos.y = pugi::cast(attr.value());
- } else {
- std::cout << "[Error] Raid: toy tag missing for areaspawn event." << std::endl;
- return false;
- }
-
- if ((attr = eventNode.attribute("toz"))) {
- toPos.z = pugi::cast(attr.value());
- } else {
- std::cout << "[Error] Raid: toz tag missing for areaspawn event." << std::endl;
- return false;
- }
- }
-
- for (auto monsterNode : eventNode.children()) {
- const char* name;
-
- if ((attr = monsterNode.attribute("name"))) {
- name = attr.value();
- } else {
- std::cout << "[Error] Raid: name tag missing for monster node." << std::endl;
- return false;
- }
-
- uint32_t minAmount;
- if ((attr = monsterNode.attribute("minamount"))) {
- minAmount = pugi::cast(attr.value());
- } else {
- minAmount = 0;
- }
-
- uint32_t maxAmount;
- if ((attr = monsterNode.attribute("maxamount"))) {
- maxAmount = pugi::cast(attr.value());
- } else {
- maxAmount = 0;
- }
-
- if (maxAmount == 0 && minAmount == 0) {
- if ((attr = monsterNode.attribute("amount"))) {
- minAmount = pugi::cast(attr.value());
- maxAmount = minAmount;
- } else {
- std::cout << "[Error] Raid: amount tag missing for monster node." << std::endl;
- return false;
- }
- }
-
- spawnList.emplace_back(name, minAmount, maxAmount);
- }
- return true;
-}
-
-bool AreaSpawnEvent::executeEvent()
-{
- for (const MonsterSpawn& spawn : spawnList) {
- uint32_t amount = uniform_random(spawn.minAmount, spawn.maxAmount);
- for (uint32_t i = 0; i < amount; ++i) {
- Monster* monster = Monster::createMonster(spawn.name);
- if (!monster) {
- std::cout << "[Error - AreaSpawnEvent::executeEvent] Can't create monster " << spawn.name << std::endl;
- return false;
- }
-
- bool success = false;
- for (int32_t tries = 0; tries < MAXIMUM_TRIES_PER_MONSTER; tries++) {
- Tile* tile = g_game.map.getTile(uniform_random(fromPos.x, toPos.x), uniform_random(fromPos.y, toPos.y),
- uniform_random(fromPos.z, toPos.z));
- if (tile && !tile->isMoveableBlocking() && !tile->hasFlag(TILESTATE_PROTECTIONZONE) &&
- !tile->getTopCreature() && g_game.placeCreature(monster, tile->getPosition(), false, true)) {
- success = true;
- break;
- }
- }
-
- if (!success) {
- delete monster;
- }
- }
- }
- return true;
-}
-
-bool ScriptEvent::configureRaidEvent(const pugi::xml_node& eventNode)
-{
- if (!RaidEvent::configureRaidEvent(eventNode)) {
- return false;
- }
-
- pugi::xml_attribute scriptAttribute = eventNode.attribute("script");
- if (!scriptAttribute) {
- std::cout << "Error: [ScriptEvent::configureRaidEvent] No script file found for raid" << std::endl;
- return false;
- }
-
- if (!loadScript("data/raids/scripts/" + std::string(scriptAttribute.as_string()))) {
- std::cout << "Error: [ScriptEvent::configureRaidEvent] Can not load raid script." << std::endl;
- return false;
- }
- return true;
-}
-
-bool ScriptEvent::executeEvent()
-{
- // onRaid()
- if (!scriptInterface->reserveScriptEnv()) {
- std::cout << "[Error - ScriptEvent::onRaid] Call stack overflow" << std::endl;
- return false;
- }
-
- ScriptEnvironment* env = scriptInterface->getScriptEnv();
- env->setScriptId(scriptId, scriptInterface);
-
- scriptInterface->pushFunction(scriptId);
-
- return scriptInterface->callFunction(0);
-}
diff --git a/src/raids.h b/src/raids.h
deleted file mode 100644
index d09a3b597d..0000000000
--- a/src/raids.h
+++ /dev/null
@@ -1,188 +0,0 @@
-// Copyright 2023 The Forgotten Server Authors. All rights reserved.
-// Use of this source code is governed by the GPL-2.0 License that can be found in the LICENSE file.
-
-#ifndef FS_RAIDS_H
-#define FS_RAIDS_H
-
-#include "baseevents.h"
-#include "const.h"
-#include "luascript.h"
-#include "position.h"
-
-enum RaidState_t
-{
- RAIDSTATE_IDLE,
- RAIDSTATE_EXECUTING,
-};
-
-struct MonsterSpawn
-{
- MonsterSpawn(std::string name, uint32_t minAmount, uint32_t maxAmount) :
- name(std::move(name)), minAmount(minAmount), maxAmount(maxAmount)
- {}
-
- std::string name;
- uint32_t minAmount;
- uint32_t maxAmount;
-};
-
-// How many times it will try to find a tile to add the monster to before giving
-// up
-static constexpr int32_t MAXIMUM_TRIES_PER_MONSTER = 10;
-static constexpr int32_t CHECK_RAIDS_INTERVAL = 60;
-static constexpr int32_t RAID_MINTICKS = 1000;
-
-class Raid;
-class RaidEvent;
-
-class Raids
-{
-public:
- Raids();
- ~Raids();
-
- // non-copyable
- Raids(const Raids&) = delete;
- Raids& operator=(const Raids&) = delete;
-
- bool loadFromXml();
- bool startup();
-
- void clear();
- bool reload();
-
- bool isLoaded() const { return loaded; }
- bool isStarted() const { return started; }
-
- Raid* getRunning() { return running; }
- void setRunning(Raid* newRunning) { running = newRunning; }
-
- Raid* getRaidByName(const std::string& name);
-
- uint64_t getLastRaidEnd() const { return lastRaidEnd; }
- void setLastRaidEnd(uint64_t newLastRaidEnd) { lastRaidEnd = newLastRaidEnd; }
-
- void checkRaids();
-
- LuaScriptInterface& getScriptInterface() { return scriptInterface; }
-
-private:
- LuaScriptInterface scriptInterface{"Raid Interface"};
-
- std::list raidList;
- Raid* running = nullptr;
- uint64_t lastRaidEnd = 0;
- uint32_t checkRaidsEvent = 0;
- bool loaded = false;
- bool started = false;
-};
-
-class Raid
-{
-public:
- Raid(std::string name, uint32_t interval, uint32_t marginTime, bool repeat) :
- name(std::move(name)), interval(interval), margin(marginTime), repeat(repeat)
- {}
- ~Raid();
-
- // non-copyable
- Raid(const Raid&) = delete;
- Raid& operator=(const Raid&) = delete;
-
- bool loadFromXml(const std::string& filename);
-
- void startRaid();
-
- void executeRaidEvent(RaidEvent* raidEvent);
- void resetRaid();
-
- RaidEvent* getNextRaidEvent();
- void setState(RaidState_t newState) { state = newState; }
- const std::string& getName() const { return name; }
-
- bool isLoaded() const { return loaded; }
- uint64_t getMargin() const { return margin; }
- uint32_t getInterval() const { return interval; }
- bool canBeRepeated() const { return repeat; }
-
- void stopEvents();
-
-private:
- std::vector raidEvents;
- std::string name;
- uint32_t interval;
- uint32_t nextEvent = 0;
- uint64_t margin;
- RaidState_t state = RAIDSTATE_IDLE;
- uint32_t nextEventEvent = 0;
- bool loaded = false;
- bool repeat;
-};
-
-class RaidEvent
-{
-public:
- virtual ~RaidEvent() = default;
-
- virtual bool configureRaidEvent(const pugi::xml_node& eventNode);
-
- virtual bool executeEvent() = 0;
- uint32_t getDelay() const { return delay; }
-
-private:
- uint32_t delay;
-};
-
-class AnnounceEvent final : public RaidEvent
-{
-public:
- AnnounceEvent() = default;
-
- bool configureRaidEvent(const pugi::xml_node& eventNode) override;
-
- bool executeEvent() override;
-
-private:
- std::string message;
- MessageClasses messageType = MESSAGE_EVENT_ADVANCE;
-};
-
-class SingleSpawnEvent final : public RaidEvent
-{
-public:
- bool configureRaidEvent(const pugi::xml_node& eventNode) override;
-
- bool executeEvent() override;
-
-private:
- std::string monsterName;
- Position position;
-};
-
-class AreaSpawnEvent final : public RaidEvent
-{
-public:
- bool configureRaidEvent(const pugi::xml_node& eventNode) override;
-
- bool executeEvent() override;
-
-private:
- std::list spawnList;
- Position fromPos, toPos;
-};
-
-class ScriptEvent final : public RaidEvent, public Event
-{
-public:
- explicit ScriptEvent(LuaScriptInterface* interface) : Event(interface) {}
-
- bool configureRaidEvent(const pugi::xml_node& eventNode) override;
- bool configureEvent(const pugi::xml_node&) override { return false; }
-
- bool executeEvent() override;
-
-private:
- std::string_view getScriptEventName() const override { return "onRaid"; }
-};
-
-#endif // FS_RAIDS_H
diff --git a/src/signals.cpp b/src/signals.cpp
index 3b8fd6d846..0f1bdabc65 100644
--- a/src/signals.cpp
+++ b/src/signals.cpp
@@ -15,7 +15,6 @@
#include "mounts.h"
#include "movement.h"
#include "npc.h"
-#include "raids.h"
#include "scheduler.h"
#include "spells.h"
#include "talkaction.h"
@@ -73,10 +72,6 @@ void sighupHandler()
Npcs::reload();
std::cout << "Reloaded npcs." << std::endl;
- g_game.raids.reload();
- g_game.raids.startup();
- std::cout << "Reloaded raids." << std::endl;
-
g_monsters.reload();
std::cout << "Reloaded monsters." << std::endl;
diff --git a/src/tools.cpp b/src/tools.cpp
index a047b690ba..3b5d506dce 100644
--- a/src/tools.cpp
+++ b/src/tools.cpp
@@ -1156,12 +1156,6 @@ const char* getReturnMessage(ReturnValue value)
case RETURNVALUE_YOUARENOTTHEOWNER:
return "You are not the owner.";
- case RETURNVALUE_NOSUCHRAIDEXISTS:
- return "No such raid exists.";
-
- case RETURNVALUE_ANOTHERRAIDISALREADYEXECUTING:
- return "Another raid is already executing.";
-
case RETURNVALUE_TRADEPLAYERFARAWAY:
return "Trade player is too far away.";
diff --git a/vc17/theforgottenserver.vcxproj b/vc17/theforgottenserver.vcxproj
index e358a52a6b..d2765ce3d7 100644
--- a/vc17/theforgottenserver.vcxproj
+++ b/vc17/theforgottenserver.vcxproj
@@ -222,7 +222,6 @@
-
@@ -307,7 +306,6 @@
-