Module:Slayer task library
Jump to navigation
Jump to search
Module documentation
This documentation is transcluded from Template:No documentation/doc. [edit] [history] [purge]
This module does not have any documentation. Please consider adding documentation at Module:Slayer task library/doc. [edit]
Module:Slayer task library requires Module:SlayerConsts.
Module:Slayer task library requires Module:SlayerConsts/MasterTables.
local SlayerConsts = require ('Module:SlayerConsts' )
local MasterTables = require ('Module:SlayerConsts/MasterTables' )
local p = {}
--
-- Creates a "status" table that holds all information needed to check
-- if a player meets task requirements. This function is purely for convenience.
-- You are free to create your own table and pass it to the various functions,
-- but using this to create your table helps to keep it from being malformed.
--
-- The strings in quests, unlocks, other, and blocks arrays should match
-- EXACTLY with strings in the respective IDS table.
--
-- @param stats {table} A table whose keys and values will be used to update
-- the default stats table.
-- @param quests {array} An array containing strings of quests that should be
-- marked as complete.
-- @param unlocks {array} An array containing strings of unlocks that should be
-- marked as complete.
-- @param other {array} An array containing strings of other things that should be
-- marked as complete.
-- @param blocks {array} An array containing strings of tasks that should be
-- treated as blocked.
-- @return {table} See status table documentation below.
--
function p.create_status(stats, quests, unlocks, other, blocks)
--[[
The status table needs to keep this layout in order to check requirements.
The Stats subtable should hold all levels for the player. You can put any
key in the Stats subtable, but make sure to have all the keys required for
your task data.
The Quests subtable consists of names of quests for keys with values
true if completed and false if not completed.
The Unlocks subtable consists of names of unlocks for keys with values
true if unlocked and false if not unlocked.
The Other subtable consists of the names of other tasks (like barbarian
training) as keys with values true if completed and false if not.
If any required subtable key has value false, check_requirements will by
default return false (equivalent to not being able to get the task).
You need to manually change that function to check for unlocks which may
actually block a task. For example, Stop the Wyvern is an unlock,
but unlocking it blocks the task. This logic is handled in check_requirements.
]]
local status = {
Stats = {
Combat = 3,
Slayer = 1,
Magic = 1,
Agility = 1,
Strength = 1,
Firemaking = 1,
Defence = 1,
Thieving = 1
},
Quests = {},
Unlocks = {},
Other = {},
Blocks = {}
}
--[[
Populate required quests, unlocks, and others with false values by default.
]]
for quest_name, _ in SlayerConsts.get_quest_pairs() do
p.set_quest_incomplete(status, quest_name)
end
for unlock_name, _ in SlayerConsts.get_unlock_pairs() do
p.set_unlock_inactive(status, unlock_name)
end
for other_name, _ in SlayerConsts.get_other_pairs() do
p.set_other_incomplete(status, other_name)
end
--[[
If you pass in stats, quests, or unlocks, they will be updated here.
]]
if stats ~= nil then
for k, v in pairs(stats) do
p.set_stat(status, k, v)
end
end
if quests ~= nil then
p.set_quests_complete(status, quests)
end
if unlocks ~= nil then
p.set_unlocks_active(status, unlocks)
end
if other ~= nil then
p.set_others_complete(status, other)
end
if blocks ~= nil then
p.add_blocks(status, blocks)
end
return status
end
-- Stub Functions
--------------------------------------------------------------------------------
-- These functions are just wrappers for the functions to access the tables in
-- the SlayerConsts module. They are included for convenience so both this
-- module and SlayerConsts do not need to be required by as many modules.
--------------------------------------------------------------------------------
function p.get_unlock_id(name)
return SlayerConsts.get_unlock_id(name)
end
function p.get_unlock_name(unlockId)
return SlayerConsts.get_unlock_name(unlockId)
end
function p.get_unlock_pairs()
return SlayerConsts.get_unlock_pairs()
end
function p.get_quest_id(name)
return SlayerConsts.get_quest_id(name)
end
function p.get_quest_name(questId)
return SlayerConsts.get_quest_name(questId)
end
function p.get_quest_pairs()
return SlayerConsts.get_quest_pairs()
end
function p.get_other_id(name)
return SlayerConsts.get_other_id(name)
end
function p.get_other_name(otherId)
return SlayerConsts.get_other_name(otherId)
end
function p.get_other_pairs()
return SlayerConsts.get_other_pairs()
end
function p.get_monster_id(name)
return SlayerConsts.get_monster_id(name)
end
function p.get_monster_name(monsterId)
return SlayerConsts.get_monster_name(monsterId)
end
function p.get_monster_pairs()
return SlayerConsts.get_monster_pairs()
end
--------------------------------------------------------------------------------
--
--
-- End of stub functions
--
--
--------------------------------------------------------------------------------
-- Status Helper Functions
--------------------------------------------------------------------------------
-- These helper functions should be somewhat self explanatory.
-- These are simply included in order to abstract away some of the code
-- that will need to be written concerning status.
-- Note that since Lua passes tables by reference, you should NOT set your status
-- equal to the result of any of these functions. None of them return anything.
--------------------------------------------------------------------------------
function p.set_stat(status, statName, statValue)
status['Stats'][statName] = statValue
end
function p.set_quest_complete(status, questName)
status['Quests'][questName] = true
end
function p.set_quest_incomplete(status, questName)
status['Quests'][questName] = false
end
function p.set_quests_complete(status, questNames)
if questNames ~= nil then
for _, questName in pairs(questNames) do
p.set_quest_complete(status, questName)
end
end
end
function p.set_quests_incomplete(status, questNames)
if questNames ~= nil then
for _, questName in pairs(questNames) do
p.set_quest_incomplete(status, questName)
end
end
end
function p.set_unlock_active(status, unlockName)
status['Unlocks'][unlockName] = true
end
function p.set_unlock_inactive(status, unlockName)
status['Unlocks'][unlockName] = false
end
function p.set_unlocks_active(status, unlockNames)
if unlockNames ~= nil then
for _, unlockName in pairs(unlockNames) do
p.set_unlock_active(status, unlockName)
end
end
end
function p.set_unlocks_inactive(status, unlockNames)
if unlockNames ~= nil then
for _, unlockName in pairs(unlockNames) do
p.set_unlock_inactive(status, unlockName)
end
end
end
function p.set_other_complete(status, otherName)
status['Other'][otherName] = true
end
function p.set_other_incomplete(status, otherName)
status['Other'][otherName] = false
end
function p.set_others_complete(status, otherNames)
if otherNames ~= nil then
for _, otherName in pairs(otherNames) do
p.set_other_complete(status, otherName)
end
end
end
function p.set_others_incomplete(status, otherNames)
if otherNames ~= nil then
for _, otherName in pairs(otherNames) do
p.set_other_incomplete(status, otherName)
end
end
end
function p.add_block(status, taskName)
-- Might want to check for dupes
-- Might want to check for length, although not having a restriction
-- here increases flexibility.
table.insert(status['Blocks'], taskName)
end
function p.remove_block(status, taskName)
toRemove = {}
-- Note that because the indices are increasing and being
-- added to the front of toRemove, the order of elements in
-- toRemove will be decreasing.
-- This avoids issues when removing table elements which changes
-- indices of elements that come later in the table.
for index=1,#status['Blocks'] do
if status['Blocks'][index] == taskName then
table.insert(toRemove, 1, index)
end
end
for i=1,#toRemove do
table.remove(status['Blocks'], toRemove[i])
end
end
function p.add_blocks(status, taskNames)
if taskNames ~= nil then
for _, taskName in pairs(taskNames) do
p.add_block(status, taskName)
end
end
end
function p.remove_blocks(status, taskNames)
if taskNames ~= nil then
for _, taskName in pairs(taskNames) do
p.remove_block(status, taskName)
end
end
end
--------------------------------------------------------------------------------
--
--
-- End of status helper functions
--
--
--------------------------------------------------------------------------------
-- List of all table names. If more masters are added, add them here.
-- DO NOT add masters who use the same table as someone else (ie. Steve)
local tableNames = {"Turael", "Krystilia", "Mazchna", "Vannaka", "Chaeldar", "Konar", "Nieve", "Duradel"}
-- Handle masters who use the same table here.
local masterNames = {
Turael = tableNames[1],
Krystilia = tableNames[2],
Mazchna = tableNames[3],
Vannaka = tableNames[4],
Chaeldar = tableNames[5],
Konar = tableNames[6],
Nieve = tableNames[7],
Steve = tableNames[7],
Duradel = tableNames[8]
}
-- Given the name of a slayer master, this returns the name of the file that
-- contains their data. Since Nieve and Steve use the same table, they map to
-- the same value.
--
-- @param masterName {string} A string containing the name of the slayer master
-- whose table file you want to get.
-- @return {string} String of the file name for that slayer master's tasks.
--
function p.check_master(masterName)
return masterNames[masterName]
end
--
-- Simple mw.loadData wrapper used to access data located on module subpages
--
-- @param master {string} Slayer master to retrieve table for
-- @return {table} Table of master task data
--
function p.get_table(master)
local t = MasterTables.get_table(p.check_master(master))
return t
end
--
-- Check to see if a player with the current status has the requirements to get
-- the task with id taskMonsterId. This should stay internal to this module
-- to avoid extra complexity for those using the module.
--
-- @param status {table} The status table corresponding to the player. See
-- create_status() documentation for more details.
-- @param requirements {table} A table containing the requirements for this task.
-- See below for an example of the expected layout.
-- @param taskMonsterId {int} The id of the task.
-- @return {boolean} Returns false if any requirement is failed or if the task is
-- blocked. Returns true otherwise.
--
function check_requirements(status, requirements, taskMonsterId)
quests = status['Quests']
unlocks = status['Unlocks']
other = status['Other']
stats = status['Stats']
blocks = status['Blocks']
-- Example requirements table
-- requirements= {Slayer= 66, Combat= 60, Unlock= "Stop the Wyvern", Quest= "Bone Voyage"}
-- In this implementation, values are always expected to be singular.
-- It may be that a slayer monster in the future requires quests A and B,
-- where A does not require B and B does not require A. Then the data and this
-- module will need to be updated to store Quests as arrays and check each quest.
-- EX:
-- requirements= {Slayer= 66, Combat= 60, Unlock= {"Stop the Wyvern"}, Quest= {"Bone Voyage"}}
for k, v in pairs(requirements) do
if k == 'Quest' then
-- Remember that v is an int containing the id of the quest, unlock,
-- or other. Since status stores strings as keys we can index in via getting the name.
if type(v) == 'table' then
for _, questId in ipairs(v) do
if quests[SlayerConsts.get_quest_name(questId)] == false then
return false
end
end
else
if quests[SlayerConsts.get_quest_name(v)] == false then
return false
end
end
elseif k == 'Unlock' then
-- Note that Stop the Wyvern is handled here.
if unlocks[SlayerConsts.get_unlock_name(v)] == false and v ~= SlayerConsts.UNLOCK_STOP_THE_WYVERN then
return false
elseif unlocks[SlayerConsts.get_unlock_name(v)] == true and v == SlayerConsts.UNLOCK_STOP_THE_WYVERN then
return false
end
elseif k == 'Other' then
if other[SlayerConsts.get_other_name(v)] == false then
return false
end
elseif stats[k] ~= nil then
if stats[k] < v then
return false
end
else
return false
end
end
for i, blockName in ipairs(blocks) do
if SlayerConsts.get_monster_id(blockName) == taskMonsterId then
return false
end
end
return true
end
--
-- Reduces the given table down to a table of only tasks the player described by
-- status can be assigned. Optionally, this can also give you the tasks the
-- player cannot be assigned.
--
-- @param tableToReduce {table} The table of tasks to be reduced. This should
-- be of the form returned by get_table
-- @param status {table} The status table corresponding to the player. See
-- create_status() documentation for more details.
-- @param returnDisallowed {boolean} If true, returns the tasks the player
-- cannot be assigned by this master as a second
-- return value.
-- @return {table, table|nil} Returns a table that contains only the tasks from tableToReduce
-- that the player can be assigned. If returnDisallowed is true,
-- a second table is returned that contains the tasks that cannot
-- be assigned to the player.
--
function p.get_effective_table(tableToReduce, status, returnDisallowed)
local availableMonsterTable = {}
local unavailableTable = {}
for taskMonsterId, taskValue in pairs(tableToReduce) do
if check_requirements(status, taskValue['requirements'], taskMonsterId) then
local subtable = taskValue['subtable']
if subtable ~= nil then
effectiveSubtable, unavailableSubtable = p.get_effective_table(subtable, status, returnDisallowed)
local taskValueCopy = {}
for k, v in pairs(taskValue) do
taskValueCopy[k] = v
end
taskValueCopy['subtable'] = {}
taskValueCopy['unavailableSubtable'] = {}
for subKey, subVal in pairs(effectiveSubtable) do
taskValueCopy['subtable'][subKey] = subVal
end
for subKey, subVal in pairs(unavailableSubtable) do
taskValueCopy['unavailableSubtable'][subKey] = subVal
end
taskValue = taskValueCopy
end
availableMonsterTable[taskMonsterId] = taskValue
elseif returnDisallowed == true then
unavailableTable[taskMonsterId] = taskValue
end
end
return availableMonsterTable, unavailableTable
end
--
-- Returns the names of the masters who can assign a given task to the player,
-- regardless of the players status.
--
-- @param taskName {string} The name of the task. This needs to match one of the
-- keys in MONSTER_IDS
-- @return {array} Returns an array containing the names of the masters who can
-- assign the task with name taskName.
--
function p.get_masters_that_assign(taskName)
mastersThatAssign = {}
for name, tableName in pairs(masterNames) do
taskTable = p.get_table(tableName)
for taskMonsterId, taskValue in pairs(taskTable) do
local subtable = taskValue['subtable']
if subtable ~= nil then
for subKey, subVal in pairs(subtable) do
if subKey == SlayerConsts.get_monster_id(taskName) then
mastersThatAssign[tableName] = true
end
end
end
if taskMonsterId == SlayerConsts.get_monster_id(taskName) then
mastersThatAssign[tableName] = true
end
end
end
return mastersThatAssign
end
return p