diff --git a/src/lib/classes/managers/FleetManager.ts b/src/lib/classes/managers/FleetManager.ts index 8b9d975..1cb81f0 100644 --- a/src/lib/classes/managers/FleetManager.ts +++ b/src/lib/classes/managers/FleetManager.ts @@ -1,15 +1,16 @@ import { ObjectId } from "mongodb"; import MissionType from "../../../types/MissionType"; import DBFleet from "../../../types/db/DBFleet"; +import { getAllDefenses } from "../../db/defenses"; import { updateFleet } from "../../db/fleet"; import { sendMail } from "../../db/mails"; import { getAllShips } from "../../db/ships"; +import { addPlanetToExistingSpyReport, addSpyReport, getSpyReportBySystemId, updatePlanetSpyReport, updateSystemSpyReportWithoutPlanets } from "../../db/spyReports"; 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, @@ -174,6 +175,86 @@ export default class FleetManager { system.asteroids.asteroids = system.asteroids.asteroids.filter(a => !a.id.equals(asteroid.id)); await system.asteroids.sync(); + return false; + case 'SPY': + if(this.data.destination instanceof SystemManager) { + const existing = await getSpyReportBySystemId(this.data.destination.data._id); + + if(existing) { + await updateSystemSpyReportWithoutPlanets( + existing._id, + this.data.destination.resources.resources, + this.data.destination.structures.structures.map(structure => { return { id: structure.data.id, level: structure.level } }), + this.data.destination.ships.ships.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 { + const gatheredData = { + systemId: this.data.destination.data._id, + resources: this.data.destination.resources.resources.map(res => { return { id: res.id, amount: res.amount } }), + structures: this.data.destination.structures.structures.map(structure => { return { id: structure.data.id, level: structure.level } }), + ships: this.data.destination.ships.ships.map(ship => { return { id: ship.data.id, amount: ship.amount } }), + defense: this.data.destination.defenses.defenses.map(defense => { return { id: defense.data.id, amount: defense.amount } }), + planets: [] + } + + await addSpyReport( + this.data.source instanceof SystemManager ? this.data.source.data.ownedBy.id : this.data.source.system.data.ownedBy.id, + this.data.destination.data.ownedBy.id, + new Date(), + [], + gatheredData + ); + } + } else if("fields" in this.data.destination) { + const existing = await getSpyReportBySystemId(this.data.destination.system.data._id); + + if(!existing) { + throw new Error("Impossible to spy on planet without system report."); + } + + const gatheredData = { + resources: this.data.destination.resources.resources.map(res => { return { id: res.id, amount: res.amount } }), + buildings: this.data.destination.buildings.buildings.map(building => { return { id: building.data.id, level: building.level } }), + ships: this.data.destination.ships.ships.map(ship => { return { id: ship.data.id, amount: ship.amount } }), + defense: this.data.destination.defenses.defenses.map(defense => { return { id: defense.data.id, amount: defense.amount } }) + } + + const planetId = this.data.destination._id; + if(existing.planets.find(p => p.id.equals(planetId))) { + await updatePlanetSpyReport(existing._id, planetId, gatheredData); + } else { + await addPlanetToExistingSpyReport(existing._id, gatheredData); + } + } + + await sendMail( + null, + this.data.source instanceof SystemManager ? this.data.source.data.ownedBy.id : this.data.source.system.data.ownedBy.id, + this.data.arrivalTime, + "Spy report", + `Your fleet has arrived at ${this.data.destination instanceof SystemManager ? `${this.data.destination.data.name} system` : `planet ${this.data.destination.name}`}.\n + Following information was gathered:\n\n + ${this.data.destination instanceof SystemManager ? `Research:\n${this.data.destination.data.ownedBy.research.research.map(research => `${research.id} - ${research.level}`).join('\n')}\n` : ""} + Resources:\n${(this.data.destination as Planet | SystemManager).resources.resources.map(res => `${res.amount} ${res.id}`).join('\n')}\n + ${this.data.destination instanceof SystemManager ? `Structures:\n${(this.data.destination as SystemManager).structures.structures.map(structure => `${structure.level} ${structure.data.id}`).join('\n')}\n` : `Buildings:\n${(this.data.destination as Planet).buildings.buildings.map(building => `${building.level} ${building.data.id}`).join('\n')}\n`} + Ships:\n${(this.data.destination as Planet | SystemManager).ships.ships.map(ship => `${ship.amount} ${ship.data.id}`).join('\n')}\n + Defense:\n${(this.data.destination as Planet | SystemManager).defenses.defenses.map(defense => `${defense.amount} ${defense.data.id}`).join('\n')}\n + ${this.data.destination instanceof SystemManager ? `Planets:\n${(this.data.destination as SystemManager).planets.map(planet => `${planet.name}`).join('\n')}` : ""} + Fleet will return at ${this.data.arrivalTime}` + ); + + await sendMail( + null, + this.data.destination instanceof SystemManager ? this.data.destination.data.ownedBy.id : (this.data.destination as Planet).system.data.ownedBy.id, + this.data.arrivalTime, + "Spy probe detected", + `Your systems have detected enemy spy probe at ${this.data.destination instanceof SystemManager ? `${this.data.destination.data.name} system` : `planet ${this.data.destination.name}`}.\n + Probe was identified to belong to ${this.data.source instanceof SystemManager ? this.data.source.data.ownedBy.username : this.data.source.system.data.ownedBy.username}.` + ); + + await this.initiateReturn(); + return false; } } diff --git a/src/lib/db/mongodb.ts b/src/lib/db/mongodb.ts index 39ce3ee..a37b450 100644 --- a/src/lib/db/mongodb.ts +++ b/src/lib/db/mongodb.ts @@ -98,4 +98,9 @@ export const Lang = async (language = "en") => { export const Mails = async() => { const db = await getDB(); return db.collection('mails'); +} + +export const SpyReports = async() => { + const db = await getDB(); + return db.collection('spyReports'); } \ No newline at end of file diff --git a/src/lib/db/spyReports.ts b/src/lib/db/spyReports.ts new file mode 100644 index 0000000..426fdde --- /dev/null +++ b/src/lib/db/spyReports.ts @@ -0,0 +1,121 @@ +import { ObjectId } from "mongodb"; +import { SpyReports } from "./mongodb" +import DBSpyReport, { DBSpyReportPlanet } from "../../types/db/DBSpyReport"; +import { addSpyReportToUser } from "./users"; + +export const getSpyReportById = async (id: ObjectId) => { + return await (await SpyReports()).findOne({ + _id: id + }) as DBSpyReport; +} + +export const getSpyReportBySystemId = async (id: ObjectId) => { + return await (await SpyReports()).findOne({ + systemId: id + }) as DBSpyReport; +} + +export const addSpyReport = async ( + toPlayer: ObjectId, + victimId: ObjectId, + scannedAt: Date, + research: Array<{ id: string, level: number }>, + data: { + systemId: ObjectId, + resources: Array<{ id: string, amount: number }>, + structures: Array<{ id: string, level: number }>, + ships: Array<{ id: string, amount: number }>, + defense: Array<{ id: string, amount: number }>, + planets: Array + } +) => { + const report = await (await SpyReports()).insertOne({ + victimId, + scannedAt, + research, + systemId: data.systemId, + resources: data.resources, + structures: data.structures, + ships: data.ships, + defense: data.defense, + planets: data.planets + }); + + await addSpyReportToUser(toPlayer, report.insertedId); +} + +export const updateSystemSpyReportWithoutPlanets = async ( + id: ObjectId, + resources: Array<{ id: string, amount: number }>, + structures: Array<{ id: string, level: number }>, + ships: Array<{ id: string, amount: number }>, + defense: Array<{ id: string, amount: number }> +) => { + await (await SpyReports()).updateOne({ + _id: id + }, { + $set: { + resources, + structures, + ships, + defense + } + }); +} + +export const addPlanetToExistingSpyReport = async ( + id: ObjectId, + data: { + resources: Array<{ id: string, amount: number }>, + buildings: Array<{ id: string, level: number }>, + ships: Array<{ id: string, amount: number }>, + defense: Array<{ id: string, amount: number }> + } +) => { + await (await SpyReports()).updateOne({ + _id: id + }, { + $push: { + planets: { + id: new ObjectId(), + scanned: true, + scannedAt: new Date(), + resources: data.resources, + buildings: data.buildings, + ships: data.ships, + defense: data.defense + } + } + }); +} + +export const updatePlanetSpyReport = async ( + id: ObjectId, + planetId: ObjectId, + data: { + resources: Array<{ id: string, amount: number }>, + buildings: Array<{ id: string, level: number }>, + ships: Array<{ id: string, amount: number }>, + defense: Array<{ id: string, amount: number }> + } +) => { + await (await SpyReports()).updateOne({ + _id: id, + "planets.id": planetId + }, { + $set: { + "planets.$.scanned": true, + "planets.$.scannedAt": new Date(), + "planets.$.resources": data.resources, + "planets.$.buildings": data.buildings, + "planets.$.ships": data.ships, + "planets.$.defense": data.defense + } + }); +} + +export const overwriteSpyReport = async (id: ObjectId, report: DBSpyReport) => { + await (await SpyReports()).replaceOne({ + _id: id + }, report); +} \ No newline at end of file diff --git a/src/lib/db/users.ts b/src/lib/db/users.ts index fa390ed..602a7d8 100644 --- a/src/lib/db/users.ts +++ b/src/lib/db/users.ts @@ -4,6 +4,8 @@ import { hash } from 'argon2' import DBUser from '../../types/db/DBUser'; import User from '../classes/User'; import AccessToken from '../../types/AccessToken'; +import { getSpyReportById } from './spyReports'; +import DBSpyReport from '../../types/db/DBSpyReport'; export const getAllUsers = async () => { const users = await Users(); @@ -20,7 +22,8 @@ export const createUser = async (id: ObjectId, username: string, email: string, createdAt: new Date(), updatedAt: new Date(), research: [], - mainPlanet + mainPlanet, + spyReports: [] } await (await Users()).insertOne(user); @@ -75,4 +78,24 @@ export const getUserResearch = async (user: User): Promise) => { const users = await Users(); users.updateOne({ username: user.username }, { $set: { research } }); +} + +export const addSpyReportToUser = async (userId: ObjectId, spyReportId: ObjectId) => { + const users = await Users(); + users.updateOne({ _id: userId }, { $push: { spyReports: spyReportId } }); +} + +export const getUserSpyReports = async (userId: ObjectId) => { + const users = await Users(); + const user = await users.findOne({ _id: userId }); + if (!user) return []; + + const out: DBSpyReport[] = []; + + for(const spyId of user.spyReports) { + const spyReport = await getSpyReportById(spyId); + if(spyReport) out.push(spyReport); + } + + return out; } \ No newline at end of file diff --git a/src/pages/game/fleet.astro b/src/pages/game/fleet.astro index 4e61873..394a81b 100644 --- a/src/pages/game/fleet.astro +++ b/src/pages/game/fleet.astro @@ -5,6 +5,7 @@ import { Planet } from '../../lib/classes/managers/PlanetManager'; import SystemManager from '../../lib/classes/managers/SystemManager'; import { getAllFleetByUser } from '../../lib/db/fleet'; import { getAllShips } from '../../lib/db/ships'; +import { getUserSpyReports } from '../../lib/db/users'; import { getName } from '../../lib/utils/langDriver'; const { token, user, lang } = Astro.locals; @@ -89,6 +90,8 @@ for(const f of fleet) { } } +const discoveredSectors = await getUserSpyReports(user.id); + const sectorsList = galaxies.map(galaxy => { return { _id: galaxy._id, @@ -98,6 +101,13 @@ const sectorsList = galaxies.map(galaxy => { _id: sector._id, name: sector.name, systems: sector.systems.map(system => { + const discovered = discoveredSectors.find(s => s.systemId.equals(system.data._id)); + if(!discovered && !system.data.ownedBy.id.equals(user.id)) return { + _id: system.data._id, + name: `${system.data.name} (not discovered)`, + planets: [] + } + return { _id: system.data._id, name: system.data.name, @@ -158,6 +168,7 @@ const sectorsList = galaxies.map(galaxy => { +

Send to:

diff --git a/src/types/MissionType.ts b/src/types/MissionType.ts index 14cb771..eb4bec8 100644 --- a/src/types/MissionType.ts +++ b/src/types/MissionType.ts @@ -1,3 +1,3 @@ -type MissionType = "TRANSPORT" | "ATTACK" | "TRANSFER" | "EXPEDITION" | "MINE"; +type MissionType = "TRANSPORT" | "ATTACK" | "TRANSFER" | "EXPEDITION" | "MINE" | "SPY"; export default MissionType; \ No newline at end of file diff --git a/src/types/SpyData.ts b/src/types/SpyData.ts new file mode 100644 index 0000000..cc63108 --- /dev/null +++ b/src/types/SpyData.ts @@ -0,0 +1,16 @@ +export default interface SpyData { + id: string; + resources: Array<{ id: string, amount: number }>; + structures: Array<{ id: string, level: number }>; + ships: Array<{ id: string, amount: number }>; + defense: Array<{ id: string, amount: number }>; + planets: Array<{ + id: string; + scanned: boolean; + scannedAt: Date; + resources: Array<{ id: string, amount: number }>; + buildings: Array<{ id: string, level: number }>; + ships: Array<{ id: string, amount: number }>; + defense: Array<{ id: string, amount: number }>; + }>; +} \ No newline at end of file diff --git a/src/types/db/DBSpyReport.ts b/src/types/db/DBSpyReport.ts new file mode 100644 index 0000000..beae343 --- /dev/null +++ b/src/types/db/DBSpyReport.ts @@ -0,0 +1,24 @@ +import { ObjectId } from "mongodb"; + +export interface DBSpyReportPlanet { + id: ObjectId; + scanned: boolean; + scannedAt: Date; + resources: Array<{ id: string, amount: number }>; + buildings: Array<{ id: string, level: number }>; + ships: Array<{ id: string, amount: number }>; + defense: Array<{ id: string, amount: number }>; +} + +export default interface DBSpyReport { + _id: ObjectId; + victimId: ObjectId; + scannedAt: Date; + research: Array<{ id: string, level: number }>; + systemId: ObjectId; + resources: Array<{ id: string, amount: number }>; + structures: Array<{ id: string, level: number }>; + ships: Array<{ id: string, amount: number }>; + defense: Array<{ id: string, amount: number }>; + planets: Array; +} \ No newline at end of file diff --git a/src/types/db/DBUser.ts b/src/types/db/DBUser.ts index ea48cfe..eab4c25 100644 --- a/src/types/db/DBUser.ts +++ b/src/types/db/DBUser.ts @@ -10,4 +10,5 @@ export default interface DBUser { updatedAt: Date; research: Array<{ id: string, level: number }>; mainPlanet: ObjectId; + spyReports: Array; } \ No newline at end of file