Various little nation improvements 🤖 (#3082)

## Description:

- Maybe greet nearby players with a 👋 emoji in the earlygame (make
nations feel a little bit more lively)
- Destroying a transport ship / capturing a trade ship of a nation now
updates the relation (mainly on higher difficulties)
- On hard difficulty: Only lift embargos if we have a friendly relation.
On impossible difficulty: Don't lift embargos
- Improve totalPlayers calculation and return value of
`hasTooManyAlliances` in `NationAllianceBehavior`

## Please complete the following:

- [X] I have added screenshots for all UI updates
- [X] I process any text displayed to the user through translateText()
and I've added it to the en.json file
- [X] I have added relevant tests to the test directory
- [X] I confirm I have thoroughly tested these changes and take full
responsibility for any bugs introduced

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

FloPinguin
This commit is contained in:
FloPinguin
2026-02-02 05:12:19 +01:00
committed by GitHub
parent e4280c28e1
commit 8ab9cef65b
4 changed files with 47 additions and 6 deletions
+9 -1
View File
@@ -360,7 +360,15 @@ export class NationExecution implements Execution {
player.addEmbargo(other, false);
} else if (
player.relation(other) >= Relation.Neutral &&
player.hasEmbargoAgainst(other)
player.hasEmbargoAgainst(other) &&
this.mg.config().gameConfig().difficulty !== Difficulty.Hard &&
this.mg.config().gameConfig().difficulty !== Difficulty.Impossible
) {
player.stopEmbargo(other);
} else if (
player.relation(other) >= Relation.Friendly &&
player.hasEmbargoAgainst(other) &&
this.mg.config().gameConfig().difficulty !== Difficulty.Impossible
) {
player.stopEmbargo(other);
}
@@ -143,10 +143,16 @@ export class NationAllianceBehavior {
return false;
}
const totalPlayers = this.game.players().length;
const totalPlayers = this.game
.players()
.filter((p) => p.type() !== PlayerType.Bot).length;
const otherPlayerAlliances = otherPlayer.alliances().length;
return otherPlayerAlliances >= totalPlayers * 0.5;
if (difficulty !== Difficulty.Hard) {
return otherPlayerAlliances >= totalPlayers * 0.5;
} else {
return otherPlayerAlliances >= totalPlayers * 0.25;
}
}
private isConfused(): boolean {
@@ -42,6 +42,7 @@ export const EMOJI_BORED = (["🥱"] as const).map(emojiId);
export const EMOJI_HANDSHAKE = (["🤝"] as const).map(emojiId);
export const EMOJI_DONATION_OK = (["👍"] as const).map(emojiId);
export const EMOJI_DONATION_TOO_SMALL = (["❓", "🥱"] as const).map(emojiId);
export const EMOJI_GREET = (["👋"] as const).map(emojiId);
export class NationEmojiBehavior {
private readonly lastEmojiSent = new Map<Player, Tick>();
@@ -63,6 +64,7 @@ export class NationEmojiBehavior {
this.charmAllies();
this.annoyTraitors();
this.findRat();
this.greetNearbyPlayers();
}
private checkOverwhelmedByAttacks(): void {
@@ -203,6 +205,22 @@ export class NationEmojiBehavior {
this.sendEmoji(smallPlayer, EMOJI_RAT);
}
private greetNearbyPlayers(): void {
if (this.game.ticks() > 600) return; // Only in the first minute
if (!this.random.chance(250)) return;
const nearbyHumans = this.player
.neighbors()
.filter(
(p): p is Player => p.isPlayer() && p.type() === PlayerType.Human,
);
if (nearbyHumans.length === 0) return;
const neighbor = this.random.randElement(nearbyHumans);
this.sendEmoji(neighbor, EMOJI_GREET);
}
maybeSendEmoji(
otherPlayer: Player | typeof AllPlayers,
emojisList: number[],
@@ -99,7 +99,11 @@ export class NationWarshipBehavior {
if (!ship.isActive()) {
// Distinguish between arrival/retreat and enemy destruction
if (ship.wasDestroyedByEnemy() && ship.destroyer() !== undefined) {
this.maybeRetaliateWithWarship(ship.tile(), ship.destroyer()!);
this.maybeRetaliateWithWarship(
ship.tile(),
ship.destroyer()!,
"transport",
);
}
this.trackedTransportShips.delete(ship);
}
@@ -121,13 +125,17 @@ export class NationWarshipBehavior {
}
if (ship.owner().id() !== this.player.id()) {
// Ship was ours and is now owned by someone else -> captured
this.maybeRetaliateWithWarship(ship.tile(), ship.owner());
this.maybeRetaliateWithWarship(ship.tile(), ship.owner(), "trade");
this.trackedTradeShips.delete(ship);
}
}
}
private maybeRetaliateWithWarship(tile: TileRef, enemy: Player): void {
private maybeRetaliateWithWarship(
tile: TileRef,
enemy: Player,
reason: "trade" | "transport",
): void {
// Don't send too many warships
if (this.player.units(UnitType.Warship).length >= 10) {
return;
@@ -148,6 +156,7 @@ export class NationWarshipBehavior {
new ConstructionExecution(this.player, UnitType.Warship, tile),
);
this.emojiBehavior.maybeSendEmoji(enemy, EMOJI_WARSHIP_RETALIATION);
this.player.updateRelation(enemy, reason === "trade" ? -7.5 : -15);
}
}