322 lines
13 KiB
Lua
322 lines
13 KiB
Lua
-----------------------------------
|
|
-- Records of Eminence
|
|
-----------------------------------
|
|
require('scripts/globals/npc_util')
|
|
require('scripts/globals/quests')
|
|
require('scripts/globals/roe_records')
|
|
-----------------------------------
|
|
xi = xi or {}
|
|
xi.roe = xi.roe or {}
|
|
|
|
-----------------------------------
|
|
-- Checks
|
|
-----------------------------------
|
|
|
|
local checks =
|
|
{
|
|
mobID = function(self, player, params) -- Mob ID check
|
|
return (params.mob and self.reqs.mobID[params.mob:getID()]) and true or false
|
|
end,
|
|
|
|
mobName = function(self, player, params)
|
|
return (params.mob and self.reqs.mobName[params.mob:getName()]) and true or false
|
|
end,
|
|
|
|
mobXP = function(self, player, params) -- Mob yields xp
|
|
return (params.mob and player:checkKillCredit(params.mob)) and true or false
|
|
end,
|
|
|
|
mobSpecies = function(self, player, params) -- Mob species in set
|
|
return (params.mob and self.reqs.mobSpecies[params.mob:getSpecies()]) and true or false
|
|
end,
|
|
|
|
mobFamily = function(self, player, params) -- Mob super family in set
|
|
return (params.mob and self.reqs.mobFamily[params.mob:getFamily()]) and true or false
|
|
end,
|
|
|
|
mobSystem = function(self, player, params) -- Mob system in set
|
|
return (params.mob and self.reqs.mobSystem[params.mob:getEcosystem()]) and true or false
|
|
end,
|
|
|
|
dmgMin = function(self, player, params) -- Minimum Dmg Dealt/Taken
|
|
return (params.dmg and params.dmg >= self.reqs.dmgMin) and true or false
|
|
end,
|
|
|
|
dmgMax = function(self, player, params) -- Maximum Dmg Dealt/Taken
|
|
return (params.dmg and params.dmg <= self.reqs.dmgMax) and true or false
|
|
end,
|
|
|
|
atkType = function(self, player, params) -- Dmg Type is
|
|
return (params.atkType == self.reqs.atkType) and true or false
|
|
end,
|
|
|
|
healMin = function(self, player, params) -- Minimum Amount healed
|
|
return (params.heal and params.heal >= self.reqs.healMin) and true or false
|
|
end,
|
|
|
|
zone = function(self, player, params) -- Player in Zone
|
|
return (self.reqs.zone[player:getZoneID()]) and true or false
|
|
end,
|
|
|
|
zoneNot = function(self, player, params) -- Player not in Zone
|
|
return (not self.reqs.zoneNot[player:getZoneID()]) and true or false
|
|
end,
|
|
|
|
itemID = function(self, player, params) -- itemid in set
|
|
return (params.itemid and self.reqs.itemID[params.itemid]) and true or false
|
|
end,
|
|
|
|
levelSync = function(self, player, params) -- Player is Level Sync'd
|
|
return self.reqs.levelSync and player:hasStatusEffect(xi.effect.LEVEL_SYNC) and true or false
|
|
end,
|
|
|
|
jobLvl = function(self, player, params) -- Player has job at minimum level X
|
|
return player:getJobLevel(self.reqs.jobLvl[1]) >= self.reqs.jobLvl[2] and true or false
|
|
end,
|
|
|
|
questComplete = function(self, player, params) -- Player has { KINGDOM, QUEST } marked complete
|
|
return player:getQuestStatus(self.reqs.questComplete[1], self.reqs.questComplete[2]) == xi.questStatus.QUEST_COMPLETED
|
|
end,
|
|
|
|
missionComplete = function(self, player, params) -- Player has { NATION, MISSION } marked complete
|
|
return player:hasCompletedMission(self.reqs.missionComplete[1], self.reqs.missionComplete[2])
|
|
end,
|
|
|
|
unityLeader = function(self, player, params) -- Player is a member of the specified Unity (1..11)
|
|
return player:getUnityLeader() == self.reqs.unityLeader
|
|
end,
|
|
|
|
skillType = function(self, player, params) -- Generic numeric check, used for synthSuccess and helmSuccess
|
|
return params.skillType == self.reqs.skillType and true or false
|
|
end,
|
|
}
|
|
|
|
-- Main general check function for all-purpose use.
|
|
-- Some functions may specify custom handlers (ie. gain exp or deal dmg.)
|
|
local masterCheck = function(self, player, params)
|
|
for func in pairs(self.reqs) do
|
|
if not checks[func] or not checks[func](self, player, params) then
|
|
return false
|
|
end
|
|
end
|
|
|
|
return true
|
|
end
|
|
|
|
-----------------------------------
|
|
-- records
|
|
-----------------------------------
|
|
|
|
-- Schedule for Timed Records.
|
|
local timedSchedule =
|
|
{
|
|
-- 4-hour timeslots (6 per day) all days/times are in JST
|
|
-- 00-04 04-08 08-12 12-16 16-20 20-00
|
|
{ 4021, 4010, 4016, 4012, 4018, 4013 }, -- Sunday
|
|
{ 4015, 4011, 4017, 4014, 4019, 4008 }, -- Monday
|
|
{ 4016, 4012, 4018, 4013, 4020, 4009 }, -- Tuesday
|
|
{ 4017, 4014, 4019, 4008, 4021, 4010 }, -- Wednesday
|
|
{ 4018, 4013, 4020, 4009, 4015, 4011 }, -- Thursdsay
|
|
{ 4019, 4008, 4021, 4010, 4016, 4012 }, -- Friday
|
|
{ 4020, 4009, 4015, 4011, 4017, 4014 }, -- Saturday
|
|
}
|
|
|
|
local defaults =
|
|
{
|
|
check = masterCheck, -- Check function should return true/false
|
|
increment = 1, -- Amount to increment per successful check
|
|
notify = 1, -- Progress notifications shown every X increases
|
|
goal = 1, -- Progress goal
|
|
flags = {}, -- Special flags. This should be a set. Possible values:
|
|
-- 'timed' - 4-hour record.
|
|
-- 'repeat' - Repeatable record.
|
|
-- 'daily' - Daily record.
|
|
-- 'weekly' - Weekly record.
|
|
-- 'unity' - Weekly reset, but doesn't reset progress, only completion.
|
|
-- 'retro' - Can be claimed retroactively. Calls check on taking record.
|
|
-- 'hidden' - Special internal-use record used only as a client-flag to unlock others.
|
|
-- Does not count towards completed record count.
|
|
reqs = {}, -- Other requirements. List of function names from above, with required values.
|
|
reward = {}, -- Reward parameters give on completion. (See completeRecord directly below.)
|
|
}
|
|
|
|
xi.roe.initialize = function()
|
|
-- Apply defaults for records. Since this table may already exist in the global state,
|
|
-- check for missing entries first.
|
|
for recordId, _ in pairs(xi.roe.records) do
|
|
for defaultKey, defaultValue in pairs(defaults) do
|
|
if not xi.roe.records[recordId][defaultKey] then
|
|
xi.roe.records[recordId][defaultKey] = defaultValue
|
|
end
|
|
end
|
|
end
|
|
|
|
-- Build global map of implemented records.
|
|
-- This is used to deny taking records which aren't implemented in the above table.
|
|
RoeParseRecords(xi.roe.records)
|
|
|
|
-- Load timetable for timed records
|
|
if xi.settings.main.ENABLE_ROE and xi.settings.main.ENABLE_ROE_TIMED > 0 then
|
|
RoeParseTimed(timedSchedule)
|
|
end
|
|
end
|
|
|
|
xi.roe.initialize()
|
|
|
|
local function isRepeatItemRewardException(items)
|
|
local itemExceptionsMap =
|
|
{
|
|
[xi.item.SILT_POUCH] = true, -- Escha Bead/Silt rewards are always rewarded
|
|
[xi.item.BEAD_POUCH] = true, -- Escha Bead/Silt rewards are always rewarded
|
|
}
|
|
|
|
-- clone of npcUtil.giveItem logic
|
|
if type(items) == 'table' then
|
|
for _, v in pairs(items) do
|
|
if type(v) == 'number' then
|
|
if itemExceptionsMap[v] == nil then
|
|
return false -- if any item in the rewards list doesn't match, bail out
|
|
end
|
|
end
|
|
end
|
|
elseif type(items) == 'number' then
|
|
return itemExceptionsMap[items] ~= nil -- If the input is only an integer, then just check the map
|
|
end
|
|
|
|
return true
|
|
end
|
|
|
|
--[[ --------------------------------------------------------------------------
|
|
Complete a record of eminence. This is for internal roe use only.
|
|
For external calls use onRecordTrigger below. (see healing.lua for example)
|
|
If record rewards items, and the player cannot carry them, return false.
|
|
Otherwise, return true.
|
|
Example of usage + reward table (all params are optional):
|
|
|
|
completeRecord(player, record#)
|
|
reward =
|
|
{
|
|
item = { { 640, 2 }, 641 }, -- see npcUtil.giveItem for formats (Only given on first completion)
|
|
keyItem = xi.ki.ZERUHN_REPORT, -- see npcUtil.giveKeyItem for formats
|
|
sparks = 500,
|
|
xp = 1000,
|
|
accolades = 300,
|
|
capacity = 400,
|
|
})
|
|
--------------------------------------------------------------------------- --]]
|
|
local function completeRecord(player, record)
|
|
local recordEntry = xi.roe.records[record]
|
|
local recordFlags = recordEntry.flags
|
|
local rewards = recordEntry.reward
|
|
local canRewardItem = rewards['item'] and (not player:getEminenceCompleted(record) or isRepeatItemRewardException(rewards['item']))
|
|
|
|
if canRewardItem then
|
|
if not npcUtil.giveItem(player, rewards['item'], { silent = true }) then
|
|
player:messageBasic(xi.msg.basic.ROE_UNABLE_BONUS_ITEM)
|
|
return false
|
|
end
|
|
end
|
|
|
|
player:messageBasic(xi.msg.basic.ROE_COMPLETE, record)
|
|
|
|
if rewards['sparks'] ~= nil and type(rewards['sparks']) == 'number' then
|
|
local bonus = 1
|
|
if player:getEminenceCompleted(record) then
|
|
player:addCurrency('spark_of_eminence', rewards['sparks'] * bonus * xi.settings.main.SPARKS_RATE, xi.settings.main.CAP_CURRENCY_SPARKS)
|
|
player:messageBasic(xi.msg.basic.ROE_RECEIVE_SPARKS, rewards['sparks'] * xi.settings.main.SPARKS_RATE, player:getCurrency('spark_of_eminence'))
|
|
else
|
|
bonus = 3
|
|
player:addCurrency('spark_of_eminence', rewards['sparks'] * bonus * xi.settings.main.SPARKS_RATE, xi.settings.main.CAP_CURRENCY_SPARKS)
|
|
player:messageBasic(xi.msg.basic.ROE_FIRST_TIME_SPARKS, rewards['sparks'] * bonus * xi.settings.main.SPARKS_RATE, player:getCurrency('spark_of_eminence'))
|
|
end
|
|
end
|
|
|
|
if rewards['exp'] ~= nil and type(rewards['exp']) == 'number' then
|
|
player:addExp(rewards['exp'] * xi.settings.main.ROE_EXP_RATE)
|
|
end
|
|
|
|
if rewards['capacity'] ~= nil and type(rewards['capacity']) == 'number' then
|
|
player:addCapacityPoints(rewards['capacity'])
|
|
end
|
|
|
|
-- NOTE: To preserve retail order, messaging is here, but item is given if able at the beginning of this
|
|
-- function, since if it fails, it will need to bail out.
|
|
if canRewardItem then
|
|
local itemQty = type(rewards['item'][1]) == 'table' and rewards['item'][1][2] or 1
|
|
local itemId = type(rewards['item'][1]) == 'table' and rewards['item'][1][1] or rewards['item'][1]
|
|
local messageId = itemQty > 1 and xi.msg.basic.ROE_BONUS_ITEM_PLURAL or xi.msg.basic.ROE_BONUS_ITEM
|
|
|
|
player:messageBasic(messageId, itemId, itemQty)
|
|
end
|
|
|
|
if recordFlags['repeat'] then
|
|
if recordFlags['timed'] then
|
|
player:messageBasic(xi.msg.basic.ROE_TIMED_CLEAR)
|
|
else
|
|
player:messageBasic(xi.msg.basic.ROE_REPEAT_OR_CANCEL)
|
|
end
|
|
|
|
player:setEminenceCompleted(record, true)
|
|
else
|
|
player:setEminenceCompleted(record)
|
|
end
|
|
|
|
if
|
|
player:getUnityLeader() > 0 and
|
|
rewards['accolades'] ~= nil and
|
|
type(rewards['accolades']) == 'number'
|
|
then
|
|
local bonusAccoladeRate = 1.0
|
|
if record ~= 5 then -- Do not grant a bonus for All for One
|
|
bonusAccoladeRate = bonusAccoladeRate + ((player:getUnityRank() - 1) * 0.05)
|
|
end
|
|
|
|
local accoladePayout = math.floor(rewards['accolades'] * bonusAccoladeRate)
|
|
player:addCurrency('unity_accolades', accoladePayout, xi.settings.main.CAP_CURRENCY_ACCOLADES)
|
|
player:messageBasic(xi.msg.basic.ROE_RECEIVED_ACCOLADES, accoladePayout, player:getCurrency('unity_accolades'))
|
|
end
|
|
|
|
if rewards['keyItem'] ~= nil then
|
|
npcUtil.giveKeyItem(player, rewards['keyItem'])
|
|
end
|
|
|
|
-- Workaround for Hidden Record #4085 (10 RoE Objectives Completed)
|
|
if
|
|
not player:getEminenceCompleted(4085) and
|
|
player:getNumEminenceCompleted() >= 10
|
|
then
|
|
player:setEminenceCompleted(4085)
|
|
end
|
|
|
|
return true
|
|
end
|
|
|
|
-- *** onRecordTrigger is the primary entry point for all record calls. ***
|
|
-- Even records which are completed through Lua scripts should point here and
|
|
-- have record information entered in records. This keeps everything neat.
|
|
|
|
function xi.roe.onRecordTrigger(player, recordID, params)
|
|
params = params or {}
|
|
params.progress = params.progress or player:getEminenceProgress(recordID)
|
|
|
|
local entry = xi.roe.records[recordID]
|
|
local isClaiming = params.claim
|
|
|
|
if entry and params.progress then
|
|
local awaitingClaim = params.progress >= entry.goal
|
|
|
|
if awaitingClaim and not isClaiming then
|
|
player:messageBasic(xi.msg.basic.ROE_YET_TO_RECEIVE)
|
|
return
|
|
elseif isClaiming or entry:check(player, params) then
|
|
params.progress = params.progress + (isClaiming and 0 or entry.increment)
|
|
if params.progress >= entry.goal then
|
|
if not completeRecord(player, recordID) and not awaitingClaim then
|
|
player:setEminenceProgress(recordID, entry.goal)
|
|
end
|
|
else
|
|
player:setEminenceProgress(recordID, params.progress, entry.goal)
|
|
end
|
|
end
|
|
end
|
|
end
|