From 526ef51758f65d4db995c51b82bd2e760f43e4c1 Mon Sep 17 00:00:00 2001
From: Beats <61994374+beats-dh@users.noreply.github.com>
Date: Fri, 27 May 2022 15:56:22 -0300
Subject: [PATCH] Fix Event Scheduler (#239)
This works directly with: https://github.com/opentibiabr/otservbr-global/pull/471
---
config.lua.dist | 9 +-
data/XML/events.xml | 4 +-
data/events/scripts/player.lua | 101 +++++++++++++---
data/global.lua | 18 +--
data/lib/core/functions/functions.lua | 11 +-
data/lib/core/storages.lua | 1 +
.../scripts/daily_reward/daily_reward.lua | 30 ++---
data/scripts/creaturescripts/advance_save.lua | 39 ++++++
data/scripts/creaturescripts/login.lua | 60 ++++++++++
data/scripts/globalevents/startup.lua | 31 +++++
data/scripts/talkactions/god/reload.lua | 7 +-
.../talkactions/player/server_info.lua | 2 +-
src/CMakeLists.txt | 2 +
src/config/config_definitions.hpp | 1 +
src/config/configmanager.cpp | 9 +-
.../monsters/spawns/spawn_monster.cpp | 11 +-
src/creatures/monsters/spawns/spawn_monster.h | 2 +-
src/creatures/players/grouping/party.cpp | 6 +-
src/creatures/players/grouping/party.h | 2 +-
src/creatures/players/player.cpp | 12 +-
src/creatures/players/player.h | 6 +-
src/game/game.cpp | 86 --------------
src/game/game.h | 37 ------
src/game/scheduling/events_scheduler.cpp | 111 ++++++++++++++++++
src/game/scheduling/events_scheduler.hpp | 86 ++++++++++++++
src/lua/creature/events.cpp | 14 +--
src/lua/creature/events.h | 2 +-
.../functions/core/game/config_functions.hpp | 1 +
.../functions/core/game/game_functions.cpp | 18 ---
.../functions/core/game/game_functions.hpp | 8 --
src/lua/functions/events/events_functions.hpp | 2 +
.../events/events_scheduler_functions.cpp | 47 ++++++++
.../events/events_scheduler_functions.hpp | 46 ++++++++
src/otserv.cpp | 10 +-
34 files changed, 586 insertions(+), 246 deletions(-)
create mode 100644 data/scripts/creaturescripts/advance_save.lua
create mode 100644 src/game/scheduling/events_scheduler.cpp
create mode 100644 src/game/scheduling/events_scheduler.hpp
create mode 100644 src/lua/functions/events/events_scheduler_functions.cpp
create mode 100644 src/lua/functions/events/events_scheduler_functions.hpp
diff --git a/config.lua.dist b/config.lua.dist
index 4c4b2dd6637..581cee0cc0d 100644
--- a/config.lua.dist
+++ b/config.lua.dist
@@ -214,12 +214,13 @@ globalServerSaveTime = "06:00:00"
sortLootByChance = false
-- Rates
--- NOTE: rateExp, rateSkill and rateMagic is used as a fallback only
+-- NOTE: rateExp, rateSkill and rateMagic are only used when 'rateUseStages = false'
-- To configure rates see file data/stages.lua
+rateUseStages = false
rateExp = 1
-rateSkill = 50
-rateLoot = 3
-rateMagic = 25
+rateSkill = 1
+rateLoot = 1
+rateMagic = 1
rateSpawn = 1
-- Today regeneration condition over an loop every 1 second,
diff --git a/data/XML/events.xml b/data/XML/events.xml
index c59ad0b4609..e2cdd69c24f 100644
--- a/data/XML/events.xml
+++ b/data/XML/events.xml
@@ -6,8 +6,8 @@
-
-
+
+
diff --git a/data/events/scripts/player.lua b/data/events/scripts/player.lua
index 70a603e6695..1594eb57c85 100644
--- a/data/events/scripts/player.lua
+++ b/data/events/scripts/player.lua
@@ -272,8 +272,43 @@ local function useStamina(player)
player:setStamina(staminaMinutes)
end
-function Player:onGainExperience(source, exp, rawExp)
- if not source or source:isPlayer() then
+local function useStaminaXpBoost(player)
+ if not player then
+ return false
+ end
+
+ local staminaMinutes = player:getExpBoostStamina() / 60
+ if staminaMinutes == 0 then
+ return
+ end
+
+ local playerId = player:getId()
+ if not playerId then
+ return false
+ end
+
+ local currentTime = os.time()
+ local timePassed = currentTime - nextUseXpStamina[playerId]
+ if timePassed <= 0 then
+ return
+ end
+
+ if timePassed > 60 then
+ if staminaMinutes > 2 then
+ staminaMinutes = staminaMinutes - 2
+ else
+ staminaMinutes = 0
+ end
+ nextUseXpStamina[playerId] = currentTime + 120
+ else
+ staminaMinutes = staminaMinutes - 1
+ nextUseXpStamina[playerId] = currentTime + 60
+ end
+ player:setExpBoostStamina(staminaMinutes * 60)
+end
+
+function Player:onGainExperience(target, exp, rawExp)
+ if not target or target:isPlayer() then
return exp
end
@@ -285,31 +320,49 @@ function Player:onGainExperience(source, exp, rawExp)
end
-- Experience Stage Multiplier
- local expStage = getRateFromTable(experienceStages, self:getLevel(), configManager.getNumber(configKeys.RATE_EXP))
- exp = exp * expStage
- baseExp = rawExp * expStage
+ local expStage = getRateFromTable(experienceStages, self:getLevel(), configManager.getNumber(configKeys.RATE_EXPERIENCE))
+
+ -- Event scheduler
+ if SCHEDULE_EXP_RATE ~= 100 then
+ expStage = math.max(0, (expStage * SCHEDULE_EXP_RATE)/100)
+ end
+
+ -- Store Bonus
+ useStaminaXpBoost(self) -- Use store boost stamina
+
+ local Boost = self:getExpBoostStamina()
+ local stillHasBoost = Boost > 0
+ local storeXpBoostAmount = stillHasBoost and self:getStoreXpBoost() or 0
+
+ self:setStoreXpBoost(storeXpBoostAmount)
- -- Stamina modifier
+ -- Stamina Bonus
+ local staminaBoost = 1
if configManager.getBoolean(configKeys.STAMINA_SYSTEM) then
useStamina(self)
-
local staminaMinutes = self:getStamina()
- if staminaMinutes > 2400 and self:isPremium() then
- exp = exp * 1.5
- elseif staminaMinutes <= 840 then
- exp = exp * 0.5
- end
+ if staminaMinutes > 2340 and self:isPremium() then
+ staminaBoost = 1.5
+ elseif staminaMinutes <= 840 then
+ staminaBoost = 0.5 --TODO destroy loot of people with 840- stamina
+ end
+ self:setStaminaXpBoost(staminaBoost * 100)
+ end
+
+ -- Boosted creature
+ if target:getName():lower() == (Game.getBoostedCreature()):lower() then
+ exp = exp * 2
end
-- Prey system
if configManager.getBoolean(configKeys.PREY_ENABLED) then
- local monsterType = source:getType()
+ local monsterType = target:getType()
if monsterType and monsterType:raceId() > 0 then
exp = math.ceil((exp * self:getPreyExperiencePercentage(monsterType:raceId())) / 100)
end
end
- return exp
+ return math.max((exp * expStage + (exp * (storeXpBoostAmount/100))) * staminaBoost)
end
function Player:onLoseExperience(exp)
@@ -321,10 +374,24 @@ function Player:onGainSkillTries(skill, tries)
return tries
end
- if skill == SKILL_MAGLEVEL then
- return tries * configManager.getNumber(configKeys.RATE_MAGIC)
+ -- Event scheduler skill rate
+ local STAGES_DEFAULT = skillsStages or nil
+ local SKILL_DEFAULT = self:getSkillLevel(skill)
+ local RATE_DEFAULT = configManager.getNumber(configKeys.RATE_SKILL)
+
+ if(skill == SKILL_MAGLEVEL) then -- Magic Level
+ STAGES_DEFAULT = magicLevelStages or nil
+ SKILL_DEFAULT = self:getBaseMagicLevel()
+ RATE_DEFAULT = configManager.getNumber(configKeys.RATE_MAGIC)
end
- return tries * configManager.getNumber(configKeys.RATE_SKILL)
+
+ skillOrMagicRate = getRateFromTable(STAGES_DEFAULT, SKILL_DEFAULT, RATE_DEFAULT)
+
+ if SCHEDULE_SKILL_RATE ~= 100 then
+ skillOrMagicRate = math.max(0, (skillOrMagicRate * SCHEDULE_SKILL_RATE) / 100)
+ end
+
+ return tries / 100 * (skillOrMagicRate * 100)
end
function Player:onChangeZone(zone)
diff --git a/data/global.lua b/data/global.lua
index 626234e1742..6affec445dc 100644
--- a/data/global.lua
+++ b/data/global.lua
@@ -35,6 +35,7 @@ weatherConfig = {
SCHEDULE_LOOT_RATE = 100
SCHEDULE_EXP_RATE = 100
SCHEDULE_SKILL_RATE = 100
+SCHEDULE_SPAWN_RATE = 100
-- MARRY
PROPOSED_STATUS = 1
@@ -65,23 +66,6 @@ if damageImpact == nil then
damageImpact = {}
end
-do -- Event Schedule rates
- local lootRate = Game.getEventSLoot()
- if lootRate ~= 100 then
- SCHEDULE_LOOT_RATE = lootRate
- end
-
- local expRate = Game.getEventSExp()
- if expRate ~= 100 then
- SCHEDULE_EXP_RATE = expRate
- end
-
- local skillRate = Game.getEventSSkill()
- if skillRate ~= 100 then
- SCHEDULE_SKILL_RATE = skillRate
- end
-end
-
table.contains = function(array, value)
for _, targetColumn in pairs(array) do
if targetColumn == value then
diff --git a/data/lib/core/functions/functions.lua b/data/lib/core/functions/functions.lua
index ef882a8e683..a8973e18f93 100644
--- a/data/lib/core/functions/functions.lua
+++ b/data/lib/core/functions/functions.lua
@@ -62,7 +62,8 @@ function getFormattedWorldTime()
end
function getLootRandom()
- return math.random(0, MAX_LOOTCHANCE) * 100 / (configManager.getNumber(configKeys.RATE_LOOT) * SCHEDULE_LOOT_RATE)
+ local multi = (configManager.getNumber(configKeys.RATE_LOOT) * SCHEDULE_LOOT_RATE)
+ return math.random(0, MAX_LOOTCHANCE) * 100 / math.max(1, multi)
end
local start = os.time()
@@ -81,9 +82,11 @@ debug.sethook(function(event, line)
end, "l")
function getRateFromTable(t, level, default)
- for _, rate in ipairs(t) do
- if level >= rate.minlevel and (not rate.maxlevel or level <= rate.maxlevel) then
- return rate.multiplier
+ if (t ~= nil) then
+ for _, rate in ipairs(t) do
+ if level >= rate.minlevel and (not rate.maxlevel or level <= rate.maxlevel) then
+ return rate.multiplier
+ end
end
end
return default
diff --git a/data/lib/core/storages.lua b/data/lib/core/storages.lua
index 068654a6a12..61586d80aee 100644
--- a/data/lib/core/storages.lua
+++ b/data/lib/core/storages.lua
@@ -43,6 +43,7 @@ Storage = {
}
GlobalStorage = {
+ XpDisplayMode = 65006,
ExampleQuest = {
Example = 60000
}
diff --git a/data/modules/scripts/daily_reward/daily_reward.lua b/data/modules/scripts/daily_reward/daily_reward.lua
index 95bb6c79cf9..174ea2ec7f8 100644
--- a/data/modules/scripts/daily_reward/daily_reward.lua
+++ b/data/modules/scripts/daily_reward/daily_reward.lua
@@ -232,21 +232,21 @@ DailyReward.retrieveHistoryEntries = function(playerId)
return entries
end
-DailyReward.loadDailyReward = function(playerId, source)
+DailyReward.loadDailyReward = function(playerId, target)
local player = Player(playerId)
if not player then
return false
end
- if source ~= 0 then
- source = REWARD_FROM_SHRINE
+ if target ~= 0 then
+ target = REWARD_FROM_SHRINE
else
- source = REWARD_FROM_PANEL
+ target = REWARD_FROM_PANEL
end
player:sendCollectionResource(ClientPackets.JokerResource, player:getJokerTokens())
player:sendCollectionResource(ClientPackets.CollectionResource, player:getCollectionTokens())
player:sendDailyReward()
- player:sendOpenRewardWall(source)
+ player:sendOpenRewardWall(target)
player:sendDailyRewardCollectionState(DailyReward.isRewardTaken(player:getId()) and DAILY_REWARD_COLLECTED or DAILY_REWARD_NOTCOLLECTED)
return true
end
@@ -273,8 +273,8 @@ DailyReward.pickedReward = function(playerId)
return true
end
-DailyReward.isShrine = function(source)
- if source ~= 0 then
+DailyReward.isShrine = function(target)
+ if target ~= 0 then
return false
else
return true
@@ -349,9 +349,9 @@ DailyReward.init = function(playerId)
player:loadDailyRewardBonuses()
end
-DailyReward.processReward = function(playerId, source)
+DailyReward.processReward = function(playerId, target)
DailyReward.pickedReward(playerId)
- DailyReward.loadDailyReward(playerId, source)
+ DailyReward.loadDailyReward(playerId, target)
local player = Player(playerId)
if player then
player:loadDailyRewardBonuses()
@@ -405,8 +405,8 @@ function Player.selectDailyReward(self, msg)
return false
end
- local source = msg:getByte() -- 0 -> shrine / 1 -> tibia panel
- if not DailyReward.isShrine(source) then
+ local target = msg:getByte() -- 0 -> shrine / 1 -> tibia panel
+ if not DailyReward.isShrine(target) then
if self:getCollectionTokens() < 1 then
self:sendError("You do not have enough collection tokens to proceed.")
return false
@@ -477,7 +477,7 @@ function Player.selectDailyReward(self, msg)
-- Registering history
DailyReward.insertHistory(self:getGuid(), self:getDayStreak(), "Claimed reward no. \z
" .. self:getDayStreak() + 1 .. ". Picked items: " .. description)
- DailyReward.processReward(playerId, source)
+ DailyReward.processReward(playerId, target)
end
local reward = nil
@@ -501,7 +501,7 @@ function Player.selectDailyReward(self, msg)
-- end
-- DailyReward.insertHistory(self:getGuid(), self:getDayStreak(), "Claimed reward no. \z
-- " .. self:getDayStreak() + 1 .. ". Picked reward: " .. description)
- -- DailyReward.processReward(playerId, source)
+ -- DailyReward.processReward(playerId, target)
-- end
if (dailyTable.type == DAILY_REWARD_TYPE_XP_BOOST) then
@@ -509,14 +509,14 @@ function Player.selectDailyReward(self, msg)
self:setStoreXpBoost(50)
DailyReward.insertHistory(self:getGuid(), self:getDayStreak(), "Claimed reward no. \z
" .. self:getDayStreak() + 1 .. ". Picked reward: XP Bonus for " .. reward .. " minutes.")
- DailyReward.processReward(playerId, source)
+ DailyReward.processReward(playerId, target)
end
if (dailyTable.type == DAILY_REWARD_TYPE_PREY_REROLL) then
self:addPreyCards(reward)
DailyReward.insertHistory(self:getGuid(), self:getDayStreak(), "Claimed reward no. \z
" .. self:getDayStreak() + 1 .. ". Picked reward: " .. reward .. "x Prey bonus reroll(s)")
- DailyReward.processReward(playerId, source)
+ DailyReward.processReward(playerId, target)
end
return true
diff --git a/data/scripts/creaturescripts/advance_save.lua b/data/scripts/creaturescripts/advance_save.lua
new file mode 100644
index 00000000000..ab2905e1c19
--- /dev/null
+++ b/data/scripts/creaturescripts/advance_save.lua
@@ -0,0 +1,39 @@
+local config = {
+ heal = true,
+ save = true,
+ effect = false
+}
+
+local advanceSave = CreatureEvent("AdvanceSave")
+
+function advanceSave.onAdvance(player, skill, oldLevel, newLevel)
+ if skill ~= SKILL_LEVEL or newLevel <= oldLevel then
+ return true
+ end
+
+ if config.effect then
+ player:getPosition():sendMagicEffect(math.random(CONST_ME_FIREWORK_YELLOW, CONST_ME_FIREWORK_BLUE))
+ player:say('LEVEL UP!', TALKTYPE_MONSTER_SAY)
+ end
+
+ if config.heal then
+ player:addHealth(player:getMaxHealth())
+ end
+
+ if config.save then
+ player:save()
+ end
+
+ if Game.getStorageValue(GlobalStorage.XpDisplayMode) > 0 then
+ local baseRate = getRateFromTable(experienceStages, player:getLevel(), configManager.getNumber(configKeys.RATE_EXPERIENCE))
+ -- Event scheduler
+ if SCHEDULE_EXP_RATE ~= 100 then
+ baseRate = math.max(0, (baseRate * SCHEDULE_EXP_RATE)/100)
+ end
+ player:setBaseXpGain(baseRate * 100)
+ end
+
+ return true
+end
+
+advanceSave:register()
diff --git a/data/scripts/creaturescripts/login.lua b/data/scripts/creaturescripts/login.lua
index efe62ff5b08..ea22cb2a7c1 100644
--- a/data/scripts/creaturescripts/login.lua
+++ b/data/scripts/creaturescripts/login.lua
@@ -40,6 +40,66 @@ function login.onLogin(player)
onExerciseTraining[player:getId()] = nil
player:setTraining(false)
end
+
+ -- Boosted creature
+ player:sendTextMessage(MESSAGE_BOOSTED_CREATURE, "Today's boosted creature: " .. Game.getBoostedCreature() .. " \
+ Boosted creatures yield more experience points, carry more loot than usual and respawn at a faster rate.")
+
+ if SCHEDULE_EXP_RATE ~= 100 then
+ if SCHEDULE_EXP_RATE > 100 then
+ player:sendTextMessage(MESSAGE_BOOSTED_CREATURE, "Exp Rate Event! Monsters yield more experience points than usual \
+ Happy Hunting!")
+ else
+ player:sendTextMessage(MESSAGE_BOOSTED_CREATURE, "Exp Rate Decreased! Monsters yield less experience points than usual.")
+ end
+ end
+
+ if SCHEDULE_SPAWN_RATE ~= 100 then
+ if SCHEDULE_SPAWN_RATE > 100 then
+ player:sendTextMessage(MESSAGE_BOOSTED_CREATURE, "Spawn Rate Event! Monsters respawn at a faster rate \
+ Happy Hunting!")
+ else
+ player:sendTextMessage(MESSAGE_BOOSTED_CREATURE, "Spawn Rate Decreased! Monsters respawn at a slower rate.")
+ end
+ end
+
+ if SCHEDULE_LOOT_RATE ~= 100 then
+ if SCHEDULE_LOOT_RATE > 100 then
+ player:sendTextMessage(MESSAGE_BOOSTED_CREATURE, "Loot Rate Event! Monsters carry more loot than usual \
+ Happy Hunting!")
+ else
+ player:sendTextMessage(MESSAGE_BOOSTED_CREATURE, "Loot Rate Decreased! Monsters carry less loot than usual.")
+ end
+ end
+
+ if SCHEDULE_SKILL_RATE ~= 100 then
+ if SCHEDULE_SKILL_RATE > 100 then
+ player:sendTextMessage(MESSAGE_BOOSTED_CREATURE, "Skill Rate Event! Your skills progresses at a higher rate \
+ Happy Hunting!")
+ else
+ player:sendTextMessage(MESSAGE_BOOSTED_CREATURE, "Skill Rate Decreased! Your skills progresses at a lower rate.")
+ end
+ end
+
+ local playerId = player:getId()
+
+ -- Stamina
+ nextUseStaminaTime[playerId] = 1
+
+ -- EXP Stamina
+ nextUseXpStamina[playerId] = 1
+
+ -- Set Client XP Gain Rate --
+ local rateExp = 1
+ if Game.getStorageValue(GlobalStorage.XpDisplayMode) > 0 then
+ rateExp = getRateFromTable(experienceStages, player:getLevel(), configManager.getNumber(configKeys.RATE_EXPERIENCE))
+ if SCHEDULE_EXP_RATE ~= 100 then
+ rateExp = math.max(0, (rateExp * SCHEDULE_EXP_RATE)/100)
+ end
+ end
+
+ player:setBaseXpGain(rateExp * 100)
+
return true
end
diff --git a/data/scripts/globalevents/startup.lua b/data/scripts/globalevents/startup.lua
index d3135d4fdfa..fbcfbd1645e 100644
--- a/data/scripts/globalevents/startup.lua
+++ b/data/scripts/globalevents/startup.lua
@@ -49,6 +49,37 @@ function startup.onStartup()
local position = town:getTemplePosition()
db.query("INSERT INTO `towns` (`id`, `name`, `posx`, `posy`, `posz`) VALUES (" .. town:getId() .. ", " .. db.escapeString(town:getName()) .. ", " .. position.x .. ", " .. position.y .. ", " .. position.z .. ")")
end
+
+ do -- Event Schedule rates
+ local lootRate = EventsScheduler.getEventSLoot()
+ if lootRate ~= 100 then
+ SCHEDULE_LOOT_RATE = lootRate
+ end
+
+ local expRate = EventsScheduler.getEventSExp()
+ if expRate ~= 100 then
+ SCHEDULE_EXP_RATE = expRate
+ end
+
+ local skillRate = EventsScheduler.getEventSSkill()
+ if skillRate ~= 100 then
+ SCHEDULE_SKILL_RATE = skillRate
+ end
+
+ local spawnRate = EventsScheduler.getSpawnMonsterSchedule()
+ if spawnRate ~= 100 then
+ SCHEDULE_SPAWN_RATE = spawnRate
+ end
+
+ if expRate ~= 100 or lootRate ~= 100 or spawnRate ~= 100 or skillRate ~= 100 then
+ Spdlog.info("Events: " .. "Exp: " .. expRate .. "%, " .. "loot: " .. lootRate .. "%, " .. "Spawn: " .. spawnRate .. "%, " .. "Skill: ".. skillRate .."%")
+ end
+ end
+
+ -- Client XP Display Mode
+ -- 0 = ignore exp rate /stage
+ -- 1 = include exp rate / stage
+ Game.setStorageValue(GlobalStorage.XpDisplayMode, 1)
end
startup:register()
diff --git a/data/scripts/talkactions/god/reload.lua b/data/scripts/talkactions/god/reload.lua
index c1ed4e7e154..a184a2c79d0 100644
--- a/data/scripts/talkactions/god/reload.lua
+++ b/data/scripts/talkactions/god/reload.lua
@@ -30,7 +30,12 @@ local reloadTypes = {
["raids"] = RELOAD_TYPE_RAIDS,
["scripts"] = RELOAD_TYPE_SCRIPTS,
- ["libs"] = RELOAD_TYPE_GLOBAL
+
+ ["libs"] = RELOAD_TYPE_GLOBAL,
+
+ ["stages"] = RELOAD_TYPE_STAGES,
+
+ ["imbuements"] = RELOAD_TYPE_IMBUEMENTS
}
local reload = TalkAction("/reload")
diff --git a/data/scripts/talkactions/player/server_info.lua b/data/scripts/talkactions/player/server_info.lua
index a5ef27e81a3..db7669abfa1 100644
--- a/data/scripts/talkactions/player/server_info.lua
+++ b/data/scripts/talkactions/player/server_info.lua
@@ -2,7 +2,7 @@ local serverInfo = TalkAction("!serverinfo")
function serverInfo.onSay(player, words, param)
player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "Server Info:"
- .. "\nExp rate: " .. getRateFromTable(experienceStages, player:getLevel(), configManager.getNumber(configKeys.RATE_EXP))
+ .. "\nExp rate: " .. getRateFromTable(experienceStages, player:getLevel(), configManager.getNumber(configKeys.RATE_EXPERIENCE))
.. "\nSkill rate: " .. configManager.getNumber(configKeys.RATE_SKILL)
.. "\nMagic rate: " .. configManager.getNumber(configKeys.RATE_MAGIC)
.. "\nLoot rate: " .. configManager.getNumber(configKeys.RATE_LOOT))
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index f6acacff2da..61a20d69d10 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -176,6 +176,7 @@ target_sources(${PROJECT_NAME}
game/movement/position.cpp
game/movement/teleport.cpp
game/scheduling/scheduler.cpp
+ game/scheduling/events_scheduler.cpp
game/scheduling/tasks.cpp
io/fileloader.cpp
io/iobestiary.cpp
@@ -242,6 +243,7 @@ target_sources(${PROJECT_NAME}
lua/functions/creatures/player/vocation_functions.cpp
lua/functions/events/action_functions.cpp
lua/functions/events/creature_event_functions.cpp
+ lua/functions/events/events_scheduler_functions.cpp
lua/functions/events/global_event_functions.cpp
lua/functions/events/move_event_functions.cpp
lua/functions/events/talk_action_functions.cpp
diff --git a/src/config/config_definitions.hpp b/src/config/config_definitions.hpp
index 1e408ba5c0e..943a9689a21 100644
--- a/src/config/config_definitions.hpp
+++ b/src/config/config_definitions.hpp
@@ -73,6 +73,7 @@ enum booleanConfig_t {
TOGGLE_IMBUEMENT_SHRINE_STORAGE,
AUTOLOOT,
AUTOBANK,
+ RATE_USE_STAGES,
LAST_BOOLEAN_CONFIG
};
diff --git a/src/config/configmanager.cpp b/src/config/configmanager.cpp
index 3568b916a3c..d4e937237df 100644
--- a/src/config/configmanager.cpp
+++ b/src/config/configmanager.cpp
@@ -183,6 +183,7 @@ bool ConfigManager::load()
boolean[TOGGLE_SAVE_INTERVAL_CLEAN_MAP] = getGlobalBoolean(L, "toggleSaveIntervalCleanMap", false);
boolean[ONLY_PREMIUM_ACCOUNT] = getGlobalBoolean(L, "onlyPremiumAccount", false);
+ boolean[RATE_USE_STAGES] = getGlobalBoolean(L, "rateUseStages", false);
boolean[TOGGLE_IMBUEMENT_SHRINE_STORAGE] = getGlobalBoolean(L, "toggleImbuementShrineStorage", true);
string[DEFAULT_PRIORITY] = getGlobalString(L, "defaultPriority", "high");
@@ -202,10 +203,10 @@ bool ConfigManager::load()
integer[PZ_LOCKED] = getGlobalNumber(L, "pzLocked", 60000);
integer[DEFAULT_DESPAWNRANGE] = getGlobalNumber(L, "deSpawnRange", 2);
integer[DEFAULT_DESPAWNRADIUS] = getGlobalNumber(L, "deSpawnRadius", 50);
- integer[RATE_EXPERIENCE] = getGlobalNumber(L, "rateExp", 5);
- integer[RATE_SKILL] = getGlobalNumber(L, "rateSkill", 3);
- integer[RATE_LOOT] = getGlobalNumber(L, "rateLoot", 2);
- integer[RATE_MAGIC] = getGlobalNumber(L, "rateMagic", 3);
+ integer[RATE_EXPERIENCE] = getGlobalNumber(L, "rateExp", 1);
+ integer[RATE_SKILL] = getGlobalNumber(L, "rateSkill", 1);
+ integer[RATE_LOOT] = getGlobalNumber(L, "rateLoot", 1);
+ integer[RATE_MAGIC] = getGlobalNumber(L, "rateMagic", 1);
integer[RATE_SPAWN] = getGlobalNumber(L, "rateSpawn", 1);
integer[HOUSE_PRICE] = getGlobalNumber(L, "housePriceEachSQM", 1000);
integer[ACTIONS_DELAY_INTERVAL] = getGlobalNumber(L, "timeBetweenActions", 200);
diff --git a/src/creatures/monsters/spawns/spawn_monster.cpp b/src/creatures/monsters/spawns/spawn_monster.cpp
index 2e2724b5a0f..55b8f0f8dcf 100644
--- a/src/creatures/monsters/spawns/spawn_monster.cpp
+++ b/src/creatures/monsters/spawns/spawn_monster.cpp
@@ -23,6 +23,7 @@
#include "game/game.h"
#include "creatures/monsters/monster.h"
#include "game/scheduling/scheduler.h"
+#include "game/scheduling/events_scheduler.hpp"
#include "utils/pugicast.h"
#include "lua/creature/events.h"
@@ -46,7 +47,7 @@ bool SpawnsMonster::loadFromXML(const std::string& filemonstername)
this->filemonstername = filemonstername;
loaded = true;
- uint32_t eventschedule = g_game().getSpawnMonsterSchedule();
+ uint32_t eventschedule = g_eventsScheduler().getSpawnMonsterSchedule();
std::string boostedNameGet = g_game().getBoostedMonsterName();
for (auto spawnMonsterNode : doc.child("monsters").children()) {
@@ -94,20 +95,18 @@ bool SpawnsMonster::loadFromXML(const std::string& filemonstername)
centerPos.z
);
- int32_t boostedrate;
+ int32_t boostedrate = 1;
if (nameAttribute.value() == boostedNameGet) {
boostedrate = 2;
- } else {
- boostedrate = 1;
}
- uint32_t interval = pugi::cast(childMonsterNode.attribute("spawntime").value()) * 100000 / (g_configManager().getNumber(RATE_SPAWN) * boostedrate * eventschedule);
+ uint32_t interval = pugi::cast(childMonsterNode.attribute("spawntime").value()) * 1000 * 100 / std::max((uint32_t)1, (g_configManager().getNumber(RATE_SPAWN) * boostedrate * eventschedule));
if (interval >= MONSTER_MINSPAWN_INTERVAL && interval <= MONSTER_MAXSPAWN_INTERVAL) {
spawnMonster.addMonster(nameAttribute.as_string(), pos, dir, static_cast(interval));
} else {
if (interval <= MONSTER_MINSPAWN_INTERVAL) {
- SPDLOG_WARN("[SpawnsMonster::loadFromXml] - {} {} spawntime can not be less than {} seconds", nameAttribute.as_string(), pos.toString(), MONSTER_MINSPAWN_INTERVAL / 1000);
+ SPDLOG_WARN("[SpawnsMonster::loadFromXml] - {} {} spawntime cannot be less than {} seconds, set to {} by default.", nameAttribute.as_string(), pos.toString(), MONSTER_MINSPAWN_INTERVAL / 1000, MONSTER_MINSPAWN_INTERVAL / 1000); spawnMonster.addMonster(nameAttribute.as_string(), pos, dir, MONSTER_MINSPAWN_INTERVAL);
} else {
SPDLOG_WARN("[SpawnsMonster::loadFromXml] - {} {} spawntime can not be more than {} seconds", nameAttribute.as_string(), pos.toString(), MONSTER_MAXSPAWN_INTERVAL / 1000);
}
diff --git a/src/creatures/monsters/spawns/spawn_monster.h b/src/creatures/monsters/spawns/spawn_monster.h
index 663bbc802f2..82498cdc0d9 100644
--- a/src/creatures/monsters/spawns/spawn_monster.h
+++ b/src/creatures/monsters/spawns/spawn_monster.h
@@ -70,7 +70,7 @@ class SpawnMonster
Position centerPos;
int32_t radius;
- uint32_t interval = 60000;
+ uint32_t interval = 30000;
uint32_t checkSpawnMonsterEvent = 0;
static bool findPlayer(const Position& pos);
diff --git a/src/creatures/players/grouping/party.cpp b/src/creatures/players/grouping/party.cpp
index ed58f4a9176..2d204acc13b 100644
--- a/src/creatures/players/grouping/party.cpp
+++ b/src/creatures/players/grouping/party.cpp
@@ -365,14 +365,14 @@ bool Party::setSharedExperience(Player* player, bool newSharedExpActive)
return true;
}
-void Party::shareExperience(uint64_t experience, Creature* source/* = nullptr*/)
+void Party::shareExperience(uint64_t experience, Creature* target/* = nullptr*/)
{
uint64_t shareExperience = experience;
g_events().eventPartyOnShareExperience(this, shareExperience);
for (Player* member : memberList) {
- member->onGainSharedExperience(shareExperience, source);
+ member->onGainSharedExperience(shareExperience, target);
}
- leader->onGainSharedExperience(shareExperience, source);
+ leader->onGainSharedExperience(shareExperience, target);
}
bool Party::canUseSharedExperience(const Player* player) const
diff --git a/src/creatures/players/grouping/party.h b/src/creatures/players/grouping/party.h
index cab2e8116dc..37fdf58d461 100644
--- a/src/creatures/players/grouping/party.h
+++ b/src/creatures/players/grouping/party.h
@@ -66,7 +66,7 @@ class Party
}
bool canOpenCorpse(uint32_t ownerId) const;
- void shareExperience(uint64_t experience, Creature* source = nullptr);
+ void shareExperience(uint64_t experience, Creature* target = nullptr);
bool setSharedExperience(Player* player, bool sharedExpActive);
bool isSharedExperienceActive() const {
return sharedExpActive;
diff --git a/src/creatures/players/player.cpp b/src/creatures/players/player.cpp
index 1ee431a28b3..cc6743ff91f 100644
--- a/src/creatures/players/player.cpp
+++ b/src/creatures/players/player.cpp
@@ -2125,7 +2125,7 @@ void Player::addManaSpent(uint64_t amount)
}
}
-void Player::addExperience(Creature* source, uint64_t exp, bool sendText/* = false*/)
+void Player::addExperience(Creature* target, uint64_t exp, bool sendText/* = false*/)
{
uint64_t currLevelExp = Player::getExpForLevel(level);
uint64_t nextLevelExp = Player::getExpForLevel(level + 1);
@@ -2137,7 +2137,7 @@ void Player::addExperience(Creature* source, uint64_t exp, bool sendText/* = fal
return;
}
- g_events().eventPlayerOnGainExperience(this, source, exp, rawExp);
+ g_events().eventPlayerOnGainExperience(this, target, exp, rawExp);
if (exp == 0) {
return;
}
@@ -4410,13 +4410,13 @@ bool Player::onKilledCreature(Creature* target, bool lastHit/* = true*/)
return unjustified;
}
-void Player::gainExperience(uint64_t gainExp, Creature* source)
+void Player::gainExperience(uint64_t gainExp, Creature* target)
{
if (hasFlag(PlayerFlag_NotGainExperience) || gainExp == 0 || staminaMinutes == 0) {
return;
}
- addExperience(source, gainExp, true);
+ addExperience(target, gainExp, true);
}
void Player::onGainExperience(uint64_t gainExp, Creature* target)
@@ -4435,9 +4435,9 @@ void Player::onGainExperience(uint64_t gainExp, Creature* target)
gainExperience(gainExp, target);
}
-void Player::onGainSharedExperience(uint64_t gainExp, Creature* source)
+void Player::onGainSharedExperience(uint64_t gainExp, Creature* target)
{
- gainExperience(gainExp, source);
+ gainExperience(gainExp, target);
}
bool Player::isImmune(CombatType_t type) const
diff --git a/src/creatures/players/player.h b/src/creatures/players/player.h
index 13c3c75967b..81aeef15a6f 100644
--- a/src/creatures/players/player.h
+++ b/src/creatures/players/player.h
@@ -768,7 +768,7 @@ class Player final : public Creature, public Cylinder
void onTargetCreatureGainHealth(Creature* target, int32_t points) override;
bool onKilledCreature(Creature* target, bool lastHit = true) override;
void onGainExperience(uint64_t gainExp, Creature* target) override;
- void onGainSharedExperience(uint64_t gainExp, Creature* source);
+ void onGainSharedExperience(uint64_t gainExp, Creature* target);
void onAttackedCreatureBlockHit(BlockType_t blockType) override;
void onBlockHit() override;
void onChangeZone(ZoneType_t zone) override;
@@ -2042,8 +2042,8 @@ class Player final : public Creature, public Cylinder
void checkLootContainers(const Item* item);
- void gainExperience(uint64_t exp, Creature* source);
- void addExperience(Creature* source, uint64_t exp, bool sendText = false);
+ void gainExperience(uint64_t exp, Creature* target);
+ void addExperience(Creature* target, uint64_t exp, bool sendText = false);
void removeExperience(uint64_t exp, bool sendText = false);
void updateInventoryWeight();
diff --git a/src/game/game.cpp b/src/game/game.cpp
index 7d8201d6b32..29a3e0d03b2 100644
--- a/src/game/game.cpp
+++ b/src/game/game.cpp
@@ -164,92 +164,6 @@ void Game::setWorldType(WorldType_t type)
worldType = type;
}
-bool Game::loadScheduleEventFromXml()
-{
- pugi::xml_document doc;
- pugi::xml_parse_result result = doc.load_file("data/XML/events.xml");
- if (!result) {
- printXMLError("Error - Game::loadScheduleEventFromXml", "data/XML/events.xml", result);
- return false;
- }
-
- int16_t daysNow;
- time_t t = time(NULL);
- tm* timePtr = localtime(&t);
- int16_t daysMath = ((timePtr->tm_year + 1900) * 365) + ((timePtr->tm_mon + 1) * 30) + (timePtr->tm_mday);
-
- for (auto schedNode : doc.child("events").children()) {
- std::string ss_d;
- std::stringstream ss;
-
- pugi::xml_attribute attr;
- if ((attr = schedNode.attribute("name"))) {
- ss_d = attr.as_string();
- ss << "> " << ss_d << " event";
- }
-
- int year;
- int day;
- int month;
-
- if (!(attr = schedNode.attribute("enddate"))) {
- continue;
- } else {
- ss_d = attr.as_string();
- sscanf(ss_d.c_str(), "%d/%d/%d", &month, &day, &year);
- daysNow = ((year * 365) + (month * 30) + day);
- if (daysMath > daysNow) {
- continue;
- }
- }
-
- if (!(attr = schedNode.attribute("startdate"))) {
- continue;
- } else {
- ss_d = attr.as_string();
- sscanf(ss_d.c_str(), "%d/%d/%d", &month, &day, &year);
- daysNow = ((year * 365) + (month * 30) + day);
- if (daysMath < daysNow) {
- continue;
- }
- }
-
- if ((attr = schedNode.attribute("script")) && !(g_scripts().loadEventSchedulerScripts(attr.as_string()))) {
- SPDLOG_WARN("Can not load the file '{}' on '/events/scripts/scheduler/'",
- attr.as_string());
- return false;
- }
-
- for (auto schedENode : schedNode.children()) {
- if ((schedENode.attribute("exprate"))) {
- uint16_t exprate = pugi::cast(schedENode.attribute("exprate").value());
- g_game().setExpSchedule(exprate);
- ss << " exp: " << (exprate - 100) << "%";
- }
-
- if ((schedENode.attribute("lootrate"))) {
- uint16_t lootrate = pugi::cast(schedENode.attribute("lootrate").value());
- g_game().setLootSchedule(lootrate);
- ss << ", loot: " << (lootrate - 100) << "%";
- }
-
- if ((schedENode.attribute("spawnrate"))) {
- uint32_t spawnrate = pugi::cast(schedENode.attribute("spawnrate").value());
- g_game().setSpawnMonsterSchedule(spawnrate);
- ss << ", spawn: " << (spawnrate - 100) << "%";
- }
-
- if ((schedENode.attribute("skillrate"))) {
- uint16_t skillrate = pugi::cast(schedENode.attribute("skillrate").value());
- g_game().setSkillSchedule(skillrate);
- ss << ", skill: " << (skillrate - 100) << "%";
- }
- }
- SPDLOG_INFO(ss.str());
- }
- return true;
-}
-
void Game::setGameState(GameState_t newState)
{
if (gameState == GAME_STATE_SHUTDOWN) {
diff --git a/src/game/game.h b/src/game/game.h
index 8b68fc690ae..66ea682766d 100644
--- a/src/game/game.h
+++ b/src/game/game.h
@@ -108,8 +108,6 @@ class Game
void removeTeamFinderListed(uint32_t leaderGuid) {
teamFinderMap.erase(leaderGuid);
}
- // Event schedule xml load
- bool loadScheduleEventFromXml();
Cylinder* internalGetCylinder(Player* player, const Position& pos) const;
Thing* internalGetThing(Player* player, const Position& pos, int32_t index,
@@ -515,35 +513,6 @@ class Game
tilesToClean.clear();
}
- // Event schedule
- uint16_t getExpSchedule() const {
- return expSchedule;
- }
- void setExpSchedule(uint16_t exprate) {
- expSchedule = (expSchedule * exprate)/100;
- }
-
- uint16_t getLootSchedule() const {
- return lootSchedule;
- }
- void setLootSchedule(uint16_t lootrate) {
- lootSchedule = (lootSchedule * lootrate)/100;
- }
-
- uint32_t getSpawnMonsterSchedule() const {
- return spawnMonsterSchedule;
- }
- void setSpawnMonsterSchedule(uint32_t spawnrate) {
- spawnMonsterSchedule = (spawnMonsterSchedule * spawnrate)/100;
- }
-
- uint16_t getSkillSchedule() const {
- return skillSchedule;
- }
- void setSkillSchedule(uint16_t skillrate) {
- skillSchedule = (skillSchedule * skillrate)/100;
- }
-
void playerInspectItem(Player* player, const Position& pos);
void playerInspectItem(Player* player, uint16_t itemId, uint8_t itemCount, bool cyclopedia);
@@ -660,12 +629,6 @@ class Game
GameState_t gameState = GAME_STATE_NORMAL;
WorldType_t worldType = WORLD_TYPE_PVP;
- // Event schedule
- uint16_t expSchedule = 100;
- uint16_t lootSchedule = 100;
- uint16_t skillSchedule = 100;
- uint32_t spawnMonsterSchedule = 100;
-
LightState_t lightState = LIGHT_STATE_DAY;
LightState_t currentLightState = lightState;
uint8_t lightLevel = LIGHT_LEVEL_DAY;
diff --git a/src/game/scheduling/events_scheduler.cpp b/src/game/scheduling/events_scheduler.cpp
new file mode 100644
index 00000000000..4c18bdfb553
--- /dev/null
+++ b/src/game/scheduling/events_scheduler.cpp
@@ -0,0 +1,111 @@
+/**
+ * The Forgotten Server - a free and open-source MMORPG server emulator
+ * Copyright (C) 2019 Mark Samman
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "otpch.h"
+
+#include "utils/pugicast.h"
+
+#include "game/scheduling/events_scheduler.hpp"
+#include "lua/scripts/scripts.h"
+
+bool EventsScheduler::loadScheduleEventFromXml() const
+{
+ pugi::xml_document doc;
+ if (pugi::xml_parse_result result = doc.load_file("data/XML/events.xml"); !result) {
+ printXMLError("Error - EventsScheduler::loadScheduleEventFromXml", "data/XML/events.xml", result);
+ consoleHandlerExit();
+ return false;
+ }
+
+ int daysNow;
+ time_t t = time(nullptr);
+ const tm* timePtr = localtime(&t);
+ int daysMath = ((timePtr->tm_year + 1900) * 365) + ((timePtr->tm_mon + 1) * 30) + (timePtr->tm_mday);
+
+ for (auto schedNode : doc.child("events").children()) {
+ std::string ss_d;
+ std::stringstream ss;
+
+ pugi::xml_attribute attr;
+ if ((attr = schedNode.attribute("name"))) {
+ ss_d = attr.as_string();
+ ss << ss_d << " event";
+ }
+
+ int16_t year;
+ int16_t day;
+ int16_t month;
+
+ if (!(attr = schedNode.attribute("enddate"))) {
+ continue;
+ } else {
+ ss_d = attr.as_string();
+ sscanf(ss_d.c_str(), "%hd/%hd/%hd", &month, &day, &year);
+ daysNow = ((year * 365) + (month * 30) + day);
+ if (daysMath > daysNow) {
+ continue;
+ }
+ }
+
+ if (!(attr = schedNode.attribute("startdate"))) {
+ continue;
+ } else {
+ ss_d = attr.as_string();
+ sscanf(ss_d.c_str(), "%hd/%hd/%hd", &month, &day, &year);
+ daysNow = ((year * 365) + (month * 30) + day);
+ if (daysMath < daysNow) {
+ continue;
+ }
+ }
+
+ if ((attr = schedNode.attribute("script")) && (!(g_scripts().loadEventSchedulerScripts(attr.as_string())))) {
+ SPDLOG_WARN("Can not load the file '{}' on '/events/scripts/scheduler/'",
+ attr.as_string());
+ return false;
+ }
+
+ for (auto schedENode : schedNode.children()) {
+ if ((schedENode.attribute("exprate"))) {
+ uint16_t exprate = pugi::cast(schedENode.attribute("exprate").value());
+ g_eventsScheduler().setExpSchedule(exprate);
+ ss << " exp: " << exprate << "%";
+ }
+
+ if ((schedENode.attribute("lootrate"))) {
+ uint16_t lootrate = pugi::cast(schedENode.attribute("lootrate").value());
+ g_eventsScheduler().setLootSchedule(lootrate);
+ ss << ", loot: " << lootrate << "%";
+ }
+
+ if ((schedENode.attribute("spawnrate"))) {
+ uint32_t spawnrate = pugi::cast(schedENode.attribute("spawnrate").value());
+ g_eventsScheduler().setSpawnMonsterSchedule(spawnrate);
+ ss << ", spawn: " << spawnrate << "%";
+ }
+
+ if ((schedENode.attribute("skillrate"))) {
+ uint16_t skillrate = pugi::cast(schedENode.attribute("skillrate").value());
+ g_eventsScheduler().setSkillSchedule(skillrate);
+ ss << ", skill: " << skillrate << "%";
+ break;
+ }
+ }
+ }
+ return true;
+}
diff --git a/src/game/scheduling/events_scheduler.hpp b/src/game/scheduling/events_scheduler.hpp
new file mode 100644
index 00000000000..d7954a5fa02
--- /dev/null
+++ b/src/game/scheduling/events_scheduler.hpp
@@ -0,0 +1,86 @@
+/**
+ * The Forgotten Server - a free and open-source MMORPG server emulator
+ * Copyright (C) 2019 Mark Samman
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#ifndef SRC_GAME_SCHEDUNLING_EVENTS_SCHEDULER_HPP_
+#define SRC_GAME_SCHEDUNLING_EVENTS_SCHEDULER_HPP_
+
+// #include
+
+#include "utils/tools.h"
+
+class EventsScheduler
+{
+ public:
+ EventsScheduler() = default;
+
+ // Singleton - ensures we don't accidentally copy it.
+ EventsScheduler(const EventsScheduler&) = delete;
+ EventsScheduler& operator=(const EventsScheduler&) = delete;
+
+ static EventsScheduler& getInstance() {
+ // Guaranteed to be destroyed
+ static EventsScheduler instance;
+ // Instantiated on first use
+ return instance;
+ }
+
+ // Event schedule xml load
+ bool loadScheduleEventFromXml() const;
+
+ // Event schedule
+ uint16_t getExpSchedule() const {
+ return expSchedule;
+ }
+ void setExpSchedule(uint16_t exprate) {
+ expSchedule = (expSchedule * exprate)/100;
+ }
+
+ uint32_t getLootSchedule() const {
+ return lootSchedule;
+ }
+ void setLootSchedule(uint32_t lootrate) {
+ lootSchedule = (lootSchedule * lootrate)/100;
+ }
+
+ uint32_t getSpawnMonsterSchedule() const {
+ return spawnMonsterSchedule;
+ }
+ void setSpawnMonsterSchedule(uint32_t spawnrate) {
+ spawnMonsterSchedule = (spawnMonsterSchedule * spawnrate)/100;
+ }
+
+ uint16_t getSkillSchedule() const {
+ return skillSchedule;
+ }
+ void setSkillSchedule(uint16_t skillrate) {
+ skillSchedule = (skillSchedule * skillrate)/100;
+ }
+
+ private:
+ // Event schedule
+ uint16_t expSchedule = 100;
+ uint32_t lootSchedule = 100;
+ uint16_t skillSchedule = 100;
+ uint32_t spawnMonsterSchedule = 100;
+
+};
+
+constexpr auto g_eventsScheduler = &EventsScheduler::getInstance;
+
+#endif // SRC_GAME_SCHEDUNLING_EVENTS_SCHEDULER_HPP_
diff --git a/src/lua/creature/events.cpp b/src/lua/creature/events.cpp
index 44ef5092faa..23b0380237c 100644
--- a/src/lua/creature/events.cpp
+++ b/src/lua/creature/events.cpp
@@ -1029,8 +1029,8 @@ bool Events::eventPlayerOnTradeAccept(Player* player, Player* target, Item* item
return scriptInterface.callFunction(4);
}
-void Events::eventPlayerOnGainExperience(Player* player, Creature* source, uint64_t& exp, uint64_t rawExp) {
- // Player:onGainExperience(source, exp, rawExp)
+void Events::eventPlayerOnGainExperience(Player* player, Creature* target, uint64_t& exp, uint64_t rawExp) {
+ // Player:onGainExperience(target, exp, rawExp)
// rawExp gives the original exp which is not multiplied
if (info.playerOnGainExperience == -1) {
return;
@@ -1038,9 +1038,9 @@ void Events::eventPlayerOnGainExperience(Player* player, Creature* source, uint6
if (!scriptInterface.reserveScriptEnv()) {
SPDLOG_ERROR("[Events::eventPlayerOnGainExperience - "
- "Player {} source {}] "
+ "Player {} target {}] "
"Call stack overflow. Too many lua script calls being nested.",
- player->getName(), source->getName());
+ player->getName(), target->getName());
return;
}
@@ -1053,9 +1053,9 @@ void Events::eventPlayerOnGainExperience(Player* player, Creature* source, uint6
LuaScriptInterface::pushUserdata(L, player);
LuaScriptInterface::setMetatable(L, -1, "Player");
- if (source) {
- LuaScriptInterface::pushUserdata(L, source);
- LuaScriptInterface::setCreatureMetatable(L, -1, source);
+ if (target) {
+ LuaScriptInterface::pushUserdata(L, target);
+ LuaScriptInterface::setCreatureMetatable(L, -1, target);
} else {
lua_pushnil(L);
}
diff --git a/src/lua/creature/events.h b/src/lua/creature/events.h
index 5b908071755..dd87999c969 100644
--- a/src/lua/creature/events.h
+++ b/src/lua/creature/events.h
@@ -121,7 +121,7 @@ class Events {
bool eventPlayerOnTurn(Player* player, Direction direction);
bool eventPlayerOnTradeRequest(Player* player, Player* target, Item* item);
bool eventPlayerOnTradeAccept(Player* player, Player* target, Item* item, Item* targetItem);
- void eventPlayerOnGainExperience(Player* player, Creature* source, uint64_t& exp, uint64_t rawExp);
+ void eventPlayerOnGainExperience(Player* player, Creature* target, uint64_t& exp, uint64_t rawExp);
void eventPlayerOnLoseExperience(Player* player, uint64_t& exp);
void eventPlayerOnGainSkillTries(Player* player, skills_t skill, uint64_t& tries);
bool eventPlayerOnRemoveCount(Player* player, Item * item);
diff --git a/src/lua/functions/core/game/config_functions.hpp b/src/lua/functions/core/game/config_functions.hpp
index ee6d83392ed..11ef224a5a9 100644
--- a/src/lua/functions/core/game/config_functions.hpp
+++ b/src/lua/functions/core/game/config_functions.hpp
@@ -176,6 +176,7 @@ class ConfigFunctions final : LuaScriptInterface {
registerEnumIn(L, "configKeys", SAVE_INTERVAL_TYPE)
registerEnumIn(L, "configKeys", TOGGLE_SAVE_INTERVAL_CLEAN_MAP)
registerEnumIn(L, "configKeys", SAVE_INTERVAL_TIME)
+ registerEnumIn(L, "configKeys", RATE_USE_STAGES)
registerEnumIn(L, "configKeys", TOGGLE_IMBUEMENT_SHRINE_STORAGE)
registerEnumIn(L, "configKeys", GLOBAL_SERVER_SAVE_TIME)
diff --git a/src/lua/functions/core/game/game_functions.cpp b/src/lua/functions/core/game/game_functions.cpp
index 67ada0787f2..929075db99f 100644
--- a/src/lua/functions/core/game/game_functions.cpp
+++ b/src/lua/functions/core/game/game_functions.cpp
@@ -74,24 +74,6 @@ int GameFunctions::luaGameCreateNpcType(lua_State* L) {
return 1;
}
-int GameFunctions::luaGamegetEventSLoot(lua_State* L) {
- // Game.getEventSLoot()
- lua_pushnumber(L, g_game().getLootSchedule());
- return 1;
-}
-
-int GameFunctions::luaGamegetEventSSkill(lua_State* L) {
- // Game.getEventSSkill()
- lua_pushnumber(L, g_game().getSkillSchedule());
- return 1;
-}
-
-int GameFunctions::luaGamegetEventSExp(lua_State* L) {
- // Game.getEventSExp()
- lua_pushnumber(L, g_game().getExpSchedule());
- return 1;
-}
-
int GameFunctions::luaGameGetSpectators(lua_State* L) {
// Game.getSpectators(position[, multifloor = false[, onlyPlayer = false[, minRangeX = 0[, maxRangeX = 0[, minRangeY = 0[, maxRangeY = 0]]]]]])
const Position& position = getPosition(L, 1);
diff --git a/src/lua/functions/core/game/game_functions.hpp b/src/lua/functions/core/game/game_functions.hpp
index 33466cc9533..2a11786a3b1 100644
--- a/src/lua/functions/core/game/game_functions.hpp
+++ b/src/lua/functions/core/game/game_functions.hpp
@@ -32,10 +32,6 @@ class GameFunctions final : LuaScriptInterface {
registerMethod(L, "Game", "createNpcType", GameFunctions::luaGameCreateNpcType);
registerMethod(L, "Game", "createMonsterType", GameFunctions::luaGameCreateMonsterType);
- registerMethod(L, "Game", "getEventSLoot", GameFunctions::luaGamegetEventSLoot);
- registerMethod(L, "Game", "getEventSSkill", GameFunctions::luaGamegetEventSSkill);
- registerMethod(L, "Game", "getEventSExp", GameFunctions::luaGamegetEventSExp);
-
registerMethod(L, "Game", "getSpectators", GameFunctions::luaGameGetSpectators);
registerMethod(L, "Game", "getBoostedCreature", GameFunctions::luaGameGetBoostedCreature);
@@ -88,10 +84,6 @@ class GameFunctions final : LuaScriptInterface {
static int luaGameCreateMonsterType(lua_State* L);
static int luaGameCreateNpcType(lua_State* L);
- static int luaGamegetEventSLoot(lua_State* L);
- static int luaGamegetEventSSkill(lua_State* L);
- static int luaGamegetEventSExp(lua_State* L);
-
static int luaGameGetSpectators(lua_State* L);
static int luaGameGetBoostedCreature(lua_State* L);
diff --git a/src/lua/functions/events/events_functions.hpp b/src/lua/functions/events/events_functions.hpp
index 359e9971ed4..70aab668a3c 100644
--- a/src/lua/functions/events/events_functions.hpp
+++ b/src/lua/functions/events/events_functions.hpp
@@ -23,6 +23,7 @@
#include "lua/scripts/luascript.h"
#include "lua/functions/events/action_functions.hpp"
#include "lua/functions/events/creature_event_functions.hpp"
+#include "lua/functions/events/events_scheduler_functions.hpp"
#include "lua/functions/events/global_event_functions.hpp"
#include "lua/functions/events/move_event_functions.hpp"
#include "lua/functions/events/talk_action_functions.hpp"
@@ -32,6 +33,7 @@ class EventFunctions final : LuaScriptInterface {
static void init(lua_State* L) {
ActionFunctions::init(L);
CreatureEventFunctions::init(L);
+ EventsSchedulerFunctions::init(L);
GlobalEventFunctions::init(L);
MoveEventFunctions::init(L);
TalkActionFunctions::init(L);
diff --git a/src/lua/functions/events/events_scheduler_functions.cpp b/src/lua/functions/events/events_scheduler_functions.cpp
new file mode 100644
index 00000000000..bcfa4979a8e
--- /dev/null
+++ b/src/lua/functions/events/events_scheduler_functions.cpp
@@ -0,0 +1,47 @@
+/**
+ * The Forgotten Server - a free and open-source MMORPG server emulator
+ * Copyright (C) 2019 Mark Samman
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#include "otpch.h"
+
+#include "game/scheduling/events_scheduler.hpp"
+#include "lua/functions/events/events_scheduler_functions.hpp"
+
+int EventsSchedulerFunctions::luaEventsSchedulergetEventSLoot(lua_State* L) {
+ // EventsScheduler.getEventSLoot
+ lua_pushnumber(L, g_eventsScheduler().getLootSchedule());
+ return 1;
+}
+
+int EventsSchedulerFunctions::luaEventsSchedulergetEventSSkill(lua_State* L) {
+ // EventsScheduler.getEventSSkill
+ lua_pushnumber(L, g_eventsScheduler().getSkillSchedule());
+ return 1;
+}
+
+int EventsSchedulerFunctions::luaEventsSchedulergetEventSExp(lua_State* L) {
+ // EventsScheduler.getEventSExp
+ lua_pushnumber(L, g_eventsScheduler().getExpSchedule());
+ return 1;
+}
+
+int EventsSchedulerFunctions::luaEventsSchedulergetSpawnMonsterSchedule(lua_State* L) {
+ // EventsScheduler.getSpawnMonsterSchedule
+ lua_pushnumber(L, g_eventsScheduler().getSpawnMonsterSchedule());
+ return 1;
+}
diff --git a/src/lua/functions/events/events_scheduler_functions.hpp b/src/lua/functions/events/events_scheduler_functions.hpp
new file mode 100644
index 00000000000..2ba31fd6d0b
--- /dev/null
+++ b/src/lua/functions/events/events_scheduler_functions.hpp
@@ -0,0 +1,46 @@
+/**
+ * The Forgotten Server - a free and open-source MMORPG server emulator
+ * Copyright (C) 2019 Mark Samman
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#ifndef SRC_GAME_SCHEDUNLING_EVENTS_SCHEDULER_FUNCTIONS_HPP_
+#define SRC_GAME_SCHEDUNLING_EVENTS_SCHEDULER_FUNCTIONS_HPP_
+
+#include
+
+#include "lua/scripts/lua_environment.hpp"
+#include "lua/scripts/luascript.h"
+
+class EventsSchedulerFunctions final : private LuaScriptInterface {
+ public:
+ static void init(lua_State* L) {
+ registerTable(L, "EventsScheduler");
+
+ registerMethod(L, "EventsScheduler", "getEventSLoot", EventsSchedulerFunctions::luaEventsSchedulergetEventSLoot);
+ registerMethod(L, "EventsScheduler", "getEventSSkill", EventsSchedulerFunctions::luaEventsSchedulergetEventSSkill);
+ registerMethod(L, "EventsScheduler", "getEventSExp", EventsSchedulerFunctions::luaEventsSchedulergetEventSExp);
+ registerMethod(L, "EventsScheduler", "getSpawnMonsterSchedule", EventsSchedulerFunctions::luaEventsSchedulergetSpawnMonsterSchedule);
+ }
+
+ private:
+ static int luaEventsSchedulergetEventSLoot(lua_State* L);
+ static int luaEventsSchedulergetEventSSkill(lua_State* L);
+ static int luaEventsSchedulergetEventSExp(lua_State* L);
+ static int luaEventsSchedulergetSpawnMonsterSchedule(lua_State* L);
+};
+
+#endif // SRC_GAME_SCHEDUNLING_EVENTS_SCHEDULER_FUNCTIONS_HPP_
diff --git a/src/otserv.cpp b/src/otserv.cpp
index cf63b968463..76f27595274 100644
--- a/src/otserv.cpp
+++ b/src/otserv.cpp
@@ -31,7 +31,7 @@
#include "database/databasetasks.h"
#include "game/game.h"
#include "game/scheduling/scheduler.h"
-#include "game/scheduling/tasks.h"
+#include "game/scheduling/events_scheduler.hpp"
#include "io/iomarket.h"
#include "lua/creature/events.h"
#include "lua/modules/modules.h"
@@ -140,8 +140,10 @@ void loadModules() {
// Lua Env
modulesLoadHelper((g_luaEnvironment.loadFile("data/global.lua") == 0),
"data/global.lua");
- modulesLoadHelper((g_luaEnvironment.loadFile("data/stages.lua") == 0),
- "data/stages.lua");
+ if (g_configManager().getBoolean(RATE_USE_STAGES)) {
+ modulesLoadHelper((g_luaEnvironment.loadFile("data/stages.lua") == 0),
+ "data/stages.lua");
+ }
modulesLoadHelper((g_luaEnvironment.loadFile("data/startup/startup.lua") == 0),
"data/startup/startup.lua");
modulesLoadHelper((g_luaEnvironment.loadFile("data/npclib/load.lua") == 0),
@@ -151,7 +153,7 @@ void loadModules() {
"data/scripts/libs");
modulesLoadHelper(g_vocations().loadFromXml(),
"data/XML/vocations.xml");
- modulesLoadHelper(g_game().loadScheduleEventFromXml(),
+ modulesLoadHelper(g_eventsScheduler().loadScheduleEventFromXml(),
"data/XML/events.xml");
modulesLoadHelper(Outfits::getInstance().loadFromXml(),
"data/XML/outfits.xml");