Target player creates target icon

This commit is contained in:
evanpelle
2024-10-02 16:25:13 -07:00
parent 8c81a75a53
commit 2223e40d53
13 changed files with 156 additions and 15 deletions
+10 -1
View File
@@ -11,6 +11,7 @@ export type Intent = SpawnIntent
| AllianceRequestIntent
| AllianceRequestReplyIntent
| BreakAllianceIntent
| TargetPlayerIntent
export type AttackIntent = z.infer<typeof AttackIntentSchema>
export type SpawnIntent = z.infer<typeof SpawnIntentSchema>
@@ -19,6 +20,7 @@ export type UpdateNameIntent = z.infer<typeof UpdateNameIntentSchema>
export type AllianceRequestIntent = z.infer<typeof AllianceRequestIntentSchema>
export type AllianceRequestReplyIntent = z.infer<typeof AllianceRequestReplyIntentSchema>
export type BreakAllianceIntent = z.infer<typeof BreakAllianceIntentSchema>
export type TargetPlayerIntent = z.infer<typeof TargetPlayerIntentSchema>
export type Turn = z.infer<typeof TurnSchema>
@@ -104,6 +106,12 @@ export const BreakAllianceIntentSchema = BaseIntentSchema.extend({
recipient: z.string(),
})
export const TargetPlayerIntentSchema = BaseIntentSchema.extend({
type: z.literal('targetPlayer'),
requestor: z.string(),
target: z.string(),
})
const IntentSchema = z.union([
AttackIntentSchema,
SpawnIntentSchema,
@@ -111,7 +119,8 @@ const IntentSchema = z.union([
UpdateNameIntentSchema,
AllianceRequestIntentSchema,
AllianceRequestReplyIntentSchema,
BreakAllianceIntentSchema
BreakAllianceIntentSchema,
TargetPlayerIntentSchema,
]);
const TurnSchema = z.object({
+2
View File
@@ -49,6 +49,8 @@ export interface Config {
boatMaxNumber(): number
allianceDuration(): Tick
allianceRequestCooldown(): Tick
targetDuration(): Tick
targetCooldown(): Tick
}
export interface Theme {
+6
View File
@@ -7,6 +7,12 @@ import {pastelTheme} from "./PastelTheme";
export class DefaultConfig implements Config {
targetDuration(): Tick {
return 10 * 10
}
targetCooldown(): Tick {
return 30 * 10
}
allianceRequestCooldown(): Tick {
return 30 * 10
}
+9 -11
View File
@@ -1,20 +1,18 @@
import {Tick} from "../game/Game";
import {GameID} from "../Schemas";
import {DefaultConfig} from "./DefaultConfig";
export const devConfig = new class extends DefaultConfig {
percentageTilesOwnedToWin(): number {
return 95
}
numSpawnPhaseTurns(): number {
return 40
}
gameCreationRate(): number {
return 2 * 1000
}
lobbyLifetime(): number {
return 2 * 1000
}
// numSpawnPhaseTurns(): number {
// return 40
// }
// gameCreationRate(): number {
// return 2 * 1000
// }
// lobbyLifetime(): number {
// return 2 * 1000
// }
turnIntervalMs(): number {
return 100
}
+3
View File
@@ -12,6 +12,7 @@ import {simpleHash} from "../Util";
import {AllianceRequestExecution} from "./alliance/AllianceRequestExecution";
import {AllianceRequestReplyExecution} from "./alliance/AllianceRequestReplyExecution";
import {BreakAllianceExecution} from "./alliance/BreakAllianceExecution";
import {TargetPlayerExecution} from "./TargetPlayerExecution";
@@ -64,6 +65,8 @@ export class Executor {
return new AllianceRequestReplyExecution(intent.requestor, intent.recipient, intent.accept)
} else if (intent.type == "breakAlliance") {
return new BreakAllianceExecution(intent.requestor, intent.recipient)
} else if (intent.type == "targetPlayer") {
return new TargetPlayerExecution(intent.requestor, intent.target)
}
else {
throw new Error(`intent type ${intent} not found`)
@@ -0,0 +1,37 @@
import {Execution, MutableGame, MutablePlayer, PlayerID} from "../game/Game";
export class TargetPlayerExecution implements Execution {
private requestor: MutablePlayer
private target: MutablePlayer
private active = true
constructor(private requestorID: PlayerID, private targetID: PlayerID) { }
init(mg: MutableGame, ticks: number): void {
this.requestor = mg.player(this.requestorID)
this.target = mg.player(this.targetID)
}
tick(ticks: number): void {
if (this.requestor.canTarget(this.target)) {
this.requestor.target(this.target)
}
this.active = false
}
owner(): MutablePlayer {
return null
}
isActive(): boolean {
return this.active
}
activeDuringSpawnPhase(): boolean {
return false
}
}
+7
View File
@@ -10,6 +10,13 @@ export class AllianceImpl implements MutableAlliance {
readonly createdAtTick_: Tick,
) { }
other(player: Player): PlayerImpl {
if (this.requestor_ == player) {
return this.recipient_
}
return this.requestor_
}
requestor(): MutablePlayer {
return this.requestor_
}
+10
View File
@@ -64,10 +64,12 @@ export interface Alliance {
requestor(): Player
recipient(): Player
createdAt(): Tick
other(player: Player): Player
}
export interface MutableAlliance extends Alliance {
expire(): void
other(player: Player): MutablePlayer
}
export class PlayerInfo {
@@ -148,6 +150,11 @@ export interface Player {
// Includes recent requests that are in cooldown
recentOrPendingAllianceRequestWith(other: Player): boolean
isTraitor(): boolean
canTarget(other: Player): boolean
// Targets for this player
targets(): Player[]
// Targets of player and all allies.
transitiveTargets(): Player[]
toString(): string
}
@@ -168,6 +175,9 @@ export interface MutablePlayer extends Player {
breakAlliance(alliance: Alliance): void
createAllianceRequest(recipient: Player): MutableAllianceRequest
addBoat(troops: number, tile: Tile, target: Player | TerraNullius): MutableBoat
target(other: Player): void
targets(): MutablePlayer[]
transitiveTargets(): MutablePlayer[]
}
export interface Game {
+34 -1
View File
@@ -1,4 +1,4 @@
import {MutablePlayer, Tile, PlayerInfo, PlayerID, PlayerType, Player, TerraNullius, Cell, MutableGame, Execution, AllianceRequest, MutableAllianceRequest, MutableAlliance, Alliance} from "./Game";
import {MutablePlayer, Tile, PlayerInfo, PlayerID, PlayerType, Player, TerraNullius, Cell, MutableGame, Execution, AllianceRequest, MutableAllianceRequest, MutableAlliance, Alliance, Tick} from "./Game";
import {ClientID} from "../Schemas";
import {simpleHash} from "../Util";
import {CellString, GameImpl} from "./GameImpl";
@@ -7,6 +7,10 @@ import {TileImpl} from "./TileImpl";
import {TerraNulliusImpl} from "./TerraNulliusImpl";
import {threadId} from "worker_threads";
interface Target {
tick: Tick
target: Player
}
export class PlayerImpl implements MutablePlayer {
isTraitor_ = false
@@ -20,6 +24,8 @@ export class PlayerImpl implements MutablePlayer {
public pastOutgoingAllianceRequests: AllianceRequest[] = []
private targets_: Target[] = []
constructor(private gs: GameImpl, private readonly playerInfo: PlayerInfo, private _troops) {
this._name = playerInfo.name;
}
@@ -172,6 +178,33 @@ export class PlayerImpl implements MutablePlayer {
return this.gs.createAllianceRequest(this, recipient)
}
canTarget(other: Player): boolean {
for (const t of this.targets_) {
if (t.target == other) {
if (this.gs.ticks() - t.tick < this.gs.config().targetCooldown()) {
return false
}
}
}
return true
}
target(other: Player): void {
this.targets_.push({tick: this.gs.ticks(), target: other})
}
targets(): PlayerImpl[] {
return this.targets_
.filter(t => this.gs.ticks() - t.tick < this.gs.config().targetDuration())
.map(t => t.target as PlayerImpl)
}
transitiveTargets(): MutablePlayer[] {
const ts = this.alliances().map(a => a.other(this)).flatMap(ally => ally.targets())
ts.push(...this.targets())
return [...new Set(ts)]
}
hash(): number {
return simpleHash(this.id()) * (this.troops() + this.numTilesOwned());
}