Merge branch 'main' into defenseposture

This commit is contained in:
1brucben
2025-04-19 01:54:00 +02:00
22 changed files with 247 additions and 79 deletions
+26
View File
@@ -12,6 +12,7 @@ import { createGameRecord } from "../core/Util";
import { ServerConfig } from "../core/configuration/Config";
import { getConfig } from "../core/configuration/ConfigLoader";
import { Team, UnitType } from "../core/game/Game";
import { TileRef } from "../core/game/GameMap";
import {
ErrorUpdate,
GameUpdateType,
@@ -28,6 +29,7 @@ import { endGame, startGame, startTime } from "./LocalPersistantStats";
import { getPersistentIDFromCookie } from "./Main";
import {
SendAttackIntentEvent,
SendBoatAttackIntentEvent,
SendHashEvent,
SendSpawnIntentEvent,
Transport,
@@ -359,6 +361,18 @@ export class ClientGameRunner {
this.myPlayer.troops() * this.renderer.uiState.attackRatio,
),
);
} else if (
actions.canBoat !== false &&
this.shouldBoat(tile, actions.canBoat) &&
this.gameView.isLand(tile)
) {
this.eventBus.emit(
new SendBoatAttackIntentEvent(
this.gameView.owner(tile).id(),
cell,
this.myPlayer.troops() * this.renderer.uiState.attackRatio,
),
);
}
const owner = this.gameView.owner(tile);
@@ -370,6 +384,18 @@ export class ClientGameRunner {
});
}
private shouldBoat(tile: TileRef, src: TileRef) {
// TODO: Global enable flag
// TODO: Global limit autoboat to nearby shore flag
// if (!enableAutoBoat) return false;
// if (!limitAutoBoatNear) return true;
const distanceSquared = this.gameView.euclideanDistSquared(tile, src);
const limit = 100;
const limitSquared = limit * limit;
if (distanceSquared > limitSquared) return false;
return true;
}
private onMouseMove(event: MouseMoveEvent) {
this.lastMousePosition = { x: event.x, y: event.y };
this.checkTileUnderCursor();
+1
View File
@@ -23,6 +23,7 @@ export const MapDescription: Record<keyof typeof GameMapType, string> = {
Japan: "Japan",
BetweenTwoSeas: "Between Two Seas",
KnownWorld: "Known World",
FaroeIslands: "Faroe Islands",
};
@customElement("map-display")
+8 -2
View File
@@ -145,8 +145,14 @@ export class PlayerPanel extends LitElement implements Layer {
this.eventBus.on(MouseUpEvent, (e: MouseEvent) => this.hide());
}
tick() {
this.requestUpdate();
async tick() {
if (this.isVisible && this.tile) {
const myPlayer = this.g.myPlayer();
if (myPlayer !== null && myPlayer.isAlive()) {
this.actions = await myPlayer.actions(this.tile);
this.requestUpdate();
}
}
}
getTotalNukesSent(otherId: PlayerID): number {
+34 -14
View File
@@ -8,7 +8,7 @@ import swordIcon from "../../../../resources/images/SwordIconWhite.svg";
import traitorIcon from "../../../../resources/images/TraitorIconWhite.svg";
import { consolex } from "../../../core/Consolex";
import { EventBus } from "../../../core/EventBus";
import { Cell, PlayerActions } from "../../../core/game/Game";
import { Cell, PlayerActions, TerraNullius } from "../../../core/game/Game";
import { TileRef } from "../../../core/game/GameMap";
import { GameView, PlayerView } from "../../../core/game/GameView";
import { ClientID } from "../../../core/Schemas";
@@ -44,6 +44,7 @@ export class RadialMenu implements Layer {
private clickedCell: Cell | null = null;
private lastClosed: number = 0;
private originalTileOwner: PlayerView | TerraNullius;
private menuElement: d3.Selection<HTMLDivElement, unknown, null, undefined>;
private isVisible: boolean = false;
private readonly menuItems = new Map([
@@ -267,8 +268,26 @@ export class RadialMenu implements Layer {
.style("pointer-events", "none");
}
tick() {
// Update logic if needed
async tick() {
// Only update when menu is visible
if (!this.isVisible || this.clickedCell === null) return;
const myPlayer = this.g.myPlayer();
if (myPlayer === null || !myPlayer.isAlive()) return;
const tile = this.g.ref(this.clickedCell.x, this.clickedCell.y);
if (this.originalTileOwner.isPlayer()) {
if (this.g.owner(tile) != this.originalTileOwner) {
this.closeMenu();
return;
}
} else {
if (this.g.owner(tile).isPlayer() || this.g.owner(tile) == myPlayer) {
this.closeMenu();
return;
}
}
const actions = await myPlayer.actions(tile);
this.disableAllButtons();
this.handlePlayerActions(myPlayer, actions, tile);
}
renderLayer(context: CanvasRenderingContext2D) {
@@ -291,12 +310,7 @@ export class RadialMenu implements Layer {
} else {
this.showRadialMenu(event.x, event.y);
}
this.enableCenterButton(false);
for (const item of this.menuItems.values()) {
item.disabled = true;
this.updateMenuItemState(item);
}
this.disableAllButtons();
this.clickedCell = this.transformHandler.screenToWorldCoordinates(
event.x,
event.y,
@@ -305,7 +319,7 @@ export class RadialMenu implements Layer {
return;
}
const tile = this.g.ref(this.clickedCell.x, this.clickedCell.y);
this.originalTileOwner = this.g.owner(tile);
if (this.g.inSpawnPhase()) {
if (this.g.isLand(tile) && !this.g.hasOwner(tile)) {
this.enableCenterButton(true);
@@ -313,10 +327,8 @@ export class RadialMenu implements Layer {
return;
}
const myPlayer = this.g
.playerViews()
.find((p) => p.clientID() == this.clientID);
if (!myPlayer) {
const myPlayer = this.g.myPlayer();
if (myPlayer === null) {
consolex.warn("my player not found");
return;
}
@@ -430,6 +442,14 @@ export class RadialMenu implements Layer {
this.hideRadialMenu();
}
private disableAllButtons() {
this.enableCenterButton(false);
for (const item of this.menuItems.values()) {
item.disabled = true;
this.updateMenuItemState(item);
}
}
private activateMenuElement(
slot: Slot,
color: string,
+3
View File
@@ -5,6 +5,7 @@ import betweenTwoSeas from "../../../resources/maps/BetweenTwoSeasThumb.webp";
import blackSea from "../../../resources/maps/BlackSeaThumb.webp";
import britannia from "../../../resources/maps/BritanniaThumb.webp";
import europe from "../../../resources/maps/EuropeThumb.webp";
import faroeislands from "../../../resources/maps/FaroeIslandsThumb.webp";
import gatewayToTheAtlantic from "../../../resources/maps/GatewayToTheAtlanticThumb.webp";
import iceland from "../../../resources/maps/IcelandThumb.webp";
import japan from "../../../resources/maps/JapanThumb.webp";
@@ -57,6 +58,8 @@ export function getMapsImage(map: GameMapType): string {
return betweenTwoSeas;
case GameMapType.KnownWorld:
return knownworld;
case GameMapType.FaroeIslands:
return faroeislands;
default:
return "";
}
+2 -1
View File
@@ -34,7 +34,7 @@ export abstract class DefaultServerConfig implements ServerConfig {
return process.env.GIT_COMMIT;
}
r2Endpoint(): string {
return process.env.R2_ENDPOINT;
return `https://${process.env.R2_ACCOUNT_ID}.r2.cloudflarestorage.com`;
}
r2AccessKey(): string {
return process.env.R2_ACCESS_KEY;
@@ -89,6 +89,7 @@ export abstract class DefaultServerConfig implements ServerConfig {
GameMapType.Mars,
GameMapType.Oceania,
GameMapType.Japan, // Japan at this level because its 2/3 water
GameMapType.FaroeIslands,
].includes(map)
) {
return Math.random() < 0.2 ? 70 : 40;
+3 -2
View File
@@ -67,6 +67,7 @@ export enum GameMapType {
Japan = "Japan",
BetweenTwoSeas = "Between Two Seas",
KnownWorld = "Known World",
FaroeIslands = "FaroeIslands",
}
export enum GameType {
@@ -416,7 +417,7 @@ export interface Player {
// Misc
toUpdate(): PlayerUpdate;
playerProfile(): PlayerProfile;
canBoat(tile: TileRef): boolean;
canBoat(tile: TileRef): TileRef | false;
tradingPorts(port: Unit): Unit[];
}
@@ -474,7 +475,7 @@ export interface Game extends GameMap {
}
export interface PlayerActions {
canBoat: boolean;
canBoat: TileRef | false;
canAttack: boolean;
buildableUnits: BuildableUnit[];
canSendEmojiAllPlayers: boolean;
+13 -5
View File
@@ -22,6 +22,7 @@ import {
Attack,
Cell,
EmojiMessage,
GameMode,
Gold,
MessageType,
MutableAlliance,
@@ -518,6 +519,13 @@ export class PlayerImpl implements Player {
}
canDonate(recipient: Player): boolean {
if (
recipient.type() == PlayerType.Human &&
this.mg.config().gameConfig().gameMode == GameMode.FFA
) {
return false;
}
if (!this.isFriendly(recipient)) {
return false;
}
@@ -543,7 +551,7 @@ export class PlayerImpl implements Player {
this.id(),
);
this.mg.displayMessage(
`Recieved ${renderTroops(troops)} troops from ${this.name()}`,
`Received ${renderTroops(troops)} troops from ${this.name()}`,
MessageType.SUCCESS,
recipient.id(),
);
@@ -557,7 +565,7 @@ export class PlayerImpl implements Player {
this.id(),
);
this.mg.displayMessage(
`Recieved ${renderNumber(gold)} gold from ${this.name()}`,
`Received ${renderNumber(gold)} gold from ${this.name()}`,
MessageType.SUCCESS,
recipient.id(),
);
@@ -886,7 +894,7 @@ export class PlayerImpl implements Player {
return rel;
}
public canBoat(tile: TileRef): boolean {
public canBoat(tile: TileRef): TileRef | false {
if (
this.units(UnitType.TransportShip).length >=
this.mg.config().boatMaxNumber()
@@ -929,7 +937,7 @@ export class PlayerImpl implements Player {
}
if (myPlayerBordersOcean && otherPlayerBordersOcean) {
return this.canBuild(UnitType.TransportShip, dst) != false;
return this.canBuild(UnitType.TransportShip, dst);
} else {
return false;
}
@@ -952,7 +960,7 @@ export class PlayerImpl implements Player {
for (const t of sorted) {
if (this.mg.owner(t) == this) {
return this.canBuild(UnitType.TransportShip, dst) != false;
return this.canBuild(UnitType.TransportShip, dst);
}
}
return false;
+1
View File
@@ -41,6 +41,7 @@ const MAP_FILE_NAMES: Record<GameMapType, string> = {
[GameMapType.Japan]: "Japan",
[GameMapType.BetweenTwoSeas]: "BetweenTwoSeas",
[GameMapType.KnownWorld]: "KnownWorld",
[GameMapType.FaroeIslands]: "FaroeIslands",
};
class GameMapLoader {
+1
View File
@@ -22,6 +22,7 @@ const maps = [
"BetweenTwoSeas",
"Japan",
"KnownWorld",
"FaroeIslands",
];
const removeSmall = true;
+1
View File
@@ -101,6 +101,7 @@ export class MapPlaylist {
BetweenTwoSeas: 3,
Japan: 3,
BlackSea: 1,
FaroeIslands: 2,
};
}
}