1
0
mirror of https://github.com/tobspr/shapez.io.git synced 2025-06-13 13:04:03 +00:00
tobspr_shapez.io/src/js/game/hud/parts/mass_selector.js

295 lines
11 KiB
JavaScript
Raw Normal View History

import { BaseHUDPart } from "../base_hud_part";
2020-05-10 16:24:50 +00:00
import { Vector } from "../../../core/vector";
import { STOP_PROPAGATION } from "../../../core/signal";
import { DrawParameters } from "../../../core/draw_parameters";
import { Entity } from "../../entity";
import { Loader } from "../../../core/loader";
import { globalConfig } from "../../../core/config";
2020-05-27 12:30:59 +00:00
import { makeDiv, formatBigNumber, formatBigNumberFull } from "../../../core/utils";
2020-05-10 16:24:50 +00:00
import { DynamicDomAttach } from "../dynamic_dom_attach";
import { createLogger } from "../../../core/logging";
2020-05-17 08:07:20 +00:00
import { enumMouseButton } from "../../camera";
2020-05-17 10:12:13 +00:00
import { T } from "../../../translations";
import { KEYMAPPINGS } from "../../key_action_mapper";
2020-05-27 12:30:59 +00:00
import { THEME } from "../../theme";
import { enumHubGoalRewards } from "../../tutorial_goals";
2020-05-10 16:24:50 +00:00
const logger = createLogger("hud/mass_selector");
export class HUDMassSelector extends BaseHUDPart {
createElements(parent) {}
2020-05-10 16:24:50 +00:00
initialize() {
this.deletionMarker = Loader.getSprite("sprites/misc/deletion_marker.png");
2020-05-31 22:07:01 +00:00
this.currentSelectionStartWorld = null;
2020-05-10 16:24:50 +00:00
this.currentSelectionEnd = null;
2020-05-27 12:30:59 +00:00
this.selectedUids = new Set();
2020-05-10 16:24:50 +00:00
this.root.signals.entityQueuedForDestroy.add(this.onEntityDestroyed, this);
this.root.hud.signals.pasteBlueprintRequested.add(this.clearSelection, this);
2020-05-10 16:24:50 +00:00
this.root.camera.downPreHandler.add(this.onMouseDown, this);
this.root.camera.movePreHandler.add(this.onMouseMove, this);
this.root.camera.upPostHandler.add(this.onMouseUp, this);
this.root.keyMapper.getBinding(KEYMAPPINGS.general.back).add(this.onBack, this);
this.root.keyMapper
.getBinding(KEYMAPPINGS.massSelect.confirmMassDelete)
.add(this.confirmDelete, this);
2020-06-11 06:19:44 +00:00
this.root.keyMapper.getBinding(KEYMAPPINGS.massSelect.massSelectCut).add(this.confirmCut, this);
2020-05-27 12:30:59 +00:00
this.root.keyMapper.getBinding(KEYMAPPINGS.massSelect.massSelectCopy).add(this.startCopy, this);
2020-05-10 16:24:50 +00:00
this.root.hud.signals.selectedPlacementBuildingChanged.add(this.clearSelection, this);
2020-05-10 16:24:50 +00:00
}
/**
* Handles the destroy callback and makes sure we clean our list
* @param {Entity} entity
*/
onEntityDestroyed(entity) {
2020-05-27 12:30:59 +00:00
this.selectedUids.delete(entity.uid);
2020-05-10 16:24:50 +00:00
}
/**
*
*/
onBack() {
// Clear entities on escape
2020-05-27 12:30:59 +00:00
if (this.selectedUids.size > 0) {
this.selectedUids = new Set();
2020-05-10 16:24:50 +00:00
return STOP_PROPAGATION;
}
}
/**
* Clears the entire selection
*/
clearSelection() {
this.selectedUids = new Set();
}
2020-05-10 16:24:50 +00:00
confirmDelete() {
if (
!this.root.app.settings.getAllSettings().disableCutDeleteWarnings &&
this.selectedUids.size > 100
) {
2020-05-27 12:30:59 +00:00
const { ok } = this.root.hud.parts.dialogs.showWarning(
T.dialogs.massDeleteConfirm.title,
T.dialogs.massDeleteConfirm.desc.replace(
"<count>",
"" + formatBigNumberFull(this.selectedUids.size)
),
["cancel:good:escape", "ok:bad:enter"]
2020-05-27 12:30:59 +00:00
);
ok.add(() => this.doDelete());
} else {
this.doDelete();
}
}
doDelete() {
const entityUids = Array.from(this.selectedUids);
2020-05-10 16:24:50 +00:00
for (let i = 0; i < entityUids.length; ++i) {
const uid = entityUids[i];
const entity = this.root.entityMgr.findByUid(uid);
if (!this.root.logic.tryDeleteBuilding(entity)) {
logger.error("Error in mass delete, could not remove building");
2020-05-27 12:30:59 +00:00
this.selectedUids.delete(uid);
2020-05-10 16:24:50 +00:00
}
}
}
2020-05-27 12:30:59 +00:00
startCopy() {
if (this.selectedUids.size > 0) {
if (!this.root.hubGoals.isRewardUnlocked(enumHubGoalRewards.reward_blueprints)) {
this.root.hud.parts.dialogs.showInfo(
T.dialogs.blueprintsNotUnlocked.title,
T.dialogs.blueprintsNotUnlocked.desc
);
return;
}
2020-05-27 12:30:59 +00:00
this.root.hud.signals.buildingsSelectedForCopy.dispatch(Array.from(this.selectedUids));
this.selectedUids = new Set();
this.root.soundProxy.playUiClick();
} else {
this.root.soundProxy.playUiError();
2020-06-11 06:19:44 +00:00
}
}
confirmCut() {
if (!this.root.hubGoals.isRewardUnlocked(enumHubGoalRewards.reward_blueprints)) {
this.root.hud.parts.dialogs.showInfo(
T.dialogs.blueprintsNotUnlocked.title,
T.dialogs.blueprintsNotUnlocked.desc
);
} else if (
!this.root.app.settings.getAllSettings().disableCutDeleteWarnings &&
this.selectedUids.size > 100
) {
2020-06-11 06:19:44 +00:00
const { ok } = this.root.hud.parts.dialogs.showWarning(
T.dialogs.massCutConfirm.title,
T.dialogs.massCutConfirm.desc.replace(
"<count>",
"" + formatBigNumberFull(this.selectedUids.size)
),
["cancel:good:escape", "ok:bad:enter"]
2020-06-11 06:19:44 +00:00
);
ok.add(() => this.doCut());
} else {
this.doCut();
}
}
doCut() {
if (this.selectedUids.size > 0) {
const entityUids = Array.from(this.selectedUids);
// copy code relies on entities still existing, so must copy before deleting.
this.root.hud.signals.buildingsSelectedForCopy.dispatch(entityUids);
for (let i = 0; i < entityUids.length; ++i) {
const uid = entityUids[i];
const entity = this.root.entityMgr.findByUid(uid);
if (!this.root.logic.tryDeleteBuilding(entity)) {
logger.error("Error in mass cut, could not remove building");
this.selectedUids.delete(uid);
}
}
this.root.soundProxy.playUiClick();
} else {
this.root.soundProxy.playUiError();
2020-05-27 12:30:59 +00:00
}
}
2020-05-10 16:24:50 +00:00
/**
* mouse down pre handler
* @param {Vector} pos
2020-05-17 08:07:20 +00:00
* @param {enumMouseButton} mouseButton
2020-05-10 16:24:50 +00:00
*/
2020-05-17 08:07:20 +00:00
onMouseDown(pos, mouseButton) {
2020-06-17 11:12:39 +00:00
if (!this.root.keyMapper.getBinding(KEYMAPPINGS.massSelect.massSelectStart).pressed) {
2020-05-10 16:24:50 +00:00
return;
2020-05-17 08:07:20 +00:00
}
if (mouseButton !== enumMouseButton.left) {
return;
2020-05-10 16:24:50 +00:00
}
2020-06-17 11:12:39 +00:00
if (!this.root.keyMapper.getBinding(KEYMAPPINGS.massSelect.massSelectSelectMultiple).pressed) {
2020-05-10 16:24:50 +00:00
// Start new selection
2020-05-27 12:30:59 +00:00
this.selectedUids = new Set();
2020-05-10 16:24:50 +00:00
}
this.currentSelectionStartWorld = this.root.camera.screenToWorld(pos.copy());
2020-05-10 16:24:50 +00:00
this.currentSelectionEnd = pos.copy();
return STOP_PROPAGATION;
}
/**
* mouse move pre handler
* @param {Vector} pos
*/
onMouseMove(pos) {
if (this.currentSelectionStartWorld) {
2020-05-10 16:24:50 +00:00
this.currentSelectionEnd = pos.copy();
}
}
onMouseUp() {
if (this.currentSelectionStartWorld) {
2020-05-31 22:07:01 +00:00
const worldStart = this.currentSelectionStartWorld;
2020-05-10 16:24:50 +00:00
const worldEnd = this.root.camera.screenToWorld(this.currentSelectionEnd);
const tileStart = worldStart.toTileSpace();
const tileEnd = worldEnd.toTileSpace();
const realTileStart = tileStart.min(tileEnd);
const realTileEnd = tileStart.max(tileEnd);
for (let x = realTileStart.x; x <= realTileEnd.x; ++x) {
for (let y = realTileStart.y; y <= realTileEnd.y; ++y) {
const contents = this.root.map.getTileContentXY(x, y);
if (contents && this.root.logic.canDeleteBuilding(contents)) {
2020-05-27 12:30:59 +00:00
this.selectedUids.add(contents.uid);
2020-05-10 16:24:50 +00:00
}
}
}
2020-05-31 22:07:01 +00:00
this.currentSelectionStartWorld = null;
2020-05-10 16:24:50 +00:00
this.currentSelectionEnd = null;
}
}
/**
*
* @param {DrawParameters} parameters
*/
draw(parameters) {
2020-05-27 12:30:59 +00:00
const boundsBorder = 2;
if (this.currentSelectionStartWorld) {
2020-05-31 22:07:01 +00:00
const worldStart = this.currentSelectionStartWorld;
2020-05-10 16:24:50 +00:00
const worldEnd = this.root.camera.screenToWorld(this.currentSelectionEnd);
const realWorldStart = worldStart.min(worldEnd);
const realWorldEnd = worldStart.max(worldEnd);
const tileStart = worldStart.toTileSpace();
const tileEnd = worldEnd.toTileSpace();
const realTileStart = tileStart.min(tileEnd);
const realTileEnd = tileStart.max(tileEnd);
parameters.context.lineWidth = 1;
2020-05-27 12:30:59 +00:00
parameters.context.fillStyle = THEME.map.selectionBackground;
parameters.context.strokeStyle = THEME.map.selectionOutline;
2020-05-10 16:24:50 +00:00
parameters.context.beginPath();
parameters.context.rect(
realWorldStart.x,
realWorldStart.y,
realWorldEnd.x - realWorldStart.x,
realWorldEnd.y - realWorldStart.y
);
parameters.context.fill();
parameters.context.stroke();
2020-05-27 12:30:59 +00:00
parameters.context.fillStyle = THEME.map.selectionOverlay;
2020-05-10 16:24:50 +00:00
for (let x = realTileStart.x; x <= realTileEnd.x; ++x) {
for (let y = realTileStart.y; y <= realTileEnd.y; ++y) {
const contents = this.root.map.getTileContentXY(x, y);
if (contents && this.root.logic.canDeleteBuilding(contents)) {
const staticComp = contents.components.StaticMapEntity;
2020-05-27 12:30:59 +00:00
const bounds = staticComp.getTileSpaceBounds();
parameters.context.beginRoundedRect(
bounds.x * globalConfig.tileSize + boundsBorder,
bounds.y * globalConfig.tileSize + boundsBorder,
bounds.w * globalConfig.tileSize - 2 * boundsBorder,
bounds.h * globalConfig.tileSize - 2 * boundsBorder,
2
2020-05-10 16:24:50 +00:00
);
2020-05-27 12:30:59 +00:00
parameters.context.fill();
2020-05-10 16:24:50 +00:00
}
}
}
}
2020-05-27 12:30:59 +00:00
parameters.context.fillStyle = THEME.map.selectionOverlay;
this.selectedUids.forEach(uid => {
2020-05-10 16:24:50 +00:00
const entity = this.root.entityMgr.findByUid(uid);
const staticComp = entity.components.StaticMapEntity;
2020-05-27 12:30:59 +00:00
const bounds = staticComp.getTileSpaceBounds();
parameters.context.beginRoundedRect(
bounds.x * globalConfig.tileSize + boundsBorder,
bounds.y * globalConfig.tileSize + boundsBorder,
bounds.w * globalConfig.tileSize - 2 * boundsBorder,
bounds.h * globalConfig.tileSize - 2 * boundsBorder,
2
2020-05-10 16:24:50 +00:00
);
2020-05-27 12:30:59 +00:00
parameters.context.fill();
2020-05-10 16:24:50 +00:00
});
}
}