Merge pull request #117 from ilan-schemoul/cance-attacks

feat: cancel attack
This commit is contained in:
evanpelle
2025-03-04 05:20:01 -08:00
committed by GitHub
10 changed files with 181 additions and 8 deletions
+16 -6
View File
@@ -15,6 +15,8 @@ import { MessageType } from "../game/Game";
import { renderNumber } from "../../client/Utils";
import { TileRef } from "../game/GameMap";
const malusForRetreat = 25;
export class AttackExecution implements Execution {
private breakAlliance = false;
private active: boolean = true;
@@ -162,7 +164,19 @@ export class AttackExecution implements Execution {
}
}
private retreat(malusPercent = 0) {
this._owner.addTroops(this.attack.troops() * (1 - malusPercent / 100));
this.attack.delete();
this.active = false;
}
tick(ticks: number) {
if (this.attack.retreated()) {
this.retreat(malusForRetreat);
this.active = false;
return;
}
if (!this.attack.isActive()) {
this.active = false;
return;
@@ -175,9 +189,7 @@ export class AttackExecution implements Execution {
}
if (this.target.isPlayer() && this._owner.isAlliedWith(this.target)) {
// In this case a new alliance was created AFTER the attack started.
this._owner.addTroops(this.attack.troops());
this.attack.delete();
this.active = false;
this.retreat();
return;
}
@@ -201,9 +213,7 @@ export class AttackExecution implements Execution {
if (this.toConquer.size() == 0) {
this.refreshToConquer();
this.active = false;
this._owner.addTroops(this.attack.troops());
this.attack.delete();
this.retreat();
return;
}
+3
View File
@@ -35,6 +35,7 @@ import { ConstructionExecution } from "./ConstructionExecution";
import { fixProfaneUsername, isProfaneUsername } from "../validations/username";
import { NoOpExecution } from "./NoOpExecution";
import { EmbargoExecution } from "./EmbargoExecution";
import { RetreatExecution } from "./RetreatExecution";
export class Executor {
// private random = new PseudoRandom(999)
@@ -80,6 +81,8 @@ export class Executor {
null,
);
}
case "cancel_attack":
return new RetreatExecution(intent.playerID, intent.attackID);
case "spawn":
return new SpawnExecution(
new PlayerInfo(
+50
View File
@@ -0,0 +1,50 @@
import { Execution, Game, Player, PlayerID } from "../game/Game";
const cancelDelay = 2;
export class RetreatExecution implements Execution {
private active = true;
private retreatOrdered = false;
private player: Player;
private executionDateInSecs = new Date().getTime() / 1000 + cancelDelay;
constructor(
private playerID: PlayerID,
private attackID: string,
) {}
init(mg: Game, ticks: number): void {
if (!mg.hasPlayer(this.playerID)) {
console.warn(`RetreatExecution: player ${this.player.id()} not found`);
return;
}
this.player = mg.player(this.playerID);
}
tick(ticks: number): void {
const nowInSecs = new Date().getTime() / 1000;
if (!this.retreatOrdered) {
this.player.orderRetreat(this.attackID);
this.retreatOrdered = true;
}
if (nowInSecs >= this.executionDateInSecs) {
this.player.executeRetreat(this.attackID);
this.active = false;
}
}
owner(): Player {
return this.player;
}
isActive(): boolean {
return this.active;
}
activeDuringSpawnPhase(): boolean {
return false;
}
}