mirror of
https://github.com/openfrontio/OpenFrontIO.git
synced 2026-06-22 11:04:16 +00:00
fix
This commit is contained in:
+1506
-749
File diff suppressed because it is too large
Load Diff
@@ -13,6 +13,7 @@ import {
|
||||
Trios,
|
||||
UnitType,
|
||||
mapCategories,
|
||||
TeamGameType,
|
||||
} from "../core/game/Game";
|
||||
import { UserSettings } from "../core/game/UserSettings";
|
||||
import { TeamCountConfig } from "../core/Schemas";
|
||||
@@ -45,22 +46,10 @@ export class SinglePlayerModal extends LitElement {
|
||||
@state() private instantBuild: boolean = false;
|
||||
@state() private useRandomMap: boolean = false;
|
||||
@state() private gameMode: GameMode = GameMode.FFA;
|
||||
@state() private teamGameType: TeamGameType = TeamGameType.Standard;
|
||||
@state() private teamCount: TeamCountConfig = 2;
|
||||
|
||||
@state() private disabledUnits: UnitType[] = [];
|
||||
|
||||
private readonly nukeWarsDisabledUnits = [
|
||||
UnitType.City,
|
||||
UnitType.Construction,
|
||||
UnitType.DefensePost,
|
||||
UnitType.Port,
|
||||
UnitType.TransportShip,
|
||||
UnitType.Warship,
|
||||
UnitType.Train,
|
||||
UnitType.TradeShip,
|
||||
UnitType.MIRV,
|
||||
];
|
||||
|
||||
private userSettings: UserSettings = new UserSettings();
|
||||
|
||||
connectedCallback() {
|
||||
@@ -195,19 +184,29 @@ export class SinglePlayerModal extends LitElement {
|
||||
${translateText("game_mode.teams")}
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="option-card ${this.gameMode === GameMode.NukeWars
|
||||
? "selected"
|
||||
: ""}"
|
||||
@click=${() => this.handleGameModeSelection(GameMode.NukeWars)}
|
||||
>
|
||||
<div class="option-card-title">Nuke Wars</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
${this.gameMode === GameMode.Team
|
||||
? html`
|
||||
<!-- Team Game Type Selection -->
|
||||
<div class="options-section">
|
||||
<div class="option-title">Team Game Type</div>
|
||||
<div class="option-cards">
|
||||
<div
|
||||
class="option-card ${this.teamGameType === TeamGameType.Standard ? "selected" : ""}"
|
||||
@click=${() => this.handleTeamGameTypeSelection(TeamGameType.Standard)}
|
||||
>
|
||||
<div class="option-card-title">Standard Team</div>
|
||||
</div>
|
||||
<div
|
||||
class="option-card ${this.teamGameType === TeamGameType.NukeWars ? "selected" : ""}"
|
||||
@click=${() => this.handleTeamGameTypeSelection(TeamGameType.NukeWars)}
|
||||
>
|
||||
<div class="option-card-title">Nuke Wars</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Team Count Selection -->
|
||||
<div class="options-section">
|
||||
<div class="option-title">
|
||||
@@ -474,9 +473,17 @@ export class SinglePlayerModal extends LitElement {
|
||||
|
||||
private handleGameModeSelection(value: GameMode) {
|
||||
this.gameMode = value;
|
||||
if (value === GameMode.FFA) {
|
||||
this.teamGameType = TeamGameType.Standard;
|
||||
}
|
||||
// Clear disabled units when switching to other modes
|
||||
this.disabledUnits = [];
|
||||
}
|
||||
|
||||
private handleTeamGameTypeSelection(value: TeamGameType) {
|
||||
this.teamGameType = value;
|
||||
// Enforce Nuke Wars restrictions
|
||||
if (value === GameMode.NukeWars) {
|
||||
if (value === TeamGameType.NukeWars) {
|
||||
// Force 2 teams for Nuke Wars
|
||||
this.teamCount = 2;
|
||||
// Force Baikal map
|
||||
@@ -484,12 +491,6 @@ export class SinglePlayerModal extends LitElement {
|
||||
this.selectedMap = GameMapType.Baikal;
|
||||
this.useRandomMap = false;
|
||||
}
|
||||
|
||||
// Disable all units except missiles and SAMs
|
||||
this.disabledUnits = [...this.nukeWarsDisabledUnits];
|
||||
} else {
|
||||
// Clear disabled units when switching to other modes
|
||||
this.disabledUnits = [];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -517,7 +518,8 @@ export class SinglePlayerModal extends LitElement {
|
||||
}
|
||||
// Enforce Nuke Wars availability only on Baikal for single player as well
|
||||
if (
|
||||
this.gameMode === GameMode.NukeWars &&
|
||||
this.gameMode === GameMode.Team &&
|
||||
this.teamGameType === TeamGameType.NukeWars &&
|
||||
this.selectedMap !== GameMapType.Baikal
|
||||
) {
|
||||
alert(
|
||||
@@ -579,6 +581,7 @@ export class SinglePlayerModal extends LitElement {
|
||||
: GameMapSize.Normal,
|
||||
gameType: GameType.Singleplayer,
|
||||
gameMode: this.gameMode,
|
||||
teamGameType: this.gameMode === GameMode.Team ? this.teamGameType : undefined,
|
||||
playerTeams: this.teamCount,
|
||||
difficulty: this.selectedDifficulty,
|
||||
disableNPCs: this.disableNPCs,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { EventBus } from "../../core/EventBus";
|
||||
import { GameView } from "../../core/game/GameView";
|
||||
import { UserSettings } from "../../core/game/UserSettings";
|
||||
import { GameMode, TeamGameType } from "../../core/game/Game";
|
||||
import { GameStartingModal } from "../GameStartingModal";
|
||||
import { RefreshGraphicsEvent as RedrawGraphicsEvent } from "../InputHandler";
|
||||
import { TransformHandler } from "./TransformHandler";
|
||||
@@ -248,7 +248,11 @@ export function createRenderer(
|
||||
playerPanel,
|
||||
),
|
||||
new SpawnTimer(game, transformHandler),
|
||||
new NukeWarsTopBanner(game),
|
||||
// Conditionally add NukeWarsTopBanner if it's a Nuke Wars game
|
||||
...(game.config().gameConfig().gameMode === GameMode.Team &&
|
||||
game.config().gameConfig().teamGameType === TeamGameType.NukeWars
|
||||
? [new NukeWarsTopBanner(game)]
|
||||
: []),
|
||||
leaderboard,
|
||||
gameLeftSidebar,
|
||||
unitDisplay,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { GameMapType, GameMode } from "../../../core/game/Game";
|
||||
import { GameMapType, GameMode, TeamGameType } from "../../../core/game/Game";
|
||||
import { GameView } from "../../../core/game/GameView";
|
||||
import { Layer } from "./Layer";
|
||||
|
||||
@@ -19,7 +19,7 @@ export class NukeWarsTopBanner implements Layer {
|
||||
|
||||
renderLayer(context: CanvasRenderingContext2D) {
|
||||
const config = this.game.config().gameConfig();
|
||||
if (config.gameMode !== GameMode.NukeWars) return;
|
||||
if (!(config.gameMode === GameMode.Team && config.teamGameType === TeamGameType.NukeWars)) return;
|
||||
if (config.gameMap !== GameMapType.Baikal) return;
|
||||
const canvasWidth = context.canvas.width;
|
||||
const padding = 12;
|
||||
|
||||
@@ -15,6 +15,7 @@ import {
|
||||
GameMode,
|
||||
GameType,
|
||||
Quads,
|
||||
TeamGameType,
|
||||
Trios,
|
||||
UnitType,
|
||||
} from "./game/Game";
|
||||
@@ -157,6 +158,7 @@ export const GameConfigSchema = z.object({
|
||||
donateTroops: z.boolean(), // Configures donations to humans only
|
||||
gameType: z.enum(GameType),
|
||||
gameMode: z.enum(GameMode),
|
||||
teamGameType: z.enum(TeamGameType).optional(),
|
||||
gameMapSize: z.enum(GameMapSize),
|
||||
disableNPCs: z.boolean(),
|
||||
bots: z.number().int().min(0).max(400),
|
||||
|
||||
@@ -18,6 +18,7 @@ import {
|
||||
Trios,
|
||||
UnitInfo,
|
||||
UnitType,
|
||||
TeamGameType,
|
||||
} from "../game/Game";
|
||||
import { TileRef } from "../game/GameMap";
|
||||
import { PlayerView } from "../game/GameView";
|
||||
@@ -316,13 +317,22 @@ export class DefaultConfig implements Config {
|
||||
|
||||
spawnNPCs(): boolean {
|
||||
return !this._gameConfig.disableNPCs;
|
||||
}
|
||||
|
||||
isUnitDisabled(unitType: UnitType): boolean {
|
||||
// Nuke Wars: only MIRV is blocked explicitly. Keep any server-configured
|
||||
// disabledUnits in the check as well.
|
||||
if (this._gameConfig.gameMode === GameMode.NukeWars) {
|
||||
if (unitType === UnitType.MIRV) return true;
|
||||
if (this._gameConfig.gameMode === GameMode.Team && this._gameConfig.teamGameType === TeamGameType.NukeWars) {
|
||||
const allowedUnits = [
|
||||
UnitType.City,
|
||||
UnitType.Port,
|
||||
UnitType.Factory,
|
||||
UnitType.MissileSilo,
|
||||
UnitType.SAMLauncher,
|
||||
UnitType.DefensePost,
|
||||
UnitType.Warship,
|
||||
UnitType.TradeShip,
|
||||
UnitType.TransportShip,
|
||||
UnitType.AtomBomb,
|
||||
UnitType.HydrogenBomb,
|
||||
];
|
||||
return !allowedUnits.includes(unitType);
|
||||
}
|
||||
|
||||
return this._gameConfig.disabledUnits?.includes(unitType) ?? false;
|
||||
@@ -619,7 +629,7 @@ export class DefaultConfig implements Config {
|
||||
|
||||
numPreparationPhaseTurns(): number {
|
||||
// Preparation phase duration (Nuke Wars uses a 3 minute prep phase)
|
||||
if (this._gameConfig.gameMode === GameMode.NukeWars) {
|
||||
if (this._gameConfig.gameMode === GameMode.Team && this._gameConfig.teamGameType === TeamGameType.NukeWars) {
|
||||
return 180 * 10; // 180 seconds * 10 ticks/sec
|
||||
}
|
||||
return 0;
|
||||
|
||||
@@ -4,6 +4,7 @@ import {
|
||||
GameMapType,
|
||||
GameMode,
|
||||
Player,
|
||||
TeamGameType,
|
||||
UnitType,
|
||||
} from "../game/Game";
|
||||
import { TileRef } from "../game/GameMap";
|
||||
@@ -34,7 +35,8 @@ export class MoveWarshipExecution implements Execution {
|
||||
// In Nuke Wars on Baikal, prevent assigning patrols that cross the midpoint.
|
||||
const gc = mg.config().gameConfig();
|
||||
if (
|
||||
gc.gameMode === GameMode.NukeWars &&
|
||||
gc.gameMode === GameMode.Team &&
|
||||
gc.teamGameType === TeamGameType.NukeWars &&
|
||||
gc.gameMap === GameMapType.Baikal
|
||||
) {
|
||||
const mapWidth = mg.width();
|
||||
|
||||
@@ -6,6 +6,7 @@ import {
|
||||
Player,
|
||||
PlayerInfo,
|
||||
PlayerType,
|
||||
TeamGameType,
|
||||
} from "../game/Game";
|
||||
import { TileRef } from "../game/GameMap";
|
||||
import { BotExecution } from "./BotExecution";
|
||||
@@ -49,7 +50,8 @@ export class SpawnExecution implements Execution {
|
||||
let spawnTile = this.tile;
|
||||
const gc = this.mg.config().gameConfig();
|
||||
if (
|
||||
gc.gameMode === GameMode.NukeWars &&
|
||||
gc.gameMode === GameMode.Team &&
|
||||
gc.teamGameType === TeamGameType.NukeWars &&
|
||||
gc.gameMap === GameMapType.Baikal
|
||||
) {
|
||||
const mapWidth = this.mg.width();
|
||||
|
||||
@@ -7,6 +7,7 @@ import {
|
||||
Player,
|
||||
PlayerID,
|
||||
TerraNullius,
|
||||
TeamGameType,
|
||||
Unit,
|
||||
UnitType,
|
||||
} from "../game/Game";
|
||||
@@ -108,7 +109,8 @@ export class TransportShipExecution implements Execution {
|
||||
// In Nuke Wars on Baikal, prevent transport ships from entering enemy territory
|
||||
const gc = this.mg.config().gameConfig();
|
||||
if (
|
||||
gc.gameMode === GameMode.NukeWars &&
|
||||
gc.gameMode === GameMode.Team &&
|
||||
gc.teamGameType === TeamGameType.NukeWars &&
|
||||
gc.gameMap === GameMapType.Baikal &&
|
||||
this.dst !== null
|
||||
) {
|
||||
|
||||
@@ -6,6 +6,7 @@ import {
|
||||
GameMode,
|
||||
Player,
|
||||
Team,
|
||||
TeamGameType,
|
||||
} from "../game/Game";
|
||||
|
||||
export class WinEvent implements GameEvent {
|
||||
@@ -32,10 +33,13 @@ export class WinCheckExecution implements Execution {
|
||||
const gameMode = this.mg.config().gameConfig().gameMode;
|
||||
if (gameMode === GameMode.FFA) {
|
||||
this.checkWinnerFFA();
|
||||
} else if (gameMode === GameMode.NukeWars) {
|
||||
this.checkWinnerNukeWars();
|
||||
} else {
|
||||
this.checkWinnerTeam();
|
||||
} else if (gameMode === GameMode.Team) {
|
||||
const teamGameType = this.mg.config().gameConfig().teamGameType;
|
||||
if (teamGameType === TeamGameType.NukeWars) {
|
||||
this.checkWinnerNukeWars();
|
||||
} else {
|
||||
this.checkWinnerTeam();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -149,8 +149,13 @@ export const isGameType = (value: unknown): value is GameType =>
|
||||
export enum GameMode {
|
||||
FFA = "Free For All",
|
||||
Team = "Team",
|
||||
}
|
||||
|
||||
export enum TeamGameType {
|
||||
Standard = "Standard",
|
||||
NukeWars = "Nuke Wars",
|
||||
}
|
||||
|
||||
export const isGameMode = (value: unknown): value is GameMode =>
|
||||
isEnumValue(GameMode, value);
|
||||
|
||||
|
||||
@@ -30,6 +30,7 @@ import {
|
||||
Unit,
|
||||
UnitInfo,
|
||||
UnitType,
|
||||
TeamGameType,
|
||||
} from "./Game";
|
||||
import { GameMap, TileRef, TileUpdate } from "./GameMap";
|
||||
import { GameUpdate, GameUpdateType } from "./GameUpdates";
|
||||
@@ -98,8 +99,7 @@ export class GameImpl implements Game {
|
||||
this.unitGrid = new UnitGrid(this._map);
|
||||
// Treat Team and NukeWars as team-based games (Nuke Wars is 2-team only)
|
||||
if (
|
||||
_config.gameConfig().gameMode === GameMode.Team ||
|
||||
_config.gameConfig().gameMode === GameMode.NukeWars
|
||||
_config.gameConfig().gameMode === GameMode.Team
|
||||
) {
|
||||
this.populateTeams();
|
||||
}
|
||||
@@ -109,7 +109,7 @@ export class GameImpl implements Game {
|
||||
private populateTeams() {
|
||||
let numPlayerTeams = this._config.playerTeams();
|
||||
// Force 2 teams for NukeWars
|
||||
if (this._config.gameConfig().gameMode === GameMode.NukeWars) {
|
||||
if (this._config.gameConfig().gameMode === GameMode.Team && this._config.gameConfig().teamGameType === TeamGameType.NukeWars) {
|
||||
numPlayerTeams = 2;
|
||||
}
|
||||
if (typeof numPlayerTeams !== "number") {
|
||||
@@ -681,10 +681,7 @@ export class GameImpl implements Game {
|
||||
|
||||
teams(): Team[] {
|
||||
if (this._config.gameConfig().gameMode !== GameMode.Team) {
|
||||
// Treat NukeWars as a team-based mode (2 teams)
|
||||
if (this._config.gameConfig().gameMode !== GameMode.NukeWars) {
|
||||
return [];
|
||||
}
|
||||
return [];
|
||||
}
|
||||
return [this.botTeam, ...this.playerTeams];
|
||||
}
|
||||
|
||||
@@ -33,6 +33,7 @@ import {
|
||||
PlayerType,
|
||||
Relation,
|
||||
Team,
|
||||
TeamGameType,
|
||||
TerraNullius,
|
||||
Tick,
|
||||
Unit,
|
||||
@@ -905,7 +906,8 @@ export class PlayerImpl implements Player {
|
||||
|
||||
private isInTeamSpawnZone(tile: TileRef): boolean {
|
||||
const gameMode = this.mg.config().gameConfig().gameMode;
|
||||
if (gameMode !== GameMode.NukeWars) {
|
||||
const teamGameType = this.mg.config().gameConfig().teamGameType;
|
||||
if (!(gameMode === GameMode.Team && teamGameType === TeamGameType.NukeWars)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -936,7 +938,8 @@ export class PlayerImpl implements Player {
|
||||
// Nuke Wars restrictions on Baikal map
|
||||
const gc = this.mg.config().gameConfig();
|
||||
if (
|
||||
gc.gameMode === GameMode.NukeWars &&
|
||||
gc.gameMode === GameMode.Team &&
|
||||
gc.teamGameType === TeamGameType.NukeWars &&
|
||||
gc.gameMap === GameMapType.Baikal
|
||||
) {
|
||||
// Ships cannot enter enemy team spawn zones
|
||||
@@ -985,7 +988,7 @@ export class PlayerImpl implements Player {
|
||||
// In Nuke Wars, AtomBomb and HydrogenBomb cannot be launched during the
|
||||
// preparation phase, but are allowed afterwards. Other build restrictions
|
||||
// (like team spawn zones) are handled above.
|
||||
if (gc.gameMode === GameMode.NukeWars && this.mg.inPreparationPhase()) {
|
||||
if (gc.gameMode === GameMode.Team && gc.teamGameType === TeamGameType.NukeWars && this.mg.inPreparationPhase()) {
|
||||
this.mg.displayMessage(
|
||||
"Nuclear weapons cannot be launched during the preparation phase",
|
||||
MessageType.ATTACK_FAILED,
|
||||
@@ -1097,7 +1100,7 @@ export class PlayerImpl implements Player {
|
||||
const owner = this.mg.owner(tile);
|
||||
const gc = this.mg.config().gameConfig();
|
||||
// In NukeWars prep phase, allow building in team territory
|
||||
if (gc.gameMode === GameMode.NukeWars && this.mg.inPreparationPhase()) {
|
||||
if (gc.gameMode === GameMode.Team && gc.teamGameType === TeamGameType.NukeWars && this.mg.inPreparationPhase()) {
|
||||
if (!owner.isPlayer() || !this.isOnSameTeam(owner as Player)) {
|
||||
return [];
|
||||
}
|
||||
@@ -1243,7 +1246,8 @@ export class PlayerImpl implements Player {
|
||||
// side deterministically by smallID parity (odd = left, even = right).
|
||||
const gameCfg = this.mg.config().gameConfig();
|
||||
if (
|
||||
gameCfg.gameMode === GameMode.NukeWars &&
|
||||
gameCfg.gameMode === GameMode.Team &&
|
||||
gameCfg.teamGameType === TeamGameType.NukeWars &&
|
||||
gameCfg.gameMap === GameMapType.Baikal &&
|
||||
this.mg.inSpawnPhase()
|
||||
) {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { PathFindResultType } from "../pathfinding/AStar";
|
||||
import { MiniAStar } from "../pathfinding/MiniAStar";
|
||||
import { Game, GameMapType, GameMode, Player, UnitType } from "./Game";
|
||||
import { Game, GameMapType, GameMode, Player, TeamGameType, UnitType } from "./Game";
|
||||
import { andFN, GameMap, manhattanDistFN, TileRef } from "./GameMap";
|
||||
|
||||
export function canBuildTransportShip(
|
||||
@@ -22,19 +22,19 @@ export function canBuildTransportShip(
|
||||
const other = game.owner(tile);
|
||||
// During NukeWars, don't block transport ships between team members
|
||||
const gc = game.config().gameConfig();
|
||||
if (gc.gameMode !== GameMode.NukeWars) {
|
||||
if (!(gc.gameMode === GameMode.Team && gc.teamGameType === TeamGameType.NukeWars)) {
|
||||
if (other === player) {
|
||||
return false;
|
||||
}
|
||||
if (other.isPlayer() && player.isFriendly(other)) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
// In NukeWars, only block sending to enemy teams
|
||||
if (other.isPlayer() && player.isOnSameTeam(other as Player)) {
|
||||
return false;
|
||||
// In NukeWars, only block sending to enemy teams
|
||||
} else if (gc.gameMode === GameMode.Team && gc.teamGameType === TeamGameType.NukeWars) {
|
||||
if (other.isPlayer() && player.isOnSameTeam(other as Player)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (game.isOceanShore(dst)) {
|
||||
let myPlayerBordersOcean = false;
|
||||
@@ -85,7 +85,8 @@ export function canBuildTransportShip(
|
||||
// Block lake deployments into enemy team territory in Nuke Wars
|
||||
const gc = game.config().gameConfig();
|
||||
if (
|
||||
gc.gameMode === GameMode.NukeWars &&
|
||||
gc.gameMode === GameMode.Team &&
|
||||
gc.teamGameType === TeamGameType.NukeWars &&
|
||||
gc.gameMap === GameMapType.Baikal
|
||||
) {
|
||||
const tileOwner = game.owner(t);
|
||||
|
||||
Reference in New Issue
Block a user