Something went wrong. Try again.
Starship Simulator Controls thoriumsim.com
Something went wrong. Try again.
7.9 kB · 224 lines
TypeScript
at develop
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225import type BaseShipSystemPlugin from "@thorium/.server/classes/Plugins/ShipSystems/BaseSystem";import CoolantTankPlugin from "@thorium/.server/classes/Plugins/ShipSystems/CoolantTank";import { ShipSystemTypes } from "@thorium/.server/classes/Plugins/ShipSystems/shipSystemTypes";import { components, type ComponentIds } from "@thorium/ecs-components";import { shipMap } from "@thorium/ecs-components/list";import { Entity } from "@thorium/utils/ecs";import { mergeDeep } from "@thorium/utils/operations/mergeDeep";import { randomFromList } from "@thorium/utils/operations/randomFromList";import { randomPointInCircle } from "@thorium/utils/operations/randomPointInSphere";import type { z } from "zod";
export function spawnShipSystem( shipId: number, systemPlugin: Partial<BaseShipSystemPlugin>, flightMode: "legacy" | "nova", shipRooms: z.infer<typeof shipMap>["deckNodes"], isPlayerShip?: boolean, overrides: Record<string, any> = {},) { const entity = new Entity(); const entities = [entity];
const template = mergeDeep(systemPlugin, overrides);
entity.addComponent("identity", { name: template.name, description: template.description, }); entity.addComponent("tags", { tags: template.tags });
if (template.soundEffects) { entity.addComponent("soundEffects", { soundBank: template.soundEffects, }); }
if (template.type) { entity.addComponent("isShipSystem", { type: template.type, shipId });
const componentName = `is${template.type[0].toUpperCase()}${template.type.slice( 1, )}` as `is${Capitalize<typeof template.type>}`;
const flags = ShipSystemTypes[template.type].flags;
if (template.type === "phasers") { const phaserBanks: number[] = [];
if ( flightMode === "legacy" && "legacyPhaserBanks" in template && typeof template.legacyPhaserBanks === "number" ) { for (let i = 0; i < template.legacyPhaserBanks; i++) { // Create phaser banks for each phaser system const phaserBank = new Entity(); phaserBank.addComponent("isPhaserBank", { // @ts-expect-error chargeSpeed: template.legacyChargeSpeed, phaserId: entity.id, shipId, }); phaserBank.addComponent("heat"); entities.push(phaserBank); phaserBanks.push(phaserBank.id); } } entity.addComponent("isPhasers", { ...template, legacyPhaserBanks: phaserBanks }); } else if (flightMode === "legacy" && template.type === "sensors") { entity.addComponent("isLegacySensors", template as any); entity.addComponent("isLegacySensorScanning", template as any); } else if (template.type !== "generic" && componentName in components) entity.addComponent(componentName as ComponentIds, template);
if ( template.type === "exocomps" && "exocompCount" in template && typeof template.exocompCount === "number" ) { // Create the exocomp entities const { exocompName, exocompMaxCharge: maxCharge, exocompChargeRate: chargeRate, exocompIdleDischargeRate: idleDischargeRate, exocompWorkingDischargeRate: workingDischargeRate, exocompMovingDischargeRate: movingDischargeRate, exocompMovementSpeed: movementSpeed, exocompCargoVolume: volume, } = template as any; let room: | { id: number; x: number; y: number; deckIndex: number; radius?: number } | undefined = randomFromList( shipRooms.filter((r) => r.isRoom && r.systems?.includes("exocomps")), ); if (!room) { room = randomFromList(shipRooms.filter((r) => r.isRoom)); console.error( "Exocomps system is not assigned to a room, which means exocomps have no place to return to.", ); } else { for (let i = 0; i < template.exocompCount; i++) { const exocompEntity = new Entity(); exocompEntity.addComponent("identity", { name: `${exocompName} ${i + 1}` }); exocompEntity.addComponent("exocomp", { shipId, maxCharge, currentCharge: maxCharge, chargeRate, idleDischargeRate, workingDischargeRate, movingDischargeRate, }); exocompEntity.addComponent("cargoContainer", { volume }); exocompEntity.addComponent("passengerMovement", { movementMaxVelocity: { x: movementSpeed, y: movementSpeed, z: movementSpeed / 10 }, destinationNode: room.id, }); // Place this exocomp inside the exocomp room. Otherwise, put it in a random place on the ship and log a warning. const [x, y] = randomPointInCircle(room?.radius || 0); exocompEntity.addComponent("position", { parentId: shipId, type: "ship", ...(room ? { x: room.x + x, y: room.y + y, z: room.deckIndex } : null), }); entities.push(exocompEntity); } } } const { powerToHeat, maxHeat, maxSafeHeat, nominalHeat, powerLevels, coolantConsumptionRate, coolantTransferRate, } = systemPlugin; if (isPlayerShip) { if (flags.includes("heat")) { entity.addComponent("heat", { powerToHeat: overrides.powerToHeat || powerToHeat, maxHeat: overrides.maxHeat || maxHeat, maxSafeHeat: overrides.maxSafeHeat || maxSafeHeat, nominalHeat: overrides.nominalHeat || nominalHeat, heat: overrides.nominalHeat || nominalHeat, }); if (flightMode === "legacy") { entity.addComponent("legacyCoolant", { coolantConsumptionRate: overrides.coolantConsumptionRate || coolantConsumptionRate, coolantTransferRate: overrides.coolantTransferRate || coolantTransferRate, }); } } if (flightMode === "legacy" && template.type === "coolantTank") { entity.addComponent("legacyCoolant", { coolantConsumptionRate: overrides.coolantConsumptionRate || coolantConsumptionRate, coolantTransferRate: overrides.coolantTransferRate || coolantTransferRate, }); }
if (flags.includes("damage")) entity.addComponent("damage"); } if (flags.includes("power")) { entity.addComponent("power", { powerLevels: overrides.powerLevels || powerLevels, }); } }
if (template instanceof CoolantTankPlugin) { // Create entities for the coolant tank, the coolant pump, and the radiator // The base entity is the tank itself entity.updateComponent("isCoolantTank", { capacity: template.tankCapacity, coolantDensity: template.coolantDensity, coolantSpecificHeat: template.coolantSpecificHeat, }); entity.updateComponent("heat", { coolantVolume: template.tankCapacity, }); entity.removeComponent("power");
const { powerToHeat, maxHeat, maxSafeHeat, nominalHeat, powerLevels } = systemPlugin;
const radiator = new Entity(); radiator.addComponent("identity", { name: "Radiator" }); radiator.addComponent("isShipSystem", { shipId, type: "coolantRadiator" }); radiator.addComponent("isCoolantRadiator", { area: template.radiatorArea, }); radiator.addComponent("heat", { inCoolantLoop: true, powerToHeat: overrides.powerToHeat || powerToHeat, maxHeat: overrides.maxHeat || maxHeat, maxSafeHeat: overrides.maxSafeHeat || maxSafeHeat, nominalHeat: overrides.nominalHeat || nominalHeat, heat: overrides.nominalHeat || nominalHeat, }); radiator.addComponent("damage"); entities.push(radiator);
const pump = new Entity(); pump.addComponent("identity", { name: "Pump" }); pump.addComponent("isShipSystem", { shipId, type: "coolantPump" }); pump.addComponent("damage"); pump.addComponent("heat", { powerToHeat: overrides.powerToHeat || powerToHeat, maxHeat: overrides.maxHeat || maxHeat, maxSafeHeat: overrides.maxSafeHeat || maxSafeHeat, nominalHeat: overrides.nominalHeat || nominalHeat, heat: overrides.nominalHeat || nominalHeat, }); const pumpPowerLevels = overrides.powerLevels || powerLevels; pump.addComponent("power", { powerLevels: pumpPowerLevels, powerDraw: pumpPowerLevels[0], }); pump.addComponent("isCoolantPump", { baseFlowRate: template.pumpBaseFlowRate }); entities.push(pump); }
return entities;}