Add defense system
This commit is contained in:
parent
8b5eef482f
commit
119cf70e86
|
@ -101,6 +101,13 @@ const listOfElements: Array<NavElement> = [{
|
||||||
url: "/game/fleet",
|
url: "/game/fleet",
|
||||||
show: "loggedInOnly",
|
show: "loggedInOnly",
|
||||||
position: "bottom"
|
position: "bottom"
|
||||||
|
},{
|
||||||
|
id: "defenses",
|
||||||
|
title: getName(lang, "general", "nav-defenses"),
|
||||||
|
type: "simple",
|
||||||
|
url: "/game/defenses",
|
||||||
|
show: "loggedInOnly",
|
||||||
|
position: "bottom"
|
||||||
}, {
|
}, {
|
||||||
id: "galaxyView",
|
id: "galaxyView",
|
||||||
title: getName(lang, "general", "nav-galaxy-view"),
|
title: getName(lang, "general", "nav-galaxy-view"),
|
||||||
|
|
|
@ -0,0 +1,84 @@
|
||||||
|
import DBDefenses from "../../types/db/DBDefenses";
|
||||||
|
import DefenseManager from "./managers/abstract/DefenseManager";
|
||||||
|
import SystemManager from "./managers/SystemManager";
|
||||||
|
|
||||||
|
export default class Defense {
|
||||||
|
manager: DefenseManager;
|
||||||
|
data: DBDefenses;
|
||||||
|
amount: number;
|
||||||
|
|
||||||
|
constructor(manager: DefenseManager, data: DBDefenses, amount: number) {
|
||||||
|
this.manager = manager;
|
||||||
|
this.data = data;
|
||||||
|
this.amount = amount;
|
||||||
|
}
|
||||||
|
|
||||||
|
async checkRequiredResources(): Promise<boolean> {
|
||||||
|
const resources = await this.manager.manager.resources.calculateCurrentAvailableResources();
|
||||||
|
|
||||||
|
const requirements = this.data.requirements.resources;
|
||||||
|
|
||||||
|
let canBuild = true;
|
||||||
|
|
||||||
|
for(let res of requirements) {
|
||||||
|
const resource = resources.find(r => r.id === res.id);
|
||||||
|
if(!resource) return false;
|
||||||
|
|
||||||
|
if(resource.amount < (res.amount * this.amount)) {
|
||||||
|
canBuild = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return canBuild;
|
||||||
|
}
|
||||||
|
|
||||||
|
async checkRequirements(): Promise<{ canBuild: boolean, error: string }> {
|
||||||
|
if(!(this.manager.manager instanceof SystemManager)) {
|
||||||
|
const playerBuildings = this.manager.manager.buildings.buildings;
|
||||||
|
let playerBuildingsCanBuild = { canBuild: true, missing: "" };
|
||||||
|
this.data.requirements.buildings.forEach((buildingReq: any) => {
|
||||||
|
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}` };
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if(!playerBuildingsCanBuild.canBuild) return {
|
||||||
|
canBuild: false,
|
||||||
|
error: playerBuildingsCanBuild.missing
|
||||||
|
}
|
||||||
|
} /*else { //TODO: check for structures requirements
|
||||||
|
const structures = this.manager.manager.structures.structures;
|
||||||
|
let playerStructuresCanBuild = { canBuild: true, missing: "" };
|
||||||
|
this.data.requirements.structures.forEach((buildingReq: any) => {
|
||||||
|
if((structures.filter((building) => building.data.id === buildingReq.id)[0]?.level ?? 0) < buildingReq.level) {
|
||||||
|
playerStructuresCanBuild = { canBuild: false, missing: `${buildingReq.id} level ${buildingReq.level} required, found ${structures.filter((structure) => structure.data.id === buildingReq.id)[0]?.level ?? 0}` };
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if(!playerStructuresCanBuild.canBuild) return {
|
||||||
|
canBuild: false,
|
||||||
|
error: playerStructuresCanBuild.missing
|
||||||
|
}
|
||||||
|
}*/
|
||||||
|
|
||||||
|
// research
|
||||||
|
const playerResearch = this.manager.manager instanceof SystemManager ? this.manager.manager.data.ownedBy.research : this.manager.manager.system.data.ownedBy.research;
|
||||||
|
let playerResearchCanBuild = { canBuild: true, missing: "" };
|
||||||
|
for(const researchReq of this.data.requirements.research) {
|
||||||
|
if(playerResearch.research.find((research) => research.id === researchReq.id)?.level ?? 0 < researchReq.level) {
|
||||||
|
playerResearchCanBuild = { canBuild: false, missing: `${researchReq.id} level ${researchReq.level} required, found ${playerResearch.research.find((research) => research.id === researchReq.id)?.level ?? 0}` };
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if(!playerResearchCanBuild.canBuild) return {
|
||||||
|
canBuild: false,
|
||||||
|
error: playerResearchCanBuild.missing
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
canBuild: true,
|
||||||
|
error: ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -9,6 +9,7 @@ import { getRandomInRange, weightedRandom } from "../../utils/math";
|
||||||
import { Sector } from "./LocationManager";
|
import { Sector } from "./LocationManager";
|
||||||
import { Planet } from "./PlanetManager";
|
import { Planet } from "./PlanetManager";
|
||||||
import SystemManager from "./SystemManager";
|
import SystemManager from "./SystemManager";
|
||||||
|
import { getAllDefenses } from "../../db/defenses";
|
||||||
|
|
||||||
export type Fleet = {
|
export type Fleet = {
|
||||||
id: ObjectId,
|
id: ObjectId,
|
||||||
|
@ -104,7 +105,7 @@ export default class FleetManager {
|
||||||
case 'ATTACK':
|
case 'ATTACK':
|
||||||
if(!("expedition" in this.data.destination)) {
|
if(!("expedition" in this.data.destination)) {
|
||||||
const enemyShips = this.data.destination.ships.ships;
|
const enemyShips = this.data.destination.ships.ships;
|
||||||
return await this.battleResults(enemyShips.map(ship => { return { id: ship.data.id, amount: ship.amount } }));
|
return await this.battleResults(enemyShips.map(ship => { return { id: ship.data.id, amount: ship.amount } }), this.data.destination.defenses.defenses.map(defense => { return { id: defense.data.id, amount: defense.amount } }));
|
||||||
} else {
|
} else {
|
||||||
throw new Error("Cannot attack sector.");
|
throw new Error("Cannot attack sector.");
|
||||||
}
|
}
|
||||||
|
@ -161,18 +162,19 @@ export default class FleetManager {
|
||||||
await this.sync();
|
await this.sync();
|
||||||
}
|
}
|
||||||
|
|
||||||
private async sendMail(title: string, description: string) {
|
private async sendMail(user: ObjectId, title: string, description: string) {
|
||||||
await sendMail(
|
await sendMail(
|
||||||
null,
|
null,
|
||||||
this.data.source instanceof SystemManager ? this.data.source.data.ownedBy.id : this.data.source.system.data.ownedBy.id,
|
user,
|
||||||
this.data.arrivalTime,
|
this.data.arrivalTime,
|
||||||
title,
|
title,
|
||||||
description
|
description
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
async battleResults(enemyFleet: { id: string, amount: number }[]) {
|
async battleResults(enemyFleet: { id: string, amount: number }[], enemyDefenses: { id: string, amount: number }[] = []) {
|
||||||
const allShips = await getAllShips();
|
const allShips = await getAllShips();
|
||||||
|
const allDefenses = await getAllDefenses();
|
||||||
|
|
||||||
const playerStats = this.data.ships.reduce((acc, ship) => {
|
const playerStats = this.data.ships.reduce((acc, ship) => {
|
||||||
const dbShip = allShips.find(s => s.id === ship.id);
|
const dbShip = allShips.find(s => s.id === ship.id);
|
||||||
|
@ -183,6 +185,14 @@ export default class FleetManager {
|
||||||
return acc;
|
return acc;
|
||||||
}, { attack: 0, defense: 0, hitpoints: 0 });
|
}, { attack: 0, defense: 0, hitpoints: 0 });
|
||||||
|
|
||||||
|
const enemyDefensesStats = enemyDefenses.reduce((acc, defense) => {
|
||||||
|
const dbDefense = allDefenses.find(d => d.id === defense.id);
|
||||||
|
if(!dbDefense) return acc;
|
||||||
|
acc.defense += dbDefense.structure.defense * defense.amount;
|
||||||
|
acc.hitpoints += dbDefense.structure.hitpoints * defense.amount;
|
||||||
|
return acc;
|
||||||
|
}, { attack: 0, defense: 0, hitpoints: 0 });
|
||||||
|
|
||||||
const enemyStats = enemyFleet.reduce((acc, ship) => {
|
const enemyStats = enemyFleet.reduce((acc, ship) => {
|
||||||
const dbShip = allShips.find(s => s.id === ship.id);
|
const dbShip = allShips.find(s => s.id === ship.id);
|
||||||
if(!dbShip) return acc;
|
if(!dbShip) return acc;
|
||||||
|
@ -190,7 +200,7 @@ export default class FleetManager {
|
||||||
acc.defense += dbShip.structure.defense * ship.amount;
|
acc.defense += dbShip.structure.defense * ship.amount;
|
||||||
acc.hitpoints += dbShip.structure.hitpoints * ship.amount;
|
acc.hitpoints += dbShip.structure.hitpoints * ship.amount;
|
||||||
return acc;
|
return acc;
|
||||||
}, { attack: 0, defense: 0, hitpoints: 0 });
|
}, enemyDefensesStats);
|
||||||
|
|
||||||
const playerShipsStructure: BattleFleet[] = [];
|
const playerShipsStructure: BattleFleet[] = [];
|
||||||
for(const playerShip of this.data.ships) {
|
for(const playerShip of this.data.ships) {
|
||||||
|
@ -282,10 +292,12 @@ export default class FleetManager {
|
||||||
} else this.data.ships = [];
|
} else this.data.ships = [];
|
||||||
|
|
||||||
await this.sendMail(
|
await this.sendMail(
|
||||||
|
this.data.source instanceof SystemManager ? this.data.source.data.ownedBy.id : this.data.source.system.data.ownedBy.id,
|
||||||
`Battle Results (${playerBalance > enemyBalance ? "Victory" : playerBalance < enemyBalance ? "Defeat" : "Draw"})`,
|
`Battle Results (${playerBalance > enemyBalance ? "Victory" : playerBalance < enemyBalance ? "Defeat" : "Draw"})`,
|
||||||
`Results of battle at ${(this.data.destination instanceof SystemManager ? this.data.destination.data.name : this.data.destination.name)}:\n
|
`Results of battle at ${(this.data.destination instanceof SystemManager ? this.data.destination.data.name : this.data.destination.name)}:\n
|
||||||
Player ships:\n${previousShips.map(ship => `${ship.amount} ${ship.id}`).join('\n')}\n
|
Player ships:\n${previousShips.map(ship => `${ship.amount} ${ship.id}`).join('\n')}\n
|
||||||
Enemy ships:\n${enemyFleet.map(ship => `${ship.amount} ${ship.id}`).join('\n')}\n\n
|
Enemy ships:\n${enemyFleet.map(ship => `${ship.amount} ${ship.id}`).join('\n')}\n
|
||||||
|
Enemy defenses:\n${enemyDefenses.map(defense => `${defense.amount} ${defense.id}`).join('\n')}\n
|
||||||
Player stats: ${playerStats.hitpoints} HP, ${playerStats.attack} ATK, ${playerStats.defense} DEF\n
|
Player stats: ${playerStats.hitpoints} HP, ${playerStats.attack} ATK, ${playerStats.defense} DEF\n
|
||||||
Enemy stats: ${enemyStats.hitpoints} HP, ${enemyStats.attack} ATK, ${enemyStats.defense} DEF\n\n
|
Enemy stats: ${enemyStats.hitpoints} HP, ${enemyStats.attack} ATK, ${enemyStats.defense} DEF\n\n
|
||||||
Player ships left:\n${Object.keys(playerShipsLeft).map(key => `${key} - ${playerShipsLeft[key]}`).join('\n')}\n
|
Player ships left:\n${Object.keys(playerShipsLeft).map(key => `${key} - ${playerShipsLeft[key]}`).join('\n')}\n
|
||||||
|
@ -293,6 +305,22 @@ export default class FleetManager {
|
||||||
${playerBalance > enemyBalance ? `Resources stolen:\n${resourcesStolen.map(res => `${res.id} - ${res.amount}`).join('\n')}` : ""}`
|
${playerBalance > enemyBalance ? `Resources stolen:\n${resourcesStolen.map(res => `${res.id} - ${res.amount}`).join('\n')}` : ""}`
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if(!("expedition" in this.data.destination)) {
|
||||||
|
await this.sendMail(
|
||||||
|
this.data.destination instanceof SystemManager ? this.data.destination.data.ownedBy.id : this.data.destination.system.data.ownedBy.id,
|
||||||
|
`Battle Results (${playerBalance < enemyBalance ? "Victory" : playerBalance > enemyBalance ? "Defeat" : "Draw"})`,
|
||||||
|
`Results of battle at ${(this.data.destination instanceof SystemManager ? this.data.destination.data.name : this.data.destination.name)}:\n
|
||||||
|
Enemy ships:\n${previousShips.map(ship => `${ship.amount} ${ship.id}`).join('\n')}\n
|
||||||
|
Player ships:\n${enemyFleet.map(ship => `${ship.amount} ${ship.id}`).join('\n')}\n
|
||||||
|
Player defenses:\n${enemyDefenses.map(defense => `${defense.amount} ${defense.id}`).join('\n')}\n
|
||||||
|
Enemy stats: ${playerStats.hitpoints} HP, ${playerStats.attack} ATK, ${playerStats.defense} DEF\n
|
||||||
|
Player stats: ${enemyStats.hitpoints} HP, ${enemyStats.attack} ATK, ${enemyStats.defense} DEF\n\n
|
||||||
|
Enemy ships left:\n${Object.keys(playerShipsLeft).map(key => `${key} - ${playerShipsLeft[key]}`).join('\n')}\n
|
||||||
|
Player ships left:\n${Object.keys(enemyShipsLeft).map(key => `${key} - ${enemyShipsLeft[key]}`).join('\n')}\n
|
||||||
|
${playerBalance > enemyBalance ? `Resources stolen:\n${resourcesStolen.map(res => `${res.id} - ${res.amount}`).join('\n')}` : ""}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return !(playerShipsStructure.length > 0);
|
return !(playerShipsStructure.length > 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -309,7 +337,7 @@ export default class FleetManager {
|
||||||
|
|
||||||
if(expeditionRandom < 0.02) { // 2% chance; lost all ships, black hole
|
if(expeditionRandom < 0.02) { // 2% chance; lost all ships, black hole
|
||||||
this.data.ships = [];
|
this.data.ships = [];
|
||||||
await this.sendMail("Expedition Results", `Your expedition to ${(this.data.destination as Sector).name} sector encountered a black hole. All ships were lost.`);
|
await this.sendMail(this.data.source instanceof SystemManager ? this.data.source.data.ownedBy.id : this.data.source.system.data.ownedBy.id, "Expedition Results", `Your expedition to ${(this.data.destination as Sector).name} sector encountered a black hole. All ships were lost.`);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -324,7 +352,7 @@ export default class FleetManager {
|
||||||
else ship.amount += s.amount;
|
else ship.amount += s.amount;
|
||||||
}
|
}
|
||||||
|
|
||||||
await this.sendMail("Expedition Results", `Your expedition to ${(this.data.destination as Sector).name} sector encountered abandoned shipyard. Following ships were added to the fleet:\n${ships.map(s => `${s.id} - ${s.amount}`).join(', ')}`);
|
await this.sendMail(this.data.source instanceof SystemManager ? this.data.source.data.ownedBy.id : this.data.source.system.data.ownedBy.id, "Expedition Results", `Your expedition to ${(this.data.destination as Sector).name} sector encountered abandoned shipyard. Following ships were added to the fleet:\n${ships.map(s => `${s.id} - ${s.amount}`).join(', ')}`);
|
||||||
await this.initiateReturn();
|
await this.initiateReturn();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -356,7 +384,7 @@ export default class FleetManager {
|
||||||
else resource.amount += res.amount;
|
else resource.amount += res.amount;
|
||||||
}
|
}
|
||||||
|
|
||||||
await this.sendMail("Expedition Results", `Your expedition to ${(this.data.destination as Sector).name} sector encountered resource-rich asteroid. Following resources were added to the cargo inventory:\n${resources.map(r => `${r.id} - ${r.amount}`).join('\n')}`);
|
await this.sendMail(this.data.source instanceof SystemManager ? this.data.source.data.ownedBy.id : this.data.source.system.data.ownedBy.id, "Expedition Results", `Your expedition to ${(this.data.destination as Sector).name} sector encountered resource-rich asteroid. Following resources were added to the cargo inventory:\n${resources.map(r => `${r.id} - ${r.amount}`).join('\n')}`);
|
||||||
await this.initiateReturn();
|
await this.initiateReturn();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -367,7 +395,7 @@ export default class FleetManager {
|
||||||
{ id: 'transporter', amount: getRandomInRange(0, 100) + valueAdded }
|
{ id: 'transporter', amount: getRandomInRange(0, 100) + valueAdded }
|
||||||
];
|
];
|
||||||
|
|
||||||
await this.sendMail("Expedition Results", `Your expedition to ${(this.data.destination as Sector).name} sector encountered drunk pirates. After attempting to communicate with them, they attacked your fleet.`)
|
await this.sendMail(this.data.source instanceof SystemManager ? this.data.source.data.ownedBy.id : this.data.source.system.data.ownedBy.id, "Expedition Results", `Your expedition to ${(this.data.destination as Sector).name} sector encountered drunk pirates. After attempting to communicate with them, they attacked your fleet.`)
|
||||||
await this.battleResults(pirates);
|
await this.battleResults(pirates);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -416,12 +444,12 @@ export default class FleetManager {
|
||||||
else resource.amount += res.amount;
|
else resource.amount += res.amount;
|
||||||
}
|
}
|
||||||
|
|
||||||
await this.sendMail("Expedition Results", `Your expedition to ${(this.data.destination as Sector).name} sector encountered resource-rich rouge planet. Your fleet could not extract all resources. Following resources were added to the cargo inventory:\n${addedResources.map(r => `${r.id} - ${r.amount}`).join('\n')}`);
|
await this.sendMail(this.data.source instanceof SystemManager ? this.data.source.data.ownedBy.id : this.data.source.system.data.ownedBy.id, "Expedition Results", `Your expedition to ${(this.data.destination as Sector).name} sector encountered resource-rich rouge planet. Your fleet could not extract all resources. Following resources were added to the cargo inventory:\n${addedResources.map(r => `${r.id} - ${r.amount}`).join('\n')}`);
|
||||||
await this.initiateReturn();
|
await this.initiateReturn();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
await this.sendMail("Expedition Results", `Your expedition to ${(this.data.destination as Sector).name} sector scanned the sector for a long time, yet it haven't found anything.`);
|
await this.sendMail(this.data.source instanceof SystemManager ? this.data.source.data.ownedBy.id : this.data.source.system.data.ownedBy.id, "Expedition Results", `Your expedition to ${(this.data.destination as Sector).name} sector scanned the sector for a long time, yet it haven't found anything.`);
|
||||||
await this.initiateReturn();
|
await this.initiateReturn();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
import { updatePlanetDefenses } from "../../db/planets";
|
||||||
|
import { Planet } from "./PlanetManager";
|
||||||
|
import DefenseManager from "./abstract/DefenseManager";
|
||||||
|
|
||||||
|
export default class PlanetDefenseManager extends DefenseManager {
|
||||||
|
constructor(planet: Planet) {
|
||||||
|
super(planet);
|
||||||
|
}
|
||||||
|
|
||||||
|
get manager() {
|
||||||
|
return this._manager as Planet;
|
||||||
|
}
|
||||||
|
|
||||||
|
async sync() {
|
||||||
|
await updatePlanetDefenses(this.manager._id, this.defenses.map(def => { return { id: def.data.id, amount: def.amount } }));
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,6 +3,7 @@ import BuildingManager from "./BuildingManager";
|
||||||
import PlanetResourceManager from "./PlanetResourceManager";
|
import PlanetResourceManager from "./PlanetResourceManager";
|
||||||
import ShipManager from "./PlanetShipManager";
|
import ShipManager from "./PlanetShipManager";
|
||||||
import SystemManager from "./SystemManager";
|
import SystemManager from "./SystemManager";
|
||||||
|
import PlanetDefenseManager from "./PlanetDefenseManager";
|
||||||
|
|
||||||
export type Planet = {
|
export type Planet = {
|
||||||
_id: ObjectId;
|
_id: ObjectId;
|
||||||
|
@ -12,4 +13,5 @@ export type Planet = {
|
||||||
resources: PlanetResourceManager;
|
resources: PlanetResourceManager;
|
||||||
buildings: BuildingManager;
|
buildings: BuildingManager;
|
||||||
ships: ShipManager;
|
ships: ShipManager;
|
||||||
|
defenses: PlanetDefenseManager;
|
||||||
}
|
}
|
|
@ -0,0 +1,17 @@
|
||||||
|
import { updateSystemDefenses } from "../../db/systems";
|
||||||
|
import SystemManager from "./SystemManager";
|
||||||
|
import DefenseManager from "./abstract/DefenseManager";
|
||||||
|
|
||||||
|
export default class SystemDefenseManager extends DefenseManager {
|
||||||
|
constructor(system: SystemManager) {
|
||||||
|
super(system);
|
||||||
|
}
|
||||||
|
|
||||||
|
get manager() {
|
||||||
|
return this._manager as SystemManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
async sync() {
|
||||||
|
await updateSystemDefenses(this.manager.data._id, this.defenses.map(def => { return { id: def.data.id, amount: def.amount } }));
|
||||||
|
}
|
||||||
|
}
|
|
@ -10,6 +10,8 @@ import PlanetShipManager from "./PlanetShipManager";
|
||||||
import StructureManager from "./StructureManager";
|
import StructureManager from "./StructureManager";
|
||||||
import SystemResourceManager from "./SystemResourceManager";
|
import SystemResourceManager from "./SystemResourceManager";
|
||||||
import SystemShipManager from "./SystemShipManager";
|
import SystemShipManager from "./SystemShipManager";
|
||||||
|
import PlanetDefenseManager from "./PlanetDefenseManager";
|
||||||
|
import SystemDefenseManager from "./SystemDefenseManager";
|
||||||
|
|
||||||
export type System = {
|
export type System = {
|
||||||
_id: ObjectId,
|
_id: ObjectId,
|
||||||
|
@ -19,6 +21,7 @@ export type System = {
|
||||||
structures: StructureManager,
|
structures: StructureManager,
|
||||||
resources: SystemResourceManager,
|
resources: SystemResourceManager,
|
||||||
ships: SystemShipManager,
|
ships: SystemShipManager,
|
||||||
|
defenses: SystemDefenseManager,
|
||||||
planets: Planet[];
|
planets: Planet[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -27,6 +30,7 @@ export default class SystemManager {
|
||||||
structures: StructureManager;
|
structures: StructureManager;
|
||||||
resources: SystemResourceManager;
|
resources: SystemResourceManager;
|
||||||
ships: SystemShipManager;
|
ships: SystemShipManager;
|
||||||
|
defenses: SystemDefenseManager;
|
||||||
data: System;
|
data: System;
|
||||||
|
|
||||||
constructor(data: System) {
|
constructor(data: System) {
|
||||||
|
@ -34,12 +38,14 @@ export default class SystemManager {
|
||||||
this.structures = new StructureManager(this);
|
this.structures = new StructureManager(this);
|
||||||
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
async fillData(systemData: DBSystem) {
|
async fillData(systemData: DBSystem) {
|
||||||
await this.structures.init(systemData.structures);
|
await this.structures.init(systemData.structures);
|
||||||
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 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);
|
||||||
|
@ -54,12 +60,15 @@ export default class SystemManager {
|
||||||
//@ts-ignore
|
//@ts-ignore
|
||||||
buildings: null,
|
buildings: null,
|
||||||
//@ts-ignore
|
//@ts-ignore
|
||||||
ships: null
|
ships: null,
|
||||||
|
//@ts-ignore
|
||||||
|
defenses: 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);
|
||||||
|
|
||||||
this.planets.push(planetObject);
|
this.planets.push(planetObject);
|
||||||
}));
|
}));
|
||||||
|
|
|
@ -0,0 +1,62 @@
|
||||||
|
import { Planet } from '../PlanetManager';
|
||||||
|
import SystemManager from '../SystemManager';
|
||||||
|
import Defense from '../../Defense';
|
||||||
|
import DBDefenses from '../../../../types/db/DBDefenses';
|
||||||
|
import { getAllDefenses } from '../../../db/defenses';
|
||||||
|
|
||||||
|
export default abstract class DefenseManager {
|
||||||
|
defenses: Array<Defense> = [];
|
||||||
|
defensesDB: Array<DBDefenses> = [];
|
||||||
|
protected _manager: Planet | SystemManager;
|
||||||
|
|
||||||
|
constructor(manager: Planet | SystemManager) {
|
||||||
|
this._manager = manager;
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract sync(): Promise<void>;
|
||||||
|
|
||||||
|
abstract get manager(): Planet | SystemManager;
|
||||||
|
|
||||||
|
async init(defenseData: { id: string, amount: number }[]) {
|
||||||
|
this.defensesDB = await getAllDefenses();
|
||||||
|
|
||||||
|
for(const def of defenseData) {
|
||||||
|
const defToFind = this.defensesDB.find(d => d.id === def.id);
|
||||||
|
|
||||||
|
if(defToFind) this.defenses.push(new Defense(
|
||||||
|
this,
|
||||||
|
defToFind,
|
||||||
|
def.amount
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
getDefenseById(id: string) {
|
||||||
|
return this.defenses.find(def => def.data.id === id);
|
||||||
|
}
|
||||||
|
|
||||||
|
addDefenses(id: string, amount: number) {
|
||||||
|
const findDef = this.defenses.find(d => d.data.id === id);
|
||||||
|
if(!findDef) {
|
||||||
|
const defData = this.defensesDB.find(d => d.id === id);
|
||||||
|
if(!defData) return;
|
||||||
|
|
||||||
|
this.defenses.push(new Defense(
|
||||||
|
this,
|
||||||
|
defData,
|
||||||
|
amount
|
||||||
|
));
|
||||||
|
}
|
||||||
|
else findDef.amount += amount;
|
||||||
|
}
|
||||||
|
|
||||||
|
removeDefenses(id: string, amount: number) {
|
||||||
|
const findDef = this.defenses.find(d => d.data.id === id);
|
||||||
|
if(findDef) {
|
||||||
|
findDef.amount -= amount;
|
||||||
|
if(findDef.amount <= 0) this.defenses.splice(this.defenses.indexOf(findDef), 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
import DBDefenses from '../../types/db/DBDefenses';
|
||||||
|
import { Defenses } from '../db/mongodb';
|
||||||
|
|
||||||
|
export const getAllDefenses = async () => {
|
||||||
|
return (await Defenses()).find({}).toArray() as unknown as Array<DBDefenses>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getDefenseById = async (id: string) => {
|
||||||
|
return (await Defenses()).findOne({
|
||||||
|
id
|
||||||
|
}) as unknown as DBDefenses;
|
||||||
|
}
|
|
@ -8,6 +8,7 @@ export const getLang = async (language = "en") => {
|
||||||
ships: (await lang[2].find({}).toArray()).map(({ _id, ...rest }) => rest),
|
ships: (await lang[2].find({}).toArray()).map(({ _id, ...rest }) => rest),
|
||||||
resources: (await lang[3].find({}).toArray()).map(({ _id, ...rest }) => rest),
|
resources: (await lang[3].find({}).toArray()).map(({ _id, ...rest }) => rest),
|
||||||
research: (await lang[4].find({}).toArray()).map(({ _id, ...rest }) => rest),
|
research: (await lang[4].find({}).toArray()).map(({ _id, ...rest }) => rest),
|
||||||
structures: (await lang[5].find({}).toArray()).map(({ _id, ...rest }) => rest)
|
structures: (await lang[5].find({}).toArray()).map(({ _id, ...rest }) => rest),
|
||||||
|
defenses: (await lang[6].find({}).toArray()).map(({ _id, ...rest }) => rest)
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -67,6 +67,11 @@ export const Ships = async() => {
|
||||||
return db.collection('ships');
|
return db.collection('ships');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const Defenses = async() => {
|
||||||
|
const db = await getDB();
|
||||||
|
return db.collection('defenses');
|
||||||
|
}
|
||||||
|
|
||||||
export const Fleet = async() => {
|
export const Fleet = async() => {
|
||||||
const db = await getDB();
|
const db = await getDB();
|
||||||
return db.collection('fleet');
|
return db.collection('fleet');
|
||||||
|
@ -85,7 +90,8 @@ export const Lang = async (language = "en") => {
|
||||||
await db.collection('ships'),
|
await db.collection('ships'),
|
||||||
await db.collection('resources'),
|
await db.collection('resources'),
|
||||||
await db.collection('research'),
|
await db.collection('research'),
|
||||||
await db.collection('structures')
|
await db.collection('structures'),
|
||||||
|
await db.collection('defenses')
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -40,4 +40,13 @@ export const updatePlanetShips = async (planetId: ObjectId, ships: Array<{ id: s
|
||||||
ships
|
ships
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export const updatePlanetDefenses = async (planetId: ObjectId, defenses: Array<{ id: string, amount: number }>) => {
|
||||||
|
const planets = await Planets();
|
||||||
|
await planets.updateOne({ _id: planetId }, {
|
||||||
|
$set: {
|
||||||
|
defenses
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
|
@ -42,4 +42,13 @@ export const updateSystemShips = async (systemId: ObjectId, ships: Array<any>) =
|
||||||
ships
|
ships
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export const updateSystemDefenses = async (systemId: ObjectId, defenses: Array<any>) => {
|
||||||
|
const systems = await Systems();
|
||||||
|
await systems.updateOne({ _id: systemId }, {
|
||||||
|
$set: {
|
||||||
|
defenses
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
|
@ -0,0 +1,146 @@
|
||||||
|
import { type APIRoute } from "astro";
|
||||||
|
import validateAccessToken from "../../../lib/utils/validateAccessToken";
|
||||||
|
import { getUserByAccessToken } from "../../../lib/db/users";
|
||||||
|
import { ObjectId } from "mongodb";
|
||||||
|
import locationManager from "../../../lib/classes/managers/LocationManager";
|
||||||
|
import { getAllResources } from "../../../lib/db/resources";
|
||||||
|
import Defense from "../../../lib/classes/Defense";
|
||||||
|
import { Planet } from "../../../lib/classes/managers/PlanetManager";
|
||||||
|
import SystemManager from "../../../lib/classes/managers/SystemManager";
|
||||||
|
|
||||||
|
export const POST: APIRoute = async({ request }) => {
|
||||||
|
const response = await validateAccessToken(request);
|
||||||
|
if(response instanceof Response) return response;
|
||||||
|
|
||||||
|
const user = await getUserByAccessToken(response);
|
||||||
|
if(user === null) {
|
||||||
|
return new Response(
|
||||||
|
JSON.stringify({
|
||||||
|
code: 401,
|
||||||
|
message: "Unauthorized"
|
||||||
|
}), { status: 401 }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
let body;
|
||||||
|
try {
|
||||||
|
body = await request.json()
|
||||||
|
} catch(e) {
|
||||||
|
return new Response(
|
||||||
|
JSON.stringify({
|
||||||
|
code: 400,
|
||||||
|
message: "Bad Request",
|
||||||
|
error: "Invalid JSON body"
|
||||||
|
}), { status: 400 }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!body.id || !body.defense || !body.amount) {
|
||||||
|
return new Response(
|
||||||
|
JSON.stringify({
|
||||||
|
code: 400,
|
||||||
|
message: "Bad Request",
|
||||||
|
error: "Missing required fields: id, defense, amount"
|
||||||
|
}), { status: 400 }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const amount = parseInt(body.amount);
|
||||||
|
if(isNaN(amount) || amount <= 0) {
|
||||||
|
return new Response(
|
||||||
|
JSON.stringify({
|
||||||
|
code: 400,
|
||||||
|
message: "Bad Request",
|
||||||
|
error: "Invalid amount"
|
||||||
|
}), { status: 400 }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
let id: ObjectId;
|
||||||
|
|
||||||
|
try {
|
||||||
|
id = new ObjectId(body.id);
|
||||||
|
} catch(e) {
|
||||||
|
return new Response(
|
||||||
|
JSON.stringify({
|
||||||
|
code: 400,
|
||||||
|
message: "Bad Request",
|
||||||
|
error: "Invalid ID"
|
||||||
|
}), { status: 400 }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
let planetOrSystem: Planet | SystemManager | undefined = locationManager.getPlanet(id);
|
||||||
|
if(!planetOrSystem) planetOrSystem = locationManager.getSystem(id);
|
||||||
|
if(!planetOrSystem) {
|
||||||
|
return new Response(
|
||||||
|
JSON.stringify({
|
||||||
|
code: 400,
|
||||||
|
message: "Bad Request",
|
||||||
|
error: "Invalid ID"
|
||||||
|
}), { status: 400 }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const defenseDB = planetOrSystem.defenses.defensesDB.find(d => d.id === body.defense);
|
||||||
|
|
||||||
|
if(!defenseDB) {
|
||||||
|
return new Response(
|
||||||
|
JSON.stringify({
|
||||||
|
code: 400,
|
||||||
|
message: "Bad Request",
|
||||||
|
error: "Invalid defense ID"
|
||||||
|
}), { status: 400 }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const defense = new Defense(planetOrSystem.defenses, defenseDB, amount);
|
||||||
|
|
||||||
|
const requirements = await defense.checkRequirements();
|
||||||
|
const resources = await defense.checkRequiredResources();
|
||||||
|
|
||||||
|
if(!requirements.canBuild || !resources) {
|
||||||
|
return new Response(
|
||||||
|
JSON.stringify({
|
||||||
|
code: 400,
|
||||||
|
message: "Bad Request",
|
||||||
|
error: `${requirements.error} | ${resources ? "" : "Not enough resources"}`
|
||||||
|
}), { status: 400 }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const resourcesDiff = await planetOrSystem.resources.getDifference(defense.data.requirements.resources.map(res => {
|
||||||
|
return {
|
||||||
|
id: res.id,
|
||||||
|
amount: amount * res.amount
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
|
const resourceDB = await getAllResources();
|
||||||
|
const resourcesAfter = resourcesDiff.map(res => {
|
||||||
|
const data = resourceDB.find(r => r.id === res.id);
|
||||||
|
|
||||||
|
if(!data) throw new Error("Resource not found");
|
||||||
|
|
||||||
|
return {
|
||||||
|
id: res.id,
|
||||||
|
amount: res.amount,
|
||||||
|
lastUpdated: res.lastUpdated,
|
||||||
|
perHourMiningRate: res.perHourMiningRate,
|
||||||
|
data
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
planetOrSystem.resources.updateAmount(resourcesAfter.map(res => { return { id: res.id, amount: res.amount } }));
|
||||||
|
planetOrSystem.defenses.addDefenses(defense.data.id, amount);
|
||||||
|
|
||||||
|
await planetOrSystem.defenses.sync();
|
||||||
|
await planetOrSystem.resources.sync();
|
||||||
|
|
||||||
|
return new Response(
|
||||||
|
JSON.stringify({
|
||||||
|
code: 200,
|
||||||
|
message: "OK"
|
||||||
|
}), { status: 200 }
|
||||||
|
);
|
||||||
|
}
|
|
@ -0,0 +1,184 @@
|
||||||
|
---
|
||||||
|
import ItemCard from '../../components/ItemCard.astro';
|
||||||
|
import LoggedIn from '../../layouts/LoggedIn.astro';
|
||||||
|
import { Planet } from '../../lib/classes/managers/PlanetManager';
|
||||||
|
import SystemManager from '../../lib/classes/managers/SystemManager';
|
||||||
|
import { getAllDefenses } from '../../lib/db/defenses';
|
||||||
|
import { getObj } from '../../lib/utils/langDriver';
|
||||||
|
|
||||||
|
const { token, lang } = Astro.locals;
|
||||||
|
const active: SystemManager | Planet = Astro.locals.active;
|
||||||
|
|
||||||
|
const defenses = await getAllDefenses();
|
||||||
|
|
||||||
|
if(Astro.request.method === "POST") {
|
||||||
|
const body = await Astro.request.formData();
|
||||||
|
|
||||||
|
const id = body.get("id") as string;
|
||||||
|
const amount = parseInt(body.get("amount") as string ?? "1");
|
||||||
|
|
||||||
|
await fetch(Astro.url.origin + '/api/defenses/add', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'Authorization': 'Bearer ' + token
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
id: active instanceof SystemManager ? active.data._id : active._id,
|
||||||
|
defense: id,
|
||||||
|
amount
|
||||||
|
})
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const modalSet: { [key: string]: { resources: Array<any>, research: Array<any>, buildings: Array<any> } } = {};
|
||||||
|
|
||||||
|
for(const def of defenses) {
|
||||||
|
modalSet[def.id] = {
|
||||||
|
resources: def.requirements.resources,
|
||||||
|
research: def.requirements.research,
|
||||||
|
buildings: def.requirements.buildings,
|
||||||
|
// energy: building.energy
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const planetId = active instanceof SystemManager ? active.data._id : active._id;
|
||||||
|
---
|
||||||
|
<LoggedIn id="defenses" title="Defenses">
|
||||||
|
<div id="ship-modal-background">
|
||||||
|
<div id="ship-modal-details" data-building-id="">
|
||||||
|
<h3>Required resources</h3>
|
||||||
|
<div class="ship-modal-text" id="ship-modal-req-resources">None</div>
|
||||||
|
<h3>Required buildings</h3>
|
||||||
|
<div class="ship-modal-text" id="ship-modal-req-buildings">None</div>
|
||||||
|
<h3>Required research</h3>
|
||||||
|
<div class="ship-modal-text" id="ship-modal-req-research">None</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="ship-cards">
|
||||||
|
{defenses.map(def => <>
|
||||||
|
<ItemCard
|
||||||
|
category="ships"
|
||||||
|
id={def.id}
|
||||||
|
name={getObj(lang, "defenses", def.id).name}
|
||||||
|
level={active.defenses.getDefenseById(def.id)?.amount.toString() ?? "0"}
|
||||||
|
description={getObj(lang, "defenses", def.id).description ?? ""}
|
||||||
|
image={`/images/defenses/${def.id}.png`}
|
||||||
|
button_type="general"
|
||||||
|
button_name="nav-build"
|
||||||
|
has_amount_input="true" />
|
||||||
|
</>)}
|
||||||
|
</div>
|
||||||
|
</LoggedIn>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.ship-cards {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
row-gap: 40px;
|
||||||
|
column-gap: 2%;
|
||||||
|
margin-top: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ship-modal-background {
|
||||||
|
display: none;
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
background: rgba(0, 0, 0, 0.5);
|
||||||
|
z-index: 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ship-modal-details {
|
||||||
|
display: none;
|
||||||
|
position: fixed;
|
||||||
|
top: 50%;
|
||||||
|
left: 50%;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
width: 80%;
|
||||||
|
max-width: 800px;
|
||||||
|
background: rgba(0, 0, 0, 0.9);
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 1rem;
|
||||||
|
z-index: 101;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<script define:vars={{ modalSet, lang, planetId }}>
|
||||||
|
const modalResources = document.getElementById("ship-modal-req-resources");
|
||||||
|
const modalBuildings = document.getElementById("ship-modal-req-buildings");
|
||||||
|
const modalResearch = document.getElementById("ship-modal-req-research");
|
||||||
|
|
||||||
|
document.querySelectorAll('.item-card-info-button').forEach((el) => {
|
||||||
|
el.addEventListener('click', () => {
|
||||||
|
// modal
|
||||||
|
const modalDiv = document.getElementById('ship-modal-details');
|
||||||
|
if(!modalDiv) return;
|
||||||
|
modalDiv.style.display = 'block';
|
||||||
|
|
||||||
|
const reqResources = modalSet[el.parentElement.parentElement.parentElement.dataset.id]?.resources ?? [];
|
||||||
|
const reqBuildings = modalSet[el.parentElement.parentElement.parentElement.dataset.id]?.buildings ?? [];
|
||||||
|
const reqResearch = modalSet[el.parentElement.parentElement.parentElement.dataset.id]?.research ?? [];
|
||||||
|
|
||||||
|
modalResources.innerHTML = reqResources.length === 0 ? "None" : reqResources.map(resource => {
|
||||||
|
return `${lang['resources'].find(r => r.id === resource.id).name}: ${resource.amount}`;
|
||||||
|
}).join("<br />");
|
||||||
|
|
||||||
|
modalBuildings.innerHTML = reqBuildings.length === 0 ? "None" : reqBuildings.map(building => {
|
||||||
|
return `${lang['buildings'].find(b => b.id === building.id).name}: ${building.level}`;
|
||||||
|
}).join("<br />");
|
||||||
|
|
||||||
|
modalResearch.innerHTML = reqResearch.length === 0 ? "None" : reqResearch.map(research => {
|
||||||
|
return `${lang['research'].find(r => r.id === research.id).name}: ${research.level}`;
|
||||||
|
}).join("<br />");
|
||||||
|
|
||||||
|
// background
|
||||||
|
const backgroundDiv = document.getElementById('ship-modal-background');
|
||||||
|
if(!backgroundDiv) return;
|
||||||
|
backgroundDiv.style.display = 'block';
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// close modal on background click
|
||||||
|
const bg = document.getElementById('ship-modal-background');
|
||||||
|
|
||||||
|
bg?.addEventListener('click', () => {
|
||||||
|
const modalDiv = document.getElementById('ship-modal-details');
|
||||||
|
if(!modalDiv) return;
|
||||||
|
modalDiv.style.display = 'none';
|
||||||
|
|
||||||
|
const backgroundDiv = document.getElementById('ship-modal-background');
|
||||||
|
if(!backgroundDiv) return;
|
||||||
|
backgroundDiv.style.display = 'none';
|
||||||
|
});
|
||||||
|
|
||||||
|
const allButtons = document.getElementsByClassName("item-card-build");
|
||||||
|
|
||||||
|
for(const shipButton of allButtons) {
|
||||||
|
shipButton.addEventListener("click", async () => {
|
||||||
|
const id = shipButton.id.split("_")[1];
|
||||||
|
|
||||||
|
const response = await fetch('/api/ships/addShip', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
planet: planetId,
|
||||||
|
ship: id,
|
||||||
|
amount: 1
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
if(response.status === 200) {
|
||||||
|
window.location.reload();
|
||||||
|
} else {
|
||||||
|
alert("Failed to build ship: " + JSON.stringify(await response.json()));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
</script>
|
|
@ -0,0 +1,18 @@
|
||||||
|
import { ObjectId } from "mongodb";
|
||||||
|
|
||||||
|
export default interface DBDefenses {
|
||||||
|
_id: ObjectId;
|
||||||
|
id: string;
|
||||||
|
requirements: {
|
||||||
|
buildings: Array<{ id: string, level: number }>,
|
||||||
|
research: Array<{ id: string, level: number }>,
|
||||||
|
resources: Array<{ id: string, amount: number }>,
|
||||||
|
};
|
||||||
|
energy: number;
|
||||||
|
time: number;
|
||||||
|
structure: {
|
||||||
|
hitpoints: number;
|
||||||
|
defense: number;
|
||||||
|
attack: number;
|
||||||
|
};
|
||||||
|
}
|
|
@ -8,4 +8,5 @@ export default interface DBPlanet {
|
||||||
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 }>;
|
||||||
ships: Array<{ id: string, amount: number }>;
|
ships: Array<{ id: string, amount: number }>;
|
||||||
|
defenses: Array<{ id: string, amount: number }>;
|
||||||
}
|
}
|
|
@ -17,4 +17,8 @@ export default interface DBSystem {
|
||||||
id: string,
|
id: string,
|
||||||
amount: number
|
amount: number
|
||||||
}>;
|
}>;
|
||||||
|
defenses: Array<{
|
||||||
|
id: string,
|
||||||
|
amount: number
|
||||||
|
}>;
|
||||||
}
|
}
|
Loading…
Reference in New Issue