Page MenuHomeWildfire Games

Move duplicated "Attack.js" schema code to helper.
Needs ReviewPublic

Authored by Freagarach on Mon, Jul 22, 7:45 AM.

Details

Reviewers
None
Group Reviewers
Restricted Owners Package(Owns No Changed Paths)
Summary

As mentioned by @bb (here) there are some schema's duplicated in Attack.js and DeathDamage.js (and in the future maybe in ProximityDamage.js; D1838), which could be moved to a seperate helper.
Currently moved:

  • Status effects (introduced in rP22304)
  • Bonuses (introduced in rP10804)
  • Preferred classes (introduced in rP11710)
  • Restricted classes (introduced in rP11710)

The reason that the bonus schema was duplicated was that it was first only called from Attack.js itself, but with the introduction of DeathDamage.js (rP19950) it was copy-pastad to that file as well. In the future, we probably want to support status effects for death damage as well.
With that in mind the move is even more logical.

Test Plan

Verify that everything works as it did before.

  • Grepped for bonusesschema and checked all occurences.
  • Grepped for statuseffects and checked all occurences.

Diff Detail

Repository
rP 0 A.D. Public Repository
Branch
/ps/trunk
Lint
Lint OK
Unit
No Unit Test Coverage
Build Status
Buildable 8595
Build 14075: Vulcan BuildJenkins
Build 14074: arc lint + arc unit

Event Timeline

Freagarach created this revision.Mon, Jul 22, 7:45 AM
Freagarach edited the test plan for this revision. (Show Details)Mon, Jul 22, 7:49 AM
Freagarach edited the test plan for this revision. (Show Details)

Successful build - Chance fights ever on the side of the prudent.

Linter detected issues:
Executing section Source...
Executing section JS...
|    | [NORMAL] ESLintBear (no-extra-semi):
|    | Unnecessary semicolon.
|----|    | /zpool0/trunk/binaries/data/mods/public/simulation/helpers/Attack.js
|    |++++| /zpool0/trunk/binaries/data/mods/public/simulation/helpers/Attack.js
|  20|  20| 			"</element>" +
|  21|  21| 		"</optional>";
|  22|  22| 	return schema;
|  23|    |-};
|    |  23|+}
|  24|  24| 
|  25|  25| /**
|  26|  26|  * Builds a RelaxRNG schema for bonuses.
|    | [NORMAL] ESLintBear (no-extra-semi):
|    | Unnecessary semicolon.
|----|    | /zpool0/trunk/binaries/data/mods/public/simulation/helpers/Attack.js
|    |++++| /zpool0/trunk/binaries/data/mods/public/simulation/helpers/Attack.js
|  46|  46| 			"</element>" +
|  47|  47| 		"</optional>";
|  48|  48| 	return schema;
|  49|    |-};
|    |  49|+}
|  50|  50| 
|  51|  51| /**
|  52|  52|  * Builds a RelaxRNG schema for preferred classes.
|    | [NORMAL] ESLintBear (no-extra-semi):
|    | Unnecessary semicolon.
|----|    | /zpool0/trunk/binaries/data/mods/public/simulation/helpers/Attack.js
|    |++++| /zpool0/trunk/binaries/data/mods/public/simulation/helpers/Attack.js
|  65|  65| 			"</element>" +
|  66|  66| 		"</optional>";
|  67|  67| 	return schema;
|  68|    |-};
|    |  68|+}
|  69|  69| 
|  70|  70| /**
|  71|  71|  * Builds a RelaxRNG schema for restricted classes.
|    | [NORMAL] ESLintBear (no-extra-semi):
|    | Unnecessary semicolon.
|----|    | /zpool0/trunk/binaries/data/mods/public/simulation/helpers/Attack.js
|    |++++| /zpool0/trunk/binaries/data/mods/public/simulation/helpers/Attack.js
|  84|  84| 			"</element>" +
|  85|  85| 		"</optional>";
|  86|  86| 	return schema;
|  87|    |-};
|    |  87|+}
|  88|  88| 
|  89|  89| Engine.RegisterGlobal("BuildStatusEffectsSchema", BuildStatusEffectsSchema);
|  90|  90| Engine.RegisterGlobal("BuildBonusesSchema", BuildBonusesSchema);

binaries/data/mods/public/simulation/helpers/Attack.js
|  23| };
|    | [NORMAL] JSHintBear:
|    | Unnecessary semicolon.

binaries/data/mods/public/simulation/helpers/Attack.js
|  49| };
|    | [NORMAL] JSHintBear:
|    | Unnecessary semicolon.

binaries/data/mods/public/simulation/helpers/Attack.js
|  68| };
|    | [NORMAL] JSHintBear:
|    | Unnecessary semicolon.

binaries/data/mods/public/simulation/helpers/Attack.js
|  87| };
|    | [NORMAL] JSHintBear:
|    | Unnecessary semicolon.
|    | [NORMAL] ESLintBear (spaced-comment):
|    | Expected space or tab after '//' in comment.
|----|    | /zpool0/trunk/binaries/data/mods/public/simulation/components/Attack.js
|    |++++| /zpool0/trunk/binaries/data/mods/public/simulation/components/Attack.js
| 478| 478| 
| 479| 479| 		let horizSpeed = +this.template[type].Projectile.Speed;
| 480| 480| 		let gravity = +this.template[type].Projectile.Gravity;
| 481|    |-		//horizSpeed /= 2; gravity /= 2; // slow it down for testing
|    | 481|+		// horizSpeed /= 2; gravity /= 2; // slow it down for testing
| 482| 482| 
| 483| 483| 		let cmpPosition = Engine.QueryInterface(this.entity, IID_Position);
| 484| 484| 		if (!cmpPosition || !cmpPosition.IsInWorld())
|    | [NORMAL] ESLintBear (no-trailing-spaces):
|    | Trailing spaces not allowed.
|----|    | /zpool0/trunk/binaries/data/mods/public/simulation/components/Attack.js
|    |++++| /zpool0/trunk/binaries/data/mods/public/simulation/components/Attack.js
| 525| 525| 		// TODO: Use unit rotation to implement x/z offsets.
| 526| 526| 		let deltaLaunchPoint = new Vector3D(0, this.template[type].Projectile.LaunchPoint["@y"], 0.0);
| 527| 527| 		let launchPoint = Vector3D.add(selfPosition, deltaLaunchPoint);
| 528|    |-		
|    | 528|+
| 529| 529| 		let cmpVisual = Engine.QueryInterface(this.entity, IID_Visual);
| 530| 530| 		if (cmpVisual)
| 531| 531| 		{
|    | [NORMAL] ESLintBear (curly):
|    | Unnecessary { after 'else'.
|----|    | /zpool0/trunk/binaries/data/mods/public/simulation/components/Attack.js
|    |++++| /zpool0/trunk/binaries/data/mods/public/simulation/components/Attack.js
| 597| 597| 			});
| 598| 598| 	}
| 599| 599| 	else
| 600|    |-	{
|    | 600|+	
| 601| 601| 		// Melee attack - hurt the target immediately
| 602| 602| 		cmpDamage.CauseDamage({
| 603| 603| 			"strengths": this.GetAttackStrengths(type),
| 607| 607| 			"type": type,
| 608| 608| 			"attackerOwner": attackerOwner
| 609| 609| 		});
| 610|    |-	}
|    | 610|+	
| 611| 611| };
| 612| 612| 
| 613| 613| /**

binaries/data/mods/public/simulation/components/Attack.js
| 468| ·»   let·cmpDamage·=·Engine.QueryInterface(SYSTEM_ENTITY,·IID_Damage);
|    | [NORMAL] ESLintBear (no-mixed-spaces-and-tabs):
|    | Mixed spaces and tabs.

binaries/data/mods/public/simulation/components/Attack.js
| 572| »   »   cmpTimer.SetTimeout(SYSTEM_ENTITY,·IID_Damage,·"MissileHit",·timeToTarget·*·1000·+·+this.template[type].Delay,·data);
|    | [NORMAL] JSHintBear:
|    | Confusing plusses.
|    | [NORMAL] ESLintBear (quote-props):
|    | Unquoted property 'turnLength' found.
|----|    | /zpool0/trunk/binaries/data/mods/public/simulation/components/tests/test_Damage.js
|    |++++| /zpool0/trunk/binaries/data/mods/public/simulation/components/tests/test_Damage.js
|  26|  26| 
|  27|  27| 	let cmpDamage = ConstructComponent(SYSTEM_ENTITY, "Damage");
|  28|  28| 	let cmpTimer = ConstructComponent(SYSTEM_ENTITY, "Timer");
|  29|    |-	cmpTimer.OnUpdate({ turnLength: 1 });
|    |  29|+	cmpTimer.OnUpdate({ "turnLength": 1 });
|  30|  30| 	let attacker = 11;
|  31|  31| 	let atkPlayerEntity = 1;
|  32|  32| 	let attackerOwner = 6;
|    | [NORMAL] ESLintBear (comma-spacing):
|    | A space is required after ','.
|----|    | /zpool0/trunk/binaries/data/mods/public/simulation/components/tests/test_Damage.js
|    |++++| /zpool0/trunk/binaries/data/mods/public/simulation/components/tests/test_Damage.js
|  64|  64| 		"position": targetPos,
|  65|  65| 		"isSplash": false,
|  66|  66| 		"projectileId": 9,
|  67|    |-		"direction": new Vector3D(1,0,0)
|    |  67|+		"direction": new Vector3D(1, 0,0)
|  68|  68| 	};
|  69|  69| 
|  70|  70| 	AddMock(atkPlayerEntity, IID_Player, {
|    | [NORMAL] ESLintBear (comma-spacing):
|    | A space is required after ','.
|----|    | /zpool0/trunk/binaries/data/mods/public/simulation/components/tests/test_Damage.js
|    |++++| /zpool0/trunk/binaries/data/mods/public/simulation/components/tests/test_Damage.js
|  64|  64| 		"position": targetPos,
|  65|  65| 		"isSplash": false,
|  66|  66| 		"projectileId": 9,
|  67|    |-		"direction": new Vector3D(1,0,0)
|    |  67|+		"direction": new Vector3D(1,0, 0)
|  68|  68| 	};
|  69|  69| 
|  70|  70| 	AddMock(atkPlayerEntity, IID_Player, {
|    | [NORMAL] ESLintBear (quote-props):
|    | Unquoted property 'turnLength' found.
|----|    | /zpool0/trunk/binaries/data/mods/public/simulation/components/tests/test_Damage.js
|    |++++| /zpool0/trunk/binaries/data/mods/public/simulation/components/tests/test_Damage.js
| 115| 115| 
| 116| 116| 	function TestDamage()
| 117| 117| 	{
| 118|    |-		cmpTimer.OnUpdate({ turnLength: 1 });
|    | 118|+		cmpTimer.OnUpdate({ "turnLength": 1 });
| 119| 119| 		TS_ASSERT(damageTaken);
| 120| 120| 		damageTaken = false;
| 121| 121| 	}
|    | [NORMAL] ESLintBear (key-spacing):
|    | Extra space after key 'hack'.
|----|    | /zpool0/trunk/binaries/data/mods/public/simulation/components/tests/test_Damage.js
|    |++++| /zpool0/trunk/binaries/data/mods/public/simulation/components/tests/test_Damage.js
| 157| 157| 		"origin": origin,
| 158| 158| 		"radius": 10,
| 159| 159| 		"shape": "Linear",
| 160|    |-		"strengths": { "hack" : 100, "pierce" : 0, "crush": 0 },
|    | 160|+		"strengths": { "hack": 100, "pierce" : 0, "crush": 0 },
| 161| 161| 		"direction": new Vector3D(1, 747, 0),
| 162| 162| 		"playersToDamage": [2],
| 163| 163| 		"type": "Ranged",
|    | [NORMAL] ESLintBear (key-spacing):
|    | Extra space after key 'pierce'.
|----|    | /zpool0/trunk/binaries/data/mods/public/simulation/components/tests/test_Damage.js
|    |++++| /zpool0/trunk/binaries/data/mods/public/simulation/components/tests/test_Damage.js
| 157| 157| 		"origin": origin,
| 158| 158| 		"radius": 10,
| 159| 159| 		"shape": "Linear",
| 160|    |-		"strengths": { "hack" : 100, "pierce" : 0, "crush": 0 },
|    | 160|+		"strengths": { "hack" : 100, "pierce": 0, "crush": 0 },
| 161| 161| 		"direction": new Vector3D(1, 747, 0),
| 162| 162| 		"playersToDamage": [2],
| 163| 163| 		"type": "Ranged",
|    | [NORMAL] ESLintBear (comma-spacing):
|    | A space is required after ','.
|----|    | /zpool0/trunk/binaries/data/mods/public/simulation/components/tests/test_Damage.js
|    |++++| /zpool0/trunk/binaries/data/mods/public/simulation/components/tests/test_Damage.js
| 164| 164| 		"attackerOwner": attackerOwner
| 165| 165| 	};
| 166| 166| 
| 167|    |-	let fallOff = function(x,y)
|    | 167|+	let fallOff = function(x, y)
| 168| 168| 	{
| 169| 169| 		return (1 - x * x / (data.radius * data.radius)) * (1 - 25 * y * y / (data.radius * data.radius));
| 170| 170| 	};
|    | [NORMAL] ESLintBear (key-spacing):
|    | Extra space after key 'hack'.
|----|    | /zpool0/trunk/binaries/data/mods/public/simulation/components/tests/test_Damage.js
|    |++++| /zpool0/trunk/binaries/data/mods/public/simulation/components/tests/test_Damage.js
| 316| 316| 		"origin": new Vector2D(3, 4),
| 317| 317| 		"radius": radius,
| 318| 318| 		"shape": "Circular",
| 319|    |-		"strengths": { "hack" : 100, "pierce" : 0, "crush": 0 },
|    | 319|+		"strengths": { "hack": 100, "pierce" : 0, "crush": 0 },
| 320| 320| 		"playersToDamage": [2],
| 321| 321| 		"type": "Ranged",
| 322| 322| 		"attackerOwner": 1
|    | [NORMAL] ESLintBear (key-spacing):
|    | Extra space after key 'pierce'.
|----|    | /zpool0/trunk/binaries/data/mods/public/simulation/components/tests/test_Damage.js
|    |++++| /zpool0/trunk/binaries/data/mods/public/simulation/components/tests/test_Damage.js
| 316| 316| 		"origin": new Vector2D(3, 4),
| 317| 317| 		"radius": radius,
| 318| 318| 		"shape": "Circular",
| 319|    |-		"strengths": { "hack" : 100, "pierce" : 0, "crush": 0 },
|    | 319|+		"strengths": { "hack" : 100, "pierce": 0, "crush": 0 },
| 320| 320| 		"playersToDamage": [2],
| 321| 321| 		"type": "Ranged",
| 322| 322| 		"attackerOwner": 1

binaries/data/mods/public/simulation/components/tests/test_Damage.js
| 126| »   type·=·data.type·=·"Ranged";
|    | [NORMAL] ESLintBear (no-multi-assign):
|    | Unexpected chained assignment.
Executing section cli...

Link to build: https://jenkins.wildfiregames.com/job/docker-differential/180/display/redirect

I think this is a good idea for bonus and status effects but would usefully wait for D2092 (since death damage could also then do capture damage...)
Further, I would put this in the Damage.js helper - and rename that to AttackEffects as discussed somewhere. I think it's all one and the same.


The question is preferred classes and restricted classes (ping @bb ). Are they a property of the attacker or the attack itself.
Preferred classes seem obviously the first - it's a hint to unitAI, relating to GetBestAttackAgainst (@Freagarach please split from D2044 ;) ).
What about restricted classes though? Right now they're a unitAI problem, that is you can't target an enemy if it's in the restricted classes. But if you randomly do it damage (e.g. a ranged attack that misses the main target), it will still be damaged normally.
There are two behaviours: making attacks ineffective (related to D2044), and hints to unitAI - which may or may not be needed. For walls for example - if we made the impervious to hack/pierce, they would effectively be restricted from damage by non-siege units right now.
Slaughter is another example: following D1938 we could easily change it to deal 'slaughter' damage, and make domestic animals impervious to all damage but slaughter damage.

IMO - don't put preferred classes and restricted classes here. Those are unitAI hints, not attack properties, and they should affect CanAttack and GetBestAttackAgainst only.

Slaughter is another example: following D1938 we could easily change it to deal 'slaughter' damage, and make domestic animals impervious to all damage but slaughter damage.

I envision a wall of sheep rising :D

IMO - don't put preferred classes and restricted classes here. Those are unitAI hints, not attack properties, and they should affect CanAttack and GetBestAttackAgainst only.

Well, the restricted classes ought to be in here for the trample damage, so that would not be a UnitAI hint only anymore. Unless there is a different idea to fix that (i.e. cavalry "trampling" buildings or elephants).

Freagarach planned changes to this revision.Mon, Jul 22, 9:49 AM

Well, the restricted classes ought to be in here for the trample damage, so that would not be a UnitAI hint only anymore. Unless there is a different idea to fix that (i.e. cavalry "trampling" buildings or elephants).

As said, I think we could do this using a new damage type (trample), which these units would be immune to, possibly.

But that needs some decision on how we want to do things. If restricted classes are part of the attacks, they become immunity and we must handle them as part of "attack effects" in D2092.

Well, the restricted classes ought to be in here for the trample damage, so that would not be a UnitAI hint only anymore. Unless there is a different idea to fix that (i.e. cavalry "trampling" buildings or elephants).

As said, I think we could do this using a new damage type (trample), which these units would be immune to, possibly.

But elephants *can* trample horses? So you would need to add two trample damage types (at least; possibly more).

Angen added a subscriber: Angen.EditedMon, Jul 22, 10:37 AM

trample should be mass vs mass, if something is bigger enough than you, you get trampled. Not class dependend.

In D2109#88058, @Angen wrote:

trample should be mass vs mass, if something is bigger enough than you, you get trampled. Not class dependend.

I actually have such a thing in my personal mod xD There mass also affects charge bonus and pushing behaviour.

bb added a comment.Thu, Jul 25, 1:04 PM

The question is preferred classes and restricted classes (ping @bb ). Are they a property of the attacker or the attack itself.
Preferred classes seem obviously the first - it's a hint to unitAI, relating to GetBestAttackAgainst (@Freagarach please split from D2044 ;) ).

Well I agree on the statement that preferred classes should be an attacker unitAI hint, which targets it should attack. However that has not much todo with GetBestAttackAgainst since there we already have chosen the target. Maybe preferred classes should be in the unitAI template instead?

There are two behaviours: making attacks ineffective (related to D2044), and hints to unitAI - which may or may not be needed. For walls for example - if we made the impervious to hack/pierce, they would effectively be restricted from damage by non-siege units right now.

If there are two behaviors maybe make two template entries, one for each?

Freagarach updated this revision to Diff 9118.Thu, Jul 25, 7:04 PM
Freagarach edited the summary of this revision. (Show Details)
Freagarach edited the test plan for this revision. (Show Details)

Reverted restricted/preferred classes.

Successful build - Chance fights ever on the side of the prudent.

Linter detected issues:
Executing section Source...
Executing section JS...
|    | [NORMAL] ESLintBear (spaced-comment):
|    | Expected space or tab after '//' in comment.
|----|    | /zpool0/trunk/binaries/data/mods/public/simulation/components/Attack.js
|    |++++| /zpool0/trunk/binaries/data/mods/public/simulation/components/Attack.js
| 498| 498| 
| 499| 499| 		let horizSpeed = +this.template[type].Projectile.Speed;
| 500| 500| 		let gravity = +this.template[type].Projectile.Gravity;
| 501|    |-		//horizSpeed /= 2; gravity /= 2; // slow it down for testing
|    | 501|+		// horizSpeed /= 2; gravity /= 2; // slow it down for testing
| 502| 502| 
| 503| 503| 		let cmpPosition = Engine.QueryInterface(this.entity, IID_Position);
| 504| 504| 		if (!cmpPosition || !cmpPosition.IsInWorld())
|    | [NORMAL] ESLintBear (no-trailing-spaces):
|    | Trailing spaces not allowed.
|----|    | /zpool0/trunk/binaries/data/mods/public/simulation/components/Attack.js
|    |++++| /zpool0/trunk/binaries/data/mods/public/simulation/components/Attack.js
| 545| 545| 		// TODO: Use unit rotation to implement x/z offsets.
| 546| 546| 		let deltaLaunchPoint = new Vector3D(0, this.template[type].Projectile.LaunchPoint["@y"], 0.0);
| 547| 547| 		let launchPoint = Vector3D.add(selfPosition, deltaLaunchPoint);
| 548|    |-		
|    | 548|+
| 549| 549| 		let cmpVisual = Engine.QueryInterface(this.entity, IID_Visual);
| 550| 550| 		if (cmpVisual)
| 551| 551| 		{

binaries/data/mods/public/simulation/components/Attack.js
| 488| ·»   let·cmpDamage·=·Engine.QueryInterface(SYSTEM_ENTITY,·IID_Damage);
|    | [NORMAL] ESLintBear (no-mixed-spaces-and-tabs):
|    | Mixed spaces and tabs.

binaries/data/mods/public/simulation/components/Attack.js
| 592| »   »   cmpTimer.SetTimeout(SYSTEM_ENTITY,·IID_Damage,·"MissileHit",·timeToTarget·*·1000·+·+this.template[type].Delay,·data);
|    | [NORMAL] JSHintBear:
|    | Confusing plusses.
|    | [NORMAL] ESLintBear (quote-props):
|    | Unquoted property 'turnLength' found.
|----|    | /zpool0/trunk/binaries/data/mods/public/simulation/components/tests/test_Damage.js
|    |++++| /zpool0/trunk/binaries/data/mods/public/simulation/components/tests/test_Damage.js
|  26|  26| 
|  27|  27| 	let cmpDamage = ConstructComponent(SYSTEM_ENTITY, "Damage");
|  28|  28| 	let cmpTimer = ConstructComponent(SYSTEM_ENTITY, "Timer");
|  29|    |-	cmpTimer.OnUpdate({ turnLength: 1 });
|    |  29|+	cmpTimer.OnUpdate({ "turnLength": 1 });
|  30|  30| 	let attacker = 11;
|  31|  31| 	let atkPlayerEntity = 1;
|  32|  32| 	let attackerOwner = 6;
|    | [NORMAL] ESLintBear (comma-spacing):
|    | A space is required after ','.
|----|    | /zpool0/trunk/binaries/data/mods/public/simulation/components/tests/test_Damage.js
|    |++++| /zpool0/trunk/binaries/data/mods/public/simulation/components/tests/test_Damage.js
|  64|  64| 		"position": targetPos,
|  65|  65| 		"isSplash": false,
|  66|  66| 		"projectileId": 9,
|  67|    |-		"direction": new Vector3D(1,0,0)
|    |  67|+		"direction": new Vector3D(1, 0,0)
|  68|  68| 	};
|  69|  69| 
|  70|  70| 	AddMock(atkPlayerEntity, IID_Player, {
|    | [NORMAL] ESLintBear (comma-spacing):
|    | A space is required after ','.
|----|    | /zpool0/trunk/binaries/data/mods/public/simulation/components/tests/test_Damage.js
|    |++++| /zpool0/trunk/binaries/data/mods/public/simulation/components/tests/test_Damage.js
|  64|  64| 		"position": targetPos,
|  65|  65| 		"isSplash": false,
|  66|  66| 		"projectileId": 9,
|  67|    |-		"direction": new Vector3D(1,0,0)
|    |  67|+		"direction": new Vector3D(1,0, 0)
|  68|  68| 	};
|  69|  69| 
|  70|  70| 	AddMock(atkPlayerEntity, IID_Player, {
|    | [NORMAL] ESLintBear (quote-props):
|    | Unquoted property 'turnLength' found.
|----|    | /zpool0/trunk/binaries/data/mods/public/simulation/components/tests/test_Damage.js
|    |++++| /zpool0/trunk/binaries/data/mods/public/simulation/components/tests/test_Damage.js
| 115| 115| 
| 116| 116| 	function TestDamage()
| 117| 117| 	{
| 118|    |-		cmpTimer.OnUpdate({ turnLength: 1 });
|    | 118|+		cmpTimer.OnUpdate({ "turnLength": 1 });
| 119| 119| 		TS_ASSERT(damageTaken);
| 120| 120| 		damageTaken = false;
| 121| 121| 	}
|    | [NORMAL] ESLintBear (key-spacing):
|    | Extra space after key 'hack'.
|----|    | /zpool0/trunk/binaries/data/mods/public/simulation/components/tests/test_Damage.js
|    |++++| /zpool0/trunk/binaries/data/mods/public/simulation/components/tests/test_Damage.js
| 157| 157| 		"origin": origin,
| 158| 158| 		"radius": 10,
| 159| 159| 		"shape": "Linear",
| 160|    |-		"strengths": { "hack" : 100, "pierce" : 0, "crush": 0 },
|    | 160|+		"strengths": { "hack": 100, "pierce" : 0, "crush": 0 },
| 161| 161| 		"direction": new Vector3D(1, 747, 0),
| 162| 162| 		"playersToDamage": [2],
| 163| 163| 		"type": "Ranged",
|    | [NORMAL] ESLintBear (key-spacing):
|    | Extra space after key 'pierce'.
|----|    | /zpool0/trunk/binaries/data/mods/public/simulation/components/tests/test_Damage.js
|    |++++| /zpool0/trunk/binaries/data/mods/public/simulation/components/tests/test_Damage.js
| 157| 157| 		"origin": origin,
| 158| 158| 		"radius": 10,
| 159| 159| 		"shape": "Linear",
| 160|    |-		"strengths": { "hack" : 100, "pierce" : 0, "crush": 0 },
|    | 160|+		"strengths": { "hack" : 100, "pierce": 0, "crush": 0 },
| 161| 161| 		"direction": new Vector3D(1, 747, 0),
| 162| 162| 		"playersToDamage": [2],
| 163| 163| 		"type": "Ranged",
|    | [NORMAL] ESLintBear (comma-spacing):
|    | A space is required after ','.
|----|    | /zpool0/trunk/binaries/data/mods/public/simulation/components/tests/test_Damage.js
|    |++++| /zpool0/trunk/binaries/data/mods/public/simulation/components/tests/test_Damage.js
| 164| 164| 		"attackerOwner": attackerOwner
| 165| 165| 	};
| 166| 166| 
| 167|    |-	let fallOff = function(x,y)
|    | 167|+	let fallOff = function(x, y)
| 168| 168| 	{
| 169| 169| 		return (1 - x * x / (data.radius * data.radius)) * (1 - 25 * y * y / (data.radius * data.radius));
| 170| 170| 	};
|    | [NORMAL] ESLintBear (key-spacing):
|    | Extra space after key 'hack'.
|----|    | /zpool0/trunk/binaries/data/mods/public/simulation/components/tests/test_Damage.js
|    |++++| /zpool0/trunk/binaries/data/mods/public/simulation/components/tests/test_Damage.js
| 316| 316| 		"origin": new Vector2D(3, 4),
| 317| 317| 		"radius": radius,
| 318| 318| 		"shape": "Circular",
| 319|    |-		"strengths": { "hack" : 100, "pierce" : 0, "crush": 0 },
|    | 319|+		"strengths": { "hack": 100, "pierce" : 0, "crush": 0 },
| 320| 320| 		"playersToDamage": [2],
| 321| 321| 		"type": "Ranged",
| 322| 322| 		"attackerOwner": 1
|    | [NORMAL] ESLintBear (key-spacing):
|    | Extra space after key 'pierce'.
|----|    | /zpool0/trunk/binaries/data/mods/public/simulation/components/tests/test_Damage.js
|    |++++| /zpool0/trunk/binaries/data/mods/public/simulation/components/tests/test_Damage.js
| 316| 316| 		"origin": new Vector2D(3, 4),
| 317| 317| 		"radius": radius,
| 318| 318| 		"shape": "Circular",
| 319|    |-		"strengths": { "hack" : 100, "pierce" : 0, "crush": 0 },
|    | 319|+		"strengths": { "hack" : 100, "pierce": 0, "crush": 0 },
| 320| 320| 		"playersToDamage": [2],
| 321| 321| 		"type": "Ranged",
| 322| 322| 		"attackerOwner": 1

binaries/data/mods/public/simulation/components/tests/test_Damage.js
| 126| »   type·=·data.type·=·"Ranged";
|    | [NORMAL] ESLintBear (no-multi-assign):
|    | Unexpected chained assignment.
|    | [NORMAL] ESLintBear (no-extra-semi):
|    | Unnecessary semicolon.
|----|    | /zpool0/trunk/binaries/data/mods/public/simulation/helpers/Attack.js
|    |++++| /zpool0/trunk/binaries/data/mods/public/simulation/helpers/Attack.js
|  20|  20| 			"</element>" +
|  21|  21| 		"</optional>";
|  22|  22| 	return schema;
|  23|    |-};
|    |  23|+}
|  24|  24| 
|  25|  25| /**
|  26|  26|  * Builds a RelaxRNG schema for bonuses.
|    | [NORMAL] ESLintBear (no-extra-semi):
|    | Unnecessary semicolon.
|----|    | /zpool0/trunk/binaries/data/mods/public/simulation/helpers/Attack.js
|    |++++| /zpool0/trunk/binaries/data/mods/public/simulation/helpers/Attack.js
|  46|  46| 			"</element>" +
|  47|  47| 		"</optional>";
|  48|  48| 	return schema;
|  49|    |-};
|    |  49|+}
|  50|  50| 
|  51|  51| Engine.RegisterGlobal("BuildStatusEffectsSchema", BuildStatusEffectsSchema);
|  52|  52| Engine.RegisterGlobal("BuildBonusesSchema", BuildBonusesSchema);

binaries/data/mods/public/simulation/helpers/Attack.js
|  23| };
|    | [NORMAL] JSHintBear:
|    | Unnecessary semicolon.

binaries/data/mods/public/simulation/helpers/Attack.js
|  49| };
|    | [NORMAL] JSHintBear:
|    | Unnecessary semicolon.
Executing section cli...

Link to build: https://jenkins.wildfiregames.com/job/docker-differential/231/display/redirect

In D2109#88737, @bb wrote:

The question is preferred classes and restricted classes (ping @bb ). Are they a property of the attacker or the attack itself.
Preferred classes seem obviously the first - it's a hint to unitAI, relating to GetBestAttackAgainst (@Freagarach please split from D2044 ;) ).

Well I agree on the statement that preferred classes should be an attacker unitAI hint, which targets it should attack. However that has not much todo with GetBestAttackAgainst since there we already have chosen the target. Maybe preferred classes should be in the unitAI template instead?

There are two behaviours: making attacks ineffective (related to D2044), and hints to unitAI - which may or may not be needed. For walls for example - if we made the impervious to hack/pierce, they would effectively be restricted from damage by non-siege units right now.

If there are two behaviors maybe make two template entries, one for each?

Ref: D1149.