mirror of
https://github.com/tobspr/shapez.io.git
synced 2025-06-13 13:04:03 +00:00
[Puzzle] Added ability to lock buildings in the puzzle editor! (#1164)
* initial test * tried to get it to work * added icon * added test exclusion * reverted css * completed flow for building locking * added lock option * finalized look and changed locked building to same sprite * removed unused art * added clearing every goal acceptor on lock to prevent creating impossible puzzles * heavily improved validation and prevented autocompletion * validation only checks every 100 ticks to improve performance * validation only checks every 100 ticks to improve performance * removed clearing goal acceptors as it isn't needed because of validation
This commit is contained in:
parent
8e25818999
commit
0f93e13a63
@ -49,63 +49,94 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.building {
|
.building {
|
||||||
color: $accentColorDark;
|
.icon {
|
||||||
display: flex;
|
color: $accentColorDark;
|
||||||
flex-direction: column;
|
display: flex;
|
||||||
position: relative;
|
flex-direction: column-reverse;
|
||||||
align-items: center;
|
position: relative;
|
||||||
justify-content: center;
|
align-items: center;
|
||||||
@include S(padding, 5px);
|
justify-content: center;
|
||||||
@include S(padding-bottom, 1px);
|
@include S(padding, 5px);
|
||||||
@include S(width, 35px);
|
@include S(padding-bottom, 1px);
|
||||||
@include S(height, 40px);
|
@include S(width, 35px);
|
||||||
|
@include S(height, 37px);
|
||||||
|
@include S(border-radius, $globalBorderRadius);
|
||||||
|
|
||||||
background: center center / 70% no-repeat;
|
background: center center / 70% no-repeat;
|
||||||
|
}
|
||||||
|
|
||||||
&:not(.unlocked) {
|
&:not(.unlocked) {
|
||||||
@include S(width, 20px);
|
.icon {
|
||||||
opacity: 0.15;
|
@include S(width, 20px);
|
||||||
background-image: none !important;
|
opacity: 0.15;
|
||||||
|
}
|
||||||
&::before {
|
&.editor {
|
||||||
content: " ";
|
.icon {
|
||||||
|
pointer-events: all;
|
||||||
position: absolute;
|
cursor: pointer;
|
||||||
top: 0;
|
&:hover {
|
||||||
right: 0;
|
background-color: rgba(22, 30, 68, 0.1);
|
||||||
bottom: 0;
|
}
|
||||||
left: 0;
|
}
|
||||||
z-index: 4;
|
}
|
||||||
& {
|
&:not(.editor) {
|
||||||
/* @load-async */
|
.icon {
|
||||||
background: uiResource("locked_building.png") center center / #{D(20px)} #{D(20px)}
|
background-image: uiResource("locked_building.png") !important;
|
||||||
no-repeat;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@include S(border-radius, $globalBorderRadius);
|
|
||||||
|
|
||||||
&.unlocked {
|
&.unlocked {
|
||||||
pointer-events: all;
|
.icon {
|
||||||
transition: all 50ms ease-in-out;
|
pointer-events: all;
|
||||||
transition-property: background-color, transform;
|
transition: all 50ms ease-in-out;
|
||||||
|
transition-property: background-color, transform;
|
||||||
|
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
&:hover {
|
&:hover {
|
||||||
background-color: rgba(30, 40, 90, 0.1);
|
background-color: rgba(30, 40, 90, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.pressed {
|
||||||
|
transform: scale(0.9) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.selected {
|
||||||
|
// transform: scale(1.05);
|
||||||
|
background-color: rgba(lighten($colorBlueBright, 9), 0.4);
|
||||||
|
|
||||||
|
.keybinding {
|
||||||
|
color: #111;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&.pressed {
|
.puzzle-lock {
|
||||||
transform: scale(0.9) !important;
|
& {
|
||||||
}
|
/* @load-async */
|
||||||
|
background: uiResource("locked_building.png") center center / #{D(14px)} #{D(14px)}
|
||||||
|
no-repeat;
|
||||||
|
}
|
||||||
|
|
||||||
&.selected {
|
display: grid;
|
||||||
// transform: scale(1.05);
|
grid-auto-flow: column;
|
||||||
background-color: rgba(lighten($colorBlueBright, 9), 0.4);
|
@include S(margin-top, 2px);
|
||||||
|
@include S(margin-left, 16px);
|
||||||
|
@include S(margin-bottom, 29px);
|
||||||
|
|
||||||
.keybinding {
|
position: absolute;
|
||||||
color: #111;
|
bottom: 20px;
|
||||||
|
transition: all 0.12s ease-in-out;
|
||||||
|
transition-property: opacity, transform;
|
||||||
|
|
||||||
|
cursor: pointer;
|
||||||
|
pointer-events: all;
|
||||||
|
|
||||||
|
@include S(width, 14px);
|
||||||
|
@include S(height, 14px);
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
opacity: 0.5;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,9 @@ $buildings: belt, cutter, miner, mixer, painter, rotater, balancer, stacker, tra
|
|||||||
@each $building in $buildings {
|
@each $building in $buildings {
|
||||||
[data-icon="building_icons/#{$building}.png"] {
|
[data-icon="building_icons/#{$building}.png"] {
|
||||||
/* @load-async */
|
/* @load-async */
|
||||||
background-image: uiResource("res/ui/building_icons/#{$building}.png") !important;
|
.icon {
|
||||||
|
background-image: uiResource("res/ui/building_icons/#{$building}.png") !important;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,10 @@
|
|||||||
import { gMetaBuildingRegistry } from "../../../core/global_registries";
|
import { gMetaBuildingRegistry } from "../../../core/global_registries";
|
||||||
import { STOP_PROPAGATION } from "../../../core/signal";
|
import { STOP_PROPAGATION } from "../../../core/signal";
|
||||||
import { makeDiv, safeModulo } from "../../../core/utils";
|
import { makeDiv, safeModulo } from "../../../core/utils";
|
||||||
|
import { MetaBlockBuilding } from "../../buildings/block";
|
||||||
|
import { MetaConstantProducerBuilding } from "../../buildings/constant_producer";
|
||||||
|
import { MetaGoalAcceptorBuilding } from "../../buildings/goal_acceptor";
|
||||||
|
import { StaticMapEntityComponent } from "../../components/static_map_entity";
|
||||||
import { KEYMAPPINGS } from "../../key_action_mapper";
|
import { KEYMAPPINGS } from "../../key_action_mapper";
|
||||||
import { MetaBuilding } from "../../meta_building";
|
import { MetaBuilding } from "../../meta_building";
|
||||||
import { GameRoot } from "../../root";
|
import { GameRoot } from "../../root";
|
||||||
@ -35,6 +39,8 @@ export class HUDBaseToolbar extends BaseHUDPart {
|
|||||||
* selected: boolean,
|
* selected: boolean,
|
||||||
* element: HTMLElement,
|
* element: HTMLElement,
|
||||||
* index: number
|
* index: number
|
||||||
|
* puzzleLocked: boolean;
|
||||||
|
* class: typeof MetaBuilding,
|
||||||
* }>} */
|
* }>} */
|
||||||
this.buildingHandles = {};
|
this.buildingHandles = {};
|
||||||
}
|
}
|
||||||
@ -105,19 +111,32 @@ export class HUDBaseToolbar extends BaseHUDPart {
|
|||||||
);
|
);
|
||||||
itemContainer.setAttribute("data-icon", "building_icons/" + metaBuilding.getId() + ".png");
|
itemContainer.setAttribute("data-icon", "building_icons/" + metaBuilding.getId() + ".png");
|
||||||
itemContainer.setAttribute("data-id", metaBuilding.getId());
|
itemContainer.setAttribute("data-id", metaBuilding.getId());
|
||||||
|
|
||||||
binding.add(() => this.selectBuildingForPlacement(metaBuilding));
|
binding.add(() => this.selectBuildingForPlacement(metaBuilding));
|
||||||
|
|
||||||
this.trackClicks(itemContainer, () => this.selectBuildingForPlacement(metaBuilding), {
|
const icon = makeDiv(itemContainer, null, ["icon"]);
|
||||||
|
|
||||||
|
this.trackClicks(icon, () => this.selectBuildingForPlacement(metaBuilding), {
|
||||||
clickSound: null,
|
clickSound: null,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
//lock icon for puzzle editor
|
||||||
|
if (this.root.gameMode.getIsEditor() && !this.inRequiredBuildings(metaBuilding)) {
|
||||||
|
const puzzleLock = makeDiv(itemContainer, null, ["puzzle-lock"]);
|
||||||
|
|
||||||
|
itemContainer.classList.toggle("editor", true);
|
||||||
|
this.trackClicks(puzzleLock, () => this.toggleBuildingLock(metaBuilding), {
|
||||||
|
clickSound: null,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
this.buildingHandles[metaBuilding.id] = {
|
this.buildingHandles[metaBuilding.id] = {
|
||||||
metaBuilding,
|
metaBuilding: metaBuilding,
|
||||||
element: itemContainer,
|
element: itemContainer,
|
||||||
unlocked: false,
|
unlocked: false,
|
||||||
selected: false,
|
selected: false,
|
||||||
index: i,
|
index: i,
|
||||||
|
puzzleLocked: false,
|
||||||
|
class: allBuildings[i],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -145,7 +164,7 @@ export class HUDBaseToolbar extends BaseHUDPart {
|
|||||||
let recomputeSecondaryToolbarVisibility = false;
|
let recomputeSecondaryToolbarVisibility = false;
|
||||||
for (const buildingId in this.buildingHandles) {
|
for (const buildingId in this.buildingHandles) {
|
||||||
const handle = this.buildingHandles[buildingId];
|
const handle = this.buildingHandles[buildingId];
|
||||||
const newStatus = handle.metaBuilding.getIsUnlocked(this.root);
|
const newStatus = !handle.puzzleLocked && handle.metaBuilding.getIsUnlocked(this.root);
|
||||||
if (handle.unlocked !== newStatus) {
|
if (handle.unlocked !== newStatus) {
|
||||||
handle.unlocked = newStatus;
|
handle.unlocked = newStatus;
|
||||||
handle.element.classList.toggle("unlocked", newStatus);
|
handle.element.classList.toggle("unlocked", newStatus);
|
||||||
@ -234,6 +253,14 @@ export class HUDBaseToolbar extends BaseHUDPart {
|
|||||||
return STOP_PROPAGATION;
|
return STOP_PROPAGATION;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const handle = this.buildingHandles[metaBuilding.getId()];
|
||||||
|
if (handle.puzzleLocked) {
|
||||||
|
handle.puzzleLocked = false;
|
||||||
|
handle.element.classList.toggle("unlocked", false);
|
||||||
|
this.root.soundProxy.playUiClick();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Allow clicking an item again to deselect it
|
// Allow clicking an item again to deselect it
|
||||||
for (const buildingId in this.buildingHandles) {
|
for (const buildingId in this.buildingHandles) {
|
||||||
const handle = this.buildingHandles[buildingId];
|
const handle = this.buildingHandles[buildingId];
|
||||||
@ -247,4 +274,51 @@ export class HUDBaseToolbar extends BaseHUDPart {
|
|||||||
this.root.hud.signals.buildingSelectedForPlacement.dispatch(metaBuilding);
|
this.root.hud.signals.buildingSelectedForPlacement.dispatch(metaBuilding);
|
||||||
this.onSelectedPlacementBuildingChanged(metaBuilding);
|
this.onSelectedPlacementBuildingChanged(metaBuilding);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {MetaBuilding} metaBuilding
|
||||||
|
*/
|
||||||
|
toggleBuildingLock(metaBuilding) {
|
||||||
|
if (!this.visibilityCondition()) {
|
||||||
|
// Not active
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.inRequiredBuildings(metaBuilding) || !metaBuilding.getIsUnlocked(this.root)) {
|
||||||
|
this.root.soundProxy.playUiError();
|
||||||
|
return STOP_PROPAGATION;
|
||||||
|
}
|
||||||
|
|
||||||
|
const handle = this.buildingHandles[metaBuilding.getId()];
|
||||||
|
handle.puzzleLocked = !handle.puzzleLocked;
|
||||||
|
handle.element.classList.toggle("unlocked", !handle.puzzleLocked);
|
||||||
|
this.root.soundProxy.playUiClick();
|
||||||
|
|
||||||
|
const entityManager = this.root.entityMgr;
|
||||||
|
for (const entity of entityManager.getAllWithComponent(StaticMapEntityComponent)) {
|
||||||
|
const staticComp = entity.components.StaticMapEntity;
|
||||||
|
if (staticComp.getMetaBuilding().id === metaBuilding.id) {
|
||||||
|
this.root.map.removeStaticEntity(entity);
|
||||||
|
entityManager.destroyEntity(entity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
entityManager.processDestroyList();
|
||||||
|
|
||||||
|
const currentMetaBuilding = this.root.hud.parts.buildingPlacer.currentMetaBuilding;
|
||||||
|
if (currentMetaBuilding.get() == metaBuilding) {
|
||||||
|
currentMetaBuilding.set(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {MetaBuilding} metaBuilding
|
||||||
|
*/
|
||||||
|
inRequiredBuildings(metaBuilding) {
|
||||||
|
const requiredBuildings = [
|
||||||
|
gMetaBuildingRegistry.findByClass(MetaConstantProducerBuilding),
|
||||||
|
gMetaBuildingRegistry.findByClass(MetaGoalAcceptorBuilding),
|
||||||
|
gMetaBuildingRegistry.findByClass(MetaBlockBuilding),
|
||||||
|
];
|
||||||
|
return requiredBuildings.includes(metaBuilding);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -49,23 +49,27 @@ export class HUDPuzzleEditorReview extends BaseHUDPart {
|
|||||||
// Manually simulate ticks
|
// Manually simulate ticks
|
||||||
this.root.logic.clearAllBeltsAndItems();
|
this.root.logic.clearAllBeltsAndItems();
|
||||||
|
|
||||||
const ticks =
|
const maxTicks =
|
||||||
this.root.gameMode.getFixedTickrate() * globalConfig.puzzleValidationDurationSeconds;
|
this.root.gameMode.getFixedTickrate() * globalConfig.puzzleValidationDurationSeconds;
|
||||||
const deltaMs = this.root.dynamicTickrate.deltaMs;
|
const deltaMs = this.root.dynamicTickrate.deltaMs;
|
||||||
logger.log("Simulating", ticks, "ticks, start=", this.root.time.now().toFixed(1));
|
logger.log("Simulating up to", maxTicks, "ticks, start=", this.root.time.now().toFixed(1));
|
||||||
const now = performance.now();
|
const now = performance.now();
|
||||||
for (let i = 0; i < ticks; ++i) {
|
|
||||||
if (i % Math.round((ticks - 1) / 10) === 0) {
|
|
||||||
console.log("Ticking", Math.round((i / ticks) * 100) + "%");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Perform logic ticks
|
let simulatedTicks = 0;
|
||||||
|
for (let i = 0; i < maxTicks; ++i) {
|
||||||
|
// Perform logic tick
|
||||||
this.root.time.performTicks(deltaMs, this.root.gameState.core.boundInternalTick);
|
this.root.time.performTicks(deltaMs, this.root.gameState.core.boundInternalTick);
|
||||||
|
simulatedTicks++;
|
||||||
|
|
||||||
|
if (simulatedTicks % 100 == 0 && !this.validatePuzzle()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const duration = performance.now() - now;
|
const duration = performance.now() - now;
|
||||||
logger.log(
|
logger.log(
|
||||||
"Simulated",
|
"Simulated",
|
||||||
ticks,
|
simulatedTicks,
|
||||||
"ticks, end=",
|
"ticks, end=",
|
||||||
this.root.time.now().toFixed(1),
|
this.root.time.now().toFixed(1),
|
||||||
"duration=",
|
"duration=",
|
||||||
@ -73,9 +77,21 @@ export class HUDPuzzleEditorReview extends BaseHUDPart {
|
|||||||
"ms"
|
"ms"
|
||||||
);
|
);
|
||||||
|
|
||||||
|
console.log("duration: " + duration);
|
||||||
closeLoading();
|
closeLoading();
|
||||||
|
|
||||||
|
//if it took so little ticks that it must have autocompeted
|
||||||
|
if (simulatedTicks <= 300) {
|
||||||
|
this.root.hud.parts.dialogs.showWarning(
|
||||||
|
T.puzzleMenu.validation.title,
|
||||||
|
T.puzzleMenu.validation.autoComplete
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//if we reached maximum ticks and the puzzle still isn't completed
|
||||||
const validationError = this.validatePuzzle();
|
const validationError = this.validatePuzzle();
|
||||||
if (validationError) {
|
if (simulatedTicks == maxTicks && validationError) {
|
||||||
this.root.hud.parts.dialogs.showWarning(T.puzzleMenu.validation.title, validationError);
|
this.root.hud.parts.dialogs.showWarning(T.puzzleMenu.validation.title, validationError);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,9 @@ import { types } from "../../savegame/serialization";
|
|||||||
import { enumGameModeTypes, GameMode } from "../game_mode";
|
import { enumGameModeTypes, GameMode } from "../game_mode";
|
||||||
import { HUDPuzzleBackToMenu } from "../hud/parts/puzzle_back_to_menu";
|
import { HUDPuzzleBackToMenu } from "../hud/parts/puzzle_back_to_menu";
|
||||||
import { HUDPuzzleDLCLogo } from "../hud/parts/puzzle_dlc_logo";
|
import { HUDPuzzleDLCLogo } from "../hud/parts/puzzle_dlc_logo";
|
||||||
|
import { gMetaBuildingRegistry } from "../../core/global_registries";
|
||||||
|
import { MetaBalancerBuilding } from "../buildings/balancer";
|
||||||
|
import { MetaUndergroundBeltBuilding } from "../buildings/underground_belt";
|
||||||
|
|
||||||
export class PuzzleGameMode extends GameMode {
|
export class PuzzleGameMode extends GameMode {
|
||||||
static getType() {
|
static getType() {
|
||||||
@ -36,6 +39,13 @@ export class PuzzleGameMode extends GameMode {
|
|||||||
this.zoneHeight = data.zoneHeight || 6;
|
this.zoneHeight = data.zoneHeight || 6;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {typeof import("../meta_building").MetaBuilding} building
|
||||||
|
*/
|
||||||
|
isBuildingExcluded(building) {
|
||||||
|
return this.hiddenBuildings.indexOf(building) >= 0;
|
||||||
|
}
|
||||||
|
|
||||||
getSaveData() {
|
getSaveData() {
|
||||||
const save = this.root.savegame.getCurrentDump();
|
const save = this.root.savegame.getCurrentDump();
|
||||||
if (!save) {
|
if (!save) {
|
||||||
|
@ -28,6 +28,7 @@ import { createLogger } from "../../core/logging";
|
|||||||
import { HUDPuzzleCompleteNotification } from "../hud/parts/puzzle_complete_notification";
|
import { HUDPuzzleCompleteNotification } from "../hud/parts/puzzle_complete_notification";
|
||||||
import { HUDPuzzlePlaySettings } from "../hud/parts/puzzle_play_settings";
|
import { HUDPuzzlePlaySettings } from "../hud/parts/puzzle_play_settings";
|
||||||
import { MetaBlockBuilding } from "../buildings/block";
|
import { MetaBlockBuilding } from "../buildings/block";
|
||||||
|
import { MetaBuilding } from "../meta_building";
|
||||||
|
|
||||||
const logger = createLogger("puzzle-play");
|
const logger = createLogger("puzzle-play");
|
||||||
const copy = require("clipboard-copy");
|
const copy = require("clipboard-copy");
|
||||||
@ -45,7 +46,8 @@ export class PuzzlePlayGameMode extends PuzzleGameMode {
|
|||||||
constructor(root, { puzzle }) {
|
constructor(root, { puzzle }) {
|
||||||
super(root);
|
super(root);
|
||||||
|
|
||||||
this.hiddenBuildings = [
|
/** @type {Array<typeof MetaBuilding>} */
|
||||||
|
const excludedBuildings = [
|
||||||
MetaConstantProducerBuilding,
|
MetaConstantProducerBuilding,
|
||||||
MetaGoalAcceptorBuilding,
|
MetaGoalAcceptorBuilding,
|
||||||
MetaBlockBuilding,
|
MetaBlockBuilding,
|
||||||
@ -68,6 +70,8 @@ export class PuzzlePlayGameMode extends PuzzleGameMode {
|
|||||||
MetaTransistorBuilding,
|
MetaTransistorBuilding,
|
||||||
];
|
];
|
||||||
|
|
||||||
|
this.hiddenBuildings = excludedBuildings.concat(puzzle.game.excludedBuildings);
|
||||||
|
|
||||||
this.additionalHudParts.puzzlePlayMetadata = HUDPuzzlePlayMetadata;
|
this.additionalHudParts.puzzlePlayMetadata = HUDPuzzlePlayMetadata;
|
||||||
this.additionalHudParts.puzzlePlaySettings = HUDPuzzlePlaySettings;
|
this.additionalHudParts.puzzlePlaySettings = HUDPuzzlePlaySettings;
|
||||||
this.additionalHudParts.puzzleCompleteNotification = HUDPuzzleCompleteNotification;
|
this.additionalHudParts.puzzleCompleteNotification = HUDPuzzleCompleteNotification;
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
/* typehints:start */
|
/* typehints:start */
|
||||||
import { GameRoot } from "../root";
|
import { GameRoot } from "../root";
|
||||||
|
import { MetaBuilding } from "../meta_building";
|
||||||
/* typehints:end */
|
/* typehints:end */
|
||||||
|
|
||||||
import { findNiceIntegerValue } from "../../core/utils";
|
import { findNiceIntegerValue } from "../../core/utils";
|
||||||
@ -582,6 +583,7 @@ export class RegularGameMode extends GameMode {
|
|||||||
this.additionalHudParts.sandboxController = HUDSandboxController;
|
this.additionalHudParts.sandboxController = HUDSandboxController;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @type {(typeof MetaBuilding)[]} */
|
||||||
this.hiddenBuildings = [MetaConstantProducerBuilding, MetaGoalAcceptorBuilding, MetaBlockBuilding];
|
this.hiddenBuildings = [MetaConstantProducerBuilding, MetaGoalAcceptorBuilding, MetaBlockBuilding];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@ import { StaticMapEntityComponent } from "../game/components/static_map_entity";
|
|||||||
import { ShapeItem } from "../game/items/shape_item";
|
import { ShapeItem } from "../game/items/shape_item";
|
||||||
import { Vector } from "../core/vector";
|
import { Vector } from "../core/vector";
|
||||||
import { MetaConstantProducerBuilding } from "../game/buildings/constant_producer";
|
import { MetaConstantProducerBuilding } from "../game/buildings/constant_producer";
|
||||||
import { defaultBuildingVariant } from "../game/meta_building";
|
import { defaultBuildingVariant, MetaBuilding } from "../game/meta_building";
|
||||||
import { gMetaBuildingRegistry } from "../core/global_registries";
|
import { gMetaBuildingRegistry } from "../core/global_registries";
|
||||||
import { MetaGoalAcceptorBuilding } from "../game/buildings/goal_acceptor";
|
import { MetaGoalAcceptorBuilding } from "../game/buildings/goal_acceptor";
|
||||||
import { createLogger } from "../core/logging";
|
import { createLogger } from "../core/logging";
|
||||||
@ -33,7 +33,6 @@ export class PuzzleSerializer {
|
|||||||
* @type {import("./savegame_typedefs").PuzzleGameData["buildings"]}
|
* @type {import("./savegame_typedefs").PuzzleGameData["buildings"]}
|
||||||
*/
|
*/
|
||||||
let buildings = [];
|
let buildings = [];
|
||||||
|
|
||||||
for (const entity of root.entityMgr.getAllWithComponent(StaticMapEntityComponent)) {
|
for (const entity of root.entityMgr.getAllWithComponent(StaticMapEntityComponent)) {
|
||||||
const staticComp = entity.components.StaticMapEntity;
|
const staticComp = entity.components.StaticMapEntity;
|
||||||
const signalComp = entity.components.ConstantSignal;
|
const signalComp = entity.components.ConstantSignal;
|
||||||
@ -83,6 +82,18 @@ export class PuzzleSerializer {
|
|||||||
|
|
||||||
const mode = /** @type {PuzzleGameMode} */ (root.gameMode);
|
const mode = /** @type {PuzzleGameMode} */ (root.gameMode);
|
||||||
|
|
||||||
|
const handles = root.hud.parts.buildingsToolbar.buildingHandles;
|
||||||
|
const ids = gMetaBuildingRegistry.getAllIds();
|
||||||
|
|
||||||
|
/** @type {Array<typeof MetaBuilding>} */
|
||||||
|
let excludedBuildings = [];
|
||||||
|
for (let i = 0; i < ids.length; ++i) {
|
||||||
|
const handle = handles[ids[i]];
|
||||||
|
if (handle && handle.puzzleLocked) {
|
||||||
|
excludedBuildings.push(handle.class);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
version: 1,
|
version: 1,
|
||||||
buildings,
|
buildings,
|
||||||
@ -90,6 +101,8 @@ export class PuzzleSerializer {
|
|||||||
w: mode.zoneWidth,
|
w: mode.zoneWidth,
|
||||||
h: mode.zoneHeight,
|
h: mode.zoneHeight,
|
||||||
},
|
},
|
||||||
|
//read from the toolbar when making a puzzle
|
||||||
|
excludedBuildings,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -41,6 +41,8 @@
|
|||||||
* }} SavegamesData
|
* }} SavegamesData
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import { MetaBuilding } from "../game/meta_building";
|
||||||
|
|
||||||
// Notice: Update backend too
|
// Notice: Update backend too
|
||||||
/**
|
/**
|
||||||
* @typedef {{
|
* @typedef {{
|
||||||
@ -84,7 +86,8 @@
|
|||||||
* @typedef {{
|
* @typedef {{
|
||||||
* version: number;
|
* version: number;
|
||||||
* bounds: { w: number; h: number; },
|
* bounds: { w: number; h: number; },
|
||||||
* buildings: (PuzzleGameBuildingGoal | PuzzleGameBuildingConstantProducer | PuzzleGameBuildingBlock)[]
|
* buildings: (PuzzleGameBuildingGoal | PuzzleGameBuildingConstantProducer | PuzzleGameBuildingBlock)[],
|
||||||
|
* excludedBuildings: Array<typeof MetaBuilding>,
|
||||||
* }} PuzzleGameData
|
* }} PuzzleGameData
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -151,6 +151,8 @@ puzzleMenu:
|
|||||||
One or more Goal Acceptors are not getting enough items. Make sure that the indicators are green for all acceptors.
|
One or more Goal Acceptors are not getting enough items. Make sure that the indicators are green for all acceptors.
|
||||||
buildingOutOfBounds: >-
|
buildingOutOfBounds: >-
|
||||||
One or more buildings are outside of the buildable area. Either increase the area or remove them.
|
One or more buildings are outside of the buildable area. Either increase the area or remove them.
|
||||||
|
autoComplete: >-
|
||||||
|
Your puzzle autocompletes itself! Please make sure your constant producers are not directly delivering to your goal acceptors.
|
||||||
|
|
||||||
dialogs:
|
dialogs:
|
||||||
buttons:
|
buttons:
|
||||||
|
Loading…
Reference in New Issue
Block a user