mirror of
https://github.com/tobspr/shapez.io.git
synced 2024-10-27 20:34:29 +00:00
Color blind mode
This commit is contained in:
parent
f204189fdb
commit
9a67115ba7
BIN
res/ui/icons/info_button.png
Normal file
BIN
res/ui/icons/info_button.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 577 B |
3
res_raw/sounds/sfx/destroy_building.wav
Normal file
3
res_raw/sounds/sfx/destroy_building.wav
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
version https://git-lfs.github.com/spec/v1
|
||||||
|
oid sha256:1dc8775fdf5155097d6e1d60a436f48916af56eec14fb9034e71b32ad3b6f1b0
|
||||||
|
size 358896
|
18
src/css/ingame_hud/color_blind_helper.scss
Normal file
18
src/css/ingame_hud/color_blind_helper.scss
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
#ingame_HUD_ColorBlindBelowTileHelper {
|
||||||
|
position: absolute;
|
||||||
|
|
||||||
|
@include SuperSmallText;
|
||||||
|
color: #fff;
|
||||||
|
background: $ingameHudBg;
|
||||||
|
@include S(padding, 5px);
|
||||||
|
@include S(top, 20px);
|
||||||
|
left: 50%;
|
||||||
|
transform: translateX(-50%);
|
||||||
|
text-transform: uppercase;
|
||||||
|
|
||||||
|
&:not(.visible) {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
@include DarkThemeInvert;
|
||||||
|
}
|
@ -72,6 +72,24 @@
|
|||||||
grid-row: 1 / 2;
|
grid-row: 1 / 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
> .infoButton {
|
||||||
|
@include S(width, 8px);
|
||||||
|
@include S(height, 8px);
|
||||||
|
background: uiResource("icons/info_button.png") center center / 95% no-repeat;
|
||||||
|
position: absolute;
|
||||||
|
opacity: 0.7;
|
||||||
|
@include S(top, 13px);
|
||||||
|
@include S(left, -7px);
|
||||||
|
@include DarkThemeInvert;
|
||||||
|
@include IncreasedClickArea(2px);
|
||||||
|
transition: opacity 0.12s ease-in-out;
|
||||||
|
z-index: 100;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
opacity: 0.8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
&.goal,
|
&.goal,
|
||||||
&.blueprint {
|
&.blueprint {
|
||||||
.amountLabel::after {
|
.amountLabel::after {
|
||||||
|
131
src/css/ingame_hud/shape_viewer.scss
Normal file
131
src/css/ingame_hud/shape_viewer.scss
Normal file
@ -0,0 +1,131 @@
|
|||||||
|
#ingame_HUD_ShapeViewer {
|
||||||
|
.dialogInner {
|
||||||
|
@include S(width, 160px);
|
||||||
|
}
|
||||||
|
.content {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
width: 100%;
|
||||||
|
align-items: center;
|
||||||
|
justify-items: center;
|
||||||
|
|
||||||
|
.seperator {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.layer {
|
||||||
|
position: relative;
|
||||||
|
background: #eee;
|
||||||
|
|
||||||
|
@include DarkThemeOverride {
|
||||||
|
background: rgba(0, 10, 20, 0.2);
|
||||||
|
}
|
||||||
|
@include S(width, 150px);
|
||||||
|
@include S(height, 100px);
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
|
||||||
|
> canvas {
|
||||||
|
@include S(width, 50px);
|
||||||
|
@include S(height, 50px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.quad {
|
||||||
|
position: absolute;
|
||||||
|
width: 50%;
|
||||||
|
height: 50%;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
box-sizing: border-box;
|
||||||
|
|
||||||
|
$arrowDims: 23px;
|
||||||
|
$spacing: 9px;
|
||||||
|
@include S(padding, 6px);
|
||||||
|
|
||||||
|
.colorLabel {
|
||||||
|
text-transform: uppercase;
|
||||||
|
@include SuperSmallText;
|
||||||
|
@include S(font-size, 9px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.emptyLabel {
|
||||||
|
text-transform: uppercase;
|
||||||
|
@include SuperSmallText;
|
||||||
|
@include S(font-size, 9px);
|
||||||
|
}
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
content: " ";
|
||||||
|
background: rgba(0, 10, 20, 0.5);
|
||||||
|
@include S(width, $arrowDims);
|
||||||
|
@include S(height, 1px);
|
||||||
|
position: absolute;
|
||||||
|
transform: rotate(45deg);
|
||||||
|
transform-origin: 50% 50%;
|
||||||
|
}
|
||||||
|
@include DarkThemeOverride {
|
||||||
|
&::after {
|
||||||
|
background: rgba(255, 255, 255, 0.5);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.quad-0 {
|
||||||
|
right: 0;
|
||||||
|
top: 0;
|
||||||
|
align-items: flex-start;
|
||||||
|
justify-content: flex-end;
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
@include S(left, $spacing);
|
||||||
|
@include S(bottom, $arrowDims / 2 + $spacing);
|
||||||
|
transform: rotate(-45deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&.quad-1 {
|
||||||
|
bottom: 0;
|
||||||
|
right: 0;
|
||||||
|
|
||||||
|
align-items: flex-end;
|
||||||
|
justify-content: flex-end;
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
@include S(left, $spacing);
|
||||||
|
@include S(top, $arrowDims / 2 + $spacing);
|
||||||
|
transform: rotate(45deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&.quad-2 {
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
|
||||||
|
align-items: flex-end;
|
||||||
|
justify-content: flex-start;
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
@include S(right, $spacing);
|
||||||
|
@include S(top, $arrowDims / 2 + $spacing);
|
||||||
|
transform: rotate(135deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&.quad-3 {
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
|
||||||
|
align-items: flex-start;
|
||||||
|
justify-content: flex-start;
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
@include S(right, $spacing);
|
||||||
|
@include S(bottom, $arrowDims / 2 + $spacing);
|
||||||
|
transform: rotate(225deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -195,6 +195,25 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
button.showInfo {
|
||||||
|
@include S(width, 11px);
|
||||||
|
@include S(height, 11px);
|
||||||
|
background: uiResource("icons/info_button.png") center center / 95% no-repeat;
|
||||||
|
position: absolute;
|
||||||
|
@include S(top, 17px);
|
||||||
|
@include S(right, 2.5px);
|
||||||
|
opacity: 0.5;
|
||||||
|
cursor: pointer;
|
||||||
|
pointer-events: all;
|
||||||
|
@include IncreasedClickArea(5px);
|
||||||
|
transition: opacity 0.12s ease-in-out;
|
||||||
|
@include DarkThemeInvert;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
opacity: 0.6;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
canvas {
|
canvas {
|
||||||
@include S(width, 40px);
|
@include S(width, 40px);
|
||||||
@include S(height, 40px);
|
@include S(height, 40px);
|
||||||
@ -241,7 +260,7 @@
|
|||||||
|
|
||||||
&.complete {
|
&.complete {
|
||||||
background-color: $colorGreenBright;
|
background-color: $colorGreenBright;
|
||||||
|
|
||||||
@include DarkThemeOverride {
|
@include DarkThemeOverride {
|
||||||
background-color: $colorGreenBright;
|
background-color: $colorGreenBright;
|
||||||
}
|
}
|
||||||
|
@ -49,6 +49,8 @@
|
|||||||
@import "ingame_hud/blueprint_placer";
|
@import "ingame_hud/blueprint_placer";
|
||||||
@import "ingame_hud/waypoints";
|
@import "ingame_hud/waypoints";
|
||||||
@import "ingame_hud/interactive_tutorial";
|
@import "ingame_hud/interactive_tutorial";
|
||||||
|
@import "ingame_hud/color_blind_helper";
|
||||||
|
@import "ingame_hud/shape_viewer";
|
||||||
|
|
||||||
// prettier-ignore
|
// prettier-ignore
|
||||||
$elements:
|
$elements:
|
||||||
@ -74,6 +76,7 @@ ingame_HUD_buildings_toolbar,
|
|||||||
ingame_HUD_BlueprintPlacer,
|
ingame_HUD_BlueprintPlacer,
|
||||||
ingame_HUD_Waypoints_Hint,
|
ingame_HUD_Waypoints_Hint,
|
||||||
ingame_HUD_Watermark,
|
ingame_HUD_Watermark,
|
||||||
|
ingame_HUD_ColorBlindBelowTileHelper,
|
||||||
|
|
||||||
// Overlays
|
// Overlays
|
||||||
ingame_HUD_BetaOverlay,
|
ingame_HUD_BetaOverlay,
|
||||||
@ -81,6 +84,7 @@ ingame_HUD_BetaOverlay,
|
|||||||
// Dialogs
|
// Dialogs
|
||||||
ingame_HUD_Shop,
|
ingame_HUD_Shop,
|
||||||
ingame_HUD_Statistics,
|
ingame_HUD_Statistics,
|
||||||
|
ingame_HUD_ShapeViewer,
|
||||||
ingame_HUD_UnlockNotification,
|
ingame_HUD_UnlockNotification,
|
||||||
ingame_HUD_SettingsMenu,
|
ingame_HUD_SettingsMenu,
|
||||||
ingame_HUD_ModalDialogs;
|
ingame_HUD_ModalDialogs;
|
||||||
|
@ -3,6 +3,8 @@ export const CHANGELOG = [
|
|||||||
version: "1.1.17",
|
version: "1.1.17",
|
||||||
date: "unreleased",
|
date: "unreleased",
|
||||||
entries: [
|
entries: [
|
||||||
|
"Color blind mode! You can now activate it in the settings and it will show you which color is below your cursor (Either resource or on the belt)",
|
||||||
|
"Add info buttons to all shapes so you can figure out how they are built! (And also, which colors they have)",
|
||||||
"Allow configuring autosave interval and disabling it in the settings",
|
"Allow configuring autosave interval and disabling it in the settings",
|
||||||
"The smart-tunnel placement has been reworked to properly replace belts. Thus the setting has been turned on again by default",
|
"The smart-tunnel placement has been reworked to properly replace belts. Thus the setting has been turned on again by default",
|
||||||
"The soundtrack now has a higher quality on the standalone version than the web version",
|
"The soundtrack now has a higher quality on the standalone version than the web version",
|
||||||
@ -10,6 +12,8 @@ export const CHANGELOG = [
|
|||||||
"Fix bug where belts in blueprints don't orient correctly (by hexy)",
|
"Fix bug where belts in blueprints don't orient correctly (by hexy)",
|
||||||
"Fix camera moving weird after dragging and holding (by hexy)",
|
"Fix camera moving weird after dragging and holding (by hexy)",
|
||||||
"Fix keybinding for pipette showing while pasting blueprints",
|
"Fix keybinding for pipette showing while pasting blueprints",
|
||||||
|
"Improve visibility of shape background in dark mode",
|
||||||
|
"Added sound when destroying a building",
|
||||||
"Update tutorial image for tier 2 tunnels to explain mix/match (by jimmyshadow1)",
|
"Update tutorial image for tier 2 tunnels to explain mix/match (by jimmyshadow1)",
|
||||||
"Prevent default actions on all keybindings in the web version so you don't accidentally use builtin browser shortcuts",
|
"Prevent default actions on all keybindings in the web version so you don't accidentally use builtin browser shortcuts",
|
||||||
],
|
],
|
||||||
|
@ -34,7 +34,8 @@ import { HUDPartTutorialHints } from "./parts/tutorial_hints";
|
|||||||
import { HUDWaypoints } from "./parts/waypoints";
|
import { HUDWaypoints } from "./parts/waypoints";
|
||||||
import { HUDInteractiveTutorial } from "./parts/interactive_tutorial";
|
import { HUDInteractiveTutorial } from "./parts/interactive_tutorial";
|
||||||
import { HUDScreenshotExporter } from "./parts/screenshot_exporter";
|
import { HUDScreenshotExporter } from "./parts/screenshot_exporter";
|
||||||
import { Entity } from "../entity";
|
import { HUDColorBlindHelper } from "./parts/color_blind_helper";
|
||||||
|
import { HUDShapeViewer } from "./parts/shape_viewer";
|
||||||
|
|
||||||
export class GameHUD {
|
export class GameHUD {
|
||||||
/**
|
/**
|
||||||
@ -68,6 +69,7 @@ export class GameHUD {
|
|||||||
debugInfo: new HUDDebugInfo(this.root),
|
debugInfo: new HUDDebugInfo(this.root),
|
||||||
dialogs: new HUDModalDialogs(this.root),
|
dialogs: new HUDModalDialogs(this.root),
|
||||||
screenshotExporter: new HUDScreenshotExporter(this.root),
|
screenshotExporter: new HUDScreenshotExporter(this.root),
|
||||||
|
shapeViewer: new HUDShapeViewer(this.root),
|
||||||
};
|
};
|
||||||
|
|
||||||
this.signals = {
|
this.signals = {
|
||||||
@ -76,7 +78,8 @@ export class GameHUD {
|
|||||||
shapeUnpinRequested: /** @type {TypedSignal<[string]>} */ (new Signal()),
|
shapeUnpinRequested: /** @type {TypedSignal<[string]>} */ (new Signal()),
|
||||||
notification: /** @type {TypedSignal<[string, enumNotificationType]>} */ (new Signal()),
|
notification: /** @type {TypedSignal<[string, enumNotificationType]>} */ (new Signal()),
|
||||||
buildingsSelectedForCopy: /** @type {TypedSignal<[Array<number>]>} */ (new Signal()),
|
buildingsSelectedForCopy: /** @type {TypedSignal<[Array<number>]>} */ (new Signal()),
|
||||||
pasteBlueprintRequested: new Signal(),
|
pasteBlueprintRequested: /** @type {TypedSignal<[]>} */ (new Signal()),
|
||||||
|
viewShapeDetailsRequested: /** @type {TypedSignal<[ShapeDefinition]>} */ (new Signal()),
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!IS_MOBILE) {
|
if (!IS_MOBILE) {
|
||||||
@ -100,6 +103,10 @@ export class GameHUD {
|
|||||||
this.parts.vignetteOverlay = new HUDVignetteOverlay(this.root);
|
this.parts.vignetteOverlay = new HUDVignetteOverlay(this.root);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this.root.app.settings.getAllSettings().enableColorBlindHelper) {
|
||||||
|
this.parts.colorBlindHelper = new HUDColorBlindHelper(this.root);
|
||||||
|
}
|
||||||
|
|
||||||
const frag = document.createDocumentFragment();
|
const frag = document.createDocumentFragment();
|
||||||
for (const key in this.parts) {
|
for (const key in this.parts) {
|
||||||
this.parts[key].createElements(frag);
|
this.parts[key].createElements(frag);
|
||||||
@ -208,7 +215,13 @@ export class GameHUD {
|
|||||||
* @param {DrawParameters} parameters
|
* @param {DrawParameters} parameters
|
||||||
*/
|
*/
|
||||||
draw(parameters) {
|
draw(parameters) {
|
||||||
const partsOrder = ["waypoints", "massSelector", "buildingPlacer", "blueprintPlacer"];
|
const partsOrder = [
|
||||||
|
"waypoints",
|
||||||
|
"massSelector",
|
||||||
|
"buildingPlacer",
|
||||||
|
"blueprintPlacer",
|
||||||
|
"colorBlindHelper",
|
||||||
|
];
|
||||||
|
|
||||||
for (let i = 0; i < partsOrder.length; ++i) {
|
for (let i = 0; i < partsOrder.length; ++i) {
|
||||||
if (this.parts[partsOrder[i]]) {
|
if (this.parts[partsOrder[i]]) {
|
||||||
|
@ -10,6 +10,7 @@ import { blueprintShape } from "../../upgrades";
|
|||||||
import { BaseHUDPart } from "../base_hud_part";
|
import { BaseHUDPart } from "../base_hud_part";
|
||||||
import { DynamicDomAttach } from "../dynamic_dom_attach";
|
import { DynamicDomAttach } from "../dynamic_dom_attach";
|
||||||
import { Blueprint } from "./blueprint";
|
import { Blueprint } from "./blueprint";
|
||||||
|
import { SOUNDS } from "../../../platform/sound";
|
||||||
|
|
||||||
export class HUDBlueprintPlacer extends BaseHUDPart {
|
export class HUDBlueprintPlacer extends BaseHUDPart {
|
||||||
createElements(parent) {
|
createElements(parent) {
|
||||||
@ -103,7 +104,7 @@ export class HUDBlueprintPlacer extends BaseHUDPart {
|
|||||||
if (blueprint.tryPlace(this.root, tile)) {
|
if (blueprint.tryPlace(this.root, tile)) {
|
||||||
const cost = blueprint.getCost();
|
const cost = blueprint.getCost();
|
||||||
this.root.hubGoals.takeShapeByKey(blueprintShape, cost);
|
this.root.hubGoals.takeShapeByKey(blueprintShape, cost);
|
||||||
|
this.root.soundProxy.playUi(SOUNDS.placeBuilding);
|
||||||
// This actually feels weird
|
// This actually feels weird
|
||||||
// if (!this.root.keyMapper.getBinding(KEYMAPPINGS.placementModifiers.placeMultiple).pressed) {
|
// if (!this.root.keyMapper.getBinding(KEYMAPPINGS.placementModifiers.placeMultiple).pressed) {
|
||||||
// this.currentBlueprint.set(null);
|
// this.currentBlueprint.set(null);
|
||||||
|
@ -10,6 +10,7 @@ import { Entity } from "../../entity";
|
|||||||
import { KEYMAPPINGS } from "../../key_action_mapper";
|
import { KEYMAPPINGS } from "../../key_action_mapper";
|
||||||
import { defaultBuildingVariant, MetaBuilding } from "../../meta_building";
|
import { defaultBuildingVariant, MetaBuilding } from "../../meta_building";
|
||||||
import { BaseHUDPart } from "../base_hud_part";
|
import { BaseHUDPart } from "../base_hud_part";
|
||||||
|
import { SOUNDS } from "../../../platform/sound";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Contains all logic for the building placer - this doesn't include the rendering
|
* Contains all logic for the building placer - this doesn't include the rendering
|
||||||
@ -215,6 +216,7 @@ export class HUDBuildingPlacerLogic extends BaseHUDPart {
|
|||||||
const contents = this.root.map.getTileContent(tile);
|
const contents = this.root.map.getTileContent(tile);
|
||||||
if (contents) {
|
if (contents) {
|
||||||
this.root.logic.tryDeleteBuilding(contents);
|
this.root.logic.tryDeleteBuilding(contents);
|
||||||
|
this.root.soundProxy.playUi(SOUNDS.destroyBuilding);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -650,6 +652,7 @@ export class HUDBuildingPlacerLogic extends BaseHUDPart {
|
|||||||
const contents = this.root.map.getTileContentXY(x0, y0);
|
const contents = this.root.map.getTileContentXY(x0, y0);
|
||||||
if (contents && !contents.queuedForDestroy && !contents.destroyed) {
|
if (contents && !contents.queuedForDestroy && !contents.destroyed) {
|
||||||
this.root.logic.tryDeleteBuilding(contents);
|
this.root.logic.tryDeleteBuilding(contents);
|
||||||
|
this.root.soundProxy.playUi(SOUNDS.destroyBuilding);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
this.tryPlaceCurrentBuildingAt(new Vector(x0, y0));
|
this.tryPlaceCurrentBuildingAt(new Vector(x0, y0));
|
||||||
|
106
src/js/game/hud/parts/color_blind_helper.js
Normal file
106
src/js/game/hud/parts/color_blind_helper.js
Normal file
@ -0,0 +1,106 @@
|
|||||||
|
import { BaseHUDPart } from "../base_hud_part";
|
||||||
|
import { makeDiv } from "../../../core/utils";
|
||||||
|
import { TrackedState } from "../../../core/tracked_state";
|
||||||
|
import { enumColors } from "../../colors";
|
||||||
|
import { ColorItem } from "../../items/color_item";
|
||||||
|
import { DrawParameters } from "../../../core/draw_parameters";
|
||||||
|
import { THEME } from "../../theme";
|
||||||
|
import { globalConfig } from "../../../core/config";
|
||||||
|
import { T } from "../../../translations";
|
||||||
|
|
||||||
|
export class HUDColorBlindHelper extends BaseHUDPart {
|
||||||
|
createElements(parent) {
|
||||||
|
this.belowTileIndicator = makeDiv(parent, "ingame_HUD_ColorBlindBelowTileHelper", []);
|
||||||
|
}
|
||||||
|
|
||||||
|
initialize() {
|
||||||
|
this.trackedColorBelowTile = new TrackedState(this.onColorBelowTileChanged, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when the color below the current tile changed
|
||||||
|
* @param {enumColors|null} color
|
||||||
|
*/
|
||||||
|
onColorBelowTileChanged(color) {
|
||||||
|
this.belowTileIndicator.classList.toggle("visible", !!color);
|
||||||
|
if (color) {
|
||||||
|
this.belowTileIndicator.innerText = T.ingame.colors[color];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Computes the color below the current tile
|
||||||
|
* @returns {enumColors}
|
||||||
|
*/
|
||||||
|
computeColorBelowTile() {
|
||||||
|
const mousePosition = this.root.app.mousePosition;
|
||||||
|
if (!mousePosition) {
|
||||||
|
// Not on screen
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const worldPos = this.root.camera.screenToWorld(mousePosition);
|
||||||
|
const tile = worldPos.toTileSpace();
|
||||||
|
const contents = this.root.map.getTileContent(tile);
|
||||||
|
|
||||||
|
if (contents && !contents.components.Miner) {
|
||||||
|
const beltComp = contents.components.Belt;
|
||||||
|
|
||||||
|
// Check if the belt has a color item
|
||||||
|
if (beltComp) {
|
||||||
|
const firstItem = beltComp.sortedItems[0];
|
||||||
|
if (firstItem && firstItem[1] instanceof ColorItem) {
|
||||||
|
return firstItem[1].color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if we are ejecting an item, if so use that color
|
||||||
|
const ejectorComp = contents.components.ItemEjector;
|
||||||
|
if (ejectorComp) {
|
||||||
|
for (let i = 0; i < ejectorComp.slots.length; ++i) {
|
||||||
|
const slot = ejectorComp.slots[i];
|
||||||
|
if (slot.item && slot.item instanceof ColorItem) {
|
||||||
|
return slot.item.color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// We hovered a lower layer, show the color there
|
||||||
|
const lowerLayer = this.root.map.getLowerLayerContentXY(tile.x, tile.y);
|
||||||
|
if (lowerLayer && lowerLayer instanceof ColorItem) {
|
||||||
|
return lowerLayer.color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
update() {
|
||||||
|
this.trackedColorBelowTile.set(this.computeColorBelowTile());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Draws the currently selected tile
|
||||||
|
* @param {DrawParameters} parameters
|
||||||
|
*/
|
||||||
|
draw(parameters) {
|
||||||
|
const mousePosition = this.root.app.mousePosition;
|
||||||
|
if (!mousePosition) {
|
||||||
|
// Not on screen
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const below = this.computeColorBelowTile();
|
||||||
|
if (below) {
|
||||||
|
// We have something below our tile
|
||||||
|
const worldPos = this.root.camera.screenToWorld(mousePosition);
|
||||||
|
const tile = worldPos.toTileSpace().toWorldSpace();
|
||||||
|
|
||||||
|
parameters.context.strokeStyle = THEME.map.colorBlindPickerTile;
|
||||||
|
parameters.context.lineWidth = 1;
|
||||||
|
parameters.context.beginPath();
|
||||||
|
parameters.context.rect(tile.x, tile.y, globalConfig.tileSize, globalConfig.tileSize);
|
||||||
|
parameters.context.stroke();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -26,7 +26,8 @@ export class HUDPinnedShapes extends BaseHUDPart {
|
|||||||
* amountLabel: HTMLElement,
|
* amountLabel: HTMLElement,
|
||||||
* lastRenderedValue: string,
|
* lastRenderedValue: string,
|
||||||
* element: HTMLElement,
|
* element: HTMLElement,
|
||||||
* detector?: ClickDetector
|
* detector?: ClickDetector,
|
||||||
|
* infoDetector?: ClickDetector
|
||||||
* }>}
|
* }>}
|
||||||
*/
|
*/
|
||||||
this.handles = [];
|
this.handles = [];
|
||||||
@ -155,6 +156,10 @@ export class HUDPinnedShapes extends BaseHUDPart {
|
|||||||
if (detector) {
|
if (detector) {
|
||||||
detector.cleanup();
|
detector.cleanup();
|
||||||
}
|
}
|
||||||
|
const infoDetector = this.handles[i].infoDetector;
|
||||||
|
if (infoDetector) {
|
||||||
|
infoDetector.cleanup();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
this.handles = [];
|
this.handles = [];
|
||||||
|
|
||||||
@ -198,12 +203,24 @@ export class HUDPinnedShapes extends BaseHUDPart {
|
|||||||
detector = new ClickDetector(element, {
|
detector = new ClickDetector(element, {
|
||||||
consumeEvents: true,
|
consumeEvents: true,
|
||||||
preventDefault: true,
|
preventDefault: true,
|
||||||
|
targetOnly: true,
|
||||||
});
|
});
|
||||||
detector.click.add(() => this.unpinShape(key));
|
detector.click.add(() => this.unpinShape(key));
|
||||||
} else {
|
} else {
|
||||||
element.classList.add("marked");
|
element.classList.add("marked");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Show small info icon
|
||||||
|
const infoButton = document.createElement("button");
|
||||||
|
infoButton.classList.add("infoButton");
|
||||||
|
element.appendChild(infoButton);
|
||||||
|
const infoDetector = new ClickDetector(infoButton, {
|
||||||
|
consumeEvents: true,
|
||||||
|
preventDefault: true,
|
||||||
|
targetOnly: true,
|
||||||
|
});
|
||||||
|
infoDetector.click.add(() => this.root.hud.signals.viewShapeDetailsRequested.dispatch(definition));
|
||||||
|
|
||||||
const amountLabel = makeDiv(element, null, ["amountLabel"], "");
|
const amountLabel = makeDiv(element, null, ["amountLabel"], "");
|
||||||
|
|
||||||
const goal = this.findGoalValueForShape(key);
|
const goal = this.findGoalValueForShape(key);
|
||||||
@ -216,6 +233,8 @@ export class HUDPinnedShapes extends BaseHUDPart {
|
|||||||
element,
|
element,
|
||||||
amountLabel,
|
amountLabel,
|
||||||
lastRenderedValue: "",
|
lastRenderedValue: "",
|
||||||
|
detector,
|
||||||
|
infoDetector,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
109
src/js/game/hud/parts/shape_viewer.js
Normal file
109
src/js/game/hud/parts/shape_viewer.js
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
import { BaseHUDPart } from "../base_hud_part";
|
||||||
|
import { makeDiv, removeAllChildren } from "../../../core/utils";
|
||||||
|
import { T } from "../../../translations";
|
||||||
|
import { defaultBuildingVariant } from "../../meta_building";
|
||||||
|
import { ShapeDefinition } from "../../shape_definition";
|
||||||
|
import { KEYMAPPINGS, KeyActionMapper } from "../../key_action_mapper";
|
||||||
|
import { InputReceiver } from "../../../core/input_receiver";
|
||||||
|
import { DynamicDomAttach } from "../dynamic_dom_attach";
|
||||||
|
|
||||||
|
export class HUDShapeViewer extends BaseHUDPart {
|
||||||
|
createElements(parent) {
|
||||||
|
this.background = makeDiv(parent, "ingame_HUD_ShapeViewer", ["ingameDialog"]);
|
||||||
|
|
||||||
|
// DIALOG Inner / Wrapper
|
||||||
|
this.dialogInner = makeDiv(this.background, null, ["dialogInner"]);
|
||||||
|
this.title = makeDiv(this.dialogInner, null, ["title"], T.ingame.shapeViewer.title);
|
||||||
|
this.closeButton = makeDiv(this.title, null, ["closeButton"]);
|
||||||
|
this.trackClicks(this.closeButton, this.close);
|
||||||
|
this.contentDiv = makeDiv(this.dialogInner, null, ["content"]);
|
||||||
|
}
|
||||||
|
|
||||||
|
initialize() {
|
||||||
|
this.root.hud.signals.viewShapeDetailsRequested.add(this.renderForShape, this);
|
||||||
|
|
||||||
|
this.domAttach = new DynamicDomAttach(this.root, this.background, {
|
||||||
|
attachClass: "visible",
|
||||||
|
});
|
||||||
|
|
||||||
|
this.inputReciever = new InputReceiver("shape_viewer");
|
||||||
|
this.keyActionMapper = new KeyActionMapper(this.root, this.inputReciever);
|
||||||
|
|
||||||
|
this.keyActionMapper.getBinding(KEYMAPPINGS.general.back).add(this.close, this);
|
||||||
|
|
||||||
|
this.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Closes the dialog
|
||||||
|
*/
|
||||||
|
close() {
|
||||||
|
this.visible = false;
|
||||||
|
document.body.classList.remove("ingameDialogOpen");
|
||||||
|
this.root.app.inputMgr.makeSureDetached(this.inputReciever);
|
||||||
|
this.update();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shows the viewer for a given definition
|
||||||
|
* @param {ShapeDefinition} definition
|
||||||
|
*/
|
||||||
|
renderForShape(definition) {
|
||||||
|
this.visible = true;
|
||||||
|
document.body.classList.add("ingameDialogOpen");
|
||||||
|
this.root.app.inputMgr.makeSureAttachedAndOnTop(this.inputReciever);
|
||||||
|
|
||||||
|
removeAllChildren(this.contentDiv);
|
||||||
|
|
||||||
|
const layers = definition.layers;
|
||||||
|
for (let i = 0; i < layers.length; ++i) {
|
||||||
|
const layerElem = makeDiv(this.contentDiv, null, ["layer", "layer-" + i]);
|
||||||
|
|
||||||
|
let fakeLayers = [];
|
||||||
|
for (let k = 0; k < i; ++k) {
|
||||||
|
fakeLayers.push([null, null, null, null]);
|
||||||
|
}
|
||||||
|
fakeLayers.push(layers[i]);
|
||||||
|
|
||||||
|
const thisLayerOnly = new ShapeDefinition({ layers: fakeLayers });
|
||||||
|
const thisLayerCanvas = thisLayerOnly.generateAsCanvas(160);
|
||||||
|
layerElem.appendChild(thisLayerCanvas);
|
||||||
|
|
||||||
|
for (let quad = 0; quad < 4; ++quad) {
|
||||||
|
const quadElem = makeDiv(layerElem, null, ["quad", "quad-" + quad]);
|
||||||
|
|
||||||
|
const contents = layers[i][quad];
|
||||||
|
if (contents) {
|
||||||
|
const colorLabelElem = makeDiv(
|
||||||
|
quadElem,
|
||||||
|
null,
|
||||||
|
["colorLabel"],
|
||||||
|
T.ingame.colors[contents.color]
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
const emptyLabelElem = makeDiv(
|
||||||
|
quadElem,
|
||||||
|
null,
|
||||||
|
["emptyLabel"],
|
||||||
|
T.ingame.shapeViewer.empty
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i < layers.length - 1) {
|
||||||
|
makeDiv(this.contentDiv, null, ["seperator"], "+");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cleans up everything
|
||||||
|
*/
|
||||||
|
cleanup() {
|
||||||
|
document.body.classList.remove("ingameDialogOpen");
|
||||||
|
}
|
||||||
|
|
||||||
|
update() {
|
||||||
|
this.domAttach.update(this.visible);
|
||||||
|
}
|
||||||
|
}
|
@ -79,6 +79,7 @@ export class HUDShop extends BaseHUDPart {
|
|||||||
const requiredHandle = handle.requireIndexToElement[i];
|
const requiredHandle = handle.requireIndexToElement[i];
|
||||||
requiredHandle.container.remove();
|
requiredHandle.container.remove();
|
||||||
requiredHandle.pinDetector.cleanup();
|
requiredHandle.pinDetector.cleanup();
|
||||||
|
requiredHandle.infoDetector.cleanup();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cleanup
|
// Cleanup
|
||||||
@ -122,6 +123,10 @@ export class HUDShop extends BaseHUDPart {
|
|||||||
pinButton.classList.add("pin");
|
pinButton.classList.add("pin");
|
||||||
container.appendChild(pinButton);
|
container.appendChild(pinButton);
|
||||||
|
|
||||||
|
const viewInfoButton = document.createElement("button");
|
||||||
|
viewInfoButton.classList.add("showInfo");
|
||||||
|
container.appendChild(viewInfoButton);
|
||||||
|
|
||||||
const currentGoalShape = this.root.hubGoals.currentGoal.definition.getHash();
|
const currentGoalShape = this.root.hubGoals.currentGoal.definition.getHash();
|
||||||
if (shape === currentGoalShape) {
|
if (shape === currentGoalShape) {
|
||||||
pinButton.classList.add("isGoal");
|
pinButton.classList.add("isGoal");
|
||||||
@ -145,6 +150,14 @@ export class HUDShop extends BaseHUDPart {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const infoDetector = new ClickDetector(viewInfoButton, {
|
||||||
|
consumeEvents: true,
|
||||||
|
preventDefault: true,
|
||||||
|
});
|
||||||
|
infoDetector.click.add(() =>
|
||||||
|
this.root.hud.signals.viewShapeDetailsRequested.dispatch(shapeDef)
|
||||||
|
);
|
||||||
|
|
||||||
handle.requireIndexToElement.push({
|
handle.requireIndexToElement.push({
|
||||||
container,
|
container,
|
||||||
progressLabel,
|
progressLabel,
|
||||||
@ -152,6 +165,7 @@ export class HUDShop extends BaseHUDPart {
|
|||||||
definition: shapeDef,
|
definition: shapeDef,
|
||||||
required: amount,
|
required: amount,
|
||||||
pinDetector,
|
pinDetector,
|
||||||
|
infoDetector,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -202,6 +216,7 @@ export class HUDShop extends BaseHUDPart {
|
|||||||
const requiredHandle = handle.requireIndexToElement[i];
|
const requiredHandle = handle.requireIndexToElement[i];
|
||||||
requiredHandle.container.remove();
|
requiredHandle.container.remove();
|
||||||
requiredHandle.pinDetector.cleanup();
|
requiredHandle.pinDetector.cleanup();
|
||||||
|
requiredHandle.infoDetector.cleanup();
|
||||||
}
|
}
|
||||||
handle.requireIndexToElement = [];
|
handle.requireIndexToElement = [];
|
||||||
}
|
}
|
||||||
|
@ -333,7 +333,7 @@ export class ShapeDefinition extends BasicSerializableObject {
|
|||||||
const quadrantSize = 10;
|
const quadrantSize = 10;
|
||||||
const quadrantHalfSize = quadrantSize / 2;
|
const quadrantHalfSize = quadrantSize / 2;
|
||||||
|
|
||||||
context.fillStyle = "rgba(40, 50, 65, 0.1)";
|
context.fillStyle = THEME.items.circleBackground;
|
||||||
context.beginCircle(0, 0, quadrantSize * 1.15);
|
context.beginCircle(0, 0, quadrantSize * 1.15);
|
||||||
context.fill();
|
context.fill();
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@ import { SOUNDS } from "../platform/sound";
|
|||||||
const avgSoundDurationSeconds = 0.25;
|
const avgSoundDurationSeconds = 0.25;
|
||||||
const maxOngoingSounds = 2;
|
const maxOngoingSounds = 2;
|
||||||
|
|
||||||
const maxOngoingUiSounds = 25;
|
const maxOngoingUiSounds = 10;
|
||||||
|
|
||||||
// Proxy to the application sound instance
|
// Proxy to the application sound instance
|
||||||
export class SoundProxy {
|
export class SoundProxy {
|
||||||
|
@ -12,6 +12,8 @@
|
|||||||
"directionLock": "rgb(74, 237, 134)",
|
"directionLock": "rgb(74, 237, 134)",
|
||||||
"directionLockTrack": "rgba(74, 237, 134, 0.2)",
|
"directionLockTrack": "rgba(74, 237, 134, 0.2)",
|
||||||
|
|
||||||
|
"colorBlindPickerTile": "rgba(255, 255, 255, 0.5)",
|
||||||
|
|
||||||
"resources": {
|
"resources": {
|
||||||
"shape": "#3d3f4a",
|
"shape": "#3d3f4a",
|
||||||
"red": "#4a3d3f",
|
"red": "#4a3d3f",
|
||||||
@ -26,6 +28,7 @@
|
|||||||
|
|
||||||
"items": {
|
"items": {
|
||||||
"outline": "#111418",
|
"outline": "#111418",
|
||||||
"outlineWidth": 0.75
|
"outlineWidth": 0.75,
|
||||||
|
"circleBackground": "rgba(20, 30, 40, 0.3)"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,6 +12,8 @@
|
|||||||
"directionLock": "rgb(74, 237, 134)",
|
"directionLock": "rgb(74, 237, 134)",
|
||||||
"directionLockTrack": "rgba(74, 237, 134, 0.2)",
|
"directionLockTrack": "rgba(74, 237, 134, 0.2)",
|
||||||
|
|
||||||
|
"colorBlindPickerTile": "rgba(50, 50, 50, 0.4)",
|
||||||
|
|
||||||
"resources": {
|
"resources": {
|
||||||
"shape": "#eaebec",
|
"shape": "#eaebec",
|
||||||
"red": "#ffbfc1",
|
"red": "#ffbfc1",
|
||||||
@ -27,6 +29,7 @@
|
|||||||
|
|
||||||
"items": {
|
"items": {
|
||||||
"outline": "#55575a",
|
"outline": "#55575a",
|
||||||
"outlineWidth": 0.75
|
"outlineWidth": 0.75,
|
||||||
|
"circleBackground": "rgba(40, 50, 65, 0.1)"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,6 +22,7 @@ export const SOUNDS = {
|
|||||||
|
|
||||||
levelComplete: "level_complete",
|
levelComplete: "level_complete",
|
||||||
|
|
||||||
|
destroyBuilding: "destroy_building",
|
||||||
placeBuilding: "place_building",
|
placeBuilding: "place_building",
|
||||||
placeBelt: "place_belt",
|
placeBelt: "place_belt",
|
||||||
};
|
};
|
||||||
|
@ -172,6 +172,15 @@ export const allApplicationSettings = [
|
|||||||
(app, value) => app.sound.setMusicMuted(value)
|
(app, value) => app.sound.setMusicMuted(value)
|
||||||
),
|
),
|
||||||
|
|
||||||
|
new BoolSetting(
|
||||||
|
"enableColorBlindHelper",
|
||||||
|
categoryApp,
|
||||||
|
/**
|
||||||
|
* @param {Application} app
|
||||||
|
*/
|
||||||
|
(app, value) => null
|
||||||
|
),
|
||||||
|
|
||||||
// GAME
|
// GAME
|
||||||
new BoolSetting("offerHints", categoryGame, (app, value) => {}),
|
new BoolSetting("offerHints", categoryGame, (app, value) => {}),
|
||||||
|
|
||||||
@ -269,6 +278,8 @@ class SettingsStorage {
|
|||||||
this.compactBuildingInfo = false;
|
this.compactBuildingInfo = false;
|
||||||
this.disableCutDeleteWarnings = false;
|
this.disableCutDeleteWarnings = false;
|
||||||
|
|
||||||
|
this.enableColorBlindHelper = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @type {Object.<string, number>}
|
* @type {Object.<string, number>}
|
||||||
*/
|
*/
|
||||||
@ -468,7 +479,7 @@ export class ApplicationSettings extends ReadWriteProxy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getCurrentVersion() {
|
getCurrentVersion() {
|
||||||
return 16;
|
return 17;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @param {{settings: SettingsStorage, version: number}} data */
|
/** @param {{settings: SettingsStorage, version: number}} data */
|
||||||
@ -536,6 +547,11 @@ export class ApplicationSettings extends ReadWriteProxy {
|
|||||||
data.version = 16;
|
data.version = 16;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (data.version < 17) {
|
||||||
|
data.settings.enableColorBlindHelper = false;
|
||||||
|
data.version = 17;
|
||||||
|
}
|
||||||
|
|
||||||
return ExplainedResult.good();
|
return ExplainedResult.good();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -290,6 +290,17 @@ ingame:
|
|||||||
clearSelection: Clear Selection
|
clearSelection: Clear Selection
|
||||||
pipette: Pipette
|
pipette: Pipette
|
||||||
|
|
||||||
|
# Names of the colors, used for the color blind mode
|
||||||
|
colors:
|
||||||
|
red: Red
|
||||||
|
green: Green
|
||||||
|
blue: Blue
|
||||||
|
yellow: Yellow
|
||||||
|
purple: Purple
|
||||||
|
cyan: Cyan
|
||||||
|
white: White
|
||||||
|
uncolored: No color
|
||||||
|
|
||||||
# Everything related to placing buildings (I.e. as soon as you selected a building
|
# Everything related to placing buildings (I.e. as soon as you selected a building
|
||||||
# from the toolbar)
|
# from the toolbar)
|
||||||
buildingPlacement:
|
buildingPlacement:
|
||||||
@ -384,6 +395,11 @@ ingame:
|
|||||||
description: Left-click a marker to jump to it, right-click to delete it.<br><br>Press <keybinding> to create a marker from the current view, or <strong>right-click</strong> to create a marker at the selected location.
|
description: Left-click a marker to jump to it, right-click to delete it.<br><br>Press <keybinding> to create a marker from the current view, or <strong>right-click</strong> to create a marker at the selected location.
|
||||||
creationSuccessNotification: Marker has been created.
|
creationSuccessNotification: Marker has been created.
|
||||||
|
|
||||||
|
# Shape viewer
|
||||||
|
shapeViewer:
|
||||||
|
title: Layers
|
||||||
|
empty: Empty
|
||||||
|
|
||||||
# Interactive tutorial
|
# Interactive tutorial
|
||||||
interactiveTutorial:
|
interactiveTutorial:
|
||||||
title: Tutorial
|
title: Tutorial
|
||||||
@ -652,6 +668,11 @@ settings:
|
|||||||
description: >-
|
description: >-
|
||||||
Change the language. All translations are user contributed and might be incomplete!
|
Change the language. All translations are user contributed and might be incomplete!
|
||||||
|
|
||||||
|
enableColorBlindHelper:
|
||||||
|
title: Color Blind Mode
|
||||||
|
description: >-
|
||||||
|
Enables various tools which allow to play the game if you are color blind.
|
||||||
|
|
||||||
fullscreen:
|
fullscreen:
|
||||||
title: Fullscreen
|
title: Fullscreen
|
||||||
description: >-
|
description: >-
|
||||||
|
Loading…
Reference in New Issue
Block a user