Skip to content
This repository has been archived by the owner on May 20, 2023. It is now read-only.

Commit

Permalink
Feat: Event Schedule (#1932)
Browse files Browse the repository at this point in the history
  • Loading branch information
marcosvf132 committed Nov 4, 2020
1 parent 919a219 commit 3123790
Show file tree
Hide file tree
Showing 10 changed files with 203 additions and 3 deletions.
15 changes: 15 additions & 0 deletions data/XML/events.xml
@@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<events>
<event name="Otservbr example 1" startdate="11/03/2020" enddate="11/30/2020" >
<ingame exprate="250" lootrate="200" spawnrate="100" skillrate="200" />
<description description="Otserver br example 1 description double exp and a half, double loot !chance!, regular spawn and double skill" />
<colors colordark="#235c00" colorlight="#2d7400" />
<details displaypriority="6" isseasonal="0" specialevent="0" />
</event>
<event name="Otservbr example 2" startdate="10/2/2020" enddate="11/7/2020" >
<ingame exprate="50" lootrate="300" spawnrate="150" skillrate="100" />
<description description="Otserver br example 2 description 50% less exp, triple loot !chance!, 50% faster spawn and regular skill" />
<colors colordark="#735D10" colorlight="#8B6D05" />
<details displaypriority="6" isseasonal="0" specialevent="0" />
</event>
</events>
9 changes: 9 additions & 0 deletions data/events/scripts/player.lua
Expand Up @@ -742,6 +742,10 @@ function Player:onGainExperience(source, exp, rawExp)
exp = exp * 2
end

-- Event scheduler
if SCHEDULE_EXP_RATE ~= 100 then
exp = (exp * SCHEDULE_EXP_RATE)/100
end
self:setBaseXpGain(displayRate * 100)
return exp
end
Expand All @@ -755,6 +759,11 @@ function Player:onGainSkillTries(skill, tries)
return tries
end

-- Event scheduler skill rate
if SCHEDULE_SKILL_RATE ~= 100 then
tries = (tries * SCHEDULE_SKILL_RATE)/100
end

local skillRate = configManager.getNumber(configKeys.RATE_SKILL)
local magicRate = configManager.getNumber(configKeys.RATE_MAGIC)

Expand Down
22 changes: 22 additions & 0 deletions data/global.lua
Expand Up @@ -9,6 +9,11 @@ STORAGEVALUE_PROMOTION = 30018

SERVER_NAME = configManager.getString(configKeys.SERVER_NAME)

-- Event Schedule
SCHEDULE_LOOT_RATE = 100
SCHEDULE_EXP_RATE = 100
SCHEDULE_SKILL_RATE = 100

-- MARRY
PROPOSED_STATUS = 1
MARRIED_STATUS = 2
Expand Down Expand Up @@ -69,6 +74,23 @@ startupGlobalStorages = {
GlobalStorage.FerumbrasAscendant.Elements.Done
}

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
Expand Down
2 changes: 1 addition & 1 deletion data/lib/core/functions.lua
Expand Up @@ -30,7 +30,7 @@ function getFormattedWorldTime()
end

function getLootRandom()
return math.random(0, MAX_LOOTCHANCE) / configManager.getNumber(configKeys.RATE_LOOT)
return math.random(0, MAX_LOOTCHANCE) * 100 / (configManager.getNumber(configKeys.RATE_LOOT) * SCHEDULE_LOOT_RATE)
end

local start = os.time()
Expand Down
80 changes: 80 additions & 0 deletions src/game.cpp
Expand Up @@ -108,6 +108,86 @@ 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;
}
}

for (auto schedENode : schedNode.children()) {
if ((schedENode.attribute("exprate"))) {
uint16_t exprate = pugi::cast<uint16_t>(schedENode.attribute("exprate").value());
g_game.setExpSchedule(exprate);
ss << " exp: " << (exprate - 100) << "%";
}

if ((schedENode.attribute("lootrate"))) {
uint16_t lootrate = pugi::cast<uint16_t>(schedENode.attribute("lootrate").value());
g_game.setLootSchedule(lootrate);
ss << ", loot: " << (lootrate - 100) << "%";
}

if ((schedENode.attribute("spawnrate"))) {
uint32_t spawnrate = pugi::cast<uint32_t>(schedENode.attribute("spawnrate").value());
g_game.setSpawnSchedule(spawnrate);
ss << ", spawn: " << (spawnrate - 100) << "%";
}

if ((schedENode.attribute("skillrate"))) {
uint16_t skillrate = pugi::cast<uint16_t>(schedENode.attribute("skillrate").value());
g_game.setSkillSchedule(skillrate);
ss << ", skill: " << (skillrate - 100) << "%";
}
}
std::cout << ss.str() << "." << std::endl;
}
return true;
}

void Game::setGameState(GameState_t newState)
{
if (gameState == GAME_STATE_SHUTDOWN) {
Expand Down
38 changes: 38 additions & 0 deletions src/game.h
Expand Up @@ -109,6 +109,9 @@ class Game
return worldType;
}

// Event schedule xml load
bool loadScheduleEventFromXml();

Cylinder* internalGetCylinder(Player* player, const Position& pos) const;
Thing* internalGetThing(Player* player, const Position& pos, int32_t index,
uint32_t spriteId, stackPosType_t type) const;
Expand Down Expand Up @@ -565,6 +568,35 @@ class Game
std::forward_list<Item*> toDecayItems;
std::forward_list<Item*> toImbuedItems;

// 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 getSpawnSchedule() const {
return spawnSchedule;
}
void setSpawnSchedule(uint32_t spawnrate) {
spawnSchedule = (spawnSchedule * spawnrate)/100;
}

uint16_t getSkillSchedule() const {
return skillSchedule;
}
void setSkillSchedule(uint16_t skillrate) {
skillSchedule = (skillSchedule * skillrate)/100;
}

private:
void checkImbuements();
bool playerSaySpell(Player* player, SpeakClasses type, const std::string& text);
Expand Down Expand Up @@ -617,6 +649,12 @@ 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 spawnSchedule = 100;

LightState_t lightState = LIGHT_STATE_DAY;
LightState_t currentLightState = lightState;
uint8_t lightLevel = LIGHT_LEVEL_DAY;
Expand Down
25 changes: 25 additions & 0 deletions src/luascript.cpp
Expand Up @@ -2103,6 +2103,10 @@ void LuaScriptInterface::registerFunctions()
// Game
registerTable("Game");

registerMethod("Game", "getEventSLoot", LuaScriptInterface::luaGamegetEventSLoot);
registerMethod("Game", "getEventSSkill", LuaScriptInterface::luaGamegetEventSSkill);
registerMethod("Game", "getEventSExp", LuaScriptInterface::luaGamegetEventSExp);

registerMethod("Game", "getSpectators", LuaScriptInterface::luaGameGetSpectators);
registerMethod("Game", "getPlayers", LuaScriptInterface::luaGameGetPlayers);
registerMethod("Game", "loadMap", LuaScriptInterface::luaGameLoadMap);
Expand Down Expand Up @@ -4600,6 +4604,27 @@ int LuaScriptInterface::luaTableCreate(lua_State* L)
}

// Game
int LuaScriptInterface::luaGamegetEventSLoot(lua_State* L)
{
// Game.getEventSLoot()
lua_pushnumber(L, g_game.getLootSchedule());
return 1;
}

int LuaScriptInterface::luaGamegetEventSSkill(lua_State* L)
{
// Game.getEventSSkill()
lua_pushnumber(L, g_game.getSkillSchedule());
return 1;
}

int LuaScriptInterface::luaGamegetEventSExp(lua_State* L)
{
// Game.getEventSExp()
lua_pushnumber(L, g_game.getExpSchedule());
return 1;
}

int LuaScriptInterface::luaGameGetSpectators(lua_State* L)
{
// Game.getSpectators(position[, multifloor = false[, onlyPlayer = false[, minRangeX = 0[, maxRangeX = 0[, minRangeY = 0[, maxRangeY = 0]]]]]])
Expand Down
4 changes: 4 additions & 0 deletions src/luascript.h
Expand Up @@ -534,6 +534,10 @@ class LuaScriptInterface
static int luaTableCreate(lua_State* L);

// Game
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 luaGameGetPlayers(lua_State* L);
static int luaGameLoadMap(lua_State* L);
Expand Down
5 changes: 5 additions & 0 deletions src/otserv.cpp
Expand Up @@ -236,6 +236,11 @@ void mainLoader(int, char*[], ServiceManager* services) {
return;
}

std::cout << ">> Loading event scheduler" << std::endl;
if (!g_game.loadScheduleEventFromXml()) {
startupErrorMessage("Unable to load event schedule!");
}

std::cout << ">> Loading script systems" << std::endl;
if (!ScriptingManager::getInstance().loadScriptSystems()) {
startupErrorMessage("Failed to load script systems");
Expand Down
6 changes: 4 additions & 2 deletions src/spawn.cpp
Expand Up @@ -51,6 +51,7 @@ bool Spawns::loadFromXml(const std::string& fromFilename)
this->filename = fromFilename;
loaded = true;

uint32_t eventschedule = g_game.getSpawnSchedule();
Database& db = Database::getInstance();
std::ostringstream query;
query << "SELECT `boostname` FROM `boosted_creature`";
Expand Down Expand Up @@ -109,7 +110,7 @@ bool Spawns::loadFromXml(const std::string& fromFilename)
boostedrate = 1;
}

uint32_t interval = pugi::cast<uint32_t>(childNode.attribute("spawntime").value()) * 1000 / (g_config.getNumber(ConfigManager::RATE_SPAWN) * boostedrate);
uint32_t interval = pugi::cast<uint32_t>(childNode.attribute("spawntime").value()) * 100000 / (g_config.getNumber(ConfigManager::RATE_SPAWN) * boostedrate * eventschedule);
if (interval > MINSPAWN_INTERVAL) {
spawn.addMonster(nameAttribute.as_string(), pos, dir, interval);
} else {
Expand Down Expand Up @@ -157,6 +158,7 @@ bool Spawns::loadCustomSpawnXml(const std::string& _filename)
return false;
}

uint32_t eventschedule = g_game.getSpawnSchedule();
Database& db = Database::getInstance();
std::ostringstream query;
query << "SELECT `boostname` FROM `boosted_creature`";
Expand Down Expand Up @@ -217,7 +219,7 @@ bool Spawns::loadCustomSpawnXml(const std::string& _filename)
boostedrate = 1;
}

uint32_t interval = pugi::cast<uint32_t>(childNode.attribute("spawntime").value()) * 1000 / (g_config.getNumber(ConfigManager::RATE_SPAWN) * boostedrate);
uint32_t interval = pugi::cast<uint32_t>(childNode.attribute("spawntime").value()) * 100000 / (g_config.getNumber(ConfigManager::RATE_SPAWN) * boostedrate * eventschedule);
if (interval > MINSPAWN_INTERVAL) {
spawn.addMonster(nameAttribute.as_string(), pos, dir, interval);
} else {
Expand Down

0 comments on commit 3123790

Please sign in to comment.