mirror of
https://github.com/tobspr/shapez.io.git
synced 2024-10-27 20:34:29 +00:00
Add final shapes and upgrades until tier 20
This commit is contained in:
parent
d27e9226be
commit
4f6d9785c1
@ -1,7 +1,8 @@
|
|||||||
#ingame_HUD_BetaOverlay {
|
#ingame_HUD_BetaOverlay {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
@include S(top, 10px);
|
@include S(top, 10px);
|
||||||
@include S(right, 15px);
|
left: 50%;
|
||||||
|
transform: translateX(-50%);
|
||||||
color: $colorRedBright;
|
color: $colorRedBright;
|
||||||
@include Heading;
|
@include Heading;
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
import { globalConfig } from "../core/config";
|
import { globalConfig } from "../core/config";
|
||||||
|
import { RandomNumberGenerator } from "../core/rng";
|
||||||
import { clamp, findNiceIntegerValue, randomChoice, randomInt } from "../core/utils";
|
import { clamp, findNiceIntegerValue, randomChoice, randomInt } from "../core/utils";
|
||||||
import { BasicSerializableObject, types } from "../savegame/serialization";
|
import { BasicSerializableObject, types } from "../savegame/serialization";
|
||||||
import { enumColors } from "./colors";
|
import { enumColors } from "./colors";
|
||||||
import { enumItemProcessorTypes } from "./components/item_processor";
|
import { enumItemProcessorTypes } from "./components/item_processor";
|
||||||
|
import { enumAnalyticsDataSource } from "./production_analytics";
|
||||||
import { GameRoot } from "./root";
|
import { GameRoot } from "./root";
|
||||||
import { enumSubShape, ShapeDefinition } from "./shape_definition";
|
import { enumSubShape, ShapeDefinition } from "./shape_definition";
|
||||||
import { enumHubGoalRewards, tutorialGoals } from "./tutorial_goals";
|
import { enumHubGoalRewards, tutorialGoals } from "./tutorial_goals";
|
||||||
@ -18,12 +20,6 @@ export class HubGoals extends BasicSerializableObject {
|
|||||||
level: types.uint,
|
level: types.uint,
|
||||||
storedShapes: types.keyValueMap(types.uint),
|
storedShapes: types.keyValueMap(types.uint),
|
||||||
upgradeLevels: types.keyValueMap(types.uint),
|
upgradeLevels: types.keyValueMap(types.uint),
|
||||||
|
|
||||||
currentGoal: types.structured({
|
|
||||||
definition: types.knownType(ShapeDefinition),
|
|
||||||
required: types.uint,
|
|
||||||
reward: types.nullable(types.enum(enumHubGoalRewards)),
|
|
||||||
}),
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -53,15 +49,7 @@ export class HubGoals extends BasicSerializableObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Compute current goal
|
// Compute current goal
|
||||||
const goal = tutorialGoals[this.level - 1];
|
this.computeNextGoal();
|
||||||
if (goal) {
|
|
||||||
this.currentGoal = {
|
|
||||||
/** @type {ShapeDefinition} */
|
|
||||||
definition: this.root.shapeDefinitionMgr.getShapeFromShortKey(goal.shape),
|
|
||||||
required: goal.required,
|
|
||||||
reward: goal.reward,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -106,7 +94,7 @@ export class HubGoals extends BasicSerializableObject {
|
|||||||
this.upgradeImprovements[key] = 1;
|
this.upgradeImprovements[key] = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.createNextGoal();
|
this.computeNextGoal();
|
||||||
|
|
||||||
// Allow quickly switching goals in dev mode
|
// Allow quickly switching goals in dev mode
|
||||||
if (G_IS_DEV) {
|
if (G_IS_DEV) {
|
||||||
@ -155,6 +143,13 @@ export class HubGoals extends BasicSerializableObject {
|
|||||||
* Returns how much of the current goal was already delivered
|
* Returns how much of the current goal was already delivered
|
||||||
*/
|
*/
|
||||||
getCurrentGoalDelivered() {
|
getCurrentGoalDelivered() {
|
||||||
|
if (this.currentGoal.throughputOnly) {
|
||||||
|
return this.root.productionAnalytics.getCurrentShapeRate(
|
||||||
|
enumAnalyticsDataSource.delivered,
|
||||||
|
this.currentGoal.definition
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return this.getShapesStored(this.currentGoal.definition);
|
return this.getShapesStored(this.currentGoal.definition);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -189,9 +184,8 @@ export class HubGoals extends BasicSerializableObject {
|
|||||||
this.root.signals.shapeDelivered.dispatch(definition);
|
this.root.signals.shapeDelivered.dispatch(definition);
|
||||||
|
|
||||||
// Check if we have enough for the next level
|
// Check if we have enough for the next level
|
||||||
const targetHash = this.currentGoal.definition.getHash();
|
|
||||||
if (
|
if (
|
||||||
this.storedShapes[targetHash] >= this.currentGoal.required ||
|
this.getCurrentGoalDelivered() >= this.currentGoal.required ||
|
||||||
(G_IS_DEV && globalConfig.debug.rewardsInstant)
|
(G_IS_DEV && globalConfig.debug.rewardsInstant)
|
||||||
) {
|
) {
|
||||||
this.onGoalCompleted();
|
this.onGoalCompleted();
|
||||||
@ -201,24 +195,28 @@ export class HubGoals extends BasicSerializableObject {
|
|||||||
/**
|
/**
|
||||||
* Creates the next goal
|
* Creates the next goal
|
||||||
*/
|
*/
|
||||||
createNextGoal() {
|
computeNextGoal() {
|
||||||
const storyIndex = this.level - 1;
|
const storyIndex = this.level - 1;
|
||||||
if (storyIndex < tutorialGoals.length) {
|
if (storyIndex < tutorialGoals.length) {
|
||||||
const { shape, required, reward } = tutorialGoals[storyIndex];
|
const { shape, required, reward, throughputOnly } = tutorialGoals[storyIndex];
|
||||||
this.currentGoal = {
|
this.currentGoal = {
|
||||||
/** @type {ShapeDefinition} */
|
/** @type {ShapeDefinition} */
|
||||||
definition: this.root.shapeDefinitionMgr.getShapeFromShortKey(shape),
|
definition: this.root.shapeDefinitionMgr.getShapeFromShortKey(shape),
|
||||||
required,
|
required,
|
||||||
reward,
|
reward,
|
||||||
|
throughputOnly,
|
||||||
};
|
};
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const required = 4 + (this.level - 27) * 0.25;
|
||||||
|
|
||||||
this.currentGoal = {
|
this.currentGoal = {
|
||||||
/** @type {ShapeDefinition} */
|
/** @type {ShapeDefinition} */
|
||||||
definition: this.createRandomShape(),
|
definition: this.computeFreeplayShape(this.level),
|
||||||
required: findNiceIntegerValue(1000 + Math.pow(this.level * 2000, 0.8)),
|
required,
|
||||||
reward: enumHubGoalRewards.no_reward_freeplay,
|
reward: enumHubGoalRewards.no_reward_freeplay,
|
||||||
|
throughputOnly: true,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -231,7 +229,7 @@ export class HubGoals extends BasicSerializableObject {
|
|||||||
|
|
||||||
this.root.app.gameAnalytics.handleLevelCompleted(this.level);
|
this.root.app.gameAnalytics.handleLevelCompleted(this.level);
|
||||||
++this.level;
|
++this.level;
|
||||||
this.createNextGoal();
|
this.computeNextGoal();
|
||||||
|
|
||||||
this.root.signals.storyGoalCompleted.dispatch(this.level - 1, reward);
|
this.root.signals.storyGoalCompleted.dispatch(this.level - 1, reward);
|
||||||
}
|
}
|
||||||
@ -325,15 +323,85 @@ export class HubGoals extends BasicSerializableObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Picks random colors which are close to each other
|
||||||
|
* @param {RandomNumberGenerator} rng
|
||||||
|
*/
|
||||||
|
generateRandomColorSet(rng, allowUncolored = false) {
|
||||||
|
const colorWheel = [
|
||||||
|
enumColors.red,
|
||||||
|
enumColors.yellow,
|
||||||
|
enumColors.green,
|
||||||
|
enumColors.cyan,
|
||||||
|
enumColors.blue,
|
||||||
|
enumColors.purple,
|
||||||
|
enumColors.red,
|
||||||
|
enumColors.yellow,
|
||||||
|
];
|
||||||
|
|
||||||
|
const universalColors = [enumColors.white];
|
||||||
|
if (allowUncolored) {
|
||||||
|
universalColors.push(enumColors.uncolored);
|
||||||
|
}
|
||||||
|
const index = rng.nextIntRangeInclusive(0, colorWheel.length - 3);
|
||||||
|
const pickedColors = colorWheel.slice(index, index + 3);
|
||||||
|
pickedColors.push(rng.choice(universalColors));
|
||||||
|
return pickedColors;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a (seeded) random shape
|
||||||
|
* @param {number} level
|
||||||
* @returns {ShapeDefinition}
|
* @returns {ShapeDefinition}
|
||||||
*/
|
*/
|
||||||
createRandomShape() {
|
computeFreeplayShape(level) {
|
||||||
const layerCount = clamp(this.level / 25, 2, 4);
|
const layerCount = clamp(this.level / 25, 2, 4);
|
||||||
|
|
||||||
/** @type {Array<import("./shape_definition").ShapeLayer>} */
|
/** @type {Array<import("./shape_definition").ShapeLayer>} */
|
||||||
let layers = [];
|
let layers = [];
|
||||||
|
|
||||||
const randomColor = () => randomChoice(Object.values(enumColors));
|
const rng = new RandomNumberGenerator(this.root.map.seed + "/" + level);
|
||||||
const randomShape = () => randomChoice(Object.values(enumSubShape));
|
|
||||||
|
const colors = this.generateRandomColorSet(rng, level > 35);
|
||||||
|
|
||||||
|
let pickedSymmetry = null; // pairs of quadrants that must be the same
|
||||||
|
let availableShapes = [enumSubShape.rect, enumSubShape.circle, enumSubShape.star];
|
||||||
|
if (rng.next() < 0.5) {
|
||||||
|
pickedSymmetry = [
|
||||||
|
// radial symmetry
|
||||||
|
[0, 2],
|
||||||
|
[1, 3],
|
||||||
|
];
|
||||||
|
availableShapes.push(enumSubShape.windmill); // windmill looks good only in radial symmetry
|
||||||
|
} else {
|
||||||
|
const symmetries = [
|
||||||
|
[
|
||||||
|
// horizontal axis
|
||||||
|
[0, 3],
|
||||||
|
[1, 2],
|
||||||
|
],
|
||||||
|
[
|
||||||
|
// vertical axis
|
||||||
|
[0, 1],
|
||||||
|
[2, 3],
|
||||||
|
],
|
||||||
|
[
|
||||||
|
// diagonal axis
|
||||||
|
[0, 2],
|
||||||
|
[1],
|
||||||
|
[3],
|
||||||
|
],
|
||||||
|
[
|
||||||
|
// other diagonal axis
|
||||||
|
[1, 3],
|
||||||
|
[0],
|
||||||
|
[2],
|
||||||
|
],
|
||||||
|
];
|
||||||
|
pickedSymmetry = rng.choice(symmetries);
|
||||||
|
}
|
||||||
|
|
||||||
|
const randomColor = () => rng.choice(colors);
|
||||||
|
const randomShape = () => rng.choice(Object.values(enumSubShape));
|
||||||
|
|
||||||
let anyIsMissingTwo = false;
|
let anyIsMissingTwo = false;
|
||||||
|
|
||||||
@ -341,23 +409,24 @@ export class HubGoals extends BasicSerializableObject {
|
|||||||
/** @type {import("./shape_definition").ShapeLayer} */
|
/** @type {import("./shape_definition").ShapeLayer} */
|
||||||
const layer = [null, null, null, null];
|
const layer = [null, null, null, null];
|
||||||
|
|
||||||
for (let quad = 0; quad < 4; ++quad) {
|
for (let j = 0; j < pickedSymmetry.length; ++j) {
|
||||||
layer[quad] = {
|
const group = pickedSymmetry[j];
|
||||||
subShape: randomShape(),
|
const shape = randomShape();
|
||||||
color: randomColor(),
|
const color = randomColor();
|
||||||
};
|
for (let k = 0; k < group.length; ++k) {
|
||||||
}
|
const quad = group[k];
|
||||||
|
layer[quad] = {
|
||||||
// Sometimes shapes are missing
|
subShape: shape,
|
||||||
if (Math.random() > 0.85) {
|
color,
|
||||||
layer[randomInt(0, 3)] = null;
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sometimes they actually are missing *two* ones!
|
// Sometimes they actually are missing *two* ones!
|
||||||
// Make sure at max only one layer is missing it though, otherwise we could
|
// Make sure at max only one layer is missing it though, otherwise we could
|
||||||
// create an uncreateable shape
|
// create an uncreateable shape
|
||||||
if (Math.random() > 0.95 && !anyIsMissingTwo) {
|
if (level > 75 && rng.next() > 0.95 && !anyIsMissingTwo) {
|
||||||
layer[randomInt(0, 3)] = null;
|
layer[rng.nextIntRange(0, 4)] = null;
|
||||||
anyIsMissingTwo = true;
|
anyIsMissingTwo = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -44,6 +44,7 @@ import { HUDWireInfo } from "./parts/wire_info";
|
|||||||
import { HUDLeverToggle } from "./parts/lever_toggle";
|
import { HUDLeverToggle } from "./parts/lever_toggle";
|
||||||
import { HUDLayerPreview } from "./parts/layer_preview";
|
import { HUDLayerPreview } from "./parts/layer_preview";
|
||||||
import { HUDMinerHighlight } from "./parts/miner_highlight";
|
import { HUDMinerHighlight } from "./parts/miner_highlight";
|
||||||
|
import { HUDBetaOverlay } from "./parts/beta_overlay";
|
||||||
|
|
||||||
export class GameHUD {
|
export class GameHUD {
|
||||||
/**
|
/**
|
||||||
@ -75,7 +76,6 @@ export class GameHUD {
|
|||||||
pinnedShapes: new HUDPinnedShapes(this.root),
|
pinnedShapes: new HUDPinnedShapes(this.root),
|
||||||
notifications: new HUDNotifications(this.root),
|
notifications: new HUDNotifications(this.root),
|
||||||
settingsMenu: new HUDSettingsMenu(this.root),
|
settingsMenu: new HUDSettingsMenu(this.root),
|
||||||
// betaOverlay: new HUDBetaOverlay(this.root),
|
|
||||||
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),
|
||||||
@ -137,6 +137,10 @@ export class GameHUD {
|
|||||||
this.parts.sandboxController = new HUDSandboxController(this.root);
|
this.parts.sandboxController = new HUDSandboxController(this.root);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!G_IS_RELEASE) {
|
||||||
|
this.parts.betaOverlay = new HUDBetaOverlay(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);
|
||||||
|
@ -3,7 +3,7 @@ import { makeDiv } from "../../../core/utils";
|
|||||||
|
|
||||||
export class HUDBetaOverlay extends BaseHUDPart {
|
export class HUDBetaOverlay extends BaseHUDPart {
|
||||||
createElements(parent) {
|
createElements(parent) {
|
||||||
this.element = makeDiv(parent, "ingame_HUD_BetaOverlay", [], "CLOSED BETA");
|
this.element = makeDiv(parent, "ingame_HUD_BetaOverlay", [], "BETA VERSION");
|
||||||
}
|
}
|
||||||
|
|
||||||
initialize() {}
|
initialize() {}
|
||||||
|
@ -4,6 +4,8 @@ import { ShapeDefinition } from "../../shape_definition";
|
|||||||
import { BaseHUDPart } from "../base_hud_part";
|
import { BaseHUDPart } from "../base_hud_part";
|
||||||
import { blueprintShape, UPGRADES } from "../../upgrades";
|
import { blueprintShape, UPGRADES } from "../../upgrades";
|
||||||
import { enumHubGoalRewards } from "../../tutorial_goals";
|
import { enumHubGoalRewards } from "../../tutorial_goals";
|
||||||
|
import { enumAnalyticsDataSource } from "../../production_analytics";
|
||||||
|
import { T } from "../../../translations";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Manages the pinned shapes on the left side of the screen
|
* Manages the pinned shapes on the left side of the screen
|
||||||
@ -22,11 +24,13 @@ export class HUDPinnedShapes extends BaseHUDPart {
|
|||||||
* convenient. Also allows for cleaning up handles.
|
* convenient. Also allows for cleaning up handles.
|
||||||
* @type {Array<{
|
* @type {Array<{
|
||||||
* key: string,
|
* key: string,
|
||||||
|
* definition: ShapeDefinition,
|
||||||
* amountLabel: HTMLElement,
|
* amountLabel: HTMLElement,
|
||||||
* lastRenderedValue: string,
|
* lastRenderedValue: string,
|
||||||
* element: HTMLElement,
|
* element: HTMLElement,
|
||||||
* detector?: ClickDetector,
|
* detector?: ClickDetector,
|
||||||
* infoDetector?: ClickDetector
|
* infoDetector?: ClickDetector,
|
||||||
|
* throughputOnly?: boolean
|
||||||
* }>}
|
* }>}
|
||||||
*/
|
*/
|
||||||
this.handles = [];
|
this.handles = [];
|
||||||
@ -163,29 +167,40 @@ export class HUDPinnedShapes extends BaseHUDPart {
|
|||||||
this.handles = [];
|
this.handles = [];
|
||||||
|
|
||||||
// Pin story goal
|
// Pin story goal
|
||||||
this.internalPinShape(currentKey, false, "goal");
|
this.internalPinShape({
|
||||||
|
key: currentKey,
|
||||||
|
canUnpin: false,
|
||||||
|
className: "goal",
|
||||||
|
throughputOnly: currentGoal.throughputOnly,
|
||||||
|
});
|
||||||
|
|
||||||
// Pin blueprint shape as well
|
// Pin blueprint shape as well
|
||||||
if (this.root.hubGoals.isRewardUnlocked(enumHubGoalRewards.reward_blueprints)) {
|
if (this.root.hubGoals.isRewardUnlocked(enumHubGoalRewards.reward_blueprints)) {
|
||||||
this.internalPinShape(blueprintShape, false, "blueprint");
|
this.internalPinShape({
|
||||||
|
key: blueprintShape,
|
||||||
|
canUnpin: false,
|
||||||
|
className: "blueprint",
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pin manually pinned shapes
|
// Pin manually pinned shapes
|
||||||
for (let i = 0; i < this.pinnedShapes.length; ++i) {
|
for (let i = 0; i < this.pinnedShapes.length; ++i) {
|
||||||
const key = this.pinnedShapes[i];
|
const key = this.pinnedShapes[i];
|
||||||
if (key !== currentKey) {
|
if (key !== currentKey) {
|
||||||
this.internalPinShape(key);
|
this.internalPinShape({ key });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Pins a new shape
|
* Pins a new shape
|
||||||
* @param {string} key
|
* @param {object} param0
|
||||||
* @param {boolean} canUnpin
|
* @param {string} param0.key
|
||||||
* @param {string=} className
|
* @param {boolean=} param0.canUnpin
|
||||||
|
* @param {string=} param0.className
|
||||||
|
* @param {boolean=} param0.throughputOnly
|
||||||
*/
|
*/
|
||||||
internalPinShape(key, canUnpin = true, className = null) {
|
internalPinShape({ key, canUnpin = true, className = null, throughputOnly = false }) {
|
||||||
const definition = this.root.shapeDefinitionMgr.getShapeFromShortKey(key);
|
const definition = this.root.shapeDefinitionMgr.getShapeFromShortKey(key);
|
||||||
|
|
||||||
const element = makeDiv(this.element, null, ["shape"]);
|
const element = makeDiv(this.element, null, ["shape"]);
|
||||||
@ -229,11 +244,13 @@ export class HUDPinnedShapes extends BaseHUDPart {
|
|||||||
|
|
||||||
this.handles.push({
|
this.handles.push({
|
||||||
key,
|
key,
|
||||||
|
definition,
|
||||||
element,
|
element,
|
||||||
amountLabel,
|
amountLabel,
|
||||||
lastRenderedValue: "",
|
lastRenderedValue: "",
|
||||||
detector,
|
detector,
|
||||||
infoDetector,
|
infoDetector,
|
||||||
|
throughputOnly,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -244,8 +261,20 @@ export class HUDPinnedShapes extends BaseHUDPart {
|
|||||||
for (let i = 0; i < this.handles.length; ++i) {
|
for (let i = 0; i < this.handles.length; ++i) {
|
||||||
const handle = this.handles[i];
|
const handle = this.handles[i];
|
||||||
|
|
||||||
const currentValue = this.root.hubGoals.getShapesStoredByKey(handle.key);
|
let currentValue = this.root.hubGoals.getShapesStoredByKey(handle.key);
|
||||||
const currentValueFormatted = formatBigNumber(currentValue);
|
let currentValueFormatted = formatBigNumber(currentValue);
|
||||||
|
|
||||||
|
if (handle.throughputOnly) {
|
||||||
|
currentValue = this.root.productionAnalytics.getCurrentShapeRate(
|
||||||
|
enumAnalyticsDataSource.delivered,
|
||||||
|
handle.definition
|
||||||
|
);
|
||||||
|
currentValueFormatted = T.ingame.statistics.shapesDisplayUnits.second.replace(
|
||||||
|
"<shapes>",
|
||||||
|
String(currentValue)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
if (currentValueFormatted !== handle.lastRenderedValue) {
|
if (currentValueFormatted !== handle.lastRenderedValue) {
|
||||||
handle.lastRenderedValue = currentValueFormatted;
|
handle.lastRenderedValue = currentValueFormatted;
|
||||||
handle.amountLabel.innerText = currentValueFormatted;
|
handle.amountLabel.innerText = currentValueFormatted;
|
||||||
|
@ -113,7 +113,7 @@ export class HUDSandboxController extends BaseHUDPart {
|
|||||||
modifyLevel(amount) {
|
modifyLevel(amount) {
|
||||||
const hubGoals = this.root.hubGoals;
|
const hubGoals = this.root.hubGoals;
|
||||||
hubGoals.level = Math.max(1, hubGoals.level + amount);
|
hubGoals.level = Math.max(1, hubGoals.level + amount);
|
||||||
hubGoals.createNextGoal();
|
hubGoals.computeNextGoal();
|
||||||
|
|
||||||
// Clear all shapes of this level
|
// Clear all shapes of this level
|
||||||
hubGoals.storedShapes[hubGoals.currentGoal.definition.getHash()] = 0;
|
hubGoals.storedShapes[hubGoals.currentGoal.definition.getHash()] = 0;
|
||||||
|
@ -90,17 +90,15 @@ export class HUDShop extends BaseHUDPart {
|
|||||||
// Max level
|
// Max level
|
||||||
handle.elemDescription.innerText = T.ingame.shop.maximumLevel.replace(
|
handle.elemDescription.innerText = T.ingame.shop.maximumLevel.replace(
|
||||||
"<currentMult>",
|
"<currentMult>",
|
||||||
currentTierMultiplier.toString()
|
formatBigNumber(currentTierMultiplier)
|
||||||
);
|
);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set description
|
// Set description
|
||||||
handle.elemDescription.innerText = T.shopUpgrades[upgradeId].description
|
handle.elemDescription.innerText = T.shopUpgrades[upgradeId].description
|
||||||
.replace("<currentMult>", currentTierMultiplier.toString())
|
.replace("<currentMult>", formatBigNumber(currentTierMultiplier))
|
||||||
.replace("<newMult>", (currentTierMultiplier + tierHandle.improvement).toString())
|
.replace("<newMult>", formatBigNumber(currentTierMultiplier + tierHandle.improvement));
|
||||||
// Backwards compatibility
|
|
||||||
.replace("<gain>", (tierHandle.improvement * 100.0).toString());
|
|
||||||
|
|
||||||
tierHandle.required.forEach(({ shape, amount }) => {
|
tierHandle.required.forEach(({ shape, amount }) => {
|
||||||
const container = makeDiv(handle.elemRequirements, null, ["requirement"]);
|
const container = makeDiv(handle.elemRequirements, null, ["requirement"]);
|
||||||
|
@ -4,11 +4,12 @@ import { makeDiv } from "../../../core/utils";
|
|||||||
import { SOUNDS } from "../../../platform/sound";
|
import { SOUNDS } from "../../../platform/sound";
|
||||||
import { T } from "../../../translations";
|
import { T } from "../../../translations";
|
||||||
import { defaultBuildingVariant } from "../../meta_building";
|
import { defaultBuildingVariant } from "../../meta_building";
|
||||||
import { enumHubGoalRewards } from "../../tutorial_goals";
|
import { enumHubGoalRewards, tutorialGoals } from "../../tutorial_goals";
|
||||||
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 { enumHubGoalRewardsToContentUnlocked } from "../../tutorial_goals_mappings";
|
import { enumHubGoalRewardsToContentUnlocked } from "../../tutorial_goals_mappings";
|
||||||
import { InputReceiver } from "../../../core/input_receiver";
|
import { InputReceiver } from "../../../core/input_receiver";
|
||||||
|
import { enumNotificationType } from "./notifications";
|
||||||
|
|
||||||
export class HUDUnlockNotification extends BaseHUDPart {
|
export class HUDUnlockNotification extends BaseHUDPart {
|
||||||
initialize() {
|
initialize() {
|
||||||
@ -50,6 +51,14 @@ export class HUDUnlockNotification extends BaseHUDPart {
|
|||||||
* @param {enumHubGoalRewards} reward
|
* @param {enumHubGoalRewards} reward
|
||||||
*/
|
*/
|
||||||
showForLevel(level, reward) {
|
showForLevel(level, reward) {
|
||||||
|
if (level > tutorialGoals.length) {
|
||||||
|
this.root.hud.signals.notification.dispatch(
|
||||||
|
T.ingame.notifications.freeplayLevelComplete.replace("<level>", String(level)),
|
||||||
|
enumNotificationType.success
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
this.root.app.inputMgr.makeSureAttachedAndOnTop(this.inputReciever);
|
this.root.app.inputMgr.makeSureAttachedAndOnTop(this.inputReciever);
|
||||||
this.elemTitle.innerText = T.ingame.levelCompleteNotification.levelTitle.replace(
|
this.elemTitle.innerText = T.ingame.levelCompleteNotification.levelTitle.replace(
|
||||||
"<level>",
|
"<level>",
|
||||||
|
@ -1,172 +1,185 @@
|
|||||||
import { DrawParameters } from "../../core/draw_parameters";
|
import { globalConfig } from "../../core/config";
|
||||||
import { Loader } from "../../core/loader";
|
import { smoothenDpi } from "../../core/dpi_manager";
|
||||||
import { formatBigNumber } from "../../core/utils";
|
import { DrawParameters } from "../../core/draw_parameters";
|
||||||
import { T } from "../../translations";
|
import { drawSpriteClipped } from "../../core/draw_utils";
|
||||||
import { HubComponent } from "../components/hub";
|
import { Loader } from "../../core/loader";
|
||||||
import { Entity } from "../entity";
|
import { Rectangle } from "../../core/rectangle";
|
||||||
import { GameSystemWithFilter } from "../game_system_with_filter";
|
import { ORIGINAL_SPRITE_SCALE } from "../../core/sprites";
|
||||||
import { globalConfig } from "../../core/config";
|
import { formatBigNumber } from "../../core/utils";
|
||||||
import { smoothenDpi } from "../../core/dpi_manager";
|
import { T } from "../../translations";
|
||||||
import { drawSpriteClipped } from "../../core/draw_utils";
|
import { HubComponent } from "../components/hub";
|
||||||
import { Rectangle } from "../../core/rectangle";
|
import { Entity } from "../entity";
|
||||||
import { ORIGINAL_SPRITE_SCALE } from "../../core/sprites";
|
import { GameSystemWithFilter } from "../game_system_with_filter";
|
||||||
|
|
||||||
const HUB_SIZE_TILES = 4;
|
const HUB_SIZE_TILES = 4;
|
||||||
const HUB_SIZE_PIXELS = HUB_SIZE_TILES * globalConfig.tileSize;
|
const HUB_SIZE_PIXELS = HUB_SIZE_TILES * globalConfig.tileSize;
|
||||||
|
|
||||||
export class HubSystem extends GameSystemWithFilter {
|
export class HubSystem extends GameSystemWithFilter {
|
||||||
constructor(root) {
|
constructor(root) {
|
||||||
super(root, [HubComponent]);
|
super(root, [HubComponent]);
|
||||||
|
|
||||||
this.hubSprite = Loader.getSprite("sprites/buildings/hub.png");
|
this.hubSprite = Loader.getSprite("sprites/buildings/hub.png");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {DrawParameters} parameters
|
* @param {DrawParameters} parameters
|
||||||
*/
|
*/
|
||||||
draw(parameters) {
|
draw(parameters) {
|
||||||
for (let i = 0; i < this.allEntities.length; ++i) {
|
for (let i = 0; i < this.allEntities.length; ++i) {
|
||||||
this.drawEntity(parameters, this.allEntities[i]);
|
this.drawEntity(parameters, this.allEntities[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
update() {
|
update() {
|
||||||
for (let i = 0; i < this.allEntities.length; ++i) {
|
for (let i = 0; i < this.allEntities.length; ++i) {
|
||||||
// Set hub goal
|
// Set hub goal
|
||||||
const entity = this.allEntities[i];
|
const entity = this.allEntities[i];
|
||||||
const pinsComp = entity.components.WiredPins;
|
const pinsComp = entity.components.WiredPins;
|
||||||
pinsComp.slots[0].value = this.root.shapeDefinitionMgr.getShapeItemFromDefinition(
|
pinsComp.slots[0].value = this.root.shapeDefinitionMgr.getShapeItemFromDefinition(
|
||||||
this.root.hubGoals.currentGoal.definition
|
this.root.hubGoals.currentGoal.definition
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param {HTMLCanvasElement} canvas
|
* @param {HTMLCanvasElement} canvas
|
||||||
* @param {CanvasRenderingContext2D} context
|
* @param {CanvasRenderingContext2D} context
|
||||||
* @param {number} w
|
* @param {number} w
|
||||||
* @param {number} h
|
* @param {number} h
|
||||||
* @param {number} dpi
|
* @param {number} dpi
|
||||||
*/
|
*/
|
||||||
redrawHubBaseTexture(canvas, context, w, h, dpi) {
|
redrawHubBaseTexture(canvas, context, w, h, dpi) {
|
||||||
// This method is quite ugly, please ignore it!
|
// This method is quite ugly, please ignore it!
|
||||||
|
|
||||||
context.scale(dpi, dpi);
|
context.scale(dpi, dpi);
|
||||||
|
|
||||||
const parameters = new DrawParameters({
|
const parameters = new DrawParameters({
|
||||||
context,
|
context,
|
||||||
visibleRect: new Rectangle(0, 0, w, h),
|
visibleRect: new Rectangle(0, 0, w, h),
|
||||||
desiredAtlasScale: ORIGINAL_SPRITE_SCALE,
|
desiredAtlasScale: ORIGINAL_SPRITE_SCALE,
|
||||||
zoomLevel: dpi * 0.75,
|
zoomLevel: dpi * 0.75,
|
||||||
root: this.root,
|
root: this.root,
|
||||||
});
|
});
|
||||||
|
|
||||||
context.clearRect(0, 0, w, h);
|
context.clearRect(0, 0, w, h);
|
||||||
|
|
||||||
this.hubSprite.draw(context, 0, 0, w, h);
|
this.hubSprite.draw(context, 0, 0, w, h);
|
||||||
|
|
||||||
const definition = this.root.hubGoals.currentGoal.definition;
|
const definition = this.root.hubGoals.currentGoal.definition;
|
||||||
definition.drawCentered(45, 58, parameters, 36);
|
definition.drawCentered(45, 58, parameters, 36);
|
||||||
|
|
||||||
const goals = this.root.hubGoals.currentGoal;
|
const goals = this.root.hubGoals.currentGoal;
|
||||||
|
|
||||||
const textOffsetX = 70;
|
const textOffsetX = 70;
|
||||||
const textOffsetY = 61;
|
const textOffsetY = 61;
|
||||||
|
|
||||||
// Deliver count
|
if (goals.throughputOnly) {
|
||||||
const delivered = this.root.hubGoals.getCurrentGoalDelivered();
|
// Throughput
|
||||||
const deliveredText = "" + formatBigNumber(delivered);
|
const deliveredText = T.ingame.statistics.shapesDisplayUnits.second.replace(
|
||||||
|
"<shapes>",
|
||||||
if (delivered > 9999) {
|
formatBigNumber(goals.required)
|
||||||
context.font = "bold 16px GameFont";
|
);
|
||||||
} else if (delivered > 999) {
|
|
||||||
context.font = "bold 20px GameFont";
|
context.font = "bold 12px GameFont";
|
||||||
} else {
|
context.fillStyle = "#64666e";
|
||||||
context.font = "bold 25px GameFont";
|
context.textAlign = "left";
|
||||||
}
|
context.fillText(deliveredText, textOffsetX, textOffsetY);
|
||||||
context.fillStyle = "#64666e";
|
} else {
|
||||||
context.textAlign = "left";
|
// Deliver count
|
||||||
context.fillText(deliveredText, textOffsetX, textOffsetY);
|
const delivered = this.root.hubGoals.getCurrentGoalDelivered();
|
||||||
|
const deliveredText = "" + formatBigNumber(delivered);
|
||||||
// Required
|
|
||||||
context.font = "13px GameFont";
|
if (delivered > 9999) {
|
||||||
context.fillStyle = "#a4a6b0";
|
context.font = "bold 16px GameFont";
|
||||||
context.fillText("/ " + formatBigNumber(goals.required), textOffsetX, textOffsetY + 13);
|
} else if (delivered > 999) {
|
||||||
|
context.font = "bold 20px GameFont";
|
||||||
// Reward
|
} else {
|
||||||
const rewardText = T.storyRewards[goals.reward].title.toUpperCase();
|
context.font = "bold 25px GameFont";
|
||||||
if (rewardText.length > 12) {
|
}
|
||||||
context.font = "bold 8px GameFont";
|
context.fillStyle = "#64666e";
|
||||||
} else {
|
context.textAlign = "left";
|
||||||
context.font = "bold 10px GameFont";
|
context.fillText(deliveredText, textOffsetX, textOffsetY);
|
||||||
}
|
|
||||||
context.fillStyle = "#fd0752";
|
// Required
|
||||||
context.textAlign = "center";
|
context.font = "13px GameFont";
|
||||||
|
context.fillStyle = "#a4a6b0";
|
||||||
context.fillText(rewardText, HUB_SIZE_PIXELS / 2, 105);
|
context.fillText("/ " + formatBigNumber(goals.required), textOffsetX, textOffsetY + 13);
|
||||||
|
}
|
||||||
// Level "8"
|
|
||||||
context.font = "bold 10px GameFont";
|
// Reward
|
||||||
context.fillStyle = "#fff";
|
const rewardText = T.storyRewards[goals.reward].title.toUpperCase();
|
||||||
context.fillText("" + this.root.hubGoals.level, 27, 32);
|
if (rewardText.length > 12) {
|
||||||
|
context.font = "bold 8px GameFont";
|
||||||
// "LVL"
|
} else {
|
||||||
context.textAlign = "center";
|
context.font = "bold 10px GameFont";
|
||||||
context.fillStyle = "#fff";
|
}
|
||||||
context.font = "bold 6px GameFont";
|
context.fillStyle = "#fd0752";
|
||||||
context.fillText(T.buildings.hub.levelShortcut, 27, 22);
|
context.textAlign = "center";
|
||||||
|
|
||||||
// "Deliver"
|
context.fillText(rewardText, HUB_SIZE_PIXELS / 2, 105);
|
||||||
context.fillStyle = "#64666e";
|
|
||||||
context.font = "bold 10px GameFont";
|
// Level "8"
|
||||||
context.fillText(T.buildings.hub.deliver.toUpperCase(), HUB_SIZE_PIXELS / 2, 30);
|
context.font = "bold 10px GameFont";
|
||||||
|
context.fillStyle = "#fff";
|
||||||
// "To unlock"
|
context.fillText("" + this.root.hubGoals.level, 27, 32);
|
||||||
const unlockText = T.buildings.hub.toUnlock.toUpperCase();
|
|
||||||
if (unlockText.length > 15) {
|
// "LVL"
|
||||||
context.font = "bold 8px GameFont";
|
context.textAlign = "center";
|
||||||
} else {
|
context.fillStyle = "#fff";
|
||||||
context.font = "bold 10px GameFont";
|
context.font = "bold 6px GameFont";
|
||||||
}
|
context.fillText(T.buildings.hub.levelShortcut, 27, 22);
|
||||||
context.fillText(T.buildings.hub.toUnlock.toUpperCase(), HUB_SIZE_PIXELS / 2, 92);
|
|
||||||
|
// "Deliver"
|
||||||
context.textAlign = "left";
|
context.fillStyle = "#64666e";
|
||||||
}
|
context.font = "bold 10px GameFont";
|
||||||
|
context.fillText(T.buildings.hub.deliver.toUpperCase(), HUB_SIZE_PIXELS / 2, 30);
|
||||||
/**
|
|
||||||
* @param {DrawParameters} parameters
|
// "To unlock"
|
||||||
* @param {Entity} entity
|
const unlockText = T.buildings.hub.toUnlock.toUpperCase();
|
||||||
*/
|
if (unlockText.length > 15) {
|
||||||
drawEntity(parameters, entity) {
|
context.font = "bold 8px GameFont";
|
||||||
const staticComp = entity.components.StaticMapEntity;
|
} else {
|
||||||
if (!staticComp.shouldBeDrawn(parameters)) {
|
context.font = "bold 10px GameFont";
|
||||||
return;
|
}
|
||||||
}
|
context.fillText(T.buildings.hub.toUnlock.toUpperCase(), HUB_SIZE_PIXELS / 2, 92);
|
||||||
|
|
||||||
// Deliver count
|
context.textAlign = "left";
|
||||||
const delivered = this.root.hubGoals.getCurrentGoalDelivered();
|
}
|
||||||
const deliveredText = "" + formatBigNumber(delivered);
|
|
||||||
|
/**
|
||||||
const dpi = smoothenDpi(globalConfig.shapesSharpness * parameters.zoomLevel);
|
* @param {DrawParameters} parameters
|
||||||
const canvas = parameters.root.buffers.getForKey({
|
* @param {Entity} entity
|
||||||
key: "hub",
|
*/
|
||||||
subKey: dpi + "/" + this.root.hubGoals.level + "/" + deliveredText,
|
drawEntity(parameters, entity) {
|
||||||
w: globalConfig.tileSize * 4,
|
const staticComp = entity.components.StaticMapEntity;
|
||||||
h: globalConfig.tileSize * 4,
|
if (!staticComp.shouldBeDrawn(parameters)) {
|
||||||
dpi,
|
return;
|
||||||
redrawMethod: this.redrawHubBaseTexture.bind(this),
|
}
|
||||||
});
|
|
||||||
|
// Deliver count
|
||||||
const extrude = 8;
|
const delivered = this.root.hubGoals.getCurrentGoalDelivered();
|
||||||
drawSpriteClipped({
|
const deliveredText = "" + formatBigNumber(delivered);
|
||||||
parameters,
|
|
||||||
sprite: canvas,
|
const dpi = smoothenDpi(globalConfig.shapesSharpness * parameters.zoomLevel);
|
||||||
x: staticComp.origin.x * globalConfig.tileSize - extrude,
|
const canvas = parameters.root.buffers.getForKey({
|
||||||
y: staticComp.origin.y * globalConfig.tileSize - extrude,
|
key: "hub",
|
||||||
w: HUB_SIZE_PIXELS + 2 * extrude,
|
subKey: dpi + "/" + this.root.hubGoals.level + "/" + deliveredText,
|
||||||
h: HUB_SIZE_PIXELS + 2 * extrude,
|
w: globalConfig.tileSize * 4,
|
||||||
originalW: HUB_SIZE_PIXELS * dpi,
|
h: globalConfig.tileSize * 4,
|
||||||
originalH: HUB_SIZE_PIXELS * dpi,
|
dpi,
|
||||||
});
|
redrawMethod: this.redrawHubBaseTexture.bind(this),
|
||||||
}
|
});
|
||||||
}
|
|
||||||
|
const extrude = 8;
|
||||||
|
drawSpriteClipped({
|
||||||
|
parameters,
|
||||||
|
sprite: canvas,
|
||||||
|
x: staticComp.origin.x * globalConfig.tileSize - extrude,
|
||||||
|
y: staticComp.origin.y * globalConfig.tileSize - extrude,
|
||||||
|
w: HUB_SIZE_PIXELS + 2 * extrude,
|
||||||
|
h: HUB_SIZE_PIXELS + 2 * extrude,
|
||||||
|
originalW: HUB_SIZE_PIXELS * dpi,
|
||||||
|
originalH: HUB_SIZE_PIXELS * dpi,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -143,10 +143,10 @@ export const tutorialGoals = [
|
|||||||
// 14
|
// 14
|
||||||
// Belt reader
|
// Belt reader
|
||||||
{
|
{
|
||||||
// @todo
|
shape: "--Cg----:--Cr----", // unused
|
||||||
shape: "CuCuCuCu",
|
required: 16, // Per second!
|
||||||
required: 0,
|
|
||||||
reward: enumHubGoalRewards.reward_belt_reader,
|
reward: enumHubGoalRewards.reward_belt_reader,
|
||||||
|
throughputOnly: true,
|
||||||
},
|
},
|
||||||
|
|
||||||
// 15
|
// 15
|
||||||
@ -176,8 +176,7 @@ export const tutorialGoals = [
|
|||||||
// 18
|
// 18
|
||||||
// Rotater (180deg)
|
// Rotater (180deg)
|
||||||
{
|
{
|
||||||
// @TODO
|
shape: "Sg----Sg:CgCgCgCg:--CyCy--", // unused
|
||||||
shape: "CuCuCuCu",
|
|
||||||
required: 20000,
|
required: 20000,
|
||||||
reward: enumHubGoalRewards.reward_rotater_180,
|
reward: enumHubGoalRewards.reward_rotater_180,
|
||||||
},
|
},
|
||||||
@ -185,8 +184,7 @@ export const tutorialGoals = [
|
|||||||
// 19
|
// 19
|
||||||
// Compact splitter
|
// Compact splitter
|
||||||
{
|
{
|
||||||
// @TODO
|
shape: "CpRpCp--:SwSwSwSw",
|
||||||
shape: "CuCuCuCu",
|
|
||||||
required: 25000,
|
required: 25000,
|
||||||
reward: enumHubGoalRewards.reward_splitter,
|
reward: enumHubGoalRewards.reward_splitter,
|
||||||
},
|
},
|
||||||
@ -202,8 +200,7 @@ export const tutorialGoals = [
|
|||||||
// 21
|
// 21
|
||||||
// Display
|
// Display
|
||||||
{
|
{
|
||||||
// @TODO
|
shape: "CrCrCrCr:CwCwCwCw:CrCrCrCr:CwCwCwCw",
|
||||||
shape: "CuCuCuCu",
|
|
||||||
required: 25000,
|
required: 25000,
|
||||||
reward: enumHubGoalRewards.reward_display,
|
reward: enumHubGoalRewards.reward_display,
|
||||||
},
|
},
|
||||||
@ -211,43 +208,37 @@ export const tutorialGoals = [
|
|||||||
// 22
|
// 22
|
||||||
// Constant signal
|
// Constant signal
|
||||||
{
|
{
|
||||||
// @TODO
|
shape: "Cg----Cr:Cw----Cw:Sy------:Cy----Cy",
|
||||||
shape: "CuCuCuCu",
|
required: 25000,
|
||||||
required: 30000,
|
|
||||||
reward: enumHubGoalRewards.reward_constant_signal,
|
reward: enumHubGoalRewards.reward_constant_signal,
|
||||||
},
|
},
|
||||||
|
|
||||||
// 23
|
// 23
|
||||||
// Quad Painter
|
// Quad Painter
|
||||||
{
|
{
|
||||||
// @TODO
|
shape: "CcSyCcSy:SyCcSyCc:CcSyCcSy",
|
||||||
shape: "CuCuCuCu",
|
required: 5000,
|
||||||
// shape: "WrRgWrRg:CwCrCwCr:SgSgSgSg", // processors t4 (two variants)
|
|
||||||
required: 35000,
|
|
||||||
reward: enumHubGoalRewards.reward_painter_quad,
|
reward: enumHubGoalRewards.reward_painter_quad,
|
||||||
},
|
},
|
||||||
|
|
||||||
// 24 Logic gates
|
// 24 Logic gates
|
||||||
{
|
{
|
||||||
// @TODO
|
shape: "CcRcCcRc:RwCwRwCw:Sr--Sw--:CyCyCyCy",
|
||||||
shape: "CuCuCuCu",
|
required: 10000,
|
||||||
required: 40000,
|
|
||||||
reward: enumHubGoalRewards.reward_logic_gates,
|
reward: enumHubGoalRewards.reward_logic_gates,
|
||||||
},
|
},
|
||||||
|
|
||||||
// 25 Virtual Processing
|
// 25 Virtual Processing
|
||||||
{
|
{
|
||||||
// @TODO
|
shape: "Rg--Rg--:CwRwCwRw:--Rg--Rg",
|
||||||
shape: "CuCuCuCu",
|
required: 10000,
|
||||||
required: 45000,
|
|
||||||
reward: enumHubGoalRewards.reward_virtual_processing,
|
reward: enumHubGoalRewards.reward_virtual_processing,
|
||||||
},
|
},
|
||||||
|
|
||||||
// 26 Freeplay
|
// 26 Freeplay
|
||||||
{
|
{
|
||||||
// @TODO
|
shape: "CbCuCbCu:Sr------:--CrSrCr:CwCwCwCw",
|
||||||
shape: "CuCuCuCu",
|
required: 10000,
|
||||||
required: 100000,
|
|
||||||
reward: enumHubGoalRewards.reward_freeplay,
|
reward: enumHubGoalRewards.reward_freeplay,
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
@ -2,10 +2,28 @@ import { findNiceIntegerValue } from "../core/utils";
|
|||||||
import { ShapeDefinition } from "./shape_definition";
|
import { ShapeDefinition } from "./shape_definition";
|
||||||
|
|
||||||
export const finalGameShape = "RuCw--Cw:----Ru--";
|
export const finalGameShape = "RuCw--Cw:----Ru--";
|
||||||
|
export const rocketShape = "CbCuCbCu:Sr------:--CrSrCr:CwCwCwCw";
|
||||||
export const blueprintShape = "CbCbCbRb:CwCwCwCw";
|
export const blueprintShape = "CbCbCbRb:CwCwCwCw";
|
||||||
|
|
||||||
const fixedImprovements = [0.5, 0.5, 1, 1, 2, 2];
|
const fixedImprovements = [0.5, 0.5, 1, 1, 2, 2];
|
||||||
|
|
||||||
|
const numEndgameUpgrades = G_IS_DEV || G_IS_STANDALONE ? 20 - fixedImprovements.length - 1 : 0;
|
||||||
|
|
||||||
|
function generateEndgameUpgrades() {
|
||||||
|
return new Array(numEndgameUpgrades).fill(null).map((_, i) => ({
|
||||||
|
required: [
|
||||||
|
{ shape: blueprintShape, amount: 30000 + i * 10000 },
|
||||||
|
{ shape: finalGameShape, amount: 20000 + i * 5000 },
|
||||||
|
{ shape: rocketShape, amount: 20000 + i * 5000 },
|
||||||
|
],
|
||||||
|
excludePrevious: true,
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let i = 0; i < numEndgameUpgrades; ++i) {
|
||||||
|
fixedImprovements.push(0.1);
|
||||||
|
}
|
||||||
|
|
||||||
/** @typedef {{
|
/** @typedef {{
|
||||||
* shape: string,
|
* shape: string,
|
||||||
* amount: number
|
* amount: number
|
||||||
@ -41,6 +59,7 @@ export const UPGRADES = {
|
|||||||
required: [{ shape: finalGameShape, amount: 50000 }],
|
required: [{ shape: finalGameShape, amount: 50000 }],
|
||||||
excludePrevious: true,
|
excludePrevious: true,
|
||||||
},
|
},
|
||||||
|
...generateEndgameUpgrades(),
|
||||||
],
|
],
|
||||||
|
|
||||||
miner: [
|
miner: [
|
||||||
@ -63,6 +82,7 @@ export const UPGRADES = {
|
|||||||
required: [{ shape: finalGameShape, amount: 50000 }],
|
required: [{ shape: finalGameShape, amount: 50000 }],
|
||||||
excludePrevious: true,
|
excludePrevious: true,
|
||||||
},
|
},
|
||||||
|
...generateEndgameUpgrades(),
|
||||||
],
|
],
|
||||||
|
|
||||||
processors: [
|
processors: [
|
||||||
@ -85,6 +105,7 @@ export const UPGRADES = {
|
|||||||
required: [{ shape: finalGameShape, amount: 50000 }],
|
required: [{ shape: finalGameShape, amount: 50000 }],
|
||||||
excludePrevious: true,
|
excludePrevious: true,
|
||||||
},
|
},
|
||||||
|
...generateEndgameUpgrades(),
|
||||||
],
|
],
|
||||||
|
|
||||||
painting: [
|
painting: [
|
||||||
@ -107,6 +128,7 @@ export const UPGRADES = {
|
|||||||
required: [{ shape: finalGameShape, amount: 50000 }],
|
required: [{ shape: finalGameShape, amount: 50000 }],
|
||||||
excludePrevious: true,
|
excludePrevious: true,
|
||||||
},
|
},
|
||||||
|
...generateEndgameUpgrades(),
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -350,6 +350,7 @@ ingame:
|
|||||||
notifications:
|
notifications:
|
||||||
newUpgrade: A new upgrade is available!
|
newUpgrade: A new upgrade is available!
|
||||||
gameSaved: Your game has been saved.
|
gameSaved: Your game has been saved.
|
||||||
|
freeplayLevelComplete: Level <level> has been completed!
|
||||||
|
|
||||||
# The "Upgrades" window
|
# The "Upgrades" window
|
||||||
shop:
|
shop:
|
||||||
@ -360,7 +361,8 @@ ingame:
|
|||||||
tier: Tier <x>
|
tier: Tier <x>
|
||||||
|
|
||||||
# The roman number for each tier
|
# The roman number for each tier
|
||||||
tierLabels: [I, II, III, IV, V, VI, VII, VIII, IX, X]
|
tierLabels:
|
||||||
|
[I, II, III, IV, V, VI, VII, VIII, IX, X, XI, XII, XIII, XIV, XV, XVI, XVII, XVIII, XIX, XX]
|
||||||
|
|
||||||
maximumLevel: MAXIMUM LEVEL (Speed x<currentMult>)
|
maximumLevel: MAXIMUM LEVEL (Speed x<currentMult>)
|
||||||
|
|
||||||
@ -788,13 +790,13 @@ storyRewards:
|
|||||||
no_reward_freeplay:
|
no_reward_freeplay:
|
||||||
title: Next level
|
title: Next level
|
||||||
desc: >-
|
desc: >-
|
||||||
Congratulations! By the way, more content is planned for the standalone!
|
Congratulations!
|
||||||
|
|
||||||
reward_freeplay:
|
reward_freeplay:
|
||||||
title: Freeplay
|
title: Freeplay
|
||||||
desc: >-
|
desc: >-
|
||||||
You did it! You unlocked the <strong>free-play mode</strong>! This means that shapes are now <strong>randomly</strong> generated!<br><br>
|
You did it! You unlocked the <strong>free-play mode</strong>! This means that shapes are now <strong>randomly</strong> generated!<br><br>
|
||||||
Since the hub will only require low quantities from now on, I highly recommend to build a machine which automatically delivers the requested shape!<br><br>
|
Since the hub will require a <strong>throughput</strong> from now on, I highly recommend to build a machine which automatically delivers the requested shape!<br><br>
|
||||||
The HUB outputs the requested shape on the wires layer, so all you have to do is to analyze it and automatically configure your factory based on that.
|
The HUB outputs the requested shape on the wires layer, so all you have to do is to analyze it and automatically configure your factory based on that.
|
||||||
|
|
||||||
settings:
|
settings:
|
||||||
|
Loading…
Reference in New Issue
Block a user