mirror of
https://github.com/openfrontio/OpenFrontIO.git
synced 2026-06-26 17:54:37 +00:00
split Player/Unit from its Views for better separation
This commit is contained in:
+10
-9
@@ -9,6 +9,7 @@ import { UsernameInput } from "./UsernameInput";
|
||||
import { HostLobbyModal as HostPrivateLobbyModal } from "./HostLobbyModal";
|
||||
import { JoinPrivateLobbyModal } from "./JoinPrivateLobbyModal";
|
||||
import { SinglePlayerModal } from "./SinglePlayerModal";
|
||||
import { PlayerView } from "../core/GameView"
|
||||
|
||||
export class PauseGameEvent implements GameEvent {
|
||||
constructor(public readonly paused: boolean) { }
|
||||
@@ -16,23 +17,23 @@ export class PauseGameEvent implements GameEvent {
|
||||
|
||||
export class SendAllianceRequestIntentEvent implements GameEvent {
|
||||
constructor(
|
||||
public readonly requestor: Player,
|
||||
public readonly recipient: Player
|
||||
public readonly requestor: PlayerView,
|
||||
public readonly recipient: PlayerView
|
||||
) { }
|
||||
}
|
||||
|
||||
export class SendBreakAllianceIntentEvent implements GameEvent {
|
||||
constructor(
|
||||
public readonly requestor: Player,
|
||||
public readonly recipient: Player
|
||||
public readonly requestor: PlayerView,
|
||||
public readonly recipient: PlayerView
|
||||
) { }
|
||||
}
|
||||
|
||||
export class SendAllianceReplyIntentEvent implements GameEvent {
|
||||
constructor(
|
||||
// The original alliance requestor
|
||||
public readonly requestor: Player,
|
||||
public readonly recipient: Player,
|
||||
public readonly requestor: PlayerView,
|
||||
public readonly recipient: PlayerView,
|
||||
public readonly accepted: boolean
|
||||
) { }
|
||||
}
|
||||
@@ -73,15 +74,15 @@ export class SendTargetPlayerIntentEvent implements GameEvent {
|
||||
|
||||
export class SendEmojiIntentEvent implements GameEvent {
|
||||
constructor(
|
||||
public readonly recipient: Player | typeof AllPlayers,
|
||||
public readonly recipient: PlayerView | typeof AllPlayers,
|
||||
public readonly emoji: string
|
||||
) { }
|
||||
}
|
||||
|
||||
export class SendDonateIntentEvent implements GameEvent {
|
||||
constructor(
|
||||
public readonly sender: Player,
|
||||
public readonly recipient: Player,
|
||||
public readonly sender: PlayerView,
|
||||
public readonly recipient: PlayerView,
|
||||
public readonly troops: number | null,
|
||||
) { }
|
||||
}
|
||||
|
||||
@@ -31,14 +31,14 @@ export class NameLayer implements Layer {
|
||||
private renderRefreshRate = 500
|
||||
private rand = new PseudoRandom(10)
|
||||
private renders: RenderInfo[] = []
|
||||
private seenPlayers: Set<Player> = new Set()
|
||||
private seenPlayers: Set<PlayerView> = new Set()
|
||||
private traitorIconImage: HTMLImageElement;
|
||||
private allianceIconImage: HTMLImageElement;
|
||||
private targetIconImage: HTMLImageElement;
|
||||
private crownIconImage: HTMLImageElement;
|
||||
private container: HTMLDivElement
|
||||
private myPlayer: Player | null = null
|
||||
private firstPlace: Player | null = null
|
||||
private myPlayer: PlayerView | null = null
|
||||
private firstPlace: PlayerView | null = null
|
||||
|
||||
constructor(private game: GameView, private theme: Theme, private transformHandler: TransformHandler, private clientID: ClientID) {
|
||||
this.traitorIconImage = new Image();
|
||||
@@ -115,7 +115,7 @@ export class NameLayer implements Layer {
|
||||
)
|
||||
}
|
||||
|
||||
private createPlayerElement(player: Player): HTMLDivElement {
|
||||
private createPlayerElement(player: PlayerView): HTMLDivElement {
|
||||
const element = document.createElement('div')
|
||||
element.style.position = 'absolute'
|
||||
element.style.display = 'flex'
|
||||
@@ -281,7 +281,7 @@ export class NameLayer implements Layer {
|
||||
return icon
|
||||
}
|
||||
|
||||
private getPlayer(): Player | null {
|
||||
private getPlayer(): PlayerView | null {
|
||||
if (this.myPlayer != null) {
|
||||
return this.myPlayer
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ import { ClientID } from '../../../core/Schemas';
|
||||
import { EventBus } from '../../../core/EventBus';
|
||||
import { TransformHandler } from '../TransformHandler';
|
||||
import { MouseMoveEvent } from '../../InputHandler';
|
||||
import { GameView, PlayerView } from '../../../core/GameView';
|
||||
import { GameView, PlayerView, UnitView } from '../../../core/GameView';
|
||||
import { TileRef } from '../../../core/game/GameMap';
|
||||
import { PauseGameEvent } from '../../Transport';
|
||||
import { renderNumber, renderTroops } from '../../Utils';
|
||||
@@ -20,7 +20,7 @@ function euclideanDistWorld(coord: { x: number, y: number }, tileRef: TileRef, g
|
||||
}
|
||||
|
||||
function distSortUnitWorld(coord: { x: number, y: number }, game: GameView) {
|
||||
return (a: Unit, b: Unit) => {
|
||||
return (a: Unit | UnitView, b: Unit | UnitView) => {
|
||||
const distA = euclideanDistWorld(coord, a.tile(), game);
|
||||
const distB = euclideanDistWorld(coord, b.tile(), game);
|
||||
return distA - distB;
|
||||
@@ -42,13 +42,13 @@ export class PlayerInfoOverlay extends LitElement implements Layer {
|
||||
public transform!: TransformHandler;
|
||||
|
||||
@state()
|
||||
private player: Player | null = null;
|
||||
private player: PlayerView | null = null;
|
||||
|
||||
@state()
|
||||
private playerProfile: PlayerProfile | null = null;
|
||||
|
||||
@state()
|
||||
private unit: Unit | null = null;
|
||||
private unit: UnitView | null = null;
|
||||
|
||||
@state()
|
||||
private showPauseButton: boolean = true;
|
||||
@@ -92,8 +92,8 @@ export class PlayerInfoOverlay extends LitElement implements Layer {
|
||||
const owner = this.game.owner(tile);
|
||||
|
||||
if (owner && owner.isPlayer()) {
|
||||
this.player = owner;
|
||||
(this.player as PlayerView).profile().then(p => {
|
||||
this.player = owner as PlayerView;
|
||||
this.player.profile().then(p => {
|
||||
this.playerProfile = p;
|
||||
});
|
||||
this.setVisible(true);
|
||||
@@ -135,14 +135,14 @@ export class PlayerInfoOverlay extends LitElement implements Layer {
|
||||
this.requestUpdate();
|
||||
}
|
||||
|
||||
private myPlayer(): Player | null {
|
||||
private myPlayer(): PlayerView | null {
|
||||
if (!this.game) {
|
||||
return null;
|
||||
}
|
||||
return this.game.playerByClientID(this.clientID);
|
||||
}
|
||||
|
||||
private renderPlayerInfo(player: Player) {
|
||||
private renderPlayerInfo(player: PlayerView) {
|
||||
const myPlayer = this.myPlayer();
|
||||
const isAlly = myPlayer?.isAlliedWith(player)
|
||||
let relationHtml = null;
|
||||
@@ -181,7 +181,7 @@ export class PlayerInfoOverlay extends LitElement implements Layer {
|
||||
`;
|
||||
}
|
||||
|
||||
private renderUnitInfo(unit: Unit) {
|
||||
private renderUnitInfo(unit: UnitView) {
|
||||
const isAlly = (unit.owner() == this.myPlayer() || this.myPlayer()?.isAlliedWith(unit.owner())) ?? false;
|
||||
return html`
|
||||
<div class="info-content">
|
||||
|
||||
@@ -7,7 +7,7 @@ import anchorIcon from '../../../../resources/images/AnchorIcon.png';
|
||||
import missileSiloIcon from '../../../../resources/images/MissileSiloUnit.png';
|
||||
import shieldIcon from '../../../../resources/images/ShieldIcon.png';
|
||||
import cityIcon from '../../../../resources/images/CityIcon.png';
|
||||
import { GameView } from "../../../core/GameView";
|
||||
import { GameView, UnitView } from "../../../core/GameView";
|
||||
import { Cell, GameUpdateType, Unit, UnitType } from "../../../core/game/Game";
|
||||
import { euclDistFN } from "../../../core/game/GameMap";
|
||||
|
||||
@@ -109,7 +109,7 @@ export class StructureLayer implements Layer {
|
||||
return unitType in this.unitConfigs;
|
||||
}
|
||||
|
||||
private handleUnitRendering(unit: Unit) {
|
||||
private handleUnitRendering(unit: UnitView) {
|
||||
const unitType = unit.type();
|
||||
if (!this.isUnitTypeSupported(unitType)) return;
|
||||
|
||||
@@ -157,7 +157,7 @@ export class StructureLayer implements Layer {
|
||||
startY: number,
|
||||
width: number,
|
||||
height: number,
|
||||
unit: Unit
|
||||
unit: UnitView
|
||||
) {
|
||||
for (let y = 0; y < height; y++) {
|
||||
for (let x = 0; x < width; x++) {
|
||||
|
||||
@@ -5,7 +5,7 @@ import { Layer } from "./Layer";
|
||||
import { EventBus } from "../../../core/EventBus";
|
||||
import { AlternateViewEvent } from "../../InputHandler";
|
||||
import { ClientID } from "../../../core/Schemas";
|
||||
import { GameView } from "../../../core/GameView";
|
||||
import { GameView, PlayerView, UnitView } from "../../../core/GameView";
|
||||
import { euclDistFN, manhattanDistFN, TileRef } from "../../../core/game/GameMap";
|
||||
|
||||
enum Relationship {
|
||||
@@ -18,15 +18,15 @@ export class UnitLayer implements Layer {
|
||||
private canvas: HTMLCanvasElement;
|
||||
private context: CanvasRenderingContext2D;
|
||||
|
||||
private boatToTrail = new Map<Unit, Set<TileRef>>();
|
||||
private boatToTrail = new Map<UnitView, Set<TileRef>>();
|
||||
|
||||
private theme: Theme = null;
|
||||
|
||||
private alternateView = false;
|
||||
|
||||
private myPlayer: Player | null = null;
|
||||
private myPlayer: PlayerView | null = null;
|
||||
|
||||
private oldShellTile = new Map<Unit, TileRef>();
|
||||
private oldShellTile = new Map<UnitView, TileRef>();
|
||||
|
||||
constructor(private game: GameView, private eventBus: EventBus, private clientID: ClientID) {
|
||||
this.theme = game.config().theme();
|
||||
@@ -77,7 +77,7 @@ export class UnitLayer implements Layer {
|
||||
}
|
||||
}
|
||||
|
||||
private relationship(unit: Unit): Relationship {
|
||||
private relationship(unit: UnitView): Relationship {
|
||||
if (this.myPlayer == null) {
|
||||
return Relationship.Enemy;
|
||||
}
|
||||
@@ -90,7 +90,7 @@ export class UnitLayer implements Layer {
|
||||
return Relationship.Enemy;
|
||||
}
|
||||
|
||||
onUnitEvent(unit: Unit) {
|
||||
onUnitEvent(unit: UnitView) {
|
||||
switch (unit.type()) {
|
||||
case UnitType.TransportShip:
|
||||
this.handleBoatEvent(unit);
|
||||
@@ -114,7 +114,7 @@ export class UnitLayer implements Layer {
|
||||
}
|
||||
}
|
||||
|
||||
private handleDestroyerEvent(unit: Unit) {
|
||||
private handleDestroyerEvent(unit: UnitView) {
|
||||
const rel = this.relationship(unit);
|
||||
|
||||
// Clear previous area
|
||||
@@ -149,7 +149,7 @@ export class UnitLayer implements Layer {
|
||||
}
|
||||
}
|
||||
|
||||
private handleBattleshipEvent(unit: Unit) {
|
||||
private handleBattleshipEvent(unit: UnitView) {
|
||||
const rel = this.relationship(unit);
|
||||
|
||||
// Clear previous area
|
||||
@@ -195,7 +195,7 @@ export class UnitLayer implements Layer {
|
||||
}
|
||||
}
|
||||
|
||||
private handleShellEvent(unit: Unit) {
|
||||
private handleShellEvent(unit: UnitView) {
|
||||
const rel = this.relationship(unit);
|
||||
|
||||
// Clear current and previous positions
|
||||
@@ -227,7 +227,7 @@ export class UnitLayer implements Layer {
|
||||
);
|
||||
}
|
||||
|
||||
private handleNuke(unit: Unit) {
|
||||
private handleNuke(unit: UnitView) {
|
||||
const rel = this.relationship(unit);
|
||||
|
||||
// Clear previous area
|
||||
@@ -249,7 +249,7 @@ export class UnitLayer implements Layer {
|
||||
}
|
||||
}
|
||||
|
||||
private handleTradeShipEvent(unit: Unit) {
|
||||
private handleTradeShipEvent(unit: UnitView) {
|
||||
const rel = this.relationship(unit);
|
||||
|
||||
// Clear previous area
|
||||
@@ -282,7 +282,7 @@ export class UnitLayer implements Layer {
|
||||
}
|
||||
}
|
||||
|
||||
private handleBoatEvent(unit: Unit) {
|
||||
private handleBoatEvent(unit: UnitView) {
|
||||
const rel = this.relationship(unit);
|
||||
|
||||
if (!this.boatToTrail.has(unit)) {
|
||||
|
||||
@@ -38,7 +38,7 @@ const buildTable: BuildItemDisplay[][] = [
|
||||
export class BuildMenu extends LitElement {
|
||||
public game: GameView;
|
||||
public eventBus: EventBus;
|
||||
private myPlayer: Player;
|
||||
private myPlayer: PlayerView;
|
||||
private clickedCell: Cell;
|
||||
private playerActions: PlayerActions | null
|
||||
|
||||
|
||||
@@ -263,7 +263,7 @@ export class RadialMenu implements Layer {
|
||||
const canSendEmojiToAllPlayers = this.g.ownerID(tile) == myPlayer.smallID() && actions.canSendEmojiAllPlayers
|
||||
if (canSendEmojiToPlayer || canSendEmojiToAllPlayers) {
|
||||
this.activateMenuElement(Slot.Emoji, "#00a6a4", emojiIcon, () => {
|
||||
const target = this.g.owner(tile) == myPlayer ? AllPlayers : (this.g.owner(tile) as Player)
|
||||
const target = this.g.owner(tile) == myPlayer ? AllPlayers : (this.g.owner(tile) as PlayerView)
|
||||
this.emojiTable.onEmojiClicked = (emoji: string) => {
|
||||
this.emojiTable.hideTable()
|
||||
this.eventBus.emit(new SendEmojiIntentEvent(target, emoji))
|
||||
@@ -290,7 +290,7 @@ export class RadialMenu implements Layer {
|
||||
if (!this.g.hasOwner(tile)) {
|
||||
return
|
||||
}
|
||||
const other = this.g.owner(tile) as Player
|
||||
const other = this.g.owner(tile) as PlayerView
|
||||
|
||||
|
||||
if (actions?.interaction.canDonate) {
|
||||
|
||||
+4
-53
@@ -6,7 +6,7 @@ import { TerraNulliusImpl } from './game/TerraNulliusImpl';
|
||||
import { WorkerClient } from './worker/WorkerClient';
|
||||
import { GameMap, GameMapImpl, TileRef, TileUpdate } from './game/GameMap';
|
||||
|
||||
export class UnitView implements Unit {
|
||||
export class UnitView {
|
||||
public _wasUpdated = true
|
||||
public lastPos: MapPos[] = []
|
||||
|
||||
@@ -62,12 +62,9 @@ export class UnitView implements Unit {
|
||||
}
|
||||
}
|
||||
|
||||
export class PlayerView implements Player {
|
||||
export class PlayerView {
|
||||
|
||||
constructor(private game: GameView, public data: PlayerUpdate, public nameData: NameViewData) { }
|
||||
borderTiles(): ReadonlySet<TileRef> {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
|
||||
async actions(tile: TileRef): Promise<PlayerActions> {
|
||||
return this.game.worker.playerInteraction(this.id(), this.game.x(tile), this.game.y(tile))
|
||||
@@ -80,9 +77,6 @@ export class PlayerView implements Player {
|
||||
smallID(): number {
|
||||
return this.data.smallID
|
||||
}
|
||||
lastTileChange(): Tick {
|
||||
return 0
|
||||
}
|
||||
name(): string {
|
||||
return this.data.name
|
||||
}
|
||||
@@ -129,67 +123,24 @@ export class PlayerView implements Player {
|
||||
return this.data.troops
|
||||
}
|
||||
|
||||
isAlliedWith(other: Player): boolean {
|
||||
isAlliedWith(other: PlayerView): boolean {
|
||||
return this.data.allies.some(n => other.smallID() == n)
|
||||
}
|
||||
allianceWith(other: Player): Alliance | null {
|
||||
return null
|
||||
}
|
||||
units(...types: UnitType[]): Unit[] {
|
||||
return []
|
||||
}
|
||||
sharesBorderWith(other: Player | TerraNullius): boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
incomingAllianceRequests(): AllianceRequest[] {
|
||||
return []
|
||||
}
|
||||
outgoingAllianceRequests(): AllianceRequest[] {
|
||||
return []
|
||||
}
|
||||
alliances(): Alliance[] {
|
||||
return []
|
||||
}
|
||||
recentOrPendingAllianceRequestWith(other: Player): boolean {
|
||||
return false
|
||||
}
|
||||
relation(other: Player): Relation {
|
||||
return Relation.Neutral
|
||||
}
|
||||
|
||||
profile(): Promise<PlayerProfile> {
|
||||
return this.game.worker.playerProfile(this.smallID())
|
||||
}
|
||||
|
||||
allRelationsSorted(): { player: Player; relation: Relation; }[] {
|
||||
return []
|
||||
}
|
||||
transitiveTargets(): Player[] {
|
||||
transitiveTargets(): PlayerView[] {
|
||||
return [...this.targets(), ...this.allies().flatMap(p => p.targets())]
|
||||
}
|
||||
|
||||
isTraitor(): boolean {
|
||||
return this.data.isTraitor
|
||||
}
|
||||
canTarget(other: Player): boolean {
|
||||
return false
|
||||
}
|
||||
toString(): string {
|
||||
return ''
|
||||
}
|
||||
canSendEmoji(recipient: Player | typeof AllPlayers): boolean {
|
||||
return false
|
||||
}
|
||||
outgoingEmojis(): EmojiMessage[] {
|
||||
return this.data.outgoingEmojis
|
||||
}
|
||||
canDonate(recipient: Player): boolean {
|
||||
return false
|
||||
}
|
||||
canBuild(type: UnitType, targetTile: TileRef): TileRef | false {
|
||||
return false
|
||||
}
|
||||
info(): PlayerInfo {
|
||||
return new PlayerInfo(this.name(), this.type(), this.clientID(), this.id())
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import { GameConfig } from "../Schemas";
|
||||
import { DefaultConfig } from "./DefaultConfig";
|
||||
import { DevConfig, DevServerConfig } from "./DevConfig";
|
||||
import { GameMap, TileRef } from "../game/GameMap";
|
||||
import { PlayerView } from "../GameView";
|
||||
|
||||
export enum GameEnv {
|
||||
Dev,
|
||||
@@ -58,8 +59,8 @@ export interface Config {
|
||||
numSpawnPhaseTurns(): number
|
||||
|
||||
startManpower(playerInfo: PlayerInfo): number
|
||||
populationIncreaseRate(player: Player): number
|
||||
goldAdditionRate(player: Player): number
|
||||
populationIncreaseRate(player: Player | PlayerView): number
|
||||
goldAdditionRate(player: Player | PlayerView): number
|
||||
troopAdjustmentRate(player: Player): number
|
||||
attackTilesPerTick(attckTroops: number, attacker: Player, defender: Player | TerraNullius, numAdjacentTilesWithEnemy: number): number
|
||||
attackLogic(gm: GameMap, attackTroops: number, attacker: Player, defender: Player | TerraNullius, tileToConquer: TileRef): {
|
||||
@@ -68,7 +69,7 @@ export interface Config {
|
||||
tilesPerTickUsed: number
|
||||
}
|
||||
attackAmount(attacker: Player, defender: Player | TerraNullius): number
|
||||
maxPopulation(player: Player): number
|
||||
maxPopulation(player: Player | PlayerView): number
|
||||
cityPopulationIncrease(): number
|
||||
boatAttackAmount(attacker: Player, defender: Player | TerraNullius): number
|
||||
boatMaxDistance(): number
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { Config } from "../configuration/Config"
|
||||
import { GameEvent } from "../EventBus"
|
||||
import { PlayerView } from "../GameView"
|
||||
import { ClientID, GameConfig, GameID } from "../Schemas"
|
||||
import { GameMap, GameMapImpl, TileRef, TileUpdate } from "./GameMap"
|
||||
|
||||
@@ -46,7 +47,7 @@ export enum GameType {
|
||||
}
|
||||
|
||||
export interface UnitInfo {
|
||||
cost: (player: Player) => Gold
|
||||
cost: (player: Player | PlayerView) => Gold
|
||||
// Determines if its owner changes when its tile is conquered.
|
||||
territoryBound: boolean
|
||||
maxHealth?: number,
|
||||
|
||||
Reference in New Issue
Block a user