add hospital unit

This commit is contained in:
1brucben
2025-06-03 18:22:03 +02:00
parent 62fd44ab6b
commit cc9ad11aff
11 changed files with 112 additions and 2 deletions
+3
View File
@@ -0,0 +1,3 @@
<svg width="800" height="800" viewBox="0 0 800 800" xmlns="http://www.w3.org/2000/svg">
<text x="400" y="570" font-size="600" font-family="Arial, sans-serif" font-weight="bold" text-anchor="middle" fill="white">H</text>
</svg>

After

Width:  |  Height:  |  Size: 229 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 156 B

+4 -2
View File
@@ -225,7 +225,8 @@
"sam_launcher": "SAM Launcher",
"atom_bomb": "Atom Bomb",
"hydrogen_bomb": "Hydrogen Bomb",
"mirv": "MIRV"
"mirv": "MIRV",
"hospital": "Hospital"
},
"user_setting": {
"title": "User Settings",
@@ -354,7 +355,8 @@
"warship": "Captures trade ships, destroys ships and boats",
"port": "Sends trade ships to generate gold",
"defense_post": "Increase defenses of nearby borders",
"city": "Increase max population"
"city": "Increase max population",
"hospital": "Boosts population growth by 5%"
},
"not_enough_money": "Not enough money"
},
+8
View File
@@ -3,6 +3,7 @@ import { customElement, state } from "lit/decorators.js";
import warshipIcon from "../../../../resources/images/BattleshipIconWhite.svg";
import cityIcon from "../../../../resources/images/CityIconWhite.svg";
import goldCoinIcon from "../../../../resources/images/GoldCoinIcon.svg";
import hospitalIcon from "../../../../resources/images/HospitalIconWhite.svg";
import mirvIcon from "../../../../resources/images/MIRVIcon.svg";
import missileSiloIcon from "../../../../resources/images/MissileSiloIconWhite.svg";
import hydrogenBombIcon from "../../../../resources/images/MushroomCloudIconWhite.svg";
@@ -93,6 +94,13 @@ const buildTable: BuildItemDisplay[][] = [
key: "unit_type.city",
countable: true,
},
{
unitType: UnitType.Hospital,
icon: hospitalIcon,
description: "build_menu.desc.hospital",
key: "unit_type.hospital",
countable: true,
},
],
];
@@ -8,6 +8,7 @@ import { UnitInfoModal } from "./UnitInfoModal";
import cityIcon from "../../../../resources/images/buildings/cityAlt1.png";
import shieldIcon from "../../../../resources/images/buildings/fortAlt2.png";
import hospitalIcon from "../../../../resources/images/buildings/hospital.png";
import anchorIcon from "../../../../resources/images/buildings/port1.png";
import MissileSiloReloadingIcon from "../../../../resources/images/buildings/silo1-reloading.png";
import missileSiloIcon from "../../../../resources/images/buildings/silo1.png";
@@ -83,6 +84,12 @@ export class StructureLayer implements Layer {
territoryRadius: 6.525,
borderType: UnitBorderType.Square,
},
[UnitType.Hospital]: {
icon: hospitalIcon,
borderRadius: 8.525,
territoryRadius: 6.525,
borderType: UnitBorderType.Square,
},
};
constructor(
@@ -18,6 +18,7 @@ const unitOptions: { type: UnitType; translationKey: string }[] = [
{ type: UnitType.AtomBomb, translationKey: "unit_type.atom_bomb" },
{ type: UnitType.HydrogenBomb, translationKey: "unit_type.hydrogen_bomb" },
{ type: UnitType.MIRV, translationKey: "unit_type.mirv" },
{ type: UnitType.Hospital, translationKey: "unit_type.hospital" },
];
export function renderUnitTypeOptions({
+21
View File
@@ -435,6 +435,23 @@ export class DefaultConfig implements Config {
cost: () => 0n,
territoryBound: true,
};
case UnitType.Hospital:
return {
cost: (p: Player) =>
p.type() === PlayerType.Human && this.infiniteGold()
? 0n
: BigInt(
Math.min(
12_000_000,
Math.pow(
2,
p.unitsIncludingConstruction(UnitType.City).length,
) * 3_000_000,
),
),
territoryBound: true,
constructionDuration: this.instantBuild() ? 0 : 2 * 10,
};
default:
assertNever(type);
}
@@ -677,6 +694,10 @@ export class DefaultConfig implements Config {
toAdd *= 0.7;
}
if (player.units(UnitType.Hospital).length > 0) {
toAdd *= 1 + 0.05 * player.units(UnitType.Hospital).length;
// hospital boosts population growth
}
if (player.type() === PlayerType.FakeHuman) {
switch (this._gameConfig.difficulty) {
case Difficulty.Easy:
@@ -12,6 +12,7 @@ import {
import { TileRef } from "../game/GameMap";
import { CityExecution } from "./CityExecution";
import { DefensePostExecution } from "./DefensePostExecution";
import { HospitalExecution } from "./HospitalExecution";
import { MirvExecution } from "./MIRVExecution";
import { MissileSiloExecution } from "./MissileSiloExecution";
import { NukeExecution } from "./NukeExecution";
@@ -124,6 +125,9 @@ export class ConstructionExecution implements Execution {
case UnitType.City:
this.mg.addExecution(new CityExecution(player.id(), this.tile));
break;
case UnitType.Hospital:
this.mg.addExecution(new HospitalExecution(player.id(), this.tile));
break;
default:
throw Error(`unit type ${this.constructionType} not supported`);
}
+60
View File
@@ -0,0 +1,60 @@
import { consolex } from "../Consolex";
import {
Execution,
Game,
Player,
PlayerID,
Unit,
UnitType,
} from "../game/Game";
import { TileRef } from "../game/GameMap";
export class HospitalExecution implements Execution {
private player: Player;
private mg: Game;
private hospital: Unit | null = null;
private active: boolean = true;
constructor(
private ownerId: PlayerID,
private tile: TileRef,
) {}
init(mg: Game, ticks: number): void {
this.mg = mg;
if (!mg.hasPlayer(this.ownerId)) {
console.warn(`HospitalExecution: player ${this.ownerId} not found`);
this.active = false;
return;
}
this.player = mg.player(this.ownerId);
}
tick(ticks: number): void {
if (this.hospital === null) {
const spawnTile = this.player.canBuild(UnitType.Hospital, this.tile);
if (spawnTile === false) {
consolex.warn("cannot build hospital");
this.active = false;
return;
}
this.hospital = this.player.buildUnit(UnitType.Hospital, spawnTile, {});
}
if (!this.hospital.isActive()) {
this.active = false;
return;
}
if (this.player !== this.hospital.owner()) {
this.player = this.hospital.owner();
}
}
isActive(): boolean {
return this.active;
}
activeDuringSpawnPhase(): boolean {
return false;
}
}
+3
View File
@@ -148,6 +148,7 @@ export enum UnitType {
MIRV = "MIRV",
MIRVWarhead = "MIRV Warhead",
Construction = "Construction",
Hospital = "Hospital",
}
export interface OwnerComp {
@@ -195,6 +196,8 @@ export interface UnitParamsMap {
[UnitType.MIRV]: {};
[UnitType.Hospital]: {};
[UnitType.MIRVWarhead]: {
targetTile?: number;
};
+1
View File
@@ -809,6 +809,7 @@ export class PlayerImpl implements Player {
case UnitType.DefensePost:
case UnitType.SAMLauncher:
case UnitType.City:
case UnitType.Hospital:
case UnitType.Construction:
return this.landBasedStructureSpawn(targetTile, validTiles);
default: