Skip to content

Commit

Permalink
Move Skull system to lua
Browse files Browse the repository at this point in the history
  • Loading branch information
ramon-bernardo committed May 26, 2024
1 parent a271374 commit a4ae680
Show file tree
Hide file tree
Showing 13 changed files with 453 additions and 171 deletions.
4 changes: 0 additions & 4 deletions config.lua.dist
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,11 @@
worldType = "pvp"
hotkeyAimbotEnabled = true
protectionLevel = 1
killsToRedSkull = 3
killsToBlackSkull = 6
pzLocked = 60000
removeChargesFromRunes = true
removeChargesFromPotions = true
removeWeaponAmmunition = true
removeWeaponCharges = true
timeToDecreaseFrags = 24 * 60 * 60
whiteSkullTime = 15 * 60
stairJumpExhaustion = 2000
experienceByKillingPlayers = false
expFromPlayersLevelRange = 75
Expand Down
2 changes: 1 addition & 1 deletion data/cpplinter.lua
Original file line number Diff line number Diff line change
Expand Up @@ -942,7 +942,7 @@ TalkAction = {}
---@field onPrepareDeath fun(creature:Creature, killer:Creature):boolean
---@field onDeath fun(creature:Creature, corpse:Item, killer:Creature, mostDamageKiller:Creature, lastHitUnjustified:boolean, mostDamageUnjustified:boolean):boolean
---@field onAdvance fun(player:Player, skill:integer, oldLevel:integer, newLevel:integer):boolean
---@field onKill fun(player:Player, target:Creature):boolean
---@field onKill fun(player:Player, target:Creature, lastHit:boolean):boolean
---@field onTextEdit fun(player:Player, item:Item, text:string, windowTextId:integer):boolean
---@field onHealthChange fun(creature:Creature, attacker:Creature, primaryDamage:integer, primaryType:integer, secondaryDamage:integer, secondaryType:integer, origin:integer):integer, integer, integer, integer
---@field onManaChange fun(creature:Creature, attacker:Creature, primaryDamage:integer, primaryType:integer, secondaryDamage:integer, secondaryType:integer, origin:integer):integer, integer, integer, integer
Expand Down
106 changes: 64 additions & 42 deletions data/creaturescripts/scripts/player_death.lua
Original file line number Diff line number Diff line change
@@ -1,6 +1,26 @@
local deathListEnabled = true
local deleteRecords = true
local maxDeathRecords = 5

local function takeScreenshot(player, killer, killedByPlayer, mostDamageKiller)
player:takeScreenshot(killedByPlayer and SCREENSHOT_TYPE_DEATHPVP or SCREENSHOT_TYPE_DEATHPVE)

if killedByPlayer then
killer:takeScreenshot(SCREENSHOT_TYPE_PLAYERKILL)
end

if mostDamageKiller and mostDamageKiller:isPlayer() then
mostDamageKiller:takeScreenshot(SCREENSHOT_TYPE_PLAYERKILL)
end
end

local function updateStamina(player)
local playerId = player:getId()
if nextUseStaminaTime[playerId] then
nextUseStaminaTime[playerId] = nil
end
end

local function getKiller(killer)
if not killer then
return false, "field item"
Expand All @@ -18,33 +38,13 @@ local function getKiller(killer)
return false, killer:getName()
end

function onDeath(player, corpse, killer, mostDamageKiller, lastHitUnjustified, mostDamageUnjustified)
local playerId = player:getId()
if nextUseStaminaTime[playerId] then
nextUseStaminaTime[playerId] = nil
end

player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "You are dead.")

local byPlayer, killerName = getKiller(killer)
local byPlayerMostDamage, killerNameMostDamage = getKiller(mostDamageKiller)

player:takeScreenshot(byPlayer and SCREENSHOT_TYPE_DEATHPVP or SCREENSHOT_TYPE_DEATHPVE)

if byPlayer then
killer:takeScreenshot(SCREENSHOT_TYPE_PLAYERKILL)
end

if mostDamageKiller and mostDamageKiller:isPlayer() then
mostDamageKiller:takeScreenshot(SCREENSHOT_TYPE_PLAYERKILL)
end

local function updateDeathList(player, corpse, killer, mostDamageKiller, lastHitUnjustified, mostDamageUnjustified, killedByPlayer, killerName, killedByPlayerMostDamage, killerNameMostDamage)
if not deathListEnabled then
return
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(killerNameMostDamage) .. ", " .. (byPlayerMostDamage and 1 or 0) .. ", " .. (lastHitUnjustified and 1 or 0) .. ", " .. (mostDamageUnjustified and 1 or 0) .. ")")
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) .. ", " .. (killedByPlayer and 1 or 0) .. ", " .. db.escapeString(killerNameMostDamage) .. ", " .. (killedByPlayerMostDamage and 1 or 0) .. ", " .. (lastHitUnjustified 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
Expand All @@ -59,28 +59,50 @@ function onDeath(player, corpse, killer, mostDamageKiller, lastHitUnjustified, m
end

local limit = deathRecords - maxDeathRecords
if limit > 0 then
if deleteRecords and limit > 0 then
db.asyncQuery("DELETE FROM `player_deaths` WHERE `player_id` = " .. playerGuid .. " ORDER BY `time` LIMIT " .. limit)
end

if byPlayer then
local targetGuild = player:getGuild()
targetGuild = targetGuild and targetGuild:getId() or 0
if targetGuild ~= 0 then
local killerGuild = killer:getGuild()
killerGuild = killerGuild and killerGuild:getId() or 0
if killerGuild ~= 0 and targetGuild ~= killerGuild and isInWar(playerId, killer:getId()) then
local warId = false
resultId = db.storeQuery("SELECT `id` FROM `guild_wars` WHERE `status` = 1 AND ((`guild1` = " .. killerGuild .. " AND `guild2` = " .. targetGuild .. ") OR (`guild1` = " .. targetGuild .. " AND `guild2` = " .. killerGuild .. "))")
if resultId then
warId = result.getNumber(resultId, "id")
result.free(resultId)
end

if warId then
db.asyncQuery("INSERT INTO `guildwar_kills` (`killer`, `target`, `killerguild`, `targetguild`, `time`, `warid`) VALUES (" .. db.escapeString(killerName) .. ", " .. db.escapeString(player:getName()) .. ", " .. killerGuild .. ", " .. targetGuild .. ", " .. os.time() .. ", " .. warId .. ")")
end
end
end
if not killedByPlayer then
return
end

local targetGuild = player:getGuild()
targetGuild = targetGuild and targetGuild:getId() or 0
if targetGuild == 0 then
return
end

local playerId = player:getId()
if not isInWar(playerId, killer:getId()) then
return
end

local killerGuild = killer:getGuild()
killerGuild = killerGuild and killerGuild:getId() or 0
if killerGuild == 0 or targetGuild == killerGuild then
return
end

local warId = nil
resultId = db.storeQuery("SELECT `id` FROM `guild_wars` WHERE `status` = 1 AND ((`guild1` = " .. killerGuild .. " AND `guild2` = " .. targetGuild .. ") OR (`guild1` = " .. targetGuild .. " AND `guild2` = " .. killerGuild .. "))")
if resultId then
warId = result.getNumber(resultId, "id")
result.free(resultId)
end

if warId then
db.asyncQuery("INSERT INTO `guildwar_kills` (`killer`, `target`, `killerguild`, `targetguild`, `time`, `warid`) VALUES (" .. db.escapeString(killerName) .. ", " .. db.escapeString(player:getName()) .. ", " .. killerGuild .. ", " .. targetGuild .. ", " .. os.time() .. ", " .. warId .. ")")
end
end

function onDeath(player, corpse, killer, mostDamageKiller, lastHitUnjustified, mostDamageUnjustified)
player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "You are dead.")

local killedByPlayer, killerName = getKiller(killer)
local killedByPlayerMostDamage, killerNameMostDamage = getKiller(mostDamageKiller)

takeScreenshot(player, killer, killedByPlayer, mostDamageKiller)
updateStamina(player)
updateDeathList(player, corpse, killer, mostDamageKiller, lastHitUnjustified, mostDamageUnjustified, killedByPlayer, killerName, killedByPlayerMostDamage, killerNameMostDamage)
end
229 changes: 229 additions & 0 deletions data/scripts/creaturescripts/player/skull_check.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,229 @@
local config = {
mode = "new", -- old or new
whiteSkullTime = 15 * 60 * 1000 -- 15 minutes
}

local newConfig = {
redDailyLimit = 3,
redWeeklyLimit = 5,
redMonthlyLimit = 10,
redSkullLength = 30 * 24 * 60 * 60, -- 30 days
blackDailyLimit = 6,
blackWeeklyLimit = 10,
blackMonthlyLimit = 20,
blackSkullLength = 45 * 24 * 60 * 60, -- 45 days
daysUnjustified = 30
}

local oldConfig = {
fragTime = 24 * 60 * 60, -- 24h
killsToRed = 3,
killsToBlack = 6
}

-- register event in player
local event = CreatureEvent("RegisterSkulls")

function event.onLogin(player)
player:registerEvent("SkullCheck")
player:registerEvent("SkullTick")
return true
end

event:register()

-- event to check when player kill another player
event = CreatureEvent("SkullCheck")

local inFight = Condition(CONDITION_INFIGHT, CONDITIONID_DEFAULT)
inFight:setParameter(CONDITION_PARAM_TICKS, config.whiteSkullTime)

-- New PVP system
local function getUnjustifiedDates(player, offsetTime, days)
local kills = {}

local resultId = db.storeQuery("SELECT `time` FROM `player_deaths` WHERE `killed_by` = " .. db.escapeString(player:getName()) .. " AND `unjustified` = 1 AND `time` >= " .. offsetTime - (days * 86400) .. "")
if resultId then
repeat
table.insert(kills, result.getNumber(resultId, "time"))
until not result.next(resultId)
result.free(resultId)
end

return kills
end

local function updateAttackerSkullNew(attacker, todayKills, weekKills, monthKills)
local attackerSkull = attacker:getSkull()
if attackerSkull == SKULL_BLACK then
attacker:setSkullTime(newConfig.blackSkullLength)
elseif attackerSkull == SKULL_RED then
local blackSkullLimitReached = newConfig.blackDailyLimit <= todayKills or newConfig.blackWeeklyLimit <= weekKills or newConfig.blackMonthlyLimit <= monthKills
if blackSkullLimitReached then
attacker:setSkull(SKULL_BLACK)
attacker:setSkullTime(newConfig.blackSkullLength)
else
attacker:setSkullTime(newConfig.redSkullLength)
end
else
local redSkullLimitReached = newConfig.redDailyLimit <= todayKills or newConfig.redWeeklyLimit <= weekKills or newConfig.redMonthlyLimit <= monthKills
if redSkullLimitReached then
attacker:setSkull(SKULL_RED)
attacker:setSkullTime(newConfig.redSkullLength)
end
end
end

local function updateAttackerNew(attacker)
local now = os.time()
local today = now - 86400
local week = now - (7 * 86400)

local kills = getUnjustifiedDates(attacker, now, newConfig.daysUnjustified)
table.insert(kills, now)

local todayKills = 0
local weekKills = 0
local monthKills = #kills

for _, time in pairs(kills) do
if time > today then
todayKills = todayKills + 1
end

if time > week then
weekKills = weekKills + 1
end
end

updateAttackerSkullNew(attacker, todayKills, weekKills, monthKills)
end

-- Old PVP system
local function updateAttackerSkullOld(attacker, skullTime)
local attackerSkull = attacker:getSkull()
if attackerSkull == SKULL_BLACK then
return
end

if oldConfig.killsToBlack > 0 then
local time = (oldConfig.killsToBlack - 1) * oldConfig.fragTime
if skullTime > time then
attacker:setSkull(SKULL_BLACK)
end
elseif oldConfig.killsToRed > 0 then
if attackerSkull == SKULL_RED then
return
end

local time = (oldConfig.killsToRed - 1) * oldConfig.fragTime
if skullTime > time then
attacker:setSkull(SKULL_RED)
end
end
end

local function updateAttackerOld(attacker)
local skullTime = attacker:getSkullTime() + oldConfig.fragTime
attacker:setSkullTime(skullTime)
updateAttackerSkullOld(attacker, skullTime)
end

-- PVP system
local function unjustifiedDead(attacker, target)
if Game.getWorldType() == WORLD_TYPE_PVP_ENFORCED then
return
end

if target:getSkull() ~= SKULL_NONE then
return
end

if target:hasFlag(PlayerFlag_NotGainInFight) then
return
end

if config.mode == "new" then
updateAttackerNew(attacker)
elseif config.mode == "old" then
updateAttackerOld(attacker)
end

attacker:sendTextMessage(MESSAGE_EVENT_ADVANCE, "Warning! The murder of " .. target:getName() .. " was not justified.")
end

function event.onKill(player, target, lastHit)
local targetPlayer = target:getPlayer()
if not targetPlayer then
return true
end

-- if the battle is in a PVP area, do not drop loot/loss skill from the target
if targetPlayer:getZone() == ZONE_PVP then
targetPlayer:setDropLoot(false)
targetPlayer:setSkillLoss(false)
return true
end

-- self attack
if player == targetPlayer then
return true
end

if player:getZone() == ZONE_PVP or player:hasFlag(PlayerFlag_NotGainInFight) then
return true
end

-- ignore when target from the same guild or party
if player:isGuildMate(targetPlayer) or player:isPartner(targetPlayer) then
return true
end

-- check if the player attacked and the target did not fight back.
if not player:hasAttacked(targetPlayer) or targetPlayer:hasAttacked(player) then
return true
end

if not player:isAtWarAgainst(targetPlayer) then
unjustifiedDead(player, targetPlayer)
end

if lastHit and player:hasCondition(CONDITION_INFIGHT) then
player:setPzLocked(true)
player:addCondition(inFight)
end
return true
end

event:register()

-- event to check skull ticks
event = CreatureEvent("SkullTick")

local function updatePlayerSkull(player, skullTime)
if skullTime > 0 then
return
end

if player:hasCondition(CONDITION_INFIGHT) then
return
end

local playerSkull = player:getSkull()
if playerSkull == SKULL_BLACK or playerSkull == SKULL_RED then
player:setSkull(SKULL_NONE)
end
end

function event.onThink(player, interval)
if Game.getWorldType() == WORLD_TYPE_PVP_ENFORCED then
return true
end

local skullTime = player:getSkullTime() - (interval / 1000)
player:setSkullTime(skullTime > 0 and skullTime or 0)
updatePlayerSkull(player, skullTime)
return true
end

event:register()
Loading

0 comments on commit a4ae680

Please sign in to comment.