Index: binaries/data/mods/public/globalscripts/AttackEffects.js =================================================================== --- binaries/data/mods/public/globalscripts/AttackEffects.js +++ binaries/data/mods/public/globalscripts/AttackEffects.js @@ -1,17 +1,61 @@ -// TODO: could be worth putting this in json files someday -const g_EffectTypes = ["Damage", "Capture", "ApplyStatus"]; -const g_EffectReceiver = { - "Damage": { - "IID": "IID_Health", - "method": "TakeDamage" - }, - "Capture": { - "IID": "IID_Capturable", - "method": "Capture", - "sound": "capture" - }, - "ApplyStatus": { - "IID": "IID_StatusEffectsReceiver", - "method": "ApplyStatus" +/** + * This class provides a cache for accessing attack effects stored in JSON files. + */ +class AttackEffects +{ + constructor() + { + let effectsDataObj = {}; + this.effectReceivers = []; + this.effectSounds = {}; + + for (let filename of Engine.ListDirectoryFiles("simulation/data/attack_effects", "*.json", false)) + { + let data = Engine.ReadJSONFile(filename); + if (!data) + continue; + + if (effectsDataObj[data.code]) + { + error("Encountered two effect types with the code " + data.name + "."); + continue; + } + + effectsDataObj[data.code] = data; + + this.effectReceivers.push({ + "type": data.code, + "IID": data.IID, + "method": data.method + }); + this.effectSounds[data.code] = data.sound || ""; + } + + let effDataSort = (a, b) => a.order < b.order ? -1 : a.order > b.order ? 1 : 0; + let effSort = (a, b) => effDataSort( + effectsDataObj[a.type], + effectsDataObj[b.type] + ); + this.effectReceivers.sort(effSort); + + deepfreeze(this.effectReceivers); + deepfreeze(this.effectSounds); } -}; + + /** + * @return {Object[]} - The effects possible with their data. + */ + Receivers() + { + return this.effectReceivers; + } + + /** + * @param {string} type - The type of effect to get the receiving sound for. + * @return {string} - The name of the soundgroup to play. + */ + GetSound(type) + { + return this.effectSounds[type] || ""; + } +} Index: binaries/data/mods/public/globalscripts/tests/test_AttackEffects.js =================================================================== --- /dev/null +++ binaries/data/mods/public/globalscripts/tests/test_AttackEffects.js @@ -0,0 +1,31 @@ +let effects = { + "eff_A": { + "code": "a", + "name": "A", + "order": "2", + "IID": "IID_A", + "method": "doA" + }, + "eff_B": { + "code": "b", + "name": "B", + "order": "1", + "IID": "IID_B", + "method": "doB" + } +}; + +Engine.ListDirectoryFiles = () => Object.keys(effects); +Engine.ReadJSONFile = (file) => effects[file]; + +let attackEffects = new AttackEffects(); + +TS_ASSERT_UNEVAL_EQUALS(attackEffects.Receivers(), [{ + "type": "b", + "IID": "IID_B", + "method": "doB" +}, { + "type": "a", + "IID": "IID_A", + "method": "doA" +}]); Index: binaries/data/mods/public/l10n/messages.json =================================================================== --- binaries/data/mods/public/l10n/messages.json +++ binaries/data/mods/public/l10n/messages.json @@ -540,6 +540,19 @@ ], "context": "status effect" } + }, + { + "extractor": "json", + "filemasks": [ + "simulation/data/attack_effects/*.json" + ], + "options": { + "keywords": [ + "name", + "description" + ], + "context": "attack effect" + } } ] }, Index: binaries/data/mods/public/simulation/components/AttackDetection.js =================================================================== --- binaries/data/mods/public/simulation/components/AttackDetection.js +++ binaries/data/mods/public/simulation/components/AttackDetection.js @@ -128,10 +128,7 @@ "targetIsDomesticAnimal": targetIsDomesticAnimal }); - let soundGroup = "attacked"; - if (g_EffectReceiver[type] && g_EffectReceiver[type].sound) - soundGroup += '_' + g_EffectReceiver[type].sound; - + let soundGroup = g_AttackEffects.GetSound(type); if (attackerOwner === 0) soundGroup += "_gaia"; Index: binaries/data/mods/public/simulation/components/tests/test_Attack.js =================================================================== --- binaries/data/mods/public/simulation/components/tests/test_Attack.js +++ binaries/data/mods/public/simulation/components/tests/test_Attack.js @@ -1,3 +1,26 @@ +AttackEffects = class AttackEffects +{ + constructor() {} + Receivers() + { + return [{ + "type": "Damage", + "IID": "IID_Health", + "method": "TakeDamage" + }, + { + "type": "Capture", + "IID": "IID_Capturable", + "method": "Capture" + }, + { + "type": "ApplyStatus", + "IID": "IID_StatusEffectsReceiver", + "method": "ApplyStatus" + }]; + } +}; + Engine.LoadHelperScript("Attacking.js"); Engine.LoadHelperScript("Player.js"); Engine.LoadHelperScript("ValueModification.js"); Index: binaries/data/mods/public/simulation/components/tests/test_Damage.js =================================================================== --- binaries/data/mods/public/simulation/components/tests/test_Damage.js +++ binaries/data/mods/public/simulation/components/tests/test_Damage.js @@ -1,3 +1,16 @@ +AttackEffects = class AttackEffects +{ + constructor() {} + Receivers() + { + return [{ + "type": "Damage", + "IID": "IID_Health", + "method": "TakeDamage" + }]; + } +}; + Engine.LoadHelperScript("Attacking.js"); Engine.LoadHelperScript("Player.js"); Engine.LoadHelperScript("Position.js"); Index: binaries/data/mods/public/simulation/components/tests/test_DeathDamage.js =================================================================== --- binaries/data/mods/public/simulation/components/tests/test_DeathDamage.js +++ binaries/data/mods/public/simulation/components/tests/test_DeathDamage.js @@ -1,3 +1,7 @@ +AttackEffects = class AttackEffects +{ +}; + Engine.LoadHelperScript("Attacking.js"); Engine.LoadHelperScript("ValueModification.js"); Engine.LoadComponentScript("interfaces/DeathDamage.js"); Index: binaries/data/mods/public/simulation/components/tests/test_Resistance.js =================================================================== --- binaries/data/mods/public/simulation/components/tests/test_Resistance.js +++ binaries/data/mods/public/simulation/components/tests/test_Resistance.js @@ -1,3 +1,26 @@ +AttackEffects = class AttackEffects +{ + constructor() {} + Receivers() + { + return [{ + "type": "Damage", + "IID": "IID_Health", + "method": "TakeDamage" + }, + { + "type": "Capture", + "IID": "IID_Capturable", + "method": "Capture" + }, + { + "type": "ApplyStatus", + "IID": "IID_StatusEffectsReceiver", + "method": "ApplyStatus" + }]; + } +}; + Engine.LoadHelperScript("Attacking.js"); Engine.LoadHelperScript("Player.js"); Engine.LoadHelperScript("ValueModification.js"); Index: binaries/data/mods/public/simulation/data/attack_effects/applystatus.json =================================================================== --- /dev/null +++ binaries/data/mods/public/simulation/data/attack_effects/applystatus.json @@ -0,0 +1,9 @@ +{ + "code": "ApplyStatus", + "description": "Various (timed) effects.", + "IID": "IID_StatusEffectsReceiver", + "method": "ApplyStatus", + "name": "Apply Status", + "order": 3, + "sound": "attacked" +} Index: binaries/data/mods/public/simulation/data/attack_effects/capture.json =================================================================== --- /dev/null +++ binaries/data/mods/public/simulation/data/attack_effects/capture.json @@ -0,0 +1,9 @@ +{ + "code": "Capture", + "description": "Reduces capture points of a target.", + "IID": "IID_Capturable", + "method": "Capture", + "name": "Capture", + "order": 2, + "sound": "attacked_capture" +} Index: binaries/data/mods/public/simulation/data/attack_effects/damage.json =================================================================== --- /dev/null +++ binaries/data/mods/public/simulation/data/attack_effects/damage.json @@ -0,0 +1,9 @@ +{ + "code": "Damage", + "description": "Reduces the health of a target.", + "IID": "IID_Health", + "method": "TakeDamage", + "name": "Damage", + "order": 1, + "sound": "attacked" +} Index: binaries/data/mods/public/simulation/helpers/Attacking.js =================================================================== --- binaries/data/mods/public/simulation/helpers/Attacking.js +++ binaries/data/mods/public/simulation/helpers/Attacking.js @@ -307,17 +307,16 @@ bonusMultiplier *= !attackData.Bonuses ? 1 : this.GetAttackBonus(attacker, target, attackType, attackData.Bonuses); let targetState = {}; - for (let effectType of g_EffectTypes) + for (let receiver of g_AttackEffects.Receivers()) { - if (!attackData[effectType]) + if (!attackData[receiver.type]) continue; - let receiver = g_EffectReceiver[effectType]; let cmpReceiver = Engine.QueryInterface(target, global[receiver.IID]); if (!cmpReceiver) continue; - Object.assign(targetState, cmpReceiver[receiver.method](this.GetTotalAttackEffects(target, attackData, effectType, bonusMultiplier, cmpResistance), attacker, attackerOwner)); + Object.assign(targetState, cmpReceiver[receiver.method](this.GetTotalAttackEffects(target, attackData, receiver.type, bonusMultiplier, cmpResistance), attacker, attackerOwner)); } if (!Object.keys(targetState).length) @@ -378,3 +377,5 @@ var AttackingInstance = new Attacking(); Engine.RegisterGlobal("Attacking", AttackingInstance); + +Engine.RegisterGlobal("g_AttackEffects", new AttackEffects()); Index: binaries/data/mods/public/simulation/helpers/tests/test_Attacking.js =================================================================== --- binaries/data/mods/public/simulation/helpers/tests/test_Attacking.js +++ binaries/data/mods/public/simulation/helpers/tests/test_Attacking.js @@ -1,3 +1,26 @@ +AttackEffects = class AttackEffects +{ + constructor() {} + Receivers() + { + return [{ + "type": "Damage", + "IID": "IID_Health", + "method": "TakeDamage" + }, + { + "type": "Capture", + "IID": "IID_Capturable", + "method": "Capture" + }, + { + "type": "ApplyStatus", + "IID": "IID_StatusEffectsReceiver", + "method": "ApplyStatus" + }]; + } +}; + Engine.LoadHelperScript("Attacking.js"); Engine.LoadComponentScript("interfaces/Capturable.js"); Engine.LoadComponentScript("interfaces/Health.js");