Implement basic energy system

This commit is contained in:
Aelita4 2025-01-24 16:22:27 +01:00
parent b1e17b16d3
commit d4dcc1e759
Signed by: Aelita4
GPG Key ID: E44490C2025906C1
12 changed files with 271 additions and 7 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 399 B

View File

@ -67,13 +67,20 @@ const listOfElements: Array<NavElement> = [{
url: "/register", url: "/register",
show: "notLoggedInOnly", show: "notLoggedInOnly",
position: "bottom" position: "bottom"
},{ }, {
id: "overview", id: "overview",
title: getName(lang, "general", "nav-overview"), title: getName(lang, "general", "nav-overview"),
type: "simple", type: "simple",
url: "/game", url: "/game",
show: "loggedInOnly", show: "loggedInOnly",
position: "bottom" position: "bottom"
}, {
id: "energy",
title: getName(lang, "general", "nav-energy"),
type: "simple",
url: "/game/energy",
show: "loggedInOnly",
position: "bottom"
}, { }, {
id: "buildings", id: "buildings",
title: getName(lang, "general", "nav-buildings"), title: getName(lang, "general", "nav-buildings"),

View File

@ -53,8 +53,21 @@ if(!(planet instanceof SystemManager)) {
} }
--- ---
<div id="resourcebar"> <div id="resourcebar">
<!-- Energy: <span class={`${planet.energy.consumption > planet.energy.production ? "prod-full" : planet.energy.consumption >= (planet.energy.production * 0.9) ? "prod-almost-full" : ""}`}>{planet.energy.consumption}/{planet.energy.production}</span> -->
<div class="resourcebar-item">
<Image src="/images/resources/energy.png" alt="energy" class="icon" width={32} height={32} />
<div class="text">
<span class="line1"><!--{getName(lang, 'resources', 'energy')}-->Energy</span>
<span class={`line2 ${planet.energy.consumption > planet.energy.production ? "prod-full" : planet.energy.consumption >= (planet.energy.production * 0.9) ? "prod-almost-full" : ""}`}>{planet.energy.consumption}/{planet.energy.production}</span>
</div>
<div class="resourcebar-item-tooltip">
<span class="resourcebar-item-tooltip-name">{getName(lang, 'general', 'production')}</span><span class={`resourcebar-item-tooltip-amount`}>{planet.energy.production}</span>
<span class="resourcebar-item-tooltip-name">{getName(lang, 'general', 'consumption')}</span><span class="resourcebar-item-tooltip-amount">{planet.energy.consumption}</span>
<span class="resourcebar-item-tooltip-name">{getName(lang, 'general', 'balance')}</span><span class={`resourcebar-item-tooltip-amount ${planet.energy.consumption > planet.energy.production ? "prod-full" : planet.energy.consumption >= (planet.energy.production * 0.9) ? "prod-almost-full" : ""}`}>{planet.energy.production - planet.energy.consumption}</span>
</div>
</div>
{resourceArray.map(res => {resourceArray.map(res =>
<div class="resourcebar-item" <div class="resourcebar-item resourcebar-iterable"
data-res-type={resourceTypes.find(x => x.id === res.id)?.type ?? "solid"} data-res-type={resourceTypes.find(x => x.id === res.id)?.type ?? "solid"}
data-res-id={res.id} data-res-id={res.id}
data-res-amount={res.amount} data-res-amount={res.amount}
@ -227,7 +240,7 @@ if(!(planet instanceof SystemManager)) {
} }
function init() { function init() {
const resourcebarItems = document.getElementById('resourcebar')?.querySelectorAll('.resourcebar-item'); const resourcebarItems = document.getElementById('resourcebar')?.querySelectorAll('.resourcebar-iterable');
resourcebarItems?.forEach((item: any) => { resourcebarItems?.forEach((item: any) => {
const resourceAmount = parseFloat(item.dataset.resAmount ?? '0'); const resourceAmount = parseFloat(item.dataset.resAmount ?? '0');
const miningRate = parseInt(item.dataset.resMiningRate ?? '0') / 3600; const miningRate = parseInt(item.dataset.resMiningRate ?? '0') / 3600;

View File

@ -5,11 +5,13 @@ export default class Building {
manager: BuildingManager manager: BuildingManager
data: DBBuilding; data: DBBuilding;
level: number; level: number;
activePercent: number = 100;
constructor(manager: BuildingManager, data: DBBuilding, level: number) { constructor(manager: BuildingManager, data: DBBuilding, level: number, activePercent?: number) {
this.manager = manager; this.manager = manager;
this.data = data; this.data = data;
this.level = level; this.level = level;
if(activePercent !== undefined) this.activePercent = activePercent;
} }
async checkRequiredResources(level: number): Promise<boolean> { async checkRequiredResources(level: number): Promise<boolean> {
@ -38,7 +40,7 @@ export default class Building {
const playerBuildings = this.manager.buildings; const playerBuildings = this.manager.buildings;
let playerBuildingsCanBuild = { canBuild: true, missing: "" }; let playerBuildingsCanBuild = { canBuild: true, missing: "" };
this.data.requirements.buildings.forEach((buildingReq: any) => { this.data.requirements.buildings.forEach((buildingReq: any) => {
if(playerBuildings.filter((building) => building.data.id === buildingReq.id)[0]?.level ?? 0 < buildingReq.level) { if((playerBuildings.filter((building) => building.data.id === buildingReq.id)[0]?.level ?? 0) < buildingReq.level) {
playerBuildingsCanBuild = { canBuild: false, missing: `${buildingReq.id} level ${buildingReq.level} required, found ${playerBuildings.filter((building) => building.data.id === buildingReq.id)[0]?.level ?? 0}` }; playerBuildingsCanBuild = { canBuild: false, missing: `${buildingReq.id} level ${buildingReq.level} required, found ${playerBuildings.filter((building) => building.data.id === buildingReq.id)[0]?.level ?? 0}` };
return; return;
} }

View File

@ -0,0 +1,29 @@
import { Planet } from "./PlanetManager";
import EnergyManager from "./abstract/EnergyManager";
export default class PlanetEnergyManager extends EnergyManager {
constructor(system: Planet) {
super(system);
}
get manager() {
return this._manager as Planet;
}
update() {
const buildings = this.manager.buildings.buildings;
this.production = 0;
this.consumption = 0;
for(const building of buildings) {
if(building.data.category === "power-plants") {
this.production += (building.data.energy * building.level);
} else {
this.consumption += (building.data.energy * building.level);
}
}
return this;
}
}

View File

@ -4,6 +4,7 @@ import PlanetResourceManager from "./PlanetResourceManager";
import ShipManager from "./PlanetShipManager"; import ShipManager from "./PlanetShipManager";
import SystemManager from "./SystemManager"; import SystemManager from "./SystemManager";
import PlanetDefenseManager from "./PlanetDefenseManager"; import PlanetDefenseManager from "./PlanetDefenseManager";
import PlanetEnergyManager from "./PlanetEnergyManager";
export type Planet = { export type Planet = {
_id: ObjectId; _id: ObjectId;
@ -14,4 +15,5 @@ export type Planet = {
buildings: BuildingManager; buildings: BuildingManager;
ships: ShipManager; ships: ShipManager;
defenses: PlanetDefenseManager; defenses: PlanetDefenseManager;
energy: PlanetEnergyManager;
} }

View File

@ -0,0 +1,26 @@
import EnergyManager from "./abstract/EnergyManager";
import SystemManager from "./SystemManager";
export default class SystemEnergyManager extends EnergyManager {
constructor(system: SystemManager) {
super(system);
}
get manager() {
return this._manager as SystemManager;
}
update() {
const structures = this.manager.structures.structures;
for(const structure of structures) {
if(structure.data.id === "dyson-sphere") {
this.production += (structure.data.energy * structure.level);
} else {
this.consumption += (structure.data.energy * structure.level);
}
}
return this;
}
}

View File

@ -12,6 +12,8 @@ import SystemResourceManager from "./SystemResourceManager";
import SystemShipManager from "./SystemShipManager"; import SystemShipManager from "./SystemShipManager";
import PlanetDefenseManager from "./PlanetDefenseManager"; import PlanetDefenseManager from "./PlanetDefenseManager";
import SystemDefenseManager from "./SystemDefenseManager"; import SystemDefenseManager from "./SystemDefenseManager";
import SystemEnergyManager from "./SystemEnergyManager";
import PlanetEnergyManager from "./PlanetEnergyManager";
export type System = { export type System = {
_id: ObjectId, _id: ObjectId,
@ -31,6 +33,7 @@ export default class SystemManager {
resources: SystemResourceManager; resources: SystemResourceManager;
ships: SystemShipManager; ships: SystemShipManager;
defenses: SystemDefenseManager; defenses: SystemDefenseManager;
energy: SystemEnergyManager;
data: System; data: System;
constructor(data: System) { constructor(data: System) {
@ -39,6 +42,7 @@ export default class SystemManager {
this.resources = new SystemResourceManager(this); this.resources = new SystemResourceManager(this);
this.ships = new SystemShipManager(this); this.ships = new SystemShipManager(this);
this.defenses = new SystemDefenseManager(this); this.defenses = new SystemDefenseManager(this);
this.energy = new SystemEnergyManager(this);
} }
async fillData(systemData: DBSystem) { async fillData(systemData: DBSystem) {
@ -46,6 +50,7 @@ export default class SystemManager {
await this.resources.init(systemData.resources); await this.resources.init(systemData.resources);
await this.ships.init(systemData.ships); await this.ships.init(systemData.ships);
await this.defenses.init(systemData.defenses); await this.defenses.init(systemData.defenses);
this.energy.update();
await Promise.all(systemData.planets.map(async planetId => { await Promise.all(systemData.planets.map(async planetId => {
const planet = await getPlanetById(planetId); const planet = await getPlanetById(planetId);
@ -62,13 +67,16 @@ export default class SystemManager {
//@ts-ignore //@ts-ignore
ships: null, ships: null,
//@ts-ignore //@ts-ignore
defenses: null defenses: null,
//@ts-ignore
energy: null
} }
planetObject.resources = await new PlanetResourceManager(planetObject).init(planet.resources); planetObject.resources = await new PlanetResourceManager(planetObject).init(planet.resources);
planetObject.buildings = await new BuildingManager(planetObject).init(planet.buildings); planetObject.buildings = await new BuildingManager(planetObject).init(planet.buildings);
planetObject.ships = await new PlanetShipManager(planetObject).init(planet.ships); planetObject.ships = await new PlanetShipManager(planetObject).init(planet.ships);
planetObject.defenses = await new PlanetDefenseManager(planetObject).init(planet.defenses); planetObject.defenses = await new PlanetDefenseManager(planetObject).init(planet.defenses);
planetObject.energy = new PlanetEnergyManager(planetObject).update();
this.planets.push(planetObject); this.planets.push(planetObject);
})); }));

View File

@ -0,0 +1,14 @@
import { Planet } from "../PlanetManager";
import SystemManager from "../SystemManager";
export default abstract class EnergyManager {
protected _manager: Planet | SystemManager;
production: number = 0;
consumption: number = 0;
constructor(manager: Planet | SystemManager) {
this._manager = manager;
}
abstract update(): this;
}

View File

@ -115,6 +115,7 @@ export const POST: APIRoute = async({ request }) => {
await userPlanet.buildings.sync(); await userPlanet.buildings.sync();
await userPlanet.resources.sync(); await userPlanet.resources.sync();
userPlanet.energy.update();
return new Response( return new Response(
JSON.stringify({ JSON.stringify({

162
src/pages/game/energy.astro Normal file
View File

@ -0,0 +1,162 @@
---
import LoggedIn from '../../layouts/LoggedIn.astro';
import { Planet } from '../../lib/classes/managers/PlanetManager';
import SystemManager from '../../lib/classes/managers/SystemManager';
const { token, lang } = Astro.locals;
const active: SystemManager | Planet = Astro.locals.active;
if(active instanceof SystemManager) {
return Astro.redirect('/game');
}
if(Astro.request.method === "POST") {
const body = await Astro.request.formData();
for(const [key, value] of body.entries()) {
console.log(key, value);
}
return Astro.redirect('/game/energy');
}
const buildingsList = {
"mines": active.buildings.buildings.filter(building => building.data.category === "mines"),
"powerPlants": active.buildings.buildings.filter(building => building.data.category === "power-plants"),
"utilities": active.buildings.buildings.filter(building => building.data.category === "utilities"),
"storage": active.buildings.buildings.filter(building => building.data.category === "storage")
}
---
<LoggedIn id="energy" title="Energy">
<form method="post" class="form-container">
<table>
<tr class="table-col-header">
<th>Building name</th>
<th>Level</th>
<th>Production %</th>
<th>Production per hour</th>
<th>Energy usage</th>
</tr>
<tr><td colspan="5" class="table-separator">Mines</td></tr>
{buildingsList.mines.map(building => <tr>
<td>{building.data.id}</td>
<td>{building.level}</td>
<td><select name={`percent_${building.data.id}`}>
<option value="100" {...{ selected: (building.activePercent ?? 100) === 100 }}>100%</option>
<option value="90" {...{ selected: (building.activePercent ?? 100) === 90 }}>90%</option>
<option value="80" {...{ selected: (building.activePercent ?? 100) === 80 }}>80%</option>
<option value="70" {...{ selected: (building.activePercent ?? 100) === 70 }}>70%</option>
<option value="60" {...{ selected: (building.activePercent ?? 100) === 60 }}>60%</option>
<option value="50" {...{ selected: (building.activePercent ?? 100) === 50 }}>50%</option>
<option value="40" {...{ selected: (building.activePercent ?? 100) === 40 }}>40%</option>
<option value="30" {...{ selected: (building.activePercent ?? 100) === 30 }}>30%</option>
<option value="20" {...{ selected: (building.activePercent ?? 100) === 20 }}>20%</option>
<option value="10" {...{ selected: (building.activePercent ?? 100) === 10 }}>10%</option>
<option value="0" {...{ selected: (building.activePercent ?? 100) === 0 }}>0%</option>
</select></td>
<td>15</td>
<td class="red">-{building.level * building.data.energy}</td>
</tr>)}
<tr><td colspan="5" class="table-separator">Power plants</td></tr>
{buildingsList.powerPlants.map(building => <tr>
<td>{building.data.id}</td>
<td>{building.level}</td>
<td><select name={`percent_${building.data.id}`}>
<option value="100" {...{ selected: (building.activePercent ?? 100) === 100 }}>100%</option>
<option value="90" {...{ selected: (building.activePercent ?? 100) === 90 }}>90%</option>
<option value="80" {...{ selected: (building.activePercent ?? 100) === 80 }}>80%</option>
<option value="70" {...{ selected: (building.activePercent ?? 100) === 70 }}>70%</option>
<option value="60" {...{ selected: (building.activePercent ?? 100) === 60 }}>60%</option>
<option value="50" {...{ selected: (building.activePercent ?? 100) === 50 }}>50%</option>
<option value="40" {...{ selected: (building.activePercent ?? 100) === 40 }}>40%</option>
<option value="30" {...{ selected: (building.activePercent ?? 100) === 30 }}>30%</option>
<option value="20" {...{ selected: (building.activePercent ?? 100) === 20 }}>20%</option>
<option value="10" {...{ selected: (building.activePercent ?? 100) === 10 }}>10%</option>
<option value="0" {...{ selected: (building.activePercent ?? 100) === 0 }}>0%</option>
</select></td>
<td></td>
<td class="green">+{building.level * building.data.energy}</td>
</tr>)}
<tr><td colspan="5" class="table-separator">Utilities</td></tr>
{buildingsList.utilities.map(building => <tr>
<td>{building.data.id}</td>
<td>{building.level}</td>
<td></td>
<td></td>
<td class="red">-{building.level * building.data.energy}</td>
</tr>)}
<tr><td colspan="5" class="table-separator">Storage</td></tr>
{buildingsList.storage.map(building => <tr>
<td>{building.data.id}</td>
<td>{building.level}</td>
<td></td>
<td></td>
<td class="red">-{building.level * building.data.energy}</td>
</tr>)}
</table>
<input type="submit" value="Save" class="save-button" />
</form>
</LoggedIn>
<style>
.form-container {
width: fit-content;
margin-left: auto;
margin-right: auto;
margin-top: 20px;
display: flex;
flex-direction: column;
align-items: center;
}
h1 {
color: white;
}
.green {
color: green;
}
.red {
color: red;
}
.table-col-header {
background-color: #444;
}
.table-separator {
background-color: #222;
font-weight: 1000;
text-align: center;
}
.table-col-header th {
border: 1px solid white;
padding: 10px;
}
th {
font-weight: 900;
}
tr {
color: white;
}
td {
padding: 10px;
border: 1px solid white;
}
.form-container .save-button {
flex-grow: 1;
margin-top: 20px;
padding: 10px;
background-color: #444;
color: white;
border: none;
border-radius: 5px;
cursor: pointer;
width: 100%;
}
</style>

View File

@ -6,7 +6,7 @@ export default interface DBPlanet {
owner: ObjectId; // shouldn't be here owner: ObjectId; // shouldn't be here
fields: number; fields: number;
resources: Array<{ id: string, amount: number, lastUpdated: Date, perHourMiningRate: number }>; resources: Array<{ id: string, amount: number, lastUpdated: Date, perHourMiningRate: number }>;
buildings: Array<{ id: string, level: number }>; buildings: Array<{ id: string, level: number, activePercent?: number }>;
ships: Array<{ id: string, amount: number }>; ships: Array<{ id: string, amount: number }>;
defenses: Array<{ id: string, amount: number }>; defenses: Array<{ id: string, amount: number }>;
} }