diff --git a/gulp/bundle-loader.js b/gulp/bundle-loader.js index d8bb8c24..16db26fa 100644 --- a/gulp/bundle-loader.js +++ b/gulp/bundle-loader.js @@ -54,8 +54,11 @@ document.documentElement.appendChild(element); } - window.addEventListener("error", errorHandler); - window.addEventListener("unhandledrejection", errorHandler); + + if (window.location.host.indexOf("localhost") < 0) { + window.addEventListener("error", errorHandler); + window.addEventListener("unhandledrejection", errorHandler); + } function makeJsTag(src, integrity) { var script = document.createElement("script"); diff --git a/res/ui/building_icons/constant_producer.png b/res/ui/building_icons/constant_producer.png index 887a3ae6..f7ac8afa 100644 Binary files a/res/ui/building_icons/constant_producer.png and b/res/ui/building_icons/constant_producer.png differ diff --git a/res/ui/building_icons/goal_acceptor.png b/res/ui/building_icons/goal_acceptor.png index 81451757..9087c155 100644 Binary files a/res/ui/building_icons/goal_acceptor.png and b/res/ui/building_icons/goal_acceptor.png differ diff --git a/res/ui/languages/he.svg b/res/ui/languages/he.svg new file mode 100644 index 00000000..aaa64e98 --- /dev/null +++ b/res/ui/languages/he.svg @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/res_raw/sprites/buildings/goal_acceptor.png b/res_raw/sprites/buildings/goal_acceptor.png index 9e5f0808..2ebf879a 100644 Binary files a/res_raw/sprites/buildings/goal_acceptor.png and b/res_raw/sprites/buildings/goal_acceptor.png differ diff --git a/src/css/ingame_hud/mode_menu_back.scss b/src/css/ingame_hud/mode_menu_back.scss index 56a489db..9f0a6c81 100644 --- a/src/css/ingame_hud/mode_menu_back.scss +++ b/src/css/ingame_hud/mode_menu_back.scss @@ -11,7 +11,6 @@ > .button { @include PlainText; - @include IncreasedClickArea(0px); pointer-events: all; cursor: pointer; position: relative; @@ -20,6 +19,8 @@ transition-property: opacity, transform; text-transform: uppercase; @include PlainText; + @include S(width, 30px); + @include S(height, 30px); opacity: 1; &:hover { @@ -30,11 +31,9 @@ transform: scale(0.95) !important; } - @include S(padding-left, 25px); - & { /* @load-async */ - background: uiResource("icons/state_back_button.png") left center / D(15px) no-repeat; + background: uiResource("icons/state_back_button.png") center center / D(15px) no-repeat; } } } diff --git a/src/css/ingame_hud/mode_menu_next.scss b/src/css/ingame_hud/mode_menu_next.scss index 7c0cfb4b..2deb4965 100644 --- a/src/css/ingame_hud/mode_menu_next.scss +++ b/src/css/ingame_hud/mode_menu_next.scss @@ -1,6 +1,6 @@ #ingame_HUD_ModeMenuNext { position: absolute; - @include S(top, 10px); + @include S(top, 15px); @include S(right, 10px); display: flex; diff --git a/src/css/ingame_hud/puzzle_dlc_logo.scss b/src/css/ingame_hud/puzzle_dlc_logo.scss index 921e853c..fc3b4c76 100644 --- a/src/css/ingame_hud/puzzle_dlc_logo.scss +++ b/src/css/ingame_hud/puzzle_dlc_logo.scss @@ -2,8 +2,8 @@ position: absolute; @include S(width, 150px); @include S(height, 40px); - @include S(bottom, 10px); - @include S(right, 15px); + @include S(left, 50px); + @include S(top, 10px); & { /* @load-async */ diff --git a/src/css/ingame_hud/puzzle_editor_controls.scss b/src/css/ingame_hud/puzzle_editor_controls.scss new file mode 100644 index 00000000..eb402aa2 --- /dev/null +++ b/src/css/ingame_hud/puzzle_editor_controls.scss @@ -0,0 +1,26 @@ +#ingame_HUD_PuzzleEditorControls { + position: absolute; + + @include S(top, 70px); + @include S(left, 10px); + + display: flex; + flex-direction: column; + @include SuperDuperSmallText; + @include S(width, 200px); + + > span { + @include S(margin-bottom, 10px); + } +} + +#ingame_HUD_PuzzleEditorTitle { + position: absolute; + + @include S(top, 23px); + left: 50%; + transform: translateX(-50%); + text-transform: uppercase; + @include Heading; + text-align: center; +} diff --git a/src/css/main.scss b/src/css/main.scss index 89ebbb10..d703663c 100644 --- a/src/css/main.scss +++ b/src/css/main.scss @@ -61,6 +61,7 @@ @import "ingame_hud/mode_menu"; @import "ingame_hud/mode_settings"; @import "ingame_hud/puzzle_dlc_logo"; +@import "ingame_hud/puzzle_editor_controls"; // prettier-ignore $elements: @@ -80,6 +81,8 @@ ingame_HUD_GameMenu, ingame_HUD_KeybindingOverlay, ingame_HUD_ModeMenuBack, ingame_HUD_ModeMenuNext, +ingame_HUD_PuzzleEditorControls, +ingame_HUD_PuzzleEditorTitle, ingame_HUD_ModeMenu, ingame_HUD_ModeSettings, ingame_HUD_Notifications, diff --git a/src/css/resources.scss b/src/css/resources.scss index 769829f6..158db23d 100644 --- a/src/css/resources.scss +++ b/src/css/resources.scss @@ -68,7 +68,7 @@ $icons: notification_saved, notification_success, notification_upgrade; } $languages: en, de, cs, da, et, es-419, fr, it, pt-BR, sv, tr, el, ru, uk, zh-TW, zh-CN, nb, mt-MT, ar, nl, vi, - th, hu, pl, ja, kor, no, pt-PT, fi, ro; + th, hu, pl, ja, kor, no, pt-PT, fi, ro, he; @each $language in $languages { [data-languageicon="#{$language}"] { diff --git a/src/css/states/puzzle_menu.scss b/src/css/states/puzzle_menu.scss index e3c139a8..75541d8d 100644 --- a/src/css/states/puzzle_menu.scss +++ b/src/css/states/puzzle_menu.scss @@ -124,16 +124,17 @@ @include SuperSmallText; grid-column: 2 / 3; grid-row: 3 / 4; - color: $accentColorDark; + color: #444; align-self: end; justify-self: end; font-weight: bold; @include S(padding-right, 12px); + opacity: 0.89; & { /* @load-async */ background: uiResource("icons/puzzle_upvotes.png") calc(100% - #{D(2px)}) #{D( - 3.3px + 3.5px )} / #{D(8px)} #{D(8px)} no-repeat; } } diff --git a/src/js/core/animation_frame.js b/src/js/core/animation_frame.js index eeefb4b0..6aa629a5 100644 --- a/src/js/core/animation_frame.js +++ b/src/js/core/animation_frame.js @@ -51,9 +51,12 @@ export class AnimationFrame { dt = resetDtMs; } - this.frameEmitted.dispatch(dt); + try { + this.frameEmitted.dispatch(dt); + } catch (ex) { + console.error(ex); + } this.lastTime = time; - window.requestAnimationFrame(this.boundMethod); } } diff --git a/src/js/core/error_handler.js b/src/js/core/error_handler.js index 686e4e4e..c149ba76 100644 --- a/src/js/core/error_handler.js +++ b/src/js/core/error_handler.js @@ -123,4 +123,6 @@ function catchErrors(message, source, lineno, colno, error) { return true; } -window.onerror = catchErrors; +if (!G_IS_DEV) { + window.onerror = catchErrors; +} diff --git a/src/js/game/camera.js b/src/js/game/camera.js index 68968d6b..d59f1059 100644 --- a/src/js/game/camera.js +++ b/src/js/game/camera.js @@ -763,13 +763,14 @@ export class Camera extends BasicSerializableObject { * Clamps the center within set boundaries */ clampToBounds() { - if (!this.root.gameMode.hasBounds()) { + const bounds = this.root.gameMode.getCameraBounds(); + if (!bounds) { return; } - const bounds = this.root.gameMode.getBounds().allScaled(globalConfig.tileSize); - this.center.x = clamp(this.center.x, bounds.x, bounds.x + bounds.w); - this.center.y = clamp(this.center.y, bounds.y, bounds.y + bounds.h); + const tileScaleBounds = this.root.gameMode.getCameraBounds().allScaled(globalConfig.tileSize); + this.center.x = clamp(this.center.x, tileScaleBounds.x, tileScaleBounds.x + tileScaleBounds.w); + this.center.y = clamp(this.center.y, tileScaleBounds.y, tileScaleBounds.y + tileScaleBounds.h); } /** diff --git a/src/js/game/components/goal_acceptor.js b/src/js/game/components/goal_acceptor.js index 72c157d7..869dd3f6 100644 --- a/src/js/game/components/goal_acceptor.js +++ b/src/js/game/components/goal_acceptor.js @@ -14,9 +14,7 @@ export class GoalAcceptorComponent extends Component { constructor({ item = null, rate = null }) { super(); this.item = item; - this.rate = rate; this.achieved = false; - this.achievedOnce = false; } } diff --git a/src/js/game/core.js b/src/js/game/core.js index d9d73cae..3333d1da 100644 --- a/src/js/game/core.js +++ b/src/js/game/core.js @@ -83,6 +83,8 @@ export class GameCore { * @param {Savegame} savegame */ initializeRoot(parentState, savegame, gameModeId) { + logger.log("initializing root"); + // Construct the root element, this is the data representation of the game this.root = new GameRoot(this.app); this.root.gameState = parentState; @@ -157,6 +159,8 @@ export class GameCore { } }); } + + logger.log("root initialized"); } /** diff --git a/src/js/game/game_mode.js b/src/js/game/game_mode.js index 31189306..b9d830d3 100644 --- a/src/js/game/game_mode.js +++ b/src/js/game/game_mode.js @@ -5,6 +5,8 @@ import { Rectangle } from "../core/rectangle"; import { gGameModeRegistry } from "../core/global_registries"; import { types, BasicSerializableObject } from "../savegame/serialization"; +import { MetaBuilding } from "./meta_building"; +import { MetaItemProducerBuilding } from "./buildings/item_producer"; /** @enum {string} */ export const enumGameModeIds = { @@ -45,8 +47,10 @@ export class GameMode extends BasicSerializableObject { constructor(root) { super(); this.root = root; - this.hudParts = {}; - this.buildings = {}; + this.hiddenHurtParts = {}; + + /** @type {typeof MetaBuilding[]} */ + this.hiddenBuildings = [MetaItemProducerBuilding]; } /** @returns {object} */ @@ -74,33 +78,30 @@ export class GameMode extends BasicSerializableObject { return this.constructor.getType(); } - setBuildings(buildings) { - Object.assign(this.buildings, buildings); - } - - setHudParts(parts) { - Object.assign(this.hudParts, parts); - } - /** * @param {string} name - Class name of HUD Part * @returns {boolean} */ isHudPartExcluded(name) { - return this.hudParts[name] === false; + return this.hiddenHurtParts[name] === false; } /** - * @param {string} name - Class name of building + * @param {typeof MetaBuilding} building - Class name of building * @returns {boolean} */ - isBuildingExcluded(name) { - return this.buildings[name] === false; + isBuildingExcluded(building) { + return this.hiddenBuildings.indexOf(building) >= 0; } - /** @returns {boolean} */ - hasZone() { - return false; + /** @returns {undefined|Rectangle[]} */ + getBuildableZones() { + return; + } + + /** @returns {Rectangle|undefined} */ + getCameraBounds() { + return; } /** @returns {boolean} */ @@ -113,21 +114,6 @@ export class GameMode extends BasicSerializableObject { return true; } - /** @returns {boolean} */ - hasBounds() { - return false; - } - - /** @returns {boolean} */ - isZoneRestricted() { - return false; - } - - /** @returns {boolean} */ - isBoundaryRestricted() { - return false; - } - /** @returns {number} */ getMinimumZoom() { return 0.1; @@ -148,9 +134,8 @@ export class GameMode extends BasicSerializableObject { }; } - /** @returns {?Rectangle} */ - getZone() { - return null; + throughputDoesNotMatter() { + return false; } /** @@ -162,11 +147,6 @@ export class GameMode extends BasicSerializableObject { return; } - /** @returns {?Rectangle} */ - getBounds() { - return null; - } - /** @returns {array} */ getLevelDefinitions() { return []; @@ -187,6 +167,11 @@ export class GameMode extends BasicSerializableObject { return true; } + /** @returns {boolean} */ + getSupportsWires() { + return true; + } + /** @returns {string} */ getBlueprintShapeKey() { return "CbCbCbRb:CwCwCwCw"; diff --git a/src/js/game/game_system_manager.js b/src/js/game/game_system_manager.js index 9220acaa..08609f89 100644 --- a/src/js/game/game_system_manager.js +++ b/src/js/game/game_system_manager.js @@ -183,7 +183,7 @@ export class GameSystemManager { add("goalAcceptor", GoalAcceptorSystem); - if (this.root.gameMode.hasZone()) { + if (this.root.gameMode.getBuildableZones()) { add("zone", ZoneSystem); } diff --git a/src/js/game/hub_goals.js b/src/js/game/hub_goals.js index b3536a3c..fee1bd79 100644 --- a/src/js/game/hub_goals.js +++ b/src/js/game/hub_goals.js @@ -184,6 +184,10 @@ export class HubGoals extends BasicSerializableObject { * @param {string} upgradeId */ getUpgradeLevel(upgradeId) { + if (this.root.gameMode.throughputDoesNotMatter()) { + return 10; + } + return this.upgradeLevels[upgradeId] || 0; } @@ -195,6 +199,10 @@ export class HubGoals extends BasicSerializableObject { if (G_IS_DEV && globalConfig.debug.allBuildingsUnlocked) { return true; } + if (this.root.gameMode.getLevelDefinitions().length < 1) { + // no story, so always unlocked + return true; + } return !!this.gainedRewards[reward]; } @@ -472,6 +480,9 @@ export class HubGoals extends BasicSerializableObject { * @returns {number} items / sec */ getBeltBaseSpeed() { + if (this.root.gameMode.throughputDoesNotMatter()) { + return globalConfig.beltSpeedItemsPerSecond * 5; + } return globalConfig.beltSpeedItemsPerSecond * this.upgradeImprovements.belt; } @@ -480,6 +491,9 @@ export class HubGoals extends BasicSerializableObject { * @returns {number} items / sec */ getUndergroundBeltBaseSpeed() { + if (this.root.gameMode.throughputDoesNotMatter()) { + return globalConfig.beltSpeedItemsPerSecond * 5; + } return globalConfig.beltSpeedItemsPerSecond * this.upgradeImprovements.belt; } @@ -488,6 +502,9 @@ export class HubGoals extends BasicSerializableObject { * @returns {number} items / sec */ getMinerBaseSpeed() { + if (this.root.gameMode.throughputDoesNotMatter()) { + return globalConfig.minerSpeedItemsPerSecond * 5; + } return globalConfig.minerSpeedItemsPerSecond * this.upgradeImprovements.miner; } @@ -497,6 +514,10 @@ export class HubGoals extends BasicSerializableObject { * @returns {number} items / sec */ getProcessorBaseSpeed(processorType) { + if (this.root.gameMode.throughputDoesNotMatter()) { + return 10; + } + switch (processorType) { case enumItemProcessorTypes.trash: case enumItemProcessorTypes.hub: diff --git a/src/js/game/hud/hud.js b/src/js/game/hud/hud.js index 8f4257b9..7d0646f4 100644 --- a/src/js/game/hud/hud.js +++ b/src/js/game/hud/hud.js @@ -32,6 +32,7 @@ import { HUDModeSettings } from "./parts/mode_settings"; import { enumNotificationType, HUDNotifications } from "./parts/notifications"; import { HUDPinnedShapes } from "./parts/pinned_shapes"; import { HUDPuzzleDLCLogo } from "./parts/puzzle_dlc_logo"; +import { HUDPuzzleEditorControls } from "./parts/puzzle_editor_controls"; import { HUDSandboxController } from "./parts/sandbox_controller"; import { HUDScreenshotExporter } from "./parts/screenshot_exporter"; import { HUDSettingsMenu } from "./parts/settings_menu"; @@ -95,6 +96,7 @@ export class GameHUD { modeMenu: HUDModeMenu, modeSettings: HUDModeSettings, puzzleDlcLogo: HUDPuzzleDLCLogo, + puzzleEditorControls: HUDPuzzleEditorControls, // Must always exist pinnedShapes: HUDPinnedShapes, diff --git a/src/js/game/hud/parts/base_toolbar.js b/src/js/game/hud/parts/base_toolbar.js index 01e9fafa..9df362f3 100644 --- a/src/js/game/hud/parts/base_toolbar.js +++ b/src/js/game/hud/parts/base_toolbar.js @@ -55,7 +55,7 @@ export class HUDBaseToolbar extends BaseHUDPart { const filtered = []; for (let i = 0; i < buildings.length; i++) { - if (this.root.gameMode.isBuildingExcluded(buildings[i].name)) { + if (this.root.gameMode.isBuildingExcluded(buildings[i])) { continue; } diff --git a/src/js/game/hud/parts/mode_menu_back.js b/src/js/game/hud/parts/mode_menu_back.js index 9eae74cc..ebe8b1e6 100644 --- a/src/js/game/hud/parts/mode_menu_back.js +++ b/src/js/game/hud/parts/mode_menu_back.js @@ -1,6 +1,5 @@ -import { BaseHUDPart } from "../base_hud_part"; import { makeDiv } from "../../../core/utils"; -import { T } from "../../../translations"; +import { BaseHUDPart } from "../base_hud_part"; export class HUDModeMenuBack extends BaseHUDPart { createElements(parent) { @@ -9,7 +8,6 @@ export class HUDModeMenuBack extends BaseHUDPart { this.element = makeDiv(parent, "ingame_HUD_ModeMenuBack"); this.button = document.createElement("button"); this.button.classList.add("button"); - this.button.textContent = T.ingame.modeMenu[key].back.title; this.element.appendChild(this.button); this.trackClicks(this.button, this.back); diff --git a/src/js/game/hud/parts/mode_settings.js b/src/js/game/hud/parts/mode_settings.js index a1dd220a..48e4defe 100644 --- a/src/js/game/hud/parts/mode_settings.js +++ b/src/js/game/hud/parts/mode_settings.js @@ -8,7 +8,8 @@ export class HUDModeSettings extends BaseHUDPart { const bind = (selector, handler) => this.trackClicks(this.element.querySelector(selector), handler); - if (this.root.gameMode.hasZone()) { + // @fixme + if (this.root.gameMode.getBuildableZones()) { this.zone = makeDiv( this.element, null, @@ -52,7 +53,12 @@ export class HUDModeSettings extends BaseHUDPart { } updateZoneValues() { - const zone = this.root.gameMode.getZone(); + const zones = this.root.gameMode.getBuildableZones(); + if (!zones || zones.length === 0) { + return; + } + + const zone = zones[0]; this.element.querySelector(".zoneWidth > .value").textContent = String(zone.w); this.element.querySelector(".zoneHeight > .value").textContent = String(zone.h); } diff --git a/src/js/game/hud/parts/puzzle_editor_controls.js b/src/js/game/hud/parts/puzzle_editor_controls.js new file mode 100644 index 00000000..77d609b7 --- /dev/null +++ b/src/js/game/hud/parts/puzzle_editor_controls.js @@ -0,0 +1,21 @@ +import { makeDiv } from "../../../core/utils"; +import { BaseHUDPart } from "../base_hud_part"; + +export class HUDPuzzleEditorControls extends BaseHUDPart { + createElements(parent) { + this.element = makeDiv(parent, "ingame_HUD_PuzzleEditorControls"); + + this.element.innerHTML = ` + + 1. Build constant producers to generate resources. + 2. Build goal acceptors the capture shapes. + 3. Produce your desired shape(s) within the puzzle area and deliver it to the goal acceptors, which will capture it. + 4. Once you are done, press 'Playtest' to validate your puzzle. + `; + + this.titleElement = makeDiv(parent, "ingame_HUD_PuzzleEditorTitle"); + this.titleElement.innerText = "Puzzle Editor"; + } + + initialize() {} +} diff --git a/src/js/game/hud/parts/wires_overlay.js b/src/js/game/hud/parts/wires_overlay.js index 2fd3092c..328d6689 100644 --- a/src/js/game/hud/parts/wires_overlay.js +++ b/src/js/game/hud/parts/wires_overlay.js @@ -28,6 +28,9 @@ export class HUDWiresOverlay extends BaseHUDPart { * Switches between layers */ switchLayers() { + if (!this.root.gameMode.getSupportsWires()) { + return; + } if (this.root.currentLayer === "regular") { if ( this.root.hubGoals.isRewardUnlocked(enumHubGoalRewards.reward_wires_painter_and_levers) || diff --git a/src/js/game/map_chunk_view.js b/src/js/game/map_chunk_view.js index 06ff7337..59bff340 100644 --- a/src/js/game/map_chunk_view.js +++ b/src/js/game/map_chunk_view.js @@ -41,7 +41,7 @@ export class MapChunkView extends MapChunk { */ drawBackgroundLayer(parameters) { const systems = this.root.systemMgr.systems; - if (this.root.gameMode.hasZone()) { + if (systems.zone) { systems.zone.drawChunk(parameters, this); } diff --git a/src/js/game/modes/puzzle.js b/src/js/game/modes/puzzle.js index 31cfcb3d..15b0c868 100644 --- a/src/js/game/modes/puzzle.js +++ b/src/js/game/modes/puzzle.js @@ -32,7 +32,7 @@ export class PuzzleGameMode extends GameMode { const data = this.getSaveData(); - this.setHudParts({ + this.hiddenHurtParts = { [HUDGameMenu.name]: false, [HUDMassSelector.name]: false, [HUDInteractiveTutorial.name]: false, @@ -40,7 +40,7 @@ export class PuzzleGameMode extends GameMode { [HUDPartTutorialHints.name]: false, [HUDPinnedShapes.name]: false, [HUDWaypoints.name]: false, - }); + }; this.setDimensions(data.zoneWidth, data.zoneHeight); } @@ -48,17 +48,13 @@ export class PuzzleGameMode extends GameMode { setDimensions(w = 16, h = 9) { this.zoneWidth = w < 2 ? 2 : w; this.zoneHeight = h < 2 ? 2 : h; - this.boundsHeight = this.zoneHeight < 8 ? 8 : this.zoneHeight; - this.boundsWidth = this.zoneWidth < 8 ? 8 : this.zoneWidth; } getSaveData() { const save = this.root.savegame.getCurrentDump(); - if (!save) { return {}; } - return save.gameMode.data; } @@ -66,46 +62,12 @@ export class PuzzleGameMode extends GameMode { return new Rectangle(-Math.ceil(width / 2), -Math.ceil(height / 2), width, height); } - getBounds() { - if (this.bounds) { - return this.bounds; - } - - this.bounds = this.createCenteredRectangle(this.boundsWidth, this.boundsHeight); - - return this.bounds; + getCameraBounds() { + return this.createCenteredRectangle(this.zoneWidth + 20, this.zoneHeight + 20); } - getZone() { - if (this.zone) { - return this.zone; - } - - this.zone = this.createCenteredRectangle(this.zoneWidth, this.zoneHeight); - - return this.zone; - } - - /** - * Overrides GameMode's implementation to treat buildings like a whitelist - * instead of a blacklist by default. - * @param {string} name - Class name of building - * @returns {boolean} - */ - isBuildingExcluded(name) { - return this.buildings[name] !== true; - } - - isInBounds(x, y) { - return this.bounds.containsPoint(x, y); - } - - isInZone(x, y) { - return this.zone.containsPoint(x, y); - } - - hasZone() { - return true; + getBuildableZones() { + return [this.createCenteredRectangle(this.zoneWidth, this.zoneHeight)]; } hasHub() { @@ -116,10 +78,6 @@ export class PuzzleGameMode extends GameMode { return false; } - hasBounds() { - return true; - } - getMinimumZoom() { return 1; } @@ -132,6 +90,14 @@ export class PuzzleGameMode extends GameMode { return false; } + throughputDoesNotMatter() { + return true; + } + + getSupportsWires() { + return false; + } + /** @returns {boolean} */ getIsFreeplayAvailable() { return true; diff --git a/src/js/game/modes/puzzle_edit.js b/src/js/game/modes/puzzle_edit.js index f927b001..680778aa 100644 --- a/src/js/game/modes/puzzle_edit.js +++ b/src/js/game/modes/puzzle_edit.js @@ -2,12 +2,23 @@ import { GameRoot } from "../root"; /* typehints:end */ -// import { MetaBeltBuilding } from "../buildings/belt"; -import { MetaConstantProducerBuilding } from "../buildings/constant_producer"; -import { MetaGoalAcceptorBuilding } from "../buildings/goal_acceptor"; -// import { MetaItemProducerBuilding } from "../buildings/item_producer"; import { enumGameModeIds } from "../game_mode"; import { PuzzleGameMode } from "./puzzle"; +import { MetaStorageBuilding } from "../buildings/storage"; +import { MetaReaderBuilding } from "../buildings/reader"; +import { MetaFilterBuilding } from "../buildings/filter"; +import { MetaDisplayBuilding } from "../buildings/display"; +import { MetaLeverBuilding } from "../buildings/lever"; +import { MetaItemProducerBuilding } from "../buildings/item_producer"; +import { MetaMinerBuilding } from "../buildings/miner"; +import { MetaWireBuilding } from "../buildings/wire"; +import { MetaWireTunnelBuilding } from "../buildings/wire_tunnel"; +import { MetaConstantSignalBuilding } from "../buildings/constant_signal"; +import { MetaLogicGateBuilding } from "../buildings/logic_gate"; +import { MetaVirtualProcessorBuilding } from "../buildings/virtual_processor"; +import { MetaAnalyzerBuilding } from "../buildings/analyzer"; +import { MetaComparatorBuilding } from "../buildings/comparator"; +import { MetaTransistorBuilding } from "../buildings/transistor"; export class PuzzleEditGameMode extends PuzzleGameMode { static getId() { @@ -24,18 +35,24 @@ export class PuzzleEditGameMode extends PuzzleGameMode { this.playtest = false; - this.setBuildings({ - [MetaConstantProducerBuilding.name]: true, - [MetaGoalAcceptorBuilding.name]: true, - }); - } + this.hiddenBuildings = [ + MetaStorageBuilding, + MetaReaderBuilding, + MetaFilterBuilding, + MetaDisplayBuilding, + MetaLeverBuilding, + MetaItemProducerBuilding, + MetaMinerBuilding, - isZoneRestricted() { - return !this.playtest; - } - - isBoundaryRestricted() { - return this.playtest; + MetaWireBuilding, + MetaWireTunnelBuilding, + MetaConstantSignalBuilding, + MetaLogicGateBuilding, + MetaVirtualProcessorBuilding, + MetaAnalyzerBuilding, + MetaComparatorBuilding, + MetaTransistorBuilding, + ]; } expandZone(w = 0, h = 0) { diff --git a/src/js/game/modes/regular.js b/src/js/game/modes/regular.js index 4f8e9ec2..1e84a115 100644 --- a/src/js/game/modes/regular.js +++ b/src/js/game/modes/regular.js @@ -518,19 +518,15 @@ export class RegularGameMode extends GameMode { constructor(root) { super(root); - this.setHudParts({ + this.hiddenHurtParts = { [HUDModeMenuBack.name]: false, [HUDModeMenuNext.name]: false, [HUDModeMenu.name]: false, [HUDModeSettings.name]: false, [HUDPuzzleDLCLogo.name]: false, - }); + }; - this.setBuildings({ - [MetaConstantProducerBuilding.name]: false, - [MetaGoalAcceptorBuilding.name]: false, - [MetaItemProducerBuilding.name]: queryParamOptions.sandboxMode || G_IS_DEV, - }); + this.hiddenBuildings = [MetaConstantProducerBuilding, MetaGoalAcceptorBuilding]; } /** diff --git a/src/js/game/systems/goal_acceptor.js b/src/js/game/systems/goal_acceptor.js index e24eb80b..6fcb479e 100644 --- a/src/js/game/systems/goal_acceptor.js +++ b/src/js/game/systems/goal_acceptor.js @@ -49,25 +49,17 @@ export class GoalAcceptorSystem extends GameSystemWithFilter { const itemInput = new FormElementInput({ id: "goalItemInput", - label: fillInLinkIntoTranslation(T.dialogs.editSignal.descShortKey, THIRDPARTY_URLS.shapeViewer), + label: fillInLinkIntoTranslation(T.dialogs.editGoalAcceptor.desc, THIRDPARTY_URLS.shapeViewer), placeholder: "CuCuCuCu", defaultValue: "CuCuCuCu", validator: val => this.parseItem(val), }); - const rateInput = new FormElementInput({ - id: "goalRateInput", - label: "Rate:", - placeholder: "0", - defaultValue: "0", - validator: val => !isNaN(Number(val)), - }); - const dialog = new DialogWithForm({ app: this.root.app, - title: "Set Goal", + title: T.dialogs.editGoalAcceptor.title, desc: "", - formElements: [itemInput, rateInput], + formElements: [itemInput], buttons: ["cancel:bad:escape", "ok:good:enter"], closeButton: false, }); @@ -79,7 +71,6 @@ export class GoalAcceptorSystem extends GameSystemWithFilter { } goalComp.item = this.parseItem(itemInput.getValue()); - goalComp.rate = this.parseRate(rateInput.getValue()); }; dialog.buttonSignals.ok.add(closeHandler); diff --git a/src/js/game/systems/zone.js b/src/js/game/systems/zone.js index 3dd68804..7e977438 100644 --- a/src/js/game/systems/zone.js +++ b/src/js/game/systems/zone.js @@ -13,8 +13,12 @@ export class ZoneSystem extends GameSystem { /** @param {GameRoot} root */ constructor(root) { super(root); - + this.drawn = false; this.root.signals.prePlacementCheck.add(this.prePlacementCheck, this); + + this.root.signals.gameFrameStarted.add(() => { + this.drawn = false; + }); } prePlacementCheck(entity, tile = null) { @@ -25,18 +29,24 @@ export class ZoneSystem extends GameSystem { } const mode = this.root.gameMode; - const zone = mode.getZone().expandedInAllDirections(-1); + + const zones = mode.getBuildableZones(); + if (!zones) { + return; + } + const transformed = staticComp.getTileSpaceBounds(); - if (zone.containsRect(transformed)) { - if (mode.isZoneRestricted()) { - return STOP_PROPAGATION; - } - } else { - if (mode.isBoundaryRestricted()) { - return STOP_PROPAGATION; + let withinAnyZone = false; + for (const zone of zones) { + if (zone.expandedInAllDirections(-1).containsRect(transformed)) { + withinAnyZone = true; } } + + if (!withinAnyZone) { + return STOP_PROPAGATION; + } } /** @@ -45,18 +55,46 @@ export class ZoneSystem extends GameSystem { * @param {MapChunkView} chunk */ drawChunk(parameters, chunk) { + if (this.drawn) { + // oof + return; + } + this.drawn = true; + const mode = this.root.gameMode; - const zone = mode.getZone().allScaled(globalConfig.tileSize); + + const zones = mode.getBuildableZones(); + if (!zones) { + return; + } + + const zone = zones[0].allScaled(globalConfig.tileSize); const context = parameters.context; - context.globalAlpha = 0.1; - context.fillStyle = THEME.map.zone.background; - context.fillRect(zone.x, zone.y, zone.w, zone.h); - - context.globalAlpha = 1; - context.strokeStyle = THEME.map.zone.border; context.lineWidth = 2; - context.strokeRect(zone.x, zone.y, zone.w, zone.h); + context.strokeStyle = THEME.map.zone.borderSolid; + context.beginPath(); + context.rect(zone.x, zone.y, zone.w, zone.h); + + context.stroke(); + + const outer = zone; + const padding = 40 * globalConfig.tileSize; + context.fillStyle = THEME.map.zone.outerColor; + context.fillRect(outer.x + outer.w, outer.y, padding, outer.h); + context.fillRect(outer.x - padding, outer.y, padding, outer.h); + context.fillRect( + outer.x - padding - globalConfig.tileSize, + outer.y - padding, + 2 * padding + zone.w + 2 * globalConfig.tileSize, + padding + ); + context.fillRect( + outer.x - padding - globalConfig.tileSize, + outer.y + outer.h, + 2 * padding + zone.w + 2 * globalConfig.tileSize, + padding + ); context.globalAlpha = 1; } diff --git a/src/js/game/themes/dark.json b/src/js/game/themes/dark.json index 02ff6ae3..010f9251 100644 --- a/src/js/game/themes/dark.json +++ b/src/js/game/themes/dark.json @@ -50,8 +50,10 @@ }, "zone": { - "background": "#3e3f47", - "border": "#667964" + "background": "#fff", + "border": "rgba(23, 192, 255, 0.1)", + "borderSolid": "rgba(23, 192, 255, 0.7)", + "outerColor": "rgba(240, 240, 255, 0.5)" } }, diff --git a/src/js/game/themes/light.json b/src/js/game/themes/light.json index 4aa367fd..c39e19f0 100644 --- a/src/js/game/themes/light.json +++ b/src/js/game/themes/light.json @@ -52,7 +52,9 @@ "zone": { "background": "#fff", - "border": "#cbffc4" + "border": "rgba(23, 192, 255, 0.1)", + "borderSolid": "rgba(23, 192, 255, 0.7)", + "outerColor": "rgba(240, 240, 255, 0.5)" } }, diff --git a/src/js/languages.js b/src/js/languages.js index 6899ef09..4dfb15d4 100644 --- a/src/js/languages.js +++ b/src/js/languages.js @@ -184,4 +184,12 @@ export const LANGUAGES = { code: "uk", region: "", }, + + "he": { + // hebrew + name: "עברית", + data: require("./built-temp/base-he.json"), + code: "he", + region: "", + }, }; diff --git a/src/js/states/ingame.js b/src/js/states/ingame.js index 32ef3edc..a872b6f6 100644 --- a/src/js/states/ingame.js +++ b/src/js/states/ingame.js @@ -370,7 +370,13 @@ export class InGameState extends GameState { // Remove unneded default element document.body.querySelector(".modalDialogParent").remove(); - this.asyncChannel.watch(waitNextFrame()).then(() => this.stage3CreateCore()); + this.asyncChannel + .watch(waitNextFrame()) + .then(() => this.stage3CreateCore()) + .catch(ex => { + logger.error(ex); + throw ex; + }); } /** diff --git a/src/js/states/puzzle_menu.js b/src/js/states/puzzle_menu.js index d6465627..8b6c8fcb 100644 --- a/src/js/states/puzzle_menu.js +++ b/src/js/states/puzzle_menu.js @@ -1,3 +1,4 @@ +import { globalConfig } from "../core/config"; import { TextualGameState } from "../core/textual_game_state"; import { formatBigNumberFull } from "../core/utils"; import { enumGameModeIds } from "../game/game_mode"; @@ -206,6 +207,10 @@ export class PuzzleMenuState extends TextualGameState { } this.trackClicks(this.htmlElement.querySelector("button.createPuzzle"), this.createNewPuzzle); + + if (G_IS_DEV && globalConfig.debug.testPuzzleMode) { + this.createNewPuzzle(); + } } createNewPuzzle() { diff --git a/translations/base-en.yaml b/translations/base-en.yaml index 29c610a7..f02b8335 100644 --- a/translations/base-en.yaml +++ b/translations/base-en.yaml @@ -248,6 +248,10 @@ dialogs: Choose a pre-defined item: descShortKey: ... or enter the short key of a shape (Which you can generate here) + editGoalAcceptor: + title: Set Goal + desc: Enter the short key of a shape (Which you can generate here). The goal will count as completed once 1 item /s is delivered. + markerDemoLimit: desc: You can only create two custom markers in the demo. Get the standalone for unlimited markers! diff --git a/translations/base-he.yml b/translations/base-he.yaml similarity index 97% rename from translations/base-he.yml rename to translations/base-he.yaml index d0e80e99..40b458c7 100644 --- a/translations/base-he.yml +++ b/translations/base-he.yaml @@ -7,13 +7,13 @@ steamPage: intro: >- אתה אוהב משחקי אוטומציה? אתה במקום הנכון! - + shapez.io הוא משחק שלווה שבו אתה בונה מפעל בשביל ליצור צורות גאומטריות אוטומטית. ככל שמתקדמים השלבים, הצורות נהיות יותר ויותר מסובכות, ואתה צריך להפתח על המפה האין סופית. - + ואם זה לא היה מספיק, אתה צריך ליצור יותר ויותר צורות בשביל לספק את הדרישה - הדבר היחיד שיכול לעזור זה להגדיל את המפעל! בזמן שבהתחלה אתה רק צריך לערוך צורות, בהמשך אתה צריך לצבוע אותם בעזרת צבעים שאתה מערבב. - + קניית המשחק בsteam תתן לך גישה למשחק המלא, אבל אתה יכול לשחק משחק דמו בhttps://shapez.io/ ולהחליט אחר כך. - + what_others_say: What people say about shapez.io nothernlion_comment: >- @@ -85,7 +85,8 @@ mainMenu: openSourceHint: המשחק הזה הוא עם קוד פתוח! discordLink: שרת הדסקורד הרשמי helpTranslate: תעזור לתרגם! - madeBy: יוצר המשחק: + madeBy: >- + יוצר המשחק: # This is shown when using firefox and other browsers which are not supported. browserWarning: >- @@ -1205,4 +1206,4 @@ tips: - בשביל לנקות מסוע, חתוך את האיזור ואז תדביק באותו מקום. - לחץ F4 בשביל להציג את הFPS ואת הTickRate. - לחץ F4 פעמיים בשביל להציג את המשבצת שהעכבר והמצלמה בהם. - - אתה יכול ללחוץ על צורה מוצמדת בצד שמאל בשביל לבטל את ההצמדה. \ No newline at end of file + - אתה יכול ללחוץ על צורה מוצמדת בצד שמאל בשביל לבטל את ההצמדה.