1
0
mirror of https://github.com/tobspr/shapez.io.git synced 2025-06-13 13:04:03 +00:00

Puzzle mode, part 2

This commit is contained in:
tobspr 2021-04-29 22:31:06 +02:00
parent 752503d892
commit 46e0c1494a
39 changed files with 332 additions and 178 deletions

View File

@ -54,8 +54,11 @@
document.documentElement.appendChild(element); 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) { function makeJsTag(src, integrity) {
var script = document.createElement("script"); var script = document.createElement("script");

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 KiB

After

Width:  |  Height:  |  Size: 3.5 KiB

42
res/ui/languages/he.svg Normal file
View File

@ -0,0 +1,42 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 512 512" style="enable-background:new 0 0 512 512;" xml:space="preserve">
<rect style="fill:#41479B;" width="512" height="512"/>
<rect y="93.86" style="fill:#F5F5F5;" width="512" height="324.28"/>
<path style="fill:#41479B;" d="M317.474,256l30.734-53.234h-61.469L256,149.523l-30.739,53.243h-61.469L194.526,256l-30.734,53.234
h61.469L256,362.477l30.739-53.243h61.469L317.474,256z M318.054,220.176l-10.632,18.415l-10.632-18.415H318.054z M297.371,256
l-20.683,35.824h-41.376L214.629,256l20.683-35.824h41.376L297.371,256z M256,184.344l10.636,18.422h-21.272L256,184.344z
M193.946,220.176h21.264l-10.632,18.415L193.946,220.176z M193.946,291.824l10.632-18.415l10.632,18.415H193.946z M256,327.656
l-10.636-18.422h21.272L256,327.656z M307.423,273.409l10.632,18.415h-21.264L307.423,273.409z"/>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 15 KiB

View File

@ -11,7 +11,6 @@
> .button { > .button {
@include PlainText; @include PlainText;
@include IncreasedClickArea(0px);
pointer-events: all; pointer-events: all;
cursor: pointer; cursor: pointer;
position: relative; position: relative;
@ -20,6 +19,8 @@
transition-property: opacity, transform; transition-property: opacity, transform;
text-transform: uppercase; text-transform: uppercase;
@include PlainText; @include PlainText;
@include S(width, 30px);
@include S(height, 30px);
opacity: 1; opacity: 1;
&:hover { &:hover {
@ -30,11 +31,9 @@
transform: scale(0.95) !important; transform: scale(0.95) !important;
} }
@include S(padding-left, 25px);
& { & {
/* @load-async */ /* @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;
} }
} }
} }

View File

@ -1,6 +1,6 @@
#ingame_HUD_ModeMenuNext { #ingame_HUD_ModeMenuNext {
position: absolute; position: absolute;
@include S(top, 10px); @include S(top, 15px);
@include S(right, 10px); @include S(right, 10px);
display: flex; display: flex;

View File

@ -2,8 +2,8 @@
position: absolute; position: absolute;
@include S(width, 150px); @include S(width, 150px);
@include S(height, 40px); @include S(height, 40px);
@include S(bottom, 10px); @include S(left, 50px);
@include S(right, 15px); @include S(top, 10px);
& { & {
/* @load-async */ /* @load-async */

View File

@ -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;
}

View File

@ -61,6 +61,7 @@
@import "ingame_hud/mode_menu"; @import "ingame_hud/mode_menu";
@import "ingame_hud/mode_settings"; @import "ingame_hud/mode_settings";
@import "ingame_hud/puzzle_dlc_logo"; @import "ingame_hud/puzzle_dlc_logo";
@import "ingame_hud/puzzle_editor_controls";
// prettier-ignore // prettier-ignore
$elements: $elements:
@ -80,6 +81,8 @@ ingame_HUD_GameMenu,
ingame_HUD_KeybindingOverlay, ingame_HUD_KeybindingOverlay,
ingame_HUD_ModeMenuBack, ingame_HUD_ModeMenuBack,
ingame_HUD_ModeMenuNext, ingame_HUD_ModeMenuNext,
ingame_HUD_PuzzleEditorControls,
ingame_HUD_PuzzleEditorTitle,
ingame_HUD_ModeMenu, ingame_HUD_ModeMenu,
ingame_HUD_ModeSettings, ingame_HUD_ModeSettings,
ingame_HUD_Notifications, ingame_HUD_Notifications,

View File

@ -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, $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 { @each $language in $languages {
[data-languageicon="#{$language}"] { [data-languageicon="#{$language}"] {

View File

@ -124,16 +124,17 @@
@include SuperSmallText; @include SuperSmallText;
grid-column: 2 / 3; grid-column: 2 / 3;
grid-row: 3 / 4; grid-row: 3 / 4;
color: $accentColorDark; color: #444;
align-self: end; align-self: end;
justify-self: end; justify-self: end;
font-weight: bold; font-weight: bold;
@include S(padding-right, 12px); @include S(padding-right, 12px);
opacity: 0.89;
& { & {
/* @load-async */ /* @load-async */
background: uiResource("icons/puzzle_upvotes.png") calc(100% - #{D(2px)}) #{D( background: uiResource("icons/puzzle_upvotes.png") calc(100% - #{D(2px)}) #{D(
3.3px 3.5px
)} / #{D(8px)} #{D(8px)} no-repeat; )} / #{D(8px)} #{D(8px)} no-repeat;
} }
} }

View File

@ -51,9 +51,12 @@ export class AnimationFrame {
dt = resetDtMs; dt = resetDtMs;
} }
this.frameEmitted.dispatch(dt); try {
this.frameEmitted.dispatch(dt);
} catch (ex) {
console.error(ex);
}
this.lastTime = time; this.lastTime = time;
window.requestAnimationFrame(this.boundMethod); window.requestAnimationFrame(this.boundMethod);
} }
} }

View File

@ -123,4 +123,6 @@ function catchErrors(message, source, lineno, colno, error) {
return true; return true;
} }
window.onerror = catchErrors; if (!G_IS_DEV) {
window.onerror = catchErrors;
}

View File

@ -763,13 +763,14 @@ export class Camera extends BasicSerializableObject {
* Clamps the center within set boundaries * Clamps the center within set boundaries
*/ */
clampToBounds() { clampToBounds() {
if (!this.root.gameMode.hasBounds()) { const bounds = this.root.gameMode.getCameraBounds();
if (!bounds) {
return; return;
} }
const bounds = this.root.gameMode.getBounds().allScaled(globalConfig.tileSize); const tileScaleBounds = this.root.gameMode.getCameraBounds().allScaled(globalConfig.tileSize);
this.center.x = clamp(this.center.x, bounds.x, bounds.x + bounds.w); this.center.x = clamp(this.center.x, tileScaleBounds.x, tileScaleBounds.x + tileScaleBounds.w);
this.center.y = clamp(this.center.y, bounds.y, bounds.y + bounds.h); this.center.y = clamp(this.center.y, tileScaleBounds.y, tileScaleBounds.y + tileScaleBounds.h);
} }
/** /**

View File

@ -14,9 +14,7 @@ export class GoalAcceptorComponent extends Component {
constructor({ item = null, rate = null }) { constructor({ item = null, rate = null }) {
super(); super();
this.item = item; this.item = item;
this.rate = rate;
this.achieved = false; this.achieved = false;
this.achievedOnce = false;
} }
} }

View File

@ -83,6 +83,8 @@ export class GameCore {
* @param {Savegame} savegame * @param {Savegame} savegame
*/ */
initializeRoot(parentState, savegame, gameModeId) { initializeRoot(parentState, savegame, gameModeId) {
logger.log("initializing root");
// Construct the root element, this is the data representation of the game // Construct the root element, this is the data representation of the game
this.root = new GameRoot(this.app); this.root = new GameRoot(this.app);
this.root.gameState = parentState; this.root.gameState = parentState;
@ -157,6 +159,8 @@ export class GameCore {
} }
}); });
} }
logger.log("root initialized");
} }
/** /**

View File

@ -5,6 +5,8 @@ import { Rectangle } from "../core/rectangle";
import { gGameModeRegistry } from "../core/global_registries"; import { gGameModeRegistry } from "../core/global_registries";
import { types, BasicSerializableObject } from "../savegame/serialization"; import { types, BasicSerializableObject } from "../savegame/serialization";
import { MetaBuilding } from "./meta_building";
import { MetaItemProducerBuilding } from "./buildings/item_producer";
/** @enum {string} */ /** @enum {string} */
export const enumGameModeIds = { export const enumGameModeIds = {
@ -45,8 +47,10 @@ export class GameMode extends BasicSerializableObject {
constructor(root) { constructor(root) {
super(); super();
this.root = root; this.root = root;
this.hudParts = {}; this.hiddenHurtParts = {};
this.buildings = {};
/** @type {typeof MetaBuilding[]} */
this.hiddenBuildings = [MetaItemProducerBuilding];
} }
/** @returns {object} */ /** @returns {object} */
@ -74,33 +78,30 @@ export class GameMode extends BasicSerializableObject {
return this.constructor.getType(); 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 * @param {string} name - Class name of HUD Part
* @returns {boolean} * @returns {boolean}
*/ */
isHudPartExcluded(name) { 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} * @returns {boolean}
*/ */
isBuildingExcluded(name) { isBuildingExcluded(building) {
return this.buildings[name] === false; return this.hiddenBuildings.indexOf(building) >= 0;
} }
/** @returns {boolean} */ /** @returns {undefined|Rectangle[]} */
hasZone() { getBuildableZones() {
return false; return;
}
/** @returns {Rectangle|undefined} */
getCameraBounds() {
return;
} }
/** @returns {boolean} */ /** @returns {boolean} */
@ -113,21 +114,6 @@ export class GameMode extends BasicSerializableObject {
return true; return true;
} }
/** @returns {boolean} */
hasBounds() {
return false;
}
/** @returns {boolean} */
isZoneRestricted() {
return false;
}
/** @returns {boolean} */
isBoundaryRestricted() {
return false;
}
/** @returns {number} */ /** @returns {number} */
getMinimumZoom() { getMinimumZoom() {
return 0.1; return 0.1;
@ -148,9 +134,8 @@ export class GameMode extends BasicSerializableObject {
}; };
} }
/** @returns {?Rectangle} */ throughputDoesNotMatter() {
getZone() { return false;
return null;
} }
/** /**
@ -162,11 +147,6 @@ export class GameMode extends BasicSerializableObject {
return; return;
} }
/** @returns {?Rectangle} */
getBounds() {
return null;
}
/** @returns {array} */ /** @returns {array} */
getLevelDefinitions() { getLevelDefinitions() {
return []; return [];
@ -187,6 +167,11 @@ export class GameMode extends BasicSerializableObject {
return true; return true;
} }
/** @returns {boolean} */
getSupportsWires() {
return true;
}
/** @returns {string} */ /** @returns {string} */
getBlueprintShapeKey() { getBlueprintShapeKey() {
return "CbCbCbRb:CwCwCwCw"; return "CbCbCbRb:CwCwCwCw";

View File

@ -183,7 +183,7 @@ export class GameSystemManager {
add("goalAcceptor", GoalAcceptorSystem); add("goalAcceptor", GoalAcceptorSystem);
if (this.root.gameMode.hasZone()) { if (this.root.gameMode.getBuildableZones()) {
add("zone", ZoneSystem); add("zone", ZoneSystem);
} }

View File

@ -184,6 +184,10 @@ export class HubGoals extends BasicSerializableObject {
* @param {string} upgradeId * @param {string} upgradeId
*/ */
getUpgradeLevel(upgradeId) { getUpgradeLevel(upgradeId) {
if (this.root.gameMode.throughputDoesNotMatter()) {
return 10;
}
return this.upgradeLevels[upgradeId] || 0; return this.upgradeLevels[upgradeId] || 0;
} }
@ -195,6 +199,10 @@ export class HubGoals extends BasicSerializableObject {
if (G_IS_DEV && globalConfig.debug.allBuildingsUnlocked) { if (G_IS_DEV && globalConfig.debug.allBuildingsUnlocked) {
return true; return true;
} }
if (this.root.gameMode.getLevelDefinitions().length < 1) {
// no story, so always unlocked
return true;
}
return !!this.gainedRewards[reward]; return !!this.gainedRewards[reward];
} }
@ -472,6 +480,9 @@ export class HubGoals extends BasicSerializableObject {
* @returns {number} items / sec * @returns {number} items / sec
*/ */
getBeltBaseSpeed() { getBeltBaseSpeed() {
if (this.root.gameMode.throughputDoesNotMatter()) {
return globalConfig.beltSpeedItemsPerSecond * 5;
}
return globalConfig.beltSpeedItemsPerSecond * this.upgradeImprovements.belt; return globalConfig.beltSpeedItemsPerSecond * this.upgradeImprovements.belt;
} }
@ -480,6 +491,9 @@ export class HubGoals extends BasicSerializableObject {
* @returns {number} items / sec * @returns {number} items / sec
*/ */
getUndergroundBeltBaseSpeed() { getUndergroundBeltBaseSpeed() {
if (this.root.gameMode.throughputDoesNotMatter()) {
return globalConfig.beltSpeedItemsPerSecond * 5;
}
return globalConfig.beltSpeedItemsPerSecond * this.upgradeImprovements.belt; return globalConfig.beltSpeedItemsPerSecond * this.upgradeImprovements.belt;
} }
@ -488,6 +502,9 @@ export class HubGoals extends BasicSerializableObject {
* @returns {number} items / sec * @returns {number} items / sec
*/ */
getMinerBaseSpeed() { getMinerBaseSpeed() {
if (this.root.gameMode.throughputDoesNotMatter()) {
return globalConfig.minerSpeedItemsPerSecond * 5;
}
return globalConfig.minerSpeedItemsPerSecond * this.upgradeImprovements.miner; return globalConfig.minerSpeedItemsPerSecond * this.upgradeImprovements.miner;
} }
@ -497,6 +514,10 @@ export class HubGoals extends BasicSerializableObject {
* @returns {number} items / sec * @returns {number} items / sec
*/ */
getProcessorBaseSpeed(processorType) { getProcessorBaseSpeed(processorType) {
if (this.root.gameMode.throughputDoesNotMatter()) {
return 10;
}
switch (processorType) { switch (processorType) {
case enumItemProcessorTypes.trash: case enumItemProcessorTypes.trash:
case enumItemProcessorTypes.hub: case enumItemProcessorTypes.hub:

View File

@ -32,6 +32,7 @@ import { HUDModeSettings } from "./parts/mode_settings";
import { enumNotificationType, HUDNotifications } from "./parts/notifications"; import { enumNotificationType, HUDNotifications } from "./parts/notifications";
import { HUDPinnedShapes } from "./parts/pinned_shapes"; import { HUDPinnedShapes } from "./parts/pinned_shapes";
import { HUDPuzzleDLCLogo } from "./parts/puzzle_dlc_logo"; import { HUDPuzzleDLCLogo } from "./parts/puzzle_dlc_logo";
import { HUDPuzzleEditorControls } from "./parts/puzzle_editor_controls";
import { HUDSandboxController } from "./parts/sandbox_controller"; import { HUDSandboxController } from "./parts/sandbox_controller";
import { HUDScreenshotExporter } from "./parts/screenshot_exporter"; import { HUDScreenshotExporter } from "./parts/screenshot_exporter";
import { HUDSettingsMenu } from "./parts/settings_menu"; import { HUDSettingsMenu } from "./parts/settings_menu";
@ -95,6 +96,7 @@ export class GameHUD {
modeMenu: HUDModeMenu, modeMenu: HUDModeMenu,
modeSettings: HUDModeSettings, modeSettings: HUDModeSettings,
puzzleDlcLogo: HUDPuzzleDLCLogo, puzzleDlcLogo: HUDPuzzleDLCLogo,
puzzleEditorControls: HUDPuzzleEditorControls,
// Must always exist // Must always exist
pinnedShapes: HUDPinnedShapes, pinnedShapes: HUDPinnedShapes,

View File

@ -55,7 +55,7 @@ export class HUDBaseToolbar extends BaseHUDPart {
const filtered = []; const filtered = [];
for (let i = 0; i < buildings.length; i++) { for (let i = 0; i < buildings.length; i++) {
if (this.root.gameMode.isBuildingExcluded(buildings[i].name)) { if (this.root.gameMode.isBuildingExcluded(buildings[i])) {
continue; continue;
} }

View File

@ -1,6 +1,5 @@
import { BaseHUDPart } from "../base_hud_part";
import { makeDiv } from "../../../core/utils"; import { makeDiv } from "../../../core/utils";
import { T } from "../../../translations"; import { BaseHUDPart } from "../base_hud_part";
export class HUDModeMenuBack extends BaseHUDPart { export class HUDModeMenuBack extends BaseHUDPart {
createElements(parent) { createElements(parent) {
@ -9,7 +8,6 @@ export class HUDModeMenuBack extends BaseHUDPart {
this.element = makeDiv(parent, "ingame_HUD_ModeMenuBack"); this.element = makeDiv(parent, "ingame_HUD_ModeMenuBack");
this.button = document.createElement("button"); this.button = document.createElement("button");
this.button.classList.add("button"); this.button.classList.add("button");
this.button.textContent = T.ingame.modeMenu[key].back.title;
this.element.appendChild(this.button); this.element.appendChild(this.button);
this.trackClicks(this.button, this.back); this.trackClicks(this.button, this.back);

View File

@ -8,7 +8,8 @@ export class HUDModeSettings extends BaseHUDPart {
const bind = (selector, handler) => this.trackClicks(this.element.querySelector(selector), handler); 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.zone = makeDiv(
this.element, this.element,
null, null,
@ -52,7 +53,12 @@ export class HUDModeSettings extends BaseHUDPart {
} }
updateZoneValues() { 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(".zoneWidth > .value").textContent = String(zone.w);
this.element.querySelector(".zoneHeight > .value").textContent = String(zone.h); this.element.querySelector(".zoneHeight > .value").textContent = String(zone.h);
} }

View File

@ -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 = `
<span>1. Build constant producers to generate resources.</span>
<span>2. Build goal acceptors the capture shapes.</span>
<span>3. Produce your desired shape(s) within the puzzle area and deliver it to the goal acceptors, which will capture it.</span>
<span>4. Once you are done, press 'Playtest' to validate your puzzle.</span>
`;
this.titleElement = makeDiv(parent, "ingame_HUD_PuzzleEditorTitle");
this.titleElement.innerText = "Puzzle Editor";
}
initialize() {}
}

View File

@ -28,6 +28,9 @@ export class HUDWiresOverlay extends BaseHUDPart {
* Switches between layers * Switches between layers
*/ */
switchLayers() { switchLayers() {
if (!this.root.gameMode.getSupportsWires()) {
return;
}
if (this.root.currentLayer === "regular") { if (this.root.currentLayer === "regular") {
if ( if (
this.root.hubGoals.isRewardUnlocked(enumHubGoalRewards.reward_wires_painter_and_levers) || this.root.hubGoals.isRewardUnlocked(enumHubGoalRewards.reward_wires_painter_and_levers) ||

View File

@ -41,7 +41,7 @@ export class MapChunkView extends MapChunk {
*/ */
drawBackgroundLayer(parameters) { drawBackgroundLayer(parameters) {
const systems = this.root.systemMgr.systems; const systems = this.root.systemMgr.systems;
if (this.root.gameMode.hasZone()) { if (systems.zone) {
systems.zone.drawChunk(parameters, this); systems.zone.drawChunk(parameters, this);
} }

View File

@ -32,7 +32,7 @@ export class PuzzleGameMode extends GameMode {
const data = this.getSaveData(); const data = this.getSaveData();
this.setHudParts({ this.hiddenHurtParts = {
[HUDGameMenu.name]: false, [HUDGameMenu.name]: false,
[HUDMassSelector.name]: false, [HUDMassSelector.name]: false,
[HUDInteractiveTutorial.name]: false, [HUDInteractiveTutorial.name]: false,
@ -40,7 +40,7 @@ export class PuzzleGameMode extends GameMode {
[HUDPartTutorialHints.name]: false, [HUDPartTutorialHints.name]: false,
[HUDPinnedShapes.name]: false, [HUDPinnedShapes.name]: false,
[HUDWaypoints.name]: false, [HUDWaypoints.name]: false,
}); };
this.setDimensions(data.zoneWidth, data.zoneHeight); this.setDimensions(data.zoneWidth, data.zoneHeight);
} }
@ -48,17 +48,13 @@ export class PuzzleGameMode extends GameMode {
setDimensions(w = 16, h = 9) { setDimensions(w = 16, h = 9) {
this.zoneWidth = w < 2 ? 2 : w; this.zoneWidth = w < 2 ? 2 : w;
this.zoneHeight = h < 2 ? 2 : h; this.zoneHeight = h < 2 ? 2 : h;
this.boundsHeight = this.zoneHeight < 8 ? 8 : this.zoneHeight;
this.boundsWidth = this.zoneWidth < 8 ? 8 : this.zoneWidth;
} }
getSaveData() { getSaveData() {
const save = this.root.savegame.getCurrentDump(); const save = this.root.savegame.getCurrentDump();
if (!save) { if (!save) {
return {}; return {};
} }
return save.gameMode.data; 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); return new Rectangle(-Math.ceil(width / 2), -Math.ceil(height / 2), width, height);
} }
getBounds() { getCameraBounds() {
if (this.bounds) { return this.createCenteredRectangle(this.zoneWidth + 20, this.zoneHeight + 20);
return this.bounds;
}
this.bounds = this.createCenteredRectangle(this.boundsWidth, this.boundsHeight);
return this.bounds;
} }
getZone() { getBuildableZones() {
if (this.zone) { return [this.createCenteredRectangle(this.zoneWidth, this.zoneHeight)];
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;
} }
hasHub() { hasHub() {
@ -116,10 +78,6 @@ export class PuzzleGameMode extends GameMode {
return false; return false;
} }
hasBounds() {
return true;
}
getMinimumZoom() { getMinimumZoom() {
return 1; return 1;
} }
@ -132,6 +90,14 @@ export class PuzzleGameMode extends GameMode {
return false; return false;
} }
throughputDoesNotMatter() {
return true;
}
getSupportsWires() {
return false;
}
/** @returns {boolean} */ /** @returns {boolean} */
getIsFreeplayAvailable() { getIsFreeplayAvailable() {
return true; return true;

View File

@ -2,12 +2,23 @@
import { GameRoot } from "../root"; import { GameRoot } from "../root";
/* typehints:end */ /* 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 { enumGameModeIds } from "../game_mode";
import { PuzzleGameMode } from "./puzzle"; 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 { export class PuzzleEditGameMode extends PuzzleGameMode {
static getId() { static getId() {
@ -24,18 +35,24 @@ export class PuzzleEditGameMode extends PuzzleGameMode {
this.playtest = false; this.playtest = false;
this.setBuildings({ this.hiddenBuildings = [
[MetaConstantProducerBuilding.name]: true, MetaStorageBuilding,
[MetaGoalAcceptorBuilding.name]: true, MetaReaderBuilding,
}); MetaFilterBuilding,
} MetaDisplayBuilding,
MetaLeverBuilding,
MetaItemProducerBuilding,
MetaMinerBuilding,
isZoneRestricted() { MetaWireBuilding,
return !this.playtest; MetaWireTunnelBuilding,
} MetaConstantSignalBuilding,
MetaLogicGateBuilding,
isBoundaryRestricted() { MetaVirtualProcessorBuilding,
return this.playtest; MetaAnalyzerBuilding,
MetaComparatorBuilding,
MetaTransistorBuilding,
];
} }
expandZone(w = 0, h = 0) { expandZone(w = 0, h = 0) {

View File

@ -518,19 +518,15 @@ export class RegularGameMode extends GameMode {
constructor(root) { constructor(root) {
super(root); super(root);
this.setHudParts({ this.hiddenHurtParts = {
[HUDModeMenuBack.name]: false, [HUDModeMenuBack.name]: false,
[HUDModeMenuNext.name]: false, [HUDModeMenuNext.name]: false,
[HUDModeMenu.name]: false, [HUDModeMenu.name]: false,
[HUDModeSettings.name]: false, [HUDModeSettings.name]: false,
[HUDPuzzleDLCLogo.name]: false, [HUDPuzzleDLCLogo.name]: false,
}); };
this.setBuildings({ this.hiddenBuildings = [MetaConstantProducerBuilding, MetaGoalAcceptorBuilding];
[MetaConstantProducerBuilding.name]: false,
[MetaGoalAcceptorBuilding.name]: false,
[MetaItemProducerBuilding.name]: queryParamOptions.sandboxMode || G_IS_DEV,
});
} }
/** /**

View File

@ -49,25 +49,17 @@ export class GoalAcceptorSystem extends GameSystemWithFilter {
const itemInput = new FormElementInput({ const itemInput = new FormElementInput({
id: "goalItemInput", id: "goalItemInput",
label: fillInLinkIntoTranslation(T.dialogs.editSignal.descShortKey, THIRDPARTY_URLS.shapeViewer), label: fillInLinkIntoTranslation(T.dialogs.editGoalAcceptor.desc, THIRDPARTY_URLS.shapeViewer),
placeholder: "CuCuCuCu", placeholder: "CuCuCuCu",
defaultValue: "CuCuCuCu", defaultValue: "CuCuCuCu",
validator: val => this.parseItem(val), 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({ const dialog = new DialogWithForm({
app: this.root.app, app: this.root.app,
title: "Set Goal", title: T.dialogs.editGoalAcceptor.title,
desc: "", desc: "",
formElements: [itemInput, rateInput], formElements: [itemInput],
buttons: ["cancel:bad:escape", "ok:good:enter"], buttons: ["cancel:bad:escape", "ok:good:enter"],
closeButton: false, closeButton: false,
}); });
@ -79,7 +71,6 @@ export class GoalAcceptorSystem extends GameSystemWithFilter {
} }
goalComp.item = this.parseItem(itemInput.getValue()); goalComp.item = this.parseItem(itemInput.getValue());
goalComp.rate = this.parseRate(rateInput.getValue());
}; };
dialog.buttonSignals.ok.add(closeHandler); dialog.buttonSignals.ok.add(closeHandler);

View File

@ -13,8 +13,12 @@ export class ZoneSystem extends GameSystem {
/** @param {GameRoot} root */ /** @param {GameRoot} root */
constructor(root) { constructor(root) {
super(root); super(root);
this.drawn = false;
this.root.signals.prePlacementCheck.add(this.prePlacementCheck, this); this.root.signals.prePlacementCheck.add(this.prePlacementCheck, this);
this.root.signals.gameFrameStarted.add(() => {
this.drawn = false;
});
} }
prePlacementCheck(entity, tile = null) { prePlacementCheck(entity, tile = null) {
@ -25,18 +29,24 @@ export class ZoneSystem extends GameSystem {
} }
const mode = this.root.gameMode; const mode = this.root.gameMode;
const zone = mode.getZone().expandedInAllDirections(-1);
const zones = mode.getBuildableZones();
if (!zones) {
return;
}
const transformed = staticComp.getTileSpaceBounds(); const transformed = staticComp.getTileSpaceBounds();
if (zone.containsRect(transformed)) { let withinAnyZone = false;
if (mode.isZoneRestricted()) { for (const zone of zones) {
return STOP_PROPAGATION; if (zone.expandedInAllDirections(-1).containsRect(transformed)) {
} withinAnyZone = true;
} else {
if (mode.isBoundaryRestricted()) {
return STOP_PROPAGATION;
} }
} }
if (!withinAnyZone) {
return STOP_PROPAGATION;
}
} }
/** /**
@ -45,18 +55,46 @@ export class ZoneSystem extends GameSystem {
* @param {MapChunkView} chunk * @param {MapChunkView} chunk
*/ */
drawChunk(parameters, chunk) { drawChunk(parameters, chunk) {
if (this.drawn) {
// oof
return;
}
this.drawn = true;
const mode = this.root.gameMode; 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; 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.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; context.globalAlpha = 1;
} }

View File

@ -50,8 +50,10 @@
}, },
"zone": { "zone": {
"background": "#3e3f47", "background": "#fff",
"border": "#667964" "border": "rgba(23, 192, 255, 0.1)",
"borderSolid": "rgba(23, 192, 255, 0.7)",
"outerColor": "rgba(240, 240, 255, 0.5)"
} }
}, },

View File

@ -52,7 +52,9 @@
"zone": { "zone": {
"background": "#fff", "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)"
} }
}, },

View File

@ -184,4 +184,12 @@ export const LANGUAGES = {
code: "uk", code: "uk",
region: "", region: "",
}, },
"he": {
// hebrew
name: "עברית",
data: require("./built-temp/base-he.json"),
code: "he",
region: "",
},
}; };

View File

@ -370,7 +370,13 @@ export class InGameState extends GameState {
// Remove unneded default element // Remove unneded default element
document.body.querySelector(".modalDialogParent").remove(); 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;
});
} }
/** /**

View File

@ -1,3 +1,4 @@
import { globalConfig } from "../core/config";
import { TextualGameState } from "../core/textual_game_state"; import { TextualGameState } from "../core/textual_game_state";
import { formatBigNumberFull } from "../core/utils"; import { formatBigNumberFull } from "../core/utils";
import { enumGameModeIds } from "../game/game_mode"; import { enumGameModeIds } from "../game/game_mode";
@ -206,6 +207,10 @@ export class PuzzleMenuState extends TextualGameState {
} }
this.trackClicks(this.htmlElement.querySelector("button.createPuzzle"), this.createNewPuzzle); this.trackClicks(this.htmlElement.querySelector("button.createPuzzle"), this.createNewPuzzle);
if (G_IS_DEV && globalConfig.debug.testPuzzleMode) {
this.createNewPuzzle();
}
} }
createNewPuzzle() { createNewPuzzle() {

View File

@ -248,6 +248,10 @@ dialogs:
Choose a pre-defined item: Choose a pre-defined item:
descShortKey: ... or enter the <strong>short key</strong> of a shape (Which you can generate <link>here</link>) descShortKey: ... or enter the <strong>short key</strong> of a shape (Which you can generate <link>here</link>)
editGoalAcceptor:
title: Set Goal
desc: Enter the <strong>short key</strong> of a shape (Which you can generate <link>here</link>). The goal will count as completed once 1 item /s is delivered.
markerDemoLimit: markerDemoLimit:
desc: You can only create two custom markers in the demo. Get the standalone for unlimited markers! desc: You can only create two custom markers in the demo. Get the standalone for unlimited markers!

View File

@ -7,13 +7,13 @@ steamPage:
intro: >- intro: >-
אתה אוהב משחקי אוטומציה? אתה במקום הנכון! אתה אוהב משחקי אוטומציה? אתה במקום הנכון!
shapez.io הוא משחק שלווה שבו אתה בונה מפעל בשביל ליצור צורות גאומטריות אוטומטית. ככל שמתקדמים השלבים, הצורות נהיות יותר ויותר מסובכות, ואתה צריך להפתח על המפה האין סופית. shapez.io הוא משחק שלווה שבו אתה בונה מפעל בשביל ליצור צורות גאומטריות אוטומטית. ככל שמתקדמים השלבים, הצורות נהיות יותר ויותר מסובכות, ואתה צריך להפתח על המפה האין סופית.
ואם זה לא היה מספיק, אתה צריך ליצור יותר ויותר צורות בשביל לספק את הדרישה - הדבר היחיד שיכול לעזור זה להגדיל את המפעל! בזמן שבהתחלה אתה רק צריך לערוך צורות, בהמשך אתה צריך לצבוע אותם בעזרת צבעים שאתה מערבב. ואם זה לא היה מספיק, אתה צריך ליצור יותר ויותר צורות בשביל לספק את הדרישה - הדבר היחיד שיכול לעזור זה להגדיל את המפעל! בזמן שבהתחלה אתה רק צריך לערוך צורות, בהמשך אתה צריך לצבוע אותם בעזרת צבעים שאתה מערבב.
קניית המשחק בsteam תתן לך גישה למשחק המלא, אבל אתה יכול לשחק משחק דמו בhttps://shapez.io/ ולהחליט אחר כך. קניית המשחק בsteam תתן לך גישה למשחק המלא, אבל אתה יכול לשחק משחק דמו בhttps://shapez.io/ ולהחליט אחר כך.
what_others_say: What people say about shapez.io what_others_say: What people say about shapez.io
nothernlion_comment: >- nothernlion_comment: >-
@ -85,7 +85,8 @@ mainMenu:
openSourceHint: המשחק הזה הוא עם קוד פתוח! openSourceHint: המשחק הזה הוא עם קוד פתוח!
discordLink: שרת הדסקורד הרשמי discordLink: שרת הדסקורד הרשמי
helpTranslate: תעזור לתרגם! helpTranslate: תעזור לתרגם!
madeBy: יוצר המשחק: <author-link> madeBy: >-
יוצר המשחק: <author-link>
# This is shown when using firefox and other browsers which are not supported. # This is shown when using firefox and other browsers which are not supported.
browserWarning: >- browserWarning: >-
@ -1205,4 +1206,4 @@ tips:
- בשביל לנקות מסוע, חתוך את האיזור ואז תדביק באותו מקום. - בשביל לנקות מסוע, חתוך את האיזור ואז תדביק באותו מקום.
- לחץ F4 בשביל להציג את הFPS ואת הTickRate. - לחץ F4 בשביל להציג את הFPS ואת הTickRate.
- לחץ F4 פעמיים בשביל להציג את המשבצת שהעכבר והמצלמה בהם. - לחץ F4 פעמיים בשביל להציג את המשבצת שהעכבר והמצלמה בהם.
- אתה יכול ללחוץ על צורה מוצמדת בצד שמאל בשביל לבטל את ההצמדה. - אתה יכול ללחוץ על צורה מוצמדת בצד שמאל בשביל לבטל את ההצמדה.