Page MenuHomeWildfire Games

Allow enabling default formation / no-formation stances on a command basis
Needs ReviewPublic

Authored by wraitii on May 23 2020, 3:11 PM.
This revision needs review, but there are no reviewers specified.

Details

Reviewers
None
Summary

The numerous fixes to formations in A24 have made them somewhat usable, at least to walk around. Our formations are quite nice for micro and just neat walking around, so it's good.

However, a long-standing issue is that once active, you have them for everything, including orders like Gather or Construct, which don't make a ton of sense for formations (even if they will work once D2763 & D2702 are committed).

This diff lets the GUI provide default formation settings for some orders and can force "no formations" for other orders.

You can test the feel by having a few units walking around and ordering them to walk, then gather.

I think this feels good. It's very similar to Age Of 2-3's system.
IMO if we could merge this in A24 we'd have improved things greatly.


Some possible TODOs:

  • there is no way to turn let units gather in formation for now. It would be nice to make both the default "on" formation and the default "off" configuration moddable (that being said, it's GUI, so it is moddable and MP-compatible).
  • perhaps implement settings for a per-order setup, or at least allow confusing which orders are "with formation/without".
Test Plan

Check out the behaviour, review the code.

To note:

  • If the player forces a (non null) formation on some entities, and then orders a walk, the formation is not overwritten.

Event Timeline

wraitii created this revision.May 23 2020, 3:11 PM
wraitii edited the summary of this revision. (Show Details)

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

Linter detected issues:
Executing section Source...
Executing section JS...
|    | [NORMAL] ESLintBear (key-spacing):
|    | Missing space before value for key 'execute'.
|----|    | /zpool0/trunk/binaries/data/mods/public/gui/session/unit_actions.js
|    |++++| /zpool0/trunk/binaries/data/mods/public/gui/session/unit_actions.js
| 535| 535| 
| 536| 536| 	"cancel-setup-trade-route":
| 537| 537| 	{
| 538|    |-		"execute":function(target, action, selection, queued)
|    | 538|+		"execute": function(target, action, selection, queued)
| 539| 539| 		{
| 540| 540| 			Engine.PostNetworkCommand({
| 541| 541| 				"type": "cancel-setup-trade-route",
|    | [NORMAL] ESLintBear (semi):
|    | Missing semicolon.
|----|    | /zpool0/trunk/binaries/data/mods/public/gui/session/unit_actions.js
|    |++++| /zpool0/trunk/binaries/data/mods/public/gui/session/unit_actions.js
| 580| 580| 				"cursor": "action-cancel-setup-trade-route",
| 581| 581| 				"tooltip": actionInfo.tooltip,
| 582| 582| 				"target": target
| 583|    |-			}
|    | 583|+			};
| 584| 584| 		},
| 585| 585| 		"specificness": 2,
| 586| 586| 	},

binaries/data/mods/public/gui/session/unit_actions.js
| 625| »   »   »   switch·(tradingDetails.type)
|    | [NORMAL] ESLintBear (default-case):
|    | Expected a default case.

binaries/data/mods/public/gui/session/unit_actions.js
| 583| »   »   »   }
|    | [NORMAL] JSHintBear:
|    | Missing semicolon.
|    | [NORMAL] ESLintBear (operator-linebreak):
|    | '&&' should be placed at the end of the line.
|----|    | /zpool0/trunk/binaries/data/mods/public/simulation/helpers/Commands.js
|    |++++| /zpool0/trunk/binaries/data/mods/public/simulation/helpers/Commands.js
| 530| 530| 			if (cmpGarrisonHolder)
| 531| 531| 			{
| 532| 532| 				// Only the owner of the garrisonHolder may unload entities from any owners
| 533|    |-				if (!IsOwnedByPlayer(player, garrisonHolder) && !data.controlAllUnits
| 534|    |-				    && player != +cmd.owner)
|    | 533|+				if (!IsOwnedByPlayer(player, garrisonHolder) && !data.controlAllUnits &&
|    | 534|+				    player != +cmd.owner)
| 535| 535| 						continue;
| 536| 536| 
| 537| 537| 				if (!cmpGarrisonHolder.UnloadTemplate(cmd.template, cmd.owner, cmd.all))
|    | [NORMAL] ESLintBear (indent):
|    | Expected indentation of 5 tabs but found 6.
|----|    | /zpool0/trunk/binaries/data/mods/public/simulation/helpers/Commands.js
|    |++++| /zpool0/trunk/binaries/data/mods/public/simulation/helpers/Commands.js
| 532| 532| 				// Only the owner of the garrisonHolder may unload entities from any owners
| 533| 533| 				if (!IsOwnedByPlayer(player, garrisonHolder) && !data.controlAllUnits
| 534| 534| 				    && player != +cmd.owner)
| 535|    |-						continue;
|    | 535|+					continue;
| 536| 536| 
| 537| 537| 				if (!cmpGarrisonHolder.UnloadTemplate(cmd.template, cmd.owner, cmd.all))
| 538| 538| 					notifyUnloadFailure(player, garrisonHolder);
|    | [NORMAL] ESLintBear (key-spacing):
|    | Extra space after key 'metadata'.
|----|    | /zpool0/trunk/binaries/data/mods/public/simulation/helpers/Commands.js
|    |++++| /zpool0/trunk/binaries/data/mods/public/simulation/helpers/Commands.js
|1149|1149| 
|1150|1150| 	// send Metadata info if any
|1151|1151| 	if (cmd.metadata)
|1152|    |-		Engine.PostMessage(ent, MT_AIMetadata, { "id": ent, "metadata" : cmd.metadata, "owner" : player } );
|    |1152|+		Engine.PostMessage(ent, MT_AIMetadata, { "id": ent, "metadata": cmd.metadata, "owner" : player } );
|1153|1153| 
|1154|1154| 	// Tell the units to start building this new entity
|1155|1155| 	if (cmd.autorepair)
|    | [NORMAL] ESLintBear (key-spacing):
|    | Extra space after key 'owner'.
|----|    | /zpool0/trunk/binaries/data/mods/public/simulation/helpers/Commands.js
|    |++++| /zpool0/trunk/binaries/data/mods/public/simulation/helpers/Commands.js
|1149|1149| 
|1150|1150| 	// send Metadata info if any
|1151|1151| 	if (cmd.metadata)
|1152|    |-		Engine.PostMessage(ent, MT_AIMetadata, { "id": ent, "metadata" : cmd.metadata, "owner" : player } );
|    |1152|+		Engine.PostMessage(ent, MT_AIMetadata, { "id": ent, "metadata" : cmd.metadata, "owner": player } );
|1153|1153| 
|1154|1154| 	// Tell the units to start building this new entity
|1155|1155| 	if (cmd.autorepair)
|    | [NORMAL] ESLintBear (space-in-parens):
|    | There should be no spaces inside this paren.
|----|    | /zpool0/trunk/binaries/data/mods/public/simulation/helpers/Commands.js
|    |++++| /zpool0/trunk/binaries/data/mods/public/simulation/helpers/Commands.js
|1149|1149| 
|1150|1150| 	// send Metadata info if any
|1151|1151| 	if (cmd.metadata)
|1152|    |-		Engine.PostMessage(ent, MT_AIMetadata, { "id": ent, "metadata" : cmd.metadata, "owner" : player } );
|    |1152|+		Engine.PostMessage(ent, MT_AIMetadata, { "id": ent, "metadata" : cmd.metadata, "owner" : player });
|1153|1153| 
|1154|1154| 	// Tell the units to start building this new entity
|1155|1155| 	if (cmd.autorepair)
|    | [NORMAL] ESLintBear (spaced-comment):
|    | Expected space or tab after '//' in comment.
|----|    | /zpool0/trunk/binaries/data/mods/public/simulation/helpers/Commands.js
|    |++++| /zpool0/trunk/binaries/data/mods/public/simulation/helpers/Commands.js
|1257|1257| 		}
|1258|1258| 
|1259|1259| 		lastTowerControlGroup = cmpSnappedStartObstruction.GetControlGroup();
|1260|    |-		//warn("setting lastTowerControlGroup to control group of start snapped entity " + cmd.startSnappedEntity + ": " + lastTowerControlGroup);
|    |1260|+		// warn("setting lastTowerControlGroup to control group of start snapped entity " + cmd.startSnappedEntity + ": " + lastTowerControlGroup);
|1261|1261| 	}
|1262|1262| 
|1263|1263| 	var i = 0;
|    | [NORMAL] ESLintBear (spaced-comment):
|    | Expected space or tab after '//' in comment.
|----|    | /zpool0/trunk/binaries/data/mods/public/simulation/helpers/Commands.js
|    |++++| /zpool0/trunk/binaries/data/mods/public/simulation/helpers/Commands.js
|1321|1321| 
|1322|1322| 				if (i > 0)
|1323|1323| 				{
|1324|    |-					//warn("   updating previous wall piece's secondary control group to " + newTowerControlGroup);
|    |1324|+					// warn("   updating previous wall piece's secondary control group to " + newTowerControlGroup);
|1325|1325| 					var cmpPreviousObstruction = Engine.QueryInterface(pieces[i-1].ent, IID_Obstruction);
|1326|1326| 					// TODO: ensure that cmpPreviousObstruction exists
|1327|1327| 					// TODO: ensure that the previous obstruction does not yet have a secondary control group set
|    | [NORMAL] ESLintBear (no-undef-init):
|    | It's not necessary to initialize 'closeClusters' to undefined.
|----|    | /zpool0/trunk/binaries/data/mods/public/simulation/helpers/Commands.js
|    |++++| /zpool0/trunk/binaries/data/mods/public/simulation/helpers/Commands.js
|1564|1564| 	while (clusters.length > 1)
|1565|1565| 	{
|1566|1566| 		// search two clusters that are closer than the required distance
|1567|    |-		let closeClusters = undefined;
|    |1567|+		let closeClusters;
|1568|1568| 
|1569|1569| 		for (let i = matrix.length - 1; i >= 0 && !closeClusters; --i)
|1570|1570| 			for (let j = i - 1; j >= 0 && !closeClusters; --j)
|    | [NORMAL] ESLintBear (comma-spacing):
|    | A space is required after ','.
|----|    | /zpool0/trunk/binaries/data/mods/public/simulation/helpers/Commands.js
|    |++++| /zpool0/trunk/binaries/data/mods/public/simulation/helpers/Commands.js
|1569|1569| 		for (let i = matrix.length - 1; i >= 0 && !closeClusters; --i)
|1570|1570| 			for (let j = i - 1; j >= 0 && !closeClusters; --j)
|1571|1571| 				if (matrix[i][j] < distSq)
|1572|    |-					closeClusters = [i,j];
|    |1572|+					closeClusters = [i, j];
|1573|1573| 
|1574|1574| 		// if no more close clusters found, just return all found clusters so far
|1575|1575| 		if (!closeClusters)
|    | [NORMAL] ESLintBear (comma-spacing):
|    | A space is required after ','.
|----|    | /zpool0/trunk/binaries/data/mods/public/simulation/helpers/Commands.js
|    |++++| /zpool0/trunk/binaries/data/mods/public/simulation/helpers/Commands.js
|1593|1593| 		}
|1594|1594| 		// remove the rows and columns in the matrix for the merged clusters,
|1595|1595| 		// and the clusters themselves from the cluster list
|1596|    |-		clusters.splice(closeClusters[0],1);
|    |1596|+		clusters.splice(closeClusters[0], 1);
|1597|1597| 		clusters.splice(closeClusters[1],1);
|1598|1598| 		matrix.splice(closeClusters[0],1);
|1599|1599| 		matrix.splice(closeClusters[1],1);
|    | [NORMAL] ESLintBear (comma-spacing):
|    | A space is required after ','.
|----|    | /zpool0/trunk/binaries/data/mods/public/simulation/helpers/Commands.js
|    |++++| /zpool0/trunk/binaries/data/mods/public/simulation/helpers/Commands.js
|1594|1594| 		// remove the rows and columns in the matrix for the merged clusters,
|1595|1595| 		// and the clusters themselves from the cluster list
|1596|1596| 		clusters.splice(closeClusters[0],1);
|1597|    |-		clusters.splice(closeClusters[1],1);
|    |1597|+		clusters.splice(closeClusters[1], 1);
|1598|1598| 		matrix.splice(closeClusters[0],1);
|1599|1599| 		matrix.splice(closeClusters[1],1);
|1600|1600| 		for (let i = 0; i < matrix.length; ++i)
|    | [NORMAL] ESLintBear (comma-spacing):
|    | A space is required after ','.
|----|    | /zpool0/trunk/binaries/data/mods/public/simulation/helpers/Commands.js
|    |++++| /zpool0/trunk/binaries/data/mods/public/simulation/helpers/Commands.js
|1595|1595| 		// and the clusters themselves from the cluster list
|1596|1596| 		clusters.splice(closeClusters[0],1);
|1597|1597| 		clusters.splice(closeClusters[1],1);
|1598|    |-		matrix.splice(closeClusters[0],1);
|    |1598|+		matrix.splice(closeClusters[0], 1);
|1599|1599| 		matrix.splice(closeClusters[1],1);
|1600|1600| 		for (let i = 0; i < matrix.length; ++i)
|1601|1601| 		{
|    | [NORMAL] ESLintBear (comma-spacing):
|    | A space is required after ','.
|----|    | /zpool0/trunk/binaries/data/mods/public/simulation/helpers/Commands.js
|    |++++| /zpool0/trunk/binaries/data/mods/public/simulation/helpers/Commands.js
|1596|1596| 		clusters.splice(closeClusters[0],1);
|1597|1597| 		clusters.splice(closeClusters[1],1);
|1598|1598| 		matrix.splice(closeClusters[0],1);
|1599|    |-		matrix.splice(closeClusters[1],1);
|    |1599|+		matrix.splice(closeClusters[1], 1);
|1600|1600| 		for (let i = 0; i < matrix.length; ++i)
|1601|1601| 		{
|1602|1602| 			if (matrix[i].length > closeClusters[0])
|    | [NORMAL] ESLintBear (comma-spacing):
|    | A space is required after ','.
|----|    | /zpool0/trunk/binaries/data/mods/public/simulation/helpers/Commands.js
|    |++++| /zpool0/trunk/binaries/data/mods/public/simulation/helpers/Commands.js
|1600|1600| 		for (let i = 0; i < matrix.length; ++i)
|1601|1601| 		{
|1602|1602| 			if (matrix[i].length > closeClusters[0])
|1603|    |-				matrix[i].splice(closeClusters[0],1);
|    |1603|+				matrix[i].splice(closeClusters[0], 1);
|1604|1604| 			if (matrix[i].length > closeClusters[1])
|1605|1605| 				matrix[i].splice(closeClusters[1],1);
|1606|1606| 		}
|    | [NORMAL] ESLintBear (comma-spacing):
|    | A space is required after ','.
|----|    | /zpool0/trunk/binaries/data/mods/public/simulation/helpers/Commands.js
|    |++++| /zpool0/trunk/binaries/data/mods/public/simulation/helpers/Commands.js
|1602|1602| 			if (matrix[i].length > closeClusters[0])
|1603|1603| 				matrix[i].splice(closeClusters[0],1);
|1604|1604| 			if (matrix[i].length > closeClusters[1])
|1605|    |-				matrix[i].splice(closeClusters[1],1);
|    |1605|+				matrix[i].splice(closeClusters[1], 1);
|1606|1606| 		}
|1607|1607| 		// add a new row of distances to the matrix and the new cluster
|1608|1608| 		clusters.push(newCluster);

binaries/data/mods/public/simulation/helpers/Commands.js
|  46| »   if·(g_Commands[cmd.type])
|    | [MAJOR] ESLintBear (no-use-before-define):
|    | 'g_Commands' was used before it was defined.

binaries/data/mods/public/simulation/helpers/Commands.js
|  50| »   »   g_Commands[cmd.type](player,·cmd,·data);
|    | [MAJOR] ESLintBear (no-use-before-define):
|    | 'g_Commands' was used before it was defined.

binaries/data/mods/public/simulation/helpers/Commands.js
| 791| »   »   let·ent·=·pickRandom(cmpRangeManager.GetEntitiesByPlayer(cmd.player).filter(ent·=>·{
|    | [NORMAL] ESLintBear (no-shadow):
|    | 'ent' is already declared in the upper scope.

binaries/data/mods/public/simulation/helpers/Commands.js
|1280| ····»   »   »   error("[TryConstructWall]·Expected·last·tower·control·group·to·be·available,·none·found·(1st·pass,·iteration·"·+·i·+·")");
|    | [NORMAL] ESLintBear (no-mixed-spaces-and-tabs):
|    | Mixed spaces and tabs.

binaries/data/mods/public/simulation/helpers/Commands.js
|1281| ····»   »   »   break;
|    | [NORMAL] ESLintBear (no-mixed-spaces-and-tabs):
|    | Mixed spaces and tabs.

binaries/data/mods/public/simulation/helpers/Commands.js
|  56| var·g_Commands·=·{
|    | [NORMAL] JSHintBear:
|    | 'g_Commands' was used before it was defined.

binaries/data/mods/public/simulation/helpers/Commands.js
| 534| »   »   »   »   ····&&·player·!=·+cmd.owner)
|    | [NORMAL] JSHintBear:
|    | Misleading line break before '&&'; readers may interpret this as an expression boundary.

binaries/data/mods/public/simulation/helpers/Commands.js
| 729| »   »   »   »   var·cmpGUIInterface·=·Engine.QueryInterface(SYSTEM_ENTITY,·IID_GuiInterface);
|    | [NORMAL] JSHintBear:
|    | 'cmpGUIInterface' is already defined.

binaries/data/mods/public/simulation/helpers/Commands.js
| 954| »   »   for·(var·i·=·0;·i·<·length;·++i)
|    | [NORMAL] JSHintBear:
|    | 'i' is already defined.

binaries/data/mods/public/simulation/helpers/Commands.js
| 967| »   »   var·count·=·0;
|    | [NORMAL] JSHintBear:
|    | 'count' is already defined.

binaries/data/mods/public/simulation/helpers/Commands.js
|1114| »   »   var·cmpGuiInterface·=·Engine.QueryInterface(SYSTEM_ENTITY,·IID_GuiInterface);
|    | [NORMAL] JSHintBear:
|    | 'cmpGuiInterface' is already defined.

binaries/data/mods/public/simulation/helpers/Commands.js
|1366| »   »   var·piece·=·pieces[j];
|    | [NORMAL] JSHintBear:
|    | 'piece' is already defined.

binaries/data/mods/public/simulation/helpers/Commands.js
|1449| »   »   var·cmpUnitAI·=·Engine.QueryInterface(ent,·IID_UnitAI);
|    | [NORMAL] JSHintBear:
|    | 'cmpUnitAI' is already defined.

binaries/data/mods/public/simulation/helpers/Commands.js
|1524| »   »   »   var·cmpFormation·=·Engine.QueryInterface(formationEnt,·IID_Formation);
|    | [NORMAL] JSHintBear:
|    | 'cmpFormation' is already defined.

binaries/data/mods/public/simulation/helpers/Commands.js
|1567| »   »   let·closeClusters·=·undefined;
|    | [NORMAL] JSHintBear:
|    | It's not necessary to initialize 'closeClusters' to 'undefined'.
Executing section cli...

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

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

Link to build: https://jenkins.wildfiregames.com/job/macos-differential/805/display/redirect

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

Link to build: https://jenkins.wildfiregames.com/job/macos-differential/816/display/redirect

wraitii updated this revision to Diff 12234.EditedJun 9 2020, 7:08 PM
wraitii retitled this revision from [proof of concept] Allow enabling default formation / no-formation stances on a command basis to [proof of concept] Allow enabling default formation / no-formation stances on a command basis.

Add a simple indicator for the default formation (using the upgrade icon for now).
Let the user pick the default formation by right-clicking on a icon.

Add default behaviours for all orders.

Edit > removing the proof-of-concept tag as this is functional enough IMO and very very nice. A complete refactoring of the selection panels isn't really manageable here.

I would like to let the player choose the "null" formation or do something on a per-order basis, but I need more GUI work for that.

wraitii retitled this revision from [proof of concept] Allow enabling default formation / no-formation stances on a command basis to Allow enabling default formation / no-formation stances on a command basis.Jun 9 2020, 7:11 PM
wraitii edited the summary of this revision. (Show Details)
wraitii edited the test plan for this revision. (Show Details)
Vulcan added a comment.Jun 9 2020, 7:12 PM

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

Linter detected issues:
Executing section Source...
Executing section JS...
|    | [NORMAL] ESLintBear (no-multi-spaces):
|    | Multiple spaces found before 'state'.
|----|    | /zpool0/trunk/binaries/data/mods/public/gui/session/selection_panels.js
|    |++++| /zpool0/trunk/binaries/data/mods/public/gui/session/selection_panels.js
| 298| 298| 		if (!g_AvailableFormations.has(unitEntStates[0].player))
| 299| 299| 			g_AvailableFormations.set(unitEntStates[0].player, Engine.GuiInterfaceCall("GetAvailableFormations", unitEntStates[0].player));
| 300| 300| 
| 301|    |-		return g_AvailableFormations.get(unitEntStates[0].player).filter(formation => unitEntStates.some(state => !!state.identity &&  state.identity.formations.indexOf(formation) != -1));
|    | 301|+		return g_AvailableFormations.get(unitEntStates[0].player).filter(formation => unitEntStates.some(state => !!state.identity && state.identity.formations.indexOf(formation) != -1));
| 302| 302| 	},
| 303| 303| 	"setupButton": function(data)
| 304| 304| 	{
|    | [NORMAL] ESLintBear (space-before-function-paren):
|    | Unexpected space before function parentheses.
|----|    | /zpool0/trunk/binaries/data/mods/public/gui/session/selection_panels.js
|    |++++| /zpool0/trunk/binaries/data/mods/public/gui/session/selection_panels.js
| 768| 768| 				addResearchToQueue(data.item.researchFacilityId, t);
| 769| 769| 			})(tech);
| 770| 770| 
| 771|    |-			button.onPressRight = (t => function () {
|    | 771|+			button.onPressRight = (t => function() {
| 772| 772| 				showTemplateDetails(
| 773| 773| 					t,
| 774| 774| 					GetTemplateData(data.unitEntStates.find(state => state.id == data.item.researchFacilityId).template).nativeCiv);

binaries/data/mods/public/gui/session/selection_panels.js
|  50| »   »   »   switch·(data.item)
|    | [NORMAL] ESLintBear (default-case):
|    | Expected a default case.

binaries/data/mods/public/gui/session/selection_panels.js
|  61| »   »   switch·(data.item)
|    | [NORMAL] ESLintBear (default-case):
|    | Expected a default case.

binaries/data/mods/public/gui/session/selection_panels.js
| 736| »   »   »   »   »   »   switch·(entity.check)
|    | [NORMAL] ESLintBear (default-case):
|    | Expected a default case.
|    | [NORMAL] ESLintBear (key-spacing):
|    | Missing space before value for key 'execute'.
|----|    | /zpool0/trunk/binaries/data/mods/public/gui/session/unit_actions.js
|    |++++| /zpool0/trunk/binaries/data/mods/public/gui/session/unit_actions.js
| 542| 542| 
| 543| 543| 	"cancel-setup-trade-route":
| 544| 544| 	{
| 545|    |-		"execute":function(target, action, selection, queued)
|    | 545|+		"execute": function(target, action, selection, queued)
| 546| 546| 		{
| 547| 547| 			Engine.PostNetworkCommand({
| 548| 548| 				"type": "cancel-setup-trade-route",
|    | [NORMAL] ESLintBear (semi):
|    | Missing semicolon.
|----|    | /zpool0/trunk/binaries/data/mods/public/gui/session/unit_actions.js
|    |++++| /zpool0/trunk/binaries/data/mods/public/gui/session/unit_actions.js
| 587| 587| 				"cursor": "action-cancel-setup-trade-route",
| 588| 588| 				"tooltip": actionInfo.tooltip,
| 589| 589| 				"target": target
| 590|    |-			}
|    | 590|+			};
| 591| 591| 		},
| 592| 592| 		"specificness": 2,
| 593| 593| 	},

binaries/data/mods/public/gui/session/unit_actions.js
| 633| »   »   »   switch·(tradingDetails.type)
|    | [NORMAL] ESLintBear (default-case):
|    | Expected a default case.

binaries/data/mods/public/gui/session/unit_actions.js
| 590| »   »   »   }
|    | [NORMAL] JSHintBear:
|    | Missing semicolon.
|    | [NORMAL] ESLintBear (operator-linebreak):
|    | '&&' should be placed at the end of the line.
|----|    | /zpool0/trunk/binaries/data/mods/public/simulation/helpers/Commands.js
|    |++++| /zpool0/trunk/binaries/data/mods/public/simulation/helpers/Commands.js
| 530| 530| 			if (cmpGarrisonHolder)
| 531| 531| 			{
| 532| 532| 				// Only the owner of the garrisonHolder may unload entities from any owners
| 533|    |-				if (!IsOwnedByPlayer(player, garrisonHolder) && !data.controlAllUnits
| 534|    |-				    && player != +cmd.owner)
|    | 533|+				if (!IsOwnedByPlayer(player, garrisonHolder) && !data.controlAllUnits &&
|    | 534|+				    player != +cmd.owner)
| 535| 535| 						continue;
| 536| 536| 
| 537| 537| 				if (!cmpGarrisonHolder.UnloadTemplate(cmd.template, cmd.owner, cmd.all))
|    | [NORMAL] ESLintBear (indent):
|    | Expected indentation of 5 tabs but found 6.
|----|    | /zpool0/trunk/binaries/data/mods/public/simulation/helpers/Commands.js
|    |++++| /zpool0/trunk/binaries/data/mods/public/simulation/helpers/Commands.js
| 532| 532| 				// Only the owner of the garrisonHolder may unload entities from any owners
| 533| 533| 				if (!IsOwnedByPlayer(player, garrisonHolder) && !data.controlAllUnits
| 534| 534| 				    && player != +cmd.owner)
| 535|    |-						continue;
|    | 535|+					continue;
| 536| 536| 
| 537| 537| 				if (!cmpGarrisonHolder.UnloadTemplate(cmd.template, cmd.owner, cmd.all))
| 538| 538| 					notifyUnloadFailure(player, garrisonHolder);
|    | [NORMAL] ESLintBear (key-spacing):
|    | Extra space after key 'metadata'.
|----|    | /zpool0/trunk/binaries/data/mods/public/simulation/helpers/Commands.js
|    |++++| /zpool0/trunk/binaries/data/mods/public/simulation/helpers/Commands.js
|1149|1149| 
|1150|1150| 	// send Metadata info if any
|1151|1151| 	if (cmd.metadata)
|1152|    |-		Engine.PostMessage(ent, MT_AIMetadata, { "id": ent, "metadata" : cmd.metadata, "owner" : player } );
|    |1152|+		Engine.PostMessage(ent, MT_AIMetadata, { "id": ent, "metadata": cmd.metadata, "owner" : player } );
|1153|1153| 
|1154|1154| 	// Tell the units to start building this new entity
|1155|1155| 	if (cmd.autorepair)
|    | [NORMAL] ESLintBear (key-spacing):
|    | Extra space after key 'owner'.
|----|    | /zpool0/trunk/binaries/data/mods/public/simulation/helpers/Commands.js
|    |++++| /zpool0/trunk/binaries/data/mods/public/simulation/helpers/Commands.js
|1149|1149| 
|1150|1150| 	// send Metadata info if any
|1151|1151| 	if (cmd.metadata)
|1152|    |-		Engine.PostMessage(ent, MT_AIMetadata, { "id": ent, "metadata" : cmd.metadata, "owner" : player } );
|    |1152|+		Engine.PostMessage(ent, MT_AIMetadata, { "id": ent, "metadata" : cmd.metadata, "owner": player } );
|1153|1153| 
|1154|1154| 	// Tell the units to start building this new entity
|1155|1155| 	if (cmd.autorepair)
|    | [NORMAL] ESLintBear (space-in-parens):
|    | There should be no spaces inside this paren.
|----|    | /zpool0/trunk/binaries/data/mods/public/simulation/helpers/Commands.js
|    |++++| /zpool0/trunk/binaries/data/mods/public/simulation/helpers/Commands.js
|1149|1149| 
|1150|1150| 	// send Metadata info if any
|1151|1151| 	if (cmd.metadata)
|1152|    |-		Engine.PostMessage(ent, MT_AIMetadata, { "id": ent, "metadata" : cmd.metadata, "owner" : player } );
|    |1152|+		Engine.PostMessage(ent, MT_AIMetadata, { "id": ent, "metadata" : cmd.metadata, "owner" : player });
|1153|1153| 
|1154|1154| 	// Tell the units to start building this new entity
|1155|1155| 	if (cmd.autorepair)
|    | [NORMAL] ESLintBear (spaced-comment):
|    | Expected space or tab after '//' in comment.
|----|    | /zpool0/trunk/binaries/data/mods/public/simulation/helpers/Commands.js
|    |++++| /zpool0/trunk/binaries/data/mods/public/simulation/helpers/Commands.js
|1257|1257| 		}
|1258|1258| 
|1259|1259| 		lastTowerControlGroup = cmpSnappedStartObstruction.GetControlGroup();
|1260|    |-		//warn("setting lastTowerControlGroup to control group of start snapped entity " + cmd.startSnappedEntity + ": " + lastTowerControlGroup);
|    |1260|+		// warn("setting lastTowerControlGroup to control group of start snapped entity " + cmd.startSnappedEntity + ": " + lastTowerControlGroup);
|1261|1261| 	}
|1262|1262| 
|1263|1263| 	var i = 0;
|    | [NORMAL] ESLintBear (spaced-comment):
|    | Expected space or tab after '//' in comment.
|----|    | /zpool0/trunk/binaries/data/mods/public/simulation/helpers/Commands.js
|    |++++| /zpool0/trunk/binaries/data/mods/public/simulation/helpers/Commands.js
|1321|1321| 
|1322|1322| 				if (i > 0)
|1323|1323| 				{
|1324|    |-					//warn("   updating previous wall piece's secondary control group to " + newTowerControlGroup);
|    |1324|+					// warn("   updating previous wall piece's secondary control group to " + newTowerControlGroup);
|1325|1325| 					var cmpPreviousObstruction = Engine.QueryInterface(pieces[i-1].ent, IID_Obstruction);
|1326|1326| 					// TODO: ensure that cmpPreviousObstruction exists
|1327|1327| 					// TODO: ensure that the previous obstruction does not yet have a secondary control group set
|    | [NORMAL] ESLintBear (no-undef-init):
|    | It's not necessary to initialize 'closeClusters' to undefined.
|----|    | /zpool0/trunk/binaries/data/mods/public/simulation/helpers/Commands.js
|    |++++| /zpool0/trunk/binaries/data/mods/public/simulation/helpers/Commands.js
|1564|1564| 	while (clusters.length > 1)
|1565|1565| 	{
|1566|1566| 		// search two clusters that are closer than the required distance
|1567|    |-		let closeClusters = undefined;
|    |1567|+		let closeClusters;
|1568|1568| 
|1569|1569| 		for (let i = matrix.length - 1; i >= 0 && !closeClusters; --i)
|1570|1570| 			for (let j = i - 1; j >= 0 && !closeClusters; --j)
|    | [NORMAL] ESLintBear (comma-spacing):
|    | A space is required after ','.
|----|    | /zpool0/trunk/binaries/data/mods/public/simulation/helpers/Commands.js
|    |++++| /zpool0/trunk/binaries/data/mods/public/simulation/helpers/Commands.js
|1569|1569| 		for (let i = matrix.length - 1; i >= 0 && !closeClusters; --i)
|1570|1570| 			for (let j = i - 1; j >= 0 && !closeClusters; --j)
|1571|1571| 				if (matrix[i][j] < distSq)
|1572|    |-					closeClusters = [i,j];
|    |1572|+					closeClusters = [i, j];
|1573|1573| 
|1574|1574| 		// if no more close clusters found, just return all found clusters so far
|1575|1575| 		if (!closeClusters)
|    | [NORMAL] ESLintBear (comma-spacing):
|    | A space is required after ','.
|----|    | /zpool0/trunk/binaries/data/mods/public/simulation/helpers/Commands.js
|    |++++| /zpool0/trunk/binaries/data/mods/public/simulation/helpers/Commands.js
|1593|1593| 		}
|1594|1594| 		// remove the rows and columns in the matrix for the merged clusters,
|1595|1595| 		// and the clusters themselves from the cluster list
|1596|    |-		clusters.splice(closeClusters[0],1);
|    |1596|+		clusters.splice(closeClusters[0], 1);
|1597|1597| 		clusters.splice(closeClusters[1],1);
|1598|1598| 		matrix.splice(closeClusters[0],1);
|1599|1599| 		matrix.splice(closeClusters[1],1);
|    | [NORMAL] ESLintBear (comma-spacing):
|    | A space is required after ','.
|----|    | /zpool0/trunk/binaries/data/mods/public/simulation/helpers/Commands.js
|    |++++| /zpool0/trunk/binaries/data/mods/public/simulation/helpers/Commands.js
|1594|1594| 		// remove the rows and columns in the matrix for the merged clusters,
|1595|1595| 		// and the clusters themselves from the cluster list
|1596|1596| 		clusters.splice(closeClusters[0],1);
|1597|    |-		clusters.splice(closeClusters[1],1);
|    |1597|+		clusters.splice(closeClusters[1], 1);
|1598|1598| 		matrix.splice(closeClusters[0],1);
|1599|1599| 		matrix.splice(closeClusters[1],1);
|1600|1600| 		for (let i = 0; i < matrix.length; ++i)
|    | [NORMAL] ESLintBear (comma-spacing):
|    | A space is required after ','.
|----|    | /zpool0/trunk/binaries/data/mods/public/simulation/helpers/Commands.js
|    |++++| /zpool0/trunk/binaries/data/mods/public/simulation/helpers/Commands.js
|1595|1595| 		// and the clusters themselves from the cluster list
|1596|1596| 		clusters.splice(closeClusters[0],1);
|1597|1597| 		clusters.splice(closeClusters[1],1);
|1598|    |-		matrix.splice(closeClusters[0],1);
|    |1598|+		matrix.splice(closeClusters[0], 1);
|1599|1599| 		matrix.splice(closeClusters[1],1);
|1600|1600| 		for (let i = 0; i < matrix.length; ++i)
|1601|1601| 		{
|    | [NORMAL] ESLintBear (comma-spacing):
|    | A space is required after ','.
|----|    | /zpool0/trunk/binaries/data/mods/public/simulation/helpers/Commands.js
|    |++++| /zpool0/trunk/binaries/data/mods/public/simulation/helpers/Commands.js
|1596|1596| 		clusters.splice(closeClusters[0],1);
|1597|1597| 		clusters.splice(closeClusters[1],1);
|1598|1598| 		matrix.splice(closeClusters[0],1);
|1599|    |-		matrix.splice(closeClusters[1],1);
|    |1599|+		matrix.splice(closeClusters[1], 1);
|1600|1600| 		for (let i = 0; i < matrix.length; ++i)
|1601|1601| 		{
|1602|1602| 			if (matrix[i].length > closeClusters[0])
|    | [NORMAL] ESLintBear (comma-spacing):
|    | A space is required after ','.
|----|    | /zpool0/trunk/binaries/data/mods/public/simulation/helpers/Commands.js
|    |++++| /zpool0/trunk/binaries/data/mods/public/simulation/helpers/Commands.js
|1600|1600| 		for (let i = 0; i < matrix.length; ++i)
|1601|1601| 		{
|1602|1602| 			if (matrix[i].length > closeClusters[0])
|1603|    |-				matrix[i].splice(closeClusters[0],1);
|    |1603|+				matrix[i].splice(closeClusters[0], 1);
|1604|1604| 			if (matrix[i].length > closeClusters[1])
|1605|1605| 				matrix[i].splice(closeClusters[1],1);
|1606|1606| 		}
|    | [NORMAL] ESLintBear (comma-spacing):
|    | A space is required after ','.
|----|    | /zpool0/trunk/binaries/data/mods/public/simulation/helpers/Commands.js
|    |++++| /zpool0/trunk/binaries/data/mods/public/simulation/helpers/Commands.js
|1602|1602| 			if (matrix[i].length > closeClusters[0])
|1603|1603| 				matrix[i].splice(closeClusters[0],1);
|1604|1604| 			if (matrix[i].length > closeClusters[1])
|1605|    |-				matrix[i].splice(closeClusters[1],1);
|    |1605|+				matrix[i].splice(closeClusters[1], 1);
|1606|1606| 		}
|1607|1607| 		// add a new row of distances to the matrix and the new cluster
|1608|1608| 		clusters.push(newCluster);

binaries/data/mods/public/simulation/helpers/Commands.js
|  46| »   if·(g_Commands[cmd.type])
|    | [MAJOR] ESLintBear (no-use-before-define):
|    | 'g_Commands' was used before it was defined.

binaries/data/mods/public/simulation/helpers/Commands.js
|  50| »   »   g_Commands[cmd.type](player,·cmd,·data);
|    | [MAJOR] ESLintBear (no-use-before-define):
|    | 'g_Commands' was used before it was defined.

binaries/data/mods/public/simulation/helpers/Commands.js
| 791| »   »   let·ent·=·pickRandom(cmpRangeManager.GetEntitiesByPlayer(cmd.player).filter(ent·=>·{
|    | [NORMAL] ESLintBear (no-shadow):
|    | 'ent' is already declared in the upper scope.

binaries/data/mods/public/simulation/helpers/Commands.js
|1280| ····»   »   »   error("[TryConstructWall]·Expected·last·tower·control·group·to·be·available,·none·found·(1st·pass,·iteration·"·+·i·+·")");
|    | [NORMAL] ESLintBear (no-mixed-spaces-and-tabs):
|    | Mixed spaces and tabs.

binaries/data/mods/public/simulation/helpers/Commands.js
|1281| ····»   »   »   break;
|    | [NORMAL] ESLintBear (no-mixed-spaces-and-tabs):
|    | Mixed spaces and tabs.

binaries/data/mods/public/simulation/helpers/Commands.js
|  56| var·g_Commands·=·{
|    | [NORMAL] JSHintBear:
|    | 'g_Commands' was used before it was defined.

binaries/data/mods/public/simulation/helpers/Commands.js
| 534| »   »   »   »   ····&&·player·!=·+cmd.owner)
|    | [NORMAL] JSHintBear:
|    | Misleading line break before '&&'; readers may interpret this as an expression boundary.

binaries/data/mods/public/simulation/helpers/Commands.js
| 729| »   »   »   »   var·cmpGUIInterface·=·Engine.QueryInterface(SYSTEM_ENTITY,·IID_GuiInterface);
|    | [NORMAL] JSHintBear:
|    | 'cmpGUIInterface' is already defined.

binaries/data/mods/public/simulation/helpers/Commands.js
| 954| »   »   for·(var·i·=·0;·i·<·length;·++i)
|    | [NORMAL] JSHintBear:
|    | 'i' is already defined.

binaries/data/mods/public/simulation/helpers/Commands.js
| 967| »   »   var·count·=·0;
|    | [NORMAL] JSHintBear:
|    | 'count' is already defined.

binaries/data/mods/public/simulation/helpers/Commands.js
|1114| »   »   var·cmpGuiInterface·=·Engine.QueryInterface(SYSTEM_ENTITY,·IID_GuiInterface);
|    | [NORMAL] JSHintBear:
|    | 'cmpGuiInterface' is already defined.

binaries/data/mods/public/simulation/helpers/Commands.js
|1366| »   »   var·piece·=·pieces[j];
|    | [NORMAL] JSHintBear:
|    | 'piece' is already defined.

binaries/data/mods/public/simulation/helpers/Commands.js
|1449| »   »   var·cmpUnitAI·=·Engine.QueryInterface(ent,·IID_UnitAI);
|    | [NORMAL] JSHintBear:
|    | 'cmpUnitAI' is already defined.

binaries/data/mods/public/simulation/helpers/Commands.js
|1524| »   »   »   var·cmpFormation·=·Engine.QueryInterface(formationEnt,·IID_Formation);
|    | [NORMAL] JSHintBear:
|    | 'cmpFormation' is already defined.

binaries/data/mods/public/simulation/helpers/Commands.js
|1567| »   »   let·closeClusters·=·undefined;
|    | [NORMAL] JSHintBear:
|    | It's not necessary to initialize 'closeClusters' to 'undefined'.
Executing section cli...

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

Formation behaviour ought to be in UnitAI, one can disband formation temporarily when close to gathering point, perhaps?

The standard formation thing is nice indeed :) However, not fully functional, IMHO. If you have the box as the standard formation, have two formations of lines and move them together, they will fall back to the box, which is unexpected.

binaries/data/mods/public/gui/session/selection_panels_left/formation_panel.xml
8

Name.

wraitii updated this revision to Diff 12466.Sat, Jun 27, 10:31 AM

Formation behaviour ought to be in UnitAI, one can disband formation temporarily when close to gathering point, perhaps?

I would largely disagree on the basis that this would be a complete refactoring and I'm not really planning for that

The standard formation thing is nice indeed :) However, not fully functional, IMHO. If you have the box as the standard formation, have two formations of lines and move them together, they will fall back to the box, which is unexpected.

Fixed

binaries/data/mods/public/gui/session/selection_panels_left/formation_panel.xml
8

I actually can't use another name, there is a lot of hardcoding in the JS here.

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

Linter detected issues:
Executing section Source...
Executing section JS...
|    | [NORMAL] ESLintBear (no-multi-spaces):
|    | Multiple spaces found before 'state'.
|----|    | /zpool0/trunk/binaries/data/mods/public/gui/session/selection_panels.js
|    |++++| /zpool0/trunk/binaries/data/mods/public/gui/session/selection_panels.js
| 298| 298| 		if (!g_AvailableFormations.has(unitEntStates[0].player))
| 299| 299| 			g_AvailableFormations.set(unitEntStates[0].player, Engine.GuiInterfaceCall("GetAvailableFormations", unitEntStates[0].player));
| 300| 300| 
| 301|    |-		return g_AvailableFormations.get(unitEntStates[0].player).filter(formation => unitEntStates.some(state => !!state.identity &&  state.identity.formations.indexOf(formation) != -1));
|    | 301|+		return g_AvailableFormations.get(unitEntStates[0].player).filter(formation => unitEntStates.some(state => !!state.identity && state.identity.formations.indexOf(formation) != -1));
| 302| 302| 	},
| 303| 303| 	"setupButton": function(data)
| 304| 304| 	{
|    | [NORMAL] ESLintBear (space-before-function-paren):
|    | Unexpected space before function parentheses.
|----|    | /zpool0/trunk/binaries/data/mods/public/gui/session/selection_panels.js
|    |++++| /zpool0/trunk/binaries/data/mods/public/gui/session/selection_panels.js
| 768| 768| 				addResearchToQueue(data.item.researchFacilityId, t);
| 769| 769| 			})(tech);
| 770| 770| 
| 771|    |-			button.onPressRight = (t => function () {
|    | 771|+			button.onPressRight = (t => function() {
| 772| 772| 				showTemplateDetails(
| 773| 773| 					t,
| 774| 774| 					GetTemplateData(data.unitEntStates.find(state => state.id == data.item.researchFacilityId).template).nativeCiv);

binaries/data/mods/public/gui/session/selection_panels.js
|  50| »   »   »   switch·(data.item)
|    | [NORMAL] ESLintBear (default-case):
|    | Expected a default case.

binaries/data/mods/public/gui/session/selection_panels.js
|  61| »   »   switch·(data.item)
|    | [NORMAL] ESLintBear (default-case):
|    | Expected a default case.

binaries/data/mods/public/gui/session/selection_panels.js
| 736| »   »   »   »   »   »   switch·(entity.check)
|    | [NORMAL] ESLintBear (default-case):
|    | Expected a default case.
|    | [NORMAL] ESLintBear (key-spacing):
|    | Missing space before value for key 'execute'.
|----|    | /zpool0/trunk/binaries/data/mods/public/gui/session/unit_actions.js
|    |++++| /zpool0/trunk/binaries/data/mods/public/gui/session/unit_actions.js
| 542| 542| 
| 543| 543| 	"cancel-setup-trade-route":
| 544| 544| 	{
| 545|    |-		"execute":function(target, action, selection, queued)
|    | 545|+		"execute": function(target, action, selection, queued)
| 546| 546| 		{
| 547| 547| 			Engine.PostNetworkCommand({
| 548| 548| 				"type": "cancel-setup-trade-route",
|    | [NORMAL] ESLintBear (semi):
|    | Missing semicolon.
|----|    | /zpool0/trunk/binaries/data/mods/public/gui/session/unit_actions.js
|    |++++| /zpool0/trunk/binaries/data/mods/public/gui/session/unit_actions.js
| 587| 587| 				"cursor": "action-cancel-setup-trade-route",
| 588| 588| 				"tooltip": actionInfo.tooltip,
| 589| 589| 				"target": target
| 590|    |-			}
|    | 590|+			};
| 591| 591| 		},
| 592| 592| 		"specificness": 2,
| 593| 593| 	},

binaries/data/mods/public/gui/session/unit_actions.js
| 633| »   »   »   switch·(tradingDetails.type)
|    | [NORMAL] ESLintBear (default-case):
|    | Expected a default case.

binaries/data/mods/public/gui/session/unit_actions.js
| 590| »   »   »   }
|    | [NORMAL] JSHintBear:
|    | Missing semicolon.
|    | [NORMAL] ESLintBear (operator-linebreak):
|    | '&&' should be placed at the end of the line.
|----|    | /zpool0/trunk/binaries/data/mods/public/simulation/helpers/Commands.js
|    |++++| /zpool0/trunk/binaries/data/mods/public/simulation/helpers/Commands.js
| 530| 530| 			if (cmpGarrisonHolder)
| 531| 531| 			{
| 532| 532| 				// Only the owner of the garrisonHolder may unload entities from any owners
| 533|    |-				if (!IsOwnedByPlayer(player, garrisonHolder) && !data.controlAllUnits
| 534|    |-				    && player != +cmd.owner)
|    | 533|+				if (!IsOwnedByPlayer(player, garrisonHolder) && !data.controlAllUnits &&
|    | 534|+				    player != +cmd.owner)
| 535| 535| 						continue;
| 536| 536| 
| 537| 537| 				if (!cmpGarrisonHolder.UnloadTemplate(cmd.template, cmd.owner, cmd.all))
|    | [NORMAL] ESLintBear (indent):
|    | Expected indentation of 5 tabs but found 6.
|----|    | /zpool0/trunk/binaries/data/mods/public/simulation/helpers/Commands.js
|    |++++| /zpool0/trunk/binaries/data/mods/public/simulation/helpers/Commands.js
| 532| 532| 				// Only the owner of the garrisonHolder may unload entities from any owners
| 533| 533| 				if (!IsOwnedByPlayer(player, garrisonHolder) && !data.controlAllUnits
| 534| 534| 				    && player != +cmd.owner)
| 535|    |-						continue;
|    | 535|+					continue;
| 536| 536| 
| 537| 537| 				if (!cmpGarrisonHolder.UnloadTemplate(cmd.template, cmd.owner, cmd.all))
| 538| 538| 					notifyUnloadFailure(player, garrisonHolder);
|    | [NORMAL] ESLintBear (key-spacing):
|    | Extra space after key 'metadata'.
|----|    | /zpool0/trunk/binaries/data/mods/public/simulation/helpers/Commands.js
|    |++++| /zpool0/trunk/binaries/data/mods/public/simulation/helpers/Commands.js
|1149|1149| 
|1150|1150| 	// send Metadata info if any
|1151|1151| 	if (cmd.metadata)
|1152|    |-		Engine.PostMessage(ent, MT_AIMetadata, { "id": ent, "metadata" : cmd.metadata, "owner" : player } );
|    |1152|+		Engine.PostMessage(ent, MT_AIMetadata, { "id": ent, "metadata": cmd.metadata, "owner" : player } );
|1153|1153| 
|1154|1154| 	// Tell the units to start building this new entity
|1155|1155| 	if (cmd.autorepair)
|    | [NORMAL] ESLintBear (key-spacing):
|    | Extra space after key 'owner'.
|----|    | /zpool0/trunk/binaries/data/mods/public/simulation/helpers/Commands.js
|    |++++| /zpool0/trunk/binaries/data/mods/public/simulation/helpers/Commands.js
|1149|1149| 
|1150|1150| 	// send Metadata info if any
|1151|1151| 	if (cmd.metadata)
|1152|    |-		Engine.PostMessage(ent, MT_AIMetadata, { "id": ent, "metadata" : cmd.metadata, "owner" : player } );
|    |1152|+		Engine.PostMessage(ent, MT_AIMetadata, { "id": ent, "metadata" : cmd.metadata, "owner": player } );
|1153|1153| 
|1154|1154| 	// Tell the units to start building this new entity
|1155|1155| 	if (cmd.autorepair)
|    | [NORMAL] ESLintBear (space-in-parens):
|    | There should be no spaces inside this paren.
|----|    | /zpool0/trunk/binaries/data/mods/public/simulation/helpers/Commands.js
|    |++++| /zpool0/trunk/binaries/data/mods/public/simulation/helpers/Commands.js
|1149|1149| 
|1150|1150| 	// send Metadata info if any
|1151|1151| 	if (cmd.metadata)
|1152|    |-		Engine.PostMessage(ent, MT_AIMetadata, { "id": ent, "metadata" : cmd.metadata, "owner" : player } );
|    |1152|+		Engine.PostMessage(ent, MT_AIMetadata, { "id": ent, "metadata" : cmd.metadata, "owner" : player });
|1153|1153| 
|1154|1154| 	// Tell the units to start building this new entity
|1155|1155| 	if (cmd.autorepair)
|    | [NORMAL] ESLintBear (spaced-comment):
|    | Expected space or tab after '//' in comment.
|----|    | /zpool0/trunk/binaries/data/mods/public/simulation/helpers/Commands.js
|    |++++| /zpool0/trunk/binaries/data/mods/public/simulation/helpers/Commands.js
|1257|1257| 		}
|1258|1258| 
|1259|1259| 		lastTowerControlGroup = cmpSnappedStartObstruction.GetControlGroup();
|1260|    |-		//warn("setting lastTowerControlGroup to control group of start snapped entity " + cmd.startSnappedEntity + ": " + lastTowerControlGroup);
|    |1260|+		// warn("setting lastTowerControlGroup to control group of start snapped entity " + cmd.startSnappedEntity + ": " + lastTowerControlGroup);
|1261|1261| 	}
|1262|1262| 
|1263|1263| 	var i = 0;
|    | [NORMAL] ESLintBear (spaced-comment):
|    | Expected space or tab after '//' in comment.
|----|    | /zpool0/trunk/binaries/data/mods/public/simulation/helpers/Commands.js
|    |++++| /zpool0/trunk/binaries/data/mods/public/simulation/helpers/Commands.js
|1321|1321| 
|1322|1322| 				if (i > 0)
|1323|1323| 				{
|1324|    |-					//warn("   updating previous wall piece's secondary control group to " + newTowerControlGroup);
|    |1324|+					// warn("   updating previous wall piece's secondary control group to " + newTowerControlGroup);
|1325|1325| 					var cmpPreviousObstruction = Engine.QueryInterface(pieces[i-1].ent, IID_Obstruction);
|1326|1326| 					// TODO: ensure that cmpPreviousObstruction exists
|1327|1327| 					// TODO: ensure that the previous obstruction does not yet have a secondary control group set
|    | [NORMAL] ESLintBear (no-undef-init):
|    | It's not necessary to initialize 'closeClusters' to undefined.
|----|    | /zpool0/trunk/binaries/data/mods/public/simulation/helpers/Commands.js
|    |++++| /zpool0/trunk/binaries/data/mods/public/simulation/helpers/Commands.js
|1577|1577| 	while (clusters.length > 1)
|1578|1578| 	{
|1579|1579| 		// search two clusters that are closer than the required distance
|1580|    |-		let closeClusters = undefined;
|    |1580|+		let closeClusters;
|1581|1581| 
|1582|1582| 		for (let i = matrix.length - 1; i >= 0 && !closeClusters; --i)
|1583|1583| 			for (let j = i - 1; j >= 0 && !closeClusters; --j)
|    | [NORMAL] ESLintBear (comma-spacing):
|    | A space is required after ','.
|----|    | /zpool0/trunk/binaries/data/mods/public/simulation/helpers/Commands.js
|    |++++| /zpool0/trunk/binaries/data/mods/public/simulation/helpers/Commands.js
|1582|1582| 		for (let i = matrix.length - 1; i >= 0 && !closeClusters; --i)
|1583|1583| 			for (let j = i - 1; j >= 0 && !closeClusters; --j)
|1584|1584| 				if (matrix[i][j] < distSq)
|1585|    |-					closeClusters = [i,j];
|    |1585|+					closeClusters = [i, j];
|1586|1586| 
|1587|1587| 		// if no more close clusters found, just return all found clusters so far
|1588|1588| 		if (!closeClusters)
|    | [NORMAL] ESLintBear (comma-spacing):
|    | A space is required after ','.
|----|    | /zpool0/trunk/binaries/data/mods/public/simulation/helpers/Commands.js
|    |++++| /zpool0/trunk/binaries/data/mods/public/simulation/helpers/Commands.js
|1606|1606| 		}
|1607|1607| 		// remove the rows and columns in the matrix for the merged clusters,
|1608|1608| 		// and the clusters themselves from the cluster list
|1609|    |-		clusters.splice(closeClusters[0],1);
|    |1609|+		clusters.splice(closeClusters[0], 1);
|1610|1610| 		clusters.splice(closeClusters[1],1);
|1611|1611| 		matrix.splice(closeClusters[0],1);
|1612|1612| 		matrix.splice(closeClusters[1],1);
|    | [NORMAL] ESLintBear (comma-spacing):
|    | A space is required after ','.
|----|    | /zpool0/trunk/binaries/data/mods/public/simulation/helpers/Commands.js
|    |++++| /zpool0/trunk/binaries/data/mods/public/simulation/helpers/Commands.js
|1607|1607| 		// remove the rows and columns in the matrix for the merged clusters,
|1608|1608| 		// and the clusters themselves from the cluster list
|1609|1609| 		clusters.splice(closeClusters[0],1);
|1610|    |-		clusters.splice(closeClusters[1],1);
|    |1610|+		clusters.splice(closeClusters[1], 1);
|1611|1611| 		matrix.splice(closeClusters[0],1);
|1612|1612| 		matrix.splice(closeClusters[1],1);
|1613|1613| 		for (let i = 0; i < matrix.length; ++i)
|    | [NORMAL] ESLintBear (comma-spacing):
|    | A space is required after ','.
|----|    | /zpool0/trunk/binaries/data/mods/public/simulation/helpers/Commands.js
|    |++++| /zpool0/trunk/binaries/data/mods/public/simulation/helpers/Commands.js
|1608|1608| 		// and the clusters themselves from the cluster list
|1609|1609| 		clusters.splice(closeClusters[0],1);
|1610|1610| 		clusters.splice(closeClusters[1],1);
|1611|    |-		matrix.splice(closeClusters[0],1);
|    |1611|+		matrix.splice(closeClusters[0], 1);
|1612|1612| 		matrix.splice(closeClusters[1],1);
|1613|1613| 		for (let i = 0; i < matrix.length; ++i)
|1614|1614| 		{
|    | [NORMAL] ESLintBear (comma-spacing):
|    | A space is required after ','.
|----|    | /zpool0/trunk/binaries/data/mods/public/simulation/helpers/Commands.js
|    |++++| /zpool0/trunk/binaries/data/mods/public/simulation/helpers/Commands.js
|1609|1609| 		clusters.splice(closeClusters[0],1);
|1610|1610| 		clusters.splice(closeClusters[1],1);
|1611|1611| 		matrix.splice(closeClusters[0],1);
|1612|    |-		matrix.splice(closeClusters[1],1);
|    |1612|+		matrix.splice(closeClusters[1], 1);
|1613|1613| 		for (let i = 0; i < matrix.length; ++i)
|1614|1614| 		{
|1615|1615| 			if (matrix[i].length > closeClusters[0])
|    | [NORMAL] ESLintBear (comma-spacing):
|    | A space is required after ','.
|----|    | /zpool0/trunk/binaries/data/mods/public/simulation/helpers/Commands.js
|    |++++| /zpool0/trunk/binaries/data/mods/public/simulation/helpers/Commands.js
|1613|1613| 		for (let i = 0; i < matrix.length; ++i)
|1614|1614| 		{
|1615|1615| 			if (matrix[i].length > closeClusters[0])
|1616|    |-				matrix[i].splice(closeClusters[0],1);
|    |1616|+				matrix[i].splice(closeClusters[0], 1);
|1617|1617| 			if (matrix[i].length > closeClusters[1])
|1618|1618| 				matrix[i].splice(closeClusters[1],1);
|1619|1619| 		}
|    | [NORMAL] ESLintBear (comma-spacing):
|    | A space is required after ','.
|----|    | /zpool0/trunk/binaries/data/mods/public/simulation/helpers/Commands.js
|    |++++| /zpool0/trunk/binaries/data/mods/public/simulation/helpers/Commands.js
|1615|1615| 			if (matrix[i].length > closeClusters[0])
|1616|1616| 				matrix[i].splice(closeClusters[0],1);
|1617|1617| 			if (matrix[i].length > closeClusters[1])
|1618|    |-				matrix[i].splice(closeClusters[1],1);
|    |1618|+				matrix[i].splice(closeClusters[1], 1);
|1619|1619| 		}
|1620|1620| 		// add a new row of distances to the matrix and the new cluster
|1621|1621| 		clusters.push(newCluster);

binaries/data/mods/public/simulation/helpers/Commands.js
|  46| »   if·(g_Commands[cmd.type])
|    | [MAJOR] ESLintBear (no-use-before-define):
|    | 'g_Commands' was used before it was defined.

binaries/data/mods/public/simulation/helpers/Commands.js
|  50| »   »   g_Commands[cmd.type](player,·cmd,·data);
|    | [MAJOR] ESLintBear (no-use-before-define):
|    | 'g_Commands' was used before it was defined.

binaries/data/mods/public/simulation/helpers/Commands.js
| 791| »   »   let·ent·=·pickRandom(cmpRangeManager.GetEntitiesByPlayer(cmd.player).filter(ent·=>·{
|    | [NORMAL] ESLintBear (no-shadow):
|    | 'ent' is already declared in the upper scope.

binaries/data/mods/public/simulation/helpers/Commands.js
|1280| ····»   »   »   error("[TryConstructWall]·Expected·last·tower·control·group·to·be·available,·none·found·(1st·pass,·iteration·"·+·i·+·")");
|    | [NORMAL] ESLintBear (no-mixed-spaces-and-tabs):
|    | Mixed spaces and tabs.

binaries/data/mods/public/simulation/helpers/Commands.js
|1281| ····»   »   »   break;
|    | [NORMAL] ESLintBear (no-mixed-spaces-and-tabs):
|    | Mixed spaces and tabs.

binaries/data/mods/public/simulation/helpers/Commands.js
|  56| var·g_Commands·=·{
|    | [NORMAL] JSHintBear:
|    | 'g_Commands' was used before it was defined.

binaries/data/mods/public/simulation/helpers/Commands.js
| 534| »   »   »   »   ····&&·player·!=·+cmd.owner)
|    | [NORMAL] JSHintBear:
|    | Misleading line break before '&&'; readers may interpret this as an expression boundary.

binaries/data/mods/public/simulation/helpers/Commands.js
| 729| »   »   »   »   var·cmpGUIInterface·=·Engine.QueryInterface(SYSTEM_ENTITY,·IID_GuiInterface);
|    | [NORMAL] JSHintBear:
|    | 'cmpGUIInterface' is already defined.

binaries/data/mods/public/simulation/helpers/Commands.js
| 954| »   »   for·(var·i·=·0;·i·<·length;·++i)
|    | [NORMAL] JSHintBear:
|    | 'i' is already defined.

binaries/data/mods/public/simulation/helpers/Commands.js
| 967| »   »   var·count·=·0;
|    | [NORMAL] JSHintBear:
|    | 'count' is already defined.

binaries/data/mods/public/simulation/helpers/Commands.js
|1114| »   »   var·cmpGuiInterface·=·Engine.QueryInterface(SYSTEM_ENTITY,·IID_GuiInterface);
|    | [NORMAL] JSHintBear:
|    | 'cmpGuiInterface' is already defined.

binaries/data/mods/public/simulation/helpers/Commands.js
|1366| »   »   var·piece·=·pieces[j];
|    | [NORMAL] JSHintBear:
|    | 'piece' is already defined.

binaries/data/mods/public/simulation/helpers/Commands.js
|1449| »   »   var·cmpUnitAI·=·Engine.QueryInterface(ent,·IID_UnitAI);
|    | [NORMAL] JSHintBear:
|    | 'cmpUnitAI' is already defined.

binaries/data/mods/public/simulation/helpers/Commands.js
|1537| »   »   »   var·cmpFormation·=·Engine.QueryInterface(formationEnt,·IID_Formation);
|    | [NORMAL] JSHintBear:
|    | 'cmpFormation' is already defined.

binaries/data/mods/public/simulation/helpers/Commands.js
|1580| »   »   let·closeClusters·=·undefined;
|    | [NORMAL] JSHintBear:
|    | It's not necessary to initialize 'closeClusters' to 'undefined'.
Executing section cli...

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

Why doesn't it make much sense to be able to gather when tasked in a formation? If I order a group of entities into a "line" formation (while the default is "box") subsequently order the group to gather and then move the group to somewhere else again, previously the entities would just have the chosen "line" formation. Now they fall back to the default ("box") formation. IMHO, that is strange ^^'

Maybe split the default formation from the disabling on command basis?

Why doesn't it make much sense to be able to gather when tasked in a formation?

Because I think so? Formations are by nature combat-related, gathering isn't.

If I order a group of entities into a "line" formation (while the default is "box") subsequently order the group to gather and then move the group to somewhere else again, previously the entities would just have the chosen "line" formation. Now they fall back to the default ("box") formation. IMHO, that is strange ^^'

It's only strange because it breaks your current expectation imo. The entities, when gathering, aren't in formation, so it makes sense that they end up in the default formation. If you were to wait a sufficient time in the "gathering" stance, it wouldn't look odd because you'd have forgotten they were in 'line' formation.

Maybe split the default formation from the disabling on command basis?

I don't understand what you mean.

Because I think so? Formations are by nature combat-related, gathering isn't.
It's only strange because it breaks your current expectation imo. The entities, when gathering, aren't in formation, so it makes sense that they end up in the default formation. If you were to wait a sufficient time in the "gathering" stance, it wouldn't look odd because you'd have forgotten they were in 'line' formation.

Well, formations are also kind of gathering related. When a group of people goes woodchopping, they stay as a group until they arrive. But it might just be me reluctant to change here ^^' If the players don't complain, why should I ;)

I don't understand what you mean.

Make this two patches, I meant. One enabling default formations and one allowing commands to disband a formation.

I don't understand what you mean.

Make this two patches, I meant. One enabling default formations and one allowing commands to disband a formation.

Ah, OK.

The trouble is that code-wise I can't really do this because our formation-setting code is very inflexible. "allowing commands to disband a formation" == "default formation is NULL".

I don't see a much easier way to simulate this behaviour too :/