Get attack effects from JSON.

Reads attack effects from JSON files to allow easier introduction (one
still needs to modify other components).

Differential revision: D2661
Comments by: @Angen, @bb, @Stan, @wraitii
This was SVN commit r24500.
This commit is contained in:
Freagarach 2021-01-02 07:09:08 +00:00
parent 2847eb2a20
commit 7f7a3edfae
13 changed files with 223 additions and 24 deletions

View file

@ -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] || "";
}
}

View file

@ -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"
}]);

View file

@ -540,6 +540,19 @@
],
"context": "status effect"
}
},
{
"extractor": "json",
"filemasks": [
"simulation/data/attack_effects/*.json"
],
"options": {
"keywords": [
"name",
"description"
],
"context": "effect caused by an attack"
}
}
]
},

View file

@ -128,10 +128,7 @@ AttackDetection.prototype.AttackAlert = function(target, attacker, type, attacke
"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";

View file

@ -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");

View file

@ -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");

View file

@ -1,3 +1,7 @@
AttackEffects = class AttackEffects
{
};
Engine.LoadHelperScript("Attacking.js");
Engine.LoadHelperScript("ValueModification.js");
Engine.LoadComponentScript("interfaces/DeathDamage.js");

View file

@ -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");

View file

@ -0,0 +1,9 @@
{
"code": "ApplyStatus",
"description": "Various (timed) effects.",
"IID": "IID_StatusEffectsReceiver",
"method": "ApplyStatus",
"name": "Apply Status",
"order": 3,
"sound": "attacked"
}

View file

@ -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"
}

View file

@ -0,0 +1,9 @@
{
"code": "Damage",
"description": "Reduces the health of a target.",
"IID": "IID_Health",
"method": "TakeDamage",
"name": "Damage",
"order": 1,
"sound": "attacked"
}

View file

@ -307,17 +307,16 @@ Attacking.prototype.HandleAttackEffects = function(target, attackType, attackDat
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 @@ Attacking.prototype.GetAttackBonus = function(source, target, type, template)
var AttackingInstance = new Attacking();
Engine.RegisterGlobal("Attacking", AttackingInstance);
Engine.RegisterGlobal("g_AttackEffects", new AttackEffects());

View file

@ -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");