Page MenuHomeWildfire Games

Allow immunity to certain damage types.
Changes PlannedPublic

Authored by Freagarach on Jul 5 2019, 8:08 PM.

Details

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

This patch allows enitities to be immune to certain damage types.
E.g. structures immune to Pierce.

Test Plan
  1. Give an entity (1) the value Infinity in any damage type in Armour.
    1. Check that the armour-value for that damage type in the GUI is the infinite-sign and 100%.
  2. Attack (1) with another entity (2).
    1. See that (1) is not harmed by that damage type.
  3. Ensure that (2) only has the same attack damage type as is set Infinity in (1).
    1. See that one cannot attack (1) with (2).

Please test this a lot with PetraAI, some bugs might be hard to find.

Diff Detail

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

Event Timeline

There are a very large number of changes, so older changes are hidden. Show Older Changes
Owners added a subscriber: Restricted Owners Package.Jul 5 2019, 8:08 PM

Will fail test.

Vulcan added a comment.Jul 5 2019, 8:10 PM

Build failure - The Moirai have given mortals hearts that can endure.

Linter detected issues:
Executing section Source...
Executing section JS...
|    | [NORMAL] ESLintBear (curly):
|    | Unnecessary { after 'for-in'.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/Attack.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/Attack.js
| 336| 336| 			let attackStrengths = this.GetAttackStrengths(type);
| 337| 337| 			let canDamage = false;
| 338| 338| 			for (let damageType in attackStrengths)
| 339|    |-			{
|    | 339|+			
| 340| 340| 				if (attackStrengths[damageType] != 0 && armourStrengths[damageType] != "Infinity")
| 341| 341| 				{
| 342| 342| 					canDamage = true;
| 343| 343| 					break;
| 344| 344| 				}
| 345|    |-			}
|    | 345|+			
| 346| 346| 			if (!canDamage)
| 347| 347| 				return false;
| 348| 348| 		}
|    | [NORMAL] ESLintBear (spaced-comment):
|    | Expected space or tab after '//' in comment.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/Attack.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/Attack.js
| 545| 545| 
| 546| 546| 		let horizSpeed = +this.template[type].Projectile.Speed;
| 547| 547| 		let gravity = +this.template[type].Projectile.Gravity;
| 548|    |-		//horizSpeed /= 2; gravity /= 2; // slow it down for testing
|    | 548|+		// horizSpeed /= 2; gravity /= 2; // slow it down for testing
| 549| 549| 
| 550| 550| 		let cmpPosition = Engine.QueryInterface(this.entity, IID_Position);
| 551| 551| 		if (!cmpPosition || !cmpPosition.IsInWorld())
|    | [NORMAL] ESLintBear (no-trailing-spaces):
|    | Trailing spaces not allowed.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/Attack.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/Attack.js
| 592| 592| 		// TODO: Use unit rotation to implement x/z offsets.
| 593| 593| 		let deltaLaunchPoint = new Vector3D(0, this.template[type].Projectile.LaunchPoint["@y"], 0.0);
| 594| 594| 		let launchPoint = Vector3D.add(selfPosition, deltaLaunchPoint);
| 595|    |-		
|    | 595|+
| 596| 596| 		let cmpVisual = Engine.QueryInterface(this.entity, IID_Visual);
| 597| 597| 		if (cmpVisual)
| 598| 598| 		{
|    | [NORMAL] ESLintBear (curly):
|    | Unnecessary { after 'else'.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/Attack.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/Attack.js
| 664| 664| 			});
| 665| 665| 	}
| 666| 666| 	else
| 667|    |-	{
|    | 667|+	
| 668| 668| 		// Melee attack - hurt the target immediately
| 669| 669| 		cmpDamage.CauseDamage({
| 670| 670| 			"strengths": this.GetAttackStrengths(type),
| 674| 674| 			"type": type,
| 675| 675| 			"attackerOwner": attackerOwner
| 676| 676| 		});
| 677|    |-	}
|    | 677|+	
| 678| 678| };
| 679| 679| 
| 680| 680| /**

binaries/data/mods/public/simulation/components/Attack.js
| 535| ·»   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
| 639| »   »   cmpTimer.SetTimeout(SYSTEM_ENTITY,·IID_Damage,·"MissileHit",·timeToTarget·*·1000·+·+this.template[type].Delay,·data);
|    | [NORMAL] JSHintBear:
|    | Confusing plusses.
|    | [NORMAL] ESLintBear (indent):
|    | Expected indentation of 2 tabs but found 3.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/gui/common/tooltips.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/gui/common/tooltips.js
| 392| 392| function getRepairTimeTooltip(entState)
| 393| 393| {
| 394| 394| 	return sprintf(translate("%(label)s %(details)s"), {
| 395|    |-			"label": headerFont(translate("Number of repairers:")),
|    | 395|+		"label": headerFont(translate("Number of repairers:")),
| 396| 396| 			"details": entState.repairable.numBuilders
| 397| 397| 		}) + "\n" + (entState.repairable.numBuilders ?
| 398| 398| 		sprintf(translatePlural(
|    | [NORMAL] ESLintBear (indent):
|    | Expected indentation of 2 tabs but found 3.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/gui/common/tooltips.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/gui/common/tooltips.js
| 393| 393| {
| 394| 394| 	return sprintf(translate("%(label)s %(details)s"), {
| 395| 395| 			"label": headerFont(translate("Number of repairers:")),
| 396|    |-			"details": entState.repairable.numBuilders
|    | 396|+		"details": entState.repairable.numBuilders
| 397| 397| 		}) + "\n" + (entState.repairable.numBuilders ?
| 398| 398| 		sprintf(translatePlural(
| 399| 399| 			"Add another worker to speed up the repairs by %(second)s second.",
|    | [NORMAL] ESLintBear (indent):
|    | Expected indentation of 1 tab but found 2.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/gui/common/tooltips.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/gui/common/tooltips.js
| 394| 394| 	return sprintf(translate("%(label)s %(details)s"), {
| 395| 395| 			"label": headerFont(translate("Number of repairers:")),
| 396| 396| 			"details": entState.repairable.numBuilders
| 397|    |-		}) + "\n" + (entState.repairable.numBuilders ?
|    | 397|+	}) + "\n" + (entState.repairable.numBuilders ?
| 398| 398| 		sprintf(translatePlural(
| 399| 399| 			"Add another worker to speed up the repairs by %(second)s second.",
| 400| 400| 			"Add another worker to speed up the repairs by %(second)s seconds.",
|    | [NORMAL] ESLintBear (indent):
|    | Expected indentation of 2 tabs but found 3.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/gui/common/tooltips.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/gui/common/tooltips.js
| 414| 414| function getBuildTimeTooltip(entState)
| 415| 415| {
| 416| 416| 	return sprintf(translate("%(label)s %(details)s"), {
| 417|    |-			"label": headerFont(translate("Number of builders:")),
|    | 417|+		"label": headerFont(translate("Number of builders:")),
| 418| 418| 			"details": entState.foundation.numBuilders
| 419| 419| 		}) + "\n" + (entState.foundation.numBuilders ?
| 420| 420| 		sprintf(translatePlural(
|    | [NORMAL] ESLintBear (indent):
|    | Expected indentation of 2 tabs but found 3.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/gui/common/tooltips.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/gui/common/tooltips.js
| 415| 415| {
| 416| 416| 	return sprintf(translate("%(label)s %(details)s"), {
| 417| 417| 			"label": headerFont(translate("Number of builders:")),
| 418|    |-			"details": entState.foundation.numBuilders
|    | 418|+		"details": entState.foundation.numBuilders
| 419| 419| 		}) + "\n" + (entState.foundation.numBuilders ?
| 420| 420| 		sprintf(translatePlural(
| 421| 421| 			"Add another worker to speed up the construction by %(second)s second.",
|    | [NORMAL] ESLintBear (indent):
|    | Expected indentation of 1 tab but found 2.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/gui/common/tooltips.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/gui/common/tooltips.js
| 416| 416| 	return sprintf(translate("%(label)s %(details)s"), {
| 417| 417| 			"label": headerFont(translate("Number of builders:")),
| 418| 418| 			"details": entState.foundation.numBuilders
| 419|    |-		}) + "\n" + (entState.foundation.numBuilders ?
|    | 419|+	}) + "\n" + (entState.foundation.numBuilders ?
| 420| 420| 		sprintf(translatePlural(
| 421| 421| 			"Add another worker to speed up the construction by %(second)s second.",
| 422| 422| 			"Add another worker to speed up the construction by %(second)s seconds.",
Executing section cli...

Link to build: https://jenkins.wildfiregames.com/job/differential/1908/display/redirect

Angen added a subscriber: Angen.Jul 5 2019, 8:13 PM

Checks for infinit armour should be in getbestattackagainst too
and you need to edit AttackPlan.js in Petra AI function "update" as well

:)

Freagarach updated this revision to Diff 8739.Jul 5 2019, 11:01 PM
Freagarach edited the summary of this revision. (Show Details)
  • GetBestAttackAgainst.
  • Mirage.
  • Test (partly).

A question: I've changed GetBestAttackAgainst to filter out attack types that cannot be used (CanAttack(attackType)) instead of just the restricted classes. But now the test fails when Melee or Ranged is checked. It seems to have trouble with cmpEntityPlayer.IsEnemy(targetOwner) at line 325 in Attack.js, but I can't figure out how to fix that, because IsEnemy is mocked already and *should* return true.

Build failure - The Moirai have given mortals hearts that can endure.

Linter detected issues:
Executing section Source...
Executing section JS...
|    | [NORMAL] ESLintBear (spaced-comment):
|    | Expected space or tab after '//' in comment.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/Attack.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/Attack.js
| 546| 546| 
| 547| 547| 		let horizSpeed = +this.template[type].Projectile.Speed;
| 548| 548| 		let gravity = +this.template[type].Projectile.Gravity;
| 549|    |-		//horizSpeed /= 2; gravity /= 2; // slow it down for testing
|    | 549|+		// horizSpeed /= 2; gravity /= 2; // slow it down for testing
| 550| 550| 
| 551| 551| 		let cmpPosition = Engine.QueryInterface(this.entity, IID_Position);
| 552| 552| 		if (!cmpPosition || !cmpPosition.IsInWorld())
|    | [NORMAL] ESLintBear (no-trailing-spaces):
|    | Trailing spaces not allowed.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/Attack.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/Attack.js
| 593| 593| 		// TODO: Use unit rotation to implement x/z offsets.
| 594| 594| 		let deltaLaunchPoint = new Vector3D(0, this.template[type].Projectile.LaunchPoint["@y"], 0.0);
| 595| 595| 		let launchPoint = Vector3D.add(selfPosition, deltaLaunchPoint);
| 596|    |-		
|    | 596|+
| 597| 597| 		let cmpVisual = Engine.QueryInterface(this.entity, IID_Visual);
| 598| 598| 		if (cmpVisual)
| 599| 599| 		{
|    | [NORMAL] ESLintBear (curly):
|    | Unnecessary { after 'else'.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/Attack.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/Attack.js
| 665| 665| 			});
| 666| 666| 	}
| 667| 667| 	else
| 668|    |-	{
|    | 668|+	
| 669| 669| 		// Melee attack - hurt the target immediately
| 670| 670| 		cmpDamage.CauseDamage({
| 671| 671| 			"strengths": this.GetAttackStrengths(type),
| 675| 675| 			"type": type,
| 676| 676| 			"attackerOwner": attackerOwner
| 677| 677| 		});
| 678|    |-	}
|    | 678|+	
| 679| 679| };
| 680| 680| 
| 681| 681| /**

binaries/data/mods/public/simulation/components/Attack.js
| 536| ·»   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
| 640| »   »   cmpTimer.SetTimeout(SYSTEM_ENTITY,·IID_Damage,·"MissileHit",·timeToTarget·*·1000·+·+this.template[type].Delay,·data);
|    | [NORMAL] JSHintBear:
|    | Confusing plusses.
|    | [NORMAL] ESLintBear (indent):
|    | Expected indentation of 2 tabs but found 3.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/gui/common/tooltips.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/gui/common/tooltips.js
| 392| 392| function getRepairTimeTooltip(entState)
| 393| 393| {
| 394| 394| 	return sprintf(translate("%(label)s %(details)s"), {
| 395|    |-			"label": headerFont(translate("Number of repairers:")),
|    | 395|+		"label": headerFont(translate("Number of repairers:")),
| 396| 396| 			"details": entState.repairable.numBuilders
| 397| 397| 		}) + "\n" + (entState.repairable.numBuilders ?
| 398| 398| 		sprintf(translatePlural(
|    | [NORMAL] ESLintBear (indent):
|    | Expected indentation of 2 tabs but found 3.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/gui/common/tooltips.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/gui/common/tooltips.js
| 393| 393| {
| 394| 394| 	return sprintf(translate("%(label)s %(details)s"), {
| 395| 395| 			"label": headerFont(translate("Number of repairers:")),
| 396|    |-			"details": entState.repairable.numBuilders
|    | 396|+		"details": entState.repairable.numBuilders
| 397| 397| 		}) + "\n" + (entState.repairable.numBuilders ?
| 398| 398| 		sprintf(translatePlural(
| 399| 399| 			"Add another worker to speed up the repairs by %(second)s second.",
|    | [NORMAL] ESLintBear (indent):
|    | Expected indentation of 1 tab but found 2.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/gui/common/tooltips.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/gui/common/tooltips.js
| 394| 394| 	return sprintf(translate("%(label)s %(details)s"), {
| 395| 395| 			"label": headerFont(translate("Number of repairers:")),
| 396| 396| 			"details": entState.repairable.numBuilders
| 397|    |-		}) + "\n" + (entState.repairable.numBuilders ?
|    | 397|+	}) + "\n" + (entState.repairable.numBuilders ?
| 398| 398| 		sprintf(translatePlural(
| 399| 399| 			"Add another worker to speed up the repairs by %(second)s second.",
| 400| 400| 			"Add another worker to speed up the repairs by %(second)s seconds.",
|    | [NORMAL] ESLintBear (indent):
|    | Expected indentation of 2 tabs but found 3.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/gui/common/tooltips.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/gui/common/tooltips.js
| 414| 414| function getBuildTimeTooltip(entState)
| 415| 415| {
| 416| 416| 	return sprintf(translate("%(label)s %(details)s"), {
| 417|    |-			"label": headerFont(translate("Number of builders:")),
|    | 417|+		"label": headerFont(translate("Number of builders:")),
| 418| 418| 			"details": entState.foundation.numBuilders
| 419| 419| 		}) + "\n" + (entState.foundation.numBuilders ?
| 420| 420| 		sprintf(translatePlural(
|    | [NORMAL] ESLintBear (indent):
|    | Expected indentation of 2 tabs but found 3.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/gui/common/tooltips.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/gui/common/tooltips.js
| 415| 415| {
| 416| 416| 	return sprintf(translate("%(label)s %(details)s"), {
| 417| 417| 			"label": headerFont(translate("Number of builders:")),
| 418|    |-			"details": entState.foundation.numBuilders
|    | 418|+		"details": entState.foundation.numBuilders
| 419| 419| 		}) + "\n" + (entState.foundation.numBuilders ?
| 420| 420| 		sprintf(translatePlural(
| 421| 421| 			"Add another worker to speed up the construction by %(second)s second.",
|    | [NORMAL] ESLintBear (indent):
|    | Expected indentation of 1 tab but found 2.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/gui/common/tooltips.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/gui/common/tooltips.js
| 416| 416| 	return sprintf(translate("%(label)s %(details)s"), {
| 417| 417| 			"label": headerFont(translate("Number of builders:")),
| 418| 418| 			"details": entState.foundation.numBuilders
| 419|    |-		}) + "\n" + (entState.foundation.numBuilders ?
|    | 419|+	}) + "\n" + (entState.foundation.numBuilders ?
| 420| 420| 		sprintf(translatePlural(
| 421| 421| 			"Add another worker to speed up the construction by %(second)s second.",
| 422| 422| 			"Add another worker to speed up the construction by %(second)s seconds.",
Executing section cli...

Link to build: https://jenkins.wildfiregames.com/job/differential/1912/display/redirect

Angen added inline comments.Jul 5 2019, 11:33 PM
binaries/data/mods/public/simulation/components/tests/test_Attack.js
122

defender has owner 1 and attacker too, so isEnemy is false

Freagarach added inline comments.Jul 6 2019, 7:05 AM
binaries/data/mods/public/simulation/components/tests/test_Attack.js
122

Yeah, I thought so as well, but the IsEnemy() is set in line 30 to be the value of isEnemy, which is set to true in line 219. If I read this correctly.
The testing of CanAttack itself does not fail, only the GetBestAttackAgainst (which in turn calls CanAttack).

Angen added inline comments.Jul 6 2019, 5:17 PM
binaries/data/mods/public/simulation/components/tests/test_Attack.js
238

This line tries to test to get best attack against not enemy entities, what currently using CanAttack as filter is not true. Do not execute this block unless expected attack is "Capture" or "Slaughter".

238

Ok, Ignore this one inline here I thought I removed it.

266

also this lines are useless

269

This line tries to test to get best attack against not enemy entities, what currently using CanAttack as filter is not true. Do not execute this block unless expected attack is "Capture" or "Slaughter".

Freagarach updated this revision to Diff 8758.Jul 7 2019, 7:13 AM
Freagarach marked 5 inline comments as done.

Fixed test.

binaries/data/mods/public/simulation/components/tests/test_Attack.js
269

Oh, now I see! This is part of the block started in line 247! Thanks for pointing it out :)

Vulcan added a comment.Jul 7 2019, 7:15 AM

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.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/Attack.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/Attack.js
| 546| 546| 
| 547| 547| 		let horizSpeed = +this.template[type].Projectile.Speed;
| 548| 548| 		let gravity = +this.template[type].Projectile.Gravity;
| 549|    |-		//horizSpeed /= 2; gravity /= 2; // slow it down for testing
|    | 549|+		// horizSpeed /= 2; gravity /= 2; // slow it down for testing
| 550| 550| 
| 551| 551| 		let cmpPosition = Engine.QueryInterface(this.entity, IID_Position);
| 552| 552| 		if (!cmpPosition || !cmpPosition.IsInWorld())
|    | [NORMAL] ESLintBear (no-trailing-spaces):
|    | Trailing spaces not allowed.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/Attack.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/Attack.js
| 593| 593| 		// TODO: Use unit rotation to implement x/z offsets.
| 594| 594| 		let deltaLaunchPoint = new Vector3D(0, this.template[type].Projectile.LaunchPoint["@y"], 0.0);
| 595| 595| 		let launchPoint = Vector3D.add(selfPosition, deltaLaunchPoint);
| 596|    |-		
|    | 596|+
| 597| 597| 		let cmpVisual = Engine.QueryInterface(this.entity, IID_Visual);
| 598| 598| 		if (cmpVisual)
| 599| 599| 		{
|    | [NORMAL] ESLintBear (curly):
|    | Unnecessary { after 'else'.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/Attack.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/Attack.js
| 665| 665| 			});
| 666| 666| 	}
| 667| 667| 	else
| 668|    |-	{
|    | 668|+	
| 669| 669| 		// Melee attack - hurt the target immediately
| 670| 670| 		cmpDamage.CauseDamage({
| 671| 671| 			"strengths": this.GetAttackStrengths(type),
| 675| 675| 			"type": type,
| 676| 676| 			"attackerOwner": attackerOwner
| 677| 677| 		});
| 678|    |-	}
|    | 678|+	
| 679| 679| };
| 680| 680| 
| 681| 681| /**

binaries/data/mods/public/simulation/components/Attack.js
| 536| ·»   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
| 640| »   »   cmpTimer.SetTimeout(SYSTEM_ENTITY,·IID_Damage,·"MissileHit",·timeToTarget·*·1000·+·+this.template[type].Delay,·data);
|    | [NORMAL] JSHintBear:
|    | Confusing plusses.
|    | [NORMAL] ESLintBear (indent):
|    | Expected indentation of 2 tabs but found 3.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/gui/common/tooltips.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/gui/common/tooltips.js
| 392| 392| function getRepairTimeTooltip(entState)
| 393| 393| {
| 394| 394| 	return sprintf(translate("%(label)s %(details)s"), {
| 395|    |-			"label": headerFont(translate("Number of repairers:")),
|    | 395|+		"label": headerFont(translate("Number of repairers:")),
| 396| 396| 			"details": entState.repairable.numBuilders
| 397| 397| 		}) + "\n" + (entState.repairable.numBuilders ?
| 398| 398| 		sprintf(translatePlural(
|    | [NORMAL] ESLintBear (indent):
|    | Expected indentation of 2 tabs but found 3.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/gui/common/tooltips.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/gui/common/tooltips.js
| 393| 393| {
| 394| 394| 	return sprintf(translate("%(label)s %(details)s"), {
| 395| 395| 			"label": headerFont(translate("Number of repairers:")),
| 396|    |-			"details": entState.repairable.numBuilders
|    | 396|+		"details": entState.repairable.numBuilders
| 397| 397| 		}) + "\n" + (entState.repairable.numBuilders ?
| 398| 398| 		sprintf(translatePlural(
| 399| 399| 			"Add another worker to speed up the repairs by %(second)s second.",
|    | [NORMAL] ESLintBear (indent):
|    | Expected indentation of 1 tab but found 2.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/gui/common/tooltips.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/gui/common/tooltips.js
| 394| 394| 	return sprintf(translate("%(label)s %(details)s"), {
| 395| 395| 			"label": headerFont(translate("Number of repairers:")),
| 396| 396| 			"details": entState.repairable.numBuilders
| 397|    |-		}) + "\n" + (entState.repairable.numBuilders ?
|    | 397|+	}) + "\n" + (entState.repairable.numBuilders ?
| 398| 398| 		sprintf(translatePlural(
| 399| 399| 			"Add another worker to speed up the repairs by %(second)s second.",
| 400| 400| 			"Add another worker to speed up the repairs by %(second)s seconds.",
|    | [NORMAL] ESLintBear (indent):
|    | Expected indentation of 2 tabs but found 3.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/gui/common/tooltips.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/gui/common/tooltips.js
| 414| 414| function getBuildTimeTooltip(entState)
| 415| 415| {
| 416| 416| 	return sprintf(translate("%(label)s %(details)s"), {
| 417|    |-			"label": headerFont(translate("Number of builders:")),
|    | 417|+		"label": headerFont(translate("Number of builders:")),
| 418| 418| 			"details": entState.foundation.numBuilders
| 419| 419| 		}) + "\n" + (entState.foundation.numBuilders ?
| 420| 420| 		sprintf(translatePlural(
|    | [NORMAL] ESLintBear (indent):
|    | Expected indentation of 2 tabs but found 3.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/gui/common/tooltips.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/gui/common/tooltips.js
| 415| 415| {
| 416| 416| 	return sprintf(translate("%(label)s %(details)s"), {
| 417| 417| 			"label": headerFont(translate("Number of builders:")),
| 418|    |-			"details": entState.foundation.numBuilders
|    | 418|+		"details": entState.foundation.numBuilders
| 419| 419| 		}) + "\n" + (entState.foundation.numBuilders ?
| 420| 420| 		sprintf(translatePlural(
| 421| 421| 			"Add another worker to speed up the construction by %(second)s second.",
|    | [NORMAL] ESLintBear (indent):
|    | Expected indentation of 1 tab but found 2.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/gui/common/tooltips.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/gui/common/tooltips.js
| 416| 416| 	return sprintf(translate("%(label)s %(details)s"), {
| 417| 417| 			"label": headerFont(translate("Number of builders:")),
| 418| 418| 			"details": entState.foundation.numBuilders
| 419|    |-		}) + "\n" + (entState.foundation.numBuilders ?
|    | 419|+	}) + "\n" + (entState.foundation.numBuilders ?
| 420| 420| 		sprintf(translatePlural(
| 421| 421| 			"Add another worker to speed up the construction by %(second)s second.",
| 422| 422| 			"Add another worker to speed up the construction by %(second)s seconds.",
Executing section cli...

Link to build: https://jenkins.wildfiregames.com/job/differential/1930/display/redirect

Angen added a comment.Jul 7 2019, 9:33 AM

Would be nice to add test against infinite armour

binaries/data/mods/public/simulation/components/Attack.js
437

cmpPlayer is not needed here

FeXoR added a subscriber: FeXoR.Jul 7 2019, 12:22 PM

This seems to be a duplication of D1965

Freagarach added a comment.EditedJul 7 2019, 12:36 PM
In D2044#85350, @FeXoR wrote:

This seems to be a duplication of D1965

It is not, I split it into instant-kill (D1965) and immunity (D2044).

FeXoR added a comment.Jul 7 2019, 1:28 PM

Ah, OK.
Still, both ticket's descriptions can't be true. It's either one or the other.

That's not really an issue, just make sure one precedes the other in the way you see fit.

Than again this patch also should have a real reason to be considered adding - I can't see that.

Freagarach updated this revision to Diff 8763.Jul 7 2019, 1:31 PM

Added unit test.

Vulcan added a comment.Jul 7 2019, 1:34 PM

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

Linter detected issues:
Executing section Source...
Executing section JS...
|    | [NORMAL] ESLintBear (indent):
|    | Expected indentation of 2 tabs but found 3.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/gui/common/tooltips.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/gui/common/tooltips.js
| 392| 392| function getRepairTimeTooltip(entState)
| 393| 393| {
| 394| 394| 	return sprintf(translate("%(label)s %(details)s"), {
| 395|    |-			"label": headerFont(translate("Number of repairers:")),
|    | 395|+		"label": headerFont(translate("Number of repairers:")),
| 396| 396| 			"details": entState.repairable.numBuilders
| 397| 397| 		}) + "\n" + (entState.repairable.numBuilders ?
| 398| 398| 		sprintf(translatePlural(
|    | [NORMAL] ESLintBear (indent):
|    | Expected indentation of 2 tabs but found 3.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/gui/common/tooltips.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/gui/common/tooltips.js
| 393| 393| {
| 394| 394| 	return sprintf(translate("%(label)s %(details)s"), {
| 395| 395| 			"label": headerFont(translate("Number of repairers:")),
| 396|    |-			"details": entState.repairable.numBuilders
|    | 396|+		"details": entState.repairable.numBuilders
| 397| 397| 		}) + "\n" + (entState.repairable.numBuilders ?
| 398| 398| 		sprintf(translatePlural(
| 399| 399| 			"Add another worker to speed up the repairs by %(second)s second.",
|    | [NORMAL] ESLintBear (indent):
|    | Expected indentation of 1 tab but found 2.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/gui/common/tooltips.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/gui/common/tooltips.js
| 394| 394| 	return sprintf(translate("%(label)s %(details)s"), {
| 395| 395| 			"label": headerFont(translate("Number of repairers:")),
| 396| 396| 			"details": entState.repairable.numBuilders
| 397|    |-		}) + "\n" + (entState.repairable.numBuilders ?
|    | 397|+	}) + "\n" + (entState.repairable.numBuilders ?
| 398| 398| 		sprintf(translatePlural(
| 399| 399| 			"Add another worker to speed up the repairs by %(second)s second.",
| 400| 400| 			"Add another worker to speed up the repairs by %(second)s seconds.",
|    | [NORMAL] ESLintBear (indent):
|    | Expected indentation of 2 tabs but found 3.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/gui/common/tooltips.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/gui/common/tooltips.js
| 414| 414| function getBuildTimeTooltip(entState)
| 415| 415| {
| 416| 416| 	return sprintf(translate("%(label)s %(details)s"), {
| 417|    |-			"label": headerFont(translate("Number of builders:")),
|    | 417|+		"label": headerFont(translate("Number of builders:")),
| 418| 418| 			"details": entState.foundation.numBuilders
| 419| 419| 		}) + "\n" + (entState.foundation.numBuilders ?
| 420| 420| 		sprintf(translatePlural(
|    | [NORMAL] ESLintBear (indent):
|    | Expected indentation of 2 tabs but found 3.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/gui/common/tooltips.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/gui/common/tooltips.js
| 415| 415| {
| 416| 416| 	return sprintf(translate("%(label)s %(details)s"), {
| 417| 417| 			"label": headerFont(translate("Number of builders:")),
| 418|    |-			"details": entState.foundation.numBuilders
|    | 418|+		"details": entState.foundation.numBuilders
| 419| 419| 		}) + "\n" + (entState.foundation.numBuilders ?
| 420| 420| 		sprintf(translatePlural(
| 421| 421| 			"Add another worker to speed up the construction by %(second)s second.",
|    | [NORMAL] ESLintBear (indent):
|    | Expected indentation of 1 tab but found 2.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/gui/common/tooltips.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/gui/common/tooltips.js
| 416| 416| 	return sprintf(translate("%(label)s %(details)s"), {
| 417| 417| 			"label": headerFont(translate("Number of builders:")),
| 418| 418| 			"details": entState.foundation.numBuilders
| 419|    |-		}) + "\n" + (entState.foundation.numBuilders ?
|    | 419|+	}) + "\n" + (entState.foundation.numBuilders ?
| 420| 420| 		sprintf(translatePlural(
| 421| 421| 			"Add another worker to speed up the construction by %(second)s second.",
| 422| 422| 			"Add another worker to speed up the construction by %(second)s seconds.",
|    | [NORMAL] ESLintBear (spaced-comment):
|    | Expected space or tab after '//' in comment.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/Attack.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/Attack.js
| 546| 546| 
| 547| 547| 		let horizSpeed = +this.template[type].Projectile.Speed;
| 548| 548| 		let gravity = +this.template[type].Projectile.Gravity;
| 549|    |-		//horizSpeed /= 2; gravity /= 2; // slow it down for testing
|    | 549|+		// horizSpeed /= 2; gravity /= 2; // slow it down for testing
| 550| 550| 
| 551| 551| 		let cmpPosition = Engine.QueryInterface(this.entity, IID_Position);
| 552| 552| 		if (!cmpPosition || !cmpPosition.IsInWorld())
|    | [NORMAL] ESLintBear (no-trailing-spaces):
|    | Trailing spaces not allowed.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/Attack.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/Attack.js
| 593| 593| 		// TODO: Use unit rotation to implement x/z offsets.
| 594| 594| 		let deltaLaunchPoint = new Vector3D(0, this.template[type].Projectile.LaunchPoint["@y"], 0.0);
| 595| 595| 		let launchPoint = Vector3D.add(selfPosition, deltaLaunchPoint);
| 596|    |-		
|    | 596|+
| 597| 597| 		let cmpVisual = Engine.QueryInterface(this.entity, IID_Visual);
| 598| 598| 		if (cmpVisual)
| 599| 599| 		{
|    | [NORMAL] ESLintBear (curly):
|    | Unnecessary { after 'else'.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/Attack.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/Attack.js
| 665| 665| 			});
| 666| 666| 	}
| 667| 667| 	else
| 668|    |-	{
|    | 668|+	
| 669| 669| 		// Melee attack - hurt the target immediately
| 670| 670| 		cmpDamage.CauseDamage({
| 671| 671| 			"strengths": this.GetAttackStrengths(type),
| 675| 675| 			"type": type,
| 676| 676| 			"attackerOwner": attackerOwner
| 677| 677| 		});
| 678|    |-	}
|    | 678|+	
| 679| 679| };
| 680| 680| 
| 681| 681| /**

binaries/data/mods/public/simulation/components/Attack.js
| 536| ·»   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
| 640| »   »   cmpTimer.SetTimeout(SYSTEM_ENTITY,·IID_Damage,·"MissileHit",·timeToTarget·*·1000·+·+this.template[type].Delay,·data);
|    | [NORMAL] JSHintBear:
|    | Confusing plusses.
Executing section cli...

Link to build: https://jenkins.wildfiregames.com/job/differential/1933/display/redirect

Nescio added a comment.Jul 7 2019, 1:39 PM

Than again this patch also should have a real reason to be considered adding - I can't see that.

Increased mod support?
Also, currently in 0 A.D. siege engines have a pierce armour of 50 (i.e. 1-0.9^50, which is over 99%), so they're practically invulnerable already; to me that seems to be a workaround. This patch would allow making them completely invulnerable, so e.g. archers won't waste their arrows on attacking rams, but instead attack other enemy units around.

FeXoR added a comment.Jul 7 2019, 2:27 PM
In D2044#85377, @Nescio wrote:

Increased mod support?

That can be said about any functional code. If we would add all that we basically would have to add all mods in the first place for other mods might use parts of it.

Also, currently in 0 A.D. siege engines have a pierce armour of 50 (i.e. 1-0.9^50, which is over 99%), so they're practically invulnerable already; to me that seems to be a workaround. This patch would allow making them completely invulnerable, so e.g. archers won't waste their arrows on attacking rams, but instead attack other enemy units around.

And to me it shows that our current damage system already can handle that. (The unitAI is a different story)

In D2044#85131, @Angen wrote:

and you need to edit AttackPlan.js in Petra AI function "update" as well

Can I somehow use the function CanAttack from Attack.js for that?

Freagarach edited the summary of this revision. (Show Details)Jul 7 2019, 2:29 PM
Angen added a comment.Jul 7 2019, 2:45 PM

You would need to write one at extendedentity.js in petra directory. I suggest to not call canAttack from cmpAttack but rather to check attack types and armour using functions petra has (attackStrengths,armourStrenghts), because that would use only template values and will be faster as petra would call canAttack very often.

In D2044#85396, @Angen wrote:

You would need to write one at extendedentity.js in petra directory. I suggest to not call canAttack from cmpAttack but rather to check attack types and armour using functions petra has (attackStrengths,armourStrenghts), because that would use only template values and will be faster as petra would call canAttack very often.

Shouldn't the check be in entity.js of the common-api? There is also a function canAttackClass already in that file.

Angen added a comment.Jul 7 2019, 7:42 PM

yes that would be better place :)

Freagarach added a comment.EditedJul 7 2019, 8:25 PM
In D2044#85423, @Angen wrote:

yes that would be better place :)

I'm not sure, but is seems that I cannot check the target there, is that correct? target.anyFunction() gives an error.

[EDIT]: Nevermind, wasted an hour on a typo,,,

Freagarach updated this revision to Diff 8770.Jul 7 2019, 9:27 PM
Freagarach marked an inline comment as done.
Freagarach edited the summary of this revision. (Show Details)

Created a canAttackTarget-function in "entity.js" of the "common-api".

I made a start with checking functions in PetraAI, but I do not yet understand all code.
@Angen, if you have time and want to, can you help me where we can use the new function? Or should that be split into another patch?

Owners added a subscriber: Restricted Owners Package.Jul 7 2019, 9:27 PM
Vulcan added a comment.Jul 7 2019, 9:29 PM

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

Linter detected issues:
Executing section Source...
Executing section JS...
|    | [NORMAL] ESLintBear (indent):
|    | Expected indentation of 1 tab but found 0.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/defenseArmy.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/defenseArmy.js
| 169| 169| 			plan.removeUnit(gameState, ent);
| 170| 170| 	}
| 171| 171| 
| 172|    |-/*
|    | 172|+	/*
| 173| 173| 	// TODO be sure that all units in the transport need the cancelation
| 174| 174| 	if (!ent.position())	// this unit must still be in a transport plan ... try to cancel it
| 175| 175| 	{
|    | [NORMAL] ESLintBear (curly):
|    | Unnecessary { after 'for-in'.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/defenseArmy.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/defenseArmy.js
| 388| 388| {
| 389| 389| 	// copy over all parameters.
| 390| 390| 	for (let i in otherArmy.assignedAgainst)
| 391|    |-	{
|    | 391|+	
| 392| 392| 		if (this.assignedAgainst[i] === undefined)
| 393| 393| 			this.assignedAgainst[i] = otherArmy.assignedAgainst[i];
| 394| 394| 		else
| 395| 395| 			this.assignedAgainst[i] = this.assignedAgainst[i].concat(otherArmy.assignedAgainst[i]);
| 396|    |-	}
|    | 396|+	
| 397| 397| 	for (let i in otherArmy.assignedTo)
| 398| 398| 		this.assignedTo[i] = otherArmy.assignedTo[i];
| 399| 399| 
|    | [NORMAL] ESLintBear (curly):
|    | Unnecessary { after 'if' condition.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/defenseArmy.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/defenseArmy.js
| 484| 484| 
| 485| 485| 	let entStrength;
| 486| 486| 	if (ent.hasClass("Structure"))
| 487|    |-	{
|    | 487|+	
| 488| 488| 		if (ent.owner() !== PlayerID)
| 489| 489| 			entStrength = ent.getDefaultArrow() ? 6*ent.getDefaultArrow() : 4;
| 490| 490| 		else	// small strength used only when we try to recover capture points
| 491| 491| 			entStrength = 2;
| 492|    |-	}
|    | 492|+	
| 493| 493| 	else
| 494| 494| 		entStrength = m.getMaxStrength(ent);
| 495| 495| 
|    | [NORMAL] ESLintBear (curly):
|    | Unnecessary { after 'for-of'.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/defenseArmy.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/defenseArmy.js
| 513| 513| 	// otherwise it would remove the old entity from this army list
| 514| 514| 	// TODO we should may-be reevaluate the strength
| 515| 515| 	for (let evt of events.EntityRenamed)	// take care of promoted and packed units
| 516|    |-	{
|    | 516|+	
| 517| 517| 		if (this.foeEntities.indexOf(evt.entity) !== -1)
| 518| 518| 		{
| 519| 519| 			let ent = gameState.getEntityById(evt.newentity);
| 541| 541| 					this.assignedAgainst[against][this.assignedAgainst[against].indexOf(evt.entity)] = evt.newentity;
| 542| 542| 			}
| 543| 543| 		}
| 544|    |-	}
|    | 544|+	
| 545| 545| 
| 546| 546| 	for (let evt of events.Garrison)
| 547| 547| 		this.removeFoe(gameState, evt.entity);
|    | [NORMAL] ESLintBear (curly):
|    | Unnecessary { after 'for-of'.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/defenseArmy.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/defenseArmy.js
| 547| 547| 		this.removeFoe(gameState, evt.entity);
| 548| 548| 
| 549| 549| 	for (let evt of events.OwnershipChanged)	// captured
| 550|    |-	{
|    | 550|+	
| 551| 551| 		if (!gameState.isPlayerEnemy(evt.to))
| 552| 552| 			this.removeFoe(gameState, evt.entity);
| 553| 553| 		else if (evt.from === PlayerID)
| 554| 554| 			this.removeOwn(gameState, evt.entity);
| 555|    |-	}
|    | 555|+	
| 556| 556| 
| 557| 557| 	for (let evt of events.Destroy)
| 558| 558| 	{

binaries/data/mods/public/simulation/ai/petra/defenseArmy.js
| 654| }(PETRA);
|    | [MAJOR] ESLintBear (no-use-before-define):
|    | 'PETRA' was used before it was defined.
|    | [NORMAL] ESLintBear (curly):
|    | Unnecessary { after 'if' condition.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
|  69|  69| 	this.rallyPoint = rallyPoint;
|  70|  70| 	this.overseas = 0;
|  71|  71| 	if (gameState.ai.HQ.navalMap)
|  72|    |-	{
|    |  72|+	
|  73|  73| 		for (let structure of gameState.getEnemyStructures().values())
|  74|  74| 		{
|  75|  75| 			if (this.target && structure.id() != this.target.id())
| 101| 101| 				gameState.ai.HQ.navalManager.setMinimalTransportShips(gameState, sea, 1);
| 102| 102| 			}
| 103| 103| 		}
| 104|    |-	}
|    | 104|+	
| 105| 105| 	this.paused = false;
| 106| 106| 	this.maxCompletingTime = 0;
| 107| 107| 
|    | [NORMAL] ESLintBear (no-multi-spaces):
|    | Multiple spaces found before '='.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
| 139| 139| 	{
| 140| 140| 		priority = 90;
| 141| 141| 		// basically we want a mix of citizen soldiers so our barracks have a purpose, and champion units.
| 142|    |-		this.unitStat.RangedInfantry    = { "priority": 0.7, "minSize": 5, "targetSize": 20, "batchSize": 5, "classes": ["Infantry", "Ranged", "CitizenSoldier"],
|    | 142|+		this.unitStat.RangedInfantry = { "priority": 0.7, "minSize": 5, "targetSize": 20, "batchSize": 5, "classes": ["Infantry", "Ranged", "CitizenSoldier"],
| 143| 143| 			"interests": [["strength", 3]] };
| 144| 144| 		this.unitStat.MeleeInfantry     = { "priority": 0.7, "minSize": 5, "targetSize": 20, "batchSize": 5, "classes": ["Infantry", "Melee", "CitizenSoldier"],
| 145| 145| 			"interests": [["strength", 3]] };
|    | [NORMAL] ESLintBear (no-multi-spaces):
|    | Multiple spaces found before '='.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
| 141| 141| 		// basically we want a mix of citizen soldiers so our barracks have a purpose, and champion units.
| 142| 142| 		this.unitStat.RangedInfantry    = { "priority": 0.7, "minSize": 5, "targetSize": 20, "batchSize": 5, "classes": ["Infantry", "Ranged", "CitizenSoldier"],
| 143| 143| 			"interests": [["strength", 3]] };
| 144|    |-		this.unitStat.MeleeInfantry     = { "priority": 0.7, "minSize": 5, "targetSize": 20, "batchSize": 5, "classes": ["Infantry", "Melee", "CitizenSoldier"],
|    | 144|+		this.unitStat.MeleeInfantry = { "priority": 0.7, "minSize": 5, "targetSize": 20, "batchSize": 5, "classes": ["Infantry", "Melee", "CitizenSoldier"],
| 145| 145| 			"interests": [["strength", 3]] };
| 146| 146| 		this.unitStat.ChampRangedInfantry = { "priority": 1, "minSize": 3, "targetSize": 18, "batchSize": 3, "classes": ["Infantry", "Ranged", "Champion"],
| 147| 147| 			"interests": [["strength", 3]] };
|    | [NORMAL] ESLintBear (no-multi-spaces):
|    | Multiple spaces found before '='.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
| 145| 145| 			"interests": [["strength", 3]] };
| 146| 146| 		this.unitStat.ChampRangedInfantry = { "priority": 1, "minSize": 3, "targetSize": 18, "batchSize": 3, "classes": ["Infantry", "Ranged", "Champion"],
| 147| 147| 			"interests": [["strength", 3]] };
| 148|    |-		this.unitStat.ChampMeleeInfantry  = { "priority": 1, "minSize": 3, "targetSize": 18, "batchSize": 3, "classes": ["Infantry", "Melee", "Champion"],
|    | 148|+		this.unitStat.ChampMeleeInfantry = { "priority": 1, "minSize": 3, "targetSize": 18, "batchSize": 3, "classes": ["Infantry", "Melee", "Champion"],
| 149| 149| 			"interests": [["strength", 3]] };
| 150| 150| 		this.unitStat.RangedCavalry     = { "priority": 0.7, "minSize": 4, "targetSize": 20, "batchSize": 4, "classes": ["Cavalry", "Ranged", "CitizenSoldier"],
| 151| 151| 			"interests": [["strength", 2]] };
|    | [NORMAL] ESLintBear (no-multi-spaces):
|    | Multiple spaces found before '='.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
| 147| 147| 			"interests": [["strength", 3]] };
| 148| 148| 		this.unitStat.ChampMeleeInfantry  = { "priority": 1, "minSize": 3, "targetSize": 18, "batchSize": 3, "classes": ["Infantry", "Melee", "Champion"],
| 149| 149| 			"interests": [["strength", 3]] };
| 150|    |-		this.unitStat.RangedCavalry     = { "priority": 0.7, "minSize": 4, "targetSize": 20, "batchSize": 4, "classes": ["Cavalry", "Ranged", "CitizenSoldier"],
|    | 150|+		this.unitStat.RangedCavalry = { "priority": 0.7, "minSize": 4, "targetSize": 20, "batchSize": 4, "classes": ["Cavalry", "Ranged", "CitizenSoldier"],
| 151| 151| 			"interests": [["strength", 2]] };
| 152| 152| 		this.unitStat.MeleeCavalry      = { "priority": 0.7, "minSize": 4, "targetSize": 20, "batchSize": 4, "classes": ["Cavalry", "Melee", "CitizenSoldier"],
| 153| 153| 			"interests": [["strength", 2]] };
|    | [NORMAL] ESLintBear (no-multi-spaces):
|    | Multiple spaces found before '='.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
| 149| 149| 			"interests": [["strength", 3]] };
| 150| 150| 		this.unitStat.RangedCavalry     = { "priority": 0.7, "minSize": 4, "targetSize": 20, "batchSize": 4, "classes": ["Cavalry", "Ranged", "CitizenSoldier"],
| 151| 151| 			"interests": [["strength", 2]] };
| 152|    |-		this.unitStat.MeleeCavalry      = { "priority": 0.7, "minSize": 4, "targetSize": 20, "batchSize": 4, "classes": ["Cavalry", "Melee", "CitizenSoldier"],
|    | 152|+		this.unitStat.MeleeCavalry = { "priority": 0.7, "minSize": 4, "targetSize": 20, "batchSize": 4, "classes": ["Cavalry", "Melee", "CitizenSoldier"],
| 153| 153| 			"interests": [["strength", 2]] };
| 154| 154| 		this.unitStat.ChampRangedCavalry  = { "priority": 1, "minSize": 3, "targetSize": 15, "batchSize": 3, "classes": ["Cavalry", "Ranged", "Champion"],
| 155| 155| 			"interests": [["strength", 3]] };
|    | [NORMAL] ESLintBear (no-multi-spaces):
|    | Multiple spaces found before '='.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
| 151| 151| 			"interests": [["strength", 2]] };
| 152| 152| 		this.unitStat.MeleeCavalry      = { "priority": 0.7, "minSize": 4, "targetSize": 20, "batchSize": 4, "classes": ["Cavalry", "Melee", "CitizenSoldier"],
| 153| 153| 			"interests": [["strength", 2]] };
| 154|    |-		this.unitStat.ChampRangedCavalry  = { "priority": 1, "minSize": 3, "targetSize": 15, "batchSize": 3, "classes": ["Cavalry", "Ranged", "Champion"],
|    | 154|+		this.unitStat.ChampRangedCavalry = { "priority": 1, "minSize": 3, "targetSize": 15, "batchSize": 3, "classes": ["Cavalry", "Ranged", "Champion"],
| 155| 155| 			"interests": [["strength", 3]] };
| 156| 156| 		this.unitStat.ChampMeleeCavalry   = { "priority": 1, "minSize": 3, "targetSize": 15, "batchSize": 3, "classes": ["Cavalry", "Melee", "Champion"],
| 157| 157| 			"interests": [["strength", 2]] };
|    | [NORMAL] ESLintBear (no-multi-spaces):
|    | Multiple spaces found before '='.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
| 153| 153| 			"interests": [["strength", 2]] };
| 154| 154| 		this.unitStat.ChampRangedCavalry  = { "priority": 1, "minSize": 3, "targetSize": 15, "batchSize": 3, "classes": ["Cavalry", "Ranged", "Champion"],
| 155| 155| 			"interests": [["strength", 3]] };
| 156|    |-		this.unitStat.ChampMeleeCavalry   = { "priority": 1, "minSize": 3, "targetSize": 15, "batchSize": 3, "classes": ["Cavalry", "Melee", "Champion"],
|    | 156|+		this.unitStat.ChampMeleeCavalry = { "priority": 1, "minSize": 3, "targetSize": 15, "batchSize": 3, "classes": ["Cavalry", "Melee", "Champion"],
| 157| 157| 			"interests": [["strength", 2]] };
| 158| 158| 		this.unitStat.Hero                = { "priority": 1, "minSize": 0, "targetSize":  1, "batchSize": 1, "classes": ["Hero"],
| 159| 159| 			"interests": [["strength", 2]] };
|    | [NORMAL] ESLintBear (no-multi-spaces):
|    | Multiple spaces found before '='.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
| 155| 155| 			"interests": [["strength", 3]] };
| 156| 156| 		this.unitStat.ChampMeleeCavalry   = { "priority": 1, "minSize": 3, "targetSize": 15, "batchSize": 3, "classes": ["Cavalry", "Melee", "Champion"],
| 157| 157| 			"interests": [["strength", 2]] };
| 158|    |-		this.unitStat.Hero                = { "priority": 1, "minSize": 0, "targetSize":  1, "batchSize": 1, "classes": ["Hero"],
|    | 158|+		this.unitStat.Hero = { "priority": 1, "minSize": 0, "targetSize":  1, "batchSize": 1, "classes": ["Hero"],
| 159| 159| 			"interests": [["strength", 2]] };
| 160| 160| 		this.neededShips = 5;
| 161| 161| 	}
|    | [NORMAL] ESLintBear (key-spacing):
|    | Extra space before value for key 'targetSize'.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
| 155| 155| 			"interests": [["strength", 3]] };
| 156| 156| 		this.unitStat.ChampMeleeCavalry   = { "priority": 1, "minSize": 3, "targetSize": 15, "batchSize": 3, "classes": ["Cavalry", "Melee", "Champion"],
| 157| 157| 			"interests": [["strength", 2]] };
| 158|    |-		this.unitStat.Hero                = { "priority": 1, "minSize": 0, "targetSize":  1, "batchSize": 1, "classes": ["Hero"],
|    | 158|+		this.unitStat.Hero                = { "priority": 1, "minSize": 0, "targetSize": 1, "batchSize": 1, "classes": ["Hero"],
| 159| 159| 			"interests": [["strength", 2]] };
| 160| 160| 		this.neededShips = 5;
| 161| 161| 	}
|    | [NORMAL] ESLintBear (no-multi-spaces):
|    | Multiple spaces found before '='.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
| 164| 164| 		priority = 70;
| 165| 165| 		this.unitStat.RangedInfantry = { "priority": 1, "minSize": 6, "targetSize": 16, "batchSize": 3, "classes": ["Infantry", "Ranged"],
| 166| 166| 			"interests": [["canGather", 1], ["strength", 1.6], ["costsResource", 0.3, "stone"], ["costsResource", 0.3, "metal"]] };
| 167|    |-		this.unitStat.MeleeInfantry  = { "priority": 1, "minSize": 6, "targetSize": 16, "batchSize": 3, "classes": ["Infantry", "Melee"],
|    | 167|+		this.unitStat.MeleeInfantry = { "priority": 1, "minSize": 6, "targetSize": 16, "batchSize": 3, "classes": ["Infantry", "Melee"],
| 168| 168| 			"interests": [["canGather", 1], ["strength", 1.6], ["costsResource", 0.3, "stone"], ["costsResource", 0.3, "metal"]] };
| 169| 169| 		this.unitStat.Cavalry = { "priority": 1, "minSize": 2, "targetSize": 6, "batchSize": 2, "classes": ["Cavalry", "CitizenSoldier"],
| 170| 170| 			"interests": [["strength", 1]] };
|    | [NORMAL] ESLintBear (curly):
|    | Unnecessary { after 'if' condition.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
| 399| 399| 	// the completing step is used to return resources and regroup the units
| 400| 400| 	// so we check that we have no more forced order before starting the attack
| 401| 401| 	if (this.state == "completing")
| 402|    |-	{
|    | 402|+	
| 403| 403| 		// if our target was destroyed, go back to "unexecuted" state
| 404| 404| 		if (this.targetPlayer === undefined || !this.target || !gameState.getEntityById(this.target.id()))
| 405| 405| 		{
| 416| 416| 				return 1;
| 417| 417| 			return 2;
| 418| 418| 		}
| 419|    |-	}
|    | 419|+	
| 420| 420| 
| 421| 421| 	if (this.Config.debug > 3 && gameState.ai.playedTurn % 50 === 0)
| 422| 422| 		this.debugAttack();
|    | [NORMAL] ESLintBear (curly):
|    | Unnecessary { after 'for-of'.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
| 525| 525| 
| 526| 526| 	// Remove those units which were in a temporary bombing attack
| 527| 527| 	for (let unitIds of gameState.ai.HQ.attackManager.bombingAttacks.values())
| 528|    |-	{
|    | 528|+	
| 529| 529| 		for (let entId of unitIds.values())
| 530| 530| 		{
| 531| 531| 			let ent = gameState.getEntityById(entId);
| 534| 534| 			unitIds.delete(entId);
| 535| 535| 			ent.stopMoving();
| 536| 536| 		}
| 537|    |-	}
|    | 537|+	
| 538| 538| 
| 539| 539| 	let rallyPoint = this.rallyPoint;
| 540| 540| 	let rallyIndex = gameState.ai.accessibility.getAccessValue(rallyPoint);
|    | [NORMAL] ESLintBear (curly):
|    | Unnecessary { after 'else'.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
| 872| 872| 			targets.addEnt(ent);
| 873| 873| 	}
| 874| 874| 	else
| 875|    |-	{
|    | 875|+	
| 876| 876| 		if (this.type == "Raid")
| 877| 877| 			targets = this.raidTargetFinder(gameState);
| 878| 878| 		else if (this.type == "Rush" || this.type == "Attack")
| 883| 883| 		}
| 884| 884| 		else
| 885| 885| 			targets = this.defaultTargetFinder(gameState, this.targetPlayer);
| 886|    |-	}
|    | 886|+	
| 887| 887| 	if (!targets.hasEntities())
| 888| 888| 		return undefined;
| 889| 889| 
|    | [NORMAL] ESLintBear (indent):
|    | Expected indentation of 2 tabs but found 0.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
|1143|1143| 
|1144|1144| 	if (blocker && blocker.hasClass("StoneWall"))
|1145|1145| 	{
|1146|    |-/*		if (this.hasSiegeUnits())
|    |1146|+		/*		if (this.hasSiegeUnits())
|1147|1147| 		{ */
|1148|1148| 			this.isBlocked = true;
|1149|1149| 			return blocker;
|    | [NORMAL] ESLintBear (indent):
|    | Expected indentation of 2 tabs but found 3.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
|1145|1145| 	{
|1146|1146| /*		if (this.hasSiegeUnits())
|1147|1147| 		{ */
|1148|    |-			this.isBlocked = true;
|    |1148|+		this.isBlocked = true;
|1149|1149| 			return blocker;
|1150|1150| /*		}
|1151|1151| 		return undefined; */
|    | [NORMAL] ESLintBear (indent):
|    | Expected indentation of 2 tabs but found 3.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
|1146|1146| /*		if (this.hasSiegeUnits())
|1147|1147| 		{ */
|1148|1148| 			this.isBlocked = true;
|1149|    |-			return blocker;
|    |1149|+		return blocker;
|1150|1150| /*		}
|1151|1151| 		return undefined; */
|1152|1152| 	}
|    | [NORMAL] ESLintBear (indent):
|    | Expected indentation of 2 tabs but found 0.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
|1147|1147| 		{ */
|1148|1148| 			this.isBlocked = true;
|1149|1149| 			return blocker;
|1150|    |-/*		}
|    |1150|+		/*		}
|1151|1151| 		return undefined; */
|1152|1152| 	}
|1153|1153| 	else if (blocker)
|    | [NORMAL] ESLintBear (curly):
|    | Unnecessary { after 'else'.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
|1345|1345| 				}
|1346|1346| 			}
|1347|1347| 			else
|1348|    |-			{
|    |1348|+			
|1349|1349| 				if (this.isBlocked && !ourUnit.hasClass("Ranged") && attacker.hasClass("Ranged"))
|1350|1350| 				{
|1351|1351| 					// do not react if our melee units are attacked by ranged one and we are blocked by walls
|1398|1398| 					ourUnit.attack(attacker.id(), m.allowCapture(gameState, ourUnit, attacker));
|1399|1399| 					ourUnit.setMetadata(PlayerID, "lastAttackPlanUpdateTime", time);
|1400|1400| 				}
|1401|    |-			}
|    |1401|+			
|1402|1402| 		}
|1403|1403| 
|1404|1404| 		let enemyUnits = gameState.getEnemyUnits(this.targetPlayer);
|    | [NORMAL] ESLintBear (curly):
|    | Unnecessary { after 'if' condition.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
|1347|1347| 			else
|1348|1348| 			{
|1349|1349| 				if (this.isBlocked && !ourUnit.hasClass("Ranged") && attacker.hasClass("Ranged"))
|1350|    |-				{
|    |1350|+				
|1351|1351| 					// do not react if our melee units are attacked by ranged one and we are blocked by walls
|1352|1352| 					// TODO check that the attacker is from behind the wall
|1353|1353| 					continue;
|1354|    |-				}
|    |1354|+				
|1355|1355| 				else if (m.isSiegeUnit(attacker))
|1356|1356| 				{	// if our unit is attacked by a siege unit, we'll send some melee units to help it.
|1357|1357| 					let collec = this.unitCollection.filter(API3.Filters.byClass("Melee")).filterNearest(ourUnit.position(), 5);
|    | [NORMAL] ESLintBear (curly):
|    | Unnecessary { after 'if' condition.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
|1390|1390| 							continue;
|1391|1391| 						let target = gameState.getEntityById(orderData[0].target);
|1392|1392| 						if (target && !target.hasClass("Structure") && !target.hasClass("Support"))
|1393|    |-						{
|    |1393|+						
|1394|1394| 							if (!target.hasClass("Ranged") || !attacker.hasClass("Melee"))
|1395|1395| 								continue;
|1396|    |-						}
|    |1396|+						
|1397|1397| 					}
|1398|1398| 					ourUnit.attack(attacker.id(), m.allowCapture(gameState, ourUnit, attacker));
|1399|1399| 					ourUnit.setMetadata(PlayerID, "lastAttackPlanUpdateTime", time);
|    | [NORMAL] ESLintBear (curly):
|    | Unnecessary { after 'if' condition.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
|1418|1418| 			if (!target || target.hasClass("Structure"))
|1419|1419| 				continue;
|1420|1420| 			if (!(targetId in unitTargets))
|1421|    |-			{
|    |1421|+			
|1422|1422| 				if (m.isSiegeUnit(target) || target.hasClass("Hero"))
|1423|1423| 					unitTargets[targetId] = -8;
|1424|1424| 				else if (target.hasClass("Champion") || target.hasClass("Ship"))
|1425|1425| 					unitTargets[targetId] = -5;
|1426|1426| 				else
|1427|1427| 					unitTargets[targetId] = -3;
|1428|    |-			}
|    |1428|+			
|1429|1429| 			++unitTargets[targetId];
|1430|1430| 		}
|1431|1431| 		let veto = {};
|    | [NORMAL] ESLintBear (curly):
|    | Unnecessary { after 'else'.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
|1438|1438| 		if (this.type == "Rush")
|1439|1439| 			targetClassesUnit = { "attack": ["Unit", "Structure"], "avoid": ["Palisade", "StoneWall", "Tower", "Fortress"], "vetoEntities": veto };
|1440|1440| 		else
|1441|    |-		{
|    |1441|+		
|1442|1442| 			if (this.target.hasClass("Fortress"))
|1443|1443| 				targetClassesUnit = { "attack": ["Unit", "Structure"], "avoid": ["Palisade", "StoneWall"], "vetoEntities": veto };
|1444|1444| 			else if (this.target.hasClass("Palisade") || this.target.hasClass("StoneWall"))
|1445|1445| 				targetClassesUnit = { "attack": ["Unit", "Structure"], "avoid": ["Fortress"], "vetoEntities": veto };
|1446|1446| 			else
|1447|1447| 				targetClassesUnit = { "attack": ["Unit", "Structure"], "avoid": ["Palisade", "StoneWall", "Fortress"], "vetoEntities": veto };
|1448|    |-		}
|    |1448|+		
|1449|1449| 		if (this.target.hasClass("Structure"))
|1450|1450| 			targetClassesSiege = { "attack": ["Structure"], "avoid": [], "vetoEntities": veto };
|1451|1451| 		else
|    | [NORMAL] ESLintBear (curly):
|    | Unnecessary { after 'if' condition.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
|1529|1529| 			let range = 60;
|1530|1530| 			let attackTypes = ent.attackTypes();
|1531|1531| 			if (this.isBlocked)
|1532|    |-			{
|    |1532|+			
|1533|1533| 				if (attackTypes && attackTypes.indexOf("Ranged") !== -1)
|1534|1534| 					range = ent.attackRange("Ranged").max;
|1535|1535| 				else if (attackTypes && attackTypes.indexOf("Melee") !== -1)
|1536|1536| 					range = ent.attackRange("Melee").max;
|1537|1537| 				else
|1538|1538| 					range = 10;
|1539|    |-			}
|    |1539|+			
|1540|1540| 			else if (attackTypes && attackTypes.indexOf("Ranged") !== -1)
|1541|1541| 				range = 30 + ent.attackRange("Ranged").max;
|1542|1542| 			else if (ent.hasClass("Cavalry"))
|    | [NORMAL] ESLintBear (operator-assignment):
|    | Assignment can be replaced with operator assignment.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
|1541|1541| 				range = 30 + ent.attackRange("Ranged").max;
|1542|1542| 			else if (ent.hasClass("Cavalry"))
|1543|1543| 				range += 30;
|1544|    |-			range = range * range;
|    |1544|+			range *= range;
|1545|1545| 			let entAccess = m.getLandAccess(gameState, ent);
|1546|1546| 			// Checking for gates if we're a siege unit.
|1547|1547| 			if (siegeUnit)
|    | [NORMAL] ESLintBear (curly):
|    | Unnecessary { after 'else'.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
|1585|1585| 					}
|1586|1586| 				}
|1587|1587| 				else
|1588|    |-				{
|    |1588|+				
|1589|1589| 					if (!ent.hasClass("Ranged"))
|1590|1590| 					{
|1591|1591| 						let targetClasses = { "attack": targetClassesSiege.attack, "avoid": targetClassesSiege.avoid.concat("Ship"), "vetoEntities": veto };
|1593|1593| 					}
|1594|1594| 					else
|1595|1595| 						ent.attackMove(this.targetPos[0], this.targetPos[1], targetClassesSiege);
|1596|    |-				}
|    |1596|+				
|1597|1597| 			}
|1598|1598| 			else
|1599|1599| 			{
|    | [NORMAL] ESLintBear (curly):
|    | Unnecessary { after 'if' condition.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
|1647|1647| 				{
|1648|1648| 					let targetClasses = targetClassesUnit;
|1649|1649| 					if (maybeUpdate && ent.unitAIState() === "INDIVIDUAL.COMBAT.APPROACHING")	// we may be blocked by walls, attack everything
|1650|    |-					{
|    |1650|+					
|1651|1651| 						if (!ent.hasClass("Ranged") && !ent.hasClass("Ship"))
|1652|1652| 							targetClasses = { "attack": ["Unit", "Structure"], "avoid": ["Ship"], "vetoEntities": veto };
|1653|1653| 						else
|1654|1654| 							targetClasses = { "attack": ["Unit", "Structure"], "vetoEntities": veto };
|1655|    |-					}
|    |1655|+					
|1656|1656| 					else if (!ent.hasClass("Ranged") && !ent.hasClass("Ship"))
|1657|1657| 						targetClasses = { "attack": targetClassesUnit.attack, "avoid": targetClassesUnit.avoid.concat("Ship"), "vetoEntities": veto };
|1658|1658| 					ent.attackMove(this.targetPos[0], this.targetPos[1], targetClasses);
|    | [NORMAL] ESLintBear (curly):
|    | Unnecessary { after 'if' condition.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
|1793|1793| 	}
|1794|1794| 	// Are we arrived at destination ?
|1795|1795| 	if (attackedNB > 1 && (attackedUnitNB || this.hasSiegeUnits()))
|1796|    |-	{
|    |1796|+	
|1797|1797| 		if (gameState.ai.HQ.territoryMap.getOwner(this.position) === this.targetPlayer || attackedNB > 3)
|1798|1798| 		{
|1799|1799| 			this.state = "arrived";
|1800|1800| 			return true;
|1801|1801| 		}
|1802|    |-	}
|    |1802|+	
|1803|1803| 
|1804|1804| 	// basically haven't moved an inch: very likely stuck)
|1805|1805| 	if (API3.SquareVectorDistance(this.position, this.position5TurnsAgo) < 10 && this.path.length > 0 && gameState.ai.playedTurn % 5 === 0)
|    | [NORMAL] ESLintBear (curly):
|    | Unnecessary { after 'for-in'.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
|1919|1919| 			// Check if we could help any current attack
|1920|1920| 			let attackManager = gameState.ai.HQ.attackManager;
|1921|1921| 			for (let attackType in attackManager.startedAttacks)
|1922|    |-			{
|    |1922|+			
|1923|1923| 				for (let attack of attackManager.startedAttacks[attackType])
|1924|1924| 				{
|1925|1925| 					if (attack.name == this.name)
|1938|1938| 					this.targetPos = this.target.position();
|1939|1939| 					return true;
|1940|1940| 				}
|1941|    |-			}
|    |1941|+			
|1942|1942| 
|1943|1943| 			// If not, let's look for another enemy
|1944|1944| 			if (!this.target)

binaries/data/mods/public/simulation/ai/petra/attackPlan.js
|2171| }(PETRA);
|    | [MAJOR] ESLintBear (no-use-before-define):
|    | 'PETRA' was used before it was defined.
|    | [NORMAL] ESLintBear (spaced-comment):
|    | Expected space or tab after '//' in comment.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/Attack.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/Attack.js
| 545| 545| 
| 546| 546| 		let horizSpeed = +this.template[type].Projectile.Speed;
| 547| 547| 		let gravity = +this.template[type].Projectile.Gravity;
| 548|    |-		//horizSpeed /= 2; gravity /= 2; // slow it down for testing
|    | 548|+		// horizSpeed /= 2; gravity /= 2; // slow it down for testing
| 549| 549| 
| 550| 550| 		let cmpPosition = Engine.QueryInterface(this.entity, IID_Position);
| 551| 551| 		if (!cmpPosition || !cmpPosition.IsInWorld())
|    | [NORMAL] ESLintBear (no-trailing-spaces):
|    | Trailing spaces not allowed.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/Attack.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/Attack.js
| 592| 592| 		// TODO: Use unit rotation to implement x/z offsets.
| 593| 593| 		let deltaLaunchPoint = new Vector3D(0, this.template[type].Projectile.LaunchPoint["@y"], 0.0);
| 594| 594| 		let launchPoint = Vector3D.add(selfPosition, deltaLaunchPoint);
| 595|    |-		
|    | 595|+
| 596| 596| 		let cmpVisual = Engine.QueryInterface(this.entity, IID_Visual);
| 597| 597| 		if (cmpVisual)
| 598| 598| 		{
|    | [NORMAL] ESLintBear (curly):
|    | Unnecessary { after 'else'.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/Attack.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/Attack.js
| 664| 664| 			});
| 665| 665| 	}
| 666| 666| 	else
| 667|    |-	{
|    | 667|+	
| 668| 668| 		// Melee attack - hurt the target immediately
| 669| 669| 		cmpDamage.CauseDamage({
| 670| 670| 			"strengths": this.GetAttackStrengths(type),
| 674| 674| 			"type": type,
| 675| 675| 			"attackerOwner": attackerOwner
| 676| 676| 		});
| 677|    |-	}
|    | 677|+	
| 678| 678| };
| 679| 679| 
| 680| 680| /**

binaries/data/mods/public/simulation/components/Attack.js
| 535| ·»   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
| 639| »   »   cmpTimer.SetTimeout(SYSTEM_ENTITY,·IID_Damage,·"MissileHit",·timeToTarget·*·1000·+·+this.template[type].Delay,·data);
|    | [NORMAL] JSHintBear:
|    | Confusing plusses.
|    | [NORMAL] ESLintBear (indent):
|    | Expected indentation of 2 tabs but found 3.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/gui/common/tooltips.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/gui/common/tooltips.js
| 392| 392| function getRepairTimeTooltip(entState)
| 393| 393| {
| 394| 394| 	return sprintf(translate("%(label)s %(details)s"), {
| 395|    |-			"label": headerFont(translate("Number of repairers:")),
|    | 395|+		"label": headerFont(translate("Number of repairers:")),
| 396| 396| 			"details": entState.repairable.numBuilders
| 397| 397| 		}) + "\n" + (entState.repairable.numBuilders ?
| 398| 398| 		sprintf(translatePlural(
|    | [NORMAL] ESLintBear (indent):
|    | Expected indentation of 2 tabs but found 3.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/gui/common/tooltips.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/gui/common/tooltips.js
| 393| 393| {
| 394| 394| 	return sprintf(translate("%(label)s %(details)s"), {
| 395| 395| 			"label": headerFont(translate("Number of repairers:")),
| 396|    |-			"details": entState.repairable.numBuilders
|    | 396|+		"details": entState.repairable.numBuilders
| 397| 397| 		}) + "\n" + (entState.repairable.numBuilders ?
| 398| 398| 		sprintf(translatePlural(
| 399| 399| 			"Add another worker to speed up the repairs by %(second)s second.",
|    | [NORMAL] ESLintBear (indent):
|    | Expected indentation of 1 tab but found 2.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/gui/common/tooltips.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/gui/common/tooltips.js
| 394| 394| 	return sprintf(translate("%(label)s %(details)s"), {
| 395| 395| 			"label": headerFont(translate("Number of repairers:")),
| 396| 396| 			"details": entState.repairable.numBuilders
| 397|    |-		}) + "\n" + (entState.repairable.numBuilders ?
|    | 397|+	}) + "\n" + (entState.repairable.numBuilders ?
| 398| 398| 		sprintf(translatePlural(
| 399| 399| 			"Add another worker to speed up the repairs by %(second)s second.",
| 400| 400| 			"Add another worker to speed up the repairs by %(second)s seconds.",
|    | [NORMAL] ESLintBear (indent):
|    | Expected indentation of 2 tabs but found 3.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/gui/common/tooltips.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/gui/common/tooltips.js
| 414| 414| function getBuildTimeTooltip(entState)
| 415| 415| {
| 416| 416| 	return sprintf(translate("%(label)s %(details)s"), {
| 417|    |-			"label": headerFont(translate("Number of builders:")),
|    | 417|+		"label": headerFont(translate("Number of builders:")),
| 418| 418| 			"details": entState.foundation.numBuilders
| 419| 419| 		}) + "\n" + (entState.foundation.numBuilders ?
| 420| 420| 		sprintf(translatePlural(
|    | [NORMAL] ESLintBear (indent):
|    | Expected indentation of 2 tabs but found 3.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/gui/common/tooltips.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/gui/common/tooltips.js
| 415| 415| {
| 416| 416| 	return sprintf(translate("%(label)s %(details)s"), {
| 417| 417| 			"label": headerFont(translate("Number of builders:")),
| 418|    |-			"details": entState.foundation.numBuilders
|    | 418|+		"details": entState.foundation.numBuilders
| 419| 419| 		}) + "\n" + (entState.foundation.numBuilders ?
| 420| 420| 		sprintf(translatePlural(
| 421| 421| 			"Add another worker to speed up the construction by %(second)s second.",
|    | [NORMAL] ESLintBear (indent):
|    | Expected indentation of 1 tab but found 2.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/gui/common/tooltips.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/gui/common/tooltips.js
| 416| 416| 	return sprintf(translate("%(label)s %(details)s"), {
| 417| 417| 			"label": headerFont(translate("Number of builders:")),
| 418| 418| 			"details": entState.foundation.numBuilders
| 419|    |-		}) + "\n" + (entState.foundation.numBuilders ?
|    | 419|+	}) + "\n" + (entState.foundation.numBuilders ?
| 420| 420| 		sprintf(translatePlural(
| 421| 421| 			"Add another worker to speed up the construction by %(second)s second.",
| 422| 422| 			"Add another worker to speed up the construction by %(second)s seconds.",
|    | [NORMAL] ESLintBear (curly):
|    | Unnecessary { after 'for-of'.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/common-api/entity.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/common-api/entity.js
|  33|  33| 		{
|  34|  34| 			let args = string.split("/");
|  35|  35| 			for (let arg of args)
|  36|    |-			{
|    |  36|+			
|  37|  37| 				if (value[arg])
|  38|  38| 					value = value[arg];
|  39|  39| 				else
|  41|  41| 					value = undefined;
|  42|  42| 					break;
|  43|  43| 				}
|  44|    |-			}
|    |  44|+			
|  45|  45| 			this._tpCache.set(string, value);
|  46|  46| 		}
|  47|  47| 		return this._tpCache.get(string);
|    | [NORMAL] ESLintBear (curly):
|    | Unnecessary { after 'if' condition.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/common-api/entity.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/common-api/entity.js
| 308| 308| 			return undefined;
| 309| 309| 
| 310| 310| 		if (this.get("Attack/" + type + "/Bonuses"))
| 311|    |-		{
|    | 311|+		
| 312| 312| 			for (let b in this.get("Attack/" + type + "/Bonuses"))
| 313| 313| 			{
| 314| 314| 				let bonusClasses = this.get("Attack/" + type + "/Bonuses/" + b + "/Classes");
| 318| 318| 					if (bcl == againstClass)
| 319| 319| 						return +this.get("Attack/" + type + "/Bonuses/" + b + "/Multiplier");
| 320| 320| 			}
| 321|    |-		}
|    | 321|+		
| 322| 322| 		return 1;
| 323| 323| 	},
| 324| 324| 
|    | [NORMAL] ESLintBear (curly):
|    | Unnecessary { after 'for-in'.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/common-api/entity.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/common-api/entity.js
| 755| 755| 			return !target.isInvulnerable();
| 756| 756| 
| 757| 757| 		for (let type in attackTypes)
| 758|    |-		{
|    | 758|+		
| 759| 759| 			// Check if the target is immune to some damage types.
| 760| 760| 			if (type != "Capture")
| 761| 761| 			{
| 773| 773| 
| 774| 774| 				return target.classes().some(cls => this.canAttackClass(cls));
| 775| 775| 			}
| 776|    |-		};
|    | 776|+		;
| 777| 777| 
| 778| 778| 		return false;
| 779| 779| 	},
|    | [NORMAL] ESLintBear (no-extra-semi):
|    | Unnecessary semicolon.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/common-api/entity.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/common-api/entity.js
| 773| 773| 
| 774| 774| 				return target.classes().some(cls => this.canAttackClass(cls));
| 775| 775| 			}
| 776|    |-		};
|    | 776|+		}
| 777| 777| 
| 778| 778| 		return false;
| 779| 779| 	},

binaries/data/mods/public/simulation/ai/common-api/entity.js
| 835| »   »   if·(this.position()·!==·undefined)·{
|    | [NORMAL] ESLintBear (brace-rules/brace-on-same-line):
|    | Opening curly brace appears on the same line as controlling statement.

binaries/data/mods/public/simulation/ai/common-api/entity.js
| 852| »   »   if·(this.position()·!==·undefined·&&·unitToFleeFrom.position()·!==·undefined)·{
|    | [NORMAL] ESLintBear (brace-rules/brace-on-same-line):
|    | Opening curly brace appears on the same line as controlling statement.

binaries/data/mods/public/simulation/ai/common-api/entity.js
| 982| }(API3);
|    | [MAJOR] ESLintBear (no-use-before-define):
|    | 'API3' was used before it was defined.

binaries/data/mods/public/simulation/ai/common-api/entity.js
| 776| »   »   };
|    | [NORMAL] JSHintBear:
|    | Unnecessary semicolon.
Executing section cli...

Link to build: https://jenkins.wildfiregames.com/job/differential/1938/display/redirect

Angen added a comment.EditedJul 7 2019, 9:51 PM

for start, then you should basicly grep .attack and think if that can be problem

This has to be fixed with this change of armour.

binaries/data/mods/public/simulation/ai/petra/attackPlan.js
1323 ↗(On Diff #8770)

no here

1335 ↗(On Diff #8770)

check here

1341 ↗(On Diff #8770)

check here

1343 ↗(On Diff #8770)

cache m.allowCapture before check at line 1341 and use that value

1360 ↗(On Diff #8770)

check here before calling attack

1381 ↗(On Diff #8770)

check before calling attack here

1398 ↗(On Diff #8770)

check here

1515 ↗(On Diff #8770)

possibly if else and check, if cannot attack -> maybeUpdate = true ( question do we need it here ? - will UnitAI attack something cannot harm ?)

1558 ↗(On Diff #8770)

if canot attack -> return false

1617 ↗(On Diff #8770)

if cannot attack -> false

1645 ↗(On Diff #8770)

check here, need to think if should be inside if (this.isBlocked) or can be used &&

1671 ↗(On Diff #8770)

if cannot attack -> return false

1708 ↗(On Diff #8770)

if cannot attack -> return, dont know what is more expensive, distance or can attack

Angen added inline comments.Jul 7 2019, 9:57 PM
binaries/data/mods/public/simulation/ai/petra/defenseArmy.js
317 ↗(On Diff #8770)

This here is ok, just question. In theory what would happen if no entity in army can hurt that foe.

You should take a look into DefenseManager.js assignDefenders

Angen added a comment.Jul 8 2019, 6:40 AM
In D2044#85379, @FeXoR wrote:
In D2044#85377, @Nescio wrote:

Increased mod support?

That can be said about any functional code. If we would add all that we basically would have to add all mods in the first place for other mods might use parts of it.

Also, currently in 0 A.D. siege engines have a pierce armour of 50 (i.e. 1-0.9^50, which is over 99%), so they're practically invulnerable already; to me that seems to be a workaround. This patch would allow making them completely invulnerable, so e.g. archers won't waste their arrows on attacking rams, but instead attack other enemy units around.

And to me it shows that our current damage system already can handle that. (The unitAI is a different story)

@FeXoR with this patch checking with UnitAi and Petra if it is worth to attack entity A with entity B will be easier and free from implementation of taking damage. Because infinite armour will always mean that unit is imune to that damage. Instead checking for some number which meaning or formula can change in the future.

FeXor makes a vild point that using 9999 as Armor will be basically equivalent to infinite, so adding support for that seems kind of un-necessary.
However infinite damage in attack types could also be a way to deal with "InstalKill", so both patches are in fact more tied than I initially realised.

unitAI currently doesn't handle either case well, so it seems like we must fix that regardless.

I'll think about this more over the upcoming days.

In D2044#85441, @Angen wrote:

This has to be fixed with this change of armour.

Thought so.

In D2044#85441, @Angen wrote:

for start, then you should basicly grep .attack and think if that can be problem

Will do.
This: enemy.hasClass("StoneWall") && !ent.canAttackClass("StoneWall") kind of code, can/should/may I replace that with the new function?

binaries/data/mods/public/simulation/ai/petra/attackPlan.js
1515 ↗(On Diff #8770)

No, UnitAI will not try to attack something it can't. So we do not need it here then?

Freagarach marked 11 inline comments as done.Jul 8 2019, 8:16 PM

Also, what to do with attackMove?

binaries/data/mods/public/simulation/ai/petra/attackPlan.js
1343 ↗(On Diff #8770)

Why would that be beneficient? As it is only called once here?

Freagarach added inline comments.Jul 8 2019, 10:53 PM
binaries/data/mods/public/simulation/ai/petra/defenseArmy.js
317 ↗(On Diff #8770)

Then the foe is just fully ignored. Not sure if that is the desired behaviour.

Freagarach updated this revision to Diff 8784.Jul 8 2019, 10:56 PM
Freagarach edited the summary of this revision. (Show Details)
Freagarach edited the test plan for this revision. (Show Details)
  • Improved function canAttackTarget in entity.js in common-api.
  • More checks whether the AI can attack units.
Freagarach added inline comments.Jul 8 2019, 10:57 PM
binaries/data/mods/public/simulation/templates/template_unit_infantry.xml
22 ↗(On Diff #8784)

This and below (and of the cavalry, currently forgotten) are needed because of restricted classes checking in PetraAI.

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

Linter detected issues:
Executing section Source...
Executing section JS...
|    | [NORMAL] ESLintBear (indent):
|    | Expected indentation of 1 tab but found 0.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/defenseArmy.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/defenseArmy.js
| 169| 169| 			plan.removeUnit(gameState, ent);
| 170| 170| 	}
| 171| 171| 
| 172|    |-/*
|    | 172|+	/*
| 173| 173| 	// TODO be sure that all units in the transport need the cancelation
| 174| 174| 	if (!ent.position())	// this unit must still be in a transport plan ... try to cancel it
| 175| 175| 	{
|    | [NORMAL] ESLintBear (curly):
|    | Unnecessary { after 'for-in'.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/defenseArmy.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/defenseArmy.js
| 388| 388| {
| 389| 389| 	// copy over all parameters.
| 390| 390| 	for (let i in otherArmy.assignedAgainst)
| 391|    |-	{
|    | 391|+	
| 392| 392| 		if (this.assignedAgainst[i] === undefined)
| 393| 393| 			this.assignedAgainst[i] = otherArmy.assignedAgainst[i];
| 394| 394| 		else
| 395| 395| 			this.assignedAgainst[i] = this.assignedAgainst[i].concat(otherArmy.assignedAgainst[i]);
| 396|    |-	}
|    | 396|+	
| 397| 397| 	for (let i in otherArmy.assignedTo)
| 398| 398| 		this.assignedTo[i] = otherArmy.assignedTo[i];
| 399| 399| 
|    | [NORMAL] ESLintBear (curly):
|    | Unnecessary { after 'if' condition.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/defenseArmy.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/defenseArmy.js
| 484| 484| 
| 485| 485| 	let entStrength;
| 486| 486| 	if (ent.hasClass("Structure"))
| 487|    |-	{
|    | 487|+	
| 488| 488| 		if (ent.owner() !== PlayerID)
| 489| 489| 			entStrength = ent.getDefaultArrow() ? 6*ent.getDefaultArrow() : 4;
| 490| 490| 		else	// small strength used only when we try to recover capture points
| 491| 491| 			entStrength = 2;
| 492|    |-	}
|    | 492|+	
| 493| 493| 	else
| 494| 494| 		entStrength = m.getMaxStrength(ent);
| 495| 495| 
|    | [NORMAL] ESLintBear (curly):
|    | Unnecessary { after 'for-of'.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/defenseArmy.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/defenseArmy.js
| 513| 513| 	// otherwise it would remove the old entity from this army list
| 514| 514| 	// TODO we should may-be reevaluate the strength
| 515| 515| 	for (let evt of events.EntityRenamed)	// take care of promoted and packed units
| 516|    |-	{
|    | 516|+	
| 517| 517| 		if (this.foeEntities.indexOf(evt.entity) !== -1)
| 518| 518| 		{
| 519| 519| 			let ent = gameState.getEntityById(evt.newentity);
| 541| 541| 					this.assignedAgainst[against][this.assignedAgainst[against].indexOf(evt.entity)] = evt.newentity;
| 542| 542| 			}
| 543| 543| 		}
| 544|    |-	}
|    | 544|+	
| 545| 545| 
| 546| 546| 	for (let evt of events.Garrison)
| 547| 547| 		this.removeFoe(gameState, evt.entity);
|    | [NORMAL] ESLintBear (curly):
|    | Unnecessary { after 'for-of'.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/defenseArmy.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/defenseArmy.js
| 547| 547| 		this.removeFoe(gameState, evt.entity);
| 548| 548| 
| 549| 549| 	for (let evt of events.OwnershipChanged)	// captured
| 550|    |-	{
|    | 550|+	
| 551| 551| 		if (!gameState.isPlayerEnemy(evt.to))
| 552| 552| 			this.removeFoe(gameState, evt.entity);
| 553| 553| 		else if (evt.from === PlayerID)
| 554| 554| 			this.removeOwn(gameState, evt.entity);
| 555|    |-	}
|    | 555|+	
| 556| 556| 
| 557| 557| 	for (let evt of events.Destroy)
| 558| 558| 	{

binaries/data/mods/public/simulation/ai/petra/defenseArmy.js
| 654| }(PETRA);
|    | [MAJOR] ESLintBear (no-use-before-define):
|    | 'PETRA' was used before it was defined.
|    | [NORMAL] ESLintBear (curly):
|    | Unnecessary { after 'for-in'.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/defenseManager.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/defenseManager.js
|  52|  52| 		}
|  53|  53| 	}
|  54|  54| 	for (let enemy in attackingArmies)
|  55|    |-	{
|    |  55|+	
|  56|  56| 		for (let ally in attackingArmies[enemy])
|  57|  57| 		{
|  58|  58| 			if (this.attackedAllies[ally] === undefined)
|  59|  59| 				this.attackedAllies[ally] = 0;
|  60|  60| 			this.attackedAllies[ally] += 1;
|  61|  61| 		}
|  62|    |-	}
|    |  62|+	
|  63|  63| 	this.checkEnemyArmies(gameState);
|  64|  64| 	this.checkEnemyUnits(gameState);
|  65|  65| 	this.assignDefenders(gameState);
|    | [NORMAL] ESLintBear (curly):
|    | Unnecessary { after 'if' condition.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/defenseManager.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/defenseManager.js
|  70|  70| m.DefenseManager.prototype.makeIntoArmy = function(gameState, entityID, type = "default")
|  71|  71| {
|  72|  72| 	if (type == "default")
|  73|    |-	{
|    |  73|+	
|  74|  74| 		// Try to add it to an existing army.
|  75|  75| 		for (let army of this.armies)
|  76|  76| 			if (army.getType() == type && army.addFoe(gameState, entityID))
|  77|  77| 				return;	// over
|  78|    |-	}
|    |  78|+	
|  79|  79| 
|  80|  80| 	// Create a new army for it.
|  81|  81| 	let army = new m.DefenseArmy(gameState, [entityID], type);
|    | [NORMAL] ESLintBear (curly):
|    | Unnecessary { after 'if' condition.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/defenseManager.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/defenseManager.js
| 179| 179| 		if (territoryOwner != PlayerID && this.attackedAllies[territoryOwner] &&
| 180| 180| 		                                  this.attackedAllies[territoryOwner] > 1 &&
| 181| 181| 		                                  this.GetCooperationLevel(territoryOwner) > 0.7)
| 182|    |-		{
|    | 182|+		
| 183| 183| 			for (let building of gameState.getAllyStructures(territoryOwner).values())
| 184| 184| 			{
| 185| 185| 				if (building.foundationProgress() == 0 ||
| 188| 188| 				if (!this.territoryMap.isBlinking(building.position()))
| 189| 189| 					return true;
| 190| 190| 			}
| 191|    |-		}
|    | 191|+		
| 192| 192| 
| 193| 193| 		// Update the number of enemies attacking this ally
| 194| 194| 		let enemy = entity.owner();
|    | [NORMAL] ESLintBear (curly):
|    | Unnecessary { after 'if' condition.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/defenseManager.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/defenseManager.js
| 211| 211| 	if (i == PlayerID)
| 212| 212| 	{
| 213| 213| 		if (!this.armies.length)
| 214|    |-		{
|    | 214|+		
| 215| 215| 			// check if we can recover capture points from any of our notdecaying structures
| 216| 216| 			for (let ent of gameState.getOwnStructures().values())
| 217| 217| 			{
| 229| 229| 				this.makeIntoArmy(gameState, ent.id(), "capturing");
| 230| 230| 				break;
| 231| 231| 			}
| 232|    |-		}
|    | 232|+		
| 233| 233| 		return;
| 234| 234| 	}
| 235| 235| 	else if (!gameState.isPlayerEnemy(i))
|    | [NORMAL] ESLintBear (curly):
|    | Unnecessary { after 'if' condition.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/defenseManager.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/defenseManager.js
| 328| 328| 		if (!gameState.isPlayerEnemy(owner))
| 329| 329| 		{
| 330| 330| 			if (gameState.isPlayerMutualAlly(owner))
| 331|    |-			{
|    | 331|+			
| 332| 332| 				// update the number of enemies attacking this ally
| 333| 333| 				for (let id of army.foeEntities)
| 334| 334| 				{
| 343| 343| 					this.attackingArmies[enemy][owner] += 1;
| 344| 344| 					break;
| 345| 345| 				}
| 346|    |-			}
|    | 346|+			
| 347| 347| 			continue;
| 348| 348| 		}
| 349| 349| 		else if (owner != 0)   // enemy army back in its territory
|    | [NORMAL] ESLintBear (no-extra-semi):
|    | Unnecessary semicolon.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/defenseManager.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/defenseManager.js
| 450| 450| 			});
| 451| 451| 			if (!canAttack)
| 452| 452| 				return;
| 453|    |-		};
|    | 453|+		}
| 454| 454| 
| 455| 455| 		if (ent.getMetadata(PlayerID, "plan") !== undefined && ent.getMetadata(PlayerID, "plan") != -1)
| 456| 456| 		{
|    | [NORMAL] ESLintBear (curly):
|    | Unnecessary { after 'for-of'.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/defenseManager.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/defenseManager.js
| 542| 542| 		army.checkEvents(gameState, events);
| 543| 543| 
| 544| 544| 	for (let evt of events.OwnershipChanged)   // capture events
| 545|    |-	{
|    | 545|+	
| 546| 546| 		if (gameState.isPlayerMutualAlly(evt.from) && evt.to > 0)
| 547| 547| 		{
| 548| 548| 			let ent = gameState.getEntityById(evt.entity);
| 549| 549| 			if (ent && ent.hasClass("CivCentre")) // one of our cc has been captured
| 550| 550| 				gameState.ai.HQ.attackManager.switchDefenseToAttack(gameState, ent, { "range": 150 });
| 551| 551| 		}
| 552|    |-	}
|    | 552|+	
| 553| 553| 
| 554| 554| 	let allAttacked = {};
| 555| 555| 	for (let evt of events.Attacked)
|    | [NORMAL] ESLintBear (curly):
|    | Unnecessary { after 'if' condition.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/defenseManager.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/defenseManager.js
| 564| 564| 		let attacker = gameState.getEntityById(evt.attacker);
| 565| 565| 		if (attacker && gameState.isEntityOwn(attacker) && gameState.isEntityEnemy(target) && !attacker.hasClass("Ship") &&
| 566| 566| 		   (!target.hasClass("Structure") || target.attackRange("Ranged")))
| 567|    |-		{
|    | 567|+		
| 568| 568| 			// If enemies are in range of one of our defensive structures, garrison it for arrow multiplier
| 569| 569| 			// (enemy non-defensive structure are not considered to stay in sync with garrisonManager)
| 570| 570| 			if (attacker.position() && attacker.isGarrisonHolder() && attacker.getArrowMultiplier() &&
| 571| 571| 			    (target.owner() != 0 || !target.hasClass("Unit") ||
| 572| 572| 			     target.unitAIState() && target.unitAIState().split(".")[1] == "COMBAT"))
| 573| 573| 				this.garrisonUnitsInside(gameState, attacker, { "attacker": target });
| 574|    |-		}
|    | 574|+		
| 575| 575| 
| 576| 576| 		if (!gameState.isEntityOwn(target))
| 577| 577| 			continue;
|    | [NORMAL] ESLintBear (curly):
|    | Unnecessary { after 'if' condition.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/defenseManager.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/defenseManager.js
| 769| 769| 	let typeGarrison = data.type || "protection";
| 770| 770| 	let allowMelee = gameState.ai.HQ.garrisonManager.allowMelee(target);
| 771| 771| 	if (allowMelee === undefined)
| 772|    |-	{
|    | 772|+	
| 773| 773| 		// Should be kept in sync with garrisonManager to avoid garrisoning-ungarrisoning some units
| 774| 774| 		if (data.attacker)
| 775| 775| 			allowMelee = data.attacker.hasClass("Structure") ? data.attacker.attackRange("Ranged") : !m.isSiegeUnit(data.attacker);
| 776| 776| 		else
| 777| 777| 			allowMelee = true;
| 778|    |-	}
|    | 778|+	
| 779| 779| 	let units = gameState.getOwnUnits().filter(ent => {
| 780| 780| 		if (!ent.position())
| 781| 781| 			return false;

binaries/data/mods/public/simulation/ai/petra/defenseManager.js
| 970| }(PETRA);
|    | [MAJOR] ESLintBear (no-use-before-define):
|    | 'PETRA' was used before it was defined.

binaries/data/mods/public/simulation/ai/petra/defenseManager.js
| 453| »   »   };
|    | [NORMAL] JSHintBear:
|    | Unnecessary semicolon.
|    | [NORMAL] ESLintBear (curly):
|    | Unnecessary { after 'for-of'.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/common-api/entity.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/common-api/entity.js
|  33|  33| 		{
|  34|  34| 			let args = string.split("/");
|  35|  35| 			for (let arg of args)
|  36|    |-			{
|    |  36|+			
|  37|  37| 				if (value[arg])
|  38|  38| 					value = value[arg];
|  39|  39| 				else
|  41|  41| 					value = undefined;
|  42|  42| 					break;
|  43|  43| 				}
|  44|    |-			}
|    |  44|+			
|  45|  45| 			this._tpCache.set(string, value);
|  46|  46| 		}
|  47|  47| 		return this._tpCache.get(string);
|    | [NORMAL] ESLintBear (curly):
|    | Unnecessary { after 'if' condition.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/common-api/entity.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/common-api/entity.js
| 308| 308| 			return undefined;
| 309| 309| 
| 310| 310| 		if (this.get("Attack/" + type + "/Bonuses"))
| 311|    |-		{
|    | 311|+		
| 312| 312| 			for (let b in this.get("Attack/" + type + "/Bonuses"))
| 313| 313| 			{
| 314| 314| 				let bonusClasses = this.get("Attack/" + type + "/Bonuses/" + b + "/Classes");
| 318| 318| 					if (bcl == againstClass)
| 319| 319| 						return +this.get("Attack/" + type + "/Bonuses/" + b + "/Multiplier");
| 320| 320| 			}
| 321|    |-		}
|    | 321|+		
| 322| 322| 		return 1;
| 323| 323| 	},
| 324| 324| 
|    | [NORMAL] ESLintBear (no-extra-semi):
|    | Unnecessary semicolon.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/common-api/entity.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/common-api/entity.js
| 784| 784| 				return true;
| 785| 785| 			if (!MatchesClassList(target.classes(), restrictedClasses))
| 786| 786| 				return true;
| 787|    |-		};
|    | 787|+		}
| 788| 788| 
| 789| 789| 		return false;
| 790| 790| 	},

binaries/data/mods/public/simulation/ai/common-api/entity.js
| 846| »   »   if·(this.position()·!==·undefined)·{
|    | [NORMAL] ESLintBear (brace-rules/brace-on-same-line):
|    | Opening curly brace appears on the same line as controlling statement.

binaries/data/mods/public/simulation/ai/common-api/entity.js
| 863| »   »   if·(this.position()·!==·undefined·&&·unitToFleeFrom.position()·!==·undefined)·{
|    | [NORMAL] ESLintBear (brace-rules/brace-on-same-line):
|    | Opening curly brace appears on the same line as controlling statement.

binaries/data/mods/public/simulation/ai/common-api/entity.js
| 993| }(API3);
|    | [MAJOR] ESLintBear (no-use-before-define):
|    | 'API3' was used before it was defined.

binaries/data/mods/public/simulation/ai/common-api/entity.js
| 787| »   »   };
|    | [NORMAL] JSHintBear:
|    | Unnecessary semicolon.
|    | [NORMAL] ESLintBear (curly):
|    | Unnecessary { after 'for-in'.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackManager.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackManager.js
|  62|  62| 		targetPlayer = evt.player;
|  63|  63| 		let available = 0;
|  64|  64| 		for (let attackType in this.upcomingAttacks)
|  65|    |-		{
|    |  65|+		
|  66|  66| 			for (let attack of this.upcomingAttacks[attackType])
|  67|  67| 			{
|  68|  68| 				if (attack.state === "completing")
|  79|  79| 				if (attack.unitCollection.length > 2)
|  80|  80| 					available += attack.unitCollection.length;
|  81|  81| 			}
|  82|    |-		}
|    |  82|+		
|  83|  83| 
|  84|  84| 		if (available > 12)	// launch the attack immediately
|  85|  85| 		{
|    | [NORMAL] ESLintBear (curly):
|    | Unnecessary { after 'for-in'.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackManager.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackManager.js
|  84|  84| 		if (available > 12)	// launch the attack immediately
|  85|  85| 		{
|  86|  86| 			for (let attackType in this.upcomingAttacks)
|  87|    |-			{
|    |  87|+			
|  88|  88| 				for (let attack of this.upcomingAttacks[attackType])
|  89|  89| 				{
|  90|  90| 					if (attack.state === "completing" ||
|  94|  94| 					attack.forceStart();
|  95|  95| 					attack.requested = true;
|  96|  96| 				}
|  97|    |-			}
|    |  97|+			
|  98|  98| 			answer = "join";
|  99|  99| 		}
| 100| 100| 		else if (other !== undefined)
|    | [NORMAL] ESLintBear (curly):
|    | Unnecessary { after 'for-of'.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackManager.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackManager.js
| 105| 105| 		m.chatAnswerRequestAttack(gameState, targetPlayer, answer, other);
| 106| 106| 
| 107| 107| 	for (let evt of events.EntityRenamed)	// take care of packing units in bombing attacks
| 108|    |-	{
|    | 108|+	
| 109| 109| 		for (let [targetId, unitIds] of this.bombingAttacks)
| 110| 110| 		{
| 111| 111| 			if (targetId == evt.entity)
| 119| 119| 				unitIds.delete(evt.entity);
| 120| 120| 			}
| 121| 121| 		}
| 122|    |-	}
|    | 122|+	
| 123| 123| };
| 124| 124| 
| 125| 125| /**
|    | [NORMAL] ESLintBear (curly):
|    | Unnecessary { after 'for-of'.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackManager.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackManager.js
| 107| 107| 	for (let evt of events.EntityRenamed)	// take care of packing units in bombing attacks
| 108| 108| 	{
| 109| 109| 		for (let [targetId, unitIds] of this.bombingAttacks)
| 110|    |-		{
|    | 110|+		
| 111| 111| 			if (targetId == evt.entity)
| 112| 112| 			{
| 113| 113| 				this.bombingAttacks.set(evt.newentity, unitIds);
| 118| 118| 				unitIds.add(evt.newentity);
| 119| 119| 				unitIds.delete(evt.entity);
| 120| 120| 			}
| 121|    |-		}
|    | 121|+		
| 122| 122| 	}
| 123| 123| };
| 124| 124| 
|    | [NORMAL] ESLintBear (curly):
|    | Unnecessary { after 'if' condition.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackManager.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackManager.js
| 189| 189| 			let x;
| 190| 190| 			let z;
| 191| 191| 			if (struct.hasClass("Field"))
| 192|    |-			{
|    | 192|+			
| 193| 193| 				if (!struct.resourceSupplyNumGatherers() ||
| 194| 194| 				    !gameState.isPlayerEnemy(gameState.ai.HQ.territoryMap.getOwner(structPos)))
| 195| 195| 					continue;
| 196|    |-			}
|    | 196|+			
| 197| 197| 			let dist = API3.VectorDistance(entPos, structPos);
| 198| 198| 			if (dist > range)
| 199| 199| 			{
|    | [NORMAL] ESLintBear (curly):
|    | Unnecessary { after 'for-in'.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackManager.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackManager.js
| 257| 257| 
| 258| 258| 	let unexecutedAttacks = { "Rush": 0, "Raid": 0, "Attack": 0, "HugeAttack": 0 };
| 259| 259| 	for (let attackType in this.upcomingAttacks)
| 260|    |-	{
|    | 260|+	
| 261| 261| 		for (let i = 0; i < this.upcomingAttacks[attackType].length; ++i)
| 262| 262| 		{
| 263| 263| 			let attack = this.upcomingAttacks[attackType][i];
| 296| 296| 				this.upcomingAttacks[attackType].splice(i--, 1);
| 297| 297| 			}
| 298| 298| 		}
| 299|    |-	}
|    | 299|+	
| 300| 300| 
| 301| 301| 	for (let attackType in this.startedAttacks)
| 302| 302| 	{
|    | [NORMAL] ESLintBear (curly):
|    | Unnecessary { after 'for-in'.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackManager.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackManager.js
| 299| 299| 	}
| 300| 300| 
| 301| 301| 	for (let attackType in this.startedAttacks)
| 302|    |-	{
|    | 302|+	
| 303| 303| 		for (let i = 0; i < this.startedAttacks[attackType].length; ++i)
| 304| 304| 		{
| 305| 305| 			let attack = this.startedAttacks[attackType][i];
| 316| 316| 				this.startedAttacks[attackType].splice(i--, 1);
| 317| 317| 			}
| 318| 318| 		}
| 319|    |-	}
|    | 319|+	
| 320| 320| 
| 321| 321| 	// creating plans after updating because an aborted plan might be reused in that case.
| 322| 322| 
|    | [NORMAL] ESLintBear (curly):
|    | Unnecessary { after 'if' condition.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackManager.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackManager.js
| 342| 342| 	else if (unexecutedAttacks.Attack == 0 && unexecutedAttacks.HugeAttack == 0 &&
| 343| 343| 		this.startedAttacks.Attack.length + this.startedAttacks.HugeAttack.length < Math.min(2, 1 + Math.round(gameState.getPopulationMax()/100)) &&
| 344| 344| 		(this.startedAttacks.Attack.length + this.startedAttacks.HugeAttack.length == 0 || gameState.getPopulationMax() - gameState.getPopulation() > 12))
| 345|    |-	{
|    | 345|+	
| 346| 346| 		if (barracksNb >= 1 && (gameState.currentPhase() > 1 || gameState.isResearching(gameState.getPhaseName(2))) ||
| 347| 347| 			!gameState.ai.HQ.baseManagers[1])	// if we have no base ... nothing else to do than attack
| 348| 348| 		{
| 360| 360| 			}
| 361| 361| 			this.attackNumber++;
| 362| 362| 		}
| 363|    |-	}
|    | 363|+	
| 364| 364| 
| 365| 365| 	if (unexecutedAttacks.Raid === 0 && gameState.ai.HQ.defenseManager.targetList.length)
| 366| 366| 	{
|    | [NORMAL] ESLintBear (curly):
|    | Unnecessary { after 'for-in'.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackManager.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackManager.js
| 386| 386| m.AttackManager.prototype.getPlan = function(planName)
| 387| 387| {
| 388| 388| 	for (let attackType in this.upcomingAttacks)
| 389|    |-	{
|    | 389|+	
| 390| 390| 		for (let attack of this.upcomingAttacks[attackType])
| 391| 391| 			if (attack.getName() == planName)
| 392| 392| 				return attack;
| 393|    |-	}
|    | 393|+	
| 394| 394| 	for (let attackType in this.startedAttacks)
| 395| 395| 	{
| 396| 396| 		for (let attack of this.startedAttacks[attackType])
|    | [NORMAL] ESLintBear (curly):
|    | Unnecessary { after 'for-in'.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackManager.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackManager.js
| 392| 392| 				return attack;
| 393| 393| 	}
| 394| 394| 	for (let attackType in this.startedAttacks)
| 395|    |-	{
|    | 395|+	
| 396| 396| 		for (let attack of this.startedAttacks[attackType])
| 397| 397| 			if (attack.getName() == planName)
| 398| 398| 				return attack;
| 399|    |-	}
|    | 399|+	
| 400| 400| 	return undefined;
| 401| 401| };
| 402| 402| 
|    | [NORMAL] ESLintBear (curly):
|    | Unnecessary { after 'if' condition.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackManager.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackManager.js
| 468| 468| 		veto[i] = true;
| 469| 469| 	// No rush if enemy too well defended (i.e. iberians)
| 470| 470| 	if (attack.type == "Rush")
| 471|    |-	{
|    | 471|+	
| 472| 472| 		for (let i = 1; i < gameState.sharedScript.playersData.length; ++i)
| 473| 473| 		{
| 474| 474| 			if (!gameState.isPlayerEnemy(i) || veto[i])
| 482| 482| 			if (enemyDefense > 6)
| 483| 483| 				veto[i] = true;
| 484| 484| 		}
| 485|    |-	}
|    | 485|+	
| 486| 486| 
| 487| 487| 	// then if not a huge attack, continue attacking our previous target as long as it has some entities,
| 488| 488| 	// otherwise target the most accessible one

binaries/data/mods/public/simulation/ai/petra/attackManager.js
| 808| }(PETRA);
|    | [MAJOR] ESLintBear (no-use-before-define):
|    | 'PETRA' was used before it was defined.
|    | [NORMAL] ESLintBear (spaced-comment):
|    | Expected space or tab after '//' in comment.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/Attack.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/Attack.js
| 545| 545| 
| 546| 546| 		let horizSpeed = +this.template[type].Projectile.Speed;
| 547| 547| 		let gravity = +this.template[type].Projectile.Gravity;
| 548|    |-		//horizSpeed /= 2; gravity /= 2; // slow it down for testing
|    | 548|+		// horizSpeed /= 2; gravity /= 2; // slow it down for testing
| 549| 549| 
| 550| 550| 		let cmpPosition = Engine.QueryInterface(this.entity, IID_Position);
| 551| 551| 		if (!cmpPosition || !cmpPosition.IsInWorld())
|    | [NORMAL] ESLintBear (no-trailing-spaces):
|    | Trailing spaces not allowed.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/Attack.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/Attack.js
| 592| 592| 		// TODO: Use unit rotation to implement x/z offsets.
| 593| 593| 		let deltaLaunchPoint = new Vector3D(0, this.template[type].Projectile.LaunchPoint["@y"], 0.0);
| 594| 594| 		let launchPoint = Vector3D.add(selfPosition, deltaLaunchPoint);
| 595|    |-		
|    | 595|+
| 596| 596| 		let cmpVisual = Engine.QueryInterface(this.entity, IID_Visual);
| 597| 597| 		if (cmpVisual)
| 598| 598| 		{
|    | [NORMAL] ESLintBear (curly):
|    | Unnecessary { after 'else'.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/Attack.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/Attack.js
| 664| 664| 			});
| 665| 665| 	}
| 666| 666| 	else
| 667|    |-	{
|    | 667|+	
| 668| 668| 		// Melee attack - hurt the target immediately
| 669| 669| 		cmpDamage.CauseDamage({
| 670| 670| 			"strengths": this.GetAttackStrengths(type),
| 674| 674| 			"type": type,
| 675| 675| 			"attackerOwner": attackerOwner
| 676| 676| 		});
| 677|    |-	}
|    | 677|+	
| 678| 678| };
| 679| 679| 
| 680| 680| /**

binaries/data/mods/public/simulation/components/Attack.js
| 535| ·»   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
| 639| »   »   cmpTimer.SetTimeout(SYSTEM_ENTITY,·IID_Damage,·"MissileHit",·timeToTarget·*·1000·+·+this.template[type].Delay,·data);
|    | [NORMAL] JSHintBear:
|    | Confusing plusses.
|    | [NORMAL] ESLintBear (indent):
|    | Expected indentation of 2 tabs but found 3.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/gui/common/tooltips.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/gui/common/tooltips.js
| 392| 392| function getRepairTimeTooltip(entState)
| 393| 393| {
| 394| 394| 	return sprintf(translate("%(label)s %(details)s"), {
| 395|    |-			"label": headerFont(translate("Number of repairers:")),
|    | 395|+		"label": headerFont(translate("Number of repairers:")),
| 396| 396| 			"details": entState.repairable.numBuilders
| 397| 397| 		}) + "\n" + (entState.repairable.numBuilders ?
| 398| 398| 		sprintf(translatePlural(
|    | [NORMAL] ESLintBear (indent):
|    | Expected indentation of 2 tabs but found 3.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/gui/common/tooltips.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/gui/common/tooltips.js
| 393| 393| {
| 394| 394| 	return sprintf(translate("%(label)s %(details)s"), {
| 395| 395| 			"label": headerFont(translate("Number of repairers:")),
| 396|    |-			"details": entState.repairable.numBuilders
|    | 396|+		"details": entState.repairable.numBuilders
| 397| 397| 		}) + "\n" + (entState.repairable.numBuilders ?
| 398| 398| 		sprintf(translatePlural(
| 399| 399| 			"Add another worker to speed up the repairs by %(second)s second.",
|    | [NORMAL] ESLintBear (indent):
|    | Expected indentation of 1 tab but found 2.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/gui/common/tooltips.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/gui/common/tooltips.js
| 394| 394| 	return sprintf(translate("%(label)s %(details)s"), {
| 395| 395| 			"label": headerFont(translate("Number of repairers:")),
| 396| 396| 			"details": entState.repairable.numBuilders
| 397|    |-		}) + "\n" + (entState.repairable.numBuilders ?
|    | 397|+	}) + "\n" + (entState.repairable.numBuilders ?
| 398| 398| 		sprintf(translatePlural(
| 399| 399| 			"Add another worker to speed up the repairs by %(second)s second.",
| 400| 400| 			"Add another worker to speed up the repairs by %(second)s seconds.",
|    | [NORMAL] ESLintBear (indent):
|    | Expected indentation of 2 tabs but found 3.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/gui/common/tooltips.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/gui/common/tooltips.js
| 414| 414| function getBuildTimeTooltip(entState)
| 415| 415| {
| 416| 416| 	return sprintf(translate("%(label)s %(details)s"), {
| 417|    |-			"label": headerFont(translate("Number of builders:")),
|    | 417|+		"label": headerFont(translate("Number of builders:")),
| 418| 418| 			"details": entState.foundation.numBuilders
| 419| 419| 		}) + "\n" + (entState.foundation.numBuilders ?
| 420| 420| 		sprintf(translatePlural(
|    | [NORMAL] ESLintBear (indent):
|    | Expected indentation of 2 tabs but found 3.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/gui/common/tooltips.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/gui/common/tooltips.js
| 415| 415| {
| 416| 416| 	return sprintf(translate("%(label)s %(details)s"), {
| 417| 417| 			"label": headerFont(translate("Number of builders:")),
| 418|    |-			"details": entState.foundation.numBuilders
|    | 418|+		"details": entState.foundation.numBuilders
| 419| 419| 		}) + "\n" + (entState.foundation.numBuilders ?
| 420| 420| 		sprintf(translatePlural(
| 421| 421| 			"Add another worker to speed up the construction by %(second)s second.",
|    | [NORMAL] ESLintBear (indent):
|    | Expected indentation of 1 tab but found 2.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/gui/common/tooltips.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/gui/common/tooltips.js
| 416| 416| 	return sprintf(translate("%(label)s %(details)s"), {
| 417| 417| 			"label": headerFont(translate("Number of builders:")),
| 418| 418| 			"details": entState.foundation.numBuilders
| 419|    |-		}) + "\n" + (entState.foundation.numBuilders ?
|    | 419|+	}) + "\n" + (entState.foundation.numBuilders ?
| 420| 420| 		sprintf(translatePlural(
| 421| 421| 			"Add another worker to speed up the construction by %(second)s second.",
| 422| 422| 			"Add another worker to speed up the construction by %(second)s seconds.",
|    | [NORMAL] ESLintBear (curly):
|    | Unnecessary { after 'if' condition.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
|  69|  69| 	this.rallyPoint = rallyPoint;
|  70|  70| 	this.overseas = 0;
|  71|  71| 	if (gameState.ai.HQ.navalMap)
|  72|    |-	{
|    |  72|+	
|  73|  73| 		for (let structure of gameState.getEnemyStructures().values())
|  74|  74| 		{
|  75|  75| 			if (this.target && structure.id() != this.target.id())
| 101| 101| 				gameState.ai.HQ.navalManager.setMinimalTransportShips(gameState, sea, 1);
| 102| 102| 			}
| 103| 103| 		}
| 104|    |-	}
|    | 104|+	
| 105| 105| 	this.paused = false;
| 106| 106| 	this.maxCompletingTime = 0;
| 107| 107| 
|    | [NORMAL] ESLintBear (no-multi-spaces):
|    | Multiple spaces found before '='.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
| 139| 139| 	{
| 140| 140| 		priority = 90;
| 141| 141| 		// basically we want a mix of citizen soldiers so our barracks have a purpose, and champion units.
| 142|    |-		this.unitStat.RangedInfantry    = { "priority": 0.7, "minSize": 5, "targetSize": 20, "batchSize": 5, "classes": ["Infantry", "Ranged", "CitizenSoldier"],
|    | 142|+		this.unitStat.RangedInfantry = { "priority": 0.7, "minSize": 5, "targetSize": 20, "batchSize": 5, "classes": ["Infantry", "Ranged", "CitizenSoldier"],
| 143| 143| 			"interests": [["strength", 3]] };
| 144| 144| 		this.unitStat.MeleeInfantry     = { "priority": 0.7, "minSize": 5, "targetSize": 20, "batchSize": 5, "classes": ["Infantry", "Melee", "CitizenSoldier"],
| 145| 145| 			"interests": [["strength", 3]] };
|    | [NORMAL] ESLintBear (no-multi-spaces):
|    | Multiple spaces found before '='.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
| 141| 141| 		// basically we want a mix of citizen soldiers so our barracks have a purpose, and champion units.
| 142| 142| 		this.unitStat.RangedInfantry    = { "priority": 0.7, "minSize": 5, "targetSize": 20, "batchSize": 5, "classes": ["Infantry", "Ranged", "CitizenSoldier"],
| 143| 143| 			"interests": [["strength", 3]] };
| 144|    |-		this.unitStat.MeleeInfantry     = { "priority": 0.7, "minSize": 5, "targetSize": 20, "batchSize": 5, "classes": ["Infantry", "Melee", "CitizenSoldier"],
|    | 144|+		this.unitStat.MeleeInfantry = { "priority": 0.7, "minSize": 5, "targetSize": 20, "batchSize": 5, "classes": ["Infantry", "Melee", "CitizenSoldier"],
| 145| 145| 			"interests": [["strength", 3]] };
| 146| 146| 		this.unitStat.ChampRangedInfantry = { "priority": 1, "minSize": 3, "targetSize": 18, "batchSize": 3, "classes": ["Infantry", "Ranged", "Champion"],
| 147| 147| 			"interests": [["strength", 3]] };
|    | [NORMAL] ESLintBear (no-multi-spaces):
|    | Multiple spaces found before '='.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
| 145| 145| 			"interests": [["strength", 3]] };
| 146| 146| 		this.unitStat.ChampRangedInfantry = { "priority": 1, "minSize": 3, "targetSize": 18, "batchSize": 3, "classes": ["Infantry", "Ranged", "Champion"],
| 147| 147| 			"interests": [["strength", 3]] };
| 148|    |-		this.unitStat.ChampMeleeInfantry  = { "priority": 1, "minSize": 3, "targetSize": 18, "batchSize": 3, "classes": ["Infantry", "Melee", "Champion"],
|    | 148|+		this.unitStat.ChampMeleeInfantry = { "priority": 1, "minSize": 3, "targetSize": 18, "batchSize": 3, "classes": ["Infantry", "Melee", "Champion"],
| 149| 149| 			"interests": [["strength", 3]] };
| 150| 150| 		this.unitStat.RangedCavalry     = { "priority": 0.7, "minSize": 4, "targetSize": 20, "batchSize": 4, "classes": ["Cavalry", "Ranged", "CitizenSoldier"],
| 151| 151| 			"interests": [["strength", 2]] };
|    | [NORMAL] ESLintBear (no-multi-spaces):
|    | Multiple spaces found before '='.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
| 147| 147| 			"interests": [["strength", 3]] };
| 148| 148| 		this.unitStat.ChampMeleeInfantry  = { "priority": 1, "minSize": 3, "targetSize": 18, "batchSize": 3, "classes": ["Infantry", "Melee", "Champion"],
| 149| 149| 			"interests": [["strength", 3]] };
| 150|    |-		this.unitStat.RangedCavalry     = { "priority": 0.7, "minSize": 4, "targetSize": 20, "batchSize": 4, "classes": ["Cavalry", "Ranged", "CitizenSoldier"],
|    | 150|+		this.unitStat.RangedCavalry = { "priority": 0.7, "minSize": 4, "targetSize": 20, "batchSize": 4, "classes": ["Cavalry", "Ranged", "CitizenSoldier"],
| 151| 151| 			"interests": [["strength", 2]] };
| 152| 152| 		this.unitStat.MeleeCavalry      = { "priority": 0.7, "minSize": 4, "targetSize": 20, "batchSize": 4, "classes": ["Cavalry", "Melee", "CitizenSoldier"],
| 153| 153| 			"interests": [["strength", 2]] };
|    | [NORMAL] ESLintBear (no-multi-spaces):
|    | Multiple spaces found before '='.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
| 149| 149| 			"interests": [["strength", 3]] };
| 150| 150| 		this.unitStat.RangedCavalry     = { "priority": 0.7, "minSize": 4, "targetSize": 20, "batchSize": 4, "classes": ["Cavalry", "Ranged", "CitizenSoldier"],
| 151| 151| 			"interests": [["strength", 2]] };
| 152|    |-		this.unitStat.MeleeCavalry      = { "priority": 0.7, "minSize": 4, "targetSize": 20, "batchSize": 4, "classes": ["Cavalry", "Melee", "CitizenSoldier"],
|    | 152|+		this.unitStat.MeleeCavalry = { "priority": 0.7, "minSize": 4, "targetSize": 20, "batchSize": 4, "classes": ["Cavalry", "Melee", "CitizenSoldier"],
| 153| 153| 			"interests": [["strength", 2]] };
| 154| 154| 		this.unitStat.ChampRangedCavalry  = { "priority": 1, "minSize": 3, "targetSize": 15, "batchSize": 3, "classes": ["Cavalry", "Ranged", "Champion"],
| 155| 155| 			"interests": [["strength", 3]] };
|    | [NORMAL] ESLintBear (no-multi-spaces):
|    | Multiple spaces found before '='.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
| 151| 151| 			"interests": [["strength", 2]] };
| 152| 152| 		this.unitStat.MeleeCavalry      = { "priority": 0.7, "minSize": 4, "targetSize": 20, "batchSize": 4, "classes": ["Cavalry", "Melee", "CitizenSoldier"],
| 153| 153| 			"interests": [["strength", 2]] };
| 154|    |-		this.unitStat.ChampRangedCavalry  = { "priority": 1, "minSize": 3, "targetSize": 15, "batchSize": 3, "classes": ["Cavalry", "Ranged", "Champion"],
|    | 154|+		this.unitStat.ChampRangedCavalry = { "priority": 1, "minSize": 3, "targetSize": 15, "batchSize": 3, "classes": ["Cavalry", "Ranged", "Champion"],
| 155| 155| 			"interests": [["strength", 3]] };
| 156| 156| 		this.unitStat.ChampMeleeCavalry   = { "priority": 1, "minSize": 3, "targetSize": 15, "batchSize": 3, "classes": ["Cavalry", "Melee", "Champion"],
| 157| 157| 			"interests": [["strength", 2]] };
|    | [NORMAL] ESLintBear (no-multi-spaces):
|    | Multiple spaces found before '='.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
| 153| 153| 			"interests": [["strength", 2]] };
| 154| 154| 		this.unitStat.ChampRangedCavalry  = { "priority": 1, "minSize": 3, "targetSize": 15, "batchSize": 3, "classes": ["Cavalry", "Ranged", "Champion"],
| 155| 155| 			"interests": [["strength", 3]] };
| 156|    |-		this.unitStat.ChampMeleeCavalry   = { "priority": 1, "minSize": 3, "targetSize": 15, "batchSize": 3, "classes": ["Cavalry", "Melee", "Champion"],
|    | 156|+		this.unitStat.ChampMeleeCavalry = { "priority": 1, "minSize": 3, "targetSize": 15, "batchSize": 3, "classes": ["Cavalry", "Melee", "Champion"],
| 157| 157| 			"interests": [["strength", 2]] };
| 158| 158| 		this.unitStat.Hero                = { "priority": 1, "minSize": 0, "targetSize":  1, "batchSize": 1, "classes": ["Hero"],
| 159| 159| 			"interests": [["strength", 2]] };
|    | [NORMAL] ESLintBear (no-multi-spaces):
|    | Multiple spaces found before '='.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
| 155| 155| 			"interests": [["strength", 3]] };
| 156| 156| 		this.unitStat.ChampMeleeCavalry   = { "priority": 1, "minSize": 3, "targetSize": 15, "batchSize": 3, "classes": ["Cavalry", "Melee", "Champion"],
| 157| 157| 			"interests": [["strength", 2]] };
| 158|    |-		this.unitStat.Hero                = { "priority": 1, "minSize": 0, "targetSize":  1, "batchSize": 1, "classes": ["Hero"],
|    | 158|+		this.unitStat.Hero = { "priority": 1, "minSize": 0, "targetSize":  1, "batchSize": 1, "classes": ["Hero"],
| 159| 159| 			"interests": [["strength", 2]] };
| 160| 160| 		this.neededShips = 5;
| 161| 161| 	}
|    | [NORMAL] ESLintBear (key-spacing):
|    | Extra space before value for key 'targetSize'.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
| 155| 155| 			"interests": [["strength", 3]] };
| 156| 156| 		this.unitStat.ChampMeleeCavalry   = { "priority": 1, "minSize": 3, "targetSize": 15, "batchSize": 3, "classes": ["Cavalry", "Melee", "Champion"],
| 157| 157| 			"interests": [["strength", 2]] };
| 158|    |-		this.unitStat.Hero                = { "priority": 1, "minSize": 0, "targetSize":  1, "batchSize": 1, "classes": ["Hero"],
|    | 158|+		this.unitStat.Hero                = { "priority": 1, "minSize": 0, "targetSize": 1, "batchSize": 1, "classes": ["Hero"],
| 159| 159| 			"interests": [["strength", 2]] };
| 160| 160| 		this.neededShips = 5;
| 161| 161| 	}
|    | [NORMAL] ESLintBear (no-multi-spaces):
|    | Multiple spaces found before '='.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
| 164| 164| 		priority = 70;
| 165| 165| 		this.unitStat.RangedInfantry = { "priority": 1, "minSize": 6, "targetSize": 16, "batchSize": 3, "classes": ["Infantry", "Ranged"],
| 166| 166| 			"interests": [["canGather", 1], ["strength", 1.6], ["costsResource", 0.3, "stone"], ["costsResource", 0.3, "metal"]] };
| 167|    |-		this.unitStat.MeleeInfantry  = { "priority": 1, "minSize": 6, "targetSize": 16, "batchSize": 3, "classes": ["Infantry", "Melee"],
|    | 167|+		this.unitStat.MeleeInfantry = { "priority": 1, "minSize": 6, "targetSize": 16, "batchSize": 3, "classes": ["Infantry", "Melee"],
| 168| 168| 			"interests": [["canGather", 1], ["strength", 1.6], ["costsResource", 0.3, "stone"], ["costsResource", 0.3, "metal"]] };
| 169| 169| 		this.unitStat.Cavalry = { "priority": 1, "minSize": 2, "targetSize": 6, "batchSize": 2, "classes": ["Cavalry", "CitizenSoldier"],
| 170| 170| 			"interests": [["strength", 1]] };
|    | [NORMAL] ESLintBear (curly):
|    | Unnecessary { after 'if' condition.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
| 399| 399| 	// the completing step is used to return resources and regroup the units
| 400| 400| 	// so we check that we have no more forced order before starting the attack
| 401| 401| 	if (this.state == "completing")
| 402|    |-	{
|    | 402|+	
| 403| 403| 		// if our target was destroyed, go back to "unexecuted" state
| 404| 404| 		if (this.targetPlayer === undefined || !this.target || !gameState.getEntityById(this.target.id()))
| 405| 405| 		{
| 416| 416| 				return 1;
| 417| 417| 			return 2;
| 418| 418| 		}
| 419|    |-	}
|    | 419|+	
| 420| 420| 
| 421| 421| 	if (this.Config.debug > 3 && gameState.ai.playedTurn % 50 === 0)
| 422| 422| 		this.debugAttack();
|    | [NORMAL] ESLintBear (curly):
|    | Unnecessary { after 'for-of'.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
| 525| 525| 
| 526| 526| 	// Remove those units which were in a temporary bombing attack
| 527| 527| 	for (let unitIds of gameState.ai.HQ.attackManager.bombingAttacks.values())
| 528|    |-	{
|    | 528|+	
| 529| 529| 		for (let entId of unitIds.values())
| 530| 530| 		{
| 531| 531| 			let ent = gameState.getEntityById(entId);
| 534| 534| 			unitIds.delete(entId);
| 535| 535| 			ent.stopMoving();
| 536| 536| 		}
| 537|    |-	}
|    | 537|+	
| 538| 538| 
| 539| 539| 	let rallyPoint = this.rallyPoint;
| 540| 540| 	let rallyIndex = gameState.ai.accessibility.getAccessValue(rallyPoint);
|    | [NORMAL] ESLintBear (curly):
|    | Unnecessary { after 'else'.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
| 872| 872| 			targets.addEnt(ent);
| 873| 873| 	}
| 874| 874| 	else
| 875|    |-	{
|    | 875|+	
| 876| 876| 		if (this.type == "Raid")
| 877| 877| 			targets = this.raidTargetFinder(gameState);
| 878| 878| 		else if (this.type == "Rush" || this.type == "Attack")
| 883| 883| 		}
| 884| 884| 		else
| 885| 885| 			targets = this.defaultTargetFinder(gameState, this.targetPlayer);
| 886|    |-	}
|    | 886|+	
| 887| 887| 	if (!targets.hasEntities())
| 888| 888| 		return undefined;
| 889| 889| 
|    | [NORMAL] ESLintBear (indent):
|    | Expected indentation of 2 tabs but found 0.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
|1143|1143| 
|1144|1144| 	if (blocker && blocker.hasClass("StoneWall"))
|1145|1145| 	{
|1146|    |-/*		if (this.hasSiegeUnits())
|    |1146|+		/*		if (this.hasSiegeUnits())
|1147|1147| 		{ */
|1148|1148| 			this.isBlocked = true;
|1149|1149| 			return blocker;
|    | [NORMAL] ESLintBear (indent):
|    | Expected indentation of 2 tabs but found 3.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
|1145|1145| 	{
|1146|1146| /*		if (this.hasSiegeUnits())
|1147|1147| 		{ */
|1148|    |-			this.isBlocked = true;
|    |1148|+		this.isBlocked = true;
|1149|1149| 			return blocker;
|1150|1150| /*		}
|1151|1151| 		return undefined; */
|    | [NORMAL] ESLintBear (indent):
|    | Expected indentation of 2 tabs but found 3.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
|1146|1146| /*		if (this.hasSiegeUnits())
|1147|1147| 		{ */
|1148|1148| 			this.isBlocked = true;
|1149|    |-			return blocker;
|    |1149|+		return blocker;
|1150|1150| /*		}
|1151|1151| 		return undefined; */
|1152|1152| 	}
|    | [NORMAL] ESLintBear (indent):
|    | Expected indentation of 2 tabs but found 0.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
|1147|1147| 		{ */
|1148|1148| 			this.isBlocked = true;
|1149|1149| 			return blocker;
|1150|    |-/*		}
|    |1150|+		/*		}
|1151|1151| 		return undefined; */
|1152|1152| 	}
|1153|1153| 	else if (blocker)
|    | [NORMAL] ESLintBear (curly):
|    | Unnecessary { after 'else'.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
|1347|1347| 				}
|1348|1348| 			}
|1349|1349| 			else
|1350|    |-			{
|    |1350|+			
|1351|1351| 				if (this.isBlocked && !ourUnit.hasClass("Ranged") && attacker.hasClass("Ranged"))
|1352|1352| 				{
|1353|1353| 					// do not react if our melee units are attacked by ranged one and we are blocked by walls
|1405|1405| 						ourUnit.setMetadata(PlayerID, "lastAttackPlanUpdateTime", time);
|1406|1406| 					}
|1407|1407| 				}
|1408|    |-			}
|    |1408|+			
|1409|1409| 		}
|1410|1410| 
|1411|1411| 		let enemyUnits = gameState.getEnemyUnits(this.targetPlayer);
|    | [NORMAL] ESLintBear (curly):
|    | Unnecessary { after 'if' condition.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
|1349|1349| 			else
|1350|1350| 			{
|1351|1351| 				if (this.isBlocked && !ourUnit.hasClass("Ranged") && attacker.hasClass("Ranged"))
|1352|    |-				{
|    |1352|+				
|1353|1353| 					// do not react if our melee units are attacked by ranged one and we are blocked by walls
|1354|1354| 					// TODO check that the attacker is from behind the wall
|1355|1355| 					continue;
|1356|    |-				}
|    |1356|+				
|1357|1357| 				else if (m.isSiegeUnit(attacker))
|1358|1358| 				{	// if our unit is attacked by a siege unit, we'll send some melee units to help it.
|1359|1359| 					let collec = this.unitCollection.filter(API3.Filters.byClass("Melee")).filterNearest(ourUnit.position(), 5);
|    | [NORMAL] ESLintBear (curly):
|    | Unnecessary { after 'if' condition.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
|1394|1394| 							continue;
|1395|1395| 						let target = gameState.getEntityById(orderData[0].target);
|1396|1396| 						if (target && !target.hasClass("Structure") && !target.hasClass("Support"))
|1397|    |-						{
|    |1397|+						
|1398|1398| 							if (!target.hasClass("Ranged") || !attacker.hasClass("Melee"))
|1399|1399| 								continue;
|1400|    |-						}
|    |1400|+						
|1401|1401| 					}
|1402|1402| 					if (ourUnit.canAttackTarget(attacker.id()))
|1403|1403| 					{
|    | [NORMAL] ESLintBear (curly):
|    | Unnecessary { after 'if' condition.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
|1425|1425| 			if (!target || target.hasClass("Structure"))
|1426|1426| 				continue;
|1427|1427| 			if (!(targetId in unitTargets))
|1428|    |-			{
|    |1428|+			
|1429|1429| 				if (m.isSiegeUnit(target) || target.hasClass("Hero"))
|1430|1430| 					unitTargets[targetId] = -8;
|1431|1431| 				else if (target.hasClass("Champion") || target.hasClass("Ship"))
|1432|1432| 					unitTargets[targetId] = -5;
|1433|1433| 				else
|1434|1434| 					unitTargets[targetId] = -3;
|1435|    |-			}
|    |1435|+			
|1436|1436| 			++unitTargets[targetId];
|1437|1437| 		}
|1438|1438| 		let veto = {};
|    | [NORMAL] ESLintBear (curly):
|    | Unnecessary { after 'else'.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
|1445|1445| 		if (this.type == "Rush")
|1446|1446| 			targetClassesUnit = { "attack": ["Unit", "Structure"], "avoid": ["Palisade", "StoneWall", "Tower", "Fortress"], "vetoEntities": veto };
|1447|1447| 		else
|1448|    |-		{
|    |1448|+		
|1449|1449| 			if (this.target.hasClass("Fortress"))
|1450|1450| 				targetClassesUnit = { "attack": ["Unit", "Structure"], "avoid": ["Palisade", "StoneWall"], "vetoEntities": veto };
|1451|1451| 			else if (this.target.hasClass("Palisade") || this.target.hasClass("StoneWall"))
|1452|1452| 				targetClassesUnit = { "attack": ["Unit", "Structure"], "avoid": ["Fortress"], "vetoEntities": veto };
|1453|1453| 			else
|1454|1454| 				targetClassesUnit = { "attack": ["Unit", "Structure"], "avoid": ["Palisade", "StoneWall", "Fortress"], "vetoEntities": veto };
|1455|    |-		}
|    |1455|+		
|1456|1456| 		if (this.target.hasClass("Structure"))
|1457|1457| 			targetClassesSiege = { "attack": ["Structure"], "avoid": [], "vetoEntities": veto };
|1458|1458| 		else
|    | [NORMAL] ESLintBear (curly):
|    | Unnecessary { after 'if' condition.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
|1536|1536| 			let range = 60;
|1537|1537| 			let attackTypes = ent.attackTypes();
|1538|1538| 			if (this.isBlocked)
|1539|    |-			{
|    |1539|+			
|1540|1540| 				if (attackTypes && attackTypes.indexOf("Ranged") !== -1)
|1541|1541| 					range = ent.attackRange("Ranged").max;
|1542|1542| 				else if (attackTypes && attackTypes.indexOf("Melee") !== -1)
|1543|1543| 					range = ent.attackRange("Melee").max;
|1544|1544| 				else
|1545|1545| 					range = 10;
|1546|    |-			}
|    |1546|+			
|1547|1547| 			else if (attackTypes && attackTypes.indexOf("Ranged") !== -1)
|1548|1548| 				range = 30 + ent.attackRange("Ranged").max;
|1549|1549| 			else if (ent.hasClass("Cavalry"))
|    | [NORMAL] ESLintBear (operator-assignment):
|    | Assignment can be replaced with operator assignment.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
|1548|1548| 				range = 30 + ent.attackRange("Ranged").max;
|1549|1549| 			else if (ent.hasClass("Cavalry"))
|1550|1550| 				range += 30;
|1551|    |-			range = range * range;
|    |1551|+			range *= range;
|1552|1552| 			let entAccess = m.getLandAccess(gameState, ent);
|1553|1553| 			// Checking for gates if we're a siege unit.
|1554|1554| 			if (siegeUnit)
|    | [NORMAL] ESLintBear (curly):
|    | Unnecessary { after 'else'.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
|1592|1592| 					}
|1593|1593| 				}
|1594|1594| 				else
|1595|    |-				{
|    |1595|+				
|1596|1596| 					if (!ent.hasClass("Ranged"))
|1597|1597| 					{
|1598|1598| 						let targetClasses = { "attack": targetClassesSiege.attack, "avoid": targetClassesSiege.avoid.concat("Ship"), "vetoEntities": veto };
|1600|1600| 					}
|1601|1601| 					else
|1602|1602| 						ent.attackMove(this.targetPos[0], this.targetPos[1], targetClassesSiege);
|1603|    |-				}
|    |1603|+				
|1604|1604| 			}
|1605|1605| 			else
|1606|1606| 			{
|    | [NORMAL] ESLintBear (curly):
|    | Unnecessary { after 'if' condition.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
|1654|1654| 				{
|1655|1655| 					let targetClasses = targetClassesUnit;
|1656|1656| 					if (maybeUpdate && ent.unitAIState() === "INDIVIDUAL.COMBAT.APPROACHING")	// we may be blocked by walls, attack everything
|1657|    |-					{
|    |1657|+					
|1658|1658| 						if (!ent.hasClass("Ranged") && !ent.hasClass("Ship"))
|1659|1659| 							targetClasses = { "attack": ["Unit", "Structure"], "avoid": ["Ship"], "vetoEntities": veto };
|1660|1660| 						else
|1661|1661| 							targetClasses = { "attack": ["Unit", "Structure"], "vetoEntities": veto };
|1662|    |-					}
|    |1662|+					
|1663|1663| 					else if (!ent.hasClass("Ranged") && !ent.hasClass("Ship"))
|1664|1664| 						targetClasses = { "attack": targetClassesUnit.attack, "avoid": targetClassesUnit.avoid.concat("Ship"), "vetoEntities": veto };
|1665|1665| 					ent.attackMove(this.targetPos[0], this.targetPos[1], targetClasses);
|    | [NORMAL] ESLintBear (curly):
|    | Unnecessary { after 'if' condition.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
|1802|1802| 	}
|1803|1803| 	// Are we arrived at destination ?
|1804|1804| 	if (attackedNB > 1 && (attackedUnitNB || this.hasSiegeUnits()))
|1805|    |-	{
|    |1805|+	
|1806|1806| 		if (gameState.ai.HQ.territoryMap.getOwner(this.position) === this.targetPlayer || attackedNB > 3)
|1807|1807| 		{
|1808|1808| 			this.state = "arrived";
|1809|1809| 			return true;
|1810|1810| 		}
|1811|    |-	}
|    |1811|+	
|1812|1812| 
|1813|1813| 	// basically haven't moved an inch: very likely stuck)
|1814|1814| 	if (API3.SquareVectorDistance(this.position, this.position5TurnsAgo) < 10 && this.path.length > 0 && gameState.ai.playedTurn % 5 === 0)
|    | [NORMAL] ESLintBear (curly):
|    | Unnecessary { after 'for-in'.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
|1928|1928| 			// Check if we could help any current attack
|1929|1929| 			let attackManager = gameState.ai.HQ.attackManager;
|1930|1930| 			for (let attackType in attackManager.startedAttacks)
|1931|    |-			{
|    |1931|+			
|1932|1932| 				for (let attack of attackManager.startedAttacks[attackType])
|1933|1933| 				{
|1934|1934| 					if (attack.name == this.name)
|1947|1947| 					this.targetPos = this.target.position();
|1948|1948| 					return true;
|1949|1949| 				}
|1950|    |-			}
|    |1950|+			
|1951|1951| 
|1952|1952| 			// If not, let's look for another enemy
|1953|1953| 			if (!this.target)

binaries/data/mods/public/simulation/ai/petra/attackPlan.js
|2180| }(PETRA);
|    | [MAJOR] ESLintBear (no-use-before-define):
|    | 'PETRA' was used before it was defined.
Executing section cli...

Link to build: https://jenkins.wildfiregames.com/job/differential/1948/display/redirect

Angen added a comment.Jul 9 2019, 7:49 AM

i ll check another things later

binaries/data/mods/public/simulation/ai/petra/attackPlan.js
1343 ↗(On Diff #8770)

because if you dont, you can end up returning capture as only option and not allowing it when calling attack

In D2044#85582, @Angen wrote:

i ll check another things later

Thanks! I'm currently running many test games AI vs AI and already found lots of errors :( Mainly when I use *.id() where it should not be used and vice versa.

Freagarach added inline comments.Jul 9 2019, 8:33 AM
binaries/data/mods/public/simulation/ai/petra/attackPlan.js
1343 ↗(On Diff #8770)

Ah, good point. But won't that problem be also present when I cache the value a tad earlier?

Freagarach updated this revision to Diff 8788.Jul 9 2019, 8:33 AM
  • Some fixes regarding PetraAI.
Vulcan added a comment.Jul 9 2019, 8:54 AM

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

Linter detected issues:
Executing section Source...
Executing section JS...
|    | [NORMAL] ESLintBear (indent):
|    | Expected indentation of 2 tabs but found 3.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/gui/common/tooltips.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/gui/common/tooltips.js
| 392| 392| function getRepairTimeTooltip(entState)
| 393| 393| {
| 394| 394| 	return sprintf(translate("%(label)s %(details)s"), {
| 395|    |-			"label": headerFont(translate("Number of repairers:")),
|    | 395|+		"label": headerFont(translate("Number of repairers:")),
| 396| 396| 			"details": entState.repairable.numBuilders
| 397| 397| 		}) + "\n" + (entState.repairable.numBuilders ?
| 398| 398| 		sprintf(translatePlural(
|    | [NORMAL] ESLintBear (indent):
|    | Expected indentation of 2 tabs but found 3.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/gui/common/tooltips.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/gui/common/tooltips.js
| 393| 393| {
| 394| 394| 	return sprintf(translate("%(label)s %(details)s"), {
| 395| 395| 			"label": headerFont(translate("Number of repairers:")),
| 396|    |-			"details": entState.repairable.numBuilders
|    | 396|+		"details": entState.repairable.numBuilders
| 397| 397| 		}) + "\n" + (entState.repairable.numBuilders ?
| 398| 398| 		sprintf(translatePlural(
| 399| 399| 			"Add another worker to speed up the repairs by %(second)s second.",
|    | [NORMAL] ESLintBear (indent):
|    | Expected indentation of 1 tab but found 2.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/gui/common/tooltips.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/gui/common/tooltips.js
| 394| 394| 	return sprintf(translate("%(label)s %(details)s"), {
| 395| 395| 			"label": headerFont(translate("Number of repairers:")),
| 396| 396| 			"details": entState.repairable.numBuilders
| 397|    |-		}) + "\n" + (entState.repairable.numBuilders ?
|    | 397|+	}) + "\n" + (entState.repairable.numBuilders ?
| 398| 398| 		sprintf(translatePlural(
| 399| 399| 			"Add another worker to speed up the repairs by %(second)s second.",
| 400| 400| 			"Add another worker to speed up the repairs by %(second)s seconds.",
|    | [NORMAL] ESLintBear (indent):
|    | Expected indentation of 2 tabs but found 3.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/gui/common/tooltips.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/gui/common/tooltips.js
| 414| 414| function getBuildTimeTooltip(entState)
| 415| 415| {
| 416| 416| 	return sprintf(translate("%(label)s %(details)s"), {
| 417|    |-			"label": headerFont(translate("Number of builders:")),
|    | 417|+		"label": headerFont(translate("Number of builders:")),
| 418| 418| 			"details": entState.foundation.numBuilders
| 419| 419| 		}) + "\n" + (entState.foundation.numBuilders ?
| 420| 420| 		sprintf(translatePlural(
|    | [NORMAL] ESLintBear (indent):
|    | Expected indentation of 2 tabs but found 3.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/gui/common/tooltips.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/gui/common/tooltips.js
| 415| 415| {
| 416| 416| 	return sprintf(translate("%(label)s %(details)s"), {
| 417| 417| 			"label": headerFont(translate("Number of builders:")),
| 418|    |-			"details": entState.foundation.numBuilders
|    | 418|+		"details": entState.foundation.numBuilders
| 419| 419| 		}) + "\n" + (entState.foundation.numBuilders ?
| 420| 420| 		sprintf(translatePlural(
| 421| 421| 			"Add another worker to speed up the construction by %(second)s second.",
|    | [NORMAL] ESLintBear (indent):
|    | Expected indentation of 1 tab but found 2.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/gui/common/tooltips.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/gui/common/tooltips.js
| 416| 416| 	return sprintf(translate("%(label)s %(details)s"), {
| 417| 417| 			"label": headerFont(translate("Number of builders:")),
| 418| 418| 			"details": entState.foundation.numBuilders
| 419|    |-		}) + "\n" + (entState.foundation.numBuilders ?
|    | 419|+	}) + "\n" + (entState.foundation.numBuilders ?
| 420| 420| 		sprintf(translatePlural(
| 421| 421| 			"Add another worker to speed up the construction by %(second)s second.",
| 422| 422| 			"Add another worker to speed up the construction by %(second)s seconds.",
|    | [NORMAL] ESLintBear (indent):
|    | Expected indentation of 1 tab but found 0.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/defenseArmy.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/defenseArmy.js
| 169| 169| 			plan.removeUnit(gameState, ent);
| 170| 170| 	}
| 171| 171| 
| 172|    |-/*
|    | 172|+	/*
| 173| 173| 	// TODO be sure that all units in the transport need the cancelation
| 174| 174| 	if (!ent.position())	// this unit must still be in a transport plan ... try to cancel it
| 175| 175| 	{
|    | [NORMAL] ESLintBear (curly):
|    | Unnecessary { after 'for-in'.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/defenseArmy.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/defenseArmy.js
| 388| 388| {
| 389| 389| 	// copy over all parameters.
| 390| 390| 	for (let i in otherArmy.assignedAgainst)
| 391|    |-	{
|    | 391|+	
| 392| 392| 		if (this.assignedAgainst[i] === undefined)
| 393| 393| 			this.assignedAgainst[i] = otherArmy.assignedAgainst[i];
| 394| 394| 		else
| 395| 395| 			this.assignedAgainst[i] = this.assignedAgainst[i].concat(otherArmy.assignedAgainst[i]);
| 396|    |-	}
|    | 396|+	
| 397| 397| 	for (let i in otherArmy.assignedTo)
| 398| 398| 		this.assignedTo[i] = otherArmy.assignedTo[i];
| 399| 399| 
|    | [NORMAL] ESLintBear (curly):
|    | Unnecessary { after 'if' condition.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/defenseArmy.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/defenseArmy.js
| 484| 484| 
| 485| 485| 	let entStrength;
| 486| 486| 	if (ent.hasClass("Structure"))
| 487|    |-	{
|    | 487|+	
| 488| 488| 		if (ent.owner() !== PlayerID)
| 489| 489| 			entStrength = ent.getDefaultArrow() ? 6*ent.getDefaultArrow() : 4;
| 490| 490| 		else	// small strength used only when we try to recover capture points
| 491| 491| 			entStrength = 2;
| 492|    |-	}
|    | 492|+	
| 493| 493| 	else
| 494| 494| 		entStrength = m.getMaxStrength(ent);
| 495| 495| 
|    | [NORMAL] ESLintBear (curly):
|    | Unnecessary { after 'for-of'.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/defenseArmy.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/defenseArmy.js
| 513| 513| 	// otherwise it would remove the old entity from this army list
| 514| 514| 	// TODO we should may-be reevaluate the strength
| 515| 515| 	for (let evt of events.EntityRenamed)	// take care of promoted and packed units
| 516|    |-	{
|    | 516|+	
| 517| 517| 		if (this.foeEntities.indexOf(evt.entity) !== -1)
| 518| 518| 		{
| 519| 519| 			let ent = gameState.getEntityById(evt.newentity);
| 541| 541| 					this.assignedAgainst[against][this.assignedAgainst[against].indexOf(evt.entity)] = evt.newentity;
| 542| 542| 			}
| 543| 543| 		}
| 544|    |-	}
|    | 544|+	
| 545| 545| 
| 546| 546| 	for (let evt of events.Garrison)
| 547| 547| 		this.removeFoe(gameState, evt.entity);
|    | [NORMAL] ESLintBear (curly):
|    | Unnecessary { after 'for-of'.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/defenseArmy.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/defenseArmy.js
| 547| 547| 		this.removeFoe(gameState, evt.entity);
| 548| 548| 
| 549| 549| 	for (let evt of events.OwnershipChanged)	// captured
| 550|    |-	{
|    | 550|+	
| 551| 551| 		if (!gameState.isPlayerEnemy(evt.to))
| 552| 552| 			this.removeFoe(gameState, evt.entity);
| 553| 553| 		else if (evt.from === PlayerID)
| 554| 554| 			this.removeOwn(gameState, evt.entity);
| 555|    |-	}
|    | 555|+	
| 556| 556| 
| 557| 557| 	for (let evt of events.Destroy)
| 558| 558| 	{

binaries/data/mods/public/simulation/ai/petra/defenseArmy.js
| 654| }(PETRA);
|    | [MAJOR] ESLintBear (no-use-before-define):
|    | 'PETRA' was used before it was defined.
|    | [NORMAL] ESLintBear (curly):
|    | Unnecessary { after 'for-of'.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/common-api/entity.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/common-api/entity.js
|  33|  33| 		{
|  34|  34| 			let args = string.split("/");
|  35|  35| 			for (let arg of args)
|  36|    |-			{
|    |  36|+			
|  37|  37| 				if (value[arg])
|  38|  38| 					value = value[arg];
|  39|  39| 				else
|  41|  41| 					value = undefined;
|  42|  42| 					break;
|  43|  43| 				}
|  44|    |-			}
|    |  44|+			
|  45|  45| 			this._tpCache.set(string, value);
|  46|  46| 		}
|  47|  47| 		return this._tpCache.get(string);
|    | [NORMAL] ESLintBear (curly):
|    | Unnecessary { after 'if' condition.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/common-api/entity.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/common-api/entity.js
| 308| 308| 			return undefined;
| 309| 309| 
| 310| 310| 		if (this.get("Attack/" + type + "/Bonuses"))
| 311|    |-		{
|    | 311|+		
| 312| 312| 			for (let b in this.get("Attack/" + type + "/Bonuses"))
| 313| 313| 			{
| 314| 314| 				let bonusClasses = this.get("Attack/" + type + "/Bonuses/" + b + "/Classes");
| 318| 318| 					if (bcl == againstClass)
| 319| 319| 						return +this.get("Attack/" + type + "/Bonuses/" + b + "/Multiplier");
| 320| 320| 			}
| 321|    |-		}
|    | 321|+		
| 322| 322| 		return 1;
| 323| 323| 	},
| 324| 324| 
|    | [NORMAL] ESLintBear (no-extra-semi):
|    | Unnecessary semicolon.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/common-api/entity.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/common-api/entity.js
| 784| 784| 				return true;
| 785| 785| 			if (!MatchesClassList(target.classes(), restrictedClasses))
| 786| 786| 				return true;
| 787|    |-		};
|    | 787|+		}
| 788| 788| 
| 789| 789| 		return false;
| 790| 790| 	},

binaries/data/mods/public/simulation/ai/common-api/entity.js
| 846| »   »   if·(this.position()·!==·undefined)·{
|    | [NORMAL] ESLintBear (brace-rules/brace-on-same-line):
|    | Opening curly brace appears on the same line as controlling statement.

binaries/data/mods/public/simulation/ai/common-api/entity.js
| 863| »   »   if·(this.position()·!==·undefined·&&·unitToFleeFrom.position()·!==·undefined)·{
|    | [NORMAL] ESLintBear (brace-rules/brace-on-same-line):
|    | Opening curly brace appears on the same line as controlling statement.

binaries/data/mods/public/simulation/ai/common-api/entity.js
| 993| }(API3);
|    | [MAJOR] ESLintBear (no-use-before-define):
|    | 'API3' was used before it was defined.

binaries/data/mods/public/simulation/ai/common-api/entity.js
| 787| »   »   };
|    | [NORMAL] JSHintBear:
|    | Unnecessary semicolon.
|    | [NORMAL] ESLintBear (curly):
|    | Unnecessary { after 'for-in'.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/defenseManager.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/defenseManager.js
|  52|  52| 		}
|  53|  53| 	}
|  54|  54| 	for (let enemy in attackingArmies)
|  55|    |-	{
|    |  55|+	
|  56|  56| 		for (let ally in attackingArmies[enemy])
|  57|  57| 		{
|  58|  58| 			if (this.attackedAllies[ally] === undefined)
|  59|  59| 				this.attackedAllies[ally] = 0;
|  60|  60| 			this.attackedAllies[ally] += 1;
|  61|  61| 		}
|  62|    |-	}
|    |  62|+	
|  63|  63| 	this.checkEnemyArmies(gameState);
|  64|  64| 	this.checkEnemyUnits(gameState);
|  65|  65| 	this.assignDefenders(gameState);
|    | [NORMAL] ESLintBear (curly):
|    | Unnecessary { after 'if' condition.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/defenseManager.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/defenseManager.js
|  70|  70| m.DefenseManager.prototype.makeIntoArmy = function(gameState, entityID, type = "default")
|  71|  71| {
|  72|  72| 	if (type == "default")
|  73|    |-	{
|    |  73|+	
|  74|  74| 		// Try to add it to an existing army.
|  75|  75| 		for (let army of this.armies)
|  76|  76| 			if (army.getType() == type && army.addFoe(gameState, entityID))
|  77|  77| 				return;	// over
|  78|    |-	}
|    |  78|+	
|  79|  79| 
|  80|  80| 	// Create a new army for it.
|  81|  81| 	let army = new m.DefenseArmy(gameState, [entityID], type);
|    | [NORMAL] ESLintBear (curly):
|    | Unnecessary { after 'if' condition.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/defenseManager.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/defenseManager.js
| 179| 179| 		if (territoryOwner != PlayerID && this.attackedAllies[territoryOwner] &&
| 180| 180| 		                                  this.attackedAllies[territoryOwner] > 1 &&
| 181| 181| 		                                  this.GetCooperationLevel(territoryOwner) > 0.7)
| 182|    |-		{
|    | 182|+		
| 183| 183| 			for (let building of gameState.getAllyStructures(territoryOwner).values())
| 184| 184| 			{
| 185| 185| 				if (building.foundationProgress() == 0 ||
| 188| 188| 				if (!this.territoryMap.isBlinking(building.position()))
| 189| 189| 					return true;
| 190| 190| 			}
| 191|    |-		}
|    | 191|+		
| 192| 192| 
| 193| 193| 		// Update the number of enemies attacking this ally
| 194| 194| 		let enemy = entity.owner();
|    | [NORMAL] ESLintBear (curly):
|    | Unnecessary { after 'if' condition.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/defenseManager.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/defenseManager.js
| 211| 211| 	if (i == PlayerID)
| 212| 212| 	{
| 213| 213| 		if (!this.armies.length)
| 214|    |-		{
|    | 214|+		
| 215| 215| 			// check if we can recover capture points from any of our notdecaying structures
| 216| 216| 			for (let ent of gameState.getOwnStructures().values())
| 217| 217| 			{
| 229| 229| 				this.makeIntoArmy(gameState, ent.id(), "capturing");
| 230| 230| 				break;
| 231| 231| 			}
| 232|    |-		}
|    | 232|+		
| 233| 233| 		return;
| 234| 234| 	}
| 235| 235| 	else if (!gameState.isPlayerEnemy(i))
|    | [NORMAL] ESLintBear (curly):
|    | Unnecessary { after 'if' condition.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/defenseManager.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/defenseManager.js
| 328| 328| 		if (!gameState.isPlayerEnemy(owner))
| 329| 329| 		{
| 330| 330| 			if (gameState.isPlayerMutualAlly(owner))
| 331|    |-			{
|    | 331|+			
| 332| 332| 				// update the number of enemies attacking this ally
| 333| 333| 				for (let id of army.foeEntities)
| 334| 334| 				{
| 343| 343| 					this.attackingArmies[enemy][owner] += 1;
| 344| 344| 					break;
| 345| 345| 				}
| 346|    |-			}
|    | 346|+			
| 347| 347| 			continue;
| 348| 348| 		}
| 349| 349| 		else if (owner != 0)   // enemy army back in its territory
|    | [NORMAL] ESLintBear (no-extra-semi):
|    | Unnecessary semicolon.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/defenseManager.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/defenseManager.js
| 450| 450| 			});
| 451| 451| 			if (!canAttack)
| 452| 452| 				return;
| 453|    |-		};
|    | 453|+		}
| 454| 454| 
| 455| 455| 		if (ent.getMetadata(PlayerID, "plan") !== undefined && ent.getMetadata(PlayerID, "plan") != -1)
| 456| 456| 		{
|    | [NORMAL] ESLintBear (curly):
|    | Unnecessary { after 'for-of'.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/defenseManager.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/defenseManager.js
| 542| 542| 		army.checkEvents(gameState, events);
| 543| 543| 
| 544| 544| 	for (let evt of events.OwnershipChanged)   // capture events
| 545|    |-	{
|    | 545|+	
| 546| 546| 		if (gameState.isPlayerMutualAlly(evt.from) && evt.to > 0)
| 547| 547| 		{
| 548| 548| 			let ent = gameState.getEntityById(evt.entity);
| 549| 549| 			if (ent && ent.hasClass("CivCentre")) // one of our cc has been captured
| 550| 550| 				gameState.ai.HQ.attackManager.switchDefenseToAttack(gameState, ent, { "range": 150 });
| 551| 551| 		}
| 552|    |-	}
|    | 552|+	
| 553| 553| 
| 554| 554| 	let allAttacked = {};
| 555| 555| 	for (let evt of events.Attacked)
|    | [NORMAL] ESLintBear (curly):
|    | Unnecessary { after 'if' condition.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/defenseManager.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/defenseManager.js
| 564| 564| 		let attacker = gameState.getEntityById(evt.attacker);
| 565| 565| 		if (attacker && gameState.isEntityOwn(attacker) && gameState.isEntityEnemy(target) && !attacker.hasClass("Ship") &&
| 566| 566| 		   (!target.hasClass("Structure") || target.attackRange("Ranged")))
| 567|    |-		{
|    | 567|+		
| 568| 568| 			// If enemies are in range of one of our defensive structures, garrison it for arrow multiplier
| 569| 569| 			// (enemy non-defensive structure are not considered to stay in sync with garrisonManager)
| 570| 570| 			if (attacker.position() && attacker.isGarrisonHolder() && attacker.getArrowMultiplier() &&
| 571| 571| 			    (target.owner() != 0 || !target.hasClass("Unit") ||
| 572| 572| 			     target.unitAIState() && target.unitAIState().split(".")[1] == "COMBAT"))
| 573| 573| 				this.garrisonUnitsInside(gameState, attacker, { "attacker": target });
| 574|    |-		}
|    | 574|+		
| 575| 575| 
| 576| 576| 		if (!gameState.isEntityOwn(target))
| 577| 577| 			continue;
|    | [NORMAL] ESLintBear (curly):
|    | Unnecessary { after 'if' condition.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/defenseManager.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/defenseManager.js
| 769| 769| 	let typeGarrison = data.type || "protection";
| 770| 770| 	let allowMelee = gameState.ai.HQ.garrisonManager.allowMelee(target);
| 771| 771| 	if (allowMelee === undefined)
| 772|    |-	{
|    | 772|+	
| 773| 773| 		// Should be kept in sync with garrisonManager to avoid garrisoning-ungarrisoning some units
| 774| 774| 		if (data.attacker)
| 775| 775| 			allowMelee = data.attacker.hasClass("Structure") ? data.attacker.attackRange("Ranged") : !m.isSiegeUnit(data.attacker);
| 776| 776| 		else
| 777| 777| 			allowMelee = true;
| 778|    |-	}
|    | 778|+	
| 779| 779| 	let units = gameState.getOwnUnits().filter(ent => {
| 780| 780| 		if (!ent.position())
| 781| 781| 			return false;

binaries/data/mods/public/simulation/ai/petra/defenseManager.js
| 970| }(PETRA);
|    | [MAJOR] ESLintBear (no-use-before-define):
|    | 'PETRA' was used before it was defined.

binaries/data/mods/public/simulation/ai/petra/defenseManager.js
| 453| »   »   };
|    | [NORMAL] JSHintBear:
|    | Unnecessary semicolon.
|    | [NORMAL] ESLintBear (curly):
|    | Unnecessary { after 'if' condition.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
|  69|  69| 	this.rallyPoint = rallyPoint;
|  70|  70| 	this.overseas = 0;
|  71|  71| 	if (gameState.ai.HQ.navalMap)
|  72|    |-	{
|    |  72|+	
|  73|  73| 		for (let structure of gameState.getEnemyStructures().values())
|  74|  74| 		{
|  75|  75| 			if (this.target && structure.id() != this.target.id())
| 101| 101| 				gameState.ai.HQ.navalManager.setMinimalTransportShips(gameState, sea, 1);
| 102| 102| 			}
| 103| 103| 		}
| 104|    |-	}
|    | 104|+	
| 105| 105| 	this.paused = false;
| 106| 106| 	this.maxCompletingTime = 0;
| 107| 107| 
|    | [NORMAL] ESLintBear (no-multi-spaces):
|    | Multiple spaces found before '='.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
| 139| 139| 	{
| 140| 140| 		priority = 90;
| 141| 141| 		// basically we want a mix of citizen soldiers so our barracks have a purpose, and champion units.
| 142|    |-		this.unitStat.RangedInfantry    = { "priority": 0.7, "minSize": 5, "targetSize": 20, "batchSize": 5, "classes": ["Infantry", "Ranged", "CitizenSoldier"],
|    | 142|+		this.unitStat.RangedInfantry = { "priority": 0.7, "minSize": 5, "targetSize": 20, "batchSize": 5, "classes": ["Infantry", "Ranged", "CitizenSoldier"],
| 143| 143| 			"interests": [["strength", 3]] };
| 144| 144| 		this.unitStat.MeleeInfantry     = { "priority": 0.7, "minSize": 5, "targetSize": 20, "batchSize": 5, "classes": ["Infantry", "Melee", "CitizenSoldier"],
| 145| 145| 			"interests": [["strength", 3]] };
|    | [NORMAL] ESLintBear (no-multi-spaces):
|    | Multiple spaces found before '='.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
| 141| 141| 		// basically we want a mix of citizen soldiers so our barracks have a purpose, and champion units.
| 142| 142| 		this.unitStat.RangedInfantry    = { "priority": 0.7, "minSize": 5, "targetSize": 20, "batchSize": 5, "classes": ["Infantry", "Ranged", "CitizenSoldier"],
| 143| 143| 			"interests": [["strength", 3]] };
| 144|    |-		this.unitStat.MeleeInfantry     = { "priority": 0.7, "minSize": 5, "targetSize": 20, "batchSize": 5, "classes": ["Infantry", "Melee", "CitizenSoldier"],
|    | 144|+		this.unitStat.MeleeInfantry = { "priority": 0.7, "minSize": 5, "targetSize": 20, "batchSize": 5, "classes": ["Infantry", "Melee", "CitizenSoldier"],
| 145| 145| 			"interests": [["strength", 3]] };
| 146| 146| 		this.unitStat.ChampRangedInfantry = { "priority": 1, "minSize": 3, "targetSize": 18, "batchSize": 3, "classes": ["Infantry", "Ranged", "Champion"],
| 147| 147| 			"interests": [["strength", 3]] };
|    | [NORMAL] ESLintBear (no-multi-spaces):
|    | Multiple spaces found before '='.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
| 145| 145| 			"interests": [["strength", 3]] };
| 146| 146| 		this.unitStat.ChampRangedInfantry = { "priority": 1, "minSize": 3, "targetSize": 18, "batchSize": 3, "classes": ["Infantry", "Ranged", "Champion"],
| 147| 147| 			"interests": [["strength", 3]] };
| 148|    |-		this.unitStat.ChampMeleeInfantry  = { "priority": 1, "minSize": 3, "targetSize": 18, "batchSize": 3, "classes": ["Infantry", "Melee", "Champion"],
|    | 148|+		this.unitStat.ChampMeleeInfantry = { "priority": 1, "minSize": 3, "targetSize": 18, "batchSize": 3, "classes": ["Infantry", "Melee", "Champion"],
| 149| 149| 			"interests": [["strength", 3]] };
| 150| 150| 		this.unitStat.RangedCavalry     = { "priority": 0.7, "minSize": 4, "targetSize": 20, "batchSize": 4, "classes": ["Cavalry", "Ranged", "CitizenSoldier"],
| 151| 151| 			"interests": [["strength", 2]] };
|    | [NORMAL] ESLintBear (no-multi-spaces):
|    | Multiple spaces found before '='.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
| 147| 147| 			"interests": [["strength", 3]] };
| 148| 148| 		this.unitStat.ChampMeleeInfantry  = { "priority": 1, "minSize": 3, "targetSize": 18, "batchSize": 3, "classes": ["Infantry", "Melee", "Champion"],
| 149| 149| 			"interests": [["strength", 3]] };
| 150|    |-		this.unitStat.RangedCavalry     = { "priority": 0.7, "minSize": 4, "targetSize": 20, "batchSize": 4, "classes": ["Cavalry", "Ranged", "CitizenSoldier"],
|    | 150|+		this.unitStat.RangedCavalry = { "priority": 0.7, "minSize": 4, "targetSize": 20, "batchSize": 4, "classes": ["Cavalry", "Ranged", "CitizenSoldier"],
| 151| 151| 			"interests": [["strength", 2]] };
| 152| 152| 		this.unitStat.MeleeCavalry      = { "priority": 0.7, "minSize": 4, "targetSize": 20, "batchSize": 4, "classes": ["Cavalry", "Melee", "CitizenSoldier"],
| 153| 153| 			"interests": [["strength", 2]] };
|    | [NORMAL] ESLintBear (no-multi-spaces):
|    | Multiple spaces found before '='.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
| 149| 149| 			"interests": [["strength", 3]] };
| 150| 150| 		this.unitStat.RangedCavalry     = { "priority": 0.7, "minSize": 4, "targetSize": 20, "batchSize": 4, "classes": ["Cavalry", "Ranged", "CitizenSoldier"],
| 151| 151| 			"interests": [["strength", 2]] };
| 152|    |-		this.unitStat.MeleeCavalry      = { "priority": 0.7, "minSize": 4, "targetSize": 20, "batchSize": 4, "classes": ["Cavalry", "Melee", "CitizenSoldier"],
|    | 152|+		this.unitStat.MeleeCavalry = { "priority": 0.7, "minSize": 4, "targetSize": 20, "batchSize": 4, "classes": ["Cavalry", "Melee", "CitizenSoldier"],
| 153| 153| 			"interests": [["strength", 2]] };
| 154| 154| 		this.unitStat.ChampRangedCavalry  = { "priority": 1, "minSize": 3, "targetSize": 15, "batchSize": 3, "classes": ["Cavalry", "Ranged", "Champion"],
| 155| 155| 			"interests": [["strength", 3]] };
|    | [NORMAL] ESLintBear (no-multi-spaces):
|    | Multiple spaces found before '='.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
| 151| 151| 			"interests": [["strength", 2]] };
| 152| 152| 		this.unitStat.MeleeCavalry      = { "priority": 0.7, "minSize": 4, "targetSize": 20, "batchSize": 4, "classes": ["Cavalry", "Melee", "CitizenSoldier"],
| 153| 153| 			"interests": [["strength", 2]] };
| 154|    |-		this.unitStat.ChampRangedCavalry  = { "priority": 1, "minSize": 3, "targetSize": 15, "batchSize": 3, "classes": ["Cavalry", "Ranged", "Champion"],
|    | 154|+		this.unitStat.ChampRangedCavalry = { "priority": 1, "minSize": 3, "targetSize": 15, "batchSize": 3, "classes": ["Cavalry", "Ranged", "Champion"],
| 155| 155| 			"interests": [["strength", 3]] };
| 156| 156| 		this.unitStat.ChampMeleeCavalry   = { "priority": 1, "minSize": 3, "targetSize": 15, "batchSize": 3, "classes": ["Cavalry", "Melee", "Champion"],
| 157| 157| 			"interests": [["strength", 2]] };
|    | [NORMAL] ESLintBear (no-multi-spaces):
|    | Multiple spaces found before '='.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
| 153| 153| 			"interests": [["strength", 2]] };
| 154| 154| 		this.unitStat.ChampRangedCavalry  = { "priority": 1, "minSize": 3, "targetSize": 15, "batchSize": 3, "classes": ["Cavalry", "Ranged", "Champion"],
| 155| 155| 			"interests": [["strength", 3]] };
| 156|    |-		this.unitStat.ChampMeleeCavalry   = { "priority": 1, "minSize": 3, "targetSize": 15, "batchSize": 3, "classes": ["Cavalry", "Melee", "Champion"],
|    | 156|+		this.unitStat.ChampMeleeCavalry = { "priority": 1, "minSize": 3, "targetSize": 15, "batchSize": 3, "classes": ["Cavalry", "Melee", "Champion"],
| 157| 157| 			"interests": [["strength", 2]] };
| 158| 158| 		this.unitStat.Hero                = { "priority": 1, "minSize": 0, "targetSize":  1, "batchSize": 1, "classes": ["Hero"],
| 159| 159| 			"interests": [["strength", 2]] };
|    | [NORMAL] ESLintBear (no-multi-spaces):
|    | Multiple spaces found before '='.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
| 155| 155| 			"interests": [["strength", 3]] };
| 156| 156| 		this.unitStat.ChampMeleeCavalry   = { "priority": 1, "minSize": 3, "targetSize": 15, "batchSize": 3, "classes": ["Cavalry", "Melee", "Champion"],
| 157| 157| 			"interests": [["strength", 2]] };
| 158|    |-		this.unitStat.Hero                = { "priority": 1, "minSize": 0, "targetSize":  1, "batchSize": 1, "classes": ["Hero"],
|    | 158|+		this.unitStat.Hero = { "priority": 1, "minSize": 0, "targetSize":  1, "batchSize": 1, "classes": ["Hero"],
| 159| 159| 			"interests": [["strength", 2]] };
| 160| 160| 		this.neededShips = 5;
| 161| 161| 	}
|    | [NORMAL] ESLintBear (key-spacing):
|    | Extra space before value for key 'targetSize'.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
| 155| 155| 			"interests": [["strength", 3]] };
| 156| 156| 		this.unitStat.ChampMeleeCavalry   = { "priority": 1, "minSize": 3, "targetSize": 15, "batchSize": 3, "classes": ["Cavalry", "Melee", "Champion"],
| 157| 157| 			"interests": [["strength", 2]] };
| 158|    |-		this.unitStat.Hero                = { "priority": 1, "minSize": 0, "targetSize":  1, "batchSize": 1, "classes": ["Hero"],
|    | 158|+		this.unitStat.Hero                = { "priority": 1, "minSize": 0, "targetSize": 1, "batchSize": 1, "classes": ["Hero"],
| 159| 159| 			"interests": [["strength", 2]] };
| 160| 160| 		this.neededShips = 5;
| 161| 161| 	}
|    | [NORMAL] ESLintBear (no-multi-spaces):
|    | Multiple spaces found before '='.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
| 164| 164| 		priority = 70;
| 165| 165| 		this.unitStat.RangedInfantry = { "priority": 1, "minSize": 6, "targetSize": 16, "batchSize": 3, "classes": ["Infantry", "Ranged"],
| 166| 166| 			"interests": [["canGather", 1], ["strength", 1.6], ["costsResource", 0.3, "stone"], ["costsResource", 0.3, "metal"]] };
| 167|    |-		this.unitStat.MeleeInfantry  = { "priority": 1, "minSize": 6, "targetSize": 16, "batchSize": 3, "classes": ["Infantry", "Melee"],
|    | 167|+		this.unitStat.MeleeInfantry = { "priority": 1, "minSize": 6, "targetSize": 16, "batchSize": 3, "classes": ["Infantry", "Melee"],
| 168| 168| 			"interests": [["canGather", 1], ["strength", 1.6], ["costsResource", 0.3, "stone"], ["costsResource", 0.3, "metal"]] };
| 169| 169| 		this.unitStat.Cavalry = { "priority": 1, "minSize": 2, "targetSize": 6, "batchSize": 2, "classes": ["Cavalry", "CitizenSoldier"],
| 170| 170| 			"interests": [["strength", 1]] };
|    | [NORMAL] ESLintBear (curly):
|    | Unnecessary { after 'if' condition.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
| 399| 399| 	// the completing step is used to return resources and regroup the units
| 400| 400| 	// so we check that we have no more forced order before starting the attack
| 401| 401| 	if (this.state == "completing")
| 402|    |-	{
|    | 402|+	
| 403| 403| 		// if our target was destroyed, go back to "unexecuted" state
| 404| 404| 		if (this.targetPlayer === undefined || !this.target || !gameState.getEntityById(this.target.id()))
| 405| 405| 		{
| 416| 416| 				return 1;
| 417| 417| 			return 2;
| 418| 418| 		}
| 419|    |-	}
|    | 419|+	
| 420| 420| 
| 421| 421| 	if (this.Config.debug > 3 && gameState.ai.playedTurn % 50 === 0)
| 422| 422| 		this.debugAttack();
|    | [NORMAL] ESLintBear (curly):
|    | Unnecessary { after 'for-of'.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
| 525| 525| 
| 526| 526| 	// Remove those units which were in a temporary bombing attack
| 527| 527| 	for (let unitIds of gameState.ai.HQ.attackManager.bombingAttacks.values())
| 528|    |-	{
|    | 528|+	
| 529| 529| 		for (let entId of unitIds.values())
| 530| 530| 		{
| 531| 531| 			let ent = gameState.getEntityById(entId);
| 534| 534| 			unitIds.delete(entId);
| 535| 535| 			ent.stopMoving();
| 536| 536| 		}
| 537|    |-	}
|    | 537|+	
| 538| 538| 
| 539| 539| 	let rallyPoint = this.rallyPoint;
| 540| 540| 	let rallyIndex = gameState.ai.accessibility.getAccessValue(rallyPoint);
|    | [NORMAL] ESLintBear (curly):
|    | Unnecessary { after 'else'.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
| 872| 872| 			targets.addEnt(ent);
| 873| 873| 	}
| 874| 874| 	else
| 875|    |-	{
|    | 875|+	
| 876| 876| 		if (this.type == "Raid")
| 877| 877| 			targets = this.raidTargetFinder(gameState);
| 878| 878| 		else if (this.type == "Rush" || this.type == "Attack")
| 883| 883| 		}
| 884| 884| 		else
| 885| 885| 			targets = this.defaultTargetFinder(gameState, this.targetPlayer);
| 886|    |-	}
|    | 886|+	
| 887| 887| 	if (!targets.hasEntities())
| 888| 888| 		return undefined;
| 889| 889| 
|    | [NORMAL] ESLintBear (indent):
|    | Expected indentation of 2 tabs but found 0.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
|1143|1143| 
|1144|1144| 	if (blocker && blocker.hasClass("StoneWall"))
|1145|1145| 	{
|1146|    |-/*		if (this.hasSiegeUnits())
|    |1146|+		/*		if (this.hasSiegeUnits())
|1147|1147| 		{ */
|1148|1148| 			this.isBlocked = true;
|1149|1149| 			return blocker;
|    | [NORMAL] ESLintBear (indent):
|    | Expected indentation of 2 tabs but found 3.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
|1145|1145| 	{
|1146|1146| /*		if (this.hasSiegeUnits())
|1147|1147| 		{ */
|1148|    |-			this.isBlocked = true;
|    |1148|+		this.isBlocked = true;
|1149|1149| 			return blocker;
|1150|1150| /*		}
|1151|1151| 		return undefined; */
|    | [NORMAL] ESLintBear (indent):
|    | Expected indentation of 2 tabs but found 3.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
|1146|1146| /*		if (this.hasSiegeUnits())
|1147|1147| 		{ */
|1148|1148| 			this.isBlocked = true;
|1149|    |-			return blocker;
|    |1149|+		return blocker;
|1150|1150| /*		}
|1151|1151| 		return undefined; */
|1152|1152| 	}
|    | [NORMAL] ESLintBear (indent):
|    | Expected indentation of 2 tabs but found 0.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
|1147|1147| 		{ */
|1148|1148| 			this.isBlocked = true;
|1149|1149| 			return blocker;
|1150|    |-/*		}
|    |1150|+		/*		}
|1151|1151| 		return undefined; */
|1152|1152| 	}
|1153|1153| 	else if (blocker)
|    | [NORMAL] ESLintBear (curly):
|    | Unnecessary { after 'else'.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
|1347|1347| 				}
|1348|1348| 			}
|1349|1349| 			else
|1350|    |-			{
|    |1350|+			
|1351|1351| 				if (this.isBlocked && !ourUnit.hasClass("Ranged") && attacker.hasClass("Ranged"))
|1352|1352| 				{
|1353|1353| 					// do not react if our melee units are attacked by ranged one and we are blocked by walls
|1405|1405| 						ourUnit.setMetadata(PlayerID, "lastAttackPlanUpdateTime", time);
|1406|1406| 					}
|1407|1407| 				}
|1408|    |-			}
|    |1408|+			
|1409|1409| 		}
|1410|1410| 
|1411|1411| 		let enemyUnits = gameState.getEnemyUnits(this.targetPlayer);
|    | [NORMAL] ESLintBear (curly):
|    | Unnecessary { after 'if' condition.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
|1349|1349| 			else
|1350|1350| 			{
|1351|1351| 				if (this.isBlocked && !ourUnit.hasClass("Ranged") && attacker.hasClass("Ranged"))
|1352|    |-				{
|    |1352|+				
|1353|1353| 					// do not react if our melee units are attacked by ranged one and we are blocked by walls
|1354|1354| 					// TODO check that the attacker is from behind the wall
|1355|1355| 					continue;
|1356|    |-				}
|    |1356|+				
|1357|1357| 				else if (m.isSiegeUnit(attacker))
|1358|1358| 				{	// if our unit is attacked by a siege unit, we'll send some melee units to help it.
|1359|1359| 					let collec = this.unitCollection.filter(API3.Filters.byClass("Melee")).filterNearest(ourUnit.position(), 5);
|    | [NORMAL] ESLintBear (curly):
|    | Unnecessary { after 'if' condition.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
|1394|1394| 							continue;
|1395|1395| 						let target = gameState.getEntityById(orderData[0].target);
|1396|1396| 						if (target && !target.hasClass("Structure") && !target.hasClass("Support"))
|1397|    |-						{
|    |1397|+						
|1398|1398| 							if (!target.hasClass("Ranged") || !attacker.hasClass("Melee"))
|1399|1399| 								continue;
|1400|    |-						}
|    |1400|+						
|1401|1401| 					}
|1402|1402| 					if (ourUnit.canAttackTarget(attacker))
|1403|1403| 					{
|    | [NORMAL] ESLintBear (curly):
|    | Unnecessary { after 'if' condition.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
|1425|1425| 			if (!target || target.hasClass("Structure"))
|1426|1426| 				continue;
|1427|1427| 			if (!(targetId in unitTargets))
|1428|    |-			{
|    |1428|+			
|1429|1429| 				if (m.isSiegeUnit(target) || target.hasClass("Hero"))
|1430|1430| 					unitTargets[targetId] = -8;
|1431|1431| 				else if (target.hasClass("Champion") || target.hasClass("Ship"))
|1432|1432| 					unitTargets[targetId] = -5;
|1433|1433| 				else
|1434|1434| 					unitTargets[targetId] = -3;
|1435|    |-			}
|    |1435|+			
|1436|1436| 			++unitTargets[targetId];
|1437|1437| 		}
|1438|1438| 		let veto = {};
|    | [NORMAL] ESLintBear (curly):
|    | Unnecessary { after 'else'.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
|1445|1445| 		if (this.type == "Rush")
|1446|1446| 			targetClassesUnit = { "attack": ["Unit", "Structure"], "avoid": ["Palisade", "StoneWall", "Tower", "Fortress"], "vetoEntities": veto };
|1447|1447| 		else
|1448|    |-		{
|    |1448|+		
|1449|1449| 			if (this.target.hasClass("Fortress"))
|1450|1450| 				targetClassesUnit = { "attack": ["Unit", "Structure"], "avoid": ["Palisade", "StoneWall"], "vetoEntities": veto };
|1451|1451| 			else if (this.target.hasClass("Palisade") || this.target.hasClass("StoneWall"))
|1452|1452| 				targetClassesUnit = { "attack": ["Unit", "Structure"], "avoid": ["Fortress"], "vetoEntities": veto };
|1453|1453| 			else
|1454|1454| 				targetClassesUnit = { "attack": ["Unit", "Structure"], "avoid": ["Palisade", "StoneWall", "Fortress"], "vetoEntities": veto };
|1455|    |-		}
|    |1455|+		
|1456|1456| 		if (this.target.hasClass("Structure"))
|1457|1457| 			targetClassesSiege = { "attack": ["Structure"], "avoid": [], "vetoEntities": veto };
|1458|1458| 		else
|    | [NORMAL] ESLintBear (curly):
|    | Unnecessary { after 'if' condition.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
|1536|1536| 			let range = 60;
|1537|1537| 			let attackTypes = ent.attackTypes();
|1538|1538| 			if (this.isBlocked)
|1539|    |-			{
|    |1539|+			
|1540|1540| 				if (attackTypes && attackTypes.indexOf("Ranged") !== -1)
|1541|1541| 					range = ent.attackRange("Ranged").max;
|1542|1542| 				else if (attackTypes && attackTypes.indexOf("Melee") !== -1)
|1543|1543| 					range = ent.attackRange("Melee").max;
|1544|1544| 				else
|1545|1545| 					range = 10;
|1546|    |-			}
|    |1546|+			
|1547|1547| 			else if (attackTypes && attackTypes.indexOf("Ranged") !== -1)
|1548|1548| 				range = 30 + ent.attackRange("Ranged").max;
|1549|1549| 			else if (ent.hasClass("Cavalry"))
|    | [NORMAL] ESLintBear (operator-assignment):
|    | Assignment can be replaced with operator assignment.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
|1548|1548| 				range = 30 + ent.attackRange("Ranged").max;
|1549|1549| 			else if (ent.hasClass("Cavalry"))
|1550|1550| 				range += 30;
|1551|    |-			range = range * range;
|    |1551|+			range *= range;
|1552|1552| 			let entAccess = m.getLandAccess(gameState, ent);
|1553|1553| 			// Checking for gates if we're a siege unit.
|1554|1554| 			if (siegeUnit)
|    | [NORMAL] ESLintBear (curly):
|    | Unnecessary { after 'else'.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
|1592|1592| 					}
|1593|1593| 				}
|1594|1594| 				else
|1595|    |-				{
|    |1595|+				
|1596|1596| 					if (!ent.hasClass("Ranged"))
|1597|1597| 					{
|1598|1598| 						let targetClasses = { "attack": targetClassesSiege.attack, "avoid": targetClassesSiege.avoid.concat("Ship"), "vetoEntities": veto };
|1600|1600| 					}
|1601|1601| 					else
|1602|1602| 						ent.attackMove(this.targetPos[0], this.targetPos[1], targetClassesSiege);
|1603|    |-				}
|    |1603|+				
|1604|1604| 			}
|1605|1605| 			else
|1606|1606| 			{
|    | [NORMAL] ESLintBear (curly):
|    | Unnecessary { after 'if' condition.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
|1654|1654| 				{
|1655|1655| 					let targetClasses = targetClassesUnit;
|1656|1656| 					if (maybeUpdate && ent.unitAIState() === "INDIVIDUAL.COMBAT.APPROACHING")	// we may be blocked by walls, attack everything
|1657|    |-					{
|    |1657|+					
|1658|1658| 						if (!ent.hasClass("Ranged") && !ent.hasClass("Ship"))
|1659|1659| 							targetClasses = { "attack": ["Unit", "Structure"], "avoid": ["Ship"], "vetoEntities": veto };
|1660|1660| 						else
|1661|1661| 							targetClasses = { "attack": ["Unit", "Structure"], "vetoEntities": veto };
|1662|    |-					}
|    |1662|+					
|1663|1663| 					else if (!ent.hasClass("Ranged") && !ent.hasClass("Ship"))
|1664|1664| 						targetClasses = { "attack": targetClassesUnit.attack, "avoid": targetClassesUnit.avoid.concat("Ship"), "vetoEntities": veto };
|1665|1665| 					ent.attackMove(this.targetPos[0], this.targetPos[1], targetClasses);
|    | [NORMAL] ESLintBear (curly):
|    | Unnecessary { after 'if' condition.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
|1802|1802| 	}
|1803|1803| 	// Are we arrived at destination ?
|1804|1804| 	if (attackedNB > 1 && (attackedUnitNB || this.hasSiegeUnits()))
|1805|    |-	{
|    |1805|+	
|1806|1806| 		if (gameState.ai.HQ.territoryMap.getOwner(this.position) === this.targetPlayer || attackedNB > 3)
|1807|1807| 		{
|1808|1808| 			this.state = "arrived";
|1809|1809| 			return true;
|1810|1810| 		}
|1811|    |-	}
|    |1811|+	
|1812|1812| 
|1813|1813| 	// basically haven't moved an inch: very likely stuck)
|1814|1814| 	if (API3.SquareVectorDistance(this.position, this.position5TurnsAgo) < 10 && this.path.length > 0 && gameState.ai.playedTurn % 5 === 0)
|    | [NORMAL] ESLintBear (curly):
|    | Unnecessary { after 'for-in'.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
|1928|1928| 			// Check if we could help any current attack
|1929|1929| 			let attackManager = gameState.ai.HQ.attackManager;
|1930|1930| 			for (let attackType in attackManager.startedAttacks)
|1931|    |-			{
|    |1931|+			
|1932|1932| 				for (let attack of attackManager.startedAttacks[attackType])
|1933|1933| 				{
|1934|1934| 					if (attack.name == this.name)
|1947|1947| 					this.targetPos = this.target.position();
|1948|1948| 					return true;
|1949|1949| 				}
|1950|    |-			}
|    |1950|+			
|1951|1951| 
|1952|1952| 			// If not, let's look for another enemy
|1953|1953| 			if (!this.target)

binaries/data/mods/public/simulation/ai/petra/attackPlan.js
|2180| }(PETRA);
|    | [MAJOR] ESLintBear (no-use-before-define):
|    | 'PETRA' was used before it was defined.
|    | [NORMAL] ESLintBear (curly):
|    | Unnecessary { after 'for-in'.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackManager.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackManager.js
|  62|  62| 		targetPlayer = evt.player;
|  63|  63| 		let available = 0;
|  64|  64| 		for (let attackType in this.upcomingAttacks)
|  65|    |-		{
|    |  65|+		
|  66|  66| 			for (let attack of this.upcomingAttacks[attackType])
|  67|  67| 			{
|  68|  68| 				if (attack.state === "completing")
|  79|  79| 				if (attack.unitCollection.length > 2)
|  80|  80| 					available += attack.unitCollection.length;
|  81|  81| 			}
|  82|    |-		}
|    |  82|+		
|  83|  83| 
|  84|  84| 		if (available > 12)	// launch the attack immediately
|  85|  85| 		{
|    | [NORMAL] ESLintBear (curly):
|    | Unnecessary { after 'for-in'.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackManager.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackManager.js
|  84|  84| 		if (available > 12)	// launch the attack immediately
|  85|  85| 		{
|  86|  86| 			for (let attackType in this.upcomingAttacks)
|  87|    |-			{
|    |  87|+			
|  88|  88| 				for (let attack of this.upcomingAttacks[attackType])
|  89|  89| 				{
|  90|  90| 					if (attack.state === "completing" ||
|  94|  94| 					attack.forceStart();
|  95|  95| 					attack.requested = true;
|  96|  96| 				}
|  97|    |-			}
|    |  97|+			
|  98|  98| 			answer = "join";
|  99|  99| 		}
| 100| 100| 		else if (other !== undefined)
|    | [NORMAL] ESLintBear (curly):
|    | Unnecessary { after 'for-of'.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackManager.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackManager.js
| 105| 105| 		m.chatAnswerRequestAttack(gameState, targetPlayer, answer, other);
| 106| 106| 
| 107| 107| 	for (let evt of events.EntityRenamed)	// take care of packing units in bombing attacks
| 108|    |-	{
|    | 108|+	
| 109| 109| 		for (let [targetId, unitIds] of this.bombingAttacks)
| 110| 110| 		{
| 111| 111| 			if (targetId == evt.entity)
| 119| 119| 				unitIds.delete(evt.entity);
| 120| 120| 			}
| 121| 121| 		}
| 122|    |-	}
|    | 122|+	
| 123| 123| };
| 124| 124| 
| 125| 125| /**
|    | [NORMAL] ESLintBear (curly):
|    | Unnecessary { after 'for-of'.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackManager.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackManager.js
| 107| 107| 	for (let evt of events.EntityRenamed)	// take care of packing units in bombing attacks
| 108| 108| 	{
| 109| 109| 		for (let [targetId, unitIds] of this.bombingAttacks)
| 110|    |-		{
|    | 110|+		
| 111| 111| 			if (targetId == evt.entity)
| 112| 112| 			{
| 113| 113| 				this.bombingAttacks.set(evt.newentity, unitIds);
| 118| 118| 				unitIds.add(evt.newentity);
| 119| 119| 				unitIds.delete(evt.entity);
| 120| 120| 			}
| 121|    |-		}
|    | 121|+		
| 122| 122| 	}
| 123| 123| };
| 124| 124| 
|    | [NORMAL] ESLintBear (curly):
|    | Unnecessary { after 'if' condition.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackManager.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackManager.js
| 189| 189| 			let x;
| 190| 190| 			let z;
| 191| 191| 			if (struct.hasClass("Field"))
| 192|    |-			{
|    | 192|+			
| 193| 193| 				if (!struct.resourceSupplyNumGatherers() ||
| 194| 194| 				    !gameState.isPlayerEnemy(gameState.ai.HQ.territoryMap.getOwner(structPos)))
| 195| 195| 					continue;
| 196|    |-			}
|    | 196|+			
| 197| 197| 			let dist = API3.VectorDistance(entPos, structPos);
| 198| 198| 			if (dist > range)
| 199| 199| 			{
|    | [NORMAL] ESLintBear (curly):
|    | Unnecessary { after 'for-in'.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackManager.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackManager.js
| 257| 257| 
| 258| 258| 	let unexecutedAttacks = { "Rush": 0, "Raid": 0, "Attack": 0, "HugeAttack": 0 };
| 259| 259| 	for (let attackType in this.upcomingAttacks)
| 260|    |-	{
|    | 260|+	
| 261| 261| 		for (let i = 0; i < this.upcomingAttacks[attackType].length; ++i)
| 262| 262| 		{
| 263| 263| 			let attack = this.upcomingAttacks[attackType][i];
| 296| 296| 				this.upcomingAttacks[attackType].splice(i--, 1);
| 297| 297| 			}
| 298| 298| 		}
| 299|    |-	}
|    | 299|+	
| 300| 300| 
| 301| 301| 	for (let attackType in this.startedAttacks)
| 302| 302| 	{
|    | [NORMAL] ESLintBear (curly):
|    | Unnecessary { after 'for-in'.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackManager.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackManager.js
| 299| 299| 	}
| 300| 300| 
| 301| 301| 	for (let attackType in this.startedAttacks)
| 302|    |-	{
|    | 302|+	
| 303| 303| 		for (let i = 0; i < this.startedAttacks[attackType].length; ++i)
| 304| 304| 		{
| 305| 305| 			let attack = this.startedAttacks[attackType][i];
| 316| 316| 				this.startedAttacks[attackType].splice(i--, 1);
| 317| 317| 			}
| 318| 318| 		}
| 319|    |-	}
|    | 319|+	
| 320| 320| 
| 321| 321| 	// creating plans after updating because an aborted plan might be reused in that case.
| 322| 322| 
|    | [NORMAL] ESLintBear (curly):
|    | Unnecessary { after 'if' condition.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackManager.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackManager.js
| 342| 342| 	else if (unexecutedAttacks.Attack == 0 && unexecutedAttacks.HugeAttack == 0 &&
| 343| 343| 		this.startedAttacks.Attack.length + this.startedAttacks.HugeAttack.length < Math.min(2, 1 + Math.round(gameState.getPopulationMax()/100)) &&
| 344| 344| 		(this.startedAttacks.Attack.length + this.startedAttacks.HugeAttack.length == 0 || gameState.getPopulationMax() - gameState.getPopulation() > 12))
| 345|    |-	{
|    | 345|+	
| 346| 346| 		if (barracksNb >= 1 && (gameState.currentPhase() > 1 || gameState.isResearching(gameState.getPhaseName(2))) ||
| 347| 347| 			!gameState.ai.HQ.baseManagers[1])	// if we have no base ... nothing else to do than attack
| 348| 348| 		{
| 360| 360| 			}
| 361| 361| 			this.attackNumber++;
| 362| 362| 		}
| 363|    |-	}
|    | 363|+	
| 364| 364| 
| 365| 365| 	if (unexecutedAttacks.Raid === 0 && gameState.ai.HQ.defenseManager.targetList.length)
| 366| 366| 	{
|    | [NORMAL] ESLintBear (curly):
|    | Unnecessary { after 'for-in'.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackManager.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackManager.js
| 386| 386| m.AttackManager.prototype.getPlan = function(planName)
| 387| 387| {
| 388| 388| 	for (let attackType in this.upcomingAttacks)
| 389|    |-	{
|    | 389|+	
| 390| 390| 		for (let attack of this.upcomingAttacks[attackType])
| 391| 391| 			if (attack.getName() == planName)
| 392| 392| 				return attack;
| 393|    |-	}
|    | 393|+	
| 394| 394| 	for (let attackType in this.startedAttacks)
| 395| 395| 	{
| 396| 396| 		for (let attack of this.startedAttacks[attackType])
|    | [NORMAL] ESLintBear (curly):
|    | Unnecessary { after 'for-in'.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackManager.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackManager.js
| 392| 392| 				return attack;
| 393| 393| 	}
| 394| 394| 	for (let attackType in this.startedAttacks)
| 395|    |-	{
|    | 395|+	
| 396| 396| 		for (let attack of this.startedAttacks[attackType])
| 397| 397| 			if (attack.getName() == planName)
| 398| 398| 				return attack;
| 399|    |-	}
|    | 399|+	
| 400| 400| 	return undefined;
| 401| 401| };
| 402| 402| 
|    | [NORMAL] ESLintBear (curly):
|    | Unnecessary { after 'if' condition.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackManager.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/ai/petra/attackManager.js
| 468| 468| 		veto[i] = true;
| 469| 469| 	// No rush if enemy too well defended (i.e. iberians)
| 470| 470| 	if (attack.type == "Rush")
| 471|    |-	{
|    | 471|+	
| 472| 472| 		for (let i = 1; i < gameState.sharedScript.playersData.length; ++i)
| 473| 473| 		{
| 474| 474| 			if (!gameState.isPlayerEnemy(i) || veto[i])
| 482| 482| 			if (enemyDefense > 6)
| 483| 483| 				veto[i] = true;
| 484| 484| 		}
| 485|    |-	}
|    | 485|+	
| 486| 486| 
| 487| 487| 	// then if not a huge attack, continue attacking our previous target as long as it has some entities,
| 488| 488| 	// otherwise target the most accessible one

binaries/data/mods/public/simulation/ai/petra/attackManager.js
| 808| }(PETRA);
|    | [MAJOR] ESLintBear (no-use-before-define):
|    | 'PETRA' was used before it was defined.
|    | [NORMAL] ESLintBear (spaced-comment):
|    | Expected space or tab after '//' in comment.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/Attack.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/Attack.js
| 545| 545| 
| 546| 546| 		let horizSpeed = +this.template[type].Projectile.Speed;
| 547| 547| 		let gravity = +this.template[type].Projectile.Gravity;
| 548|    |-		//horizSpeed /= 2; gravity /= 2; // slow it down for testing
|    | 548|+		// horizSpeed /= 2; gravity /= 2; // slow it down for testing
| 549| 549| 
| 550| 550| 		let cmpPosition = Engine.QueryInterface(this.entity, IID_Position);
| 551| 551| 		if (!cmpPosition || !cmpPosition.IsInWorld())
|    | [NORMAL] ESLintBear (no-trailing-spaces):
|    | Trailing spaces not allowed.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/Attack.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/Attack.js
| 592| 592| 		// TODO: Use unit rotation to implement x/z offsets.
| 593| 593| 		let deltaLaunchPoint = new Vector3D(0, this.template[type].Projectile.LaunchPoint["@y"], 0.0);
| 594| 594| 		let launchPoint = Vector3D.add(selfPosition, deltaLaunchPoint);
| 595|    |-		
|    | 595|+
| 596| 596| 		let cmpVisual = Engine.QueryInterface(this.entity, IID_Visual);
| 597| 597| 		if (cmpVisual)
| 598| 598| 		{
|    | [NORMAL] ESLintBear (curly):
|    | Unnecessary { after 'else'.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/Attack.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/Attack.js
| 664| 664| 			});
| 665| 665| 	}
| 666| 666| 	else
| 667|    |-	{
|    | 667|+	
| 668| 668| 		// Melee attack - hurt the target immediately
| 669| 669| 		cmpDamage.CauseDamage({
| 670| 670| 			"strengths": this.GetAttackStrengths(type),
| 674| 674| 			"type": type,
| 675| 675| 			"attackerOwner": attackerOwner
| 676| 676| 		});
| 677|    |-	}
|    | 677|+	
| 678| 678| };
| 679| 679| 
| 680| 680| /**

binaries/data/mods/public/simulation/components/Attack.js
| 535| ·»   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
| 639| »   »   cmpTimer.SetTimeout(SYSTEM_ENTITY,·IID_Damage,·"MissileHit",·timeToTarget·*·1000·+·+this.template[type].Delay,·data);
|    | [NORMAL] JSHintBear:
|    | Confusing plusses.
Executing section cli...

Link to build: https://jenkins.wildfiregames.com/job/differential/1951/display/redirect

So this diff has mostly become "UnitAI refactor for choosing the best attack" - which probably ought to be a separate diff :P, but is a valuable improvement.

The question of invulnerability, unlike infinite damage, does have some sense: a unit invulnerable to some damage won't take any, whereas one with 9999 might. So that is somewhat of a conceptual difference.

However, in practice, a value of 1000 for armour, given our exponential armour, would actually multiply damage by 10^-46. A value of "10000" gets converted by Javascript to actual 0, making the "infinite" armour part of this diff rather redundant. We should probably just decide on a cutoff point in the GUI.

Freagarach added a comment.EditedJul 18 2019, 4:44 PM

If restricted classes would be also applicable to damage (also splash/death/trample) immunity would not be necessary, I guess.

[EDIT]: Seems to me we need a definition of restrictedClasses ;)

[EDIT]: Seems to me we need a definition of restrictedClasses ;)

No, not really; e.g. spearmen inflict both hack and pierce damage; they should be able to attack structures even if structures would be immune to pierce damage.

Freagarach planned changes to this revision.EditedJul 22 2019, 9:41 AM

Split GetBestAttackAgainst.