mirror of
https://github.com/openfrontio/OpenFrontIO.git
synced 2026-06-21 09:30:22 +00:00
Redraw stacked buildings sprites (#1170)
## Description: When buildings are stacked on each other, the buildings under are not redrawn when the stacked building is destroyed. A simple outer range + sprite radius check triggers a touch which redraws the buildings. Sprite radius is set to 16 (dont forget to change it if it ever changes) ### Before:  ### After:  ## 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 - [x] I understand that submitting code with bugs that could have been caught through manual testing blocks releases and new features for all contributors ## Please put your Discord username so you can be contacted if a bug or regression is found: Vivacious Box
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
import {
|
||||
Execution,
|
||||
Game,
|
||||
isStructureType,
|
||||
MessageType,
|
||||
Player,
|
||||
TerraNullius,
|
||||
@@ -12,6 +13,8 @@ import { ParabolaPathFinder } from "../pathfinding/PathFinding";
|
||||
import { PseudoRandom } from "../PseudoRandom";
|
||||
import { NukeType } from "../StatsSchemas";
|
||||
|
||||
const SPRITE_RADIUS = 16;
|
||||
|
||||
export class NukeExecution implements Execution {
|
||||
private active = true;
|
||||
private mg: Game;
|
||||
@@ -221,6 +224,8 @@ export class NukeExecution implements Execution {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.redrawBuildings(magnitude.outer + SPRITE_RADIUS);
|
||||
this.active = false;
|
||||
this.nuke.setReachedTarget();
|
||||
this.nuke.delete(false);
|
||||
@@ -231,6 +236,19 @@ export class NukeExecution implements Execution {
|
||||
.bombLand(this.player, this.target(), this.nuke.type() as NukeType);
|
||||
}
|
||||
|
||||
private redrawBuildings(range: number) {
|
||||
const rangeSquared = range * range;
|
||||
for (const unit of this.mg.units()) {
|
||||
if (isStructureType(unit.type())) {
|
||||
if (
|
||||
this.mg.euclideanDistSquared(this.dst, unit.tile()) < rangeSquared
|
||||
) {
|
||||
unit.touch();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
owner(): Player {
|
||||
return this.player;
|
||||
}
|
||||
|
||||
@@ -151,6 +151,19 @@ export enum UnitType {
|
||||
Construction = "Construction",
|
||||
}
|
||||
|
||||
const _structureTypes: ReadonlySet<UnitType> = new Set([
|
||||
UnitType.City,
|
||||
UnitType.Construction,
|
||||
UnitType.DefensePost,
|
||||
UnitType.SAMLauncher,
|
||||
UnitType.MissileSilo,
|
||||
UnitType.Port,
|
||||
]);
|
||||
|
||||
export function isStructureType(type: UnitType): boolean {
|
||||
return _structureTypes.has(type);
|
||||
}
|
||||
|
||||
export interface OwnerComp {
|
||||
owner: Player;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
import { NukeExecution } from "../../../src/core/execution/NukeExecution";
|
||||
import {
|
||||
Game,
|
||||
Player,
|
||||
PlayerInfo,
|
||||
PlayerType,
|
||||
UnitType,
|
||||
} from "../../../src/core/game/Game";
|
||||
import { setup } from "../../util/Setup";
|
||||
import { TestConfig } from "../../util/TestConfig";
|
||||
import { executeTicks } from "../../util/utils";
|
||||
|
||||
let game: Game;
|
||||
let player: Player;
|
||||
|
||||
describe("NukeExecution", () => {
|
||||
beforeEach(async () => {
|
||||
game = await setup("BigPlains", { infiniteGold: true, instantBuild: true });
|
||||
|
||||
(game.config() as TestConfig).nukeMagnitudes = jest.fn(() => ({
|
||||
inner: 10,
|
||||
outer: 10,
|
||||
}));
|
||||
const player_info = new PlayerInfo(
|
||||
"us",
|
||||
"player_id",
|
||||
PlayerType.Human,
|
||||
null,
|
||||
"player_id",
|
||||
);
|
||||
game.addPlayer(player_info);
|
||||
|
||||
while (game.inSpawnPhase()) {
|
||||
game.executeNextTick();
|
||||
}
|
||||
|
||||
player = game.player("player_id");
|
||||
});
|
||||
|
||||
test("nuke should destroy buildings and redraw out of range buildings", async () => {
|
||||
// Build a city at (1,1)
|
||||
player.buildUnit(UnitType.City, game.ref(1, 1), {});
|
||||
// Build a missile silo in range
|
||||
player.buildUnit(UnitType.MissileSilo, game.ref(1, 10), {});
|
||||
// Build a SAM out of range
|
||||
const sam = player.buildUnit(UnitType.SAMLauncher, game.ref(1, 11), {});
|
||||
sam.touch = jest.fn();
|
||||
// Build a Defense post out of range AND out of redraw range
|
||||
const defensePost = player.buildUnit(
|
||||
UnitType.DefensePost,
|
||||
game.ref(1, 27),
|
||||
{},
|
||||
);
|
||||
defensePost.touch = jest.fn();
|
||||
// Add a nuke execution targeting the city
|
||||
const nukeExec = new NukeExecution(
|
||||
UnitType.AtomBomb,
|
||||
player,
|
||||
game.ref(1, 1),
|
||||
game.ref(1, 2),
|
||||
);
|
||||
game.addExecution(nukeExec);
|
||||
// Run enough ticks for the nuke to detonate
|
||||
executeTicks(game, 10);
|
||||
// The city and silo should be destroyed
|
||||
expect(player.units(UnitType.City)).toHaveLength(0);
|
||||
expect(player.units(UnitType.MissileSilo)).toHaveLength(0);
|
||||
expect(player.units(UnitType.SAMLauncher)).toHaveLength(1);
|
||||
expect(sam.touch).toHaveBeenCalled();
|
||||
expect(defensePost.touch).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user