Unlock all levels when having a legacy savegame

pull/786/head
tobspr 4 years ago
parent fa27d1681f
commit 7dccc1a844

@ -1,5 +1,3 @@
import { queryParamOptions } from "./query_parameters";
export const IS_DEBUG =
G_IS_DEV &&
typeof window !== "undefined" &&
@ -9,6 +7,8 @@ export const IS_DEBUG =
export const SUPPORT_TOUCH = false;
export const IS_MAC = navigator.platform.toLowerCase().indexOf("mac") >= 0;
const smoothCanvas = true;
export const THIRDPARTY_URLS = {

@ -1,4 +1,5 @@
import { Application } from "../application";
import { IS_MAC } from "./config";
import { ExplainedResult } from "./explained_result";
import { queryParamOptions } from "./query_parameters";
import { ReadWriteProxy } from "./read_write_proxy";
@ -9,6 +10,8 @@ export class RestrictionManager extends ReadWriteProxy {
*/
constructor(app) {
super(app, "restriction-flags.bin");
this.currentData = this.getDefaultData();
}
// -- RW Proxy Impl
@ -24,6 +27,7 @@ export class RestrictionManager extends ReadWriteProxy {
*/
getDefaultData() {
return {
version: this.getCurrentVersion(),
savegameV1119Imported: false,
};
}
@ -42,17 +46,53 @@ export class RestrictionManager extends ReadWriteProxy {
return ExplainedResult.good();
}
initialize() {
return this.readAsync().then(() => {
if (this.currentData.savegameV1119Imported) {
console.warn("Levelunlock is granted to current user due to past savegame");
}
});
}
// -- End RW Proxy Impl
/**
* Checks if there are any savegames from the 1.1.19 version
*/
onHasLegacySavegamesChanged(has119Savegames = false) {
if (has119Savegames && !this.currentData.savegameV1119Imported) {
this.currentData.savegameV1119Imported = true;
console.warn("Current user now has access to all levels due to 1119 savegame");
return this.writeAsync();
}
return Promise.resolve();
}
/**
* Returns if the app is currently running as the limited version
* @returns {boolean}
*/
isLimitedVersion() {
return queryParamOptions.fullVersion
? false
: (!G_IS_DEV && !G_IS_STANDALONE) ||
(typeof window !== "undefined" && window.location.search.indexOf("demo") >= 0);
if (IS_MAC) {
// On mac, the full version is always active
return false;
}
if (G_IS_STANDALONE) {
// Standalone is never limited
return false;
}
if (queryParamOptions.fullVersion) {
// Full version is activated via flag
return false;
}
if (G_IS_DEV) {
return typeof window !== "undefined" && window.location.search.indexOf("demo") >= 0;
}
return true;
}
/**
@ -94,4 +134,20 @@ export class RestrictionManager extends ReadWriteProxy {
getHasExtendedSettings() {
return !this.isLimitedVersion();
}
/**
* Returns if all upgrades are available
* @returns {boolean}
*/
getHasExtendedUpgrades() {
return !this.isLimitedVersion() || this.currentData.savegameV1119Imported;
}
/**
* Returns if all levels & freeplay is available
* @returns {boolean}
*/
getHasExtendedLevelsAndFreeplay() {
return !this.isLimitedVersion() || this.currentData.savegameV1119Imported;
}
}

@ -1,4 +1,3 @@
import { IS_DEMO } from "../../core/config";
import { findNiceIntegerValue } from "../../core/utils";
import { GameMode } from "../game_mode";
import { ShapeDefinition } from "../shape_definition";
@ -9,423 +8,442 @@ const finalGameShape = "RuCw--Cw:----Ru--";
const preparementShape = "CpRpCp--:SwSwSwSw";
const blueprintShape = "CbCbCbRb:CwCwCwCw";
const fixedImprovements = [0.5, 0.5, 1, 1, 2, 1, 1];
// Tiers need % of the previous tier as requirement too
const tierGrowth = 2.5;
/**
* Generates all upgrades
* @returns {Object<string, import("../game_mode").UpgradeTiers>} */
function generateUpgrades(limitedVersion = false) {
const fixedImprovements = [0.5, 0.5, 1, 1, 2, 1, 1];
const numEndgameUpgrades = limitedVersion ? 0 : 1000 - fixedImprovements.length - 1;
function generateInfiniteUnlocks() {
return new Array(numEndgameUpgrades).fill(null).map((_, i) => ({
required: [
{ shape: preparementShape, amount: 30000 + i * 10000 },
{ shape: finalGameShape, amount: 20000 + i * 5000 },
{ shape: rocketShape, amount: 20000 + i * 5000 },
],
excludePrevious: true,
}));
}
// Fill in endgame upgrades
for (let i = 0; i < numEndgameUpgrades; ++i) {
fixedImprovements.push(0.1);
}
// @FIXME @TODO
const numEndgameUpgrades = !IS_DEMO ? 20 - fixedImprovements.length - 1 : 0;
const upgrades = {
belt: [
{
required: [{ shape: "CuCuCuCu", amount: 60 }],
},
{
required: [{ shape: "--CuCu--", amount: 500 }],
},
{
required: [{ shape: "CpCpCpCp", amount: 1000 }],
},
{
required: [{ shape: "SrSrSrSr:CyCyCyCy", amount: 6000 }],
},
{
required: [{ shape: "SrSrSrSr:CyCyCyCy:SwSwSwSw", amount: 25000 }],
},
{
required: [{ shape: preparementShape, amount: 25000 }],
excludePrevious: true,
},
{
required: [
{ shape: preparementShape, amount: 25000 },
{ shape: finalGameShape, amount: 50000 },
],
excludePrevious: true,
},
...generateInfiniteUnlocks(),
],
function generateEndgameUpgrades() {
return new Array(numEndgameUpgrades).fill(null).map((_, i) => ({
required: [
{ shape: preparementShape, amount: 30000 + i * 10000 },
{ shape: finalGameShape, amount: 20000 + i * 5000 },
{ shape: rocketShape, amount: 20000 + i * 5000 },
miner: [
{
required: [{ shape: "RuRuRuRu", amount: 300 }],
},
{
required: [{ shape: "Cu------", amount: 800 }],
},
{
required: [{ shape: "ScScScSc", amount: 3500 }],
},
{
required: [{ shape: "CwCwCwCw:WbWbWbWb", amount: 23000 }],
},
{
required: [{ shape: "CbRbRbCb:CwCwCwCw:WbWbWbWb", amount: 50000 }],
},
{
required: [{ shape: preparementShape, amount: 25000 }],
excludePrevious: true,
},
{
required: [
{ shape: preparementShape, amount: 25000 },
{ shape: finalGameShape, amount: 50000 },
],
excludePrevious: true,
},
...generateInfiniteUnlocks(),
],
excludePrevious: true,
}));
}
for (let i = 0; i < numEndgameUpgrades; ++i) {
fixedImprovements.push(0.1);
processors: [
{
required: [{ shape: "SuSuSuSu", amount: 500 }],
},
{
required: [{ shape: "RuRu----", amount: 600 }],
},
{
required: [{ shape: "CgScScCg", amount: 3500 }],
},
{
required: [{ shape: "CwCrCwCr:SgSgSgSg", amount: 25000 }],
},
{
required: [{ shape: "WrRgWrRg:CwCrCwCr:SgSgSgSg", amount: 50000 }],
},
{
required: [{ shape: preparementShape, amount: 25000 }],
excludePrevious: true,
},
{
required: [
{ shape: preparementShape, amount: 25000 },
{ shape: finalGameShape, amount: 50000 },
],
excludePrevious: true,
},
...generateInfiniteUnlocks(),
],
painting: [
{
required: [{ shape: "RbRb----", amount: 600 }],
},
{
required: [{ shape: "WrWrWrWr", amount: 3800 }],
},
{
required: [{ shape: "RpRpRpRp:CwCwCwCw", amount: 6500 }],
},
{
required: [{ shape: "WpWpWpWp:CwCwCwCw:WpWpWpWp", amount: 25000 }],
},
{
required: [{ shape: "WpWpWpWp:CwCwCwCw:WpWpWpWp:CwCwCwCw", amount: 50000 }],
},
{
required: [{ shape: preparementShape, amount: 25000 }],
excludePrevious: true,
},
{
required: [
{ shape: preparementShape, amount: 25000 },
{ shape: finalGameShape, amount: 50000 },
],
excludePrevious: true,
},
...generateInfiniteUnlocks(),
],
};
// Automatically generate tier levels
for (const upgradeId in upgrades) {
const upgradeTiers = upgrades[upgradeId];
let currentTierRequirements = [];
for (let i = 0; i < upgradeTiers.length; ++i) {
const tierHandle = upgradeTiers[i];
tierHandle.improvement = fixedImprovements[i];
const originalRequired = tierHandle.required.slice();
for (let k = currentTierRequirements.length - 1; k >= 0; --k) {
const oldTierRequirement = currentTierRequirements[k];
if (!tierHandle.excludePrevious) {
tierHandle.required.unshift({
shape: oldTierRequirement.shape,
amount: oldTierRequirement.amount,
});
}
}
currentTierRequirements.push(
...originalRequired.map(req => ({
amount: req.amount,
shape: req.shape,
}))
);
currentTierRequirements.forEach(tier => {
tier.amount = findNiceIntegerValue(tier.amount * tierGrowth);
});
}
}
// VALIDATE
if (G_IS_DEV) {
for (const upgradeId in upgrades) {
upgrades[upgradeId].forEach(tier => {
tier.required.forEach(({ shape }) => {
try {
ShapeDefinition.fromShortKey(shape);
} catch (ex) {
throw new Error("Invalid upgrade goal: '" + ex + "' for shape" + shape);
}
});
});
}
}
return upgrades;
}
/** @type {Object<string, import("../game_mode").UpgradeTiers>} */
const cachedUpgrades = {
belt: [
{
required: [{ shape: "CuCuCuCu", amount: 60 }],
},
{
required: [{ shape: "--CuCu--", amount: 500 }],
},
{
required: [{ shape: "CpCpCpCp", amount: 1000 }],
},
{
required: [{ shape: "SrSrSrSr:CyCyCyCy", amount: 6000 }],
},
{
required: [{ shape: "SrSrSrSr:CyCyCyCy:SwSwSwSw", amount: 25000 }],
},
/**
* Generates the level definitions
* @param {boolean} limitedVersion
*/
export function generateLevelDefinitions(limitedVersion = false) {
const levelDefinitions = [
// 1
// Circle
{
required: [{ shape: preparementShape, amount: 25000 }],
excludePrevious: true,
},
{
required: [
{ shape: preparementShape, amount: 25000 },
{ shape: finalGameShape, amount: 50000 },
],
excludePrevious: true,
shape: "CuCuCuCu", // belts t1
required: 30,
reward: enumHubGoalRewards.reward_cutter_and_trash,
},
...generateEndgameUpgrades(),
],
miner: [
{
required: [{ shape: "RuRuRuRu", amount: 300 }],
},
{
required: [{ shape: "Cu------", amount: 800 }],
},
{
required: [{ shape: "ScScScSc", amount: 3500 }],
},
// 2
// Cutter
{
required: [{ shape: "CwCwCwCw:WbWbWbWb", amount: 23000 }],
shape: "----CuCu", //
required: 40,
reward: enumHubGoalRewards.no_reward,
},
{
required: [{ shape: "CbRbRbCb:CwCwCwCw:WbWbWbWb", amount: 50000 }],
},
{
required: [{ shape: preparementShape, amount: 25000 }],
excludePrevious: true,
},
{
required: [
{ shape: preparementShape, amount: 25000 },
{ shape: finalGameShape, amount: 50000 },
],
excludePrevious: true,
},
...generateEndgameUpgrades(),
],
processors: [
{
required: [{ shape: "SuSuSuSu", amount: 500 }],
},
// 3
// Rectangle
{
required: [{ shape: "RuRu----", amount: 600 }],
},
{
required: [{ shape: "CgScScCg", amount: 3500 }],
},
{
required: [{ shape: "CwCrCwCr:SgSgSgSg", amount: 25000 }],
shape: "RuRuRuRu", // miners t1
required: 70,
reward: enumHubGoalRewards.reward_balancer,
},
// 4
{
required: [{ shape: "WrRgWrRg:CwCrCwCr:SgSgSgSg", amount: 50000 }],
shape: "RuRu----", // processors t2
required: 70,
reward: enumHubGoalRewards.reward_rotater,
},
// 5
// Rotater
{
required: [{ shape: preparementShape, amount: 25000 }],
excludePrevious: true,
shape: "Cu----Cu", // belts t2
required: 170,
reward: enumHubGoalRewards.reward_tunnel,
},
// 6
{
required: [
{ shape: preparementShape, amount: 25000 },
{ shape: finalGameShape, amount: 50000 },
],
excludePrevious: true,
shape: "Cu------", // miners t2
required: 270,
reward: enumHubGoalRewards.reward_painter,
},
...generateEndgameUpgrades(),
],
painting: [
// 7
// Painter
{
required: [{ shape: "RbRb----", amount: 600 }],
shape: "CrCrCrCr", // unused
required: 300,
reward: enumHubGoalRewards.reward_rotater_ccw,
},
// 8
{
required: [{ shape: "WrWrWrWr", amount: 3800 }],
shape: "RbRb----", // painter t2
required: 480,
reward: enumHubGoalRewards.reward_mixer,
},
// 9
// Mixing (purple)
{
required: [{ shape: "RpRpRpRp:CwCwCwCw", amount: 6500 }],
shape: "CpCpCpCp", // belts t3
required: 600,
reward: enumHubGoalRewards.reward_merger,
},
// 10
// STACKER: Star shape + cyan
{
required: [{ shape: "WpWpWpWp:CwCwCwCw:WpWpWpWp", amount: 25000 }],
shape: "ScScScSc", // miners t3
required: 800,
reward: enumHubGoalRewards.reward_stacker,
},
// 11
// Chainable miner
{
required: [{ shape: "WpWpWpWp:CwCwCwCw:WpWpWpWp:CwCwCwCw", amount: 50000 }],
shape: "CgScScCg", // processors t3
required: 1000,
reward: enumHubGoalRewards.reward_miner_chainable,
},
// 12
// Blueprints
{
required: [{ shape: preparementShape, amount: 25000 }],
excludePrevious: true,
shape: "CbCbCbRb:CwCwCwCw",
required: 1000,
reward: enumHubGoalRewards.reward_blueprints,
},
// 13
// Tunnel Tier 2
{
required: [
{ shape: preparementShape, amount: 25000 },
{ shape: finalGameShape, amount: 50000 },
],
excludePrevious: true,
shape: "RpRpRpRp:CwCwCwCw", // painting t3
required: 3800,
reward: enumHubGoalRewards.reward_underground_belt_tier_2,
},
...generateEndgameUpgrades(),
],
};
// Tiers need % of the previous tier as requirement too
const tierGrowth = 2.5;
// Automatically generate tier levels
for (const upgradeId in cachedUpgrades) {
const upgradeTiers = cachedUpgrades[upgradeId];
let currentTierRequirements = [];
for (let i = 0; i < upgradeTiers.length; ++i) {
const tierHandle = upgradeTiers[i];
tierHandle.improvement = fixedImprovements[i];
const originalRequired = tierHandle.required.slice();
for (let k = currentTierRequirements.length - 1; k >= 0; --k) {
const oldTierRequirement = currentTierRequirements[k];
if (!tierHandle.excludePrevious) {
tierHandle.required.unshift({
shape: oldTierRequirement.shape,
amount: oldTierRequirement.amount,
});
// DEMO STOPS HERE
...(limitedVersion
? [
{
shape: "RpRpRpRp:CwCwCwCw",
required: 0,
reward: enumHubGoalRewards.reward_demo_end,
},
]
: [
// 14
// Belt reader
{
shape: "--Cg----:--Cr----", // unused
required: 16, // Per second!
reward: enumHubGoalRewards.reward_belt_reader,
throughputOnly: true,
},
// 15
// Storage
{
shape: "SrSrSrSr:CyCyCyCy", // unused
required: 10000,
reward: enumHubGoalRewards.reward_storage,
},
// 16
// Quad Cutter
{
shape: "SrSrSrSr:CyCyCyCy:SwSwSwSw", // belts t4 (two variants)
required: 6000,
reward: enumHubGoalRewards.reward_cutter_quad,
},
// 17
// Double painter
{
shape: "CbRbRbCb:CwCwCwCw:WbWbWbWb", // miner t4 (two variants)
required: 20000,
reward: enumHubGoalRewards.reward_painter_double,
},
// 18
// Rotater (180deg)
{
shape: "Sg----Sg:CgCgCgCg:--CyCy--", // unused
required: 20000,
reward: enumHubGoalRewards.reward_rotater_180,
},
// 19
// Compact splitter
{
shape: "CpRpCp--:SwSwSwSw",
required: 25000,
reward: enumHubGoalRewards.reward_splitter,
},
// 20
// WIRES
{
shape: finalGameShape,
required: 25000,
reward: enumHubGoalRewards.reward_wires_painter_and_levers,
},
// 21
// Filter
{
shape: "CrCwCrCw:CwCrCwCr:CrCwCrCw:CwCrCwCr",
required: 25000,
reward: enumHubGoalRewards.reward_filter,
},
// 22
// Constant signal
{
shape: "Cg----Cr:Cw----Cw:Sy------:Cy----Cy",
required: 25000,
reward: enumHubGoalRewards.reward_constant_signal,
},
// 23
// Display
{
shape: "CcSyCcSy:SyCcSyCc:CcSyCcSy",
required: 25000,
reward: enumHubGoalRewards.reward_display,
},
// 24 Logic gates
{
shape: "CcRcCcRc:RwCwRwCw:Sr--Sw--:CyCyCyCy",
required: 25000,
reward: enumHubGoalRewards.reward_logic_gates,
},
// 25 Virtual Processing
{
shape: "Rg--Rg--:CwRwCwRw:--Rg--Rg",
required: 25000,
reward: enumHubGoalRewards.reward_virtual_processing,
},
// 26 Freeplay
{
shape: "CbCuCbCu:Sr------:--CrSrCr:CwCwCwCw",
required: 50000,
reward: enumHubGoalRewards.reward_freeplay,
},
]),
];
if (G_IS_DEV) {
levelDefinitions.forEach(({ shape }) => {
try {
ShapeDefinition.fromShortKey(shape);
} catch (ex) {
throw new Error("Invalid tutorial goal: '" + ex + "' for shape" + shape);
}
}
currentTierRequirements.push(
...originalRequired.map(req => ({
amount: req.amount,
shape: req.shape,
}))
);
currentTierRequirements.forEach(tier => {
tier.amount = findNiceIntegerValue(tier.amount * tierGrowth);
});
}
}
// VALIDATE
if (G_IS_DEV) {
for (const upgradeId in cachedUpgrades) {
cachedUpgrades[upgradeId].forEach(tier => {
tier.required.forEach(({ shape }) => {
try {
ShapeDefinition.fromShortKey(shape);
} catch (ex) {
throw new Error("Invalid upgrade goal: '" + ex + "' for shape" + shape);
}
});
});
}
return levelDefinitions;
}
const levelDefinitions = [
// 1
// Circle
{
shape: "CuCuCuCu", // belts t1
required: 30,
reward: enumHubGoalRewards.reward_cutter_and_trash,
},
// 2
// Cutter
{
shape: "----CuCu", //
required: 40,
reward: enumHubGoalRewards.no_reward,
},
// 3
// Rectangle
{
shape: "RuRuRuRu", // miners t1
required: 70,
reward: enumHubGoalRewards.reward_balancer,
},
// 4
{
shape: "RuRu----", // processors t2
required: 70,
reward: enumHubGoalRewards.reward_rotater,
},
// 5
// Rotater
{
shape: "Cu----Cu", // belts t2
required: 170,
reward: enumHubGoalRewards.reward_tunnel,
},
// 6
{
shape: "Cu------", // miners t2
required: 270,
reward: enumHubGoalRewards.reward_painter,
},
// 7
// Painter
{
shape: "CrCrCrCr", // unused
required: 300,
reward: enumHubGoalRewards.reward_rotater_ccw,
},
// 8
{
shape: "RbRb----", // painter t2
required: 480,
reward: enumHubGoalRewards.reward_mixer,
},
// 9
// Mixing (purple)
{
shape: "CpCpCpCp", // belts t3
required: 600,
reward: enumHubGoalRewards.reward_merger,
},
// 10
// STACKER: Star shape + cyan
{
shape: "ScScScSc", // miners t3
required: 800,
reward: enumHubGoalRewards.reward_stacker,
},
// 11
// Chainable miner
{
shape: "CgScScCg", // processors t3
required: 1000,
reward: enumHubGoalRewards.reward_miner_chainable,
},
// 12
// Blueprints
{
shape: "CbCbCbRb:CwCwCwCw",
required: 1000,
reward: enumHubGoalRewards.reward_blueprints,
},
// 13
// Tunnel Tier 2
{
shape: "RpRpRpRp:CwCwCwCw", // painting t3
required: 3800,
reward: enumHubGoalRewards.reward_underground_belt_tier_2,
},
// DEMO STOPS HERE
...(IS_DEMO
? [
{
shape: "RpRpRpRp:CwCwCwCw",
required: 0,
reward: enumHubGoalRewards.reward_demo_end,
},
]
: [
// 14
// Belt reader
{
shape: "--Cg----:--Cr----", // unused
required: 16, // Per second!
reward: enumHubGoalRewards.reward_belt_reader,
throughputOnly: true,
},
// 15
// Storage
{
shape: "SrSrSrSr:CyCyCyCy", // unused
required: 10000,
reward: enumHubGoalRewards.reward_storage,
},
// 16
// Quad Cutter
{
shape: "SrSrSrSr:CyCyCyCy:SwSwSwSw", // belts t4 (two variants)
required: 6000,
reward: enumHubGoalRewards.reward_cutter_quad,
},
// 17
// Double painter
{
shape: "CbRbRbCb:CwCwCwCw:WbWbWbWb", // miner t4 (two variants)
required: 20000,
reward: enumHubGoalRewards.reward_painter_double,
},
// 18
// Rotater (180deg)
{
shape: "Sg----Sg:CgCgCgCg:--CyCy--", // unused
required: 20000,
reward: enumHubGoalRewards.reward_rotater_180,
},
// 19
// Compact splitter
{
shape: "CpRpCp--:SwSwSwSw",
required: 25000,
reward: enumHubGoalRewards.reward_splitter,
},
// 20
// WIRES
{
shape: finalGameShape,
required: 25000,
reward: enumHubGoalRewards.reward_wires_painter_and_levers,
},
// 21
// Filter
{
shape: "CrCwCrCw:CwCrCwCr:CrCwCrCw:CwCrCwCr",
required: 25000,
reward: enumHubGoalRewards.reward_filter,
},
// 22
// Constant signal
{
shape: "Cg----Cr:Cw----Cw:Sy------:Cy----Cy",
required: 25000,
reward: enumHubGoalRewards.reward_constant_signal,
},
// 23
// Display
{
shape: "CcSyCcSy:SyCcSyCc:CcSyCcSy",
required: 25000,
reward: enumHubGoalRewards.reward_display,
},
// 24 Logic gates
{
shape: "CcRcCcRc:RwCwRwCw:Sr--Sw--:CyCyCyCy",
required: 25000,
reward: enumHubGoalRewards.reward_logic_gates,
},
// 25 Virtual Processing
{
shape: "Rg--Rg--:CwRwCwRw:--Rg--Rg",
required: 25000,
reward: enumHubGoalRewards.reward_virtual_processing,
},
// 26 Freeplay
{
shape: "CbCuCbCu:Sr------:--CrSrCr:CwCwCwCw",
required: 50000,
reward: enumHubGoalRewards.reward_freeplay,
},
]),
];
if (G_IS_DEV) {
levelDefinitions.forEach(({ shape }) => {
try {
ShapeDefinition.fromShortKey(shape);
} catch (ex) {
throw new Error("Invalid tutorial goal: '" + ex + "' for shape" + shape);
}
});
}
const fullVersionUpgrades = generateUpgrades(false);
const demoVersionUpgrades = generateUpgrades(true);
const fullVersionLevels = generateLevelDefinitions(false);
const demoVersionLevels = generateLevelDefinitions(true);
export class RegularGameMode extends GameMode {
constructor(root) {
@ -433,7 +451,13 @@ export class RegularGameMode extends GameMode {
}
getUpgrades() {
return cachedUpgrades;
return this.root.app.restrictionMgr.getHasExtendedUpgrades()
? fullVersionUpgrades
: demoVersionUpgrades;
}
getIsFreeplayAvailable() {
return this.root.app.restrictionMgr.getHasExtendedLevelsAndFreeplay();
}
getBlueprintShapeKey() {
@ -441,6 +465,8 @@ export class RegularGameMode extends GameMode {
}
getLevelDefinitions() {
return levelDefinitions;
return this.root.app.restrictionMgr.getHasExtendedLevelsAndFreeplay()
? fullVersionLevels
: demoVersionLevels;
}
}

@ -89,6 +89,14 @@ export class SavegameManager extends ReadWriteProxy {
return new Savegame(this.app, { internalId, metaDataRef: metadata });
}
/**
* Returns if this manager has any savegame of a 1.1.19 version, which
* enables all levels
*/
getHasAnyLegacySavegames() {
return this.currentData.savegames.some(savegame => savegame.version === 1005 || savegame.level > 14);
}
/**
* Deletes a savegame
* @param {SavegameMetadata} game
@ -142,7 +150,9 @@ export class SavegameManager extends ReadWriteProxy {
});
this.currentData.savegames.push(metaData);
this.sortSavegames();
// Notice: This is async and happening in the background
this.updateAfterSavegamesChanged();
return new Savegame(this.app, {
internalId: id,
@ -150,8 +160,16 @@ export class SavegameManager extends ReadWriteProxy {
});
}
/**
* Attempts to import a savegame
* @param {object} data
*/
importSavegame(data) {
const savegame = this.createNewSavegame();
// Track legacy savegames
const isOldSavegame = data.version < 1006;
const migrationResult = savegame.migrate(data);
if (migrationResult.isBad()) {
return Promise.reject("Failed to migrate: " + migrationResult.reason);
@ -163,7 +181,19 @@ export class SavegameManager extends ReadWriteProxy {
return Promise.reject("Verification failed: " + verification.result);
}
return savegame.writeSavegameAndMetadata().then(() => this.sortSavegames());
return savegame
.writeSavegameAndMetadata()
.then(() => this.updateAfterSavegamesChanged())
.then(() => this.app.restrictionMgr.onHasLegacySavegamesChanged(isOldSavegame));
}
/**
* Hook after the savegames got changed
*/
updateAfterSavegamesChanged() {
return this.sortSavegames()
.then(() => this.writeAsync())
.then(() => this.app.restrictionMgr.onHasLegacySavegamesChanged(this.getHasAnyLegacySavegames()));
}
/**
@ -212,7 +242,7 @@ export class SavegameManager extends ReadWriteProxy {
if (G_IS_DEV && globalConfig.debug.disableSavegameWrite) {
return Promise.resolve();
}
return this.sortSavegames().then(() => this.writeAsync());
return this.updateAfterSavegamesChanged();
});
}
}

@ -145,6 +145,11 @@ export class PreloadState extends GameState {
this.app.backgroundResourceLoader.startLoading();
})
.then(() => this.setStatus("Initializing restrictions"))
.then(() => {
return this.app.restrictionMgr.initialize();
})
.then(() => this.setStatus("Initializing savegame"))
.then(() => {
return this.app.savegameMgr.initialize().catch(err => {

Loading…
Cancel
Save