Something went wrong. Try again.
Starship Simulator Controls thoriumsim.com
Something went wrong. Try again.
4.6 kB · 123 lines
TypeScript
at develop
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124import { pubsub } from "@thorium/.server/init/pubsub";import { cancelLoopingSound } from "@thorium/utils/.server/playRangedSound";import { applyDamage } from "@thorium/utils/.server/ship/collisionDamage";import { type Entity, System } from "@thorium/utils/ecs";import { isPointWithinCone } from "@thorium/utils/starmap/isPointWithinCone";import { degToRad, megaWattHourToGigaJoule } from "@thorium/utils/unitTypes";import { Quaternion, Vector3 } from "three";
export class PhasersSystem extends System { static flightMode = ["nova"]; test(entity: Entity) { return !!entity.components.isPhasers; } update(entity: Entity, elapsed: number) { const elapsedHours = elapsed / 1000 / 3600; const phasers = entity.components.isPhasers; if (!phasers) return; // Phaser damage is calculated based on the power output and efficiency // of the phaser system const power = entity.components.power; if (!power) return; const efficiency = entity.components.damage?.efficiency ?? 1; if (phasers.firePercent === 0) return; const phaserShip = entity.ecs?.getEntityById(entity.components.isShipSystem?.shipId || -1); if (power.currentPower === 0) { entity.updateComponent("isPhasers", { firePercent: 0 }); // TODO: Pubsub anywhere that needs to know phasers aren't firing pubsub.publish.targeting.phasers.firing({ systemId: phaserShip?.components.position?.parentId || null, });
// Stop any phaser sounds cancelLoopingSound(entity, "fire"); } const phaserDamage = power.currentPower * efficiency * elapsedHours * phasers.yieldMultiplier; if (phaserDamage === 0) return; if (!phaserShip) return; const target = getCurrentTarget(phaserShip);
if (!target) return; // Calculate the vector between the target and the ship const vectorBetween = getVectorBetweenTargetAndShip(entity, target); applyDamage(target, megaWattHourToGigaJoule(phaserDamage), vectorBetween); }}
const targetPosition = new Vector3();const shipPosition = new Vector3();const direction = new Vector3();const rotationQuaternion = new Quaternion();
function getVectorBetweenTargetAndShip(ship: Entity, target: Entity) { targetPosition.set( target.components.position?.x || 0, target.components.position?.y || 0, target.components.position?.z || 0, ); shipPosition.set( ship.components.position?.x || 0, ship.components.position?.y || 0, ship.components.position?.z || 0, );
return targetPosition.sub(shipPosition).normalize();}export function getTargetIsInPhaserRange(phasers: Entity) { if (!phasers.components.isPhasers) return false; const ship = phasers.ecs?.getEntityById(phasers.components.isShipSystem?.shipId || -1); if (!ship) return false; const target = getCurrentTarget(ship); if (!target) return false;
const { maxRange, arc, maxArc, headingDegree, pitchDegree } = phasers.components.isPhasers; const range = maxRange - maxRange * (arc / (maxArc + 1));
targetPosition.set( target.components.position?.x || 0, target.components.position?.y || 0, target.components.position?.z || 0, ); shipPosition.set( ship.components.position?.x || 0, ship.components.position?.y || 0, ship.components.position?.z || 0, ); rotationQuaternion.set( ship.components.rotation?.x || 0, ship.components.rotation?.y || 0, ship.components.rotation?.z || 0, ship.components.rotation?.w || 1, ); // Turn the ship rotation quaternion into a vector direction.set(0, 0, 1).applyQuaternion(rotationQuaternion); // Add the Phaser rotation to the ship rotation direction.applyAxisAngle(new Vector3(0, 1, 0), degToRad(headingDegree || 0)); direction.applyAxisAngle(new Vector3(1, 0, 0), degToRad(pitchDegree || 0)); direction.multiplyScalar(range); return isPointWithinCone(targetPosition, { apex: shipPosition, direction, angle: degToRad(phasers.components.isPhasers?.arc || 0), });}
export function getCurrentTarget(ship: Entity) { for (const [entityId] of ship.components.shipSystems?.shipSystems || []) { const entity = ship.ecs?.getEntityById(entityId);
if (entity?.components.isTargeting) { return ship.ecs?.getEntityById(entity.components.isTargeting?.target || -1); } }}
/** Returns the charge of the battery connected this phaser system */export function getPhaserCharge(e: Entity) { const phaseCapacitor = e.ecs.getEntityById(e.components.power?.batterySource || -1); let chargePercent = phaseCapacitor?.components.isBattery ? phaseCapacitor.components.isBattery.storage / phaseCapacitor.components.isBattery.capacity : 0;
return chargePercent;}