diff --git a/artwork/.gitignore b/artwork/.gitignore new file mode 100644 index 00000000..fc14a67a --- /dev/null +++ b/artwork/.gitignore @@ -0,0 +1 @@ +trailer/ \ No newline at end of file diff --git a/src/css/ingame_hud/unlock_notification.scss b/src/css/ingame_hud/unlock_notification.scss index 5f72909d..dbd4bace 100644 --- a/src/css/ingame_hud/unlock_notification.scss +++ b/src/css/ingame_hud/unlock_notification.scss @@ -143,6 +143,12 @@ cursor: default; } + &.unlocked { + &::after { + animation: none !important; + } + } + &::after { content: " "; display: inline-block; @@ -153,7 +159,7 @@ bottom: 0; background: rgba(0, 10, 20, 0.8); - @include InlineAnimation(10s linear) { + @include InlineAnimation(5s linear) { 0% { left: 0; } diff --git a/src/css/main.scss b/src/css/main.scss index 2c573318..46fdab9c 100644 --- a/src/css/main.scss +++ b/src/css/main.scss @@ -102,7 +102,9 @@ body.uiHidden { #ingame_HUD_MassSelector, #ingame_HUD_PinnedShapes, #ingame_HUD_Notifications, - #ingame_HUD_TutorialHints { + #ingame_HUD_TutorialHints, + #ingame_HUD_Waypoints, + #ingame_HUD_Waypoints_Hint { display: none !important; } } diff --git a/src/css/states/main_menu.scss b/src/css/states/main_menu.scss index fe44f464..e5d8bbef 100644 --- a/src/css/states/main_menu.scss +++ b/src/css/states/main_menu.scss @@ -228,7 +228,7 @@ @include S(grid-column-gap, 5px); @include S(grid-row-gap, 3px); - .internalId { + .playtime { grid-column: 1 / 2; grid-row: 2 / 3; @include SuperSmallText; diff --git a/src/js/core/config.js b/src/js/core/config.js index 953af4e7..c84dee3a 100644 --- a/src/js/core/config.js +++ b/src/js/core/config.js @@ -94,6 +94,7 @@ export const globalConfig = { // showChunkBorders: true, // rewardsInstant: true, allBuildingsUnlocked: true, + blueprintsNoCost: true, // upgradesNoCost: true, // disableUnlockDialog: true, // disableLogicTicks: true, @@ -105,6 +106,11 @@ export const globalConfig = { // disableMapOverview: true, disableTutorialHints: true, disableUpgradeNotification: true, + // instantBelts: true, + // instantProcessors: true, + // instantMiners: true, + + // renderForTrailer: true, /* dev:end */ }, @@ -131,3 +137,14 @@ if (globalConfig.debug.disableMapOverview) { globalConfig.mapChunkOverviewMinZoom = 0; globalConfig.mapChunkPrerenderMinZoom = 0; } + +if (G_IS_DEV && globalConfig.debug.renderForTrailer) { + globalConfig.debug.framePausesBetweenTicks = 32; + // globalConfig.mapChunkOverviewMinZoom = 0.0; + // globalConfig.mapChunkPrerenderMinZoom = globalConfig.mapChunkOverviewMinZoom; + // globalConfig.debug.instantBelts = true; + // globalConfig.debug.instantProcessors = true; + // globalConfig.debug.instantMiners = true; + globalConfig.debug.disableSavegameWrite = true; + // globalConfig.beltSpeedItemsPerSecond *= 2; +} diff --git a/src/js/game/dynamic_tickrate.js b/src/js/game/dynamic_tickrate.js index b8d2d0d4..076532d5 100644 --- a/src/js/game/dynamic_tickrate.js +++ b/src/js/game/dynamic_tickrate.js @@ -26,6 +26,10 @@ export class DynamicTickrate { this.averageFps = 60; this.setTickRate(60); + + if (G_IS_DEV && globalConfig.debug.renderForTrailer) { + this.setTickRate(300); + } } onFrameRendered() { @@ -56,6 +60,10 @@ export class DynamicTickrate { * Increases the tick rate marginally */ increaseTickRate() { + if (G_IS_DEV && globalConfig.debug.renderForTrailer) { + return; + } + const desiredFps = this.root.app.settings.getDesiredFps(); this.setTickRate(Math_round(Math_min(desiredFps, this.currentTickRate * 1.2))); } @@ -64,6 +72,10 @@ export class DynamicTickrate { * Decreases the tick rate marginally */ decreaseTickRate() { + if (G_IS_DEV && globalConfig.debug.renderForTrailer) { + return; + } + const desiredFps = this.root.app.settings.getDesiredFps(); this.setTickRate(Math_round(Math_max(desiredFps / 2, this.currentTickRate * 0.8))); } diff --git a/src/js/game/hub_goals.js b/src/js/game/hub_goals.js index aa410e75..7d1dbacd 100644 --- a/src/js/game/hub_goals.js +++ b/src/js/game/hub_goals.js @@ -53,10 +53,6 @@ export class HubGoals extends BasicSerializableObject { } this.upgradeImprovements[upgradeId] = totalImprovement; } - - if (G_IS_DEV) { - this.storedShapes[blueprintShape] = 1000; - } } /** @@ -81,10 +77,6 @@ export class HubGoals extends BasicSerializableObject { */ this.storedShapes = {}; - if (G_IS_DEV) { - this.storedShapes[blueprintShape] = 1000; - } - /** * Stores the levels for all upgrades * @type {Object} @@ -128,9 +120,9 @@ export class HubGoals extends BasicSerializableObject { */ takeShapeByKey(key, amount) { assert(this.getShapesStoredByKey(key) >= amount, "Can not afford: " + key + " x " + amount); - assert(amount > 0, "Amount <= 0 for " + key); + assert(amount >= 0, "Amount < 0 for " + key); assert(Number.isInteger(amount), "Invalid amount: " + amount); - this.storedShapes[key] -= amount; + this.storedShapes[key] = (this.storedShapes[key] || 0) - amount; return; } diff --git a/src/js/game/hud/hud.js b/src/js/game/hud/hud.js index b21aa2b9..4b13b9f3 100644 --- a/src/js/game/hud/hud.js +++ b/src/js/game/hud/hud.js @@ -29,6 +29,10 @@ import { HUDModalDialogs } from "./parts/modal_dialogs"; import { HUDPartTutorialHints } from "./parts/tutorial_hints"; import { HUDWaypoints } from "./parts/waypoints"; +/* dev:start */ +import { TrailerMaker } from "./trailer_maker"; +/* dev:end */ + export class GameHUD { /** * @param {GameRoot} root @@ -98,6 +102,12 @@ export class GameHUD { this.internalInitSignalConnections(); this.root.keyMapper.getBinding(KEYMAPPINGS.ingame.toggleHud).add(this.toggleUi, this); + + /* dev:start */ + if (G_IS_DEV && globalConfig.debug.renderForTrailer) { + this.trailerMaker = new TrailerMaker(this.root); + } + /* dev:end*/ } /** @@ -174,6 +184,10 @@ export class GameHUD { for (const key in this.parts) { this.parts[key].update(); } + + /* dev:start */ + this.trailerMaker.update(); + /* dev:end*/ } /** diff --git a/src/js/game/hud/parts/blueprint.js b/src/js/game/hud/parts/blueprint.js index 16d0e7da..6dcd4c43 100644 --- a/src/js/game/hud/parts/blueprint.js +++ b/src/js/game/hud/parts/blueprint.js @@ -7,6 +7,7 @@ import { GameRoot } from "../../root"; import { findNiceIntegerValue } from "../../../core/utils"; import { Math_pow } from "../../../core/builtins"; import { blueprintShape } from "../../upgrades"; +import { globalConfig } from "../../../core/config"; const logger = createLogger("blueprint"); @@ -54,6 +55,9 @@ export class Blueprint { * Returns the cost of this blueprint in shapes */ getCost() { + if (G_IS_DEV && globalConfig.debug.blueprintsNoCost) { + return 0; + } return findNiceIntegerValue(4 * Math_pow(this.entities.length, 1.1)); } diff --git a/src/js/game/hud/parts/unlock_notification.js b/src/js/game/hud/parts/unlock_notification.js index 8427c01e..847efc70 100644 --- a/src/js/game/hud/parts/unlock_notification.js +++ b/src/js/game/hud/parts/unlock_notification.js @@ -90,10 +90,15 @@ export class HUDUnlockNotification extends BaseHUDPart { } this.element.querySelector("button.close").classList.remove("unlocked"); - this.buttonShowTimeout = setTimeout( - () => this.element.querySelector("button.close").classList.add("unlocked"), - G_IS_DEV ? 100 : 10000 - ); + + if (this.root.app.settings.getAllSettings().offerHints) { + this.buttonShowTimeout = setTimeout( + () => this.element.querySelector("button.close").classList.add("unlocked"), + G_IS_DEV ? 100 : 5000 + ); + } else { + this.element.querySelector("button.close").classList.add("unlocked"); + } } cleanup() { diff --git a/src/js/game/hud/trailer_maker.js b/src/js/game/hud/trailer_maker.js new file mode 100644 index 00000000..72509b93 --- /dev/null +++ b/src/js/game/hud/trailer_maker.js @@ -0,0 +1,126 @@ +import { GameRoot } from "../root"; +import { globalConfig } from "../../core/config"; +import { Vector, mixVector } from "../../core/vector"; +import { performanceNow } from "../../core/builtins"; +import { lerp } from "../../core/utils"; + +/* dev:start */ +import trailerPoints from "./trailer_points"; +import { gMetaBuildingRegistry } from "../../core/global_registries"; +import { MetaBeltBaseBuilding } from "../buildings/belt_base"; +import { MinerComponent } from "../components/miner"; + +const tickrate = 1 / 165; + +export class TrailerMaker { + /** + * + * @param {GameRoot} root + */ + constructor(root) { + this.root = root; + + this.markers = []; + this.playbackMarkers = null; + this.currentPlaybackOrigin = new Vector(); + this.currentPlaybackZoom = 3; + + window.addEventListener("keydown", ev => { + if (ev.key === "j") { + console.log("Record"); + this.markers.push({ + pos: this.root.camera.center.copy(), + zoom: this.root.camera.zoomLevel, + time: 1, + wait: 0, + }); + } else if (ev.key === "k") { + console.log("Export"); + const json = JSON.stringify(this.markers); + const handle = window.open("about:blank"); + handle.document.write(json); + } else if (ev.key === "u") { + if (this.playbackMarkers && this.playbackMarkers.length > 0) { + this.playbackMarkers = []; + return; + } + console.log("Playback"); + this.playbackMarkers = trailerPoints.map(p => Object.assign({}, p)); + this.playbackMarkers.unshift(this.playbackMarkers[0]); + this.currentPlaybackOrigin = Vector.fromSerializedObject(this.playbackMarkers[0].pos); + + this.currentPlaybackZoom = this.playbackMarkers[0].zoom; + this.root.camera.center = this.currentPlaybackOrigin.copy(); + this.root.camera.zoomLevel = this.currentPlaybackZoom; + console.log("STart at", this.currentPlaybackOrigin); + + // this.root.entityMgr.getAllWithComponent(MinerComponent).forEach(miner => { + // miner.components.Miner.itemChainBuffer = []; + // miner.components.Miner.lastMiningTime = this.root.time.now() + 5; + // miner.components.ItemEjector.slots.forEach(slot => (slot.item = null)); + // }); + + // this.root.logic.tryPlaceBuilding({ + // origin: new Vector(-428, -15), + // building: gMetaBuildingRegistry.findByClass(MetaBeltBaseBuilding), + // originalRotation: 0, + // rotation: 0, + // variant: "default", + // rotationVariant: 0, + // }); + + // this.root.logic.tryPlaceBuilding({ + // origin: new Vector(-427, -15), + // building: gMetaBuildingRegistry.findByClass(MetaBeltBaseBuilding), + // originalRotation: 0, + // rotation: 0, + // variant: "default", + // rotationVariant: 0, + // }); + } + }); + } + + update() { + if (this.playbackMarkers && this.playbackMarkers.length > 0) { + const nextMarker = this.playbackMarkers[0]; + + if (!nextMarker.startTime) { + console.log("Starting to approach", nextMarker.pos); + nextMarker.startTime = performanceNow() / 1000.0; + } + + const speed = + globalConfig.tileSize * + globalConfig.beltSpeedItemsPerSecond * + globalConfig.itemSpacingOnBelts; + // let time = + // this.currentPlaybackOrigin.distance(Vector.fromSerializedObject(nextMarker.pos)) / speed; + const time = nextMarker.time; + + const progress = (performanceNow() / 1000.0 - nextMarker.startTime) / time; + + if (progress > 1.0) { + if (nextMarker.wait > 0) { + nextMarker.wait -= tickrate; + } else { + console.log("Approached"); + this.currentPlaybackOrigin = this.root.camera.center.copy(); + this.currentPlaybackZoom = this.root.camera.zoomLevel; + this.playbackMarkers.shift(); + } + return; + } + + const targetPos = Vector.fromSerializedObject(nextMarker.pos); + const targetZoom = nextMarker.zoom; + + const pos = mixVector(this.currentPlaybackOrigin, targetPos, progress); + const zoom = lerp(this.currentPlaybackZoom, targetZoom, progress); + this.root.camera.zoomLevel = zoom; + this.root.camera.center = pos; + } + } +} + +/* dev:end */ diff --git a/src/js/game/hud/trailer_points.js b/src/js/game/hud/trailer_points.js new file mode 100644 index 00000000..35a9be91 --- /dev/null +++ b/src/js/game/hud/trailer_points.js @@ -0,0 +1,89 @@ +export default [ + // // initial + // { pos: { x: -13665, y: -434 }, zoom: 6, time: 1, wait: 8 }, + + // // Go up to first curve + // { pos: { x: -13665, y: -580 }, zoom: 6, time: 1, wait: 0 }, + + // // To balancers + // { pos: { x: -13450, y: -580 }, zoom: 6, time: 1, wait: 0 }, + + // // To cutters + // { pos: { x: -13350, y: -580 }, zoom: 3, time: 1, wait: 2 }, + + // // To initial cutters + // { pos: { x: -12713, y: -580 }, zoom: 3, time: 1, wait: 2.5 }, + + // // To rotaters 3,2,1,0 + // { pos: { x: -12402, y: -580 }, zoom: 3, time: 1, wait: 0 }, + + // // Zoom in further to stackers + // { pos: { x: -12045, y: -580 }, zoom: 6, time: 1, wait: 4 }, + + // // Focus on painter + // { pos: { x: -11700, y: -660 }, zoom: 6, time: 1, wait: 3.5 }, + + // // Zoom in to mixers + // { pos: { x: -11463, y: -520 }, zoom: 6, time: 1, wait: 3.8 }, + + // // Focus to second painter + // { pos: { x: -11290, y: -610 }, zoom: 6, time: 1, wait: 1 }, + + // // Second stacker + // { pos: { x: -11022, y: -610 }, zoom: 6, time: 1, wait: 0 }, + + // // Go right until first curve + // { pos: { x: -10859, y: -650 }, zoom: 6, time: 1, wait: 0 }, + + // // Go up to stacker + // { pos: { x: -10859, y: -1120 }, zoom: 6, time: 1, wait: 0 }, + + // // Go further up + // { pos: { x: -10859, y: -1260 }, zoom: 6, time: 1, wait: 0 }, + + // // Go left + // { pos: { x: -11235, y: -1260 }, zoom: 6, time: 1, wait: 1 }, + + // OWO Savegames + // { pos: { x: -4939.356940622392, y: 71.76431237675517 }, zoom: 5.06640625, time: 1, wait: 1 }, + // { pos: { x: -4275.441641063683, y: 26.3603982512193 }, zoom: 0.45, time: 32, wait: 0 }, + + // Eve + + // { pos: { x: -277.22574043554704, y: 2151.1873666983033 }, zoom: 3.1, time: 0, wait: 2 }, + // { pos: { x: -43.64015426578788, y: 1577.5520572108883 }, zoom: 1.4, time: 16, wait: 0 }, + // { pos: { x: 133.22735227708466, y: 957.2211413984563 }, zoom: 1.4, time: 8, wait: 0 }, + // { pos: { x: 480.20365842184424, y: -313.5485044644265 }, zoom: 1.4, time: 8, wait: 0 }, + // { + // pos: { x: 452.56528647804333, y: -1341.6422407571154 }, + // zoom: 1.4, + // time: 8, + // wait: 0, + // }, + + // D + { pos: { x: -7506.562977380196, y: 1777.6671860680613 }, zoom: 2.3764616075569833, time: 0, wait: 1 }, + { pos: { x: -7506.562977380196, y: 1777.6671860680613 }, zoom: 2.3764616075569833, time: 1, wait: 0 }, + { pos: { x: -6592.471896026158, y: 1841.974816890533 }, zoom: 1.4594444847409322, time: 24, wait: 0 }, + { pos: { x: -7274.384090342281, y: 729.3783696229457 }, zoom: 1.4594444847409322, time: 24, wait: 0 }, + { pos: { x: -6048.006011617565, y: 764.6297752493597 }, zoom: 1.1853320776932916, time: 24, wait: 0 }, + { + pos: { x: -3674.7204249483366, y: 658.6366426023269 }, + zoom: 0.25332031250000003, + time: 24, + wait: 0, + }, + { + pos: { x: -1213.9916574596728, y: -1387.1496772071198 }, + zoom: 0.443058809814453, + time: 24, + wait: 0, + }, + { + pos: { x: 1722.5210292405573, y: -2457.2072755163636 }, + zoom: 0.6313986260996299, + time: 24, + wait: 0, + }, + { pos: { x: 3533.263459106946, y: -1806.6756300805193 }, zoom: 1.551908182277415, time: 24, wait: 0 }, +]; diff --git a/src/js/game/systems/belt.js b/src/js/game/systems/belt.js index dd173045..0b299964 100644 --- a/src/js/game/systems/belt.js +++ b/src/js/game/systems/belt.js @@ -206,14 +206,18 @@ export class BeltSystem extends GameSystemWithFilter { this.computeBeltCache(); } + // Divide by item spacing on belts since we use throughput and not speed + let beltSpeed = + this.root.hubGoals.getBeltBaseSpeed() * + this.root.dynamicTickrate.deltaSeconds * + globalConfig.itemSpacingOnBelts; + if (G_IS_DEV && globalConfig.debug.instantBelts) { + beltSpeed *= 100; + } + for (let i = 0; i < this.beltCache.length; ++i) { const { entity, followUp } = this.beltCache[i]; - // Divide by item spacing on belts since we use throughput and not speed - const beltSpeed = - this.root.hubGoals.getBeltBaseSpeed() * - this.root.dynamicTickrate.deltaSeconds * - globalConfig.itemSpacingOnBelts; const beltComp = entity.components.Belt; const items = beltComp.sortedItems; diff --git a/src/js/game/systems/item_ejector.js b/src/js/game/systems/item_ejector.js index 503356ad..e714cce5 100644 --- a/src/js/game/systems/item_ejector.js +++ b/src/js/game/systems/item_ejector.js @@ -14,7 +14,11 @@ export class ItemEjectorSystem extends GameSystemWithFilter { update() { const effectiveBeltSpeed = this.root.hubGoals.getBeltBaseSpeed() * globalConfig.itemSpacingOnBelts; - const progressGrowth = (effectiveBeltSpeed / 0.5) * this.root.dynamicTickrate.deltaSeconds; + let progressGrowth = (effectiveBeltSpeed / 0.5) * this.root.dynamicTickrate.deltaSeconds; + + if (G_IS_DEV && globalConfig.debug.instantBelts) { + progressGrowth = 1; + } // Try to find acceptors for every ejector for (let i = 0; i < this.allEntities.length; ++i) { diff --git a/src/js/game/systems/item_processor.js b/src/js/game/systems/item_processor.js index d3f68c04..ae7a4568 100644 --- a/src/js/game/systems/item_processor.js +++ b/src/js/game/systems/item_processor.js @@ -26,6 +26,10 @@ export class ItemProcessorSystem extends GameSystemWithFilter { processorComp.secondsUntilEject - this.root.dynamicTickrate.deltaSeconds ); + if (G_IS_DEV && globalConfig.debug.instantProcessors) { + processorComp.secondsUntilEject = 0; + } + // Check if we have any finished items we can eject if ( processorComp.secondsUntilEject === 0 && // it was processed in time diff --git a/src/js/game/systems/miner.js b/src/js/game/systems/miner.js index 5420cf36..78223516 100644 --- a/src/js/game/systems/miner.js +++ b/src/js/game/systems/miner.js @@ -13,7 +13,11 @@ export class MinerSystem extends GameSystemWithFilter { } update() { - const miningSpeed = this.root.hubGoals.getMinerBaseSpeed(); + let miningSpeed = this.root.hubGoals.getMinerBaseSpeed(); + if (G_IS_DEV && globalConfig.debug.instantMiners) { + miningSpeed *= 100; + } + for (let i = 0; i < this.allEntities.length; ++i) { const entity = this.allEntities[i]; diff --git a/src/js/game/systems/underground_belt.js b/src/js/game/systems/underground_belt.js index 538fab36..34decc11 100644 --- a/src/js/game/systems/underground_belt.js +++ b/src/js/game/systems/underground_belt.js @@ -32,6 +32,10 @@ export class UndergroundBeltSystem extends GameSystemWithFilter { for (let k = 0; k < undergroundComp.pendingItems.length; ++k) { const item = undergroundComp.pendingItems[k]; item[1] = Math_max(0, item[1] - this.root.dynamicTickrate.deltaSeconds); + + if (G_IS_DEV && globalConfig.debug.instantBelts) { + item[1] = 0; + } } if (undergroundComp.mode === enumUndergroundBeltMode.sender) { diff --git a/src/js/game/time/game_time.js b/src/js/game/time/game_time.js index 44623be2..748ccb2d 100644 --- a/src/js/game/time/game_time.js +++ b/src/js/game/time/game_time.js @@ -113,7 +113,6 @@ export class GameTime extends BasicSerializableObject { } if (this.logicTimeBudget > this.root.dynamicTickrate.deltaMs * maxLogicSteps) { - // logger.warn("Skipping logic time steps since more than", maxLogicSteps, "are in queue"); this.logicTimeBudget = this.root.dynamicTickrate.deltaMs * maxLogicSteps; } } diff --git a/src/js/states/main_menu.js b/src/js/states/main_menu.js index f6cfaa02..28b0d45c 100644 --- a/src/js/states/main_menu.js +++ b/src/js/states/main_menu.js @@ -279,7 +279,13 @@ export class MainMenuState extends GameState { for (let i = 0; i < games.length; ++i) { const elem = makeDiv(parent, null, ["savegame"]); - makeDiv(elem, null, ["internalId"], games[i].internalId.substr(0, 6)); + makeDiv( + elem, + null, + ["playtime"], + formatSecondsToTimeAgo((new Date().getTime() - games[i].lastUpdate) / 1000.0) + ); + makeDiv( elem, null, diff --git a/translations/base-en.yaml b/translations/base-en.yaml index e293516f..f424d9b1 100644 --- a/translations/base-en.yaml +++ b/translations/base-en.yaml @@ -572,6 +572,7 @@ keybindings: mapZoomIn: Zoom in mapZoomOut: Zoom out + createMarker: Create Marker menuOpenShop: Upgrades menuOpenStats: Statistics