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);
}
if (window.location.host.indexOf("localhost") < 0) {
window.addEventListener("error", errorHandler);
window.addEventListener("unhandledrejection", errorHandler);
}
function makeJsTag(src, integrity) {
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 {
@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;
}
}
}

View File

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

View File

@ -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 */

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_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,

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,
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}"] {

View File

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

View File

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

View File

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

View File

@ -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);
}
/**

View File

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

View File

@ -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");
}
/**

View File

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

View File

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

View File

@ -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:

View File

@ -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,

View File

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

View File

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

View File

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

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
*/
switchLayers() {
if (!this.root.gameMode.getSupportsWires()) {
return;
}
if (this.root.currentLayer === "regular") {
if (
this.root.hubGoals.isRewardUnlocked(enumHubGoalRewards.reward_wires_painter_and_levers) ||

View File

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

View File

@ -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;
getCameraBounds() {
return this.createCenteredRectangle(this.zoneWidth + 20, this.zoneHeight + 20);
}
this.bounds = this.createCenteredRectangle(this.boundsWidth, this.boundsHeight);
return this.bounds;
}
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;

View File

@ -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) {

View File

@ -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];
}
/**

View File

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

View File

@ -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,17 +29,23 @@ 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;
let withinAnyZone = false;
for (const zone of zones) {
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
*/
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;
}

View File

@ -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)"
}
},

View File

@ -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)"
}
},

View File

@ -184,4 +184,12 @@ export const LANGUAGES = {
code: "uk",
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
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 { 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() {

View File

@ -248,6 +248,10 @@ dialogs:
Choose a pre-defined item:
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:
desc: You can only create two custom markers in the demo. Get the standalone for unlimited markers!

View File

@ -85,7 +85,8 @@ mainMenu:
openSourceHint: המשחק הזה הוא עם קוד פתוח!
discordLink: שרת הדסקורד הרשמי
helpTranslate: תעזור לתרגם!
madeBy: יוצר המשחק: <author-link>
madeBy: >-
יוצר המשחק: <author-link>
# This is shown when using firefox and other browsers which are not supported.
browserWarning: >-