landsandboat/modules/custom/lua/world_first_announcements.lua
2025-10-31 22:41:37 -05:00

111 lines
4.2 KiB
Lua

-----------------------------------
-- World First Announcements
--
-- Send worldwide messages when certain conditions are met for the first time.
--
-- NOTE: GetVolatileServerVariable/SetVolatileServerVariable are cached, so are cheap to use every time (*apart from the first).
-- : It is recommended you go and look at the implementation to see how these work.
--
-- You can look up who did what with this SQL query:
-- SELECT
-- server_variables.`name`, chars.charname
-- FROM
-- server_variables
-- INNER JOIN
-- chars ON server_variables.value = chars.charid
-- WHERE
-- server_variables.`name` LIKE "WF_%" OR
-- server_variables.`name` LIKE "WT_%"
-----------------------------------
require('modules/module_utils')
require('scripts/globals/mobs')
require('scripts/globals/player')
-----------------------------------
local m = Module:new('world_first_announcements')
local openingDecoration = '\129\154'
local closingDecoration = '\129\154'
local checkWorldFirstServerVar = function(player, varName, worldMessage)
local worldFirst = string.format('WF_%s', varName)
local worldTime = string.format('WT_%s', varName)
if GetVolatileServerVariable(worldFirst) == 0 then -- Record hasn't been set yet
local decoratedMessage = string.format('%s %s %s', openingDecoration, worldMessage, closingDecoration)
-- Sends announcement via ZMQ to all processes and zones
player:printToArea(decoratedMessage, xi.msg.channel.SYSTEM_3, xi.msg.area.SYSTEM, '', false)
-- Write out World First (WF) and World First Time (WT) to server vars)
SetVolatileServerVariable(worldFirst, player:getID())
SetVolatileServerVariable(worldTime, GetSystemTime())
-- Summon big swirly starry animation which lingers on the players client in the location
-- where this event happened. It will linger in that area for anyone that saw it until
-- they zone.
-- player:independentAnimation(player, 12, 3)
end
end
m:addOverride('xi.player.onPlayerDeath', function(player)
super(player)
checkWorldFirstServerVar(player,
'PLAYER_DEATH',
string.format('%s has been the first player to die!', player:getName()))
end)
m:addOverride('xi.player.onPlayerLevelUp', function(player)
super(player)
checkWorldFirstServerVar(player,
'PLAYER_LEVEL_UP',
string.format('%s has been the first player to level up!', player:getName()))
local levelMilestones = { 10, 20, 30, 40, 50, 60, 70, 75, 80, 90, 99 }
for _, level in pairs(levelMilestones) do
if player:getMainLvl() == level then
checkWorldFirstServerVar(player,
string.format('JOB_%u_%s', level, xi.jobName[player:getMainJob()][1]),
string.format('%s has been the first player to reach level %u on %s!', player:getName(), level, xi.jobName[player:getMainJob()][2]))
end
end
end)
m:addOverride('xi.player.onPlayerLevelDown', function(player)
super(player)
checkWorldFirstServerVar(player,
'PLAYER_LEVEL_DOWN',
string.format('%s has been the first player to level down!', player:getName()))
end)
m:addOverride('xi.mob.onMobDeathEx', function(mob, player, isKiller, isWeaponSkillKill)
super(mob, player, isKiller, isWeaponSkillKill)
if mob:isNM() and isKiller then
local nmName, _ = string.gsub(mob:getName(), '_', ' ')
checkWorldFirstServerVar(player,
'NM_KILL_' .. string.upper(mob:getName()),
string.format('%s has been killed for the first time by %s!', nmName, player:getName()))
end
end)
--[[
NOTE: For this to work, the quest 'ELDER_MEMORIES' will need to be adjusted to use npcUtil.completeQuest,
: or be rewritten to use the interaction framework.
m:addOverride('npcUtil.completeQuest', function(player, area, quest, params)
local result = super(player, area, quest, params)
if result and area == xi.quest.log_id.OTHER_AREAS and quest == xi.quest.id.otherAreas.ELDER_MEMORIES then
checkWorldFirstServerVar(player,
'UNLOCK_SJ',
string.format('%s has been the first player to unlock their subjob!', player:getName()))
end
return result
end)
]]
return m