From cddcc681dde4809734699e85a06d5ff90845c9a4 Mon Sep 17 00:00:00 2001 From: Aotumuri Date: Wed, 7 May 2025 22:14:54 +0900 Subject: [PATCH] Added custom disable settings (#593) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Description: I will write an issue later as I don't have time. ![スクリーンショット 2025-04-23 22 04 24](https://github.com/user-attachments/assets/77754140-eee9-46bd-a98f-a3abec35ca6a) スクリーンショット 2025-04-23 22 04 40 スクリーンショット 2025-04-23 22 04 47 ## Please complete the following: - [x] I have added screenshots for all UI updates - [x] I confirm I have thoroughly tested these changes and take full responsibility for any bugs introduced - [x] I understand that submitting code with bugs that could have been caught through manual testing blocks releases and new features for all contributors ## Please put your Discord username so you can be contacted if a bug or regression is found: aotumuri --- resources/lang/en.json | 14 +++- resources/lang/ja.json | 15 ++++- src/client/HostLobbyModal.ts | 81 ++++++++++++++++++++---- src/client/SinglePlayerModal.ts | 73 ++++++++++++++++----- src/client/graphics/layers/BuildMenu.ts | 18 +----- src/core/Schemas.ts | 3 +- src/core/configuration/Config.ts | 2 +- src/core/configuration/DefaultConfig.ts | 5 +- src/core/execution/FakeHumanExecution.ts | 4 +- src/core/game/PlayerImpl.ts | 21 +++--- src/server/GameManager.ts | 2 +- src/server/GameServer.ts | 8 ++- src/server/Worker.ts | 2 +- 13 files changed, 177 insertions(+), 71 deletions(-) diff --git a/resources/lang/en.json b/resources/lang/en.json index 62a7153d7..871b516bd 100644 --- a/resources/lang/en.json +++ b/resources/lang/en.json @@ -101,6 +101,7 @@ "infinite_gold": "Infinite gold", "infinite_troops": "Infinite troops", "disable_nukes": "Disable Nukes", + "enables_title": "Enable Settings", "start": "Start Game" }, "map": { @@ -167,7 +168,7 @@ "instant_build": "Instant build", "infinite_gold": "Infinite gold", "infinite_troops": "Infinite troops", - "disable_nukes": "Disable Nukes", + "enables_title": "Enable Settings", "player": "Player", "players": "Players", "waiting": "Waiting for players...", @@ -191,6 +192,17 @@ "select_lang": { "title": "Select Language" }, + "unit_type": { + "city": "City", + "defense_post": "Defense Post", + "port": "Port", + "warship": "Warship", + "missile_silo": "Missile Silo", + "sam_launcher": "SAM Launcher", + "atom_bomb": "Atom Bomb", + "hydrogen_bomb": "Hydrogen Bomb", + "mirv": "MIRV" + }, "user_setting": { "title": "User Settings", "tab_basic": "Basic Settings", diff --git a/resources/lang/ja.json b/resources/lang/ja.json index 98e89edbd..06eb8d9c3 100644 --- a/resources/lang/ja.json +++ b/resources/lang/ja.json @@ -97,7 +97,7 @@ "instant_build": "即時建設", "infinite_gold": "資金無限", "infinite_troops": "兵士無限", - "disable_nukes": "核兵器使用禁止", + "enables_title": "有効化設定", "start": "ゲーム開始" }, "map": { @@ -158,7 +158,7 @@ "instant_build": "実在する国家を無効化", "infinite_gold": "資金無限", "infinite_troops": "兵士無限", - "disable_nukes": "核兵器使用禁止", + "enables_title": "有効化設定", "player": "プレイヤー", "players": "プレイヤー", "waiting": "他のプレイヤーの参加を待っています...", @@ -182,6 +182,17 @@ "select_lang": { "title": "言語を選択" }, + "unit_type": { + "city": "都市", + "defense_post": "防衛ポスト", + "port": "港", + "warship": "戦艦", + "missile_silo": "ミサイル格納庫", + "sam_launcher": "SAMランチャー", + "atom_bomb": "原子爆弾", + "hydrogen_bomb": "水素爆弾", + "mirv": "MIRV" + }, "user_setting": { "title": "ユーザー設定", "tab_basic": "基本設定", diff --git a/src/client/HostLobbyModal.ts b/src/client/HostLobbyModal.ts index 86b6197b5..0f86f05b8 100644 --- a/src/client/HostLobbyModal.ts +++ b/src/client/HostLobbyModal.ts @@ -9,6 +9,7 @@ import { Duos, GameMapType, GameMode, + UnitType, mapCategories, } from "../core/game/Game"; import { GameConfig, GameInfo } from "../core/Schemas"; @@ -39,6 +40,7 @@ export class HostLobbyModal extends LitElement { @state() private copySuccess = false; @state() private players: string[] = []; @state() private useRandomMap: boolean = false; + @state() private disabledUnits: string[] = []; private playersInterval = null; // Add a new timer for debouncing bot changes @@ -302,21 +304,72 @@ export class HostLobbyModal extends LitElement { - + - +
+
+ ${translateText("single_modal.enables_title")} +
+
+ ${[ + [UnitType.City, "unit_type.city"], + [UnitType.DefensePost, "unit_type.defense_post"], + [UnitType.Port, "unit_type.port"], + [UnitType.Warship, "unit_type.warship"], + [UnitType.MissileSilo, "unit_type.missile_silo"], + [UnitType.SAMLauncher, "unit_type.sam_launcher"], + [UnitType.AtomBomb, "unit_type.atom_bomb"], + [UnitType.HydrogenBomb, "unit_type.hydrogen_bomb"], + [UnitType.MIRV, "unit_type.mirv"], + ].map( + ([unitType, translationKey]) => html` + + `, + )}
@@ -419,6 +461,7 @@ export class SinglePlayerModal extends LitElement { infiniteGold: this.infiniteGold, infiniteTroops: this.infiniteTroops, instantBuild: this.instantBuild, + disabledUnits: this.disabledUnits, }, }, } as JoinLobbyEvent, diff --git a/src/client/graphics/layers/BuildMenu.ts b/src/client/graphics/layers/BuildMenu.ts index ed3a477d8..a4105c46f 100644 --- a/src/client/graphics/layers/BuildMenu.ts +++ b/src/client/graphics/layers/BuildMenu.ts @@ -409,21 +409,9 @@ export class BuildMenu extends LitElement implements Layer { } private getBuildableUnits(): BuildItemDisplay[][] { - if (this.game?.config()?.disableNukes()) { - return buildTable.map((row) => - row.filter( - (item) => - ![ - UnitType.AtomBomb, - UnitType.MIRV, - UnitType.HydrogenBomb, - UnitType.MissileSilo, - UnitType.SAMLauncher, - ].includes(item.unitType), - ), - ); - } - return buildTable; + return buildTable.map((row) => + row.filter((item) => !this.game?.config()?.isUnitDisabled(item.unitType)), + ); } get isVisible() { diff --git a/src/core/Schemas.ts b/src/core/Schemas.ts index b08fcfcfb..fba00a877 100644 --- a/src/core/Schemas.ts +++ b/src/core/Schemas.ts @@ -116,12 +116,13 @@ const GameConfigSchema = z.object({ gameType: z.nativeEnum(GameType), gameMode: z.nativeEnum(GameMode), disableNPCs: z.boolean(), - disableNukes: z.boolean(), bots: z.number().int().min(0).max(400), infiniteGold: z.boolean(), infiniteTroops: z.boolean(), instantBuild: z.boolean(), maxPlayers: z.number().optional(), + numPlayerTeams: z.number().optional(), + disabledUnits: z.array(z.nativeEnum(UnitType)).optional(), playerTeams: z.union([z.number().optional(), z.literal(Duos)]), }); diff --git a/src/core/configuration/Config.ts b/src/core/configuration/Config.ts index 1442dd814..9f55f8b52 100644 --- a/src/core/configuration/Config.ts +++ b/src/core/configuration/Config.ts @@ -66,7 +66,7 @@ export interface Config { percentageTilesOwnedToWin(): number; numBots(): number; spawnNPCs(): boolean; - disableNukes(): boolean; + isUnitDisabled(unitType: UnitType): boolean; bots(): number; infiniteGold(): boolean; infiniteTroops(): boolean; diff --git a/src/core/configuration/DefaultConfig.ts b/src/core/configuration/DefaultConfig.ts index dfbca1d77..660820fd8 100644 --- a/src/core/configuration/DefaultConfig.ts +++ b/src/core/configuration/DefaultConfig.ts @@ -231,9 +231,10 @@ export class DefaultConfig implements Config { return !this._gameConfig.disableNPCs; } - disableNukes(): boolean { - return this._gameConfig.disableNukes; + isUnitDisabled(unitType: UnitType): boolean { + return this._gameConfig.disabledUnits?.includes(unitType) ?? false; } + bots(): number { return this._gameConfig.bots; } diff --git a/src/core/execution/FakeHumanExecution.ts b/src/core/execution/FakeHumanExecution.ts index 9870fe662..358164931 100644 --- a/src/core/execution/FakeHumanExecution.ts +++ b/src/core/execution/FakeHumanExecution.ts @@ -421,9 +421,7 @@ export class FakeHumanExecution implements Execution { if (this.maybeSpawnWarship()) { return; } - if (!this.mg.config().disableNukes()) { - this.maybeSpawnStructure(UnitType.MissileSilo, 1); - } + this.maybeSpawnStructure(UnitType.MissileSilo, 1); } private maybeSpawnStructure(type: UnitType, maxNum: number) { diff --git a/src/core/game/PlayerImpl.ts b/src/core/game/PlayerImpl.ts index b2046cd40..55972adc5 100644 --- a/src/core/game/PlayerImpl.ts +++ b/src/core/game/PlayerImpl.ts @@ -709,6 +709,12 @@ export class PlayerImpl implements Player { spawnTile: TileRef, unitSpecificInfos: UnitSpecificInfos = {}, ): UnitImpl { + if (this.mg.config().isUnitDisabled(type)) { + throw new Error( + `Attempted to build disabled unit ${type} at tile ${spawnTile} by player ${this.name()}`, + ); + } + const cost = this.mg.unitInfo(type).cost(this); const b = new UnitImpl( type, @@ -746,19 +752,8 @@ export class PlayerImpl implements Player { targetTile: TileRef, validTiles: TileRef[] | null = null, ): TileRef | false { - // prevent the building of nukes and nuke related buildings - if (this.mg.config().disableNukes()) { - if ( - unitType === UnitType.MissileSilo || - unitType === UnitType.MIRV || - unitType === UnitType.AtomBomb || - unitType === UnitType.HydrogenBomb || - unitType === UnitType.SAMLauncher || - unitType === UnitType.SAMMissile || - unitType === UnitType.MIRVWarhead - ) { - return false; - } + if (this.mg.config().isUnitDisabled(unitType)) { + return false; } const cost = this.mg.unitInfo(unitType).cost(this); diff --git a/src/server/GameManager.ts b/src/server/GameManager.ts index 2a4e196c5..c2a890e9d 100644 --- a/src/server/GameManager.ts +++ b/src/server/GameManager.ts @@ -34,12 +34,12 @@ export class GameManager { gameType: GameType.Private, difficulty: Difficulty.Medium, disableNPCs: false, - disableNukes: false, infiniteGold: false, infiniteTroops: false, instantBuild: false, gameMode: GameMode.FFA, bots: 400, + disabledUnits: [], ...gameConfig, }); this.games.set(id, game); diff --git a/src/server/GameServer.ts b/src/server/GameServer.ts index c655a1cf4..df95296f9 100644 --- a/src/server/GameServer.ts +++ b/src/server/GameServer.ts @@ -77,9 +77,6 @@ export class GameServer { if (gameConfig.disableNPCs != null) { this.gameConfig.disableNPCs = gameConfig.disableNPCs; } - if (gameConfig.disableNukes != null) { - this.gameConfig.disableNukes = gameConfig.disableNukes; - } if (gameConfig.bots != null) { this.gameConfig.bots = gameConfig.bots; } @@ -95,6 +92,11 @@ export class GameServer { if (gameConfig.gameMode != null) { this.gameConfig.gameMode = gameConfig.gameMode; } + + if (gameConfig.disabledUnits != null) { + this.gameConfig.disabledUnits = gameConfig.disabledUnits; + } + if (gameConfig.playerTeams != null) { this.gameConfig.playerTeams = gameConfig.playerTeams; } diff --git a/src/server/Worker.ts b/src/server/Worker.ts index 3307d5629..880dca263 100644 --- a/src/server/Worker.ts +++ b/src/server/Worker.ts @@ -162,7 +162,7 @@ export function startWorker() { instantBuild: req.body.instantBuild, bots: req.body.bots, disableNPCs: req.body.disableNPCs, - disableNukes: req.body.disableNukes, + disabledUnits: req.body.disabledUnits, gameMode: req.body.gameMode, playerTeams: req.body.playerTeams, });