Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
92c4324
Better ship handling for AFK player
VariableVince Oct 15, 2025
870a35a
New src for retreating transport
VariableVince Oct 15, 2025
0f867eb
Small fix
VariableVince Oct 15, 2025
ac128e0
Merge branch 'v26' into warship-afk-handling
VariableVince Oct 15, 2025
d479c3e
Warships never attack when friendly is disconnected
VariableVince Oct 17, 2025
1b44273
Fix leftover troop removal on attack and add tests
VariableVince Oct 17, 2025
3c0baa5
Fix condition
VariableVince Oct 17, 2025
f583e5b
Merge branch 'v26' into warship-afk-handling
VariableVince Oct 17, 2025
fac44c8
Merge branch 'v26' into warship-afk-handling
VariableVince Oct 18, 2025
c84e532
Originalowner = attacker
VariableVince Oct 24, 2025
705fce6
Move src check to retreating block
VariableVince Oct 24, 2025
a85b6da
add param to isFriendly to prevent afk warship attack
VariableVince Oct 24, 2025
9e7d9ef
Prettier
VariableVince Oct 24, 2025
b844bea
origowner outside constr
VariableVince Oct 24, 2025
d26886b
Merge branch 'v26' into warship-afk-handling
VariableVince Oct 24, 2025
8b4f35b
Fix origowner
VariableVince Oct 24, 2025
dd13a89
Use bestTransportShipSpawn instead of canBuild
VariableVince Oct 25, 2025
3c0d967
Fix no troop loss
VariableVince Oct 28, 2025
32bbdf2
Wording
VariableVince Oct 28, 2025
d3382a7
Merge branch 'v26' into warship-afk-handling
VariableVince Oct 28, 2025
04d9c76
No troop remove at init but keep bugfix and test
VariableVince Oct 30, 2025
cbcd3db
Prettier
VariableVince Oct 30, 2025
8abebe6
Merge branch 'v26' into warship-afk-handling
VariableVince Oct 30, 2025
a91c671
Pascal Case and more ticks
VariableVince Oct 30, 2025
fe854c0
Merge branch 'warship-afk-handling' of https://github.com/openfrontio…
VariableVince Oct 30, 2025
a7974d9
Merge branch 'v26' into warship-afk-handling
evanpelle Nov 1, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/core/configuration/DefaultConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -676,7 +676,7 @@ export class DefaultConfig implements Config {

if (attacker.isPlayer() && defender.isPlayer()) {
if (defender.isDisconnected() && attacker.isOnSameTeam(defender)) {
// No troop loss if defender is disconnected.
// No troop loss if defender is disconnected and on same team
mag = 0;
}
if (
Expand Down
6 changes: 6 additions & 0 deletions src/core/execution/AttackExecution.ts
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,12 @@ export class AttackExecution implements Execution {
this._owner.id(),
);
}
if (this.removeTroops === false) {
// startTroops are always added to attack troops at init but not always removed from owner troops
// subtract startTroops from attack troops so we don't give back startTroops to owner that were never removed
this.attack.setTroops(this.attack.troops() - (this.startTroops ?? 0));
}

const survivors = this.attack.troops() - deaths;
this._owner.addTroops(survivors);
this.attack.delete();
Expand Down
44 changes: 40 additions & 4 deletions src/core/execution/TransportShipExecution.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,17 @@ export class TransportShipExecution implements Execution {

private pathFinder: PathFinder;

private originalOwner: Player;

constructor(
private attacker: Player,
private targetID: PlayerID | null,
private ref: TileRef,
private startTroops: number,
private src: TileRef | null,
) {}
) {
this.originalOwner = this.attacker;
}

activeDuringSpawnPhase(): boolean {
return false;
Expand Down Expand Up @@ -173,11 +177,43 @@ export class TransportShipExecution implements Execution {
}
this.lastMove = ticks;

// Team mate can conquer disconnected player and get their ships
// captureUnit has changed the owner of the unit, now update attacker
if (
this.originalOwner.isDisconnected() &&
this.boat.owner() !== this.originalOwner &&
this.boat.owner().isOnSameTeam(this.originalOwner)
) {
this.attacker = this.boat.owner();
this.originalOwner = this.boat.owner(); // for when this owner disconnects too
}

if (this.boat.retreating()) {
this.dst = this.src!; // src is guaranteed to be set at this point
// Ensure retreat source is valid for the new owner
if (this.mg.owner(this.src!) !== this.attacker) {
// Use bestTransportShipSpawn, not canBuild because of its max boats check etc
const newSrc = this.attacker.bestTransportShipSpawn(this.dst);
if (newSrc === false) {
this.src = null;
} else {
this.src = newSrc;
}
}

if (this.boat.targetTile() !== this.dst) {
this.boat.setTargetTile(this.dst);
if (this.src === null) {
console.warn(
`TransportShipExecution: retreating but no src found for new attacker`,
);
this.attacker.addTroops(this.boat.troops());
this.boat.delete(false);
this.active = false;
return;
} else {
this.dst = this.src;

if (this.boat.targetTile() !== this.dst) {
this.boat.setTargetTile(this.dst);
}
}
}

Expand Down
6 changes: 1 addition & 5 deletions src/core/execution/WarshipExecution.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,10 +55,6 @@ export class WarshipExecution implements Execution {
this.warship.delete();
return;
}
if (this.warship.owner().isDisconnected()) {
this.warship.delete();
return;
}

const hasPort = this.warship.owner().unitCount(UnitType.Port) > 0;
if (hasPort) {
Expand Down Expand Up @@ -93,7 +89,7 @@ export class WarshipExecution implements Execution {
if (
unit.owner() === this.warship.owner() ||
unit === this.warship ||
unit.owner().isFriendly(this.warship.owner()) ||
unit.owner().isFriendly(this.warship.owner(), true) ||
this.alreadySentShell.has(unit)
) {
continue;
Expand Down
2 changes: 1 addition & 1 deletion src/core/game/Game.ts
Original file line number Diff line number Diff line change
Expand Up @@ -584,7 +584,7 @@ export interface Player {
decayRelations(): void;
isOnSameTeam(other: Player): boolean;
// Either allied or on same team.
isFriendly(other: Player): boolean;
isFriendly(other: Player, treatAFKFriendly?: boolean): boolean;
team(): Team | null;
clan(): string | null;
incomingAllianceRequests(): AllianceRequest[];
Expand Down
14 changes: 14 additions & 0 deletions src/core/game/GameImpl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -877,6 +877,20 @@ export class GameImpl implements Game {
return this._railNetwork;
}
conquerPlayer(conqueror: Player, conquered: Player) {
if (conquered.isDisconnected() && conqueror.isOnSameTeam(conquered)) {
const ships = conquered
.units()
.filter(
(u) =>
u.type() === UnitType.Warship ||
u.type() === UnitType.TransportShip,
);

for (const ship of ships) {
conqueror.captureUnit(ship);
}
}

const gold = conquered.gold();
this.displayMessage(
`Conquered ${conquered.displayName()} received ${renderNumber(
Expand Down
4 changes: 2 additions & 2 deletions src/core/game/PlayerImpl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -784,8 +784,8 @@ export class PlayerImpl implements Player {
return this._team === other.team();
}

isFriendly(other: Player): boolean {
if (other.isDisconnected()) {
isFriendly(other: Player, treatAFKFriendly: boolean = false): boolean {
if (other.isDisconnected() && !treatAFKFriendly) {
return false;
}
return this.isOnSameTeam(other) || this.isAlliedWith(other);
Expand Down
2 changes: 2 additions & 0 deletions src/core/game/TransportShipUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,8 @@ export function bestShoreDeploymentSource(
if (t === null) return false;

const candidates = candidateShoreTiles(gm, player, t);
if (candidates.length === 0) return false;

const aStar = new MiniAStar(gm, gm.miniMap(), candidates, t, 1_000_000, 1);
const result = aStar.compute();
if (result !== PathFindResultType.Completed) {
Expand Down
Loading
Loading