Stellow
C++/C#/PHP/LUA
Hello *,
this set of scripts provides a War System for Nostalrius 7.7.
Features:
Commands:
- !war invite, guildname
Invite guildname to war.
- !war invite, guildname, fraglimit
Invite guildname to war for fraglimit frags.
- !war cancel, guildname
Cancel invitation to war against guildname.
- !war reject, guildname
Reject invitation to war from guildname.
- !war end, guildname
Request war armistice with guildname.
data/talkactions/Talkactions.xml (add line)
data/talkactions/custom/war.lua (create file)
data/creaturescripts/playerdeath.lua (replace)
data/lib/core/core.lua (add line)
data/lib/core/guildwars.lua (create file)
data/global.lua (add)
luascript.h (add)
Replace
With
luascript.cpp (add)
player.h
Replace
With
Remove
Remove
Remove
player.cpp
Replace
With
Replace
With
Replace
With
Remove
Replace
With
Remove
iologindata.cpp
Remove
ioguild.h
Remove
Remove
ioguild.cpp
Remove
chat.cpp
Replace
With
Replace
With
MYSQL
this set of scripts provides a War System for Nostalrius 7.7.
Features:
- broadcast messages on the guild channel (killing, deaths, war status)
- green skull for enemies
- configure limit of frags
- no unjustified kill upon enemy killing
- cancel, reject war invitation
- create armistice with running war
Commands:
- !war invite, guildname
Invite guildname to war.
- !war invite, guildname, fraglimit
Invite guildname to war for fraglimit frags.
- !war cancel, guildname
Cancel invitation to war against guildname.
- !war reject, guildname
Reject invitation to war from guildname.
- !war end, guildname
Request war armistice with guildname.
data/talkactions/Talkactions.xml (add line)
XML:
<talkaction words="!war" separator=" " script="custom/war.lua"/>
data/talkactions/custom/war.lua (create file)
Lua:
--
-- Created by IntelliJ IDEA.
-- User: eubrunomiguel
-- Date: 2020-05-10
-- Time: 12:49
-- To change this template use File | Settings | File Templates.
--
function onSay(player, words, param)
if not player:getGuild() or player:getGuildLevel() < 3 then
player:sendCancelMessage("You cannot execute this talkaction.")
return true
end
local t = param:split(",")
if not t[2] then
player:sendCancelMessage("Not enough param(s).")
return true
end
local enemyGuildName = string.trim(t[2])
local enemyGuild = Guild(getGuildId(enemyGuildName))
if not enemyGuild then
player:sendCancelMessage("Guild \"" .. guildName .. "\" does not exists.")
return true
end
if enemyGuild:getId() == player:getGuild():getId() then
player:sendCancelMessage("You cannot perform war action on your own guild.")
return true
end
local warCommand = string.trim(t[1])
if isInArray({"accept", "reject", "cancel"}, warCommand) then
local pendingWarId = 0
if warCommand == "cancel" then
pendingWarId = guildwars:getPendingInvitation(player:getGuild():getId(), enemyGuild:getId())
else
pendingWarId = guildwars:getPendingInvitation(enemyGuild:getId(), player:getGuild():getId())
end
if pendingWarId == 0 then
player:sendCancelMessage("Currently there's no pending invitation for a war with " .. enemyGuild:getName() .. ".")
return true
end
if warCommand == "reject" then
guildwars:rejectWar(pendingWarId, player:getGuild(), enemyGuild)
elseif warCommand == "cancel" then
guildwars:cancelWar(pendingWarId, player:getGuild(), enemyGuild)
else
guildwars:startWar(pendingWarId, player:getGuild(), enemyGuild)
end
return true
end
if warCommand == "invite" then
guildwars:invite(player:getGuild(), enemyGuild, tonumber(t[3] and string.trim(t[3]) or 100))
return true
end
if isInArray({"end", "finish"}, warCommand) then
if not guildwars:acceptRequestToEndWar(player:getGuild(), enemyGuild) then
if not guildwars:requestToEndWar(enemyGuild, player:getGuild()) then
player:sendCancelMessage("Currently there's no active war with " .. enemyGuild:getName() .. ".")
end
end
return true
end
return true
end
data/creaturescripts/playerdeath.lua (replace)
Lua:
local deathListEnabled = true
local maxDeathRecords = 50
function onDeath(player, corpse, killer, mostDamageKiller, unjustified, mostDamageUnjustified)
local playerId = player:getId()
player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "You are dead.")
-- restart blessings values
player:setStorageValue(101,0)
player:setStorageValue(102,0)
player:setStorageValue(103,0)
player:setStorageValue(104,0)
player:setStorageValue(105,0)
if not deathListEnabled then
return
end
local byPlayer = false
local killerName
if killer ~= nil then
if killer:isPlayer() then
byPlayer = true
else
local master = killer:getMaster()
if master and master ~= killer and master:isPlayer() then
killer = master
byPlayer = true
end
end
killerName = killer:getName()
else
killerName = "field item"
end
local byPlayerMostDamage = 0
local mostDamageKillerName
if mostDamageKiller ~= nil then
if mostDamageKiller:isPlayer() then
byPlayerMostDamage = 1
else
local master = mostDamageKiller:getMaster()
if master and master ~= mostDamageKiller and master:isPlayer() then
mostDamageKiller = master
byPlayerMostDamage = 1
end
end
mostDamageName = mostDamageKiller:getName()
else
mostDamageName = "field item"
end
local playerGuid = player:getGuid()
db.query("INSERT INTO `player_deaths` (`player_id`, `time`, `level`, `killed_by`, `is_player`, `mostdamage_by`, `mostdamage_is_player`, `unjustified`, `mostdamage_unjustified`) VALUES (" .. playerGuid .. ", " .. os.time() .. ", " .. player:getLevel() .. ", " .. db.escapeString(killerName) .. ", " .. (byPlayer and 1 or 0) .. ", " .. db.escapeString(mostDamageName) .. ", " .. byPlayerMostDamage .. ", " .. (unjustified and 1 or 0) .. ", " .. (mostDamageUnjustified and 1 or 0) .. ")")
local resultId = db.storeQuery("SELECT `player_id` FROM `player_deaths` WHERE `player_id` = " .. playerGuid)
local deathRecords = 0
local tmpResultId = resultId
while tmpResultId ~= false do
tmpResultId = result.next(resultId)
deathRecords = deathRecords + 1
end
if resultId ~= false then
result.free(resultId)
end
local limit = deathRecords - maxDeathRecords
if limit > 0 then
db.asyncQuery("DELETE FROM `player_deaths` WHERE `player_id` = " .. playerGuid .. " ORDER BY `time` LIMIT " .. limit)
end
if not byPlayer then
return
end
local warId = guildwars:isInWar(killer, player)
if warId ~= 0 then
guildwars:processKill(warId, killer, player)
end
end
data/lib/core/core.lua (add line)
Code:
dofile('data/lib/core/guildwars.lua')
data/lib/core/guildwars.lua (create file)
Lua:
--
-- Created by IntelliJ IDEA.
-- User: eubrunomiguel
-- Date: 2020-05-23
-- Time: 08:37
-- To change this template use File | Settings | File Templates.
--
guildwars = {}
guildwars.__index = guildwars
function guildwars:isInWar(player1, player2)
if not player1:getGuild() or not player2:getGuild() then
return 0
end
if player1:getGuild():getId() == 0 or player2:getGuild():getId() == 0 then
return 0
end
if player1:getGuild():getId() == player2:getGuild():getId() then
return 0
end
return isInWar(player1:getId(), player2:getId())
end
function guildwars:processKill(warId, killer, player)
local fragLimit = self:getFragLimit(warId)
local killerFrags = self:getKills(warId, killer:getGuild():getId()) + 1
local deadFrags = self:getKills(warId, player:getGuild():getId())
local killerMsg = "Opponent " .. player:getName() .. " of the " .. player:getGuild():getName() .. " was killed by " .. killer:getName() .. ". The new score is " .. killerFrags .. ":" .. deadFrags .. " frags (limit " .. fragLimit .. ")."
killer:guildBroadcast(killerMsg)
local deadMsg = "Guild member " .. player:getName() .. " was killed by " .. killer:getName() .. " of the " .. killer:getGuild():getName() .. ". The new score is " .. deadFrags .. ":" .. killerFrags .. " frags (limit " .. fragLimit .. ")."
player:guildBroadcast(deadMsg)
self:insertKill(warId, killer, player)
if killerFrags >= fragLimit then
self:endWar(warId, killer, player, killerFrags)
end
end
function guildwars:getFragLimit(warId)
local resultId = db.storeQuery("SELECT `frag_limit` FROM `guild_wars` WHERE `id` = " .. warId)
if resultId ~= false then
local frag_limit = result.getDataInt(resultId, "frag_limit")
result.free(resultId)
return frag_limit
end
return 0
end
function guildwars:getKills(warId, guildId)
local resultId = db.storeQuery("SELECT COUNT(*) as frags FROM `guildwar_kills` WHERE `warid` = " .. warId .. " and `killerguild` = " .. guildId)
if resultId ~= false then
local frags = result.getDataInt(resultId, "frags")
result.free(resultId)
return frags
end
return 0
end
function guildwars:insertKill(warId, killer, target)
db.asyncQuery("INSERT INTO `guildwar_kills` (`killer`, `target`, `killerguild`, `targetguild`, `warid`) VALUES (" .. db.escapeString(killer:getName()) .. ", " .. db.escapeString(target:getName()) .. ", " .. killer:getGuild():getId() .. ", " .. target:getGuild():getId() .. ", " .. warId .. ")")
end
function guildwars:endWar(warId, killer, player, frags)
local winGuildInternalMessage = "Congratulations! You have won the war against " .. player:getGuild():getName() .. " with " .. frags .. " frags."
killer:guildBroadcast(winGuildInternalMessage)
local loseGuildInternalMessage = "You have lost the war against " .. killer:getGuild():getName() .. ". They have reached the limit of " .. frags .. " frags."
player:guildBroadcast(loseGuildInternalMessage)
broadcastMessage(killer:getGuild():getName() .. " have won the war against " .. player:getGuild():getName() .. " with " .. frags .. " frags.", MESSAGE_EVENT_ADVANCE)
self:updateState(warId, 5)
self:setWarEmblem(killer:getGuild(), player:getGuild(), 0)
end
function guildwars:setWarEmblem(guild1, guild2, emblem)
local guild1Members = guild1:getMembersOnline()
for i = #guild1Members, 1, -1 do
guild1Members[i]:setSkull(emblem)
end
local guild2Members = guild2:getMembersOnline()
for i = #guild2Members, 1, -1 do
guild2Members[i]:setSkull(emblem)
end
end
function guildwars:updateState(warId, status)
db.asyncQuery("UPDATE `guild_wars` SET `status` = " .. status .. " WHERE `id` = " .. warId)
end
function guildwars:getPendingInvitation(guild1, guild2)
local resultId = db.storeQuery("SELECT `id` FROM `guild_wars` WHERE `guild1` = " .. guild1 .. " AND `guild2` = " .. guild2 .. " AND `status` = 0")
if resultId then
local id = result.getDataInt(resultId, "id")
result.free(resultId)
return id
end
return 0
end
function guildwars:startWar(warId, guild1, guild2)
self:updateState(warId, 1)
self:setWarEmblem(guild1, guild2, 2)
broadcastMessage(guild1:getName() .. " has accepted " .. guild2:getName() .. " invitation to war.", MESSAGE_EVENT_ADVANCE)
end
function guildwars:rejectWar(warId, guild1, guild2)
self:updateState(warId, 2)
broadcastMessage(guild1:getName() .. " has rejected " .. guild2:getName() .. " invitation to war.", MESSAGE_EVENT_ADVANCE)
end
function guildwars:cancelWar(warId, guild1, guild2)
self:updateState(warId, 3)
broadcastMessage(guild1:getName() .. " has canceled invitation to a war with " .. guild2:getName() .. ".", MESSAGE_EVENT_ADVANCE)
end
function guildwars:invite(guild1, guild2, frags)
local str = ""
local tmpQuery = db.storeQuery("SELECT `guild1`, `status` FROM `guild_wars` WHERE `guild1` IN (" .. guild1:getId() .. "," .. guild2:getId() .. ") AND `guild2` IN (" .. guild2:getId() .. "," .. guild1:getId() .. ") AND `status` IN (0, 1)")
if tmpQuery then
if result.getDataInt(tmpQuery, "status") == 0 then
if result.getDataInt(tmpQuery, "guild1") == guild1:getId() then
str = "You have already invited " .. guild2:getName() .. " to war."
else
str = guild2:getName() .. " have already invited you to war."
end
else
str = "You are already on a war with " .. guild2:getName() .. "."
end
result.free(tmpQuery)
end
if str ~= "" then
player:sendCancelMessage(str)
return true
end
frags = math.max(10, math.min(1000, frags))
db.asyncQuery("INSERT INTO `guild_wars` (`guild1`, `guild2`, `frag_limit`) VALUES (" .. guild1:getId() .. ", " .. guild2:getId() .. ", " .. frags .. ");")
broadcastMessage(guild1:getName() .. " has invited " .. guild2:getName() .. " to war for " .. frags .. " frags.", MESSAGE_EVENT_ADVANCE)
end
function guildwars:acceptRequestToEndWar(guild1, guild2)
local resultId = db.storeQuery("SELECT `id`, `status` FROM `guild_wars` WHERE `guild1` = " .. guild1:getId() .. " AND `guild2` = " .. guild2:getId() .. " AND `status` IN (1, 4)")
if resultId then
local warId = result.getDataInt(resultId, "id")
local status = result.getDataInt(resultId, "status")
result.free(resultId)
self:updateState(warId, 5)
broadcastMessage(guild1:getName() .. " has " .. (status == 4 and "mend fences" or "ended up a war") .. " with " .. guild2:getName() .. ".", MESSAGE_EVENT_ADVANCE)
self:setWarEmblem(guild1, guild2, 0)
return true
end
return false
end
function guildwars:requestToEndWar(guild1, guild2)
local resultId = db.storeQuery("SELECT `id` FROM `guild_wars` WHERE `guild1` = " .. guild1:getId() .. " AND `guild2` = " .. guild2:getId() .. " AND `status` = 1")
if resultId then
local warId = result.getDataInt(resultId, "id")
result.free(resultId)
self:updateState(warId, 4)
broadcastMessage(guild1:getName() .. " has signed an armstice declaration on a war with " .. guild2:getName() .. ".", MESSAGE_EVENT_ADVANCE)
return true
end
return false
end
data/global.lua (add)
Lua:
function isInArray(array, value, isCaseSensitive)
local compareLowerCase = false
if value ~= nil and type(value) == "string" and not isCaseSensitive then
value = string.lower(value)
compareLowerCase = true
end
if array == nil or value == nil then
return (array == value), nil
end
local t = type(array)
if t ~= "table" then
if compareLowerCase and t == "string" then
return (string.lower(array) == string.lower(value)), nil
else
return (array == value), nil
end
end
for k,v in pairs(array) do
local newV
if compareLowerCase and type(v) == "string" then
newV = string.lower(v)
else
newV = v
end
if newV == value then
return true, k
end
end
return false
end
luascript.h (add)
C++:
static int luaPlayerGuildBroadcast(lua_State* L);
Replace
C++:
pushBoolean(L, player->isInWar(targetPlayer));
C++:
lua_pushnumber(L, player->isInWar(targetPlayer));
luascript.cpp (add)
C++:
registerMethod("Player", "guildBroadcast", LuaScriptInterface::luaPlayerGuildBroadcast);
C++:
int LuaScriptInterface::luaPlayerGuildBroadcast(lua_State* L)
{
// player:guildBroadcast(text)
Player* player = getUserdata<Player>(L, 1);
if (!player || !player->getGuild()) {
lua_pushnil(L);
return 1;
}
const std::string& text = getString(L, 2);
g_chat->talkToChannel(*player, TALKTYPE_CHANNEL_R2, text, CHANNEL_GUILD, "");
pushBoolean(L, true);
return 1;
}
player.h
Replace
C++:
bool isInWar(const Player* player) const;
C++:
uint32_t isInWar(const Player* player) const;
Remove
C++:
bool isInWarList(uint32_t guild_id) const;
Remove
C++:
const GuildWarList& getGuildWarList() const {
return guildWarList;
}
Remove
C++:
RemoveGuildWarList guildWarList;
player.cpp
Replace
C++:
if (!Combat::isInPvpZone(this, targetPlayer) && !isInWar(targetPlayer)) {
C++:
if (!Combat::isInPvpZone(this, targetPlayer) && isInWar(targetPlayer) == 0) {
Replace
C++:
if (targetPlayer->getSkull() == SKULL_NONE && !isInWar(targetPlayer)) {
C++:
if (targetPlayer->getSkull() == SKULL_NONE && isInWar(targetPlayer) == 0) {
Replace
C++:
if (isInWar(player)) {
C++:
if (isInWar(player) != 0) {
Remove
C++:
bool Player::isInWarList(uint32_t guildId) const
{
...
}
Replace
C++:
bool Player::isInWar(const Player* targetPlayer) const
{
...
}
C++:
uint32_t Player::isInWar(const Player* targetPlayer) const
{
if (!targetPlayer || !guild) {
return false;
}
const Guild* targetPlayerGuild = targetPlayer->getGuild();
if (!targetPlayerGuild) {
return false;
}
const auto targetGuild = guild->getId();
const auto killerGuild = targetPlayerGuild->getId();
Database* db = Database::getInstance();
std::ostringstream query;
query << "SELECT `id` FROM `guild_wars` WHERE `status` = 1 AND ((`guild1` = " << killerGuild << " AND `guild2` = " << targetGuild << ") OR (`guild1` = " << targetGuild << " AND `guild2` = " << killerGuild << "))";
DBResult_ptr result = db->storeQuery(query.str());
if (!result) {
return 0;
}
return result->getNumber<uint32_t>("id");
}
Remove
C++:
if (!player->getGuildWarList().empty() && guild == player->getGuild()) {
return SKULL_GREEN;
}
iologindata.cpp
Remove
C++:
IOGuild::getWarList(guildId, player->guildWarList);
ioguild.h
Remove
C++:
typedef std::vector<uint32_t> GuildWarList;
Remove
C++:
static void getWarList(uint32_t guildId, GuildWarList& guildWarList);
ioguild.cpp
Remove
C++:
void IOGuild::getWarList(uint32_t guildId, GuildWarList& guildWarList){
...
}
chat.cpp
Replace
C++:
if (users.find(fromPlayer.getID()) == users.end()) {
C++:
if (type != TALKTYPE_CHANNEL_R2 && users.find(fromPlayer.getID()) == users.end()) {
Replace
C++:
if (channelId == CHANNEL_GUILD) {
C++:
if (channelId == CHANNEL_GUILD && type != TALKTYPE_CHANNEL_R2) {
MYSQL
SQL:
SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO";
SET AUTOCOMMIT = 0;
START TRANSACTION;
SET time_zone = "+00:00";
CREATE TABLE `guild_wars` (
`id` int(11) NOT NULL,
`guild1` int(11) NOT NULL DEFAULT '0',
`guild2` int(11) NOT NULL DEFAULT '0',
`status` tinyint(2) NOT NULL DEFAULT '0',
`frag_limit` int(11) NOT NULL DEFAULT '0',
`declaration_date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
ALTER TABLE `guild_wars`
ADD PRIMARY KEY (`id`),
ADD KEY `guild1` (`guild1`),
ADD KEY `guild2` (`guild2`);
ALTER TABLE `guild_wars`
MODIFY `id` int(11) NOT NULL AUTO_INCREMENT;
ALTER TABLE `guild_wars`
ADD CONSTRAINT `guild1_ibfk_1` FOREIGN KEY (`guild1`) REFERENCES `guilds` (`id`) ON DELETE CASCADE,
ADD CONSTRAINT `guild2_ibfk_1` FOREIGN KEY (`guild2`) REFERENCES `guilds` (`id`) ON DELETE CASCADE;
COMMIT;
Last edited: