Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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
5 changes: 5 additions & 0 deletions src/client/graphics/layers/PlayerActionHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { PlayerActions } from "../../../core/game/Game";
import { TileRef } from "../../../core/game/GameMap";
import { PlayerView } from "../../../core/game/GameView";
import {
SendAllianceExtensionIntentEvent,
SendAllianceRequestIntentEvent,
SendAttackIntentEvent,
SendBoatAttackIntentEvent,
Expand Down Expand Up @@ -63,6 +64,10 @@ export class PlayerActionHandler {
this.eventBus.emit(new SendAllianceRequestIntentEvent(player, recipient));
}

handleExtendAlliance(recipient: PlayerView) {
this.eventBus.emit(new SendAllianceExtensionIntentEvent(recipient));
}

handleBreakAlliance(player: PlayerView, recipient: PlayerView) {
this.eventBus.emit(new SendBreakAllianceIntentEvent(player, recipient));
}
Expand Down
19 changes: 18 additions & 1 deletion src/client/graphics/layers/RadialMenuElements.ts
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,20 @@ const allyRequestElement: MenuElement = {
},
};

const allyExtendElement: MenuElement = {
id: "ally_extend",
name: "extend",
disabled: (params: MenuElementParams) => false,
displayed: (params: MenuElementParams) =>
!!params.playerActions?.interaction?.canExtendAlliance,
color: COLORS.boat,
icon: allianceIcon,
action: (params: MenuElementParams) => {
params.playerActionHandler.handleExtendAlliance(params.selected!);
params.closeMenu();
},
};

const allyBreakElement: MenuElement = {
id: "ally_break",
name: "break",
Expand Down Expand Up @@ -624,13 +638,16 @@ export const rootMenuElement: MenuElement = {
tileOwner.isPlayer() &&
(tileOwner as PlayerView).id() === params.myPlayer.id();

const canExtendAlliance =
params.playerActions.interaction?.canExtendAlliance;

const menuItems: (MenuElement | null)[] = [
infoMenuElement,
...(isOwnTerritory
? [deleteUnitElement, allyRequestElement, buildMenuElement]
: [
isAllied ? allyBreakElement : boatMenuElement,
allyRequestElement,
canExtendAlliance ? allyExtendElement : allyRequestElement,
isFriendlyTarget(params) && !isDisconnectedTarget(params)
? donateGoldRadialElement
: attackMenuElement,
Expand Down
1 change: 1 addition & 0 deletions src/core/GameRunner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,7 @@ export class GameRunner {
canSendEmoji: player.canSendEmoji(other),
canTarget: player.canTarget(other),
canSendAllianceRequest: player.canSendAllianceRequest(other),
canExtendAlliance: player.canExtendAlliance(other),
canBreakAlliance: player.isAlliedWith(other),
canDonateGold: player.canDonateGold(other),
canDonateTroops: player.canDonateTroops(other),
Expand Down
7 changes: 7 additions & 0 deletions src/core/game/AllianceImpl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,13 @@ export class AllianceImpl implements MutableAlliance {
);
}

agreedToExtend(player: Player): boolean {
return (
(this.requestor_ === player && this.extensionRequestedRequestor_) ||
(this.recipient_ === player && this.extensionRequestedRecipient_)
);
}

public id(): number {
return this.id_;
}
Expand Down
4 changes: 4 additions & 0 deletions src/core/game/Game.ts
Original file line number Diff line number Diff line change
Expand Up @@ -450,6 +450,8 @@ export interface MutableAlliance extends Alliance {
id(): number;
extend(): void;
onlyOneAgreedToExtend(): boolean;

agreedToExtend(player: Player): boolean;
}

export class PlayerInfo {
Expand Down Expand Up @@ -658,6 +660,7 @@ export interface Player {
isAlliedWith(other: Player): boolean;
allianceWith(other: Player): MutableAlliance | null;
canSendAllianceRequest(other: Player): boolean;
canExtendAlliance(other: Player): boolean;
breakAlliance(alliance: Alliance): void;
createAllianceRequest(recipient: Player): AllianceRequest | null;
betrayals(): number;
Expand Down Expand Up @@ -858,6 +861,7 @@ export interface PlayerInteraction {
sharedBorder: boolean;
canSendEmoji: boolean;
canSendAllianceRequest: boolean;
canExtendAlliance: boolean;
canBreakAlliance: boolean;
canTarget: boolean;
canDonateGold: boolean;
Expand Down
32 changes: 32 additions & 0 deletions src/core/game/PlayerImpl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -400,6 +400,38 @@ export class PlayerImpl implements Player {
);
}

canExtendAlliance(other: Player): boolean {
if (other === this) {
return false;
}

if (this.isDisconnected() || other.isDisconnected()) {
// Disconnected players are marked as not-friendly even if they are allies,
// so we need to return early if either player is disconnected.
// Otherwise we could end up sending an alliance extension to someone
// we are already allied with.
return false;
}
if (!this.allianceWith(other) || !this.isAlive() || !other.isAlive()) {
return false;
}

const alliance = this.allianceWith(other);

if (!alliance) {
return false;
}

if (
alliance.expiresAt() >
this.mg.ticks() + this.mg.config().allianceExtensionPromptOffset()
) {
return false;
}

return !alliance.agreedToExtend(this);
}

canSendAllianceRequest(other: Player): boolean {
if (other === this) {
return false;
Expand Down
Loading