Anonymous

Module:Modifiers: Difference between revisions

From Melvor Idle
Support modifier matching by properties such as skill ID, item ID, etc.
(getMatchCriteriaFromIDs: Fix processing of scopes from modifier IDs)
(Support modifier matching by properties such as skill ID, item ID, etc.)
Line 33: Line 33:
['mod'] = modDefn,
['mod'] = modDefn,
['alias'] = modAlias,
['alias'] = modAlias,
['type'] = keyDefn.type
['props'] = { ['valueType'] = keyDefn.type }
}
}
end
end
Line 52: Line 52:
['key'] = 'damageType',
['key'] = 'damageType',
['templateKey'] = 'damageType',
['templateKey'] = 'damageType',
['templateKey2'] = 'resistanceName'
['templateKey2'] = 'resistanceName',
['gameDataKey'] = 'damageTypes'
},
},
['realmID'] = {
['realmID'] = {
['key'] = 'realm',
['key'] = 'realm',
['templateKey'] = 'realmName'
['templateKey'] = 'realmName',
['gameDataKey'] = 'realms'
},
},
['currencyID'] = {
['currencyID'] = {
['key'] = 'currency',
['key'] = 'currency',
['templateKey'] = 'currencyName'
['templateKey'] = 'currencyName',
['gameDataKey'] = 'currencies'
},
},
['categoryID'] = {
['categoryID'] = {
Line 76: Line 79:
['itemID'] = {
['itemID'] = {
['key'] = 'item',
['key'] = 'item',
['templateKey'] = 'itemName'
['templateKey'] = 'itemName',
['gameDataKey'] = 'items'
},
},
['effectGroupID'] = {
['effectGroupID'] = {
['key'] = 'effectGroup',
['key'] = 'effectGroup',
['templateKey'] = 'effectGroupName'
['templateKey'] = 'effectGroupName',
['gameDataKey'] = 'combatEffectGroups'
},
},
}
}
local ScopeKeyToIDMap = {}
for idKey, defn in pairs(ScopeKeyMap) do
ScopeKeyToIDMap[defn.key] = idKey
end


-- Retrieves a modifier definition by ID
-- Retrieves a modifier definition by ID
Line 127: Line 137:
-- At this point, both definitions have the same elements
-- At this point, both definitions have the same elements
return true
return true
end
-- Given a table containing one or more sets of data criteria, combines those criteria into a
-- single set of criteria. Should the same criteria key be specified more than once, the value from
-- the last set containing that key will be retained
function p.combineDataCriteria(dataCriteriaList)
local rv = {}
for _, dataCriteria in ipairs(dataCriteriaList) do
for dataKey, dataValue in pairs(dataCriteria) do
rv[dataKey] = dataValue
end
end
return rv
end
-- Given data criteria where the values are entity names, converts those names to IDs.
function p.convertCriteriaNamesToIDs(dataCriteriaByName)
local dataCriteria = {}
for criteriaKey, criteriaName in pairs(dataCriteriaByName) do
if criteriaName == nil or criteriaName == '' then
error('Value for criteria ' .. criteriaKey .. ' cannot be nil', 2)
end
if criteriaKey == 'valueType' then
-- Special case
dataCriteria[criteriaKey] = string.lower(criteriaName)
elseif ScopeKeyMap[criteriaKey] ~= nil then
-- ID specified directly
dataCriteria[criteriaKey] = criteriaName
else
local criteriaIDKey = ScopeKeyToIDMap[criteriaKey]
if criteriaIDKey == nil then
error('Invalid criteria specified: ' .. criteriaKey, 2)
end
local keyMap = ScopeKeyMap[criteriaIDKey]
local criteriaID = nil
if keyMap.gameDataKey ~= nil then
local criteriaData = GameData.getEntityByName(keyMap.gameDataKey, criteriaName)
if criteriaData ~= nil then
criteriaID = criteriaData.id
end
elseif criteriaKey == 'skill' then
criteriaID = Common.getSkillID(criteriaName)
else
error('Criteria ' .. criteriaKey .. ' is currently unsupported', 2)
end
if criteriaID == nil then
error('Unknown ' .. criteriaKey .. ': ' .. criteriaName, 2)
end
dataCriteria[criteriaIDKey] = criteriaID
end
end
return dataCriteria
end
end


Line 174: Line 239:
-- Given a list of modifier IDs and aliases, returns all match criteria for these.
-- Given a list of modifier IDs and aliases, returns all match criteria for these.
-- This matching criteria can then be pased to p.getMatchingModifiers()
-- This matching criteria can then be pased to p.getMatchingModifiers()
function p.getMatchCriteriaFromIDs(modifierIDs, modifierAliases)
function p.getMatchCriteriaFromIDs(modifierIDs)
local matchCriteria = {}
local matchCriteria = {}
-- For modifier IDs, find the relevant mod definition and add all allowed scopes
-- For modifier IDs, find the relevant mod definition and add all allowed scopes
if modifierIDs ~= nil then
if modifierIDs ~= nil then
for _, modifierID in ipairs(modifierIDs) do
for _, idObject in ipairs(modifierIDs) do
local modDefn = p.getModifierByID(modifierID)
local modifierID = idObject.id
if modDefn == nil then
local modType = idObject.type
error('No such modifier ID: ' .. modifierID)
local modProps = idObject.props or {}
end
 
if modType == 'id' then
local modDefn = p.getModifierByID(modifierID)
if modDefn == nil then
error('No such modifier ID: ' .. modifierID, 2)
end


-- Add all scopes
-- Add all scopes
for _, allowedScope in ipairs(modDefn.allowedScopes) do
for _, allowedScope in ipairs(modDefn.allowedScopes) do
table.insert(matchCriteria, {
["mod"] = modDefn,
["scope"] = allowedScope.scopes or {},
["props"] = modProps
})
end
elseif modType == 'alias' then
-- For alias IDs, simply add these one at a time to the table
table.insert(matchCriteria, {
table.insert(matchCriteria, {
["mod"] = modDefn,
["alias"] = modifierID,
["scope"] = allowedScope.scopes or {}
["props"] = modProps
})
})
else
error('Unknown modifier ID type: ' .. (modType or 'nil'), 2)
end
end
end
end
-- For alias IDs, simply add these one at a time to the table
if modifierAliases ~= nil then
for _, modifierAlias in ipairs(modifierAliases) do
table.insert(matchCriteria, {
["alias"] = modifierAlias
})
end
end
end
end
Line 209: Line 281:
-- when they relate to that given skill ID
-- when they relate to that given skill ID
-- matchCriteria is a table of elements structured as follows:
-- matchCriteria is a table of elements structured as follows:
-- { ["mod"] = modDefn, ["scope"] = scopeDefn, ["alias"] = modAlias }
-- {
-- ["mod"] = modDefn,
-- ["scope"] = scopeDefn,
-- ["alias"] = modAlias,
-- ["props"] = modProps
-- }
-- Examples of valid mod and scope definitions can be obtained from
-- Examples of valid mod and scope definitions can be obtained from
-- p.getModifierByID() and p.getScope()
-- p.getModifierByID() and p.getScope()
-- alias is an optional property, if specified mod and scope are derived
-- alias is an optional property, if specified mod and scope are derived
-- from the modAlias.
-- from the modAlias.
function p.getMatchingModifiers(modifiers, matchCriteria, skillID)
-- props is an optional property, if specified then a modifier is only matched
-- if the properties (skillID, itemID, etc.) also match.
function p.getMatchingModifiers(modifiers, matchCriteria)
local resultMods = {
local resultMods = {
["matched"] = {},
["matched"] = {},
Line 223: Line 302:
local matchCriteriaMap = {}
local matchCriteriaMap = {}
for _, matchDefn in ipairs(matchCriteria) do
for _, matchDefn in ipairs(matchCriteria) do
local modDefn, scopeDefn, modAlias, valueType = matchDefn.mod, matchDefn.scope, {}, matchDefn.type
local modDefn, scopeDefn, modAlias, propCriteria = matchDefn.mod, matchDefn.scope, {}, (matchDefn.props or {})
if matchDefn.alias ~= nil then
if matchDefn.alias ~= nil then
local aliasData = p.getModifierByAlias(matchDefn.alias)
local aliasData = p.getModifierByAlias(matchDefn.alias)
Line 229: Line 308:
error('No such modifier alias: ' .. matchDefn.alias, 2)
error('No such modifier alias: ' .. matchDefn.alias, 2)
else
else
modDefn, scopeDefn, modAlias, valueType = aliasData.mod, aliasData.scope.scopes, aliasData.alias, aliasData.type
local aliasProps = p.combineDataCriteria({propCriteria, aliasData.props})
modDefn, scopeDefn, modAlias, propCriteria = aliasData.mod, aliasData.scope.scopes, aliasData.alias, aliasProps
end
end
Line 237: Line 317:
matchCriteriaMap[modLocalID] = {}
matchCriteriaMap[modLocalID] = {}
end
end
table.insert(matchCriteriaMap[modLocalID], { ["scope"] = scopeDefn, ["alias"] = modAlias, ["valueType"] = valueType })
table.insert(matchCriteriaMap[modLocalID], { ["scope"] = scopeDefn, ["alias"] = modAlias, ["props"] = propCriteria })
end
end


Line 259: Line 339:
local modScopeDefn = p.convertScopeDataToDefinition(scopeData)
local modScopeDefn = p.convertScopeDataToDefinition(scopeData)
for _, matchDefn in ipairs(modMatchCriteria) do
for _, matchDefn in ipairs(modMatchCriteria) do
local scopeDefn, modAlias = matchDefn.scope, matchDefn.alias
local scopeDefn, modAlias, propCriteria = matchDefn.scope, matchDefn.alias, matchDefn.props
local dataCriteria = {
["skillID"] = skillID,
["valueType"] = matchDefn.valueType
}
local matchKey = 'unmatched'
local matchKey = 'unmatched'
-- Check that:
-- Check that:
Line 272: Line 348:
p.doScopeDefinitionsMatch(modScopeDefn, scopeDefn)
p.doScopeDefinitionsMatch(modScopeDefn, scopeDefn)
and p.checkScopeDataMeetsCriteria(scopeData, scopeDefn, modAlias)
and p.checkScopeDataMeetsCriteria(scopeData, scopeDefn, modAlias)
and p.checkScopeDataMeetsCriteria(scopeData, scopeDefn, dataCriteria)
and p.checkScopeDataMeetsCriteria(scopeData, scopeDefn, propCriteria)
) then
) then
-- Add to matched table
-- Add to matched table
Line 646: Line 722:


function p.test3()
function p.test3()
local item = GameData.getEntityByID('items', 'melvorF:Miners_Helmet')
local item = GameData.getEntityByID('items', 'melvorItA:Corrupted_Light_Consumable_I')
local matchCriteria = {
local matchCriteria = {
{
{
Line 674: Line 750:
["damageType"] = true
["damageType"] = true
}
}
},
{
["mod"] = p.getModifierByID('flatBaseRandomProductQuantity'),
["scope"] = {
["item"] = true,
["skill"] = true
},
["props"] = p.convertCriteriaNamesToIDs({ ["item"] = 'Abyssal Stardust' })
}
}
}
}
return p.getMatchingModifiers(item.modifiers, matchCriteria, 'melvorD:Thieving')
return p.getMatchingModifiers(item.modifiers, matchCriteria)
end
end


Line 702: Line 786:
local modIDs = {}
local modIDs = {}
for modID, modDet in pairs(entMods) do
for modID, modDet in pairs(entMods) do
table.insert(modIDs, modID)
table.insert(modIDs, {
["id"] = modID,
["type"] = 'id',
["props"] = {}
})
end
end
local matchCriteria = p.getMatchCriteriaFromIDs(modIDs, nil)
local matchCriteria = p.getMatchCriteriaFromIDs(modIDs)
mw.logObject(matchCriteria)
mw.logObject(matchCriteria)
mw.log('=======================================================')
mw.log('=======================================================')