mirror of
https://github.com/openfrontio/OpenFrontIO.git
synced 2026-06-24 13:52:45 +00:00
Show player relations in player info overlay
This commit is contained in:
@@ -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`<div class="type-label">Attitude: ${player.relation(myPlayer)}</div>`;
|
||||
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`<div class="type-label">Attitude: <span class="${classType}">${relationName}</span></div>`;
|
||||
}
|
||||
return html`
|
||||
<div class="info-content">
|
||||
@@ -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;
|
||||
}
|
||||
`;
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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}`)
|
||||
}
|
||||
|
||||
@@ -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}`)
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
+24
-12
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user