diff --git a/src/client/graphics/layers/PlayerInfoOverlay.ts b/src/client/graphics/layers/PlayerInfoOverlay.ts index f04b7032e..4a709fc24 100644 --- a/src/client/graphics/layers/PlayerInfoOverlay.ts +++ b/src/client/graphics/layers/PlayerInfoOverlay.ts @@ -1,7 +1,7 @@ import { LitElement, html, css } from 'lit'; import { customElement, property, state } from 'lit/decorators.js'; import { Layer } from './Layer'; -import { Game, GameType, Player, PlayerType, Unit, UnitType } from '../../../core/game/Game'; +import { Game, GameType, Player, PlayerType, Relation, Unit, UnitType } from '../../../core/game/Game'; import { ClientID } from '../../../core/Schemas'; import { EventBus } from '../../../core/EventBus'; import { TransformHandler } from '../TransformHandler'; @@ -114,8 +114,28 @@ export class PlayerInfoOverlay extends LitElement implements Layer { const isAlly = (myPlayer?.isAlliedWith(player) || player == this.myPlayer()) ?? false; let relation = null if (player.type() == PlayerType.FakeHuman && myPlayer != null) { - // Don't create an HTML string, let Lit handle the templating - relation = html`
Attitude: ${player.relation(myPlayer)}
`; + let classType = '' + let relationName = '' + switch (player.relation(myPlayer)) { + case Relation.Hostile: + classType = 'hostile' + relationName = 'Hostile' + break + case Relation.Distrustful: + classType = 'distrustful' + relationName = 'Distrustful' + break + case Relation.Neutral: + classType = 'neutral' + relationName = 'Neutral' + break + case Relation.Friendly: + classType = 'friendly' + relationName = 'Friendly' + break + } + + relation = html`
Attitude: ${relationName}
`; } return html`
@@ -273,6 +293,19 @@ export class PlayerInfoOverlay extends LitElement implements Layer { .type-label { font-size: 12px; } + + } + .hostile { + color: #ff4444; + } + .distrustful { + color: #ff8888; + } + .neutral { + color: #ffffff; + } + .friendly { + color: #4CAF50; } `; } \ No newline at end of file diff --git a/src/core/execution/AttackExecution.ts b/src/core/execution/AttackExecution.ts index 033d45ab7..e9d6208ae 100644 --- a/src/core/execution/AttackExecution.ts +++ b/src/core/execution/AttackExecution.ts @@ -101,7 +101,7 @@ export class AttackExecution implements Execution { // No updates should happen in init. this.breakAlliance = true } - this.target.updateRelation(this._owner, -500) + this.target.updateRelation(this._owner, -80) } } diff --git a/src/core/execution/DonateExecution.ts b/src/core/execution/DonateExecution.ts index c737f1bca..5c93b41f2 100644 --- a/src/core/execution/DonateExecution.ts +++ b/src/core/execution/DonateExecution.ts @@ -1,5 +1,5 @@ import { consolex } from "../Consolex"; -import {AllPlayers, Execution, MutableGame, MutablePlayer, PlayerID} from "../game/Game"; +import { Execution, MutableGame, MutablePlayer, PlayerID } from "../game/Game"; export class DonateExecution implements Execution { @@ -26,6 +26,7 @@ export class DonateExecution implements Execution { tick(ticks: number): void { if (this.sender.canDonate(this.recipient)) { this.sender.donate(this.recipient, this.troops) + this.recipient.updateRelation(this.sender, 50) } else { consolex.warn(`cannot send tropps from ${this.sender} to ${this.recipient}`) } diff --git a/src/core/execution/EmojiExecution.ts b/src/core/execution/EmojiExecution.ts index e5dbcb782..04d753ab6 100644 --- a/src/core/execution/EmojiExecution.ts +++ b/src/core/execution/EmojiExecution.ts @@ -24,7 +24,7 @@ export class EmojiExecution implements Execution { if (this.requestor.canSendEmoji(this.recipient)) { this.requestor.sendEmoji(this.recipient, this.emoji) if (this.emoji == "🖕" && this.recipient != AllPlayers && this.recipient.type() == PlayerType.FakeHuman) { - this.recipient.updateRelation(this.requestor, -10000) + this.recipient.updateRelation(this.requestor, -100) } } else { consolex.warn(`cannot send emoji from ${this.requestor} to ${this.recipient}`) diff --git a/src/core/execution/FakeHumanExecution.ts b/src/core/execution/FakeHumanExecution.ts index edaaad30d..b8eae57bd 100644 --- a/src/core/execution/FakeHumanExecution.ts +++ b/src/core/execution/FakeHumanExecution.ts @@ -1,4 +1,4 @@ -import { AllianceRequest, Cell, Execution, MutableGame, MutablePlayer, Player, PlayerInfo, PlayerType, TerrainType, TerraNullius, Tile, UnitType } from "../game/Game" +import { AllianceRequest, Cell, Execution, MutableGame, MutablePlayer, Player, PlayerInfo, PlayerType, Relation, TerrainType, TerraNullius, Tile, UnitType } from "../game/Game" import { PseudoRandom } from "../PseudoRandom" import { and, bfs, calculateBoundingBox, dist, euclDist, manhattanDist, simpleHash } from "../Util"; import { AttackExecution } from "./AttackExecution"; @@ -144,12 +144,12 @@ export class FakeHumanExecution implements Execution { } const target = this.player.allies() - .filter(ally => this.player.relation(ally) > 0) + .filter(ally => this.player.relation(ally) >= Relation.Neutral) .filter(ally => ally.targets().length > 0) .map(ally => ({ ally: ally, t: ally.targets() }))[0] ?? null if (target != null) { - this.player.updateRelation(target.ally, -2000) + this.player.updateRelation(target.ally, -20) this.enemy = target.t[0] this.lastEnemyUpdateTick = this.mg.ticks() this.mg.addExecution(new EmojiExecution(this.player.id(), target.ally.id(), "👍")) @@ -157,7 +157,7 @@ export class FakeHumanExecution implements Execution { if (this.enemy == null) { const mostHated = this.player.allRelationsSorted()[0] ?? null - if (mostHated != null && mostHated.relation < - 2000) { + if (mostHated != null && mostHated.relation == Relation.Hostile) { this.enemy = mostHated.player this.lastEnemyUpdateTick = this.mg.ticks() this.mg.addExecution( @@ -323,7 +323,7 @@ export class FakeHumanExecution implements Execution { this.replyToAllianceRequest(req, false) continue } - if (this.player.relation(req.requestor()) < 0) { + if (this.player.relation(req.requestor()) < Relation.Neutral) { this.replyToAllianceRequest(req, false) continue } diff --git a/src/core/execution/NukeExecution.ts b/src/core/execution/NukeExecution.ts index c3fbafe09..d007c0c97 100644 --- a/src/core/execution/NukeExecution.ts +++ b/src/core/execution/NukeExecution.ts @@ -103,7 +103,7 @@ export class NukeExecution implements Execution { this.player.breakAlliance(alliance) } if (other != this.player) { - other.updateRelation(this.player, -5000) + other.updateRelation(this.player, -100) } } } diff --git a/src/core/execution/TargetPlayerExecution.ts b/src/core/execution/TargetPlayerExecution.ts index 66a8735a0..b88c47e09 100644 --- a/src/core/execution/TargetPlayerExecution.ts +++ b/src/core/execution/TargetPlayerExecution.ts @@ -18,7 +18,7 @@ export class TargetPlayerExecution implements Execution { tick(ticks: number): void { if (this.requestor.canTarget(this.target)) { this.requestor.target(this.target) - this.target.updateRelation(this.requestor, -5000) + this.target.updateRelation(this.requestor, -40) } this.active = false } diff --git a/src/core/execution/alliance/AllianceRequestReplyExecution.ts b/src/core/execution/alliance/AllianceRequestReplyExecution.ts index fd24fbd3d..7e52d6b7c 100644 --- a/src/core/execution/alliance/AllianceRequestReplyExecution.ts +++ b/src/core/execution/alliance/AllianceRequestReplyExecution.ts @@ -25,8 +25,8 @@ export class AllianceRequestReplyExecution implements Execution { } else { if (this.accept) { request.accept() - this.requestor.updateRelation(this.recipient, 5000) - this.recipient.updateRelation(this.requestor, 5000) + this.requestor.updateRelation(this.recipient, 100) + this.recipient.updateRelation(this.requestor, 100) } else { request.reject() } diff --git a/src/core/execution/alliance/BreakAllianceExecution.ts b/src/core/execution/alliance/BreakAllianceExecution.ts index a8529bfce..9ed2c552a 100644 --- a/src/core/execution/alliance/BreakAllianceExecution.ts +++ b/src/core/execution/alliance/BreakAllianceExecution.ts @@ -5,12 +5,14 @@ export class BreakAllianceExecution implements Execution { private active = true private requestor: MutablePlayer; private recipient: MutablePlayer + private mg: MutableGame constructor(private requestorID: PlayerID, private recipientID: PlayerID) { } init(mg: MutableGame, ticks: number): void { this.requestor = mg.player(this.requestorID) this.recipient = mg.player(this.recipientID) + this.mg = mg } tick(ticks: number): void { @@ -19,7 +21,12 @@ export class BreakAllianceExecution implements Execution { consolex.warn('cant break alliance, not allied') } else { this.requestor.breakAlliance(alliance) - this.recipient.updateRelation(this.requestor, -5000) + this.recipient.updateRelation(this.requestor, -200) + for (const player of this.mg.players()) { + if (player != this.requestor) { + player.updateRelation(this.requestor, -40) + } + } } this.active = false } diff --git a/src/core/game/Game.ts b/src/core/game/Game.ts index 05cd08a08..b62db108b 100644 --- a/src/core/game/Game.ts +++ b/src/core/game/Game.ts @@ -53,6 +53,13 @@ export enum UnitType { City = "City" } +export enum Relation { + Hostile = 0, + Distrustful = 1, + Neutral = 2, + Friendly = 3 +} + export class Nation { constructor( public readonly name: string, @@ -242,9 +249,9 @@ export interface Player { // TODO: why can't I have "canSendAllyRequest" function instead? recentOrPendingAllianceRequestWith(other: Player): boolean // How this player feels about other player. - relation(other: Player): number + relation(other: Player): Relation // Sorted from most hated to most liked - allRelationsSorted(): { player: Player, relation: number }[] + allRelationsSorted(): { player: Player, relation: Relation }[] isTraitor(): boolean canTarget(other: Player): boolean // Targets for this player diff --git a/src/core/game/PlayerImpl.ts b/src/core/game/PlayerImpl.ts index fab9a6987..f344aa9a9 100644 --- a/src/core/game/PlayerImpl.ts +++ b/src/core/game/PlayerImpl.ts @@ -1,4 +1,4 @@ -import { MutablePlayer, Tile, PlayerInfo, PlayerID, PlayerType, Player, TerraNullius, Cell, Execution, AllianceRequest, MutableAllianceRequest, MutableAlliance, Alliance, Tick, TargetPlayerEvent, EmojiMessage, EmojiMessageEvent, AllPlayers, Gold, UnitType, Unit, MutableUnit } from "./Game"; +import { MutablePlayer, Tile, PlayerInfo, PlayerID, PlayerType, Player, TerraNullius, Cell, Execution, AllianceRequest, MutableAllianceRequest, MutableAlliance, Alliance, Tick, TargetPlayerEvent, EmojiMessage, EmojiMessageEvent, AllPlayers, Gold, UnitType, Unit, MutableUnit, Relation } from "./Game"; import { ClientID } from "../Schemas"; import { assertNever, bfs, closestOceanShoreFromPlayer, dist, distSortUnit, manhattanDist, manhattanDistWrapped, processName, simpleHash, sourceDstOceanShore, within } from "../Util"; import { CellString, GameImpl } from "./GameImpl"; @@ -200,19 +200,33 @@ export class PlayerImpl implements MutablePlayer { return this.gs.createAllianceRequest(this, recipient as MutablePlayer) } - relation(other: Player): number { + relation(other: Player): Relation { if (other == this) { throw new Error(`cannot get relation with self: ${this}`) } if (this.relations.has(other)) { - return this.relations.get(other) + return this.relationFromValue(this.relations.get(other)) } - return 0 + return Relation.Neutral } - allRelationsSorted(): { player: Player, relation: number }[] { + private relationFromValue(relationValue: number): Relation { + if (relationValue < -50) { + return Relation.Hostile + } + if (relationValue < 0) { + return Relation.Distrustful + } + if (relationValue < 50) { + return Relation.Neutral + } + return Relation.Friendly + } + + allRelationsSorted(): { player: Player, relation: Relation }[] { return Array.from(this.relations, ([k, v]) => ({ player: k, relation: v })) .sort((a, b) => a.relation - b.relation) + .map(r => ({ player: r.player, relation: this.relationFromValue(r.relation) })) } updateRelation(other: Player, delta: number): void { @@ -223,18 +237,16 @@ export class PlayerImpl implements MutablePlayer { if (this.relations.has(other)) { relation = this.relations.get(other) } - const newRelation = within(relation + delta, -10000, 10000) + const newRelation = within(relation + delta, -100, 100) this.relations.set(other, newRelation) } decayRelations() { this.relations.forEach((r: number, p: Player) => { - // Have relationships decay over time - if (r > 1) { - r -= 1 - } else if (r < -1) { - r += 1 - } else { + const sign = -1 * Math.sign(r) + const delta = .05 + r += sign * delta + if (Math.abs(r) < delta * 2) { r = 0 } this.relations.set(p, r)