mirror of
https://github.com/tobspr/shapez.io.git
synced 2025-06-13 13:04:03 +00:00
[WIP] Add achievements. Start savefile migration
This commit is contained in:
parent
a722c3562d
commit
10b90a8df2
@ -41,7 +41,7 @@ export const globalConfig = {
|
||||
shapesSharpness: 1.4,
|
||||
|
||||
// Achievements
|
||||
achievementSliceDuration: 30, // Seconds
|
||||
achievementSliceDuration: 10, // Seconds
|
||||
|
||||
// Production analytics
|
||||
statisticsGraphDpi: 2.5,
|
||||
|
@ -5,21 +5,42 @@ import { GameRoot } from "./root";
|
||||
import { globalConfig } from "../core/config";
|
||||
import { createLogger } from "../core/logging";
|
||||
import { ACHIEVEMENTS } from "../platform/achievement_provider";
|
||||
import { BasicSerializableObject } from "../savegame/serialization";
|
||||
//import { typeAchievementCollection } from "./achievement_resolver";
|
||||
|
||||
const logger = createLogger("achievement_proxy");
|
||||
|
||||
export class AchievementProxy {
|
||||
export class AchievementProxy extends BasicSerializableObject {
|
||||
static getId() {
|
||||
return "AchievementProxy";
|
||||
}
|
||||
|
||||
static getSchema() {
|
||||
return {
|
||||
// collection: typeAchievementCollection
|
||||
};
|
||||
}
|
||||
|
||||
deserialize(data, root) {
|
||||
|
||||
}
|
||||
|
||||
/** @param {GameRoot} root */
|
||||
constructor(root) {
|
||||
super();
|
||||
|
||||
this.root = root;
|
||||
this.provider = this.root.app.achievementProvider;
|
||||
this.lastSlice = 0;
|
||||
this.disabled = true;
|
||||
|
||||
if (!this.provider.hasAchievements()) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.sliceTime = 0;
|
||||
this.sliceIteration = 0;
|
||||
this.sliceIterationLimit = 2;
|
||||
|
||||
this.root.signals.postLoadHook.add(this.onLoad, this);
|
||||
}
|
||||
|
||||
@ -37,22 +58,49 @@ export class AchievementProxy {
|
||||
});
|
||||
}
|
||||
|
||||
// Have certain checks every 30 seconds, 10 seconds, etc.
|
||||
// Re-check relevance every so often
|
||||
// Consider disabling checks if no longer relevant
|
||||
startSlice() {
|
||||
this.lastSlice = this.root.time.now();
|
||||
this.sliceTime = this.root.time.now();
|
||||
|
||||
// Every slice
|
||||
this.root.signals.achievementCheck.dispatch(ACHIEVEMENTS.storeShape, this.sliceTime);
|
||||
|
||||
// Every other slice
|
||||
if (this.sliceIteration % 2 === 0) {
|
||||
this.root.signals.bulkAchievementCheck.dispatch(
|
||||
ACHIEVEMENTS.play1h, this.lastSlice,
|
||||
ACHIEVEMENTS.play10h, this.lastSlice,
|
||||
ACHIEVEMENTS.play20h, this.lastSlice
|
||||
ACHIEVEMENTS.throughputBp25, this.sliceTime,
|
||||
ACHIEVEMENTS.throughputBp50, this.sliceTime,
|
||||
ACHIEVEMENTS.throughputLogo25, this.sliceTime,
|
||||
ACHIEVEMENTS.throughputLogo50, this.sliceTime,
|
||||
ACHIEVEMENTS.throughputRocket10, this.sliceTime,
|
||||
ACHIEVEMENTS.throughputRocket20, this.sliceTime
|
||||
);
|
||||
}
|
||||
|
||||
// Every 3rd slice
|
||||
if (this.sliceIteration % 3 === 0) {
|
||||
this.root.signals.bulkAchievementCheck.dispatch(
|
||||
ACHIEVEMENTS.play1h, this.sliceTime,
|
||||
ACHIEVEMENTS.play10h, this.sliceTime,
|
||||
ACHIEVEMENTS.play20h, this.sliceTime
|
||||
);
|
||||
}
|
||||
|
||||
if (this.sliceIteration === this.sliceIterationLimit) {
|
||||
this.sliceIteration = 0;
|
||||
} else {
|
||||
this.sliceIteration++;
|
||||
}
|
||||
}
|
||||
|
||||
update() {
|
||||
if (this.disabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.root.time.now() - this.lastSlice > globalConfig.achievementSliceDuration) {
|
||||
if (this.root.time.now() - this.sliceTime > globalConfig.achievementSliceDuration) {
|
||||
this.startSlice();
|
||||
}
|
||||
}
|
||||
|
4
src/js/game/achievement_resolver.js
Normal file
4
src/js/game/achievement_resolver.js
Normal file
@ -0,0 +1,4 @@
|
||||
export function achievementResolver(root, data) {
|
||||
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
import { generateMatrixRotations } from "../../core/utils";
|
||||
import { enumDirection, Vector } from "../../core/vector";
|
||||
import { ACHIEVEMENTS } from "../../platform/achievement_provider";
|
||||
import { ItemAcceptorComponent } from "../components/item_acceptor";
|
||||
import { enumItemProcessorTypes, ItemProcessorComponent } from "../components/item_processor";
|
||||
import { Entity } from "../entity";
|
||||
@ -37,6 +38,25 @@ export class MetaTrashBuilding extends MetaBuilding {
|
||||
return root.hubGoals.isRewardUnlocked(enumHubGoalRewards.reward_cutter_and_trash);
|
||||
}
|
||||
|
||||
addAchievementReceiver(entity) {
|
||||
if (!entity.root) {
|
||||
return;
|
||||
}
|
||||
|
||||
const itemProcessor = entity.components.ItemProcessor
|
||||
const tryTakeItem = itemProcessor.tryTakeItem.bind(itemProcessor);
|
||||
|
||||
itemProcessor.tryTakeItem = () => {
|
||||
const taken = tryTakeItem(...arguments);
|
||||
|
||||
if (taken) {
|
||||
entity.root.signals.achievementCheck.dispatch(ACHIEVEMENTS.trash1000, 1);
|
||||
}
|
||||
|
||||
return taken;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the entity at the given location
|
||||
* @param {Entity} entity
|
||||
@ -57,11 +77,14 @@ export class MetaTrashBuilding extends MetaBuilding {
|
||||
],
|
||||
})
|
||||
);
|
||||
|
||||
entity.addComponent(
|
||||
new ItemProcessorComponent({
|
||||
inputsPerCharge: 1,
|
||||
processorType: enumItemProcessorTypes.trash,
|
||||
})
|
||||
);
|
||||
|
||||
this.addAchievementReceiver(entity);
|
||||
}
|
||||
}
|
||||
|
@ -251,16 +251,6 @@ export class ShapeDefinitionManager extends BasicSerializableObject {
|
||||
return this.shapeKeyToDefinition[id];
|
||||
}
|
||||
this.shapeKeyToDefinition[id] = definition;
|
||||
|
||||
this.root.signals.bulkAchievementCheck.dispatch(
|
||||
ACHIEVEMENTS.logoBefore18, definition,
|
||||
ACHIEVEMENTS.oldLevel17, definition,
|
||||
ACHIEVEMENTS.produceLogo, definition,
|
||||
ACHIEVEMENTS.produceMsLogo, definition,
|
||||
ACHIEVEMENTS.produceRocket, definition,
|
||||
ACHIEVEMENTS.stack4Layers, definition
|
||||
);
|
||||
|
||||
// logger.log("Registered shape with key (2)", id);
|
||||
return definition;
|
||||
}
|
||||
|
@ -275,9 +275,6 @@ export class ItemEjectorSystem extends GameSystemWithFilter {
|
||||
// It's a storage
|
||||
if (storageComp.canAcceptItem(item)) {
|
||||
storageComp.takeItem(item);
|
||||
|
||||
this.root.signals.achievementCheck.dispatch(ACHIEVEMENTS.storeShape, storageComp);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1,11 +1,14 @@
|
||||
/* typehints:start */
|
||||
import { Application } from "../application";
|
||||
import { BaseItem } from "./base_item";
|
||||
import { StorageComponent } from "../game/components/storage";
|
||||
import { Entity } from "../game/entity";
|
||||
import { GameRoot } from "../game/root";
|
||||
import { ShapeDefinition } from "../game/shape_definition";
|
||||
/* typehints:end */
|
||||
|
||||
import { enumAnalyticsDataSource } from "../game/production_analytics";
|
||||
|
||||
export const ACHIEVEMENTS = {
|
||||
belt500Tiles: "belt500Tiles",
|
||||
blueprint100k: "blueprint100k",
|
||||
@ -32,25 +35,41 @@ export const ACHIEVEMENTS = {
|
||||
produceMsLogo: "produceMsLogo",
|
||||
produceRocket: "produceRocket",
|
||||
rotateShape: "rotateShape",
|
||||
speedrunBp30: "speedrunBp30",
|
||||
speedrunBp60: "speedrunBp60",
|
||||
speedrunBp120: "speedrunBp120",
|
||||
stack4Layers: "stack4Layers",
|
||||
stackShape: "stackShape",
|
||||
store100Unique: "store100Unique",
|
||||
storeShape: "storeShape",
|
||||
throughputBp25: "throughputBp25",
|
||||
throughputBp50: "throughputBp50",
|
||||
throughputLogo25: "throughputLogo25",
|
||||
throughputLogo50: "throughputLogo50",
|
||||
throughputRocket10: "throughputRocket10",
|
||||
throughputRocket20: "throughputRocket20",
|
||||
trash1000: "trash1000",
|
||||
unlockWires: "unlockWires",
|
||||
upgradesTier5: "upgradesTier5",
|
||||
upgradesTier8: "upgradesTier8",
|
||||
};
|
||||
|
||||
const DARK_MODE = "dark";
|
||||
const WIRE_LAYER = "wires";
|
||||
const HOUR_1 = 3600; // Seconds
|
||||
const HOUR_10 = HOUR_1 * 10;
|
||||
const HOUR_20 = HOUR_1 * 20;
|
||||
const SHAPE_BLUEPRINT = "CbCbCbRb:CwCwCwCw";
|
||||
const ITEM_SHAPE = "shape";
|
||||
const MINUTE_30 = 1800; // Seconds
|
||||
const MINUTE_60 = MINUTE_30 * 2;
|
||||
const MINUTE_120 = MINUTE_30 * 4;
|
||||
const PRODUCED = "produced";
|
||||
const RATE_SLICE_COUNT = 10;
|
||||
const SHAPE_BP = "CbCbCbRb:CwCwCwCw";
|
||||
const SHAPE_LOGO = "RuCw--Cw:----Ru--";
|
||||
const SHAPE_MS_LOGO = "RgRyRbRr";
|
||||
const SHAPE_ROCKET = "CbCuCbCu:Sr------:--CrSrCr:CwCwCwCw";
|
||||
const SHAPE_OLD_LEVEL_17 = "WrRgWrRg:CwCrCwCr:SgSgSgSg";
|
||||
const WIRE_LAYER = "wires";
|
||||
|
||||
export class AchievementProviderInterface {
|
||||
/** @param {Application} app */
|
||||
@ -167,6 +186,7 @@ export class AchievementCollection {
|
||||
this.createAndSet(ACHIEVEMENTS.logoBefore18, {
|
||||
isRelevant: this.isLogoBefore18Relevant,
|
||||
isValid: this.isLogoBefore18Valid,
|
||||
signal: "itemProduced"
|
||||
});
|
||||
this.createAndSet(ACHIEVEMENTS.mapMarkers15, {
|
||||
isRelevant: this.isMapMarkers15Relevant,
|
||||
@ -194,8 +214,12 @@ export class AchievementCollection {
|
||||
this.createAndSet(ACHIEVEMENTS.produceRocket, this.createShapeOptions(SHAPE_ROCKET));
|
||||
this.createAndSet(ACHIEVEMENTS.produceMsLogo, this.createShapeOptions(SHAPE_MS_LOGO));
|
||||
this.createAndSet(ACHIEVEMENTS.rotateShape);
|
||||
this.createAndSet(ACHIEVEMENTS.speedrunBp30, this.createSpeedOptions(12, MINUTE_30));
|
||||
this.createAndSet(ACHIEVEMENTS.speedrunBp60, this.createSpeedOptions(12, MINUTE_60));
|
||||
this.createAndSet(ACHIEVEMENTS.speedrunBp120, this.createSpeedOptions(12, MINUTE_120));
|
||||
this.createAndSet(ACHIEVEMENTS.stack4Layers, {
|
||||
isValid: this.isStack4LayersValid,
|
||||
signal: "itemProduced",
|
||||
});
|
||||
this.createAndSet(ACHIEVEMENTS.stackShape);
|
||||
this.createAndSet(ACHIEVEMENTS.store100Unique, {
|
||||
@ -205,7 +229,16 @@ export class AchievementCollection {
|
||||
});
|
||||
this.createAndSet(ACHIEVEMENTS.storeShape, {
|
||||
isValid: this.isStoreShapeValid,
|
||||
signal: "entityGotNewComponent",
|
||||
});
|
||||
this.createAndSet(ACHIEVEMENTS.throughputBp25, this.createRateOptions(SHAPE_BP, 25));
|
||||
this.createAndSet(ACHIEVEMENTS.throughputBp50, this.createRateOptions(SHAPE_BP, 50));
|
||||
this.createAndSet(ACHIEVEMENTS.throughputLogo25, this.createRateOptions(SHAPE_LOGO, 25));
|
||||
this.createAndSet(ACHIEVEMENTS.throughputLogo50, this.createRateOptions(SHAPE_LOGO, 50));
|
||||
this.createAndSet(ACHIEVEMENTS.throughputRocket10, this.createRateOptions(SHAPE_ROCKET, 25));
|
||||
this.createAndSet(ACHIEVEMENTS.throughputRocket20, this.createRateOptions(SHAPE_ROCKET, 50));
|
||||
this.createAndSet(ACHIEVEMENTS.trash1000, {
|
||||
init: this.initTrash1000,
|
||||
isValid: this.isTrash1000Valid,
|
||||
});
|
||||
this.createAndSet(ACHIEVEMENTS.unlockWires, this.createLevelOptions(20));
|
||||
this.createAndSet(ACHIEVEMENTS.upgradesTier5, this.createUpgradeOptions(5));
|
||||
@ -219,6 +252,10 @@ export class AchievementCollection {
|
||||
this.root.signals.bulkAchievementCheck.add(this.bulkUnlock, this);
|
||||
|
||||
for (let [key, achievement] of this.map.entries()) {
|
||||
if (achievement.init) {
|
||||
achievement.init();
|
||||
}
|
||||
|
||||
if (!achievement.isRelevant()) {
|
||||
this.remove(key);
|
||||
continue;
|
||||
@ -251,6 +288,10 @@ export class AchievementCollection {
|
||||
|
||||
achievement.activate = this.activate;
|
||||
|
||||
if (options.init) {
|
||||
achievement.init = options.init.bind(this, achievement);
|
||||
}
|
||||
|
||||
if (options.isValid) {
|
||||
achievement.isValid = options.isValid.bind(this);
|
||||
}
|
||||
@ -274,16 +315,16 @@ export class AchievementCollection {
|
||||
|
||||
/**
|
||||
* @param {string} key - Maps to an Achievement
|
||||
* @param {*[]} [arguments] - Additional arguments received from signal dispatches
|
||||
* @param {?*} data - Data received from signal dispatches for validation
|
||||
*/
|
||||
unlock(key) {
|
||||
unlock(key, data) {
|
||||
if (!this.map.has(key)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const achievement = this.map.get(key);
|
||||
|
||||
if (!achievement.isValid(...arguments)) {
|
||||
if (!achievement.isValid(data, achievement.state)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -347,17 +388,46 @@ export class AchievementCollection {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {BaseItem} item
|
||||
* @param {string} shape
|
||||
* @returns {boolean}
|
||||
*/
|
||||
isShape(item, shape) {
|
||||
return item.getItemType() === ITEM_SHAPE && item.definition.getHash() === shape;
|
||||
}
|
||||
|
||||
createLevelOptions(level) {
|
||||
return {
|
||||
isRelevant: () => this.root.hubGoals.level < level,
|
||||
isValid: (key, currentLevel) => currentLevel === level,
|
||||
isValid: (currentLevel) => currentLevel === level,
|
||||
signal: "storyGoalCompleted",
|
||||
};
|
||||
}
|
||||
|
||||
createRateOptions(shape, rate) {
|
||||
return {
|
||||
isValid: () => {
|
||||
return this.root.productionAnalytics.getCurrentShapeRate(
|
||||
enumAnalyticsDataSource.produced,
|
||||
this.root.shapeDefinitionMgr.getShapeFromShortKey(shape)
|
||||
) >= rate;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
createShapeOptions(shape) {
|
||||
return {
|
||||
isValid: (key, definition) => definition.cachedHash === shape,
|
||||
isValid: (item) => this.isShape(item, shape),
|
||||
signal: "itemProduced",
|
||||
};
|
||||
}
|
||||
|
||||
createSpeedOptions(level, time) {
|
||||
return {
|
||||
isRelevant: () => this.root.hubGoals.level <= level && this.root.time.now() < time,
|
||||
isValid: (currentLevel) => currentLevel === level && this.root.time.now() < time,
|
||||
signal: "storyGoalCompleted",
|
||||
};
|
||||
}
|
||||
|
||||
@ -376,62 +446,39 @@ export class AchievementCollection {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} key
|
||||
* @param {Entity} entity
|
||||
* @returns {boolean}
|
||||
*/
|
||||
isBelt500TilesValid(key, entity) {
|
||||
/** @param {Entity} entity @returns {boolean} */
|
||||
isBelt500TilesValid(entity) {
|
||||
return entity.components.Belt && entity.components.Belt.assignedPath.totalLength >= 500;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} key
|
||||
* @param {ShapeDefinition} definition
|
||||
* @returns {boolean}
|
||||
*/
|
||||
isBlueprint100kValid(key, definition) {
|
||||
/** @param {ShapeDefinition} definition @returns {boolean} */
|
||||
isBlueprint100kValid(definition) {
|
||||
return (
|
||||
definition.cachedHash === SHAPE_BLUEPRINT &&
|
||||
this.root.hubGoals.storedShapes[SHAPE_BLUEPRINT] >= 100000
|
||||
definition.cachedHash === SHAPE_BP &&
|
||||
this.root.hubGoals.storedShapes[SHAPE_BP] >= 100000
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} key
|
||||
* @param {ShapeDefinition} definition
|
||||
* @returns {boolean}
|
||||
*/
|
||||
isBlueprint1mValid(key, definition) {
|
||||
/** @param {ShapeDefinition} definition @returns {boolean} */
|
||||
isBlueprint1mValid(definition) {
|
||||
return (
|
||||
definition.cachedHash === SHAPE_BLUEPRINT &&
|
||||
this.root.hubGoals.storedShapes[SHAPE_BLUEPRINT] >= 1000000
|
||||
definition.cachedHash === SHAPE_BP &&
|
||||
this.root.hubGoals.storedShapes[SHAPE_BP] >= 1000000
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} key
|
||||
* @returns {boolean}
|
||||
*/
|
||||
isDarkModeValid(key) {
|
||||
/** @returns {boolean} */
|
||||
isDarkModeValid() {
|
||||
return this.root.app.settings.currentData.settings.theme === DARK_MODE;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} key
|
||||
* @param {number} count - The count of selected entities destroyed
|
||||
* @returns {boolean}
|
||||
*/
|
||||
isDestroy1000Valid(key, count) {
|
||||
/** @param {number} count @returns {boolean} */
|
||||
isDestroy1000Valid(count) {
|
||||
return count >= 1000;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} key
|
||||
* @param {ShapeDefinition} definition
|
||||
* @returns {boolean}
|
||||
*/
|
||||
isIrrelevantShapeValid(key, definition) {
|
||||
/** @param {ShapeDefinition} definition @returns {boolean} */
|
||||
isIrrelevantShapeValid(definition) {
|
||||
if (definition.cachedHash === this.root.hubGoals.currentGoal.definition.cachedHash) {
|
||||
return false;
|
||||
}
|
||||
@ -456,13 +503,9 @@ export class AchievementCollection {
|
||||
return this.root.hubGoals.level < 18;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} key
|
||||
* @param {ShapeDefinition} definition
|
||||
* @returns {boolean}
|
||||
*/
|
||||
isLogoBefore18Valid(key, definition) {
|
||||
return this.root.hubGoals.level < 18 && definition.cachedHash === SHAPE_LOGO;
|
||||
/** @param {BaseItem} item @returns {boolean} */
|
||||
isLogoBefore18Valid(item) {
|
||||
return this.root.hubGoals.level < 18 && this.isShape(item, SHAPE_LOGO);
|
||||
}
|
||||
|
||||
/** @returns {boolean} */
|
||||
@ -470,30 +513,18 @@ export class AchievementCollection {
|
||||
return this.root.hud.parts.waypoints.waypoints.length < 16; // 16 - HUB
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} key
|
||||
* @param {number} count - Count of map markers excluding HUB
|
||||
* @returns {boolean}
|
||||
*/
|
||||
isMapMarkers15Valid(key, count) {
|
||||
/** @param {number} count @returns {boolean} */
|
||||
isMapMarkers15Valid(count) {
|
||||
return count === 15;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} key
|
||||
* @param {string} currentLayer
|
||||
* @returns {boolean}
|
||||
*/
|
||||
isOpenWiresValid(key, currentLayer) {
|
||||
/** @param {string} currentLayer @returns {boolean} */
|
||||
isOpenWiresValid(currentLayer) {
|
||||
return currentLayer === WIRE_LAYER;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} key
|
||||
* @param {Entity} entity
|
||||
* @returns {boolean}
|
||||
*/
|
||||
isPlace5000WiresValid(key, entity) {
|
||||
/** @param {Entity} entity @returns {boolean} */
|
||||
isPlace5000WiresValid(entity) {
|
||||
return (
|
||||
entity.components.Wire &&
|
||||
entity.registered &&
|
||||
@ -501,31 +532,19 @@ export class AchievementCollection {
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} key
|
||||
* @param {number} count
|
||||
* @returns {boolean}
|
||||
*/
|
||||
isPlaceBlueprintValid(key, count) {
|
||||
/** @param {number} count @returns {boolean} */
|
||||
isPlaceBlueprintValid(count) {
|
||||
return count != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} key
|
||||
* @param {number} count
|
||||
* @returns {boolean}
|
||||
*/
|
||||
isPlaceBp1000Valid(key, count) {
|
||||
/** @param {number} count @returns {boolean} */
|
||||
isPlaceBp1000Valid(count) {
|
||||
return count >= 1000;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} key
|
||||
* @param {ShapeDefinition} definition
|
||||
* @returns {boolean}
|
||||
*/
|
||||
isStack4LayersValid(key, definition) {
|
||||
return definition.layers.length === 4;
|
||||
/** @param {string} key @param {BaseItem} item @returns {boolean} */
|
||||
isStack4LayersValid(item) {
|
||||
return item.getItemType() === ITEM_SHAPE && item.definition.layers.length === 4;
|
||||
}
|
||||
|
||||
/** @returns {boolean} */
|
||||
@ -533,20 +552,43 @@ export class AchievementCollection {
|
||||
return Object.keys(this.root.hubGoals.storedShapes).length < 100;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} key
|
||||
* @returns {boolean}
|
||||
*/
|
||||
isStore100UniqueValid(key) {
|
||||
/** @returns {boolean} */
|
||||
isStore100UniqueValid() {
|
||||
return Object.keys(this.root.hubGoals.storedShapes).length === 100;
|
||||
}
|
||||
|
||||
/** @param {StorageComponent} storage @returns {boolean} */
|
||||
isStoreShapeValid() {
|
||||
const entities = this.root.systemMgr.systems.storage.allEntities;
|
||||
|
||||
if (entities.length === 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (var i = 0; i < entities.length; i++) {
|
||||
if (entities[i].components.Storage.storedCount > 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
initTrash1000(achievement) {
|
||||
// get state from root
|
||||
console.log(this.root.savegame.currentData.dump);
|
||||
|
||||
achievement.state = achievement.state || {
|
||||
count: 0
|
||||
};
|
||||
}
|
||||
/**
|
||||
* @param {string} key
|
||||
* @param {StorageComponent} storage
|
||||
* @returns {boolean}
|
||||
*/
|
||||
isStoreShapeValid(key, storage) {
|
||||
return storage.storedCount >= 1;
|
||||
* @params {number} count
|
||||
* @params {object} state - The achievement's current state
|
||||
* @returns {boolean} */
|
||||
isTrash1000Valid(count, state) {
|
||||
state.count += count;
|
||||
|
||||
return state.count >= 1000;
|
||||
}
|
||||
}
|
||||
|
@ -35,10 +35,20 @@ const ACHIEVEMENT_IDS = {
|
||||
[ACHIEVEMENTS.produceMsLogo]: "produce_ms_logo",
|
||||
[ACHIEVEMENTS.produceRocket]: "produce_rocket",
|
||||
[ACHIEVEMENTS.rotateShape]: "rotate_shape",
|
||||
[ACHIEVEMENTS.speedrunBp30]: "speedrun_bp_30",
|
||||
[ACHIEVEMENTS.speedrunBp60]: "speedrun_bp_60",
|
||||
[ACHIEVEMENTS.speedrunBp120]: "speedrun_bp_120",
|
||||
[ACHIEVEMENTS.stack4Layers]: "stack_4_layers",
|
||||
[ACHIEVEMENTS.stackShape]: "stack_shape",
|
||||
[ACHIEVEMENTS.store100Unique]: "store_100_unique",
|
||||
[ACHIEVEMENTS.storeShape]: "store_shape",
|
||||
[ACHIEVEMENTS.throughputBp25]: "throughput_bp_25",
|
||||
[ACHIEVEMENTS.throughputBp50]: "throughput_bp_50",
|
||||
[ACHIEVEMENTS.throughputLogo25]: "throughput_logo_25",
|
||||
[ACHIEVEMENTS.throughputLogo50]: "throughput_logo_50",
|
||||
[ACHIEVEMENTS.throughputRocket10]: "throughput_rocket_10",
|
||||
[ACHIEVEMENTS.throughputRocket20]: "throughput_rocket_20",
|
||||
[ACHIEVEMENTS.trash1000]: "trash_1000",
|
||||
[ACHIEVEMENTS.unlockWires]: "unlock_wires",
|
||||
[ACHIEVEMENTS.upgradesTier5]: "upgrades_tier_5",
|
||||
[ACHIEVEMENTS.upgradesTier8]: "upgrades_tier_8",
|
||||
|
26
src/js/savegame/schemas/1008.js
Normal file
26
src/js/savegame/schemas/1008.js
Normal file
@ -0,0 +1,26 @@
|
||||
import { createLogger } from "../../core/logging.js";
|
||||
import { SavegameInterface_V1007 } from "./1007.js";
|
||||
|
||||
const schema = require("./1008.json");
|
||||
const logger = createLogger("savegame_interface/1008");
|
||||
|
||||
export class SavegameInterface_V1008 extends SavegameInterface_V1007 {
|
||||
getVersion() {
|
||||
return 1008;
|
||||
}
|
||||
|
||||
getSchemaUncached() {
|
||||
return schema;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {import("../savegame_typedefs.js").SavegameData} data
|
||||
*/
|
||||
static migrate1007to1008(data) {
|
||||
logger.log("Migrating 1007 to 1008");
|
||||
const dump = data.dump;
|
||||
if (!dump) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
5
src/js/savegame/schemas/1008.json
Normal file
5
src/js/savegame/schemas/1008.json
Normal file
@ -0,0 +1,5 @@
|
||||
{
|
||||
"type": "object",
|
||||
"required": [],
|
||||
"additionalProperties": true
|
||||
}
|
Loading…
Reference in New Issue
Block a user