diff --git a/res/puzzle_dlc_logo.png b/res/puzzle_dlc_logo.png new file mode 100644 index 00000000..1c430c82 Binary files /dev/null and b/res/puzzle_dlc_logo.png differ diff --git a/res_raw/sounds/music/puzzle-full.mp3 b/res_raw/sounds/music/puzzle-full.mp3 new file mode 100644 index 00000000..6ea6f544 Binary files /dev/null and b/res_raw/sounds/music/puzzle-full.mp3 differ diff --git a/src/css/ingame_hud/buildings_toolbar.scss b/src/css/ingame_hud/buildings_toolbar.scss index ec20ff02..af9001bb 100644 --- a/src/css/ingame_hud/buildings_toolbar.scss +++ b/src/css/ingame_hud/buildings_toolbar.scss @@ -37,7 +37,7 @@ .building { @include S(width, 30px); - @include S(height, 22px); + @include S(height, 30px); background-size: 45%; &:not(.unlocked) { @@ -49,6 +49,10 @@ } .building { + display: flex; + @include S(width, 40px); + position: relative; + @include S(height, 40px); .icon { color: $accentColorDark; display: flex; @@ -56,18 +60,18 @@ position: relative; align-items: center; justify-content: center; - @include S(padding, 5px); - @include S(padding-bottom, 1px); - @include S(width, 35px); - @include S(height, 37px); + width: 100%; + height: 100%; + padding: 0; + margin: 0; @include S(border-radius, $globalBorderRadius); background: center center / 70% no-repeat; } &:not(.unlocked) { + @include S(width, 25px); .icon { - @include S(width, 20px); opacity: 0.15; } &.editor { @@ -91,8 +95,8 @@ pointer-events: all; transition: all 50ms ease-in-out; transition-property: background-color, transform; - cursor: pointer; + &:hover { background-color: rgba(30, 40, 90, 0.1); } @@ -120,12 +124,11 @@ display: grid; grid-auto-flow: column; - @include S(margin-top, 2px); - @include S(margin-left, 16px); - @include S(margin-bottom, 29px); position: absolute; - bottom: 20px; + top: -30px; + left: 50%; + transform: translateX(-50%) !important; transition: all 0.12s ease-in-out; transition-property: opacity, transform; diff --git a/src/css/ingame_hud/puzzle_complete_notification.scss b/src/css/ingame_hud/puzzle_complete_notification.scss index b3b7bf14..5f36df82 100644 --- a/src/css/ingame_hud/puzzle_complete_notification.scss +++ b/src/css/ingame_hud/puzzle_complete_notification.scss @@ -96,12 +96,13 @@ @include S(height, 60px); @include S(margin, 0, 10px); box-sizing: border-box; - @include S(border-radius, $globalBorderRadius); + border-radius: 50%; transition: opacity 0.12s ease-in-out, background-color 0.12s ease-in-out; + @include IncreasedClickArea(0px); &.liked-yes { /* @load-async */ - background: uiResource("icons/puzzle_action_liked_yes.png") center center / 70% + background: uiResource("icons/puzzle_action_liked_yes.png") center 55% / 60% no-repeat; } @@ -110,7 +111,18 @@ } &.active { - background-color: #151118 !important; + background-color: $colorRedBright !important; + @include InlineAnimation(0.3s ease-in-out) { + 0% { + transform: scale(0); + } + 50% { + transform: scale(1.2); + } + 100% { + transform: scale(1); + } + } } &:not(.active) { opacity: 0.4; @@ -119,6 +131,26 @@ } } + > .buttonBar { + display: flex; + @include S(margin-top, 20px); + + button.continue { + background: #555; + @include S(margin-right, 10px); + } + + button.menu { + background-color: $colorGreenBright; + } + + > button { + @include S(min-width, 100px); + @include S(padding, 10px, 20px); + @include IncreasedClickArea(0px); + } + } + > .actions { position: absolute; @include S(bottom, 40px); @@ -135,14 +167,5 @@ } } } - - button.close { - border: 0; - position: relative; - @include S(margin-top, 15px); - background: $colorGreenBright; - @include Heading; - @include S(padding, 14px, 40px); - } } } diff --git a/src/css/states/main_menu.scss b/src/css/states/main_menu.scss index f46230a2..005ee7af 100644 --- a/src/css/states/main_menu.scss +++ b/src/css/states/main_menu.scss @@ -88,11 +88,7 @@ @include S(grid-column-gap, 10px); display: grid; - grid-template-columns: 1fr; - - &.demo { - grid-template-columns: 1fr 1fr; - } + grid-template-columns: 1fr 1fr; .standaloneBanner { background: rgb(255, 75, 84); @@ -223,9 +219,33 @@ } } + .puzzleContainer { + display: flex; + align-items: center; + justify-content: center; + flex-direction: column; + background: #4cc98a; + grid-row: 1 / 2; + grid-column: 2 / 3; + @include S(padding, 20px); + @include S(border-radius, $globalBorderRadius); + > .dlcLogo { + @include S(width, 200px); + } + + > button { + @include S(margin-top, 20px); + @include Heading; + @include S(padding, 10px, 30px); + background-color: #333; + color: #fff; + } + } + .mainContainer { display: flex; align-items: center; + grid-row: 1 / 2; justify-content: center; flex-direction: column; background: #fafafa; diff --git a/src/js/core/state_manager.js b/src/js/core/state_manager.js index 3c49ada9..e0c04bba 100644 --- a/src/js/core/state_manager.js +++ b/src/js/core/state_manager.js @@ -90,9 +90,9 @@ export class StateManager { dialogParent.classList.add("modalDialogParent"); document.body.appendChild(dialogParent); + this.currentState.internalEnterCallback(payload); this.app.sound.playThemeMusic(this.currentState.getThemeMusic()); - this.currentState.internalEnterCallback(payload); this.currentState.onResized(this.app.screenWidth, this.app.screenHeight); this.app.analytics.trackStateEnter(key); diff --git a/src/js/game/hud/parts/base_toolbar.js b/src/js/game/hud/parts/base_toolbar.js index 4abace68..15faad66 100644 --- a/src/js/game/hud/parts/base_toolbar.js +++ b/src/js/game/hud/parts/base_toolbar.js @@ -40,7 +40,6 @@ export class HUDBaseToolbar extends BaseHUDPart { * element: HTMLElement, * index: number * puzzleLocked: boolean; - * class: typeof MetaBuilding, * }>} */ this.buildingHandles = {}; } @@ -136,7 +135,6 @@ export class HUDBaseToolbar extends BaseHUDPart { selected: false, index: i, puzzleLocked: false, - class: allBuildings[i], }; } diff --git a/src/js/game/hud/parts/puzzle_complete_notification.js b/src/js/game/hud/parts/puzzle_complete_notification.js index b0235417..f223c1d6 100644 --- a/src/js/game/hud/parts/puzzle_complete_notification.js +++ b/src/js/game/hud/parts/puzzle_complete_notification.js @@ -52,19 +52,23 @@ export class HUDPuzzleCompleteNotification extends BaseHUDPart { this.updateState(); }); + const buttonBar = document.createElement("div"); + buttonBar.classList.add("buttonBar"); + this.elemContents.appendChild(buttonBar); + this.continueBtn = document.createElement("button"); - this.continueBtn.classList.add("close", "styledButton"); + this.continueBtn.classList.add("continue", "styledButton"); this.continueBtn.innerText = T.ingame.puzzleCompletion.continueBtn; - dialog.appendChild(this.continueBtn); - - this.menuBtn = document.createElement("button"); - this.menuBtn.classList.add("close", "styledButton"); - this.menuBtn.innerText = T.ingame.puzzleCompletion.menuBtn; - dialog.appendChild(this.menuBtn); - + buttonBar.appendChild(this.continueBtn); this.trackClicks(this.continueBtn, () => { this.close(false); }); + + this.menuBtn = document.createElement("button"); + this.menuBtn.classList.add("menu", "styledButton"); + this.menuBtn.innerText = T.ingame.puzzleCompletion.menuBtn; + buttonBar.appendChild(this.menuBtn); + this.trackClicks(this.menuBtn, () => { this.close(true); }); diff --git a/src/js/game/hud/parts/puzzle_editor_review.js b/src/js/game/hud/parts/puzzle_editor_review.js index b358dc6d..68f5360c 100644 --- a/src/js/game/hud/parts/puzzle_editor_review.js +++ b/src/js/game/hud/parts/puzzle_editor_review.js @@ -163,7 +163,9 @@ export class HUDPuzzleEditorReview extends BaseHUDPart { const serialized = new PuzzleSerializer().generateDumpFromGameRoot(this.root); logger.log("Submitting puzzle, title=", title, "shortKey=", shortKey); - logger.log("Serialized data:", serialized); + if (G_IS_DEV) { + logger.log("Serialized data:", serialized); + } const closeLoading = this.root.hud.parts.dialogs.showLoadingDialog(T.puzzleMenu.submittingPuzzle); diff --git a/src/js/game/hud/parts/sandbox_controller.js b/src/js/game/hud/parts/sandbox_controller.js index c8104d99..3689fa36 100644 --- a/src/js/game/hud/parts/sandbox_controller.js +++ b/src/js/game/hud/parts/sandbox_controller.js @@ -152,9 +152,6 @@ export class HUDSandboxController extends BaseHUDPart { } toggle() { - if (!this.visible) { - return; - } this.visible = !this.visible; } diff --git a/src/js/game/modes/puzzle.js b/src/js/game/modes/puzzle.js index 3f5febf1..4bf3b1e6 100644 --- a/src/js/game/modes/puzzle.js +++ b/src/js/game/modes/puzzle.js @@ -7,9 +7,6 @@ import { types } from "../../savegame/serialization"; import { enumGameModeTypes, GameMode } from "../game_mode"; import { HUDPuzzleBackToMenu } from "../hud/parts/puzzle_back_to_menu"; 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 { static getType() { diff --git a/src/js/game/modes/puzzle_play.js b/src/js/game/modes/puzzle_play.js index eafbd7ff..46480c51 100644 --- a/src/js/game/modes/puzzle_play.js +++ b/src/js/game/modes/puzzle_play.js @@ -29,6 +29,7 @@ import { HUDPuzzleCompleteNotification } from "../hud/parts/puzzle_complete_noti import { HUDPuzzlePlaySettings } from "../hud/parts/puzzle_play_settings"; import { MetaBlockBuilding } from "../buildings/block"; import { MetaBuilding } from "../meta_building"; +import { gMetaBuildingRegistry } from "../../core/global_registries"; const logger = createLogger("puzzle-play"); const copy = require("clipboard-copy"); @@ -47,7 +48,7 @@ export class PuzzlePlayGameMode extends PuzzleGameMode { super(root); /** @type {Array} */ - const excludedBuildings = [ + let excludedBuildings = [ MetaConstantProducerBuilding, MetaGoalAcceptorBuilding, MetaBlockBuilding, @@ -70,7 +71,22 @@ export class PuzzlePlayGameMode extends PuzzleGameMode { MetaTransistorBuilding, ]; - this.hiddenBuildings = excludedBuildings.concat(puzzle.game.excludedBuildings); + if (puzzle.game.excludedBuildings) { + /** + * @type {any} + */ + const puzzleHidden = puzzle.game.excludedBuildings + .map(id => { + if (!gMetaBuildingRegistry.hasId(id)) { + return; + } + return gMetaBuildingRegistry.findById(id).constructor; + }) + .filter(x => !!x); + excludedBuildings = excludedBuildings.concat(puzzleHidden); + } + + this.hiddenBuildings = excludedBuildings; this.additionalHudParts.puzzlePlayMetadata = HUDPuzzlePlayMetadata; this.additionalHudParts.puzzlePlaySettings = HUDPuzzlePlaySettings; diff --git a/src/js/platform/sound.js b/src/js/platform/sound.js index 9d5a8461..d43c76c2 100644 --- a/src/js/platform/sound.js +++ b/src/js/platform/sound.js @@ -35,6 +35,10 @@ export const MUSIC = { menu: "menu", }; +if (G_IS_STANDALONE || G_IS_DEV) { + MUSIC.puzzle = "puzzle-full"; +} + export class SoundInstanceInterface { constructor(key, url) { this.key = key; diff --git a/src/js/savegame/puzzle_serializer.js b/src/js/savegame/puzzle_serializer.js index 8a032e9a..c7bfa652 100644 --- a/src/js/savegame/puzzle_serializer.js +++ b/src/js/savegame/puzzle_serializer.js @@ -85,12 +85,13 @@ export class PuzzleSerializer { const handles = root.hud.parts.buildingsToolbar.buildingHandles; const ids = gMetaBuildingRegistry.getAllIds(); - /** @type {Array} */ + /** @type {Array} */ let excludedBuildings = []; for (let i = 0; i < ids.length; ++i) { const handle = handles[ids[i]]; if (handle && handle.puzzleLocked) { - excludedBuildings.push(handle.class); + // @ts-ignore + excludedBuildings.push(handle.metaBuilding.getId()); } } diff --git a/src/js/savegame/savegame_typedefs.js b/src/js/savegame/savegame_typedefs.js index 3abe8c21..c5e0e5c5 100644 --- a/src/js/savegame/savegame_typedefs.js +++ b/src/js/savegame/savegame_typedefs.js @@ -87,7 +87,7 @@ import { MetaBuilding } from "../game/meta_building"; * version: number; * bounds: { w: number; h: number; }, * buildings: (PuzzleGameBuildingGoal | PuzzleGameBuildingConstantProducer | PuzzleGameBuildingBlock)[], - * excludedBuildings: Array, + * excludedBuildings: Array, * }} PuzzleGameData */ diff --git a/src/js/states/ingame.js b/src/js/states/ingame.js index 9ab38dd1..0dd6c72a 100644 --- a/src/js/states/ingame.js +++ b/src/js/states/ingame.js @@ -104,6 +104,9 @@ export class InGameState extends GameState { } getThemeMusic() { + if (this.creationPayload.gameModeId && this.creationPayload.gameModeId.includes("puzzle")) { + return MUSIC.puzzle; + } return MUSIC.theme; } diff --git a/src/js/states/main_menu.js b/src/js/states/main_menu.js index a4e19453..25d93d7a 100644 --- a/src/js/states/main_menu.js +++ b/src/js/states/main_menu.js @@ -15,7 +15,6 @@ import { startFileChoose, waitNextFrame, } from "../core/utils"; -import { enumGameModeIds } from "../game/game_mode"; import { HUDModalDialogs } from "../game/hud/parts/modal_dialogs"; import { getApplicationSettingById } from "../profile/application_settings"; import { T } from "../translations"; @@ -83,9 +82,19 @@ export class MainMenuState extends GameState { }
-
-
-
+ + ${ + // @TODO: Only display if DLC is owned, otherwise show ad for store page + showDemoBadges + ? "" + : ` +
+ + +
` + }