From 59b7abdd34a793187c428e691e1d3892a376adeb Mon Sep 17 00:00:00 2001 From: Luan Luciano Date: Fri, 1 Mar 2024 09:40:53 -0300 Subject: [PATCH] feat: options 'frags' and 'payment' to war system (#1982) When declaring war, the guild leader chooses their opponent and defines the conditions: duration (from 7 to 180 days), frags limit (up to 1,000), a penalty to be paid in case of loss (up to 2kkk), among others. Based on the information above, we can add the columns "frags_limit," "payment," and "duration_days" to the 'guild wars' table so that the websites can interact correctly according to the system. Resolves #2121 --- data-otservbr-global/migrations/41.lua | 4 +- data-otservbr-global/migrations/43.lua | 11 ++++- data-otservbr-global/migrations/44.lua | 3 ++ .../creaturescripts/others/player_death.lua | 48 +++++++++++++++---- .../scripts/globalevents/others/guild_war.lua | 5 +- schema.sql | 7 ++- src/io/ioguild.cpp | 2 +- 7 files changed, 62 insertions(+), 18 deletions(-) create mode 100644 data-otservbr-global/migrations/44.lua diff --git a/data-otservbr-global/migrations/41.lua b/data-otservbr-global/migrations/41.lua index 179ac18b574..15eb1d88e99 100644 --- a/data-otservbr-global/migrations/41.lua +++ b/data-otservbr-global/migrations/41.lua @@ -3,8 +3,8 @@ function onUpdateDatabase() db.query([[ ALTER TABLE `players` - MODIFY `xpboost_stamina` smallint(5) UNSIGNED DEFAULT NULL, - MODIFY `xpboost_value` tinyint(4) UNSIGNED DEFAULT NULL + MODIFY `xpboost_stamina` smallint(5) UNSIGNED DEFAULT NULL, + MODIFY `xpboost_value` tinyint(4) UNSIGNED DEFAULT NULL ]]) return true diff --git a/data-otservbr-global/migrations/43.lua b/data-otservbr-global/migrations/43.lua index 86a6d8ffec1..1464703c96e 100644 --- a/data-otservbr-global/migrations/43.lua +++ b/data-otservbr-global/migrations/43.lua @@ -1,3 +1,12 @@ function onUpdateDatabase() - return false -- true = There are others migrations file | false = this is the last migration file + logger.info("Updating database to version 43 (feat frags_limit, payment and duration_days in guild wars)") + + db.query([[ + ALTER TABLE `guild_wars` + ADD `frags_limit` smallint(4) UNSIGNED NOT NULL DEFAULT '0', + ADD `payment` bigint(13) UNSIGNED NOT NULL DEFAULT '0', + ADD `duration_days` tinyint(3) UNSIGNED NOT NULL DEFAULT '0' + ]]) + + return true end diff --git a/data-otservbr-global/migrations/44.lua b/data-otservbr-global/migrations/44.lua new file mode 100644 index 00000000000..86a6d8ffec1 --- /dev/null +++ b/data-otservbr-global/migrations/44.lua @@ -0,0 +1,3 @@ +function onUpdateDatabase() + return false -- true = There are others migrations file | false = this is the last migration file +end diff --git a/data-otservbr-global/scripts/creaturescripts/others/player_death.lua b/data-otservbr-global/scripts/creaturescripts/others/player_death.lua index 9e8bfbeca34..b848235ebae 100644 --- a/data-otservbr-global/scripts/creaturescripts/others/player_death.lua +++ b/data-otservbr-global/scripts/creaturescripts/others/player_death.lua @@ -84,24 +84,52 @@ function playerDeath.onDeath(player, corpse, killer, mostDamageKiller, unjustifi if byPlayer == 1 then local targetGuild = player:getGuild() - targetGuild = targetGuild and targetGuild:getId() or 0 - if targetGuild ~= 0 then + local targetGuildId = targetGuild and targetGuild:getId() or 0 + if targetGuildId ~= 0 then local killerGuild = killer:getGuild() - killerGuild = killerGuild and killerGuild:getId() or 0 - if killerGuild ~= 0 and targetGuild ~= killerGuild and isInWar(player:getId(), killer.uid) then + local killerGuildId = killerGuild and killerGuild:getId() or 0 + if killerGuildId ~= 0 and targetGuildId ~= killerGuildId and isInWar(player:getId(), killer:getId()) then local warId = false resultId = db.storeQuery("SELECT `id` FROM `guild_wars` WHERE `status` = 1 AND \z - ((`guild1` = " .. killerGuild .. " AND `guild2` = " .. targetGuild .. ") OR \z - (`guild1` = " .. targetGuild .. " AND `guild2` = " .. killerGuild .. "))") - if resultId ~= false then + ((`guild1` = " .. killerGuildId .. " AND `guild2` = " .. targetGuildId .. ") OR \z + (`guild1` = " .. targetGuildId .. " AND `guild2` = " .. killerGuildId .. "))") + if resultId then warId = Result.getNumber(resultId, "id") Result.free(resultId) end - if warId ~= false then + if warId then + local playerName = player:getName() db.asyncQuery("INSERT INTO `guildwar_kills` (`killer`, `target`, `killerguild`, `targetguild`, `time`, `warid`) \z - VALUES (" .. db.escapeString(killerName) .. ", " .. db.escapeString(player:getName()) .. ", " .. killerGuild .. ", \z - " .. targetGuild .. ", " .. os.time() .. ", " .. warId .. ")") + VALUES (" .. db.escapeString(killerName) .. ", " .. db.escapeString(playerName) .. ", " .. killerGuildId .. ", \z + " .. targetGuildId .. ", " .. os.time() .. ", " .. warId .. ")") + + resultId = db.storeQuery("SELECT `guild_wars`.`id`, `guild_wars`.`frags_limit`, (SELECT COUNT(1) FROM `guildwar_kills` \z + WHERE `guildwar_kills`.`warid` = `guild_wars`.`id` AND `guildwar_kills`.`killerguild` = `guild_wars`.`guild1`) AS guild1_kills, \z + (SELECT COUNT(1) FROM `guildwar_kills` WHERE `guildwar_kills`.`warid` = `guild_wars`.`id` AND `guildwar_kills`.`killerguild` = `guild_wars`.`guild2`) AS guild2_kills \z + FROM `guild_wars` WHERE (`guild1` = " .. killerGuildId .. " OR `guild2` = " .. killerGuildId .. ") AND `status` = 1 AND `id` = " .. warId) + + if resultId then + local guild1_kills = Result.getNumber(resultId, "guild1_kills") + local guild2_kills = Result.getNumber(resultId, "guild2_kills") + local frags_limit = Result.getNumber(resultId, "frags_limit") + Result.free(resultId) + + local members = killerGuild:getMembersOnline() + for i = 1, #members do + members[i]:sendChannelMessage(members[i], string.format("%s was killed by %s. The new score is: %s %d:%d %s (frags limit: %d)", playerName, killerName, targetGuild:getName(), guild1_kills, guild2_kills, killerGuild:getName(), frags_limit), TALKTYPE_CHANNEL_R1, CHANNEL_GUILD) + end + + local enemyMembers = targetGuild:getMembersOnline() + for i = 1, #enemyMembers do + enemyMembers[i]:sendChannelMessage(enemyMembers[i], string.format("%s was killed by %s. The new score is: %s %d:%d %s (frags limit: %d)", playerName, killerName, targetGuild:getName(), guild1_kills, guild2_kills, killerGuild:getName(), frags_limit), TALKTYPE_CHANNEL_R1, CHANNEL_GUILD) + end + + if guild1_kills >= frags_limit or guild2_kills >= frags_limit then + db.query("UPDATE `guild_wars` SET `status` = 4, `ended` = " .. os.time() .. " WHERE `status` = 1 AND `id` = " .. warId) + Game.broadcastMessage(string.format("%s has just won the war against %s.", killerGuild:getName(), targetGuild:getName())) + end + end end end end diff --git a/data-otservbr-global/scripts/globalevents/others/guild_war.lua b/data-otservbr-global/scripts/globalevents/others/guild_war.lua index f34828b1fa7..41238755494 100644 --- a/data-otservbr-global/scripts/globalevents/others/guild_war.lua +++ b/data-otservbr-global/scripts/globalevents/others/guild_war.lua @@ -1,9 +1,10 @@ local guildWar = GlobalEvent("guildwar") + function guildWar.onThink(interval) local time = os.time() - db.query("UPDATE `guild_wars` SET `status` = 4, `ended` = " .. time .. " WHERE `status` = 1 AND (`started` + 5 * 60 * 60) < " .. time) + db.query("UPDATE `guild_wars` SET `status` = 4, `ended` = " .. time .. " WHERE `status` = 1 AND `ended` != 0 AND `ended` < " .. time) return true end -guildWar:interval(100000) +guildWar:interval(60000) guildWar:register() diff --git a/schema.sql b/schema.sql index 1eeb78fcd14..58e6ea216ce 100644 --- a/schema.sql +++ b/schema.sql @@ -7,7 +7,7 @@ CREATE TABLE IF NOT EXISTS `server_config` ( CONSTRAINT `server_config_pk` PRIMARY KEY (`config`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -INSERT INTO `server_config` (`config`, `value`) VALUES ('db_version', '43'), ('motd_hash', ''), ('motd_num', '0'), ('players_record', '0'); +INSERT INTO `server_config` (`config`, `value`) VALUES ('db_version', '44'), ('motd_hash', ''), ('motd_num', '0'), ('players_record', '0'); -- Table structure `accounts` CREATE TABLE IF NOT EXISTS `accounts` ( @@ -312,9 +312,12 @@ CREATE TABLE IF NOT EXISTS `guild_wars` ( `guild2` int(11) NOT NULL DEFAULT '0', `name1` varchar(255) NOT NULL, `name2` varchar(255) NOT NULL, - `status` tinyint(2) NOT NULL DEFAULT '0', + `status` tinyint(2) UNSIGNED NOT NULL DEFAULT '0', `started` bigint(15) NOT NULL DEFAULT '0', `ended` bigint(15) NOT NULL DEFAULT '0', + `frags_limit` smallint(4) UNSIGNED NOT NULL DEFAULT '0', + `payment` bigint(13) UNSIGNED NOT NULL DEFAULT '0', + `duration_days` tinyint(3) UNSIGNED NOT NULL DEFAULT '0', INDEX `guild1` (`guild1`), INDEX `guild2` (`guild2`), CONSTRAINT `guild_wars_pk` PRIMARY KEY (`id`) diff --git a/src/io/ioguild.cpp b/src/io/ioguild.cpp index 115d688c89a..99e1e750676 100644 --- a/src/io/ioguild.cpp +++ b/src/io/ioguild.cpp @@ -60,7 +60,7 @@ uint32_t IOGuild::getGuildIdByName(const std::string &name) { void IOGuild::getWarList(uint32_t guildId, GuildWarVector &guildWarVector) { std::ostringstream query; - query << "SELECT `guild1`, `guild2` FROM `guild_wars` WHERE (`guild1` = " << guildId << " OR `guild2` = " << guildId << ") AND `ended` = 0 AND `status` = 1"; + query << "SELECT `guild1`, `guild2` FROM `guild_wars` WHERE (`guild1` = " << guildId << " OR `guild2` = " << guildId << ") AND `status` = 1"; DBResult_ptr result = Database::getInstance().storeQuery(query.str()); if (!result) {