243 lines
No EOL
7.5 KiB
TypeScript
Executable file
243 lines
No EOL
7.5 KiB
TypeScript
Executable file
import type { valuableBody } from "../@types/edsmResponses"
|
|
import type { asteroidScan, autoScan, detailedScan, planetScan, starScan } from "../@types/journalLines"
|
|
|
|
import { BodyCodes } from "../data/BodyCodes"
|
|
|
|
export interface Body extends starScan<'AutoScan'|'DetailedScan'>, asteroidScan<'AutoScan'|'DetailedScan'>, planetScan<'AutoScan'|'DetailedScan'> {}
|
|
export class Body {
|
|
DSSDone: boolean
|
|
mappedValue: number
|
|
|
|
constructor(journalLine: autoScan|detailedScan|valuableBody|null = null, DSS: boolean = false) {
|
|
this.DSSDone = DSS
|
|
|
|
if (journalLine !== null) {
|
|
Object.assign(this, journalLine)
|
|
}
|
|
|
|
this.mappedValue = this.#getValue()
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------- isAsteroid ---- */
|
|
|
|
isAsteroid(): boolean {
|
|
return this.BodyName.includes('Belt')
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------------- isPlanet ---- */
|
|
|
|
isPlanet(): boolean {
|
|
return !!this.PlanetClass
|
|
}
|
|
|
|
/* ------------------------------------------------------------------------------ isStar ---- */
|
|
|
|
isStar(): boolean {
|
|
return !!this.StarType
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------------- nameIcon ---- */
|
|
|
|
nameIcon(): string|null {
|
|
let nameIcon: string|null = null
|
|
|
|
if (this.isAsteroid()) {
|
|
nameIcon = 'asteroid-4'
|
|
} else if (this.isStar()) {
|
|
nameIcon = 'star'
|
|
} else if (this.isPlanet()) {
|
|
nameIcon = 'jupiter-3'
|
|
}
|
|
|
|
return nameIcon
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------- simpleName ---- */
|
|
|
|
simpleName(): string {
|
|
return this.BodyName.replace(this.StarSystem, '')
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------------- typeIcon ---- */
|
|
|
|
typeIcon(): string|null {
|
|
let typeIcon: string|null = null
|
|
|
|
if (this.isStar() || this.isAsteroid()) {
|
|
typeIcon = this.nameIcon()
|
|
} else {
|
|
const planetClass: string = this.PlanetClass.toLowerCase()
|
|
|
|
if (planetClass.includes('metal')) {
|
|
typeIcon = 'ingot'
|
|
} else if (planetClass.includes('icy')) {
|
|
typeIcon = 'snowflake'
|
|
} else if (planetClass.includes('earth')) {
|
|
typeIcon = 'earth'
|
|
} else if (planetClass.includes('gas giant')) {
|
|
typeIcon = 'jupiter-1'
|
|
} else if (planetClass.includes('rock')) {
|
|
typeIcon = 'asteroid-3'
|
|
} else if (planetClass.includes('water') || planetClass.includes('ammonia')) {
|
|
typeIcon = 'water-drops'
|
|
}
|
|
}
|
|
|
|
return typeIcon
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------------- getValue ---- */
|
|
|
|
// https://forums.frontier.co.uk/threads/exploration-value-formulae.232000/
|
|
// https://github.com/EDSM-NET/Component/blob/master/Body/Value.php
|
|
|
|
#getValue(): number {
|
|
let bodyType: number|undefined = undefined // Asteroids.
|
|
|
|
if (this.isStar()) {
|
|
// Typescript feels so stupid sometimes.
|
|
bodyType = BodyCodes.starTypes[this.StarType as keyof typeof BodyCodes.starTypes]
|
|
} else if (this.isPlanet()) {
|
|
bodyType = BodyCodes.planetTypes[this.PlanetClass as keyof typeof BodyCodes.planetTypes]
|
|
}
|
|
|
|
// Asteroids don't have mass.
|
|
const mass = ('MassEM' in this) ? this.MassEM : 1
|
|
|
|
let terraformState: number|undefined = undefined // Asteroids & Stars.
|
|
|
|
if ('TerraformState' in this) {
|
|
terraformState =
|
|
BodyCodes.terraformStates[this.TerraformState as keyof typeof BodyCodes.terraformStates]
|
|
}
|
|
|
|
const firstDiscover = !this.WasDiscovered
|
|
const firstMap = !this.WasMapped
|
|
|
|
if (this.isStar()) {
|
|
return this.#appraiseStar(bodyType, mass)
|
|
|
|
} else if (this.isPlanet() || this.isAsteroid()) {
|
|
// Asteroids are treated as planets for the purpose of value calculation.
|
|
return this.#appraisePlanet(bodyType, mass, terraformState, firstDiscover, firstMap)
|
|
|
|
} else {
|
|
return 0
|
|
}
|
|
}
|
|
|
|
/* ----------------------------------------------------------------------- #appraiseStar ---- */
|
|
|
|
#appraiseStar(bodyType: number|undefined, mass: number): number {
|
|
let value: number = 1200
|
|
|
|
if (bodyType) {
|
|
if (BodyCodes.whiteDwarf.includes(bodyType)) {
|
|
value = 14057
|
|
|
|
} else if (
|
|
BodyCodes.neutronStar.includes(bodyType)
|
|
|| BodyCodes.blackHole.includes(bodyType)
|
|
) {
|
|
value = 22628
|
|
|
|
} else if (BodyCodes.superMassiveBlackHole.includes(bodyType)) {
|
|
value = 33.5678 // Not confirmed in game.
|
|
}
|
|
}
|
|
|
|
return Math.round(value + (mass * value / 66.25))
|
|
}
|
|
|
|
/* --------------------------------------------------------------------- #appraisePlanet ---- */
|
|
|
|
#appraisePlanet(
|
|
bodyType: number|undefined,
|
|
mass: number,
|
|
terraformState: number|undefined,
|
|
firstDiscover: boolean,
|
|
firstMap: boolean
|
|
): number {
|
|
|
|
// Base value & terraform bonus calculation.
|
|
let value: number = 300
|
|
let terraformBonus: number = 0
|
|
|
|
// Base terraform bonus.
|
|
if (terraformState && terraformState > 0) {
|
|
terraformBonus = 93328
|
|
}
|
|
|
|
if (bodyType) {
|
|
// Metal-rich body.
|
|
if (BodyCodes.metalRich.includes(bodyType)) {
|
|
value = 21790
|
|
|
|
if (terraformState && terraformState > 0) {
|
|
terraformBonus = 65631
|
|
}
|
|
|
|
// Ammonia world.
|
|
} else if (BodyCodes.ammonia.includes(bodyType)) {
|
|
value = 96932
|
|
|
|
// Class I gas giant.
|
|
} else if (BodyCodes.classIGiant.includes(bodyType)) {
|
|
value = 1656
|
|
|
|
// High metal content & Class II gas giant.
|
|
} else if (
|
|
BodyCodes.highMetalContent.includes(bodyType)
|
|
|| BodyCodes.classIIGiant.includes(bodyType)
|
|
) {
|
|
value = 9654
|
|
|
|
if (terraformState && terraformState > 0) {
|
|
terraformBonus = 100677
|
|
}
|
|
|
|
// Earth-like world & water world.
|
|
} else if (
|
|
BodyCodes.earthLike.includes(bodyType)
|
|
|| BodyCodes.water.includes(bodyType)
|
|
) {
|
|
value = 64831
|
|
|
|
if (terraformState && terraformState > 0) {
|
|
terraformBonus = 116295
|
|
}
|
|
|
|
// Earth-like always gets a bonus.
|
|
if (BodyCodes.earthLike.includes(bodyType)) {
|
|
terraformBonus = 116295
|
|
}
|
|
}
|
|
}
|
|
|
|
// Mapping multiplier.
|
|
let mapMultiplier: number = 3.3333333333
|
|
|
|
if (firstDiscover && firstMap) {
|
|
mapMultiplier = 3.699622554
|
|
|
|
} else if (!firstDiscover && firstMap) {
|
|
mapMultiplier = 8.0956
|
|
}
|
|
|
|
// Efficiency bonus.
|
|
mapMultiplier *= 1.25
|
|
|
|
// Final calculation.
|
|
const q = 0.56591828
|
|
value += terraformBonus
|
|
|
|
let finalValue = Math.max((value + (value * Math.pow(mass, 0.2) * q)) * mapMultiplier, 500)
|
|
|
|
// First discovery bonus.
|
|
if (firstDiscover) {
|
|
finalValue *= 2.6
|
|
}
|
|
|
|
return Math.round(finalValue)
|
|
}
|
|
} |