landsandboat/modules/custom/lua/claim_shield.lua

172 lines
5.7 KiB
Lua

-----------------------------------
-- Claim Shield
-----------------------------------
require('modules/module_utils')
-----------------------------------
local m = Module:new('claim_shield')
local claimshieldTime = 7500
-- NOTE: These names are as they are as filenames.
-- Example: Behemoth's Dominion => Behemoths_Dominion
-- Example: King Behemoth => King_Behemoth
-- { zone name, mob name }
-- Format:
local nmsToShield =
{
{ 'Attohwa_Chasm', 'Citipati' },
{ 'Attohwa_Chasm', 'Tiamat' },
{ 'Attohwa_Chasm', 'Xolotl' },
{ 'Caedarva_Mire', 'Khimaira' },
{ 'Castle_Oztroja', 'Mee_Deggi_the_Punisher' },
{ 'Castle_Oztroja', 'Quu_Domi_the_Gallant' },
{ 'FeiYin', 'Capricious_Cassie' },
{ 'FeiYin', 'Eastern_Shadow' },
{ 'FeiYin', 'Northern_Shadow' },
{ 'FeiYin', 'Southern_Shadow' },
{ 'FeiYin', 'Western_Shadow' },
{ 'Garlaige_Citadel', 'Serket' },
{ 'Giddeus', 'Hoo_Mjuu_the_Torrent' },
{ 'Gustav_Tunnel', 'Bune' },
{ 'Jugner_Forest', 'King_Arthro' },
{ 'King_Ranperres_Tomb', 'Vrtra' },
{ 'Labyrinth_of_Onzozo', 'Lord_of_Onzozo' },
{ 'Lufaise_Meadows', 'Padfoot' },
{ 'Maze_of_Shakhrami', 'Argus' },
{ 'Maze_of_Shakhrami', 'Leech_King' },
{ 'Mount_Zhayolm', 'Cerberus' },
{ 'Rolanberry_Fields', 'Eldritch_Edge' },
{ 'Rolanberry_Fields', 'Simurgh' },
{ 'Rolanberry_Fields_[S]', 'Lamina' },
{ 'Sauromugue_Champaign', 'Blighting_Brand' },
{ 'Sauromugue_Champaign', 'Roc' },
{ 'Sauromugue_Champaign_[S]', 'Hyakinthos' },
{ 'Sea_Serpent_Grotto', 'Charybdis' },
{ 'South_Gustaberg', 'Leaping_Lizzy' },
{ 'Uleguerand_Range', 'Jormungand' },
{ 'Valkurm_Dunes', 'Valkurm_Emperor' },
{ 'Wajaom_Woodlands', 'Hydra' },
{ 'Western_Altepa_Desert', 'King_Vinegarroon' },
}
-- Find the position of a target entity in a table,
-- only if they have matching ids
local tableFindPosByID = function(t, target)
for index, entity in ipairs(t) do
if entity:getID() == target:getID() then
return index
end
end
return nil
end
-- Using entity ids: dedupe a table in-place
local dedupeByID = function(t)
local seen = {}
for index, entity in ipairs(t) do
if seen[entity:getID()] then
table.remove(t, index)
else
seen[entity:getID()] = true
end
end
end
-- Called when the claimshield period ends
local timerFunc = function(mob)
local enmityList = mob:getEnmityList()
-- Filter so that pets will only count as a single entry along
-- with their masters
local entries = {}
for _, v in pairs(enmityList) do
local entity = v['entity']
local master = entity:getMaster()
if
not entity:isPC() and
master and
master:isPC()
then
table.insert(entries, master)
else
table.insert(entries, entity)
end
end
-- Remove duplicates from entries table caused by pets or other shenanigans
dedupeByID(entries)
local numEntries = #entries
mob:setMobMod(xi.mobMod.CLAIM_TYPE, xi.claimType.EXCLUSIVE)
mob:setUnkillable(false)
mob:setCallForHelpBlocked(false)
mob:resetAI()
mob:setHP(mob:getMaxHP())
mob:delStatusEffectsByFlag(0xFFFF) -- Delete all effects with all flags
-- Select a winner
local claimWinner = utils.randomEntry(entries)
if claimWinner then
mob:updateClaim(claimWinner)
-- Message winner and their party/alliance that they've won
local alliance = claimWinner:getAlliance()
for _, member in pairs(alliance) do
local str = string.format('Your group has won the lottery for %s! (out of %i players)', mob:getPacketName(), numEntries)
if #alliance == 1 then
str = string.format('You have won the lottery for %s! (out of %i players)', mob:getPacketName(), numEntries)
end
member:printToPlayer(str, xi.msg.channel.SYSTEM_3, '')
-- Remove from entries table
local pos = tableFindPosByID(entries, member)
if pos then
table.remove(entries, pos)
end
end
-- Everyone left in the entries table isn't part of the winning group, message them and
-- clear them from the enmity list
for _, member in pairs(entries) do
local str = string.format('Your group was not successful in the lottery for %s. (out of %i players)', mob:getPacketName(), numEntries)
if #alliance == 1 then
str = string.format('Your were not successful in the lottery for %s. (out of %i players)', mob:getPacketName(), numEntries)
end
member:printToPlayer(str, xi.msg.channel.SYSTEM_3, '')
mob:clearEnmityForEntity(member)
end
end
end
-- Called on entity onMobSpawn, sets up timerFunc
local listenerFunc = function(mob)
print(string.format('Applying Claimshield to %s for %ims', mob:getPacketName(), claimshieldTime))
mob:setMobMod(xi.mobMod.CLAIM_TYPE, xi.claimType.UNCLAIMABLE)
mob:setUnkillable(true)
mob:setCallForHelpBlocked(true)
mob:stun(claimshieldTime)
mob:timer(claimshieldTime, timerFunc)
end
-- Main entrypoint of each override
local overrideFunc = function(mob)
mob:addListener('SPAWN', string.format('%s_CS_SPAWN', mob:getPacketName()), listenerFunc)
-- Call original onMobInitialize
super(mob)
end
-- NOTE: At the time we iterate over these entries, the Lua zone and mob objects won't be ready,
-- : so we deal with everything as strings for now.
for _, entry in pairs(nmsToShield) do
m:addOverride(string.format('xi.zones.%s.mobs.%s.onMobInitialize', entry[1], entry[2]), overrideFunc)
end
return m