mirror of
https://github.com/openfrontio/OpenFrontIO.git
synced 2026-07-15 12:43:05 +00:00
BUG FIX: Gold double deduction + Rmoval of UnitType.Construction (#2378)
## Description: - Removed the temporary UnitType.Construction and embedded construction state into real units via isUnderConstruction(). - Centralized non-structure spawning to perform a single validation right before unit creation/launch. - Updated UI layers to render construction state without relying on the removed enum. - Adjusted and created tests to match the new flow and to cover the no-refundscenarios. # Tests updated - tests/economy/ConstructionGold.test.ts: covers structure cost deduction and income, tolerant of passive income; ensures no refunds during construction. - tests/nukes/HydrogenAndMirv.test.ts: accounts for single-check launch flow; MIRV test targets a player-owned tile; ensures launch after payment. - tests/client/graphics/UILayer.test.ts: mocks now provide isUnderConstruction and real type strings; ## Please complete the following: - [X] I have added screenshots for all UI updates - [X] I process any text displayed to the user through translateText() and I've added it to the en.json file - [X] I have added relevant tests to the test directory - [X] I confirm I have thoroughly tested these changes and take full responsibility for any bugs introduced ## Please put your Discord username so you can be contacted if a bug or regression is found: CrackeRR1 --------- Co-authored-by: Evan <evanpelle@gmail.com>
This commit is contained in:
@@ -452,7 +452,7 @@ export const deleteUnitElement: MenuElement = {
|
||||
.units()
|
||||
.filter(
|
||||
(unit) =>
|
||||
unit.constructionType() === undefined &&
|
||||
!unit.isUnderConstruction() &&
|
||||
unit.markedForDeletion() === false &&
|
||||
params.game.manhattanDist(unit.tile(), params.tile) <=
|
||||
DELETE_SELECTION_RADIUS,
|
||||
|
||||
@@ -143,19 +143,12 @@ export class SpriteFactory {
|
||||
const screenPos = this.transformHandler.worldToScreenCoordinates(worldPos);
|
||||
|
||||
const isMarkedForDeletion = unit.markedForDeletion() !== false;
|
||||
const isConstruction = unit.type() === UnitType.Construction;
|
||||
const constructionType = unit.constructionType();
|
||||
const structureType = isConstruction ? constructionType! : unit.type();
|
||||
const isConstruction = unit.isUnderConstruction();
|
||||
const structureType = unit.type();
|
||||
const { type, stage } = options;
|
||||
const { scale } = this.transformHandler;
|
||||
|
||||
if (type === "icon" || type === "dot") {
|
||||
if (isConstruction && constructionType === undefined) {
|
||||
console.warn(
|
||||
`Unit ${unit.id()} is a construction but has no construction type.`,
|
||||
);
|
||||
return parentContainer;
|
||||
}
|
||||
const texture = this.createTexture(
|
||||
structureType,
|
||||
unit.owner(),
|
||||
|
||||
@@ -469,10 +469,7 @@ export class StructureIconsLayer implements Layer {
|
||||
this.checkForOwnershipChange(render, unitView);
|
||||
this.checkForLevelChange(render, unitView);
|
||||
}
|
||||
} else if (
|
||||
this.structures.has(unitView.type()) ||
|
||||
unitView.type() === UnitType.Construction
|
||||
) {
|
||||
} else if (this.structures.has(unitView.type())) {
|
||||
this.addNewStructure(unitView);
|
||||
}
|
||||
}
|
||||
@@ -485,10 +482,7 @@ export class StructureIconsLayer implements Layer {
|
||||
}
|
||||
|
||||
private modifyVisibility(render: StructureRenderInfo) {
|
||||
const structureType =
|
||||
render.unit.type() === UnitType.Construction
|
||||
? render.unit.constructionType()!
|
||||
: render.unit.type();
|
||||
const structureType = render.unit.type();
|
||||
const structureInfos = this.structures.get(structureType);
|
||||
|
||||
let focusStructure = false;
|
||||
@@ -529,10 +523,7 @@ export class StructureIconsLayer implements Layer {
|
||||
render: StructureRenderInfo,
|
||||
unit: UnitView,
|
||||
) {
|
||||
if (
|
||||
render.underConstruction &&
|
||||
render.unit.type() !== UnitType.Construction
|
||||
) {
|
||||
if (render.underConstruction && !unit.isUnderConstruction()) {
|
||||
render.underConstruction = false;
|
||||
render.iconContainer?.destroy();
|
||||
render.dotContainer?.destroy();
|
||||
@@ -580,10 +571,7 @@ export class StructureIconsLayer implements Layer {
|
||||
: screenPos.y,
|
||||
);
|
||||
|
||||
const type =
|
||||
render.unit.type() === UnitType.Construction
|
||||
? render.unit.constructionType()
|
||||
: render.unit.type();
|
||||
const type = render.unit.type();
|
||||
const margin =
|
||||
type !== undefined && STRUCTURE_SHAPES[type] !== undefined
|
||||
? ICON_SIZE[STRUCTURE_SHAPES[type]]
|
||||
@@ -637,7 +625,7 @@ export class StructureIconsLayer implements Layer {
|
||||
this.createLevelSprite(unitView),
|
||||
this.createDotSprite(unitView),
|
||||
unitView.level(),
|
||||
unitView.type() === UnitType.Construction,
|
||||
unitView.isUnderConstruction(),
|
||||
);
|
||||
this.renders.push(render);
|
||||
this.computeNewLocation(render);
|
||||
|
||||
@@ -190,7 +190,7 @@ export class StructureLayer implements Layer {
|
||||
)) {
|
||||
this.paintCell(
|
||||
new Cell(this.game.x(tile), this.game.y(tile)),
|
||||
unit.type() === UnitType.Construction
|
||||
unit.isUnderConstruction()
|
||||
? underConstructionColor
|
||||
: unit.owner().territoryColor(),
|
||||
130,
|
||||
@@ -199,7 +199,7 @@ export class StructureLayer implements Layer {
|
||||
}
|
||||
|
||||
private handleUnitRendering(unit: UnitView) {
|
||||
const unitType = unit.constructionType() ?? unit.type();
|
||||
const unitType = unit.type();
|
||||
const iconType = unitType;
|
||||
if (!this.isUnitTypeSupported(unitType)) return;
|
||||
|
||||
@@ -208,7 +208,7 @@ export class StructureLayer implements Layer {
|
||||
let borderColor = unit.owner().borderColor();
|
||||
|
||||
// Handle cooldown states and special icons
|
||||
if (unit.type() === UnitType.Construction) {
|
||||
if (unit.isUnderConstruction()) {
|
||||
icon = this.unitIcons.get(iconType);
|
||||
borderColor = underConstructionColor;
|
||||
} else {
|
||||
@@ -247,7 +247,7 @@ export class StructureLayer implements Layer {
|
||||
unit: UnitView,
|
||||
) {
|
||||
let color = unit.owner().borderColor();
|
||||
if (unit.type() === UnitType.Construction) {
|
||||
if (unit.isUnderConstruction()) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
color = underConstructionColor;
|
||||
}
|
||||
|
||||
@@ -90,6 +90,11 @@ export class TerritoryLayer implements Layer {
|
||||
const unitUpdates = updates !== null ? updates[GameUpdateType.Unit] : [];
|
||||
unitUpdates.forEach((update) => {
|
||||
if (update.unitType === UnitType.DefensePost) {
|
||||
// Only update borders if the defense post is not under construction
|
||||
if (update.underConstruction) {
|
||||
return; // Skip barrier creation while under construction
|
||||
}
|
||||
|
||||
const tile = update.pos;
|
||||
this.game
|
||||
.bfs(tile, euclDistFN(tile, this.game.config().defensePostRange()))
|
||||
|
||||
@@ -103,16 +103,12 @@ export class UILayer implements Layer {
|
||||
}
|
||||
|
||||
onUnitEvent(unit: UnitView) {
|
||||
const underConst = unit.isUnderConstruction();
|
||||
if (underConst) {
|
||||
this.createLoadingBar(unit);
|
||||
return;
|
||||
}
|
||||
switch (unit.type()) {
|
||||
case UnitType.Construction: {
|
||||
const constructionType = unit.constructionType();
|
||||
if (constructionType === undefined) {
|
||||
// Skip units without construction type
|
||||
return;
|
||||
}
|
||||
this.createLoadingBar(unit);
|
||||
break;
|
||||
}
|
||||
case UnitType.Warship: {
|
||||
this.drawHealthBar(unit);
|
||||
break;
|
||||
@@ -318,22 +314,20 @@ export class UILayer implements Layer {
|
||||
if (!unit.isActive()) {
|
||||
return 1;
|
||||
}
|
||||
switch (unit.type()) {
|
||||
case UnitType.Construction: {
|
||||
const constructionType = unit.constructionType();
|
||||
if (constructionType === undefined) {
|
||||
return 1;
|
||||
}
|
||||
const constDuration =
|
||||
this.game.unitInfo(constructionType).constructionDuration;
|
||||
if (constDuration === undefined) {
|
||||
throw new Error("unit does not have constructionTime");
|
||||
}
|
||||
return (
|
||||
(this.game.ticks() - unit.createdAt()) /
|
||||
(constDuration === 0 ? 1 : constDuration)
|
||||
);
|
||||
const underConst = unit.isUnderConstruction();
|
||||
if (underConst) {
|
||||
const constDuration = this.game.unitInfo(
|
||||
unit.type(),
|
||||
).constructionDuration;
|
||||
if (constDuration === undefined) {
|
||||
throw new Error("unit does not have constructionTime");
|
||||
}
|
||||
return (
|
||||
(this.game.ticks() - unit.createdAt()) /
|
||||
(constDuration === 0 ? 1 : constDuration)
|
||||
);
|
||||
}
|
||||
switch (unit.type()) {
|
||||
case UnitType.MissileSilo:
|
||||
case UnitType.SAMLauncher:
|
||||
return !unit.markedForDeletion()
|
||||
|
||||
Reference in New Issue
Block a user