Index: binaries/data/mods/public/gui/session/unit_actions.js =================================================================== --- binaries/data/mods/public/gui/session/unit_actions.js +++ binaries/data/mods/public/gui/session/unit_actions.js @@ -1041,8 +1041,10 @@ "entities": selection, "x": position.x, "z": position.z, + "target": action.target, "data": action.data, - "queued": queued + "queued": queued, + "pushFront": pushFront }); // Display rally point at the new coordinates, to avoid display lag @@ -1246,11 +1248,13 @@ "target": null, "tooltip": actionInfo.tooltip }; - + if (Engine.HotkeyIsPressed("session.autorallypoint")) + target = null; return actionInfo.possible && { "type": "set-rallypoint", "cursor": actionInfo.cursor, "data": actionInfo.data, + "target": target, "tooltip": actionInfo.tooltip, "position": actionInfo.position, "firstAbleEntity": actionInfo.entity Index: binaries/data/mods/public/simulation/components/BuildingAI.js =================================================================== --- binaries/data/mods/public/simulation/components/BuildingAI.js +++ binaries/data/mods/public/simulation/components/BuildingAI.js @@ -1,5 +1,5 @@ // Number of rounds of firing per 2 seconds. -const roundCount = 10; +const roundCount = 5; const attackType = "Ranged"; function BuildingAI() {} @@ -28,6 +28,7 @@ this.archersGarrisoned = 0; this.arrowsLeft = 0; this.targetUnits = []; + this.focusTargets = []; }; BuildingAI.prototype.OnGarrisonedUnitsChanged = function(msg) @@ -50,6 +51,7 @@ BuildingAI.prototype.OnOwnershipChanged = function(msg) { this.targetUnits = []; + this.focusTargets = []; this.SetupRangeQuery(); this.SetupGaiaRangeQuery(); }; @@ -267,6 +269,22 @@ }; /** + * Adds index to keep track of the user-targeted units supporting a queue + * @param {ent} - Target of rallypoint selection when selection is an enemy unit from unit_actions.js + */ +BuildingAI.prototype.AddFocusTarget = function(ent, queued, push) +{ + if (!ent || this.targetUnits.indexOf(ent) === -1) + return; + if (queued) + this.focusTargets.push({"entityId": ent}); + else if (push) + this.focusTargets.unshift({"entityId": ent}); + else + this.focusTargets = [{"entityId": ent}]; +}; + +/** * Fire arrows with random temporal distribution on prefered targets. * Called 'roundCount' times every 'RepeatTime' seconds when there are units in the range. */ @@ -308,25 +326,32 @@ return; } - // Add targets to a weighted list, to allow preferences. - let targets = new WeightedList(); - let maxPreference = this.MAX_PREFERENCE_BONUS; - let addTarget = function(target) + // Add targets to a list. + let targets = []; + let addTarget = function(target) { - let preference = cmpAttack.GetPreference(target); - let weight = 1; - - if (preference !== null && preference !== undefined) - weight += maxPreference / (1 + preference); - - targets.push(target, weight); + const pref = (cmpAttack.GetPreference(target) ?? 49); + targets.push({"entityId": target, "preference": pref}); }; - // Add the UnitAI target separately, as the UnitMotion and RangeManager implementations differ. if (this.unitAITarget && this.targetUnits.indexOf(this.unitAITarget) == -1) - addTarget(this.unitAITarget); - for (let target of this.targetUnits) - addTarget(target); + addTarget(this.unitAITarget); + else if (this.unitAITarget && this.targetUnits.indexOf(this.unitAITarget) != -1) + this.focusTargets = [{"entityId": this.unitAITarget}]; + if (!this.focusTargets.length) + { + for (let target of this.targetUnits) + addTarget(target); + // Sort targets by preference and then by proximity. + targets.sort( (a,b) => { + if (a.preference > b.preference) return 1; + else if (a.preference < b.preference) return -1; + else if (PositionHelper.DistanceBetweenEntities(this.entity,a.entityId) > PositionHelper.DistanceBetweenEntities(this.entity,b.entityId)) return 1; + return -1; + }); + } + else + targets = this.focusTargets; // The obstruction manager performs approximate range checks. // so we need to verify them here. @@ -335,10 +360,12 @@ const range = cmpAttack.GetRange(attackType); const yOrigin = cmpAttack.GetAttackYOrigin(attackType); - let firedArrows = 0; - while (firedArrows < arrowsToFire && targets.length()) - { - const selectedTarget = targets.randomItem(); + let firedArrows = 0; + let targetIndex = 0; + while (firedArrows < arrowsToFire && targetIndex < targets.length) + { + + let selectedTarget = targets[targetIndex].entityId; if (this.CheckTargetVisible(selectedTarget) && cmpObstructionManager.IsInTargetParabolicRange( this.entity, selectedTarget, @@ -350,13 +377,14 @@ cmpAttack.PerformAttack(attackType, selectedTarget); PlaySound("attack_" + attackType.toLowerCase(), this.entity); ++firedArrows; - continue; } - - // Could not attack target, try a different target. - targets.remove(selectedTarget); + else + { + // Could not attack target, try a different target. + ++targetIndex + } } - + targets.splice(0, targetIndex); this.arrowsLeft -= firedArrows; ++this.currentRound; }; Index: binaries/data/mods/public/simulation/helpers/Commands.js =================================================================== --- binaries/data/mods/public/simulation/helpers/Commands.js +++ binaries/data/mods/public/simulation/helpers/Commands.js @@ -435,6 +435,8 @@ { for (let ent of data.entities) { + if (cmd.data.command == "attack" && cmd.data.target) + Engine.QueryInterface(ent, IID_BuildingAI)?.AddFocusTarget(cmd.target, cmd.queued, cmd.pushFront); var cmpRallyPoint = Engine.QueryInterface(ent, IID_RallyPoint); if (cmpRallyPoint) { Index: binaries/data/mods/public/simulation/templates/template_structure_civic_civil_centre.xml =================================================================== --- binaries/data/mods/public/simulation/templates/template_structure_civic_civil_centre.xml +++ binaries/data/mods/public/simulation/templates/template_structure_civic_civil_centre.xml @@ -17,7 +17,7 @@ 2000 100 - 1.5 + 2 50 false Index: binaries/data/mods/public/simulation/templates/template_structure_military_fortress.xml =================================================================== --- binaries/data/mods/public/simulation/templates/template_structure_military_fortress.xml +++ binaries/data/mods/public/simulation/templates/template_structure_military_fortress.xml @@ -11,7 +11,7 @@ 2000 100 - 1.5 + 3 50 false