Module:Modifiers: Difference between revisions

Implement modType criteria for checking if a modifier is deemed to have a positive or negative effect upon the target
No edit summary
(Implement modType criteria for checking if a modifier is deemed to have a positive or negative effect upon the target)
(2 intermediate revisions by the same user not shown)
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' or criteriaKey == 'modType' then
-- Special cases:
-- valueType restricts by sign of modifier value
-- modType restricts by whether the modifier is deemed to be a positive or
-- negative to the target
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 135: Line 203:
-- "valueType". This indicates whether the value of the modifier should be positive ('pos') or
-- "valueType". This indicates whether the value of the modifier should be positive ('pos') or
-- negative ('neg') in order for the criteria to be met
-- negative ('neg') in order for the criteria to be met
function p.checkScopeDataMeetsCriteria(scopeData, scopeDefn, dataCriteria)
function p.checkScopeDataMeetsCriteria(modDefn, scopeData, scopeDefn, dataCriteria)
for criteriaKey, criteriaValue in pairs(dataCriteria) do
for criteriaKey, criteriaValue in pairs(dataCriteria) do
if criteriaKey == 'valueType' then
if criteriaKey == 'valueType' then
Line 148: Line 216:
-- Value criteria not met
-- Value criteria not met
return false
return false
end
elseif criteriaKey == 'modType' then
if criteriaValue ~= nil and scopeData.value ~= nil then
local isInverted = modDefn.inverted
if isInverted == nil then
isInverted = false
end
local isPositive = ((isInverted and scopeData.value < 0) or (not isInverted and scopeData.value > 0))
if not (
(criteriaValue == 'pos' and isPositive)
or (criteriaValue == 'neg' and not isPositive)
) then
-- Mod type criteria not met
return false
end
end
end
elseif criteriaValue ~= nil and criteriaKey ~= 'key' then
elseif criteriaValue ~= nil and criteriaKey ~= 'key' then
Line 174: Line 257:
-- 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


for _, allowedScope in ipairs(modDefn.allowedScopes) do
-- Add all scopes
if Shared.tableIsEmpty(allowedScope.scopes) then
for _, allowedScope in ipairs(modDefn.allowedScopes) do
-- No scope definitions, so add modifier once with an empty scope
table.insert(matchCriteria, {
table.insert(matchCriteria, {
["mod"] = modDefn,
["mod"] = modDefn,
["scope"] = {}
["scope"] = allowedScope.scopes or {},
["props"] = modProps
})
})
else
-- Add all available scope definitions
for _, scopeDefn in ipairs(allowedScope.scopes) do
table.insert(matchCriteria, {
["mod"] = modDefn,
["scope"] = scopeDefn
})
end
end
end
elseif modType == 'alias' then
-- For alias IDs, simply add these one at a time to the table
table.insert(matchCriteria, {
["alias"] = modifierID,
["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 219: Line 299:
-- 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 233: Line 320:
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 239: Line 326:
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 247: Line 335:
matchCriteriaMap[modLocalID] = {}
matchCriteriaMap[modLocalID] = {}
end
end
table.insert(matchCriteriaMap[modLocalID], { ["scope"] = scopeDefn, ["alias"] = modAlias, ["valueType"] = valueType })
table.insert(matchCriteriaMap[modLocalID], {
["mod"] = modDefn,
["scope"] = scopeDefn,
["alias"] = modAlias,
["props"] = propCriteria
})
end
end


Line 269: Line 362:
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 modDefn, scopeDefn, modAlias, propCriteria = matchDefn.mod, matchDefn.scope, matchDefn.alias, matchDefn.props
local dataCriteria = {
["skillID"] = skillID,
["valueType"] = matchDefn.valueType
}
local matchKey = 'unmatched'
local matchKey = 'unmatched'
-- Check that:
-- Check that:
Line 281: Line 370:
if (
if (
p.doScopeDefinitionsMatch(modScopeDefn, scopeDefn)
p.doScopeDefinitionsMatch(modScopeDefn, scopeDefn)
and p.checkScopeDataMeetsCriteria(scopeData, scopeDefn, modAlias)
and p.checkScopeDataMeetsCriteria(modDefn, scopeData, scopeDefn, modAlias)
and p.checkScopeDataMeetsCriteria(scopeData, scopeDefn, dataCriteria)
and p.checkScopeDataMeetsCriteria(modDefn, scopeData, scopeDefn, propCriteria)
) then
) then
-- Add to matched table
-- Add to matched table
Line 656: Line 745:


function p.test3()
function p.test3()
local item = GameData.getEntityByID('items', 'melvorD:Aorpheats_Signet_Ring')
local item = GameData.getEntityByID('items', 'melvorItA:Corrupted_Light_Consumable_I')
local matchCriteria = {
local matchCriteria = {
{
{
Line 664: Line 753:
--}
--}
-- Should no longer match if changed to increased
-- Should no longer match if changed to increased
["alias"] = 'decreasedChanceToDoubleItemsSkill',
["alias"] = 'increasedChanceNoDamageMining',
},
},
{
{
Line 684: Line 773:
["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 700: Line 797:
return p.getModifierValue(matchedMods.matched)
return p.getModifierValue(matchedMods.matched)
--return p.getMatchingModifiers(purch.contains.modifiers, matchCriteria)
--return p.getMatchingModifiers(purch.contains.modifiers, matchCriteria)
end
 
-- Checks p.getMatchCriteriaFromIDs() and p.getMatchingModifiers()
-- Any entity processed by this should return a table with all modifiers
-- matched and none unmatched. Unmatched modifiers implies an issue with one
-- of the aforementioned functions
function p.test5()
local ent = GameData.getEntityByID('items', 'melvorF:Miners_Helmet')
local entMods = ent.modifiers
if entMods ~= nil then
local modIDs = {}
for modID, modDet in pairs(entMods) do
table.insert(modIDs, {
["id"] = modID,
["type"] = 'id',
["props"] = {}
})
end
local matchCriteria = p.getMatchCriteriaFromIDs(modIDs)
mw.logObject(matchCriteria)
mw.log('=======================================================')
local matchingMods = p.getMatchingModifiers(entMods, matchCriteria)
return matchingMods
end
return nil
end
end


return p
return p