502 lines
27 KiB
TypeScript
502 lines
27 KiB
TypeScript
import { ObjectId } from "mongodb";
|
|
import MissionType from "../../../types/MissionType";
|
|
import DBFleet from "../../../types/db/DBFleet";
|
|
import { updateFleet } from "../../db/fleet";
|
|
import { sendMail } from "../../db/mails";
|
|
import { getAllShips } from "../../db/ships";
|
|
import getDistanceBetween from "../../utils/getDistanceBetween";
|
|
import { getRandomInRange, weightedRandom } from "../../utils/math";
|
|
import { Sector } from "./LocationManager";
|
|
import { Planet } from "./PlanetManager";
|
|
import SystemManager from "./SystemManager";
|
|
import { getAllDefenses } from "../../db/defenses";
|
|
|
|
export type Fleet = {
|
|
id: ObjectId,
|
|
source: Planet | SystemManager,
|
|
destination: Planet | SystemManager | Sector,
|
|
departureTime: Date,
|
|
arrivalTime: Date,
|
|
returning: boolean,
|
|
mission: MissionType,
|
|
ships: Array<{ id: string, amount: number }>,
|
|
cargo: Array<{ id: string, amount: number }>,
|
|
additionalData?: string
|
|
}
|
|
|
|
export type BattleFleet = {
|
|
id: string,
|
|
hitpoints: number,
|
|
attack: number,
|
|
defense: number
|
|
}
|
|
|
|
export default class FleetManager {
|
|
data: Fleet;
|
|
|
|
constructor(id: ObjectId, source: Planet | SystemManager, destination: Planet | SystemManager | Sector, departureTime: Date, arrivalTime: Date, returning: boolean, mission: MissionType, ships: Array<{ id: string, amount: number }>, cargo: Array<{ id: string, amount: number }>, additionalData?: string) {
|
|
this.data = {
|
|
id,
|
|
source,
|
|
destination,
|
|
departureTime,
|
|
arrivalTime,
|
|
returning,
|
|
mission,
|
|
ships,
|
|
cargo,
|
|
additionalData
|
|
}
|
|
}
|
|
|
|
isSourcePlanet(): this is { data: { source: Planet } } {
|
|
return 'resources' in this.data.source;
|
|
}
|
|
|
|
isSourceSystem(): this is { data: { source: SystemManager } } {
|
|
return 'structures' in this.data.source;
|
|
}
|
|
|
|
isDestinationPlanet(): this is { data: { destination: Planet } } {
|
|
return 'resources' in this.data.destination;
|
|
}
|
|
|
|
isDestinationSystem(): this is { data: { destination: SystemManager } } {
|
|
return 'structures' in this.data.destination;
|
|
}
|
|
|
|
getSourceOwner() {
|
|
if(this.isSourcePlanet()) return this.data.source.system.data.ownedBy;
|
|
if(this.isSourceSystem()) return this.data.source.data.ownedBy;
|
|
}
|
|
|
|
getDestinationOwner() {
|
|
if(this.isDestinationPlanet()) return this.data.destination.system.data.ownedBy;
|
|
if(this.isDestinationSystem()) return this.data.destination.data.ownedBy;
|
|
}
|
|
|
|
async checkStatus(): Promise<{ finished: boolean, fleet: Fleet }> {
|
|
if(this.data.arrivalTime.getTime() < Date.now()) {
|
|
const finished = await this.finish();
|
|
return { finished, fleet: this.data };
|
|
}
|
|
|
|
return { finished: false, fleet: this.data };
|
|
}
|
|
|
|
async finish() {
|
|
if(this.data.returning) {
|
|
for(const ship of this.data.ships) {
|
|
this.data.source.ships.addShips(ship.id, ship.amount);
|
|
}
|
|
await this.data.source.resources.updateAmount(this.data.cargo);
|
|
await this.data.source.ships.sync();
|
|
await this.data.source.resources.sync();
|
|
await sendMail(
|
|
null,
|
|
this.data.source instanceof SystemManager ? this.data.source.data.ownedBy.id : this.data.source.system.data.ownedBy.id,
|
|
this.data.arrivalTime,
|
|
"Fleet Returned",
|
|
`Your fleet from ${this.data.destination instanceof SystemManager ? `${this.data.destination.data.name} system` : `${this.data.destination.name} ${"expedition" in this.data.destination ? "sector" : "planet"}`} has returned.\n
|
|
Ships: ${this.data.ships.map(ship => `${ship.amount} ${ship.id}`).join(', ')}\n
|
|
Cargo: ${this.data.cargo.length > 0 ? this.data.cargo.map(cargo => `${cargo.amount} ${cargo.id}`).join(', ') : 'None'}`
|
|
);
|
|
return true;
|
|
} else {
|
|
switch(this.data.mission) {
|
|
case 'ATTACK':
|
|
if(!("expedition" in this.data.destination)) {
|
|
const enemyShips = this.data.destination.ships.ships;
|
|
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 {
|
|
throw new Error("Cannot attack sector.");
|
|
}
|
|
case 'TRANSPORT':
|
|
await (this.data.destination as Planet | SystemManager).resources.updateAmount(this.data.cargo);
|
|
await (this.data.destination as Planet | SystemManager).resources.sync();
|
|
const cargo = JSON.parse(JSON.stringify(this.data.cargo)) as Array<{ id: string, amount: number }>;
|
|
this.data.cargo = [];
|
|
const arrived = new Date(this.data.arrivalTime);
|
|
await this.initiateReturn();
|
|
await sendMail(
|
|
null,
|
|
this.data.source instanceof SystemManager ? this.data.source.data.ownedBy.id : this.data.source.system.data.ownedBy.id,
|
|
arrived,
|
|
"Fleet Arrived",
|
|
`Your fleet has arrived at ${this.data.destination instanceof SystemManager ? `${this.data.destination.data.name} system` : `planet ${this.data.destination.name}`}.\n
|
|
Ships: ${this.data.ships.map(ship => `${ship.amount} ${ship.id}`).join(', ')}\n
|
|
Cargo delivered: ${cargo.length > 0 ? cargo.map(cargo => `${cargo.amount} ${cargo.id}`).join(', ') : 'None'}\n
|
|
Fleet will return at ${this.data.arrivalTime}`
|
|
);
|
|
return false;
|
|
case 'TRANSFER':
|
|
await (this.data.destination as Planet | SystemManager).resources.updateAmount(this.data.cargo);
|
|
await (this.data.destination as Planet | SystemManager).resources.sync();
|
|
for(const ship of this.data.ships) {
|
|
(this.data.destination as Planet | SystemManager).ships.addShips(ship.id, ship.amount);
|
|
}
|
|
await (this.data.destination as Planet | SystemManager).ships.sync();
|
|
await sendMail(
|
|
null,
|
|
this.data.source instanceof SystemManager ? this.data.source.data.ownedBy.id : this.data.source.system.data.ownedBy.id,
|
|
this.data.arrivalTime,
|
|
"Fleet Arrived",
|
|
`Your fleet has arrived at ${this.data.destination instanceof SystemManager ? `${this.data.destination.data.name} system` : `planet ${this.data.destination.name}`}.\n
|
|
Ships: ${this.data.ships.map(ship => `${ship.amount} ${ship.id}`).join(', ')}\n
|
|
Cargo delivered: ${this.data.cargo.length > 0 ? this.data.cargo.map(cargo => `${cargo.amount} ${cargo.id}`).join(', ') : 'None'}\n
|
|
Ships will stay at the destination.`
|
|
);
|
|
return true;
|
|
case 'EXPEDITION':
|
|
await this.expeditionResults();
|
|
|
|
return false;
|
|
case 'MINE':
|
|
const system = this.data.destination as SystemManager;
|
|
const asteroid = system.asteroids.asteroids.find(a => a.id.equals(this.data.additionalData ?? ""));
|
|
if(!asteroid) throw new Error("Asteroid not found.");
|
|
for(const res of asteroid.resources) {
|
|
const resource = this.data.cargo.find(r => r.id === res.id);
|
|
if(!resource) this.data.cargo.push(res);
|
|
else resource.amount += res.amount;
|
|
}
|
|
|
|
await this.initiateReturn();
|
|
await sendMail(
|
|
null,
|
|
this.data.source instanceof SystemManager ? this.data.source.data.ownedBy.id : this.data.source.system.data.ownedBy.id,
|
|
this.data.arrivalTime,
|
|
"Asteroid mined",
|
|
`Your fleet has arrived at AS-${this.data.additionalData} asteroid.\n
|
|
Following resources were added to the cargo inventory:\n${asteroid.resources.map(r => `${r.id} - ${r.amount}`).join('\n')}\n
|
|
Fleet will return at ${this.data.arrivalTime}`
|
|
);
|
|
|
|
system.asteroids.asteroids = system.asteroids.asteroids.filter(a => !a.id.equals(asteroid.id));
|
|
await system.asteroids.sync();
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
async initiateReturn(isByPlayer: boolean = false) {
|
|
this.data.returning = true;
|
|
const elapsedTime = Date.now() - this.data.departureTime.getTime();
|
|
this.data.departureTime = isByPlayer ? new Date() : new Date(this.data.arrivalTime);
|
|
const travelTime = getDistanceBetween(this.data.destination, this.data.source);
|
|
this.data.arrivalTime = new Date(this.data.departureTime.getTime() + (isByPlayer ? elapsedTime : 1000 * travelTime));
|
|
await this.sync();
|
|
}
|
|
|
|
private async sendMail(user: ObjectId, title: string, description: string) {
|
|
await sendMail(
|
|
null,
|
|
user,
|
|
this.data.arrivalTime,
|
|
title,
|
|
description
|
|
);
|
|
}
|
|
|
|
async battleResults(enemyFleet: { id: string, amount: number }[], enemyDefenses: { id: string, amount: number }[] = []) {
|
|
const allShips = await getAllShips();
|
|
const allDefenses = await getAllDefenses();
|
|
|
|
const playerStats = this.data.ships.reduce((acc, ship) => {
|
|
const dbShip = allShips.find(s => s.id === ship.id);
|
|
if(!dbShip) return acc;
|
|
acc.attack += dbShip.structure.attack * ship.amount;
|
|
acc.defense += dbShip.structure.defense * ship.amount;
|
|
acc.hitpoints += dbShip.structure.hitpoints * ship.amount;
|
|
return acc;
|
|
}, { 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 dbShip = allShips.find(s => s.id === ship.id);
|
|
if(!dbShip) return acc;
|
|
acc.attack += dbShip.structure.attack * ship.amount;
|
|
acc.defense += dbShip.structure.defense * ship.amount;
|
|
acc.hitpoints += dbShip.structure.hitpoints * ship.amount;
|
|
return acc;
|
|
}, enemyDefensesStats);
|
|
|
|
const playerShipsStructure: BattleFleet[] = [];
|
|
for(const playerShip of this.data.ships) {
|
|
for(let i = 0; i < playerShip.amount; i++) playerShipsStructure.push({
|
|
id: playerShip.id,
|
|
hitpoints: allShips.find(s => s.id === playerShip.id)?.structure.hitpoints ?? 0,
|
|
attack: allShips.find(s => s.id === playerShip.id)?.structure.attack ?? 0,
|
|
defense: allShips.find(s => s.id === playerShip.id)?.structure.defense ?? 0
|
|
});
|
|
}
|
|
|
|
const enemyShipsStructure: BattleFleet[] = [];
|
|
for(const enemyShip of enemyFleet) {
|
|
for(let i = 0; i < enemyShip.amount; i++) enemyShipsStructure.push({
|
|
id: enemyShip.id,
|
|
hitpoints: allShips.find(s => s.id === enemyShip.id)?.structure.hitpoints ?? 0,
|
|
attack: allShips.find(s => s.id === enemyShip.id)?.structure.attack ?? 0,
|
|
defense: allShips.find(s => s.id === enemyShip.id)?.structure.defense ?? 0
|
|
});
|
|
}
|
|
|
|
if(playerStats.attack > enemyStats.defense * 2 && playerStats.defense > enemyStats.attack * 2) {
|
|
enemyShipsStructure.forEach((_, index) => enemyShipsStructure.splice(index, 1));
|
|
} else if(enemyStats.attack > playerStats.defense * 2 && enemyStats.defense > playerStats.attack * 2) {
|
|
playerShipsStructure.forEach((_, index) => playerShipsStructure.splice(index, 1));
|
|
} else {
|
|
roundLoop: for(let i = 0; i < 3; i++) {
|
|
for(const playerShip of playerShipsStructure) {
|
|
const enemyShip = enemyShipsStructure[Math.floor(Math.random() * enemyShipsStructure.length)];
|
|
|
|
if(!enemyShip) break roundLoop;
|
|
const typeCount = playerShipsStructure.filter(s => s.id === playerShip.id).length;
|
|
const additionalShipAttack = typeCount > 1 ? Math.floor(Math.random() * typeCount) * playerShip.attack : 0;
|
|
const playerDamage = Math.max(0, (playerShip.attack + additionalShipAttack) - enemyShip.defense);
|
|
enemyShip.hitpoints -= playerDamage;
|
|
}
|
|
|
|
for(const enemyShip of enemyShipsStructure) {
|
|
const playerShip = playerShipsStructure[Math.floor(Math.random() * playerShipsStructure.length)];
|
|
|
|
if(!playerShip) break roundLoop;
|
|
const typeCount = enemyShipsStructure.filter(s => s.id === enemyShip.id).length;
|
|
const additionalShipAttack = typeCount > 1 ? Math.floor(Math.random() * typeCount) * enemyShip.attack : 0;
|
|
const enemyDamage = Math.max(0, (enemyShip.attack + additionalShipAttack) - playerShip.defense);
|
|
playerShip.hitpoints -= enemyDamage;
|
|
}
|
|
|
|
playerShipsStructure.forEach((ship, index) => {
|
|
if(ship.hitpoints <= 0) playerShipsStructure.splice(index, 1);
|
|
});
|
|
|
|
enemyShipsStructure.forEach((ship, index) => {
|
|
if(ship.hitpoints <= 0) enemyShipsStructure.splice(index, 1);
|
|
});
|
|
}
|
|
}
|
|
|
|
const playerBalance = playerStats.defense - enemyStats.attack;
|
|
const enemyBalance = enemyStats.defense - playerStats.attack;
|
|
|
|
const playerShipsLeft = playerShipsStructure.reduce((acc, ship) => { acc[ship.id] = (acc[ship.id] ?? 0) + 1; return acc }, {} as { [key: string]: number });
|
|
const enemyShipsLeft = enemyShipsStructure.reduce((acc, ship) => { acc[ship.id] = (acc[ship.id] ?? 0) + 1; return acc }, {} as { [key: string]: number });
|
|
|
|
const resourcesStolen: { id: string, amount: number }[] = [];
|
|
|
|
const previousShips = JSON.parse(JSON.stringify(this.data.ships)) as Array<{ id: string, amount: number }>;
|
|
if(playerShipsStructure.length > 0) {
|
|
this.data.ships = Object.keys(playerShipsLeft).map(id => { return { id, amount: playerShipsLeft[id] } });
|
|
if(playerBalance > enemyBalance) {
|
|
const enemyResources = await (this.data.destination as Planet | SystemManager).resources;
|
|
await enemyResources.calculateCurrentAvailableResources();
|
|
let cargoSpaceFree = this.data.ships.reduce((acc, ship) => {
|
|
const dbShip = allShips.find(s => s.id === ship.id);
|
|
if(!dbShip) return acc;
|
|
return acc + dbShip.capacity.solid * ship.amount;
|
|
}, 0);
|
|
|
|
for(const res of enemyResources.resources) {
|
|
if(cargoSpaceFree <= 0) break;
|
|
const amount = Math.min(Math.floor(Math.random() * res.amount), cargoSpaceFree);
|
|
cargoSpaceFree -= amount;
|
|
this.data.cargo.push({ id: res.id, amount });
|
|
resourcesStolen.push({ id: res.id, amount });
|
|
enemyResources.setAmount([{ id: res.id, amount: res.amount - amount }]);
|
|
};
|
|
}
|
|
|
|
await this.initiateReturn();
|
|
} else this.data.ships = [];
|
|
|
|
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"})`,
|
|
`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
|
|
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
|
|
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
|
|
Enemy 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')}` : ""}`
|
|
);
|
|
|
|
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);
|
|
}
|
|
|
|
async expeditionResults() {
|
|
const expeditionRandom = Math.random(); //TODO: make use of "expedition" from DBSector
|
|
|
|
const allShips = await getAllShips();
|
|
const shipCount = this.data.ships.reduce((acc, ship) => acc += ship.amount, 0);
|
|
const totalShipCapacity = this.data.ships.reduce((acc, ship) => acc + (allShips.find(s => s.id === ship.id)?.capacity.solid ?? 0) * ship.amount, 0);
|
|
const currentCargo = this.data.cargo.reduce((acc, res) => acc + res.amount, 0);
|
|
|
|
const expeditionShipPositiveRandom = weightedRandom(shipCount > 100_000 ? 100_000 : shipCount);
|
|
const valueAdded = Math.floor(Math.pow(Math.E * expeditionShipPositiveRandom, 4 * Math.PI) + 10)
|
|
|
|
if(expeditionRandom < 0.02) { // 2% chance; lost all ships, black hole
|
|
this.data.ships = [];
|
|
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;
|
|
}
|
|
|
|
if(expeditionRandom < 0.1) { // 8% chance; found ships
|
|
const ships: { id: string, amount: number }[] = [];
|
|
ships.push({ id: 'transporter', amount: getRandomInRange(0, 20) + Math.floor(valueAdded ) });
|
|
ships.push({ id: 'fighter', amount: getRandomInRange(0, 20) + Math.floor(valueAdded ) });
|
|
|
|
for(const s of ships) {
|
|
const ship = this.data.ships.find((sh => sh.id === s.id));
|
|
if(!ship) this.data.ships.push(s);
|
|
else ship.amount += s.amount;
|
|
}
|
|
|
|
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();
|
|
return;
|
|
}
|
|
|
|
if(expeditionRandom < 0.2) { // 10% chance; found resources
|
|
let totalCapacityUsed = 0;
|
|
let resources = [];
|
|
|
|
const resToAdd = valueAdded * 3 + currentCargo > totalShipCapacity ? totalShipCapacity / 3 : valueAdded;
|
|
|
|
do {
|
|
resources = [{
|
|
id: "coal",
|
|
amount: getRandomInRange(0, 10000) + resToAdd
|
|
}, {
|
|
id: "iron",
|
|
amount: getRandomInRange(0, 10000) + resToAdd
|
|
}, {
|
|
id: "gold",
|
|
amount: getRandomInRange(0, 10000) + resToAdd
|
|
}];
|
|
|
|
totalCapacityUsed = resources.reduce((acc, res) => acc + res.amount, 0);
|
|
} while((totalCapacityUsed + currentCargo) > totalShipCapacity);
|
|
|
|
for(const res of resources) {
|
|
const resource = this.data.cargo.find(r => r.id === res.id);
|
|
if(!resource) this.data.cargo.push(res);
|
|
else resource.amount += res.amount;
|
|
}
|
|
|
|
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();
|
|
return;
|
|
}
|
|
|
|
if(expeditionRandom < 0.35) { // 15% chance; pirates/aliens
|
|
const pirates: { id: string, amount: number }[] = [
|
|
{ id: 'fighter', amount: getRandomInRange(0, 100) + valueAdded },
|
|
{ id: 'transporter', amount: getRandomInRange(0, 100) + valueAdded }
|
|
];
|
|
|
|
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);
|
|
return;
|
|
}
|
|
|
|
if(expeditionRandom < 0.36) { // 1% chance; rich rouge planet
|
|
const oneResourceMax = totalShipCapacity / 3;
|
|
|
|
let currentCargo = this.data.cargo.reduce((acc, res) => {
|
|
return acc + res.amount;
|
|
}, 0);
|
|
|
|
const addedResources: { id: string, amount: number }[] = [{
|
|
id: "coal",
|
|
amount: 0
|
|
}, {
|
|
id: "iron",
|
|
amount: 0
|
|
}, {
|
|
id: "gold",
|
|
amount: 0
|
|
}];
|
|
|
|
while(currentCargo < totalShipCapacity) {
|
|
if((addedResources.find(r => r.id === "coal")?.amount ?? 0) < oneResourceMax) {
|
|
(addedResources.find(r => r.id === "coal") as { amount: number }).amount++;
|
|
currentCargo++;
|
|
if(currentCargo >= totalShipCapacity) break;
|
|
}
|
|
|
|
if((addedResources.find(r => r.id === "iron")?.amount ?? 0) < oneResourceMax) {
|
|
(addedResources.find(r => r.id === "iron") as { amount: number }).amount++;
|
|
currentCargo++;
|
|
if(currentCargo >= totalShipCapacity) break;
|
|
}
|
|
|
|
if((addedResources.find(r => r.id === "gold")?.amount ?? 0) < oneResourceMax) {
|
|
(addedResources.find(r => r.id === "gold") as { amount: number }).amount++;
|
|
currentCargo++;
|
|
if(currentCargo >= totalShipCapacity) break;
|
|
}
|
|
}
|
|
|
|
for(const res of addedResources) {
|
|
const resource = this.data.cargo.find(r => r.id === res.id);
|
|
if(!resource) this.data.cargo.push(res);
|
|
else resource.amount += res.amount;
|
|
}
|
|
|
|
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();
|
|
return;
|
|
}
|
|
|
|
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();
|
|
return;
|
|
}
|
|
|
|
async sync() {
|
|
const source = this.data.source instanceof SystemManager ? this.data.source.data._id : this.data.source._id;
|
|
const destination = this.data.destination instanceof SystemManager ? this.data.destination.data._id : this.data.destination._id;
|
|
|
|
const data: DBFleet = {
|
|
_id: this.data.id,
|
|
source,
|
|
destination,
|
|
departureTime: this.data.departureTime,
|
|
arrivalTime: this.data.arrivalTime,
|
|
returning: this.data.returning,
|
|
mission: this.data.mission,
|
|
ships: this.data.ships,
|
|
cargo: this.data.cargo,
|
|
additionalData: this.data.additionalData
|
|
}
|
|
|
|
await updateFleet(data);
|
|
}
|
|
} |