diff --git a/TODO.txt b/TODO.txt index 00bcf5e26..2c900ff4d 100644 --- a/TODO.txt +++ b/TODO.txt @@ -148,8 +148,9 @@ * BUG: fake humans break alliance too often DONE 9/29/2024 * make fake humans more difficult DONE 9/29/2024 * BUG: make event box work on mobile DONE 9/30/2024 -* BUG: alliance cooldown request -* BUG: alliance expire message after player dies +* BUG: alliance expire message after player dies DONE 9/30/2024 +* BUG: alliance cooldown request DONE 9/30/2024 +* BUG: double tap zooms on mobile * Make fake humans spawn by their country * add request attack other players * make create/break alliance single button diff --git a/src/client/graphics/layers/EventsDisplay.ts b/src/client/graphics/layers/EventsDisplay.ts index 7a5769ead..b88b1bde7 100644 --- a/src/client/graphics/layers/EventsDisplay.ts +++ b/src/client/graphics/layers/EventsDisplay.ts @@ -199,6 +199,9 @@ export class EventsDisplay implements Layer { if (other == null) { return } + if (!myPlayer.isAlive() || !other.isAlive()) { + return + } this.addEvent({ description: `Your alliance with ${other.name()} expired`, type: MessageType.WARN, diff --git a/src/client/graphics/layers/RadialMenu.ts b/src/client/graphics/layers/RadialMenu.ts index ea36c9afb..e0d8d0fa3 100644 --- a/src/client/graphics/layers/RadialMenu.ts +++ b/src/client/graphics/layers/RadialMenu.ts @@ -231,17 +231,13 @@ export class RadialMenu implements Layer { return } - if (myPlayer.pendingAllianceRequestWith(other)) { - return - } - if (myPlayer.isAlliedWith(other)) { this.activateMenuElement(RadialElement.BreakAlliance, () => { this.eventBus.emit( new SendBreakAllianceIntentEvent(myPlayer, other) ) }) - } else { + } else if (!myPlayer.recentOrPendingAllianceRequestWith(other)) { this.activateMenuElement(RadialElement.RequestAlliance, () => { this.eventBus.emit( new SendAllianceRequestIntentEvent(myPlayer, other) diff --git a/src/core/configuration/Config.ts b/src/core/configuration/Config.ts index 87ba20d46..0c7385bcf 100644 --- a/src/core/configuration/Config.ts +++ b/src/core/configuration/Config.ts @@ -48,6 +48,7 @@ export interface Config { boatMaxDistance(): number boatMaxNumber(): number allianceDuration(): Tick + allianceRequestCooldown(): Tick } export interface Theme { diff --git a/src/core/configuration/DefaultConfig.ts b/src/core/configuration/DefaultConfig.ts index af17fb24b..2da9a93cf 100644 --- a/src/core/configuration/DefaultConfig.ts +++ b/src/core/configuration/DefaultConfig.ts @@ -7,8 +7,11 @@ import {pastelTheme} from "./PastelTheme"; export class DefaultConfig implements Config { + allianceRequestCooldown(): Tick { + return 30 * 10 + } allianceDuration(): Tick { - return 20 * 100 + return 200 * 10 } percentageTilesOwnedToWin(): number { return 95 diff --git a/src/core/configuration/DevConfig.ts b/src/core/configuration/DevConfig.ts index fd9f08618..03c696189 100644 --- a/src/core/configuration/DevConfig.ts +++ b/src/core/configuration/DevConfig.ts @@ -20,7 +20,7 @@ export const devConfig = new class extends DefaultConfig { } // numBots(): number { - // return 1000 + // return 0 // } // allianceDuration(): Tick { @@ -28,7 +28,7 @@ export const devConfig = new class extends DefaultConfig { // } // numFakeHumans(gameID: GameID): number { - // return 50 + // return 1 // } // startTroops(playerInfo: PlayerInfo): number { diff --git a/src/core/execution/alliance/AllianceRequestExecution.ts b/src/core/execution/alliance/AllianceRequestExecution.ts index 7a0c0492b..588e0b0fc 100644 --- a/src/core/execution/alliance/AllianceRequestExecution.ts +++ b/src/core/execution/alliance/AllianceRequestExecution.ts @@ -17,6 +17,8 @@ export class AllianceRequestExecution implements Execution { tick(ticks: number): void { if (this.requestor.isAlliedWith(this.recipient)) { console.warn('already allied') + } else if (this.requestor.recentOrPendingAllianceRequestWith(this.recipient)) { + console.warn('recent or pending alliance request') } else { this.requestor.createAllianceRequest(this.recipient) } diff --git a/src/core/game/AllianceRequestImpl.ts b/src/core/game/AllianceRequestImpl.ts index 75469f4aa..54001c5df 100644 --- a/src/core/game/AllianceRequestImpl.ts +++ b/src/core/game/AllianceRequestImpl.ts @@ -1,4 +1,4 @@ -import {MutableAllianceRequest, Player} from "./Game"; +import {MutableAllianceRequest, Player, Tick} from "./Game"; import {GameImpl} from "./GameImpl"; @@ -14,6 +14,10 @@ export class AllianceRequestImpl implements MutableAllianceRequest { return this.recipient_; } + createdAt(): Tick { + return this.tickCreated + } + accept(): void { this.game.acceptAllianceRequest(this) } diff --git a/src/core/game/Game.ts b/src/core/game/Game.ts index fcc0e72d6..96142795e 100644 --- a/src/core/game/Game.ts +++ b/src/core/game/Game.ts @@ -52,6 +52,7 @@ export interface Execution extends ExecutionView { export interface AllianceRequest { requestor(): Player recipient(): Player + createdAt(): Tick } export interface MutableAllianceRequest extends AllianceRequest { @@ -144,7 +145,8 @@ export interface Player { alliances(): Alliance[] isAlliedWith(other: Player): boolean allianceWith(other: Player): Alliance | null - pendingAllianceRequestWith(other: Player): boolean + // Includes recent requests that are in cooldown + recentOrPendingAllianceRequestWith(other: Player): boolean isTraitor(): boolean toString(): string } diff --git a/src/core/game/GameImpl.ts b/src/core/game/GameImpl.ts index da1ec07ee..89d762fc3 100644 --- a/src/core/game/GameImpl.ts +++ b/src/core/game/GameImpl.ts @@ -73,12 +73,14 @@ export class GameImpl implements MutableGame { acceptAllianceRequest(request: AllianceRequestImpl) { this.allianceRequests = this.allianceRequests.filter(ar => ar != request) const alliance = new AllianceImpl(this, request.requestor() as PlayerImpl, request.recipient() as PlayerImpl, this._ticks) - this.alliances_.push(alliance) + this.alliances_.push(alliance); + (request.requestor() as PlayerImpl).pastOutgoingAllianceRequests.push(request) this.eventBus.emit(new AllianceRequestReplyEvent(request, true)) } rejectAllianceRequest(request: AllianceRequestImpl) { - this.allianceRequests = this.allianceRequests.filter(ar => ar != request) + this.allianceRequests = this.allianceRequests.filter(ar => ar != request); + (request.requestor() as PlayerImpl).pastOutgoingAllianceRequests.push(request) this.eventBus.emit(new AllianceRequestReplyEvent(request, false)) } diff --git a/src/core/game/PlayerImpl.ts b/src/core/game/PlayerImpl.ts index 012cd2793..b6fea5825 100644 --- a/src/core/game/PlayerImpl.ts +++ b/src/core/game/PlayerImpl.ts @@ -18,6 +18,8 @@ export class PlayerImpl implements MutablePlayer { private _name: string; + public pastOutgoingAllianceRequests: AllianceRequest[] = [] + constructor(private gs: GameImpl, private readonly playerInfo: PlayerInfo, private _troops) { this._name = playerInfo.name; } @@ -134,11 +136,24 @@ export class PlayerImpl implements MutablePlayer { return this.alliances().find(a => a.recipient() == other || a.requestor() == other) } - - pendingAllianceRequestWith(other: Player): boolean { - return this.incomingAllianceRequests().find(ar => ar.requestor() == other) != null + recentOrPendingAllianceRequestWith(other: Player): boolean { + const hasPending = this.incomingAllianceRequests().find(ar => ar.requestor() == other) != null || this.outgoingAllianceRequests().find(ar => ar.recipient() == other) != null + if (hasPending) { + return true + } + const recent = this.pastOutgoingAllianceRequests + .filter(ar => ar.recipient() == other) + .sort((a, b) => b.createdAt() - a.createdAt()) + + if (recent.length == 0) { + return false + } + + const delta = this.gs.ticks() - recent[0].createdAt() + + return delta < this.gs.config().allianceRequestCooldown() } breakAlliance(alliance: Alliance): void {