Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/client/graphics/layers/SAMRadiusLayer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ export class SAMRadiusLayer implements Layer {
return {
x: this.game.x(tile),
y: this.game.y(tile),
r: this.game.config().defaultSamRange(),
r: this.game.config().samRange(sam.level()),
owner: sam.owner().smallID(),
};
});
Expand Down
3 changes: 2 additions & 1 deletion src/client/graphics/layers/StructureDrawingUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -428,14 +428,15 @@ export class SpriteFactory {
type: UnitType,
stage: PIXI.Container,
pos: { x: number; y: number },
level?: number,
): PIXI.Container | null {
if (stage === undefined) throw new Error("Not initialized");
const parentContainer = new PIXI.Container();
const circle = new PIXI.Graphics();
let radius = 0;
switch (type) {
case UnitType.SAMLauncher:
radius = this.game.config().defaultSamRange();
radius = this.game.config().samRange(level ?? 1);
break;
case UnitType.Factory:
radius = this.game.config().trainStationMaxRange();
Expand Down
54 changes: 50 additions & 4 deletions src/client/graphics/layers/StructureIconsLayer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ export class StructureIconsLayer implements Layer {
private ghostUnit: {
container: PIXI.Container;
range: PIXI.Container | null;
rangeLevel?: number;
buildableUnit: BuildableUnit;
} | null = null;
private pixicanvas: HTMLCanvasElement;
Expand Down Expand Up @@ -277,6 +278,9 @@ export class StructureIconsLayer implements Layer {

this.ghostUnit.buildableUnit = unit;

const targetLevel = this.resolveGhostRangeLevel(unit);
this.updateGhostRange(targetLevel);

if (unit.canUpgrade) {
this.potentialUpgrade = this.renders.find(
(r) =>
Expand Down Expand Up @@ -369,12 +373,11 @@ export class StructureIconsLayer implements Layer {
{ x: localX, y: localY },
type,
),
range: this.factory.createRange(type, this.ghostStage, {
x: localX,
y: localY,
}),
range: null,
buildableUnit: { type, canBuild: false, canUpgrade: false, cost: 0n },
};
const baseLevel = this.resolveGhostRangeLevel(this.ghostUnit.buildableUnit);
this.updateGhostRange(baseLevel);
}

private clearGhostStructure() {
Expand All @@ -395,6 +398,49 @@ export class StructureIconsLayer implements Layer {
this.uiState.ghostStructure = null;
}

private resolveGhostRangeLevel(
buildableUnit: BuildableUnit,
): number | undefined {
if (buildableUnit.type !== UnitType.SAMLauncher) {
return undefined;
}
if (buildableUnit.canUpgrade !== false) {
const existing = this.game.unit(buildableUnit.canUpgrade);
if (existing) {
return existing.level() + 1;
} else {
console.error("Failed to find existing SAMLauncher for upgrade");
}
}

return 1;
}

private updateGhostRange(level?: number) {
if (!this.ghostUnit) {
return;
}

if (this.ghostUnit.range && this.ghostUnit.rangeLevel === level) {
return;
}

this.ghostUnit.range?.destroy();
this.ghostUnit.range = null;
this.ghostUnit.rangeLevel = level;

const position = this.ghostUnit.container.position;
const range = this.factory.createRange(
this.ghostUnit.buildableUnit.type,
this.ghostStage,
{ x: position.x, y: position.y },
level,
);
if (range) {
this.ghostUnit.range = range;
}
}

private toggleStructures(toggleStructureType: UnitType[] | null): void {
for (const [structureType, infos] of this.structures) {
infos.visible =
Expand Down
2 changes: 2 additions & 0 deletions src/core/configuration/Config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,8 @@ export interface Config {
defaultNukeTargetableRange(): number;
defaultSamMissileSpeed(): number;
defaultSamRange(): number;
samRange(level: number): number;
maxSamRange(): number;
nukeDeathFactor(
nukeType: NukeType,
humans: number,
Expand Down
9 changes: 9 additions & 0 deletions src/core/configuration/DefaultConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -920,6 +920,15 @@ export class DefaultConfig implements Config {
return 70;
}

samRange(level: number): number {
// rational growth function (level 1 = 70, level 5 just above hydro range, asymptotically approaches 150)
return this.maxSamRange() - 480 / (level + 5);
}

maxSamRange(): number {
return 150;
}

defaultSamMissileSpeed(): number {
return 12;
}
Expand Down
4 changes: 2 additions & 2 deletions src/core/execution/SAMLauncherExecution.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ class SAMTargetingSystem {

private isInRange(tile: TileRef) {
const samTile = this.sam.tile();
const range = this.mg.config().defaultSamRange();
const range = this.mg.config().samRange(this.sam.level());
const rangeSquared = range * range;
return this.mg.euclideanDistSquared(samTile, tile) <= rangeSquared;
}
Expand Down Expand Up @@ -82,7 +82,7 @@ class SAMTargetingSystem {

public getSingleTarget(ticks: number): Target | null {
// Look beyond the SAM range so it can preshot nukes
const detectionRange = this.mg.config().defaultSamRange() * 2;
const detectionRange = this.mg.config().maxSamRange() * 2;
const nukes = this.mg.nearbyUnits(
this.sam.tile(),
detectionRange,
Expand Down
Loading