diff --git a/src/js/core/config.local.js b/src/js/core/config.local.js index b5aa3572..87aaaa14 100644 --- a/src/js/core/config.local.js +++ b/src/js/core/config.local.js @@ -9,7 +9,7 @@ export default { // noArtificialDelays: true, // ----------------------------------------------------------------------------------- // Disables writing of savegames, useful for testing the same savegame over and over - disableSavegameWrite: true, + // disableSavegameWrite: true, // ----------------------------------------------------------------------------------- // Shows bounds of all entities // showEntityBounds: true, @@ -33,7 +33,7 @@ export default { // allBuildingsUnlocked: true, // ----------------------------------------------------------------------------------- // Disables cost of blueprints - blueprintsNoCost: true, + // blueprintsNoCost: true, // ----------------------------------------------------------------------------------- // Disables cost of upgrades // upgradesNoCost: true, @@ -75,7 +75,7 @@ export default { // instantMiners: true, // ----------------------------------------------------------------------------------- // When using fastGameEnter, controls whether a new game is started or the last one is resumed - resumeGameOnFastEnter: true, + // resumeGameOnFastEnter: true, // ----------------------------------------------------------------------------------- // Special option used to render the trailer // renderForTrailer: true, diff --git a/src/js/core/read_write_proxy.js b/src/js/core/read_write_proxy.js index b2ff9051..7c96149b 100644 --- a/src/js/core/read_write_proxy.js +++ b/src/js/core/read_write_proxy.js @@ -169,7 +169,7 @@ export class ReadWriteProxy { // Check for errors during read .catch(err => { if (err === FILE_NOT_FOUND) { - logger.error("File not found, using default data"); + logger.log("File not found, using default data"); // File not found or unreadable, assume default file return Promise.resolve(null); diff --git a/src/js/game/entity_manager.js b/src/js/game/entity_manager.js index 4009c2d5..9c4a3dda 100644 --- a/src/js/game/entity_manager.js +++ b/src/js/game/entity_manager.js @@ -1,4 +1,3 @@ -import { arrayDeleteValue, newEmptyMap, fastArrayDeleteValue } from "../core/utils"; import { Component } from "./component"; import { GameRoot } from "./root"; import { Entity } from "./entity"; @@ -10,9 +9,6 @@ const logger = createLogger("entity_manager"); // Manages all entities -// NOTICE: We use arrayDeleteValue instead of fastArrayDeleteValue since that does not preserve the order -// This is slower but we need it for the street path generation - /** @typedef {number} EntityUid */ /** @typedef {string} ComponentId */ @@ -37,11 +33,6 @@ export class EntityManager extends BasicSerializableObject { /** @type {Array} */ this.destroyList = []; - // Store a map from componentid to entities - This is used by the game system - // for faster processing - ///** @type {Object.>} */ - //this.componentToEntity = newEmptyMap(); - // Store the next uid to use this.nextUid = 10000; } diff --git a/src/js/game/game_system_with_filter.js b/src/js/game/game_system_with_filter.js index d76fdcf3..32da0881 100644 --- a/src/js/game/game_system_with_filter.js +++ b/src/js/game/game_system_with_filter.js @@ -5,7 +5,6 @@ import { Entity } from "./entity"; import { GameRoot } from "./root"; import { GameSystem } from "./game_system"; -import { arrayDelete, arrayDeleteValue, fastArrayDelete } from "../core/utils"; export class GameSystemWithFilter extends GameSystem { /** @@ -71,7 +70,6 @@ export class GameSystemWithFilter extends GameSystem { for (let i = 0; i < this.requiredComponentIds.length; ++i) { if (!entity.components[this.requiredComponentIds[i]]) { // Entity is not interesting anymore - //arrayDeleteValue(this.allEntities, entity); this.allEntitiesArrayIsOutdated = this.allEntitiesSet.delete(entity); } } @@ -94,7 +92,6 @@ export class GameSystemWithFilter extends GameSystem { } refreshCaches() { - //this.allEntities.sort((a, b) => a.uid - b.uid); // Remove all entities which are queued for destroy if (this.entitiesQueuedToDelete.length > 0) { for (let i = this.entitiesQueuedToDelete.length - 1; i >= 0; --i) { @@ -121,11 +118,6 @@ export class GameSystemWithFilter extends GameSystem { internalRegisterEntity(entity) { this.allEntitiesSet.add(entity); this.allEntitiesArray.push(entity); - - // if (this.root.gameInitialized && !this.root.bulkOperationRunning) { - // // Sort entities by uid so behaviour is predictable - // this.allEntities.sort((a, b) => a.uid - b.uid); - // } } /** diff --git a/src/js/game/hud/hud.js b/src/js/game/hud/hud.js index 5725cea5..5f1bd226 100644 --- a/src/js/game/hud/hud.js +++ b/src/js/game/hud/hud.js @@ -44,7 +44,6 @@ import { HUDWireInfo } from "./parts/wire_info"; import { HUDLeverToggle } from "./parts/lever_toggle"; import { HUDLayerPreview } from "./parts/layer_preview"; import { HUDMinerHighlight } from "./parts/miner_highlight"; -import { Entity } from "../entity"; import { HUDBetaOverlay } from "./parts/beta_overlay"; import { HUDStandaloneAdvantages } from "./parts/standalone_advantages"; import { HUDCatMemes } from "./parts/cat_memes"; diff --git a/src/js/game/hud/parts/mass_selector.js b/src/js/game/hud/parts/mass_selector.js index 87ce453c..72f4ca3e 100644 --- a/src/js/game/hud/parts/mass_selector.js +++ b/src/js/game/hud/parts/mass_selector.js @@ -1,19 +1,17 @@ -import { BaseHUDPart } from "../base_hud_part"; -import { Vector } from "../../../core/vector"; -import { STOP_PROPAGATION } from "../../../core/signal"; -import { DrawParameters } from "../../../core/draw_parameters"; -import { Entity } from "../../entity"; -import { Loader } from "../../../core/loader"; import { globalConfig } from "../../../core/config"; -import { makeDiv, formatBigNumber, formatBigNumberFull, dirInterval } from "../../../core/utils"; -import { DynamicDomAttach } from "../dynamic_dom_attach"; +import { DrawParameters } from "../../../core/draw_parameters"; import { createLogger } from "../../../core/logging"; -import { enumMouseButton } from "../../camera"; +import { STOP_PROPAGATION } from "../../../core/signal"; +import { formatBigNumberFull } from "../../../core/utils"; +import { Vector } from "../../../core/vector"; import { T } from "../../../translations"; +import { Blueprint } from "../../blueprint"; +import { enumMouseButton } from "../../camera"; +import { Entity } from "../../entity"; import { KEYMAPPINGS } from "../../key_action_mapper"; import { THEME } from "../../theme"; import { enumHubGoalRewards } from "../../tutorial_goals"; -import { Blueprint } from "../../blueprint"; +import { BaseHUDPart } from "../base_hud_part"; const logger = createLogger("hud/mass_selector"); @@ -52,16 +50,6 @@ export class HUDMassSelector extends BaseHUDPart { this.selectedEntities.clear(); } - // getUidArray() { - // if (this.selectedEntities.size <= 0) return []; - // const uids = []; - // const arr = [...this.selectedEntities.values()]; - // for (let i = arr.length - 1; i >= 0; --i) { - // uids.push(arr[i].uid); - // } - // return uids; - // } - /** * Handles the destroy callback and makes sure we clean our list * @param {Entity} entity @@ -115,7 +103,6 @@ export class HUDMassSelector extends BaseHUDPart { /** * @type {Map} */ - //const mapUidToEntity = this.root.entityMgr.getFrozenUidSearchMap(); this.root.logic.performBulkOperation(() => { const arr = [...this.selectedEntities.values()]; @@ -138,8 +125,8 @@ export class HUDMassSelector extends BaseHUDPart { ); return; } - const uids = []; + // @ts-ignore this.root.hud.signals.buildingsSelectedForCopy.dispatch([...this.selectedEntities.values()]); this.selectedEntities.clear(); this.root.soundProxy.playUiClick(); diff --git a/src/js/game/systems/hub.js b/src/js/game/systems/hub.js index a98eabc9..748a4f7c 100644 --- a/src/js/game/systems/hub.js +++ b/src/js/game/systems/hub.js @@ -1,185 +1,196 @@ -import { globalConfig } from "../../core/config"; -import { smoothenDpi } from "../../core/dpi_manager"; -import { DrawParameters } from "../../core/draw_parameters"; -import { drawSpriteClipped } from "../../core/draw_utils"; -import { Loader } from "../../core/loader"; -import { Rectangle } from "../../core/rectangle"; -import { ORIGINAL_SPRITE_SCALE } from "../../core/sprites"; -import { formatBigNumber } from "../../core/utils"; -import { T } from "../../translations"; -import { HubComponent } from "../components/hub"; -import { Entity } from "../entity"; -import { GameSystemWithFilter } from "../game_system_with_filter"; - -const HUB_SIZE_TILES = 4; -const HUB_SIZE_PIXELS = HUB_SIZE_TILES * globalConfig.tileSize; - -export class HubSystem extends GameSystemWithFilter { - constructor(root) { - super(root, [HubComponent]); - - this.hubSprite = Loader.getSprite("sprites/buildings/hub.png"); - } - - /** - * @param {DrawParameters} parameters - */ - draw(parameters) { - for (let i = this.allEntitiesArray.length - 1; i >= 0; --i) { - const entity = this.allEntitiesArray[i]; - this.drawEntity(parameters, entity); - } - } - - update() { - for (let i = this.allEntitiesArray.length - 1; i >= 0; --i) { - const entity = this.allEntitiesArray[i]; - const pinsComp = entity.components.WiredPins; - pinsComp.slots[0].value = this.root.shapeDefinitionMgr.getShapeItemFromDefinition( - this.root.hubGoals.currentGoal.definition - ); - } - } - /** - * - * @param {HTMLCanvasElement} canvas - * @param {CanvasRenderingContext2D} context - * @param {number} w - * @param {number} h - * @param {number} dpi - */ - redrawHubBaseTexture(canvas, context, w, h, dpi) { - // This method is quite ugly, please ignore it! - - context.scale(dpi, dpi); - - const parameters = new DrawParameters({ - context, - visibleRect: new Rectangle(0, 0, w, h), - desiredAtlasScale: ORIGINAL_SPRITE_SCALE, - zoomLevel: dpi * 0.75, - root: this.root, - }); - - context.clearRect(0, 0, w, h); - - this.hubSprite.draw(context, 0, 0, w, h); - - const definition = this.root.hubGoals.currentGoal.definition; - definition.drawCentered(45, 58, parameters, 36); - - const goals = this.root.hubGoals.currentGoal; - - const textOffsetX = 70; - const textOffsetY = 61; - - if (goals.throughputOnly) { - // Throughput - const deliveredText = T.ingame.statistics.shapesDisplayUnits.second.replace( - "", - formatBigNumber(goals.required) - ); - - context.font = "bold 12px GameFont"; - context.fillStyle = "#64666e"; - context.textAlign = "left"; - context.fillText(deliveredText, textOffsetX, textOffsetY); - } else { - // Deliver count - const delivered = this.root.hubGoals.getCurrentGoalDelivered(); - const deliveredText = "" + formatBigNumber(delivered); - - if (delivered > 9999) { - context.font = "bold 16px GameFont"; - } else if (delivered > 999) { - context.font = "bold 20px GameFont"; - } else { - context.font = "bold 25px GameFont"; - } - context.fillStyle = "#64666e"; - context.textAlign = "left"; - context.fillText(deliveredText, textOffsetX, textOffsetY); - - // Required - context.font = "13px GameFont"; - context.fillStyle = "#a4a6b0"; - context.fillText("/ " + formatBigNumber(goals.required), textOffsetX, textOffsetY + 13); - - // Reward - const rewardText = T.storyRewards[goals.reward].title.toUpperCase(); - if (rewardText.length > 12) { - context.font = "bold 8px GameFont"; - } else { - context.font = "bold 10px GameFont"; - } - context.fillStyle = "#fd0752"; - context.textAlign = "center"; - - context.fillText(rewardText, HUB_SIZE_PIXELS / 2, 105); - - // Level "8" - context.font = "bold 10px GameFont"; - context.fillStyle = "#fff"; - context.fillText("" + this.root.hubGoals.level, 27, 32); - - // "LVL" - context.textAlign = "center"; - context.fillStyle = "#fff"; - context.font = "bold 6px GameFont"; - context.fillText(T.buildings.hub.levelShortcut, 27, 22); - - // "Deliver" - context.fillStyle = "#64666e"; - context.font = "bold 10px GameFont"; - context.fillText(T.buildings.hub.deliver.toUpperCase(), HUB_SIZE_PIXELS / 2, 30); - - // "To unlock" - const unlockText = T.buildings.hub.toUnlock.toUpperCase(); - if (unlockText.length > 15) { - context.font = "bold 8px GameFont"; - } else { - context.font = "bold 10px GameFont"; - } - context.fillText(T.buildings.hub.toUnlock.toUpperCase(), HUB_SIZE_PIXELS / 2, 92); - - context.textAlign = "left"; - } - } - - /** - * @param {DrawParameters} parameters - * @param {Entity} entity - */ - drawEntity(parameters, entity) { - const staticComp = entity.components.StaticMapEntity; - if (!staticComp.shouldBeDrawn(parameters)) { - return; - } - - // Deliver count - const delivered = this.root.hubGoals.getCurrentGoalDelivered(); - const deliveredText = "" + formatBigNumber(delivered); - - const dpi = smoothenDpi(globalConfig.shapesSharpness * parameters.zoomLevel); - const canvas = parameters.root.buffers.getForKey({ - key: "hub", - subKey: dpi + "/" + this.root.hubGoals.level + "/" + deliveredText, - w: globalConfig.tileSize * 4, - h: globalConfig.tileSize * 4, - dpi, - redrawMethod: this.redrawHubBaseTexture.bind(this), - }); - - const extrude = 8; - drawSpriteClipped({ - parameters, - sprite: canvas, - x: staticComp.origin.x * globalConfig.tileSize - extrude, - y: staticComp.origin.y * globalConfig.tileSize - extrude, - w: HUB_SIZE_PIXELS + 2 * extrude, - h: HUB_SIZE_PIXELS + 2 * extrude, - originalW: HUB_SIZE_PIXELS * dpi, - originalH: HUB_SIZE_PIXELS * dpi, - }); - } -} +import { globalConfig } from "../../core/config"; +import { smoothenDpi } from "../../core/dpi_manager"; +import { DrawParameters } from "../../core/draw_parameters"; +import { drawSpriteClipped } from "../../core/draw_utils"; +import { Loader } from "../../core/loader"; +import { Rectangle } from "../../core/rectangle"; +import { ORIGINAL_SPRITE_SCALE } from "../../core/sprites"; +import { formatBigNumber } from "../../core/utils"; +import { T } from "../../translations"; +import { HubComponent } from "../components/hub"; +import { Entity } from "../entity"; +import { GameSystemWithFilter } from "../game_system_with_filter"; + +const HUB_SIZE_TILES = 4; +const HUB_SIZE_PIXELS = HUB_SIZE_TILES * globalConfig.tileSize; + +export class HubSystem extends GameSystemWithFilter { + constructor(root) { + super(root, [HubComponent]); + + this.hubSprite = Loader.getSprite("sprites/buildings/hub.png"); + } + + /** + * @param {DrawParameters} parameters + */ + draw(parameters) { + for (let i = this.allEntitiesArray.length - 1; i >= 0; --i) { + this.drawEntity(parameters, this.allEntitiesArray[i]); + } + } + + update() { + for (let i = 0; i < this.allEntitiesArray.length; ++i) { + // Set hub goal + const entity = this.allEntitiesArray[i]; + const pinsComp = entity.components.WiredPins; + pinsComp.slots[0].value = this.root.shapeDefinitionMgr.getShapeItemFromDefinition( + this.root.hubGoals.currentGoal.definition + ); + } + } + /** + * + * @param {HTMLCanvasElement} canvas + * @param {CanvasRenderingContext2D} context + * @param {number} w + * @param {number} h + * @param {number} dpi + */ + redrawHubBaseTexture(canvas, context, w, h, dpi) { + // This method is quite ugly, please ignore it! + + context.scale(dpi, dpi); + + const parameters = new DrawParameters({ + context, + visibleRect: new Rectangle(0, 0, w, h), + desiredAtlasScale: ORIGINAL_SPRITE_SCALE, + zoomLevel: dpi * 0.75, + root: this.root, + }); + + context.clearRect(0, 0, w, h); + + this.hubSprite.draw(context, 0, 0, w, h); + + if (this.root.hubGoals.isEndOfDemoReached()) { + // End of demo + context.font = "bold 12px GameFont"; + context.fillStyle = "#fd0752"; + context.textAlign = "center"; + context.fillText(T.buildings.hub.endOfDemo.toUpperCase(), w / 2, h / 2 + 6); + context.textAlign = "left"; + + return; + } + + const definition = this.root.hubGoals.currentGoal.definition; + definition.drawCentered(45, 58, parameters, 36); + + const goals = this.root.hubGoals.currentGoal; + + const textOffsetX = 70; + const textOffsetY = 61; + + if (goals.throughputOnly) { + // Throughput + const deliveredText = T.ingame.statistics.shapesDisplayUnits.second.replace( + "", + formatBigNumber(goals.required) + ); + + context.font = "bold 12px GameFont"; + context.fillStyle = "#64666e"; + context.textAlign = "left"; + context.fillText(deliveredText, textOffsetX, textOffsetY); + } else { + // Deliver count + const delivered = this.root.hubGoals.getCurrentGoalDelivered(); + const deliveredText = "" + formatBigNumber(delivered); + + if (delivered > 9999) { + context.font = "bold 16px GameFont"; + } else if (delivered > 999) { + context.font = "bold 20px GameFont"; + } else { + context.font = "bold 25px GameFont"; + } + context.fillStyle = "#64666e"; + context.textAlign = "left"; + context.fillText(deliveredText, textOffsetX, textOffsetY); + + // Required + context.font = "13px GameFont"; + context.fillStyle = "#a4a6b0"; + context.fillText("/ " + formatBigNumber(goals.required), textOffsetX, textOffsetY + 13); + } + + // Reward + const rewardText = T.storyRewards[goals.reward].title.toUpperCase(); + if (rewardText.length > 12) { + context.font = "bold 8px GameFont"; + } else { + context.font = "bold 10px GameFont"; + } + context.fillStyle = "#fd0752"; + context.textAlign = "center"; + + context.fillText(rewardText, HUB_SIZE_PIXELS / 2, 105); + + // Level "8" + context.font = "bold 10px GameFont"; + context.fillStyle = "#fff"; + context.fillText("" + this.root.hubGoals.level, 27, 32); + + // "LVL" + context.textAlign = "center"; + context.fillStyle = "#fff"; + context.font = "bold 6px GameFont"; + context.fillText(T.buildings.hub.levelShortcut, 27, 22); + + // "Deliver" + context.fillStyle = "#64666e"; + context.font = "bold 10px GameFont"; + context.fillText(T.buildings.hub.deliver.toUpperCase(), HUB_SIZE_PIXELS / 2, 30); + + // "To unlock" + const unlockText = T.buildings.hub.toUnlock.toUpperCase(); + if (unlockText.length > 15) { + context.font = "bold 8px GameFont"; + } else { + context.font = "bold 10px GameFont"; + } + context.fillText(T.buildings.hub.toUnlock.toUpperCase(), HUB_SIZE_PIXELS / 2, 92); + + context.textAlign = "left"; + } + + /** + * @param {DrawParameters} parameters + * @param {Entity} entity + */ + drawEntity(parameters, entity) { + const staticComp = entity.components.StaticMapEntity; + if (!staticComp.shouldBeDrawn(parameters)) { + return; + } + + // Deliver count + const delivered = this.root.hubGoals.getCurrentGoalDelivered(); + const deliveredText = "" + formatBigNumber(delivered); + + const dpi = smoothenDpi(globalConfig.shapesSharpness * parameters.zoomLevel); + const canvas = parameters.root.buffers.getForKey({ + key: "hub", + subKey: dpi + "/" + this.root.hubGoals.level + "/" + deliveredText, + w: globalConfig.tileSize * 4, + h: globalConfig.tileSize * 4, + dpi, + redrawMethod: this.redrawHubBaseTexture.bind(this), + }); + + const extrude = 8; + drawSpriteClipped({ + parameters, + sprite: canvas, + x: staticComp.origin.x * globalConfig.tileSize - extrude, + y: staticComp.origin.y * globalConfig.tileSize - extrude, + w: HUB_SIZE_PIXELS + 2 * extrude, + h: HUB_SIZE_PIXELS + 2 * extrude, + originalW: HUB_SIZE_PIXELS * dpi, + originalH: HUB_SIZE_PIXELS * dpi, + }); + } +} diff --git a/src/js/game/systems/storage.js b/src/js/game/systems/storage.js index 69eb5a3f..4b300ea0 100644 --- a/src/js/game/systems/storage.js +++ b/src/js/game/systems/storage.js @@ -1,101 +1,101 @@ -import { GameSystemWithFilter } from "../game_system_with_filter"; -import { StorageComponent } from "../components/storage"; -import { DrawParameters } from "../../core/draw_parameters"; -import { formatBigNumber, lerp } from "../../core/utils"; -import { Loader } from "../../core/loader"; -import { BOOL_TRUE_SINGLETON, BOOL_FALSE_SINGLETON } from "../items/boolean_item"; -import { MapChunkView } from "../map_chunk_view"; - -export class StorageSystem extends GameSystemWithFilter { - constructor(root) { - super(root, [StorageComponent]); - - this.storageOverlaySprite = Loader.getSprite("sprites/misc/storage_overlay.png"); - - /** - * Stores which uids were already drawn to avoid drawing entities twice - * @type {Set} - */ - this.drawnUids = new Set(); - - this.root.signals.gameFrameStarted.add(this.clearDrawnUids, this); - } - - clearDrawnUids() { - this.drawnUids.clear(); - } - - update() { - for (let i = this.allEntitiesArray.length - 1; i >= 0; --i) { - const entity = this.allEntitiesArray[i]; - const storageComp = entity.components.Storage; - const pinsComp = entity.components.WiredPins; - - // Eject from storage - if (storageComp.storedItem && storageComp.storedCount > 0) { - const ejectorComp = entity.components.ItemEjector; - - const nextSlot = ejectorComp.getFirstFreeSlot(); - if (nextSlot !== null) { - if (ejectorComp.tryEject(nextSlot, storageComp.storedItem)) { - storageComp.storedCount--; - - if (storageComp.storedCount === 0) { - storageComp.storedItem = null; - } - } - } - } - - let targetAlpha = storageComp.storedCount > 0 ? 1 : 0; - storageComp.overlayOpacity = lerp(storageComp.overlayOpacity, targetAlpha, 0.05); - - pinsComp.slots[0].value = storageComp.storedItem; - pinsComp.slots[1].value = storageComp.getIsFull() ? BOOL_TRUE_SINGLETON : BOOL_FALSE_SINGLETON; - } - } - - /** - * @param {DrawParameters} parameters - * @param {MapChunkView} chunk - */ - drawChunk(parameters, chunk) { - const contents = chunk.containedEntitiesByLayer.regular; - for (let i = 0; i < contents.length; ++i) { - const entity = contents[i]; - const storageComp = entity.components.Storage; - if (!storageComp) { - continue; - } - - const storedItem = storageComp.storedItem; - if (!storedItem) { - continue; - } - - if (this.drawnUids.has(entity.uid)) { - continue; - } - - this.drawnUids.add(entity.uid); - - const staticComp = entity.components.StaticMapEntity; - - const context = parameters.context; - context.globalAlpha = storageComp.overlayOpacity; - const center = staticComp.getTileSpaceBounds().getCenter().toWorldSpace(); - storedItem.drawItemCenteredClipped(center.x, center.y, parameters, 30); - - this.storageOverlaySprite.drawCached(parameters, center.x - 15, center.y + 15, 30, 15); - - if (parameters.visibleRect.containsCircle(center.x, center.y + 25, 20)) { - context.font = "bold 10px GameFont"; - context.textAlign = "center"; - context.fillStyle = "#64666e"; - context.fillText(formatBigNumber(storageComp.storedCount), center.x, center.y + 25.5); - context.textAlign = "left"; - } - context.globalAlpha = 1; - } - } -} +import { GameSystemWithFilter } from "../game_system_with_filter"; +import { StorageComponent } from "../components/storage"; +import { DrawParameters } from "../../core/draw_parameters"; +import { formatBigNumber, lerp } from "../../core/utils"; +import { Loader } from "../../core/loader"; +import { BOOL_TRUE_SINGLETON, BOOL_FALSE_SINGLETON } from "../items/boolean_item"; +import { MapChunkView } from "../map_chunk_view"; + +export class StorageSystem extends GameSystemWithFilter { + constructor(root) { + super(root, [StorageComponent]); + + this.storageOverlaySprite = Loader.getSprite("sprites/misc/storage_overlay.png"); + + /** + * Stores which uids were already drawn to avoid drawing entities twice + * @type {Set} + */ + this.drawnUids = new Set(); + + this.root.signals.gameFrameStarted.add(this.clearDrawnUids, this); + } + + clearDrawnUids() { + this.drawnUids.clear(); + } + + update() { + for (let i = this.allEntitiesArray.length - 1; i >= 0; --i) { + const entity = this.allEntitiesArray[i]; + const storageComp = entity.components.Storage; + const pinsComp = entity.components.WiredPins; + + // Eject from storage + if (storageComp.storedItem && storageComp.storedCount > 0) { + const ejectorComp = entity.components.ItemEjector; + + const nextSlot = ejectorComp.getFirstFreeSlot(); + if (nextSlot !== null) { + if (ejectorComp.tryEject(nextSlot, storageComp.storedItem)) { + storageComp.storedCount--; + + if (storageComp.storedCount === 0) { + storageComp.storedItem = null; + } + } + } + } + + let targetAlpha = storageComp.storedCount > 0 ? 1 : 0; + storageComp.overlayOpacity = lerp(storageComp.overlayOpacity, targetAlpha, 0.05); + + pinsComp.slots[0].value = storageComp.storedItem; + pinsComp.slots[1].value = storageComp.getIsFull() ? BOOL_TRUE_SINGLETON : BOOL_FALSE_SINGLETON; + } + } + + /** + * @param {DrawParameters} parameters + * @param {MapChunkView} chunk + */ + drawChunk(parameters, chunk) { + const contents = chunk.containedEntitiesByLayer.regular; + for (let i = 0; i < contents.length; ++i) { + const entity = contents[i]; + const storageComp = entity.components.Storage; + if (!storageComp) { + continue; + } + + const storedItem = storageComp.storedItem; + if (!storedItem) { + continue; + } + + if (this.drawnUids.has(entity.uid)) { + continue; + } + + this.drawnUids.add(entity.uid); + + const staticComp = entity.components.StaticMapEntity; + + const context = parameters.context; + context.globalAlpha = storageComp.overlayOpacity; + const center = staticComp.getTileSpaceBounds().getCenter().toWorldSpace(); + storedItem.drawItemCenteredClipped(center.x, center.y, parameters, 30); + + this.storageOverlaySprite.drawCached(parameters, center.x - 15, center.y + 15, 30, 15); + + if (parameters.visibleRect.containsCircle(center.x, center.y + 25, 20)) { + context.font = "bold 10px GameFont"; + context.textAlign = "center"; + context.fillStyle = "#64666e"; + context.fillText(formatBigNumber(storageComp.storedCount), center.x, center.y + 25.5); + context.textAlign = "left"; + } + context.globalAlpha = 1; + } + } +} diff --git a/src/js/savegame/savegame.js b/src/js/savegame/savegame.js index 1316cb91..8d2d9819 100644 --- a/src/js/savegame/savegame.js +++ b/src/js/savegame/savegame.js @@ -169,10 +169,13 @@ export class Savegame extends ReadWriteProxy { * Returns if this game has a serialized game dump */ hasGameDump() { - return ( - !!this.currentData.dump && - (this.currentData.dump.entities.length > 0 || this.currentData.dump.entities.size > 0) - ); + if(!this.currentData.dump) return false; + if(Array.isArray(this.currentData.dump.entities)) { + return this.currentData.dump.entities.length; + } + else { + return this.currentData.dump.entities.size; + } } /** diff --git a/src/js/savegame/savegame_serializer.js b/src/js/savegame/savegame_serializer.js index 11e1e69c..581eaf6b 100644 --- a/src/js/savegame/savegame_serializer.js +++ b/src/js/savegame/savegame_serializer.js @@ -68,7 +68,7 @@ export class SavegameSerializer { // Check for duplicate UIDS const entities = [...savegame.entities.values()]; - for (let i = 0; i < entities.length; ++i) { + for (let i = entities.length - 1; i >= 0; --i) { /** @type {Entity} */ const entity = entities[i]; diff --git a/src/js/tslint.json b/src/js/tslint.json index c89e7770..4d554235 100644 --- a/src/js/tslint.json +++ b/src/js/tslint.json @@ -10,7 +10,8 @@ "no-console": false, "forin": false, "no-empty": false, - "space-before-function-paren": ["always"] + "space-before-function-paren": ["always"], + "no-unused-declaration": true }, "rulesDirectory": [] }