mirror of
https://github.com/openfrontio/OpenFrontIO.git
synced 2026-06-21 13:10:42 +00:00
don't render player info on top of exit button, render unit type
This commit is contained in:
@@ -242,6 +242,10 @@
|
||||
* better error logging in server DONE 12/16/2024
|
||||
* store and archive player cookies DONE 12/17/2024
|
||||
* make ips less precise for user safety DONE 12/17/2024
|
||||
* send client logs back to server DONE 12/18/2024
|
||||
* render more info in info overlay
|
||||
* right click brings up player info menu
|
||||
* create new view for enemies & personal units
|
||||
* send client logs back to server DONE 12/17/2024
|
||||
* make info panel merge with X, display more info
|
||||
* right click brings up player info menu
|
||||
|
||||
@@ -68,6 +68,7 @@ export function createRenderer(canvas: HTMLCanvasElement, game: Game, eventBus:
|
||||
playerInfo.eventBus = eventBus
|
||||
playerInfo.clientID = clientID
|
||||
playerInfo.transform = transformHandler
|
||||
playerInfo.game = game
|
||||
|
||||
|
||||
const layers: Layer[] = [
|
||||
|
||||
@@ -6,51 +6,64 @@ import { ClientID } from '../../../core/Schemas';
|
||||
import { EventBus } from '../../../core/EventBus';
|
||||
import { TransformHandler } from '../TransformHandler';
|
||||
import { MouseMoveEvent } from '../../InputHandler';
|
||||
import { dist, distSortUnit, euclideanDist, manhattanDist } from '../../../core/Util';
|
||||
import { euclideanDist, distSortUnit } from '../../../core/Util';
|
||||
import { renderNumber, renderTroops } from '../../Utils';
|
||||
|
||||
@customElement('player-info-overlay')
|
||||
export class PlayerInfoOverlay extends LitElement implements Layer {
|
||||
private game: Game;
|
||||
public clientID: ClientID;
|
||||
public eventBus: EventBus;
|
||||
public transform: TransformHandler;
|
||||
@property({ type: Object })
|
||||
public game!: Game;
|
||||
|
||||
@property({ type: String })
|
||||
public clientID!: ClientID;
|
||||
|
||||
@property({ type: Object })
|
||||
public eventBus!: EventBus;
|
||||
|
||||
@property({ type: Object })
|
||||
public transform!: TransformHandler;
|
||||
|
||||
@state()
|
||||
private selectedType: "player" | "unit" | null = null
|
||||
private player: Player | null = null;
|
||||
|
||||
@state()
|
||||
private player: Player
|
||||
|
||||
@state()
|
||||
private unit: Unit
|
||||
private unit: Unit | null = null;
|
||||
|
||||
@state()
|
||||
private _isVisible: boolean = false;
|
||||
|
||||
init(game: Game) {
|
||||
this.game = game;
|
||||
this.eventBus.on(MouseMoveEvent, e => this.onMouseEvent(e));
|
||||
this.eventBus.on(MouseMoveEvent, (e: MouseMoveEvent) => this.onMouseEvent(e));
|
||||
}
|
||||
|
||||
private onMouseEvent(event: MouseMoveEvent) {
|
||||
this._isVisible = false;
|
||||
this.setVisible(false);
|
||||
this.unit = null;
|
||||
this.player = null;
|
||||
|
||||
const worldCoord = this.transform.screenToWorldCoordinates(event.x, event.y);
|
||||
if (!this.game.isOnMap(worldCoord)) {
|
||||
return;
|
||||
return;
|
||||
}
|
||||
|
||||
const tile = this.game.tile(worldCoord);
|
||||
let owner = tile.owner();
|
||||
if (!owner.isPlayer()) {
|
||||
if (tile.isLand()) {
|
||||
return;
|
||||
const owner = tile.owner();
|
||||
|
||||
if (owner.isPlayer()) {
|
||||
this.player = owner;
|
||||
this.setVisible(true);
|
||||
} else if (!tile.isLand()) {
|
||||
const units = this.game.units()
|
||||
.filter(u => euclideanDist(worldCoord, u.tile().cell()) < 50)
|
||||
.sort(distSortUnit(tile));
|
||||
|
||||
if (units.length > 0) {
|
||||
this.unit = units[0];
|
||||
this.setVisible(true);
|
||||
}
|
||||
const units = this.game.units().filter(u => euclideanDist(worldCoord, u.tile().cell()) < 50).sort(distSortUnit(tile));
|
||||
if (units.length == 0) {
|
||||
return;
|
||||
}
|
||||
owner = units[0].owner();
|
||||
}
|
||||
this._isVisible = true;
|
||||
}
|
||||
|
||||
private onExitButtonClick() {
|
||||
@@ -58,11 +71,14 @@ export class PlayerInfoOverlay extends LitElement implements Layer {
|
||||
}
|
||||
|
||||
tick() {
|
||||
this.unit = this.unit
|
||||
if (this.game.ticks() % 10 == 0) {
|
||||
this.requestUpdate()
|
||||
}
|
||||
// Implementation for Layer interface
|
||||
}
|
||||
|
||||
renderLayer(context: CanvasRenderingContext2D) {
|
||||
// Render any necessary canvas elements
|
||||
// Implementation for Layer interface
|
||||
}
|
||||
|
||||
shouldTransform(): boolean {
|
||||
@@ -74,47 +90,70 @@ export class PlayerInfoOverlay extends LitElement implements Layer {
|
||||
this.requestUpdate();
|
||||
}
|
||||
|
||||
private myPlayer(): Player | null {
|
||||
if (!this.game) {
|
||||
return null;
|
||||
}
|
||||
return this.game.playerByClientID(this.clientID);
|
||||
}
|
||||
|
||||
private renderPlayerInfo(player: Player) {
|
||||
const isAlly = (this.myPlayer()?.isAlliedWith(player) || player == this.myPlayer()) ?? false;
|
||||
return html`
|
||||
<div class="info-content">
|
||||
<div class="player-name ${isAlly ? 'ally' : ''}">${player.name()}</div>
|
||||
<div class="type-label">Troops: ${renderTroops(player.troops())}</div>
|
||||
<div class="type-label">Gold: ${renderNumber(player.gold())}</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
private renderUnitInfo(unit: Unit) {
|
||||
const isAlly = (unit.owner() == this.myPlayer() || this.myPlayer()?.isAlliedWith(unit.owner())) ?? false;
|
||||
return html`
|
||||
<div class="info-content">
|
||||
<div class="player-name ${isAlly ? 'ally' : ''}">${unit.owner().name()}</div>
|
||||
<div class="unit-details">
|
||||
<div class="type-label">${unit.type()}</div>
|
||||
</div>
|
||||
</div>
|
||||
`
|
||||
}
|
||||
|
||||
render() {
|
||||
return html`
|
||||
<div class="container">
|
||||
<div class="controls">
|
||||
<button class="exit-button" @click=${this.onExitButtonClick}>×</button>
|
||||
</div>
|
||||
<div class="player-info ${!this._isVisible ? 'hidden' : ''}">
|
||||
${this.player != null ? this.renderPlayerInfo(this.player) : ''}
|
||||
${this.unit != null ? this.renderUnitInfo(this.unit) : ''}
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
static styles = css`
|
||||
:host {
|
||||
display: block;
|
||||
}
|
||||
.overlay-container {
|
||||
|
||||
.container {
|
||||
position: fixed;
|
||||
top: 10px;
|
||||
right: 10px;
|
||||
z-index: 9999;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-end;
|
||||
}
|
||||
|
||||
.controls {
|
||||
position: relative;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
width: 40px; /* Same as button width */
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.exit-button {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
font-size: 20px;
|
||||
font-weight: bold;
|
||||
background-color: rgba(255, 0, 0, 0.4);
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 50%;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
transition: background-color 0.3s;
|
||||
}
|
||||
.exit-button:hover {
|
||||
background-color: rgba(255, 0, 0, 0.5);
|
||||
}
|
||||
.exit-button:active {
|
||||
background-color: rgba(255, 0, 0, 0.6);
|
||||
align-self: flex-end;
|
||||
margin-bottom: 4px;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.player-info {
|
||||
background-color: rgba(30, 30, 30, 0.7);
|
||||
padding: 8px 12px;
|
||||
@@ -123,84 +162,85 @@ export class PlayerInfoOverlay extends LitElement implements Layer {
|
||||
backdrop-filter: blur(5px);
|
||||
transition: opacity 0.3s ease-in-out, visibility 0.3s ease-in-out;
|
||||
color: white;
|
||||
font-size: 18px;
|
||||
min-width: 120px;
|
||||
text-align: left;
|
||||
font-size: 18px;
|
||||
}
|
||||
.hidden {
|
||||
opacity: 0;
|
||||
visibility: hidden;
|
||||
display: none;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.info-content {
|
||||
margin-top: 8px;
|
||||
}
|
||||
.player-name {
|
||||
font-weight: bold;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.player-name.ally {
|
||||
color: #4CAF50;
|
||||
}
|
||||
|
||||
.type-label {
|
||||
font-size: 14px;
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.unit-details {
|
||||
margin-top: 4px;
|
||||
}
|
||||
|
||||
.health-bar {
|
||||
height: 4px;
|
||||
background-color: rgba(255, 255, 255, 0.2);
|
||||
border-radius: 2px;
|
||||
margin-top: 4px;
|
||||
}
|
||||
|
||||
.health-fill {
|
||||
height: 100%;
|
||||
background-color: #4CAF50;
|
||||
border-radius: 2px;
|
||||
transition: width 0.2s ease-out;
|
||||
}
|
||||
|
||||
.exit-button {
|
||||
background: none;
|
||||
border: none;
|
||||
color: white;
|
||||
font-size: 40px;
|
||||
cursor: pointer;
|
||||
padding: 4px;
|
||||
opacity: 0.7;
|
||||
transition: opacity 0.2s;
|
||||
}
|
||||
|
||||
.exit-button:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.overlay-container {
|
||||
.container {
|
||||
top: 5px;
|
||||
right: 5px;
|
||||
}
|
||||
.controls {
|
||||
width: 30px;
|
||||
}
|
||||
|
||||
.player-info {
|
||||
padding: 6px 10px;
|
||||
font-size: 12px;
|
||||
min-width: 100px;
|
||||
}
|
||||
|
||||
.exit-button {
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
font-size: 16px;
|
||||
.exit-button {
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.type-label {
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
private renderPlayerInfo(player: Player) {
|
||||
return html`
|
||||
<div class="info-content">
|
||||
<div class="name ${player.isAlly ? 'ally' : 'enemy'}">${player.name}</div>
|
||||
<div class="type-label">Player Territory</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
private renderUnitInfo(unit: Unit) {
|
||||
return html`
|
||||
<div class="info-content">
|
||||
<div class="name ${unit.isAlly ? 'ally' : 'enemy'}">${unit.owner}</div>
|
||||
<div class="unit-details">
|
||||
<div class="type-label">${unit.type}</div>
|
||||
<div class="health-bar">
|
||||
<div class="health-fill" style="width: ${unit.health}%"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
render() {
|
||||
return html`
|
||||
<div class="overlay-container">
|
||||
<div class="controls">
|
||||
<button class="exit-button" @click=${this.onExitButtonClick}>×</button>
|
||||
</div>
|
||||
<div class="info-panel ${this._infoType === 'none' ? 'hidden' : ''}">
|
||||
${this._infoType === 'player' && this._playerInfo
|
||||
? this.renderPlayerInfo(this._playerInfo)
|
||||
: this._infoType === 'unit' && this._unitInfo
|
||||
? this.renderUnitInfo(this._unitInfo)
|
||||
: nothing}
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
}
|
||||
@@ -1,13 +1,9 @@
|
||||
import { GameEnv, Theme } from "../../../core/configuration/Config";
|
||||
import { EventBus } from "../../../core/EventBus";
|
||||
import { WinEvent } from "../../../core/execution/WinCheckExecution";
|
||||
import { AllianceRequest, AllianceRequestReplyEvent, Game, Player } from "../../../core/game/Game";
|
||||
import { ClientID } from "../../../core/Schemas";
|
||||
import { ContextMenuEvent } from "../../InputHandler";
|
||||
import { Layer } from "./Layer";
|
||||
import { TransformHandler } from "../TransformHandler";
|
||||
import { MessageType } from "./EventsDisplay";
|
||||
import { SendBreakAllianceIntentEvent } from "../../Transport";
|
||||
import { consolex } from "../../../core/Consolex";
|
||||
|
||||
interface MenuOption {
|
||||
@@ -151,6 +147,7 @@ export class UILayer implements Layer {
|
||||
button.onmouseout = () => button.style.backgroundColor = '#4A90E2';
|
||||
}
|
||||
|
||||
|
||||
onWinEvent(event: WinEvent) {
|
||||
consolex.log(`${event.winner.name()} won the game!!}`)
|
||||
this.showWinModal(event.winner)
|
||||
|
||||
@@ -8,7 +8,7 @@ export const devConfig = new class extends DefaultConfig {
|
||||
unitInfo(type: UnitType): UnitInfo {
|
||||
const info = super.unitInfo(type)
|
||||
const oldCost = info.cost
|
||||
info.cost = (p: Player) => oldCost(p) / 20
|
||||
info.cost = (p: Player) => oldCost(p) / 10000
|
||||
return info
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user