Feat : focus attack average position and some movement camera fixes (#740)

## Description:

Makes so that when clicking on the attack warning message in chat, the
camera focuses on the "average position" of the attack, instead of just
the player.

The average position is calculated by taking the average position of all
attacking border cells. It makes the calculation for every AttackUpdate,
which adds some calculations every tick, but it shouldn't affect
performance that much, as it's just a sum of coordinates.
If you have a better way of getting the averagePosition information
(calculating it only when necessary instead of every tick), it would be
great.

closes #703 

## Please complete the following:

- [x] I have added screenshots for all UI updates
- [x] I confirm I have thoroughly tested these changes and take full
responsibility for any bugs introduced
- [x] I understand that submitting code with bugs that could have been
caught through manual testing blocks releases and new features for all
contributors

## Please put your Discord username so you can be contacted if a bug or
regression is found:
leo21_

---------

Co-authored-by: Scott Anderson <scottanderson@users.noreply.github.com>
Co-authored-by: evanpelle <evanpelle@gmail.com>
This commit is contained in:
Léo Kosman
2025-05-24 04:03:53 +02:00
committed by GitHub
parent c30839b12b
commit 2c4d2334dd
12 changed files with 279 additions and 65 deletions
+19 -12
View File
@@ -27,8 +27,6 @@ export class AttackExecution implements Execution {
private mg: Game;
private border = new Set<TileRef>();
private attack: Attack | null = null;
constructor(
@@ -119,8 +117,15 @@ export class AttackExecution implements Execution {
this.target,
this.startTroops,
this.sourceTile,
new Set<TileRef>(),
);
if (this.sourceTile !== null) {
this.addNeighbors(this.sourceTile);
} else {
this.refreshToConquer();
}
// Record stats
this.mg.stats().attack(this._owner, this.target, this.startTroops);
@@ -152,12 +157,6 @@ export class AttackExecution implements Execution {
}
}
if (this.sourceTile !== null) {
this.addNeighbors(this.sourceTile);
} else {
this.refreshToConquer();
}
if (this.target.isPlayer()) {
if (this._owner.isAlliedWith(this.target)) {
// No updates should happen in init.
@@ -168,8 +167,12 @@ export class AttackExecution implements Execution {
}
private refreshToConquer() {
if (this.attack === null) {
throw new Error("Attack not initialized");
}
this.toConquer.clear();
this.border.clear();
this.attack.clearBorder();
for (const tile of this._owner.borderTiles()) {
this.addNeighbors(tile);
}
@@ -243,7 +246,7 @@ export class AttackExecution implements Execution {
troopCount,
this._owner,
this.target,
this.border.size + this.random.nextInt(0, 5),
this.attack.borderSize() + this.random.nextInt(0, 5),
);
while (numTilesPerTick > 0) {
@@ -260,7 +263,7 @@ export class AttackExecution implements Execution {
}
const [tileToConquer] = this.toConquer.dequeue();
this.border.delete(tileToConquer);
this.attack.removeBorderTile(tileToConquer);
let onBorder = false;
for (const n of this.mg.neighbors(tileToConquer)) {
@@ -294,6 +297,10 @@ export class AttackExecution implements Execution {
}
private addNeighbors(tile: TileRef) {
if (this.attack === null) {
throw new Error("Attack not initialized");
}
const tickNow = this.mg.ticks(); // cache tick
for (const neighbor of this.mg.neighbors(tile)) {
@@ -303,7 +310,7 @@ export class AttackExecution implements Execution {
) {
continue;
}
this.border.add(neighbor);
this.attack.addBorderTile(neighbor);
let numOwnedByMe = 0;
for (const n of this.mg.neighbors(neighbor)) {
if (this.mg.owner(n) === this._owner) {