Skip to content

Commit 00a1ae6

Browse files
committed
Improve nations
1 parent c9d9a32 commit 00a1ae6

7 files changed

Lines changed: 245 additions & 63 deletions

File tree

src/core/execution/AttackExecution.ts

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { renderTroops } from "../../client/Utils";
22
import {
33
Attack,
4+
Difficulty,
45
Execution,
56
Game,
67
MessageType,
@@ -152,7 +153,23 @@ export class AttackExecution implements Execution {
152153
}
153154

154155
if (this.target.isPlayer()) {
155-
this.target.updateRelation(this._owner, -80);
156+
const difficulty = this.mg.config().gameConfig().difficulty;
157+
let relationChange: number;
158+
switch (difficulty) {
159+
case Difficulty.Easy:
160+
relationChange = -60;
161+
break;
162+
case Difficulty.Medium:
163+
relationChange = -70;
164+
break;
165+
case Difficulty.Hard:
166+
relationChange = -80;
167+
break;
168+
case Difficulty.Impossible:
169+
relationChange = -100;
170+
break;
171+
}
172+
this.target.updateRelation(this._owner, relationChange);
156173
}
157174
}
158175

src/core/execution/NationExecution.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -448,7 +448,6 @@ export class NationExecution implements Execution {
448448
this.allianceBehavior.maybeSendAllianceRequests(borderingEnemies);
449449
}
450450

451-
this.attackBehavior.assistAllies();
452451
this.attackBehavior.attackBestTarget(borderingFriends, borderingEnemies);
453452
this.maybeSendNuke(
454453
this.attackBehavior.findBestNukeTarget(borderingEnemies),

src/core/execution/alliance/BreakAllianceExecution.ts

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -35,11 +35,16 @@ export class BreakAllianceExecution implements Execution {
3535
console.warn("cant break alliance, not allied");
3636
} else {
3737
this.requestor.breakAlliance(alliance);
38-
this.recipient.updateRelation(this.requestor, -200);
39-
for (const player of this.mg.players()) {
40-
if (player !== this.requestor && !player.isOnSameTeam(this.requestor)) {
41-
player.updateRelation(this.requestor, -40);
42-
}
38+
this.recipient.updateRelation(this.requestor, -100);
39+
40+
const neighbors = this.requestor
41+
.neighbors()
42+
.filter(
43+
(n): n is Player => n.isPlayer() && !n.isOnSameTeam(this.recipient!),
44+
);
45+
46+
for (const neighbor of neighbors) {
47+
neighbor.updateRelation(this.requestor, -40);
4348
}
4449
}
4550
this.active = false;

src/core/execution/nation/NationAllianceBehavior.ts

Lines changed: 48 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import {
22
Difficulty,
33
Game,
4+
GameMode,
45
Player,
56
PlayerType,
67
Relation,
@@ -59,7 +60,7 @@ export class NationAllianceBehavior {
5960

6061
for (const enemy of borderingEnemies) {
6162
if (
62-
this.random.chance(20) &&
63+
this.random.chance(30) &&
6364
isAcceptablePlayerType(enemy) &&
6465
this.player.canSendAllianceRequest(enemy) &&
6566
this.getAllianceDecision(enemy, false)
@@ -86,18 +87,27 @@ export class NationAllianceBehavior {
8687
}
8788
return false;
8889
}
90+
// Reject if otherPlayer has allied with 50% or more of all players (Hard and Impossible only)
91+
// To make sure there are enough non-friendly players in the game to stop the crown with nukes
92+
if (this.hasTooManyAlliances(otherPlayer)) {
93+
return false;
94+
}
8995
// Before caring about the relation, first check if the otherPlayer is a threat
9096
// Easy (dumb) nations are blinded by hatred, they don't care about threats, they care about the relation
9197
// Impossible (smart) nations on the other hand are analyzing the facts
9298
if (this.isAlliancePartnerThreat(otherPlayer)) {
93-
if (!isResponse && this.random.chance(3)) {
99+
if (!isResponse && this.random.chance(6)) {
94100
this.emojiBehavior.sendEmoji(otherPlayer, EMOJI_SCARED_OF_THREAT);
95101
}
96-
if (isResponse && this.random.chance(3)) {
102+
if (isResponse && this.random.chance(6)) {
97103
this.emojiBehavior.sendEmoji(otherPlayer, EMOJI_LOVE);
98104
}
99105
return true;
100106
}
107+
// Maybe reject if we are in a team game (allying makes less sense there)
108+
if (this.shouldRejectInTeamGame()) {
109+
return false;
110+
}
101111
// Reject if relation is bad
102112
if (this.player.relation(otherPlayer) < Relation.Neutral) {
103113
if (isResponse && this.random.chance(3)) {
@@ -124,6 +134,21 @@ export class NationAllianceBehavior {
124134
return this.isAlliancePartnerSimilarlyStrong(otherPlayer);
125135
}
126136

137+
private hasTooManyAlliances(otherPlayer: Player): boolean {
138+
const { difficulty } = this.game.config().gameConfig();
139+
if (
140+
difficulty !== Difficulty.Hard &&
141+
difficulty !== Difficulty.Impossible
142+
) {
143+
return false;
144+
}
145+
146+
const totalPlayers = this.game.players().length;
147+
const otherPlayerAlliances = otherPlayer.alliances().length;
148+
149+
return otherPlayerAlliances >= totalPlayers * 0.5;
150+
}
151+
127152
private isConfused(): boolean {
128153
const { difficulty } = this.game.config().gameConfig();
129154
switch (difficulty) {
@@ -207,6 +232,26 @@ export class NationAllianceBehavior {
207232
}
208233
}
209234

235+
private shouldRejectInTeamGame(): boolean {
236+
if (this.game.config().gameConfig().gameMode !== GameMode.Team) {
237+
return false;
238+
}
239+
240+
const { difficulty } = this.game.config().gameConfig();
241+
switch (difficulty) {
242+
case Difficulty.Easy:
243+
return false; // 0% chance to reject on easy
244+
case Difficulty.Medium:
245+
return this.random.nextInt(0, 100) < 20; // 20% chance to reject on medium
246+
case Difficulty.Hard:
247+
return this.random.nextInt(0, 100) < 40; // 40% chance to reject on hard
248+
case Difficulty.Impossible:
249+
return this.random.nextInt(0, 100) < 60; // 60% chance to reject on impossible
250+
default:
251+
assertNever(difficulty);
252+
}
253+
}
254+
210255
private checkAlreadyEnoughAlliances(otherPlayer: Player): boolean {
211256
const { difficulty } = this.game.config().gameConfig();
212257
switch (difficulty) {

src/core/execution/nation/NationEmojiBehavior.ts

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,7 @@ import { EmojiExecution } from "../EmojiExecution";
1515

1616
const emojiId = (e: (typeof flattenedEmojiTable)[number]) =>
1717
flattenedEmojiTable.indexOf(e);
18-
export const EMOJI_ASSIST_ACCEPT = (["👍", "⛵", "🤝", "🎯"] as const).map(
19-
emojiId,
20-
);
18+
export const EMOJI_ASSIST_ACCEPT = (["👍", "🤝", "🎯"] as const).map(emojiId);
2119
export const EMOJI_ASSIST_RELATION_TOO_LOW = (["🥱", "🤦‍♂️"] as const).map(
2220
emojiId,
2321
);
@@ -34,7 +32,7 @@ export const EMOJI_LOVE = (["❤️", "😊", "🥰"] as const).map(emojiId);
3432
export const EMOJI_CONFUSED = (["❓", "🤡"] as const).map(emojiId);
3533
export const EMOJI_BRAG = (["👑", "🥇", "💪"] as const).map(emojiId);
3634
export const EMOJI_CHARM_ALLIES = (["🤝", "😇", "💪"] as const).map(emojiId);
37-
export const EMOJI_CLOWN = (["🤡"] as const).map(emojiId);
35+
export const EMOJI_CLOWN = (["🤡", "🤦‍♂️"] as const).map(emojiId);
3836
export const EMOJI_RAT = (["🐀"] as const).map(emojiId);
3937
export const EMOJI_OVERWHELMED = (
4038
["💀", "🆘", "😱", "🥺", "😭", "😞", "🫡", "👋"] as const
@@ -67,7 +65,7 @@ export class NationEmojiBehavior {
6765
}
6866

6967
private checkOverwhelmedByAttacks(): void {
70-
if (!this.random.chance(4)) return;
68+
if (!this.random.chance(8)) return;
7169

7270
const incomingAttacks = this.player.incomingAttacks();
7371
if (incomingAttacks.length === 0) return;
@@ -85,7 +83,7 @@ export class NationEmojiBehavior {
8583
}
8684

8785
private checkVerySmallAttack(): void {
88-
if (!this.random.chance(4)) return;
86+
if (!this.random.chance(8)) return;
8987

9088
const incomingAttacks = this.player.incomingAttacks();
9189
if (incomingAttacks.length === 0) return;
@@ -175,7 +173,7 @@ export class NationEmojiBehavior {
175173

176174
// Brag with our crown
177175
private brag(): void {
178-
if (!this.random.chance(100)) return;
176+
if (!this.random.chance(300)) return;
179177

180178
const sorted = this.game
181179
.players()
@@ -218,6 +216,7 @@ export class NationEmojiBehavior {
218216
}
219217

220218
private findRat(): void {
219+
if (this.game.ticks() < 6000) return; // Ignore first 10 minutes (everybody is small in the early game)
221220
if (!this.random.chance(10000)) return;
222221

223222
const totalLand = this.game.numLandTiles();
@@ -340,3 +339,19 @@ export function respondToEmoji(
340339
);
341340
}
342341
}
342+
343+
export function respondToMIRV(
344+
game: Game,
345+
random: PseudoRandom,
346+
mirvTarget: Player,
347+
) {
348+
if (!random.chance(8)) return;
349+
350+
game.addExecution(
351+
new EmojiExecution(
352+
mirvTarget,
353+
AllPlayers,
354+
random.randElement(EMOJI_OVERWHELMED),
355+
),
356+
);
357+
}

src/core/execution/nation/NationMIRVBehavior.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,11 @@ import { PseudoRandom } from "../../PseudoRandom";
1212
import { assertNever } from "../../Util";
1313
import { MirvExecution } from "../MIRVExecution";
1414
import { calculateTerritoryCenter } from "../Util";
15-
import { EMOJI_NUKE, NationEmojiBehavior } from "./NationEmojiBehavior";
15+
import {
16+
EMOJI_NUKE,
17+
NationEmojiBehavior,
18+
respondToMIRV,
19+
} from "./NationEmojiBehavior";
1620

1721
export class NationMIRVBehavior {
1822
constructor(
@@ -258,6 +262,7 @@ export class NationMIRVBehavior {
258262
if (centerTile && this.player.canBuild(UnitType.MIRV, centerTile)) {
259263
this.game.addExecution(new MirvExecution(this.player, centerTile));
260264
this.emojiBehavior.sendEmoji(AllPlayers, EMOJI_NUKE);
265+
respondToMIRV(this.game, this.random, enemy);
261266
}
262267
}
263268

0 commit comments

Comments
 (0)