17,101
edits
(Move Farming functions to Module:Skills/Gathering) |
(Update for v1.1) |
||
Line 17: | Line 17: | ||
local ItemData = mw.loadData('Module:Items/data') | local ItemData = mw.loadData('Module:Items/data') | ||
local Shared = require('Module:Shared') | local Shared = require('Module:Shared') | ||
local Constants = require('Module:Constants') | local Constants = require('Module:Constants') | ||
local GameData = require('Module:GameData') | |||
local SkillData = GameData.skillData | |||
local Items = require('Module:Items') | local Items = require('Module:Items') | ||
local Icons = require('Module:Icons') | local Icons = require('Module:Icons') | ||
-- Thieving | |||
function p.getThievingNPCByID(npcID) | |||
return GameData.getEntityByID(SkillData.Thieving.npcs, npcID) | |||
end | |||
function p.getThievingNPC(npcName) | function p.getThievingNPC(npcName) | ||
return GameData.getEntityByName(SkillData.Thieving.npcs, npcName) | |||
end | end | ||
function p.getThievingNPCArea(npc) | function p.getThievingNPCArea(npc) | ||
for i, area in ipairs(SkillData.Thieving.areas) do | |||
for j, npcID in ipairs(area.npcIDs) do | |||
for i, area in | |||
for j, npcID in | |||
if npcID == npc.id then | if npcID == npc.id then | ||
return area | |||
end | end | ||
end | end | ||
end | end | ||
end | end | ||
Line 89: | Line 78: | ||
function p.getThievingSourcesForItem(itemID) | function p.getThievingSourcesForItem(itemID) | ||
local resultArray = {} | local resultArray = {} | ||
local areaNPCs = {} | local areaNPCs = {} | ||
--First check area unique drops | --First check area unique drops | ||
--If an area drops the item, add all the NPC ids to the list so we can add them later | --If an area drops the item, add all the NPC ids to the list so we can add them later | ||
for i, area in pairs(SkillData.Thieving.areas) do | |||
for j, drop in pairs(area.uniqueDrops) do | |||
if drop.id == itemID then | |||
for k, npcID in pairs(area.npcs) do | |||
areaNPCs[npcID] = drop.quantity | |||
end | end | ||
break | |||
end | end | ||
end | end | ||
Line 108: | Line 94: | ||
--Now go through and get drop chances on each NPC if needed | --Now go through and get drop chances on each NPC if needed | ||
for i, npc in pairs(SkillData.Thieving. | for i, npc in pairs(SkillData.Thieving.npcs) do | ||
local totalWt = 0 | local totalWt = 0 | ||
local dropWt = 0 | local dropWt = 0 | ||
local dropQty = 0 | local dropQty = { min = 0, max = 0 } | ||
for j, drop in | for j, drop in ipairs(npc.lootTable) do | ||
totalWt = totalWt + drop | totalWt = totalWt + drop.weight | ||
if drop | if drop.itemID == itemID then | ||
dropWt = drop | dropWt = drop.weight | ||
dropQty = drop | dropQty = { min = drop.minQuantity, max = drop.maxQuantity } | ||
end | end | ||
end | end | ||
if dropWt > 0 then | if dropWt > 0 then | ||
table.insert(resultArray, {npc = npc.name, minQty = | table.insert(resultArray, {npc = npc.name, minQty = dropQty.min, maxQty = dropQty.max, wt = dropWt * SkillData.Thieving.itemChance, totalWt = totalWt * 100, level = npc.level}) | ||
end | end | ||
--Chance of -1 on unique drops is to indicate variable chance | --Chance of -1 on unique drops is to indicate variable chance | ||
if npc.uniqueDrop ~= nil and npc.uniqueDrop. | if npc.uniqueDrop ~= nil and npc.uniqueDrop.id == itemID then | ||
table.insert(resultArray, {npc = npc.name, minQty = npc.uniqueDrop. | table.insert(resultArray, {npc = npc.name, minQty = npc.uniqueDrop.quantity, maxQty = npc.uniqueDrop.quantity, wt = -1, totalWt = -1, level = npc.level}) | ||
end | end | ||
if areaNPCs[npc.id] ~= nil then | if areaNPCs[npc.id] ~= nil then | ||
table.insert(resultArray, {npc = npc.name, minQty = areaNPCs[npc.id], maxQty = areaNPCs[npc.id], wt = SkillData.Thieving. | table.insert(resultArray, {npc = npc.name, minQty = areaNPCs[npc.id], maxQty = areaNPCs[npc.id], wt = SkillData.Thieving.baseAreaUniqueChance, totalWt = 100, level = npc.level}) | ||
end | end | ||
end | end | ||
for i, drop in | for i, drop in ipairs(SkillData.Thieving.generalRareItems) do | ||
if drop.itemID == itemID then | if drop.itemID == itemID then | ||
table.insert(resultArray, {npc = 'all', minQty = 1, maxQty = 1, wt = 1, totalWt = Shared.round2(1/(drop.chance/100), 0), level = 1}) | if drop.npcs == nil then | ||
table.insert(resultArray, {npc = 'all', minQty = 1, maxQty = 1, wt = 1, totalWt = Shared.round2(1/(drop.chance/100), 0), level = 1}) | |||
else | |||
for j, npcID in ipairs(drop.npcs) do | |||
local npc = p.getThievingNPCByID(npcID) | |||
if npc ~= nil then | |||
table.insert(resultArray, {npc = npc.name, minQty = 1, maxQty = 1, wt = 1, totalWt = Shared.round2(1/(drop.chance/100), 0), level = npc.level}) | |||
end | |||
end | |||
end | |||
end | end | ||
end | end | ||
Line 144: | Line 139: | ||
-- Astrology | -- Astrology | ||
function p.getConstellationByID(constID) | function p.getConstellationByID(constID) | ||
return SkillData.Astrology. | return GameData.getEntityByID(SkillData.Astrology.recipes, constID) | ||
end | end | ||
function p.getConstellation(constName) | function p.getConstellation(constName) | ||
return GameData.getEntityByName(SkillData.Astrology.recipes, constName) | |||
end | end | ||
function p.getConstellations(checkFunc) | function p.getConstellations(checkFunc) | ||
return GameData.getEntities(SkillData.Astrology.recipes, checkFunc) | |||
end | end | ||
Line 206: | Line 190: | ||
local modArray = {} | local modArray = {} | ||
local isSkillMod = {} | local isSkillMod = {} | ||
for _, modType in ipairs(modTypes) do | for _, modType in ipairs(modTypes) do | ||
for i, | for i, modTypeData in ipairs(cons[modType]) do | ||
local | local modVal = nil | ||
if | if modValue ~= nil then | ||
for j, | modVal = modValue | ||
else | |||
modVal = modTypeData.incrementValue * modTypeData.maxCount | |||
end | |||
for j, modifier in ipairs(modTypeData.modifiers) do | |||
local modEntry = (modifier.skill ~= nil and {modifier.skill, modVal}) or modVal | |||
addToArray(modArray, {modifier.key, modEntry}) | |||
end | end | ||
end | end | ||
Line 228: | Line 210: | ||
for i, modDefn in ipairs(modArray) do | for i, modDefn in ipairs(modArray) do | ||
local modName, modVal = modDefn[1], modDefn[2] | local modName, modVal = modDefn[1], modDefn[2] | ||
local isSkill = | local isSkill = type(modVal) == 'table' and type(modVal[1]) == 'string' | ||
if modArrayKV[modName] == nil then | if modArrayKV[modName] == nil then | ||
modArrayKV[modName] = (isSkill and { modVal } or modVal) | modArrayKV[modName] = (isSkill and { modVal } or modVal) | ||
Line 251: | Line 233: | ||
end | end | ||
local unlockTable = SkillData | local unlockTable = SkillData[skillID].masteryLevelUnlocks | ||
if unlockTable == nil then | if unlockTable == nil then | ||
return 'ERROR: Failed to find Mastery Unlock data for '..skillName | return 'ERROR: Failed to find Mastery Unlock data for '..skillName | ||
Line 257: | Line 239: | ||
local result = '{|class="wikitable"\r\n!Level!!Unlock' | local result = '{|class="wikitable"\r\n!Level!!Unlock' | ||
for i, unlock in | for i, unlock in ipairs(unlockTable) do | ||
result = result..'\r\n|-' | result = result..'\r\n|-' | ||
result = result..'\r\n|'..unlock.level..'||'..unlock. | result = result..'\r\n|'..unlock.level..'||'..unlock.description | ||
end | end | ||
result = result..'\r\n|}' | result = result..'\r\n|}' | ||
Line 272: | Line 254: | ||
end | end | ||
local checkpoints = SkillData[skillID].masteryCheckpoints | |||
if checkpoints == nil then | |||
return 'ERROR: Failed to find Mastery Unlock data for '..skillName | return 'ERROR: Failed to find Mastery Unlock data for '..skillName | ||
end | end | ||
local | local totalPoolXP = SkillData[skillID].baseMasteryPoolCap | ||
local result = '{|class="wikitable"\r\n!Pool %!!style="width:100px"|Pool XP!!Bonus' | local result = '{|class="wikitable"\r\n!Pool %!!style="width:100px"|Pool XP!!Bonus' | ||
for i, | for i, checkpointDesc in ipairs(checkpoints) do | ||
result = result..'\r\n|-' | result = result..'\r\n|-' | ||
result = result..'\r\n|'.. | result = result..'\r\n|'..GameData.masteryCheckpoints[i]..'%||' | ||
result = result..Shared.formatnum(totalPoolXP * | result = result..Shared.formatnum(math.floor(totalPoolXP * GameData.masteryCheckpoints[i] / 100))..' xp||'..checkpointDesc | ||
end | end | ||
result = result..'\r\n|-\r\n!colspan="2"|Total Mastery Pool XP' | result = result..'\r\n|-\r\n!colspan="2"|Total Mastery Pool XP' | ||
Line 294: | Line 275: | ||
local baseTokenChance = 18500 | local baseTokenChance = 18500 | ||
local masterySkills = {} | local masterySkills = {} | ||
local CCI = Items.getItemByID('melvorD:Clue_Chasers_Insignia') | |||
if CCI == nil then return '' end | |||
-- | -- Build table of mastery skills | ||
for skillLocalID, skill in pairs(SkillData) do | |||
for | if skill.masteryTokenID ~= nil then | ||
table.insert(masterySkills, skill) | |||
table.insert(masterySkills, | |||
end | end | ||
end | end | ||
table.sort(masterySkills, function(a, b) | table.sort(masterySkills, | ||
function(a, b) | |||
if a.milestoneCount == b.milestoneCount then | |||
return a.name < b.name | |||
else | |||
return a.milestoneCount > b.milestoneCount | |||
end | |||
end) | |||
-- Generate output table | -- Generate output table | ||
local resultPart = {} | local resultPart = {} | ||
local CCIIcon = Icons.Icon({CCI.name, type='item', notext=true}) | |||
local CCIIcon = Icons.Icon({ | |||
table.insert(resultPart, '{| class="wikitable sortable"') | table.insert(resultPart, '{| class="wikitable sortable"') | ||
Line 321: | Line 301: | ||
table.insert(resultPart, '\r\n|-\r\n!Without ' .. CCIIcon .. '!!With ' .. CCIIcon) | table.insert(resultPart, '\r\n|-\r\n!Without ' .. CCIIcon .. '!!With ' .. CCIIcon) | ||
for i, | for i, skill in ipairs(masterySkills) do | ||
local token = | local token = Items.getItemByID(skill.masteryTokenID) | ||
local denom = math.floor(baseTokenChance / | local denom = math.floor(baseTokenChance / skill.milestoneCount) | ||
local denomCCI = Shared.round(baseTokenChance / ( | local denomCCI = Shared.round(baseTokenChance / (skill.milestoneCount * (1 + CCI.modifiers.increasedOffItemChance / 100)), 0, 0) | ||
table.insert(resultPart, '\r\n|-') | table.insert(resultPart, '\r\n|-') | ||
table.insert(resultPart, '\r\n|style="text-align:center"|' .. Icons.Icon({token.name, type='item', size=50, notext=true})) | table.insert(resultPart, '\r\n|style="text-align:center"|' .. Icons.Icon({token.name, type='item', size=50, notext=true})) | ||
table.insert(resultPart, '\r\n|' .. Icons.Icon({ | table.insert(resultPart, '\r\n|' .. Icons.Icon({skill.name, type='skill'})) | ||
table.insert(resultPart, '\r\n|style="text-align:right" data-sort-value="' .. denom .. '"|1/' .. Shared.formatnum(denom)) | table.insert(resultPart, '\r\n|style="text-align:right" data-sort-value="' .. denom .. '"|1/' .. Shared.formatnum(denom)) | ||
table.insert(resultPart, '\r\n|style="text-align:right" data-sort-value="' .. denomCCI .. '"|1/' .. Shared.formatnum(denomCCI)) | table.insert(resultPart, '\r\n|style="text-align:right" data-sort-value="' .. denomCCI .. '"|1/' .. Shared.formatnum(denomCCI)) | ||
Line 339: | Line 319: | ||
-- Skill unlock costs for Adventure game mode | -- Skill unlock costs for Adventure game mode | ||
function p.getSkillUnlockCostTable() | function p.getSkillUnlockCostTable() | ||
local returnPart = {} | local advMode = GameData.getEntityByID('gamemodes', 'melvorF:Adventure') | ||
if advMode ~= nil then | |||
local returnPart = {} | |||
table.insert(returnPart, '{| class="wikitable stickyHeader"\r\n|- class="headerRow-0"\r\n!Unlock!!Cost!!Cumulative Cost') | |||
local accCost = 0 | |||
for i, cost in ipairs(advMode.skillUnlockCost) do | |||
accCost = accCost + cost | |||
table.insert(returnPart, '|-') | |||
table.insert(returnPart, '|' .. i .. '||' .. Icons.GP(cost) .. '||' .. Icons.GP(accCost)) | |||
end | |||
table.insert(returnPart, '|}') | |||
return table.concat(returnPart, '\r\n') | |||
end | end | ||
end | end | ||
Line 359: | Line 342: | ||
local tableType = frame.args ~= nil and frame.args[1] or frame | local tableType = frame.args ~= nil and frame.args[1] or frame | ||
tableType = Shared.splitString(tableType, ' ')[1] | tableType = Shared.splitString(tableType, ' ')[1] | ||
-- | |||
local | -- Has a valid category been passed (by name)? | ||
local category = GameData.getEntityByName(SkillData.Smithing.categories, tableType) | |||
if category == nil then | |||
if | |||
return 'ERROR: Invalid Smithing category: "' .. tableType .. '"[[Category:Pages with script errors]]' | return 'ERROR: Invalid Smithing category: "' .. tableType .. '"[[Category:Pages with script errors]]' | ||
end | end | ||
Line 381: | Line 352: | ||
-- The bar list will be used later for value/bar calculations | -- The bar list will be used later for value/bar calculations | ||
local recipeList, barIDList = {}, {} | local recipeList, barIDList = {}, {} | ||
for i, recipe in ipairs(SkillData.Smithing. | for i, recipe in ipairs(SkillData.Smithing.recipes) do | ||
if recipe. | if recipe.categoryID == category.id then | ||
local recipeItem = Items.getItemByID(recipe. | local recipeItem = Items.getItemByID(recipe.productID) | ||
if recipeItem ~= nil then | if recipeItem ~= nil then | ||
table.insert(recipeList, { id = i, level = recipe.level, itemName = recipeItem.name, itemValue = recipeItem.sellsFor }) | table.insert(recipeList, { id = i, level = recipe.level, itemName = recipeItem.name, itemValue = recipeItem.sellsFor }) | ||
end | end | ||
elseif recipe. | elseif recipe.categoryID == 'melvorD:Bars' then | ||
barIDList[recipe. | barIDList[recipe.productID] = true | ||
end | end | ||
end | end | ||
Line 398: | Line 369: | ||
table.insert(resultPart, '\r\n!Item!!Name!!'..Icons.Icon({'Smithing', type='skill', notext=true})..' Level!!XP!!Value!!Ingredients') | table.insert(resultPart, '\r\n!Item!!Name!!'..Icons.Icon({'Smithing', type='skill', notext=true})..' Level!!XP!!Value!!Ingredients') | ||
--Adding value/bar for things other than smelting | --Adding value/bar for things other than smelting | ||
if | if category.id ~= 'melvorD:Bars' then | ||
table.insert(resultPart, '!!Value/Bar') | table.insert(resultPart, '!!Value/Bar') | ||
end | end | ||
Line 411: | Line 382: | ||
for i, recipeDef in ipairs(recipeList) do | for i, recipeDef in ipairs(recipeList) do | ||
local recipe = SkillData.Smithing. | local recipe = SkillData.Smithing.recipes[recipeDef.id] | ||
local totalValue = recipe.baseQuantity * recipeDef.itemValue | local totalValue = recipe.baseQuantity * recipeDef.itemValue | ||
-- Determine the bar quantity & build the recipe cost string | -- Determine the bar quantity & build the recipe cost string | ||
Line 418: | Line 389: | ||
local costItem = Items.getItemByID(itemCost.id) | local costItem = Items.getItemByID(itemCost.id) | ||
if costItem ~= nil then | if costItem ~= nil then | ||
table.insert(costString, Icons.Icon({costItem.name, type='item', qty=itemCost. | table.insert(costString, Icons.Icon({costItem.name, type='item', qty=itemCost.quantity, notext=true})) | ||
end | end | ||
if barIDList[itemCost.id] then | if barIDList[itemCost.id] then | ||
barQty = barQty + itemCost. | barQty = barQty + itemCost.quantity | ||
end | end | ||
end | end | ||
Line 433: | Line 404: | ||
table.insert(resultPart, Icons.Icon({recipeDef.itemName, type='item', noicon=true})) | table.insert(resultPart, Icons.Icon({recipeDef.itemName, type='item', noicon=true})) | ||
table.insert(resultPart, '\r\n|data-sort-value="' .. recipe.level .. '"| ' .. Icons._SkillReq('Smithing', recipe.level)) | table.insert(resultPart, '\r\n|data-sort-value="' .. recipe.level .. '"| ' .. Icons._SkillReq('Smithing', recipe.level)) | ||
table.insert(resultPart, '\r\n|data-sort-value="' .. recipe. | table.insert(resultPart, '\r\n|data-sort-value="' .. recipe.baseExperience .. '"| ' .. Shared.formatnum(recipe.baseExperience)) | ||
table.insert(resultPart, '\r\n|data-sort-value="' .. totalValue .. '"| ' .. Icons.GP(recipeDef.itemValue)) | table.insert(resultPart, '\r\n|data-sort-value="' .. totalValue .. '"| ' .. Icons.GP(recipeDef.itemValue)) | ||
if recipe.baseQuantity > 1 then | if recipe.baseQuantity > 1 then | ||
Line 439: | Line 410: | ||
end | end | ||
table.insert(resultPart, '\r\n| ' .. table.concat(costString, ', ')) | table.insert(resultPart, '\r\n| ' .. table.concat(costString, ', ')) | ||
if | if category.id ~= 'melvorD:Bars' then | ||
local barVal, barValTxt = 0, 'N/A' | local barVal, barValTxt = 0, 'N/A' | ||
if barQty > 0 then | if barQty > 0 then | ||
barVal = totalValue / barQty | barVal = totalValue / barQty | ||
barValTxt = Icons.GP(Shared.round(barVal, 1, 1)) | |||
end | end | ||
table.insert(resultPart, '\r\n|data-sort-value="' .. barVal .. '"| ' .. | table.insert(resultPart, '\r\n|data-sort-value="' .. barVal .. '"| ' .. barValTxt) | ||
end | end | ||
end | end | ||
Line 462: | Line 433: | ||
table.insert(resultPart, '\r\n!XP!!XP/s!!XP!!XP/s') | table.insert(resultPart, '\r\n!XP!!XP/s!!XP!!XP/s') | ||
for i, logData in | for i, logData in ipairs(SkillData.Firemaking.logs) do | ||
local logs = Items.getItemByID(logData.logID) | local logs = Items.getItemByID(logData.logID) | ||
local name = logs.name | local name = logs.name | ||
local burnTime = logData.baseInterval / 1000 | local burnTime = logData.baseInterval / 1000 | ||
local bonfireTime = logData.baseBonfireInterval / 1000 | local bonfireTime = logData.baseBonfireInterval / 1000 | ||
local XPS = logData. | local XPS = logData.baseExperience / burnTime | ||
local XP_BF = logData. | local XP_BF = logData.baseExperience * (1 + logData.bonfireXPBonus / 100) | ||
local XPS_BF = XP_BF / burnTime | local XPS_BF = XP_BF / burnTime | ||