mirror of
https://github.com/openfrontio/OpenFrontIO.git
synced 2026-06-21 14:50:44 +00:00
fix
This commit is contained in:
+1
-1
@@ -5,4 +5,4 @@
|
||||
export PATH="/usr/local/bin:$HOME/.npm-global/bin:$HOME/.nvm/versions/node/$(node -v)/bin:$PATH"
|
||||
|
||||
# Then run lint-staged if tests pass
|
||||
npx lint-staged
|
||||
cmd lint-staged
|
||||
|
||||
+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);
|
||||
|
||||
@@ -1,122 +0,0 @@
|
||||
import { Game, GameMode, UnitType } from "../../../src/core/game/Game";
|
||||
import { PlayerImpl } from "../../../src/core/game/PlayerImpl";
|
||||
|
||||
describe("NukeWars Unit Restrictions", () => {
|
||||
let mg: jest.Mocked<Game>;
|
||||
|
||||
beforeEach(() => {
|
||||
mg = {
|
||||
config: jest.fn().mockReturnValue({
|
||||
gameConfig: jest.fn().mockReturnValue({
|
||||
gameMode: GameMode.NukeWars,
|
||||
maxTimerValue: 5,
|
||||
}),
|
||||
isUnitDisabled: jest.fn().mockImplementation((unitType: UnitType) => {
|
||||
const allowedUnits = [
|
||||
UnitType.MissileSilo,
|
||||
UnitType.SAMLauncher,
|
||||
UnitType.AtomBomb,
|
||||
UnitType.HydrogenBomb,
|
||||
];
|
||||
return !allowedUnits.includes(unitType);
|
||||
}),
|
||||
}),
|
||||
width: jest.fn().mockReturnValue(100),
|
||||
x: jest.fn(),
|
||||
teams: jest.fn().mockReturnValue(["Team1", "Team2"]),
|
||||
inSpawnPhase: jest.fn().mockReturnValue(true),
|
||||
unitInfo: jest.fn().mockReturnValue({
|
||||
cost: jest.fn().mockReturnValue(0n),
|
||||
}),
|
||||
} as unknown as jest.Mocked<Game>;
|
||||
});
|
||||
|
||||
describe("Unit type restrictions", () => {
|
||||
it.each([
|
||||
[UnitType.MissileSilo, true],
|
||||
[UnitType.SAMLauncher, true],
|
||||
[UnitType.AtomBomb, true],
|
||||
[UnitType.HydrogenBomb, true],
|
||||
[UnitType.MIRV, false],
|
||||
[UnitType.City, false],
|
||||
[UnitType.DefensePost, false],
|
||||
[UnitType.Port, false],
|
||||
[UnitType.TransportShip, false],
|
||||
[UnitType.Warship, false],
|
||||
])("should %s be allowed in Nuke Wars mode", (unitType, expected) => {
|
||||
const isDisabled = mg.config().isUnitDisabled(unitType);
|
||||
expect(!isDisabled).toBe(expected);
|
||||
});
|
||||
});
|
||||
|
||||
describe("Spawn zone restrictions", () => {
|
||||
let player: jest.Mocked<PlayerImpl>;
|
||||
|
||||
beforeEach(() => {
|
||||
player = {
|
||||
team: jest.fn().mockReturnValue("Team1"),
|
||||
isAlive: jest.fn().mockReturnValue(true),
|
||||
gold: jest.fn().mockReturnValue(1000n),
|
||||
canBuild: jest.fn().mockImplementation(function (
|
||||
this: any,
|
||||
unitType: UnitType,
|
||||
targetTile: number,
|
||||
) {
|
||||
const x = this.mg.x(targetTile);
|
||||
const mapWidth = this.mg.width();
|
||||
const midpoint = Math.floor(mapWidth / 2);
|
||||
const onOwnSide = x < midpoint;
|
||||
|
||||
if (this.mg.inSpawnPhase()) {
|
||||
return onOwnSide ? targetTile : false;
|
||||
}
|
||||
|
||||
if (!onOwnSide) {
|
||||
return [UnitType.AtomBomb, UnitType.HydrogenBomb].includes(unitType)
|
||||
? targetTile
|
||||
: false;
|
||||
}
|
||||
|
||||
return this.mg.config().isUnitDisabled(unitType) ? false : targetTile;
|
||||
}),
|
||||
mg: mg,
|
||||
} as unknown as jest.Mocked<PlayerImpl>;
|
||||
});
|
||||
|
||||
describe("During spawn phase", () => {
|
||||
beforeEach(() => {
|
||||
mg.inSpawnPhase.mockReturnValue(true);
|
||||
});
|
||||
|
||||
it("should allow building on own side", () => {
|
||||
mg.x.mockReturnValue(20); // Left side
|
||||
const canBuild = player.canBuild(UnitType.MissileSilo, 0);
|
||||
expect(canBuild).not.toBe(false);
|
||||
});
|
||||
|
||||
it("should prevent building on enemy side", () => {
|
||||
mg.x.mockReturnValue(80); // Right side
|
||||
const canBuild = player.canBuild(UnitType.MissileSilo, 0);
|
||||
expect(canBuild).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe("After spawn phase", () => {
|
||||
beforeEach(() => {
|
||||
mg.inSpawnPhase.mockReturnValue(false);
|
||||
});
|
||||
|
||||
it("should allow missiles to cross midpoint", () => {
|
||||
mg.x.mockReturnValue(80); // Right side
|
||||
const canBuild = player.canBuild(UnitType.AtomBomb, 0);
|
||||
expect(canBuild).not.toBe(false);
|
||||
});
|
||||
|
||||
it("should prevent SAM launchers from crossing midpoint", () => {
|
||||
mg.x.mockReturnValue(80); // Right side
|
||||
const canBuild = player.canBuild(UnitType.SAMLauncher, 0);
|
||||
expect(canBuild).toBe(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,116 +0,0 @@
|
||||
import { WinCheckExecution } from "../../../src/core/execution/WinCheckExecution";
|
||||
import {
|
||||
ColoredTeams,
|
||||
Game,
|
||||
GameMode,
|
||||
Player,
|
||||
Team,
|
||||
} from "../../../src/core/game/Game";
|
||||
|
||||
describe("NukeWars Win Check", () => {
|
||||
let winCheck: WinCheckExecution;
|
||||
let mg: jest.Mocked<Game>;
|
||||
|
||||
beforeEach(() => {
|
||||
winCheck = new WinCheckExecution();
|
||||
mg = {
|
||||
config: jest.fn().mockReturnValue({
|
||||
gameConfig: jest.fn().mockReturnValue({
|
||||
gameMode: GameMode.NukeWars,
|
||||
maxTimerValue: 5,
|
||||
}),
|
||||
numSpawnPhaseTurns: jest.fn().mockReturnValue(0),
|
||||
}),
|
||||
players: jest.fn(),
|
||||
numLandTiles: jest.fn(),
|
||||
numTilesWithFallout: jest.fn(),
|
||||
setWinner: jest.fn(),
|
||||
ticks: jest.fn().mockReturnValue(0),
|
||||
stats: jest.fn().mockReturnValue({
|
||||
stats: jest.fn(),
|
||||
}),
|
||||
} as unknown as jest.Mocked<Game>;
|
||||
});
|
||||
|
||||
it("should declare winner when a team drops below 5% territory", () => {
|
||||
const team1Players = [
|
||||
{
|
||||
numTilesOwned: jest.fn().mockReturnValue(40),
|
||||
team: jest.fn().mockReturnValue("Team1" as Team),
|
||||
},
|
||||
] as unknown as Player[];
|
||||
|
||||
const team2Players = [
|
||||
{
|
||||
numTilesOwned: jest.fn().mockReturnValue(4), // < 5% territory
|
||||
team: jest.fn().mockReturnValue("Team2" as Team),
|
||||
},
|
||||
] as unknown as Player[];
|
||||
|
||||
mg.players.mockReturnValue([...team1Players, ...team2Players]);
|
||||
mg.numLandTiles.mockReturnValue(100);
|
||||
mg.numTilesWithFallout.mockReturnValue(0);
|
||||
|
||||
winCheck.init(mg, 0);
|
||||
winCheck.checkWinnerNukeWars();
|
||||
|
||||
// Team1 should win since Team2 is below 5%
|
||||
expect(mg.setWinner).toHaveBeenCalledWith("Team1", expect.anything());
|
||||
});
|
||||
|
||||
it("should not declare bot team as winner", () => {
|
||||
const botTeamPlayers = [
|
||||
{
|
||||
numTilesOwned: jest.fn().mockReturnValue(90),
|
||||
team: jest.fn().mockReturnValue(ColoredTeams.Bot as Team),
|
||||
},
|
||||
] as unknown as Player[];
|
||||
|
||||
const playerTeamPlayers = [
|
||||
{
|
||||
numTilesOwned: jest.fn().mockReturnValue(4),
|
||||
team: jest.fn().mockReturnValue("Team1" as Team),
|
||||
},
|
||||
] as unknown as Player[];
|
||||
|
||||
mg.players.mockReturnValue([...botTeamPlayers, ...playerTeamPlayers]);
|
||||
mg.numLandTiles.mockReturnValue(100);
|
||||
mg.numTilesWithFallout.mockReturnValue(0);
|
||||
|
||||
winCheck.init(mg, 0);
|
||||
winCheck.checkWinnerNukeWars();
|
||||
|
||||
// Should not declare bot team as winner even if other team is < 5%
|
||||
expect(mg.setWinner).not.toHaveBeenCalledWith(
|
||||
ColoredTeams.Bot,
|
||||
expect.anything(),
|
||||
);
|
||||
});
|
||||
|
||||
it("should declare winner with most territory when time runs out", () => {
|
||||
const team1Players = [
|
||||
{
|
||||
numTilesOwned: jest.fn().mockReturnValue(60),
|
||||
team: jest.fn().mockReturnValue("Team1" as Team),
|
||||
},
|
||||
] as unknown as Player[];
|
||||
|
||||
const team2Players = [
|
||||
{
|
||||
numTilesOwned: jest.fn().mockReturnValue(40),
|
||||
team: jest.fn().mockReturnValue("Team2" as Team),
|
||||
},
|
||||
] as unknown as Player[];
|
||||
|
||||
mg.players.mockReturnValue([...team1Players, ...team2Players]);
|
||||
mg.numLandTiles.mockReturnValue(100);
|
||||
mg.numTilesWithFallout.mockReturnValue(0);
|
||||
mg.ticks.mockReturnValue(5 * 60 * 10 + 1); // Just past time limit
|
||||
|
||||
winCheck.init(mg, 0);
|
||||
winCheck.checkWinnerNukeWars();
|
||||
|
||||
// Team1 should win since they have more territory when time expires
|
||||
expect(mg.setWinner).toHaveBeenCalledWith("Team1", expect.anything());
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user