mirror of
https://github.com/tobspr/shapez.io.git
synced 2025-06-13 13:04:03 +00:00
Add more achievements. Add bulk achievement check signal
This commit is contained in:
parent
dc2ae5504c
commit
a722c3562d
@ -24,30 +24,27 @@ export class AchievementProxy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
onLoad() {
|
onLoad() {
|
||||||
if (this.provider.hasLoaded()) {
|
|
||||||
this.disabled = false;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.provider.onLoad(this.root)
|
this.provider.onLoad(this.root)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
logger.log("Listening for unlocked achievements");
|
logger.log("Recieving achievement signals");
|
||||||
this.root.signals.achievementUnlocked.dispatch(ACHIEVEMENTS.darkMode);
|
this.root.signals.achievementCheck.dispatch(ACHIEVEMENTS.darkMode);
|
||||||
this.startSlice();
|
this.startSlice();
|
||||||
this.disabled = false;
|
this.disabled = false;
|
||||||
})
|
})
|
||||||
.catch(err => {
|
.catch(err => {
|
||||||
this.disabled = true;
|
this.disabled = true;
|
||||||
logger.error("Ignoring achievement signals", err);
|
logger.error("Ignoring achievement signals", err);
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
startSlice() {
|
startSlice() {
|
||||||
this.lastSlice = this.root.time.now();
|
this.lastSlice = this.root.time.now();
|
||||||
|
|
||||||
this.root.signals.achievementUnlocked.dispatch(ACHIEVEMENTS.play1h, this.lastSlice);
|
this.root.signals.bulkAchievementCheck.dispatch(
|
||||||
this.root.signals.achievementUnlocked.dispatch(ACHIEVEMENTS.play10h, this.lastSlice);
|
ACHIEVEMENTS.play1h, this.lastSlice,
|
||||||
this.root.signals.achievementUnlocked.dispatch(ACHIEVEMENTS.play20h, this.lastSlice);
|
ACHIEVEMENTS.play10h, this.lastSlice,
|
||||||
|
ACHIEVEMENTS.play20h, this.lastSlice
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
update() {
|
update() {
|
||||||
|
@ -149,7 +149,7 @@ export class Blueprint {
|
|||||||
*/
|
*/
|
||||||
tryPlace(root, tile) {
|
tryPlace(root, tile) {
|
||||||
return root.logic.performBulkOperation(() => {
|
return root.logic.performBulkOperation(() => {
|
||||||
let anyPlaced = false;
|
let count = 0;
|
||||||
for (let i = 0; i < this.entities.length; ++i) {
|
for (let i = 0; i < this.entities.length; ++i) {
|
||||||
const entity = this.entities[i];
|
const entity = this.entities[i];
|
||||||
if (!root.logic.checkCanPlaceEntity(entity, tile)) {
|
if (!root.logic.checkCanPlaceEntity(entity, tile)) {
|
||||||
@ -161,12 +161,15 @@ export class Blueprint {
|
|||||||
root.logic.freeEntityAreaBeforeBuild(clone);
|
root.logic.freeEntityAreaBeforeBuild(clone);
|
||||||
root.map.placeStaticEntity(clone);
|
root.map.placeStaticEntity(clone);
|
||||||
root.entityMgr.registerEntity(clone);
|
root.entityMgr.registerEntity(clone);
|
||||||
anyPlaced = true;
|
count++;
|
||||||
}
|
}
|
||||||
|
|
||||||
root.signals.achievementUnlocked.dispatch(ACHIEVEMENTS.placeBlueprint, anyPlaced);
|
root.signals.bulkAchievementCheck.dispatch(
|
||||||
|
ACHIEVEMENTS.placeBlueprint, count,
|
||||||
|
ACHIEVEMENTS.placeBp1000, count
|
||||||
|
);
|
||||||
|
|
||||||
return anyPlaced;
|
return count !== 0;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,7 @@ import { globalConfig } from "../../../core/config";
|
|||||||
import { makeDiv, formatBigNumber, formatBigNumberFull } from "../../../core/utils";
|
import { makeDiv, formatBigNumber, formatBigNumberFull } from "../../../core/utils";
|
||||||
import { DynamicDomAttach } from "../dynamic_dom_attach";
|
import { DynamicDomAttach } from "../dynamic_dom_attach";
|
||||||
import { createLogger } from "../../../core/logging";
|
import { createLogger } from "../../../core/logging";
|
||||||
|
import { ACHIEVEMENTS } from "../../../platform/achievement_provider";
|
||||||
import { enumMouseButton } from "../../camera";
|
import { enumMouseButton } from "../../camera";
|
||||||
import { T } from "../../../translations";
|
import { T } from "../../../translations";
|
||||||
import { KEYMAPPINGS } from "../../key_action_mapper";
|
import { KEYMAPPINGS } from "../../key_action_mapper";
|
||||||
@ -100,6 +101,7 @@ export class HUDMassSelector extends BaseHUDPart {
|
|||||||
*/
|
*/
|
||||||
const mapUidToEntity = this.root.entityMgr.getFrozenUidSearchMap();
|
const mapUidToEntity = this.root.entityMgr.getFrozenUidSearchMap();
|
||||||
|
|
||||||
|
let count = 0;
|
||||||
this.root.logic.performBulkOperation(() => {
|
this.root.logic.performBulkOperation(() => {
|
||||||
for (let i = 0; i < entityUids.length; ++i) {
|
for (let i = 0; i < entityUids.length; ++i) {
|
||||||
const uid = entityUids[i];
|
const uid = entityUids[i];
|
||||||
@ -111,8 +113,12 @@ export class HUDMassSelector extends BaseHUDPart {
|
|||||||
|
|
||||||
if (!this.root.logic.tryDeleteBuilding(entity)) {
|
if (!this.root.logic.tryDeleteBuilding(entity)) {
|
||||||
logger.error("Error in mass delete, could not remove building");
|
logger.error("Error in mass delete, could not remove building");
|
||||||
|
} else {
|
||||||
|
count++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.root.signals.achievementCheck.dispatch(ACHIEVEMENTS.destroy1000, count);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Clear uids later
|
// Clear uids later
|
||||||
|
@ -15,6 +15,7 @@ import {
|
|||||||
removeAllChildren,
|
removeAllChildren,
|
||||||
} from "../../../core/utils";
|
} from "../../../core/utils";
|
||||||
import { Vector } from "../../../core/vector";
|
import { Vector } from "../../../core/vector";
|
||||||
|
import { ACHIEVEMENTS } from "../../../platform/achievement_provider";
|
||||||
import { T } from "../../../translations";
|
import { T } from "../../../translations";
|
||||||
import { BaseItem } from "../../base_item";
|
import { BaseItem } from "../../base_item";
|
||||||
import { MetaHubBuilding } from "../../buildings/hub";
|
import { MetaHubBuilding } from "../../buildings/hub";
|
||||||
@ -349,6 +350,10 @@ export class HUDWaypoints extends BaseHUDPart {
|
|||||||
T.ingame.waypoints.creationSuccessNotification,
|
T.ingame.waypoints.creationSuccessNotification,
|
||||||
enumNotificationType.success
|
enumNotificationType.success
|
||||||
);
|
);
|
||||||
|
this.root.signals.achievementCheck.dispatch(
|
||||||
|
ACHIEVEMENTS.mapMarkers15,
|
||||||
|
this.waypoints.length - 1 // Disregard HUB
|
||||||
|
);
|
||||||
|
|
||||||
// Re-render the list and thus add it
|
// Re-render the list and thus add it
|
||||||
this.rerenderWaypointList();
|
this.rerenderWaypointList();
|
||||||
|
@ -181,7 +181,8 @@ export class GameRoot {
|
|||||||
freeEntityAreaBeforeBuild: /** @type {TypedSignal<[Entity]>} */ (new Signal()),
|
freeEntityAreaBeforeBuild: /** @type {TypedSignal<[Entity]>} */ (new Signal()),
|
||||||
|
|
||||||
// Called with an achievement key and necessary args to validate it can be unlocked.
|
// Called with an achievement key and necessary args to validate it can be unlocked.
|
||||||
achievementUnlocked: /** @type {TypedSignal<[string, ...*]>} */ (new Signal()),
|
achievementCheck: /** @type {TypedSignal<[string, *]>} */ (new Signal()),
|
||||||
|
bulkAchievementCheck: /** @type {TypedSignal<[string, ...*]>} */ (new Signal()),
|
||||||
};
|
};
|
||||||
|
|
||||||
// RNG's
|
// RNG's
|
||||||
|
@ -97,7 +97,7 @@ export class ShapeDefinitionManager extends BasicSerializableObject {
|
|||||||
const rightSide = definition.cloneFilteredByQuadrants([2, 3]);
|
const rightSide = definition.cloneFilteredByQuadrants([2, 3]);
|
||||||
const leftSide = definition.cloneFilteredByQuadrants([0, 1]);
|
const leftSide = definition.cloneFilteredByQuadrants([0, 1]);
|
||||||
|
|
||||||
this.root.signals.achievementUnlocked.dispatch(ACHIEVEMENTS.cutShape);
|
this.root.signals.achievementCheck.dispatch(ACHIEVEMENTS.cutShape);
|
||||||
|
|
||||||
return /** @type {[ShapeDefinition, ShapeDefinition]} */ (this.operationCache[key] = [
|
return /** @type {[ShapeDefinition, ShapeDefinition]} */ (this.operationCache[key] = [
|
||||||
this.registerOrReturnHandle(rightSide),
|
this.registerOrReturnHandle(rightSide),
|
||||||
@ -140,7 +140,7 @@ export class ShapeDefinitionManager extends BasicSerializableObject {
|
|||||||
|
|
||||||
const rotated = definition.cloneRotateCW();
|
const rotated = definition.cloneRotateCW();
|
||||||
|
|
||||||
this.root.signals.achievementUnlocked.dispatch(ACHIEVEMENTS.rotateShape);
|
this.root.signals.achievementCheck.dispatch(ACHIEVEMENTS.rotateShape);
|
||||||
|
|
||||||
return /** @type {ShapeDefinition} */ (this.operationCache[key] = this.registerOrReturnHandle(
|
return /** @type {ShapeDefinition} */ (this.operationCache[key] = this.registerOrReturnHandle(
|
||||||
rotated
|
rotated
|
||||||
@ -195,7 +195,7 @@ export class ShapeDefinitionManager extends BasicSerializableObject {
|
|||||||
return /** @type {ShapeDefinition} */ (this.operationCache[key]);
|
return /** @type {ShapeDefinition} */ (this.operationCache[key]);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.root.signals.achievementUnlocked.dispatch(ACHIEVEMENTS.stackShape);
|
this.root.signals.achievementCheck.dispatch(ACHIEVEMENTS.stackShape);
|
||||||
|
|
||||||
const stacked = lowerDefinition.cloneAndStackWith(upperDefinition);
|
const stacked = lowerDefinition.cloneAndStackWith(upperDefinition);
|
||||||
return /** @type {ShapeDefinition} */ (this.operationCache[key] = this.registerOrReturnHandle(
|
return /** @type {ShapeDefinition} */ (this.operationCache[key] = this.registerOrReturnHandle(
|
||||||
@ -215,7 +215,7 @@ export class ShapeDefinitionManager extends BasicSerializableObject {
|
|||||||
return /** @type {ShapeDefinition} */ (this.operationCache[key]);
|
return /** @type {ShapeDefinition} */ (this.operationCache[key]);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.root.signals.achievementUnlocked.dispatch(ACHIEVEMENTS.paintShape);
|
this.root.signals.achievementCheck.dispatch(ACHIEVEMENTS.paintShape);
|
||||||
|
|
||||||
const colorized = definition.cloneAndPaintWith(color);
|
const colorized = definition.cloneAndPaintWith(color);
|
||||||
return /** @type {ShapeDefinition} */ (this.operationCache[key] = this.registerOrReturnHandle(
|
return /** @type {ShapeDefinition} */ (this.operationCache[key] = this.registerOrReturnHandle(
|
||||||
@ -252,11 +252,14 @@ export class ShapeDefinitionManager extends BasicSerializableObject {
|
|||||||
}
|
}
|
||||||
this.shapeKeyToDefinition[id] = definition;
|
this.shapeKeyToDefinition[id] = definition;
|
||||||
|
|
||||||
this.root.signals.achievementUnlocked.dispatch(ACHIEVEMENTS.oldLevel17, definition);
|
this.root.signals.bulkAchievementCheck.dispatch(
|
||||||
this.root.signals.achievementUnlocked.dispatch(ACHIEVEMENTS.produceLogo, definition);
|
ACHIEVEMENTS.logoBefore18, definition,
|
||||||
this.root.signals.achievementUnlocked.dispatch(ACHIEVEMENTS.produceMsLogo, definition);
|
ACHIEVEMENTS.oldLevel17, definition,
|
||||||
this.root.signals.achievementUnlocked.dispatch(ACHIEVEMENTS.produceRocket, definition);
|
ACHIEVEMENTS.produceLogo, definition,
|
||||||
this.root.signals.achievementUnlocked.dispatch(ACHIEVEMENTS.stack4Layers, definition);
|
ACHIEVEMENTS.produceMsLogo, definition,
|
||||||
|
ACHIEVEMENTS.produceRocket, definition,
|
||||||
|
ACHIEVEMENTS.stack4Layers, definition
|
||||||
|
);
|
||||||
|
|
||||||
// logger.log("Registered shape with key (2)", id);
|
// logger.log("Registered shape with key (2)", id);
|
||||||
return definition;
|
return definition;
|
||||||
|
@ -276,7 +276,7 @@ export class ItemEjectorSystem extends GameSystemWithFilter {
|
|||||||
if (storageComp.canAcceptItem(item)) {
|
if (storageComp.canAcceptItem(item)) {
|
||||||
storageComp.takeItem(item);
|
storageComp.takeItem(item);
|
||||||
|
|
||||||
this.root.signals.achievementUnlocked.dispatch(ACHIEVEMENTS.storeShape, storageComp);
|
this.root.signals.achievementCheck.dispatch(ACHIEVEMENTS.storeShape, storageComp);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -698,7 +698,7 @@ export class WireSystem extends GameSystemWithFilter {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.root.signals.achievementUnlocked.dispatch(ACHIEVEMENTS.place5000Wires, entity);
|
this.root.signals.achievementCheck.dispatch(ACHIEVEMENTS.place5000Wires, entity);
|
||||||
|
|
||||||
// Invalidate affected area
|
// Invalidate affected area
|
||||||
const originalRect = staticComp.getTileSpaceBounds();
|
const originalRect = staticComp.getTileSpaceBounds();
|
||||||
|
@ -13,14 +13,18 @@ export const ACHIEVEMENTS = {
|
|||||||
completeLvl26: "completeLvl26",
|
completeLvl26: "completeLvl26",
|
||||||
cutShape: "cutShape",
|
cutShape: "cutShape",
|
||||||
darkMode: "darkMode",
|
darkMode: "darkMode",
|
||||||
|
destroy1000: "destroy1000",
|
||||||
irrelevantShape: "irrelevantShape",
|
irrelevantShape: "irrelevantShape",
|
||||||
level100: "level100",
|
level100: "level100",
|
||||||
level50: "level50",
|
level50: "level50",
|
||||||
|
logoBefore18: "logoBefore18",
|
||||||
|
mapMarkers15: "mapMarkers15",
|
||||||
oldLevel17: "oldLevel17",
|
oldLevel17: "oldLevel17",
|
||||||
openWires: "openWires",
|
openWires: "openWires",
|
||||||
paintShape: "paintShape",
|
paintShape: "paintShape",
|
||||||
place5000Wires: "place5000Wires",
|
place5000Wires: "place5000Wires",
|
||||||
placeBlueprint: "placeBlueprint",
|
placeBlueprint: "placeBlueprint",
|
||||||
|
placeBp1000: "placeBp1000",
|
||||||
play1h: "play1h",
|
play1h: "play1h",
|
||||||
play10h: "play10h",
|
play10h: "play10h",
|
||||||
play20h: "play20h",
|
play20h: "play20h",
|
||||||
@ -33,6 +37,8 @@ export const ACHIEVEMENTS = {
|
|||||||
store100Unique: "store100Unique",
|
store100Unique: "store100Unique",
|
||||||
storeShape: "storeShape",
|
storeShape: "storeShape",
|
||||||
unlockWires: "unlockWires",
|
unlockWires: "unlockWires",
|
||||||
|
upgradesTier5: "upgradesTier5",
|
||||||
|
upgradesTier8: "upgradesTier8",
|
||||||
};
|
};
|
||||||
|
|
||||||
const DARK_MODE = "dark";
|
const DARK_MODE = "dark";
|
||||||
@ -149,14 +155,23 @@ export class AchievementCollection {
|
|||||||
this.createAndSet(ACHIEVEMENTS.darkMode, {
|
this.createAndSet(ACHIEVEMENTS.darkMode, {
|
||||||
isValid: this.isDarkModeValid,
|
isValid: this.isDarkModeValid,
|
||||||
});
|
});
|
||||||
/*
|
this.createAndSet(ACHIEVEMENTS.destroy1000, {
|
||||||
*this.createAndSet(ACHIEVEMENTS.irrelevantShape, {
|
isValid: this.isDestroy1000Valid,
|
||||||
* isValid: this.isIrrelevantShapeValid,
|
});
|
||||||
* signal: "shapeDelivered",
|
this.createAndSet(ACHIEVEMENTS.irrelevantShape, {
|
||||||
*});
|
isValid: this.isIrrelevantShapeValid,
|
||||||
*/
|
signal: "shapeDelivered",
|
||||||
|
});
|
||||||
this.createAndSet(ACHIEVEMENTS.level100, this.createLevelOptions(100));
|
this.createAndSet(ACHIEVEMENTS.level100, this.createLevelOptions(100));
|
||||||
this.createAndSet(ACHIEVEMENTS.level50, this.createLevelOptions(50));
|
this.createAndSet(ACHIEVEMENTS.level50, this.createLevelOptions(50));
|
||||||
|
this.createAndSet(ACHIEVEMENTS.logoBefore18, {
|
||||||
|
isRelevant: this.isLogoBefore18Relevant,
|
||||||
|
isValid: this.isLogoBefore18Valid,
|
||||||
|
});
|
||||||
|
this.createAndSet(ACHIEVEMENTS.mapMarkers15, {
|
||||||
|
isRelevant: this.isMapMarkers15Relevant,
|
||||||
|
isValid: this.isMapMarkers15Valid,
|
||||||
|
});
|
||||||
this.createAndSet(ACHIEVEMENTS.oldLevel17, this.createShapeOptions(SHAPE_OLD_LEVEL_17));
|
this.createAndSet(ACHIEVEMENTS.oldLevel17, this.createShapeOptions(SHAPE_OLD_LEVEL_17));
|
||||||
this.createAndSet(ACHIEVEMENTS.openWires, {
|
this.createAndSet(ACHIEVEMENTS.openWires, {
|
||||||
isValid: this.isOpenWiresValid,
|
isValid: this.isOpenWiresValid,
|
||||||
@ -169,6 +184,9 @@ export class AchievementCollection {
|
|||||||
this.createAndSet(ACHIEVEMENTS.placeBlueprint, {
|
this.createAndSet(ACHIEVEMENTS.placeBlueprint, {
|
||||||
isValid: this.isPlaceBlueprintValid,
|
isValid: this.isPlaceBlueprintValid,
|
||||||
});
|
});
|
||||||
|
this.createAndSet(ACHIEVEMENTS.placeBp1000, {
|
||||||
|
isValid: this.isPlaceBp1000Valid,
|
||||||
|
});
|
||||||
this.createAndSet(ACHIEVEMENTS.play1h, this.createTimeOptions(HOUR_1));
|
this.createAndSet(ACHIEVEMENTS.play1h, this.createTimeOptions(HOUR_1));
|
||||||
this.createAndSet(ACHIEVEMENTS.play10h, this.createTimeOptions(HOUR_10));
|
this.createAndSet(ACHIEVEMENTS.play10h, this.createTimeOptions(HOUR_10));
|
||||||
this.createAndSet(ACHIEVEMENTS.play20h, this.createTimeOptions(HOUR_20));
|
this.createAndSet(ACHIEVEMENTS.play20h, this.createTimeOptions(HOUR_20));
|
||||||
@ -190,12 +208,15 @@ export class AchievementCollection {
|
|||||||
signal: "entityGotNewComponent",
|
signal: "entityGotNewComponent",
|
||||||
});
|
});
|
||||||
this.createAndSet(ACHIEVEMENTS.unlockWires, this.createLevelOptions(20));
|
this.createAndSet(ACHIEVEMENTS.unlockWires, this.createLevelOptions(20));
|
||||||
|
this.createAndSet(ACHIEVEMENTS.upgradesTier5, this.createUpgradeOptions(5));
|
||||||
|
this.createAndSet(ACHIEVEMENTS.upgradesTier8, this.createUpgradeOptions(8));
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @param {GameRoot} root */
|
/** @param {GameRoot} root */
|
||||||
initialize(root) {
|
initialize(root) {
|
||||||
this.root = root;
|
this.root = root;
|
||||||
this.root.signals.achievementUnlocked.add(this.unlock, this);
|
this.root.signals.achievementCheck.add(this.unlock, this);
|
||||||
|
this.root.signals.bulkAchievementCheck.add(this.bulkUnlock, this);
|
||||||
|
|
||||||
for (let [key, achievement] of this.map.entries()) {
|
for (let [key, achievement] of this.map.entries()) {
|
||||||
if (!achievement.isRelevant()) {
|
if (!achievement.isRelevant()) {
|
||||||
@ -210,7 +231,7 @@ export class AchievementCollection {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!this.hasDefaultReceivers()) {
|
if (!this.hasDefaultReceivers()) {
|
||||||
this.root.signals.achievementUnlocked.remove(this.unlock);
|
this.root.signals.achievementCheck.remove(this.unlock);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -222,6 +243,10 @@ export class AchievementCollection {
|
|||||||
* @param {string} [options.signal]
|
* @param {string} [options.signal]
|
||||||
*/
|
*/
|
||||||
createAndSet(key, options = {}) {
|
createAndSet(key, options = {}) {
|
||||||
|
if (G_IS_DEV) {
|
||||||
|
assert(ACHIEVEMENTS[key], "Achievement key not found: ", key);
|
||||||
|
}
|
||||||
|
|
||||||
const achievement = new Achievement(key);
|
const achievement = new Achievement(key);
|
||||||
|
|
||||||
achievement.activate = this.activate;
|
achievement.activate = this.activate;
|
||||||
@ -241,6 +266,12 @@ export class AchievementCollection {
|
|||||||
this.map.set(key, achievement);
|
this.map.set(key, achievement);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bulkUnlock() {
|
||||||
|
for (let i = 0; i < arguments.length; i += 2) {
|
||||||
|
this.unlock(arguments[i], arguments[i + 1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {string} key - Maps to an Achievement
|
* @param {string} key - Maps to an Achievement
|
||||||
* @param {*[]} [arguments] - Additional arguments received from signal dispatches
|
* @param {*[]} [arguments] - Additional arguments received from signal dispatches
|
||||||
@ -271,11 +302,11 @@ export class AchievementCollection {
|
|||||||
* @param {?Error} err - Error is null if activation was successful
|
* @param {?Error} err - Error is null if activation was successful
|
||||||
* @param {string} key - Maps to an Achievement
|
* @param {string} key - Maps to an Achievement
|
||||||
*/
|
*/
|
||||||
onActivate (err, key) {
|
onActivate(err, key) {
|
||||||
this.remove(key);
|
this.remove(key);
|
||||||
|
|
||||||
if (!this.hasDefaultReceivers()) {
|
if (!this.hasDefaultReceivers()) {
|
||||||
this.root.signals.achievementUnlocked.remove(this.unlock);
|
this.root.signals.achievementCheck.remove(this.unlock);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -304,25 +335,45 @@ export class AchievementCollection {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
createLevelOptions (level) {
|
hasAllUpgradesAtTier(tier) {
|
||||||
|
const upgrades = this.root.gameMode.getUpgrades();
|
||||||
|
|
||||||
|
for (let upgradeId in upgrades) {
|
||||||
|
if (this.root.hubGoals.getUpgradeLevel(upgradeId) < tier - 1) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
createLevelOptions(level) {
|
||||||
return {
|
return {
|
||||||
isRelevant: () => this.root.hubGoals.level < level,
|
isRelevant: () => this.root.hubGoals.level < level,
|
||||||
isValid: (key, currentLevel) => currentLevel === level,
|
isValid: (key, currentLevel) => currentLevel === level,
|
||||||
signal: "storyGoalCompleted"
|
signal: "storyGoalCompleted",
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
createShapeOptions (shape) {
|
createShapeOptions(shape) {
|
||||||
return {
|
return {
|
||||||
isValid: (key, definition) => definition.cachedHash === shape
|
isValid: (key, definition) => definition.cachedHash === shape,
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
createTimeOptions (duration) {
|
createTimeOptions(duration) {
|
||||||
return {
|
return {
|
||||||
isRelevant: () => this.root.time.now() < duration,
|
isRelevant: () => this.root.time.now() < duration,
|
||||||
isValid: () => this.root.time.now() >= duration,
|
isValid: () => this.root.time.now() >= duration,
|
||||||
}
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
createUpgradeOptions(tier) {
|
||||||
|
return {
|
||||||
|
isRelevant: () => !this.hasAllUpgradesAtTier(tier),
|
||||||
|
isValid: () => this.hasAllUpgradesAtTier(tier),
|
||||||
|
signal: "upgradePurchased",
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -340,8 +391,10 @@ export class AchievementCollection {
|
|||||||
* @returns {boolean}
|
* @returns {boolean}
|
||||||
*/
|
*/
|
||||||
isBlueprint100kValid(key, definition) {
|
isBlueprint100kValid(key, definition) {
|
||||||
return definition.cachedHash === SHAPE_BLUEPRINT &&
|
return (
|
||||||
this.root.hubGoals.storedShapes[SHAPE_BLUEPRINT] >= 100000;
|
definition.cachedHash === SHAPE_BLUEPRINT &&
|
||||||
|
this.root.hubGoals.storedShapes[SHAPE_BLUEPRINT] >= 100000
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -350,8 +403,10 @@ export class AchievementCollection {
|
|||||||
* @returns {boolean}
|
* @returns {boolean}
|
||||||
*/
|
*/
|
||||||
isBlueprint1mValid(key, definition) {
|
isBlueprint1mValid(key, definition) {
|
||||||
return definition.cachedHash === SHAPE_BLUEPRINT &&
|
return (
|
||||||
this.root.hubGoals.storedShapes[SHAPE_BLUEPRINT] >= 1000000;
|
definition.cachedHash === SHAPE_BLUEPRINT &&
|
||||||
|
this.root.hubGoals.storedShapes[SHAPE_BLUEPRINT] >= 1000000
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -362,13 +417,66 @@ export class AchievementCollection {
|
|||||||
return this.root.app.settings.currentData.settings.theme === DARK_MODE;
|
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) {
|
||||||
|
return count >= 1000;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {string} key
|
* @param {string} key
|
||||||
* @param {ShapeDefinition} definition
|
* @param {ShapeDefinition} definition
|
||||||
* @returns {boolean}
|
* @returns {boolean}
|
||||||
*/
|
*/
|
||||||
isIrrelevantShapeValid(key, definition) {
|
isIrrelevantShapeValid(key, definition) {
|
||||||
//return definition.cachedHash !== this.hubGoals.currentGoal.definition.cachedHash
|
if (definition.cachedHash === this.root.hubGoals.currentGoal.definition.cachedHash) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const upgrades = this.root.gameMode.getUpgrades();
|
||||||
|
for (let upgradeId in upgrades) {
|
||||||
|
const currentTier = this.root.hubGoals.getUpgradeLevel(upgradeId);
|
||||||
|
const requiredShapes = upgrades[upgradeId][currentTier].required;
|
||||||
|
|
||||||
|
for (let i = 0; i < requiredShapes.length; i++) {
|
||||||
|
if (definition.cachedHash === requiredShapes[i].shape) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @returns {boolean} */
|
||||||
|
isLogoBefore18Relevant() {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @returns {boolean} */
|
||||||
|
isMapMarkers15Relevant() {
|
||||||
|
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) {
|
||||||
|
return count === 15;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -386,18 +494,29 @@ export class AchievementCollection {
|
|||||||
* @returns {boolean}
|
* @returns {boolean}
|
||||||
*/
|
*/
|
||||||
isPlace5000WiresValid(key, entity) {
|
isPlace5000WiresValid(key, entity) {
|
||||||
return entity.components.Wire &&
|
return (
|
||||||
|
entity.components.Wire &&
|
||||||
entity.registered &&
|
entity.registered &&
|
||||||
entity.root.entityMgr.componentToEntity.Wire.length === 5000;
|
entity.root.entityMgr.componentToEntity.Wire.length === 5000
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {string} key
|
* @param {string} key
|
||||||
* @param {boolean} anyPlaced
|
* @param {number} count
|
||||||
* @returns {boolean}
|
* @returns {boolean}
|
||||||
*/
|
*/
|
||||||
isPlaceBlueprintValid(key, anyPlaced) {
|
isPlaceBlueprintValid(key, count) {
|
||||||
return anyPlaced;
|
return count != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} key
|
||||||
|
* @param {number} count
|
||||||
|
* @returns {boolean}
|
||||||
|
*/
|
||||||
|
isPlaceBp1000Valid(key, count) {
|
||||||
|
return count >= 1000;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -14,7 +14,7 @@ export class NoAchievementProvider extends AchievementProviderInterface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
onLoad() {
|
onLoad() {
|
||||||
return Promise.resolve();
|
return Promise.reject(new Error("No achievements to load"));
|
||||||
}
|
}
|
||||||
|
|
||||||
activate() {
|
activate() {
|
||||||
|
@ -16,14 +16,18 @@ const ACHIEVEMENT_IDS = {
|
|||||||
[ACHIEVEMENTS.completeLvl26]: "complete_lvl_26",
|
[ACHIEVEMENTS.completeLvl26]: "complete_lvl_26",
|
||||||
[ACHIEVEMENTS.cutShape]: "cut_shape",
|
[ACHIEVEMENTS.cutShape]: "cut_shape",
|
||||||
[ACHIEVEMENTS.darkMode]: "dark_mode",
|
[ACHIEVEMENTS.darkMode]: "dark_mode",
|
||||||
|
[ACHIEVEMENTS.destroy1000]: "destroy_1000",
|
||||||
[ACHIEVEMENTS.irrelevantShape]: "irrelevant_shape",
|
[ACHIEVEMENTS.irrelevantShape]: "irrelevant_shape",
|
||||||
[ACHIEVEMENTS.level100]: "level_100",
|
[ACHIEVEMENTS.level100]: "level_100",
|
||||||
[ACHIEVEMENTS.level50]: "level_50",
|
[ACHIEVEMENTS.level50]: "level_50",
|
||||||
|
[ACHIEVEMENTS.logoBefore18]: "logo_before_18",
|
||||||
|
[ACHIEVEMENTS.mapMarkers15]: "map_markers_15",
|
||||||
[ACHIEVEMENTS.openWires]: "open_wires",
|
[ACHIEVEMENTS.openWires]: "open_wires",
|
||||||
[ACHIEVEMENTS.oldLevel17]: "old_level_17",
|
[ACHIEVEMENTS.oldLevel17]: "old_level_17",
|
||||||
[ACHIEVEMENTS.paintShape]: "paint_shape",
|
[ACHIEVEMENTS.paintShape]: "paint_shape",
|
||||||
[ACHIEVEMENTS.place5000Wires]: "place_5000_wires",
|
[ACHIEVEMENTS.place5000Wires]: "place_5000_wires",
|
||||||
[ACHIEVEMENTS.placeBlueprint]: "place_blueprint",
|
[ACHIEVEMENTS.placeBlueprint]: "place_blueprint",
|
||||||
|
[ACHIEVEMENTS.placeBp1000]: "place_bp_1000",
|
||||||
[ACHIEVEMENTS.play1h]: "play_1h",
|
[ACHIEVEMENTS.play1h]: "play_1h",
|
||||||
[ACHIEVEMENTS.play10h]: "play_10h",
|
[ACHIEVEMENTS.play10h]: "play_10h",
|
||||||
[ACHIEVEMENTS.play20h]: "play_20h",
|
[ACHIEVEMENTS.play20h]: "play_20h",
|
||||||
@ -36,6 +40,8 @@ const ACHIEVEMENT_IDS = {
|
|||||||
[ACHIEVEMENTS.store100Unique]: "store_100_unique",
|
[ACHIEVEMENTS.store100Unique]: "store_100_unique",
|
||||||
[ACHIEVEMENTS.storeShape]: "store_shape",
|
[ACHIEVEMENTS.storeShape]: "store_shape",
|
||||||
[ACHIEVEMENTS.unlockWires]: "unlock_wires",
|
[ACHIEVEMENTS.unlockWires]: "unlock_wires",
|
||||||
|
[ACHIEVEMENTS.upgradesTier5]: "upgrades_tier_5",
|
||||||
|
[ACHIEVEMENTS.upgradesTier8]: "upgrades_tier_8",
|
||||||
};
|
};
|
||||||
|
|
||||||
export class SteamAchievementProvider extends AchievementProviderInterface {
|
export class SteamAchievementProvider extends AchievementProviderInterface {
|
||||||
@ -44,9 +50,15 @@ export class SteamAchievementProvider extends AchievementProviderInterface {
|
|||||||
super(app);
|
super(app);
|
||||||
|
|
||||||
this.initialized = false;
|
this.initialized = false;
|
||||||
this.loaded = false;
|
this.saveId = null;
|
||||||
this.collection = new AchievementCollection(this.activate.bind(this));
|
this.collection = new AchievementCollection(this.activate.bind(this));
|
||||||
|
|
||||||
|
if (G_IS_DEV) {
|
||||||
|
for (let key in ACHIEVEMENT_IDS) {
|
||||||
|
assert(this.collection.map.has(key), "Key not found in collection: " + key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
logger.log("Collection created with", this.collection.map.size, "achievements");
|
logger.log("Collection created with", this.collection.map.size, "achievements");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -55,27 +67,26 @@ export class SteamAchievementProvider extends AchievementProviderInterface {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @returns {boolean} */
|
|
||||||
hasLoaded() {
|
|
||||||
return this.loaded;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {GameRoot} root
|
* @param {GameRoot} root
|
||||||
* @returns {Promise<void>}
|
* @returns {Promise<void>}
|
||||||
*/
|
*/
|
||||||
onLoad(root) {
|
onLoad(root) {
|
||||||
if (this.loaded) {
|
this.root = root;
|
||||||
return Promise.resolve();
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
this.collection.initialize(root);
|
if (!this.saveId || this.saveId === this.root.savegame.internalId) {
|
||||||
this.loaded = true;
|
this.collection.initialize(root);
|
||||||
logger.log(this.collection.map.size, "achievements are relevant and initialized");
|
} else {
|
||||||
|
this.collection = new AchievementCollection(this.activate.bind(this));
|
||||||
|
this.collection.initialize(root);
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.log("Initialized", this.collection.map.size, "relevant achievements");
|
||||||
|
this.saveId = this.root.savegame.internalId;
|
||||||
return Promise.resolve();
|
return Promise.resolve();
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
logger.error("Failed to initialize the achievement collection");
|
logger.error("Failed to initialize the collection");
|
||||||
return Promise.reject(err);
|
return Promise.reject(err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user