Anonymous

Module:GameData/doc: Difference between revisions

From Melvor Idle
Amend equipmentStat handling for resistances
(Update JS - Support localization overrides)
(Amend equipmentStat handling for resistances)
Line 612: Line 612:
// TODO Handle dependentData
// TODO Handle dependentData
}
}
}
getDataToModify(modCat) {
switch (modCat) {
case 'combatAreaCategories':
case 'dungeons':
case 'equipmentSlots':
case 'modifiers':
case 'shopUpgradeChains':
case 'shopPurchases':
return this.gameData[modCat];
case 'cookingCategories':
const cookingSkill = this.getObjectByID(this.gameData.skillData, 'melvorD:Cooking', 'skillID');
return cookingSkill.data.categories;
case 'fletchingRecipes':
const fletchingSkill = this.getObjectByID(this.gameData.skillData, 'melvorD:Fletching', 'skillID');
return fletchingSkill.data.recipes;
}
return undefined;
}
}
applyDataModifications(modData) {
applyDataModifications(modData) {
Line 623: Line 641:
const modCat = modDataKeys[modCatID];
const modCat = modDataKeys[modCatID];
const catData = modData[modCat];
const catData = modData[modCat];
if (modCat === 'combatAreaCategories') {
const dataToModify = this.getDataToModify(modCat);
// The 'areas' property of elements within the category data are ordered data
if (dataToModify === undefined) {
console.warn(
`Could not apply data modification for category "${modCat}": Unable to retrieve category data to be modified`
);
}
else {
catData.forEach((modItem) => {
catData.forEach((modItem) => {
const modObjID = modItem.id;
const modObjID = modItem.id;
if (modObjID === undefined) {
if (modObjID === undefined) {
console.warn(
console.warn(
`Could not apply data modification: ID of object to be modified not found, category "${modCat}"`
`Could not apply data modification for category "${modCat}": ID of object to be modified not found`
);
);
} else {
} else {
const modObj = this.getObjectByID(this.gameData[modCat], modObjID);
const objToModify = this.getObjectByID(dataToModify, modObjID);
if (modObj === undefined) {
if (objToModify === undefined) {
console.warn(
console.warn(
`Could not apply data modification: Object with ID "${modObjID}" not found for category "${modCat}"`
`Could not apply data modification: Object with ID "${modObjID}" not found for ctaegory "${modCat}"`
);
);
} else {
modObj.areas = this.combineOrderedData(modObj.areas, modItem.areas.add);
}
}
}
else {
});
switch (modCat) {
} else if (modCat === 'shopUpgradeChains' || modCat === 'shopPurchases') {
case 'combatAreaCategories':
// Modify the root upgrade ID of shop upgrade chains, and modify attributes of shop purchases
// The 'areas' property of elements within the category data are ordered data
catData.forEach((modItem) => {
objToModify.areas = this.combineOrderedData(objToModify.areas, modItem.areas.add);
const modObjID = modItem.id;
break;
if (modObjID === undefined) {
case 'shopPurchases':
console.warn(
case 'shopUpgradeChains':
`Could not apply data modification: ID of object to be modified not found, category "${modCat}"`
// Modify the root upgrade ID of shop upgrade chains, and modify attributes of shop purchases
);
const overrideKeys = {
} else {
purchaseRequirements: {
const modObj = this.getObjectByID(this.gameData[modCat], modObjID);
sourceKey: 'newRequirements', // Key that holds the data in the data package
if (modObj === undefined) {
destKey: 'purchaseRequirementsOverrides', // Key to insert into within this.gameData
console.warn(
subKey: 'requirements', // Sub-key containing the override data
`Could not apply data modification: Object with ID "${modObjID}" not found for category "${modCat}"`
},
);
cost: {
} else {
sourceKey: 'newCosts',
const overrideKeys = {
destKey: 'costOverrides',
purchaseRequirements: {
subKey: 'cost',
sourceKey: 'newRequirements', // Key that holds the data in the data package
},
destKey: 'purchaseRequirementsOverrides', // Key to insert into within this.gameData
};
subKey: 'requirements', // Sub-key containing the override data
Object.keys(modItem)
},
.filter((k) => k !== 'id')
cost: {
.forEach((k) => {
sourceKey: 'newCosts',
const overrideKey = overrideKeys[k];
destKey: 'costOverrides',
if (overrideKey !== undefined) {
subKey: 'cost',
// Is an override specific to a gamemode, do not replace
},
// the key's existing data
};
const destKey = overrideKey.destKey;
Object.keys(modItem)
if (objToModify[destKey] === undefined) {
.filter((k) => k !== 'id')
objToModify[destKey] = [];
.forEach((k) => {
}
const overrideKey = overrideKeys[k];
modItem[k].forEach((gamemodeOverride) => {
if (overrideKey !== undefined) {
var newData = {};
// Is an override specific to a gamemode, do not replace
newData.gamemodeID = gamemodeOverride.gamemodeID;
// the key's existing data
newData[overrideKey.subKey] = gamemodeOverride[overrideKey.sourceKey];
const destKey = overrideKey.destKey;
objToModify[destKey].push(newData);
if (modObj[destKey] === undefined) {
});
modObj[destKey] = [];
} else {
}
objToModify[k] = modItem[k];
modItem[k].forEach((gamemodeOverride) => {
}
var newData = {};
newData.gamemodeID = gamemodeOverride.gamemodeID;
newData[overrideKey.subKey] = gamemodeOverride[overrideKey.sourceKey];
modObj[destKey].push(newData);
});
});
} else {
break;
modObj[k] = modItem[k];
case 'cookingCategories':
}
// Append to the list of shop upgrade IDs for cooking utilities/categories
});
case 'fletchingRecipes':
}
// Append to alternativeCosts property of recipes (e.g. Arrow shafts)
}
Object.keys(modItem)
});
.filter((k) => k !== 'id')
} else if (modCat === 'cookingCategories') {
.forEach((k) => {
// Append to the list of shop upgrade IDs for cooking utilities/categories
if ((k === 'shopUpgradeIDs') || (k === 'alternativeCosts')) {
catData.forEach((modItem) => {
if (objToModify[k] === undefined) {
const modObjID = modItem.id;
objToModify[k] = modItem[k];
const cookingSkill = this.getObjectByID(this.gameData.skillData, 'melvorD:Cooking', 'skillID');
} else {
if (modObjID === undefined) {
objToModify[k].push(...modItem[k]);
console.warn(
`Could not apply data modification: ID of object to be modified not found, category "${modCat}"`
);
} else if (cookingSkill === undefined) {
console.warn('Could not apply data modification: Data for skill "melvorD:Cooking" not found');
} else {
const modObj = this.getObjectByID(cookingSkill.data.categories, modObjID);
if (modObj === undefined) {
console.warn(
`Could not apply data modification: Object with ID "${modObjID}" not found for category "${modCat}"`
);
} else {
Object.keys(modItem)
.filter((k) => k !== 'id')
.forEach((k) => {
if (k === 'shopUpgradeIDs') {
if (modObj[k] === undefined) {
modObj[k] = modItem[k];
} else {
modObj[k].push(...modItem[k]);
}
} else {
console.warn(
`Could not apply data modification: Unhandled key "${k}" for category "${modCat}", object "${mobObjID}"`
);
}
});
}
}
});
} else if (modCat === 'fletchingRecipes') {
// Append to alternativeCosts property of recipes (e.g. Arrow shafts)
catData.forEach((modItem) => {
const modObjID = modItem.id;
const fletchingSkill = this.getObjectByID(this.gameData.skillData, 'melvorD:Fletching', 'skillID');
if (modObjID === undefined) {
console.warn(
`Could not apply data modification: ID of object to be modified not found, category "${modCat}"`
);
} else if (fletchingSkill === undefined) {
console.warn('Could not apply data modification: Data for skill "melvorD:Fletching" not found');
} else {
const modObj = this.getObjectByID(fletchingSkill.data.recipes, modObjID);
if (modObj === undefined) {
console.warn(
`Could not apply data modification: Object with ID "${modObjID}" not found for category "${modCat}"`
);
} else {
Object.keys(modItem)
.filter((k) => k !== 'id')
.forEach((k) => {
if (k === 'alternativeCosts') {
if (modObj[k] === undefined) {
modObj[k] = modItem[k];
} else {
modObj[k].push(...modItem[k]);
}
} else {
console.warn(
`Could not apply data modification: Unhandled key "${k}" for category "${modCat}", object "${mobObjID}"`
);
}
});
}
}
});
} else if (modCat === 'dungeons') {
catData.forEach((modItem) => {
const modObjID = modItem.id;
if (modObjID === undefined) {
console.warn(
`Could not apply data modification: ID of object to be modified not found, category "${modCat}"`
);
} else {
const modObj = this.getObjectByID(this.gameData.dungeons, modObjID);
if (modObj === undefined) {
console.warn(
`Could not apply data modification: Object with ID "${modObjID}" not found for category "${modCat}"`
);
} else {
Object.keys(modItem)
.filter((k) => k !== 'id')
.forEach((k) => {
if (k === 'gamemodeRewardItemIDs') {
// Add gamemode specific item rewards to dungeon data
const itemRules = modItem[k];
Object.keys(itemRules).forEach((ruleKey) => {
if (ruleKey === 'add') {
if (modObj[k] === undefined) {
modObj[k] = [];
}
}
itemRules[ruleKey].forEach((itemDef) => {
} else {
let gamemodeRewards = this.getObjectByID(modObj[k], itemDef.gamemodeID, 'gamemodeID');
console.warn(
if (gamemodeRewards === undefined) {
`Could not apply data modification: Unhandled key "${k}" for category "${modCat}", object "${mobObjID}"`
modObj[k].push({
);
gamemodeID: itemDef.gamemodeID,
}
itemIDs: itemDef.rewardItemIDs,
});
break;
case 'dungeons':
// Add gamemode specific data to dungeons
Object.keys(modItem)
.filter((k) => k !== 'id')
.forEach((k) => {
if (k === 'gamemodeRewardItemIDs') {
// Add gamemode specific item rewards to dungeon data
const itemRules = modItem[k];
Object.keys(itemRules).forEach((ruleKey) => {
if (ruleKey === 'add') {
if (objToModify[k] === undefined) {
objToModify[k] = [];
}
itemRules[ruleKey].forEach((itemDef) => {
let gamemodeRewards = this.getObjectByID(objToModify[k], itemDef.gamemodeID, 'gamemodeID');
if (gamemodeRewards === undefined) {
objToModify[k].push({
gamemodeID: itemDef.gamemodeID,
itemIDs: itemDef.rewardItemIDs,
});
} else {
gamemodeRewards.push(...itemDef.rewardItemIDs);
}
});
});
} else {
} else {
gamemodeRewards.push(...itemDef.rewardItemIDs);
console.warn(
`Could not apply data modification: Unknown rule for gamemode item rewards: "${ruleKey}", object "${modObjID}"`
);
}
}
});
});
} else if (k === 'gamemodeEntryRequirements') {
// Add or remove gamemode specific entry requirements to dungeon data
if (objToModify[k] === undefined) {
objToModify[k] = [];
}
objToModify[k].push(modItem[k]);
} else {
} else {
console.warn(
console.warn(
`Could not apply data modification: Unknown rule for gamemode item rewards: "${ruleKey}", object "${modObjID}"`
`Could not apply data modification: Unhandled key "${k}" for category "${modCat}", object "${modObjID}"`
);
);
}
}
});
});
} else if (k === 'gamemodeEntryRequirements') {
break;
// Add or remove gamemode specific entry requirements to dungeon data
case 'modifiers':
if (modObj[k] === undefined) {
// Add modifier aliases to existing mod scopes
modObj[k] = [];
if (objToModify.allowedScopes === undefined) {
}
console.warn(`Could not apply data modification: Modifier with ID ${modObjID} not found or modifier has no scopes`);
modObj[k].push(modItem[k]);
} else {
} else {
console.warn(
modItem.allowedScopes.forEach((srcScope) => {
`Could not apply data modification: Unhandled key "${k}" for category "${modCat}", object "${modObjID}"`
// Find scope within modifier objToModify with matching scopes definition
);
const srcScopeKeys = Object.keys(srcScope.scopes);
}
objToModify.allowedScopes.forEach((destScope) => {
});
const destScopeKeys = Object.keys(destScope.scopes);
}
const scopeMatch = (
}
srcScopeKeys.length === destScopeKeys.length
});
&& srcScopeKeys.every((k) => destScope.scopes[k] !== undefined && srcScope.scopes[k] == destScope.scopes[k])
} else if (modCat === 'modifiers') {
);
catData.forEach((modItem) => {
if (scopeMatch) {
const modObjID = modItem.id;
// Scopes match - add aliases to modifier allowedScope definition
if (modObjID === undefined) {
const aliasKeys = ['posAliases', 'negAliases'];
console.warn(
aliasKeys.forEach((aliasKey) => {
`Could not apply data modification: ID of object to be modified not found, category "${modCat}"`);
if (srcScope[aliasKey] !== undefined) {
} else {
if (destScope[aliasKey] === undefined) {
// Find modifier definition
destScope[aliasKey] = [];
const modParentObj = this.getObjectByID(this.gameData.modifiers, modObjID);
}
if ((modParentObj === undefined) || (modParentObj.allowedScopes === undefined)) {
destScope[aliasKey].push(...srcScope[aliasKey]);
console.warn(`Could not apply data modification: Modifier with ID ${modObjID} not found or modifier has no scopes`);
}
} else {
});
modItem.allowedScopes.forEach((srcScope) => {
// Find scope within modifier modParentObj with matching scopes definition
const srcScopeKeys = Object.keys(srcScope.scopes);
modParentObj.allowedScopes.forEach((destScope) => {
const destScopeKeys = Object.keys(destScope.scopes);
const scopeMatch = (
srcScopeKeys.length === destScopeKeys.length
&& srcScopeKeys.every((k) => destScope.scopes[k] !== undefined && srcScope.scopes[k] == destScope.scopes[k])
);
if (scopeMatch) {
// Scopes match - add aliases to modifier allowedScope definition
const aliasKeys = ['posAliases', 'negAliases'];
aliasKeys.forEach((aliasKey) => {
if (srcScope[aliasKey] !== undefined) {
if (destScope[aliasKey] === undefined) {
destScope[aliasKey] = [];
}
}
destScope[aliasKey].push(...srcScope[aliasKey]);
});
}
});
});
}
}
});
break;
});
// case 'equipmentSlots':
// TODO
default:
console.warn(
`Could not apply data modification: Unhandled category "${modCat}"`
);
}
}
}
}
}
});
});
} else {
console.warn(`Could not apply data modification: Unhandled category "${modCat}"`);
}
}
}
}
Line 1,064: Line 1,009:
const newStats = {};
const newStats = {};
entity.forEach((stat) => {
entity.forEach((stat) => {
if (newStats[stat.key] === undefined) {
let statKey = stat.key;
newStats[stat.key] = stat.value;
if (stat.damageType !== undefined) {
statKey += this.getLocalID(stat.damageType);
}
if (newStats[statKey] === undefined) {
newStats[statKey] = stat.value;
} else {
} else {
newStats[stat.key] += stat.value;
newStats[statKey] += stat.value;
}
}
});
});