Index: binaries/data/mods/public/simulation/components/Attack.js =================================================================== --- binaries/data/mods/public/simulation/components/Attack.js +++ binaries/data/mods/public/simulation/components/Attack.js @@ -2,6 +2,23 @@ var g_AttackTypes = ["Melee", "Ranged", "Capture"]; +Attack.prototype.statusEffectsSchema = + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + ""; + Attack.prototype.bonusesSchema = "" + "" + @@ -187,6 +204,7 @@ "" + "" + "" + + Attack.prototype.statusEffectsSchema + Attack.prototype.bonusesSchema + Attack.prototype.preferredClassesSchema + Attack.prototype.restrictedClassesSchema + @@ -577,7 +595,8 @@ "bonus": this.GetBonusTemplate(type), "isSplash": false, "attackerOwner": attackerOwner, - "attackImpactSound": attackImpactSound + "attackImpactSound": attackImpactSound, + "statusEffects": this.template[type].StatusEffects }; if (this.template[type].Splash) { Index: binaries/data/mods/public/simulation/components/Damage.js =================================================================== --- binaries/data/mods/public/simulation/components/Damage.js +++ binaries/data/mods/public/simulation/components/Damage.js @@ -93,6 +93,7 @@ * @param {Vector3D} data.direction - the unit vector defining the direction. * @param {Object} data.bonus - the attack bonus template from the attacker. * @param {string} data.attackImpactSound - the name of the sound emited on impact. + * @param {Object} data.statusEffects - status effects eg. poisoning, burning etc. * ***When splash damage*** * @param {boolean} data.friendlyFire - a flag indicating if allied entities are also damaged. * @param {number} data.radius - the radius of the splash damage. @@ -136,6 +137,12 @@ data.multiplier = GetDamageBonus(data.target, data.bonus); this.CauseDamage(data); cmpProjectileManager.RemoveProjectile(data.projectileId); + + // Do the status change, eg. poisoning, burning etc. + let cmpStatus = Engine.QueryInterface(data.target, IID_Status); + if (cmpStatus && data.statusEffects) + cmpStatus.StartEffect(data.statusEffects); + return; } @@ -160,6 +167,7 @@ "attackerOwner": data.attackerOwner }); cmpProjectileManager.RemoveProjectile(data.projectileId); + break; } }; @@ -236,7 +244,7 @@ * @param {Object} data - the data passed by the caller. * @param {Object} data.strengths - data in the form of { 'hack': number, 'pierce': number, 'crush': number }. * @param {number} data.target - the entity id of the target. - * @param {number} data.attacker - the entity id og the attacker. + * @param {number} data.attacker - the entity id of the attacker. * @param {number} data.multiplier - the damage multiplier. * @param {string} data.type - the type of damage. * @param {number} data.attackerOwner - the player id of the attacker. Index: binaries/data/mods/public/simulation/components/Status.js =================================================================== --- binaries/data/mods/public/simulation/components/Status.js +++ binaries/data/mods/public/simulation/components/Status.js @@ -0,0 +1,40 @@ +function Status() {} + +Status.prototype.Init = function() +{ + this.isBurning = false; +} + +Status.prototype.StartEffect = function(statusEffects) +{ + if (!statusEffects || !statusEffects.Burn) + return; + + // TODO: multiple burning attack may reset the duration + if (this.isBurning) + return; + + this.isBurning = true; + + let effect = statusEffects.Burn; + this.duration = +effect.Duration; + this.damage = +effect.Damage; + + let cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer); + this.timer = cmpTimer.SetInterval(this.entity, IID_Status, "ExecuteEffect", 0, +effect.Interval, null); +} + +Status.prototype.ExecuteEffect = function() +{ + let cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer); + if (cmpTimer.GetTime(this.timer) > this.duration) + { + cmpTimer.CancelTimer(this.timer); + return; + } + + let cmpHealth = Engine.QueryInterface(this.entity, IID_Health); + cmpHealth.Reduce(this.damage); +}; + +Engine.RegisterComponentType(IID_Status, "Status", Status); Index: binaries/data/mods/public/simulation/components/interfaces/Status.js =================================================================== --- binaries/data/mods/public/simulation/components/interfaces/Status.js +++ binaries/data/mods/public/simulation/components/interfaces/Status.js @@ -0,0 +1 @@ +Engine.RegisterInterface("Status"); 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 @@ -12,6 +12,7 @@ Engine.LoadComponentScript("interfaces/Loot.js"); Engine.LoadComponentScript("interfaces/Player.js"); Engine.LoadComponentScript("interfaces/Promotion.js"); +Engine.LoadComponentScript("interfaces/Status.js"); Engine.LoadComponentScript("interfaces/TechnologyManager.js"); Engine.LoadComponentScript("interfaces/Timer.js"); Engine.LoadComponentScript("Attack.js"); Index: binaries/data/mods/public/simulation/components/tests/test_Status.js =================================================================== --- binaries/data/mods/public/simulation/components/tests/test_Status.js +++ binaries/data/mods/public/simulation/components/tests/test_Status.js @@ -0,0 +1,48 @@ +Engine.LoadComponentScript("interfaces/Health.js"); +Engine.LoadComponentScript("interfaces/Status.js"); +Engine.LoadComponentScript("interfaces/Timer.js"); + +Engine.LoadComponentScript("Status.js"); +Engine.LoadComponentScript("Timer.js"); + +function testStatusChange() +{ + let target = 42; + let attacker = 43; + + let cmpStatus = ConstructComponent(target, "Status"); + let cmpTimer = ConstructComponent(SYSTEM_ENTITY, "Timer"); + let statusEffects = { + "Burn": { + "Duration": 20000, + "Interval": 10000, + "Damage": 1 + } + }; + + let health = 10; + + AddMock(target, IID_Health, { + "Reduce": (amount) => { health -= amount; } + }); + + // damage scheduled: 0 sec, 10 sec, 20 sec + cmpStatus.StartEffect(statusEffects); + + cmpTimer.OnUpdate({ turnLength: 1 }); + TS_ASSERT_EQUALS(health, 9); // 1 sec + + cmpTimer.OnUpdate({ turnLength: 8 }); + TS_ASSERT_EQUALS(health, 9); // 9 sec + + cmpTimer.OnUpdate({ turnLength: 1 }); + TS_ASSERT_EQUALS(health, 8); // 10 sec + + cmpTimer.OnUpdate({ turnLength: 10 }); + TS_ASSERT_EQUALS(health, 7); // 20 sec + + cmpTimer.OnUpdate({ turnLength: 10 }); + TS_ASSERT_EQUALS(health, 7); // 30 sec +} + +testStatusChange(); Index: binaries/data/mods/public/simulation/templates/template_structure.xml =================================================================== --- binaries/data/mods/public/simulation/templates/template_structure.xml +++ binaries/data/mods/public/simulation/templates/template_structure.xml @@ -1,5 +1,6 @@ + 1 Index: binaries/data/mods/public/simulation/templates/template_unit.xml =================================================================== --- binaries/data/mods/public/simulation/templates/template_unit.xml +++ binaries/data/mods/public/simulation/templates/template_unit.xml @@ -1,5 +1,6 @@ + 1 Index: binaries/data/mods/public/simulation/templates/units/iber_champion_cavalry.xml =================================================================== --- binaries/data/mods/public/simulation/templates/units/iber_champion_cavalry.xml +++ binaries/data/mods/public/simulation/templates/units/iber_champion_cavalry.xml @@ -4,6 +4,13 @@ 5 15 + + + 50000 + 1000 + 1 + +