Skip to content
Draft
Show file tree
Hide file tree
Changes from 13 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 8 additions & 5 deletions src/client/ClientGameRunner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,11 @@ import {
import { createPartialGameRecord, replacer } from "../core/Util";
import { ServerConfig } from "../core/configuration/Config";
import { getConfig } from "../core/configuration/ConfigLoader";
import { PlayerActions, UnitType } from "../core/game/Game";
import {
PlayerActions,
TransportShipFilter,
UnitType,
} from "../core/game/Game";
import { TileRef } from "../core/game/GameMap";
import { GameMapLoader } from "../core/game/GameMapLoader";
import {
Expand Down Expand Up @@ -414,13 +418,12 @@ export class ClientGameRunner {
if (myPlayer === null) return;
this.myPlayer = myPlayer;
}
this.myPlayer.actions(tile).then((actions) => {
if (this.myPlayer === null) return;
this.myPlayer.actions(tile, TransportShipFilter.Only).then((actions) => {
if (actions.canAttack) {
this.eventBus.emit(
new SendAttackIntentEvent(
this.gameView.owner(tile).id(),
this.myPlayer.troops() * this.renderer.uiState.attackRatio,
this.myPlayer!.troops() * this.renderer.uiState.attackRatio,
),
);
} else if (this.canAutoBoat(actions, tile)) {
Expand Down Expand Up @@ -511,7 +514,7 @@ export class ClientGameRunner {
this.myPlayer = myPlayer;
}

this.myPlayer.actions(tile).then((actions) => {
this.myPlayer.actions(tile, TransportShipFilter.Only).then((actions) => {
if (this.canBoatAttack(actions) !== false) {
this.sendBoatAttackIntent(tile);
}
Expand Down
3 changes: 2 additions & 1 deletion src/client/graphics/layers/StructureIconsLayer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
Cell,
PlayerActions,
PlayerID,
TransportShipFilter,
UnitType,
} from "../../../core/game/Game";
import { TileRef } from "../../../core/game/GameMap";
Expand Down Expand Up @@ -249,7 +250,7 @@ export class StructureIconsLayer implements Layer {

this.game
?.myPlayer()
?.actions(tileRef)
?.actions(tileRef, TransportShipFilter.Exclude)
.then((actions) => {
if (this.potentialUpgrade) {
this.potentialUpgrade.iconContainer.filters = [];
Expand Down
9 changes: 7 additions & 2 deletions src/client/graphics/layers/UnitDisplay.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,12 @@ import portIcon from "../../../../resources/images/PortIcon.svg";
import samLauncherIcon from "../../../../resources/images/SamLauncherIconWhite.svg";
import defensePostIcon from "../../../../resources/images/ShieldIconWhite.svg";
import { EventBus } from "../../../core/EventBus";
import { Gold, PlayerActions, UnitType } from "../../../core/game/Game";
import {
Gold,
PlayerActions,
TransportShipFilter,
UnitType,
} from "../../../core/game/Game";
import { GameView } from "../../../core/game/GameView";
import { ToggleStructureEvent } from "../../InputHandler";
import { renderNumber, translateText } from "../../Utils";
Expand Down Expand Up @@ -97,7 +102,7 @@ export class UnitDisplay extends LitElement implements Layer {

tick() {
const player = this.game?.myPlayer();
player?.actions().then((actions) => {
player?.actions(undefined, TransportShipFilter.Exclude).then((actions) => {
this.playerActions = actions;
});
if (!player) return;
Expand Down
4 changes: 3 additions & 1 deletion src/core/GameRunner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import {
PlayerInfo,
PlayerProfile,
PlayerType,
TransportShipFilter,
} from "./game/Game";
import { createGame } from "./game/GameImpl";
import { TileRef } from "./game/GameMap";
Expand Down Expand Up @@ -181,13 +182,14 @@ export class GameRunner {
playerID: PlayerID,
x?: number,
y?: number,
transportShipFilter?: TransportShipFilter,
): PlayerActions {
const player = this.game.player(playerID);
const tile =
x !== undefined && y !== undefined ? this.game.ref(x, y) : null;
const actions = {
canAttack: tile !== null && player.canAttack(tile),
buildableUnits: player.buildableUnits(tile),
buildableUnits: player.buildableUnits(tile, transportShipFilter),
canSendEmojiAllPlayers: player.canSendEmoji(AllPlayers),
canEmbargoAll: player.canEmbargoAll(),
} as PlayerActions;
Expand Down
11 changes: 10 additions & 1 deletion src/core/game/Game.ts
Original file line number Diff line number Diff line change
Expand Up @@ -566,7 +566,10 @@ export interface Player {
unitCount(type: UnitType): number;
unitsConstructed(type: UnitType): number;
unitsOwned(type: UnitType): number;
buildableUnits(tile: TileRef | null): BuildableUnit[];
buildableUnits(
tile: TileRef | null,
transportShipFilter?: TransportShipFilter,
): BuildableUnit[];
canBuild(type: UnitType, targetTile: TileRef): TileRef | false;
buildUnit<T extends UnitType>(
type: T,
Expand Down Expand Up @@ -866,3 +869,9 @@ export interface NameViewData {
y: number;
size: number;
}

// Filter for buildableUnits
export enum TransportShipFilter {
Exclude = "exclude",
Only = "only",
}
7 changes: 6 additions & 1 deletion src/core/game/GameView.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import {
TerraNullius,
Tick,
TrainType,
TransportShipFilter,
UnitInfo,
UnitType,
} from "./Game";
Expand Down Expand Up @@ -276,11 +277,15 @@ export class PlayerView {
: this._defendedBorderColors.dark;
}

async actions(tile?: TileRef): Promise<PlayerActions> {
async actions(
tile?: TileRef,
transportShipFilter?: TransportShipFilter,
): Promise<PlayerActions> {
return this.game.worker.playerInteraction(
this.id(),
tile && this.game.x(tile),
tile && this.game.y(tile),
transportShipFilter,
);
}

Expand Down
109 changes: 83 additions & 26 deletions src/core/game/PlayerImpl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import {
Team,
TerraNullius,
Tick,
TransportShipFilter,
Unit,
UnitParams,
UnitType,
Expand Down Expand Up @@ -874,7 +875,15 @@ export class PlayerImpl implements Player {
return b;
}

public findUnitToUpgrade(type: UnitType, targetTile: TileRef): Unit | false {
public findUnitToUpgrade(
type: UnitType,
targetTile: TileRef,
skipUnitTypeCheck: boolean = false,
): Unit | false {
if (!this.canUpgradeUnitType(type, skipUnitTypeCheck)) {
return false;
}

const range = this.mg.config().structureMinDist();
const existing = this.mg
.nearbyUnits(targetTile, range, type)
Expand All @@ -883,23 +892,47 @@ export class PlayerImpl implements Player {
return false;
}
const unit = existing[0].unit;
if (!this.canUpgradeUnit(unit)) {
if (!this.canUpgradeUnit(unit, skipUnitTypeCheck)) {
return false;
}

return unit;
}

public canUpgradeUnit(unit: Unit): boolean {
public canUpgradeUnit(
unit: Unit,
skipUnitTypeCheck: boolean = false,
): boolean {
if (unit.isMarkedForDeletion()) {
return false;
}
if (!this.mg.config().unitInfo(unit.type()).upgradable) {
if (!skipUnitTypeCheck && !this.canUpgradeUnitType(unit.type())) {
return false;
}
return true;
}

private canUpgradeUnitType(
unitType: UnitType,
skipUnitTypeCheck: boolean = false,
): boolean {
if (!this.mg.config().unitInfo(unitType).upgradable) {
return false;
}
if (!skipUnitTypeCheck && !this.canBuildUnitType(unitType)) {
return false;
}
return true;
}

private canBuildUnitType(unitType: UnitType): boolean {
if (this.mg.config().isUnitDisabled(unitType)) {
return false;
}
if (this.mg.config().isUnitDisabled(unit.type())) {
if (this._gold < this.mg.config().unitInfo(unitType).cost(this)) {
return false;
}
if (this._gold < this.mg.config().unitInfo(unit.type()).cost(this)) {
if (!this.isAlive()) {
return false;
}
return true;
Expand All @@ -912,41 +945,65 @@ export class PlayerImpl implements Player {
this.recordUnitConstructed(unit.type());
}

public buildableUnits(tile: TileRef | null): BuildableUnit[] {
const validTiles = tile !== null ? this.validStructureSpawnTiles(tile) : [];
return Object.values(UnitType).map((u) => {
public buildableUnits(
tile: TileRef | null,
transportShipFilter?: TransportShipFilter,
): BuildableUnit[] {
const notInSpawnPhase = !this.mg.inSpawnPhase();
let foundShip = false;
const result: BuildableUnit[] = [];

const validTiles =
tile !== null && transportShipFilter !== TransportShipFilter.Only
? this.validStructureSpawnTiles(tile)
: [];

for (const u of Object.values(UnitType)) {
if (
u === UnitType.TransportShip &&
transportShipFilter === TransportShipFilter.Exclude
) {
continue;
}

if (transportShipFilter === TransportShipFilter.Only) {
if (foundShip) break;

if (u !== UnitType.TransportShip) continue;
else foundShip = true;
}

let canBuild: TileRef | false = false;
let canUpgrade: number | false = false;
if (!this.mg.inSpawnPhase()) {
const existingUnit = tile !== null && this.findUnitToUpgrade(u, tile);
if (existingUnit !== false) {
canUpgrade = existingUnit.id();
}

if (tile !== null && this.canBuildUnitType(u) && notInSpawnPhase) {
canBuild = this.canBuild(u, tile, validTiles, true);

const existingUnit = this.findUnitToUpgrade(u, tile, true);
canUpgrade = existingUnit !== false ? existingUnit.id() : false;
}
return {

result.push({
type: u,
canBuild:
this.mg.inSpawnPhase() || tile === null
? false
: this.canBuild(u, tile, validTiles),
canBuild: canBuild,
canUpgrade: canUpgrade,
cost: this.mg.config().unitInfo(u).cost(this),
} as BuildableUnit;
});
} as BuildableUnit);
}

return result;
}

canBuild(
unitType: UnitType,
targetTile: TileRef,
validTiles: TileRef[] | null = null,
skipUnitTypeCheck: boolean = false,
): TileRef | false {
if (this.mg.config().isUnitDisabled(unitType)) {
if (!skipUnitTypeCheck && !this.canBuildUnitType(unitType)) {
return false;
}

const cost = this.mg.unitInfo(unitType).cost(this);
if (!this.isAlive() || this.gold() < cost) {
return false;
}
switch (unitType) {
case UnitType.MIRV:
if (!this.mg.hasOwner(targetTile)) {
Expand Down
Loading
Loading