mirror of
https://github.com/tobspr/shapez.io.git
synced 2025-12-09 16:21:51 +00:00
Merge pull request #63 from tobspr-games/dengr1065/remove-achievements
Remove support for achievements
This commit is contained in:
commit
f9ad135fe3
@ -12,7 +12,6 @@ import { Vector } from "./core/vector";
|
||||
import { MOD_SIGNALS } from "./mods/mod_signals";
|
||||
import { MODS } from "./mods/modloader";
|
||||
import { ClientAPI } from "./platform/api";
|
||||
import { NoAchievementProvider } from "./platform/no_achievement_provider";
|
||||
import { Sound } from "./platform/sound";
|
||||
import { Storage } from "./platform/storage";
|
||||
import { PlatformWrapperImplElectron } from "./platform/wrapper";
|
||||
@ -30,7 +29,6 @@ import { PuzzleMenuState } from "./states/puzzle_menu";
|
||||
import { SettingsState } from "./states/settings";
|
||||
|
||||
/**
|
||||
* @typedef {import("./platform/achievement_provider").AchievementProviderInterface} AchievementProviderInterface
|
||||
* @typedef {import("./platform/sound").SoundInterface} SoundInterface
|
||||
*/
|
||||
|
||||
@ -74,7 +72,6 @@ export class Application {
|
||||
this.platformWrapper = new PlatformWrapperImplElectron(this);
|
||||
|
||||
this.sound = new Sound(this);
|
||||
this.achievementProvider = new NoAchievementProvider(this);
|
||||
|
||||
// Track if the window is focused (only relevant for browser)
|
||||
this.focused = true;
|
||||
|
||||
@ -59,9 +59,6 @@ export default {
|
||||
// Enables ads in the local build (normally they are deactivated there)
|
||||
// testAds: true,
|
||||
// -----------------------------------------------------------------------------------
|
||||
// Allows unlocked achievements to be logged to console in the local build
|
||||
// testAchievements: true,
|
||||
// -----------------------------------------------------------------------------------
|
||||
// Enables use of (some) existing flags within the puzzle mode context
|
||||
// testPuzzleMode: true,
|
||||
// -----------------------------------------------------------------------------------
|
||||
|
||||
@ -41,9 +41,6 @@ export const globalConfig = {
|
||||
assetsSharpness: 1.5,
|
||||
shapesSharpness: 1.3,
|
||||
|
||||
// Achievements
|
||||
achievementSliceDuration: 10, // Seconds
|
||||
|
||||
// Production analytics
|
||||
statisticsGraphDpi: 2.5,
|
||||
statisticsGraphSlices: 100,
|
||||
|
||||
@ -1,154 +0,0 @@
|
||||
/* typehints:start */
|
||||
import { Entity } from "./entity";
|
||||
import { GameRoot } from "./root";
|
||||
/* typehints:end */
|
||||
|
||||
import { globalConfig } from "../core/config";
|
||||
import { createLogger } from "../core/logging";
|
||||
import { ACHIEVEMENTS } from "../platform/achievement_provider";
|
||||
import { getBuildingDataFromCode } from "./building_codes";
|
||||
|
||||
const logger = createLogger("achievement_proxy");
|
||||
|
||||
const ROTATOR = "rotator";
|
||||
const DEFAULT = "default";
|
||||
|
||||
export class AchievementProxy {
|
||||
/** @param {GameRoot} root */
|
||||
constructor(root) {
|
||||
this.root = root;
|
||||
this.provider = this.root.app.achievementProvider;
|
||||
this.disabled = true;
|
||||
|
||||
if (G_IS_DEV && globalConfig.debug.testAchievements) {
|
||||
// still enable the proxy
|
||||
} else if (!this.provider.hasAchievements()) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.sliceTime = 0;
|
||||
|
||||
this.root.signals.postLoadHook.add(this.onLoad, this);
|
||||
}
|
||||
|
||||
onLoad() {
|
||||
if (!this.root.gameMode.hasAchievements()) {
|
||||
logger.log("Disabling achievements because game mode does not have achievements");
|
||||
this.disabled = true;
|
||||
return;
|
||||
}
|
||||
|
||||
this.provider
|
||||
.onLoad(this.root)
|
||||
.then(() => {
|
||||
this.disabled = false;
|
||||
logger.log("Recieving achievement signals");
|
||||
this.initialize();
|
||||
})
|
||||
.catch(err => {
|
||||
this.disabled = true;
|
||||
logger.error("Ignoring achievement signals", err);
|
||||
});
|
||||
}
|
||||
|
||||
initialize() {
|
||||
this.root.signals.achievementCheck.dispatch(ACHIEVEMENTS.darkMode, null);
|
||||
|
||||
if (this.has(ACHIEVEMENTS.mam)) {
|
||||
this.root.signals.entityAdded.add(this.onMamFailure, this);
|
||||
this.root.signals.entityDestroyed.add(this.onMamFailure, this);
|
||||
this.root.signals.storyGoalCompleted.add(this.onStoryGoalCompleted, this);
|
||||
}
|
||||
|
||||
if (this.has(ACHIEVEMENTS.noInverseRotator)) {
|
||||
this.root.signals.entityAdded.add(this.onEntityAdded, this);
|
||||
}
|
||||
|
||||
this.startSlice();
|
||||
}
|
||||
|
||||
startSlice() {
|
||||
this.sliceTime = this.root.time.now();
|
||||
|
||||
this.root.signals.bulkAchievementCheck.dispatch(
|
||||
ACHIEVEMENTS.storeShape,
|
||||
this.sliceTime,
|
||||
ACHIEVEMENTS.throughputBp25,
|
||||
this.sliceTime,
|
||||
ACHIEVEMENTS.throughputBp50,
|
||||
this.sliceTime,
|
||||
ACHIEVEMENTS.throughputLogo25,
|
||||
this.sliceTime,
|
||||
ACHIEVEMENTS.throughputLogo50,
|
||||
this.sliceTime,
|
||||
ACHIEVEMENTS.throughputRocket10,
|
||||
this.sliceTime,
|
||||
ACHIEVEMENTS.throughputRocket20,
|
||||
this.sliceTime,
|
||||
ACHIEVEMENTS.play1h,
|
||||
this.sliceTime,
|
||||
ACHIEVEMENTS.play10h,
|
||||
this.sliceTime,
|
||||
ACHIEVEMENTS.play20h,
|
||||
this.sliceTime
|
||||
);
|
||||
}
|
||||
|
||||
update() {
|
||||
if (this.disabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.root.time.now() - this.sliceTime > globalConfig.achievementSliceDuration) {
|
||||
this.startSlice();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} key
|
||||
* @returns {boolean}
|
||||
*/
|
||||
has(key) {
|
||||
if (!this.provider.collection) {
|
||||
return false;
|
||||
}
|
||||
return this.provider.collection.map.has(key);
|
||||
}
|
||||
|
||||
/** @param {Entity} entity */
|
||||
onEntityAdded(entity) {
|
||||
if (!entity.components.StaticMapEntity) {
|
||||
return;
|
||||
}
|
||||
|
||||
const building = getBuildingDataFromCode(entity.components.StaticMapEntity.code);
|
||||
|
||||
if (building.metaInstance.id !== ROTATOR) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (building.variant === DEFAULT) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.root.savegame.currentData.stats.usedInverseRotator = true;
|
||||
this.root.signals.entityAdded.remove(this.onEntityAdded);
|
||||
}
|
||||
|
||||
/** @param {number} level */
|
||||
onStoryGoalCompleted(level) {
|
||||
if (level > 26) {
|
||||
this.root.signals.entityAdded.add(this.onMamFailure, this);
|
||||
this.root.signals.entityDestroyed.add(this.onMamFailure, this);
|
||||
}
|
||||
|
||||
this.root.signals.achievementCheck.dispatch(ACHIEVEMENTS.mam, null);
|
||||
|
||||
// reset on every level
|
||||
this.root.savegame.currentData.stats.failedMam = false;
|
||||
}
|
||||
|
||||
onMamFailure() {
|
||||
this.root.savegame.currentData.stats.failedMam = true;
|
||||
}
|
||||
}
|
||||
@ -3,7 +3,6 @@ import { DrawParameters } from "../core/draw_parameters";
|
||||
import { findNiceIntegerValue } from "../core/utils";
|
||||
import { Vector } from "../core/vector";
|
||||
import { Entity } from "./entity";
|
||||
import { ACHIEVEMENTS } from "../platform/achievement_provider";
|
||||
import { GameRoot } from "./root";
|
||||
|
||||
export class Blueprint {
|
||||
@ -178,13 +177,6 @@ export class Blueprint {
|
||||
count++;
|
||||
}
|
||||
|
||||
root.signals.bulkAchievementCheck.dispatch(
|
||||
ACHIEVEMENTS.placeBlueprint,
|
||||
count,
|
||||
ACHIEVEMENTS.placeBp1000,
|
||||
count
|
||||
);
|
||||
|
||||
return count !== 0;
|
||||
});
|
||||
});
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
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";
|
||||
@ -47,25 +46,6 @@ 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
|
||||
@ -100,7 +80,5 @@ export class MetaTrashBuilding extends MetaBuilding {
|
||||
processorType: enumItemProcessorTypes.trash,
|
||||
})
|
||||
);
|
||||
|
||||
this.addAchievementReceiver(entity);
|
||||
}
|
||||
}
|
||||
|
||||
@ -20,7 +20,6 @@ import { Vector } from "../core/vector";
|
||||
import { MOD_SIGNALS } from "../mods/mod_signals";
|
||||
import { Savegame } from "../savegame/savegame";
|
||||
import { SavegameSerializer } from "../savegame/savegame_serializer";
|
||||
import { AchievementProxy } from "./achievement_proxy";
|
||||
import { AutomaticSave } from "./automatic_save";
|
||||
import { MetaHubBuilding } from "./buildings/hub";
|
||||
import { Camera } from "./camera";
|
||||
@ -115,7 +114,6 @@ export class GameCore {
|
||||
root.logic = new GameLogic(root);
|
||||
root.hud = new GameHUD(root);
|
||||
root.time = new GameTime(root);
|
||||
root.achievementProxy = new AchievementProxy(root);
|
||||
root.automaticSave = new AutomaticSave(root);
|
||||
root.soundProxy = new SoundProxy(root);
|
||||
|
||||
@ -154,9 +152,6 @@ export class GameCore {
|
||||
|
||||
// Update analytics
|
||||
root.productionAnalytics.update();
|
||||
|
||||
// Check achievements
|
||||
root.achievementProxy.update();
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -290,9 +285,6 @@ export class GameCore {
|
||||
|
||||
// Update analytics
|
||||
root.productionAnalytics.update();
|
||||
|
||||
// Check achievements
|
||||
root.achievementProxy.update();
|
||||
}
|
||||
|
||||
// Update automatic save after everything finished
|
||||
|
||||
@ -2,12 +2,12 @@
|
||||
import { GameRoot } from "./root";
|
||||
/* typehints:end */
|
||||
|
||||
import { Rectangle } from "../core/rectangle";
|
||||
import { gGameModeRegistry } from "../core/global_registries";
|
||||
import { types, BasicSerializableObject } from "../savegame/serialization";
|
||||
import { MetaBuilding } from "./meta_building";
|
||||
import { Rectangle } from "../core/rectangle";
|
||||
import { BasicSerializableObject } from "../savegame/serialization";
|
||||
import { MetaItemProducerBuilding } from "./buildings/item_producer";
|
||||
import { BaseHUDPart } from "./hud/base_hud_part";
|
||||
import { MetaBuilding } from "./meta_building";
|
||||
|
||||
/** @enum {string} */
|
||||
export const enumGameModeIds = {
|
||||
@ -112,11 +112,6 @@ export class GameMode extends BasicSerializableObject {
|
||||
return true;
|
||||
}
|
||||
|
||||
/** @returns {boolean} */
|
||||
hasAchievements() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/** @returns {number} */
|
||||
getMinimumZoom() {
|
||||
return 0.06;
|
||||
|
||||
@ -4,7 +4,6 @@ import { createLogger } from "../../../core/logging";
|
||||
import { STOP_PROPAGATION } from "../../../core/signal";
|
||||
import { formatBigNumberFull } from "../../../core/utils";
|
||||
import { Vector } from "../../../core/vector";
|
||||
import { ACHIEVEMENTS } from "../../../platform/achievement_provider";
|
||||
import { T } from "../../../translations";
|
||||
import { Blueprint } from "../../blueprint";
|
||||
import { enumMouseButton } from "../../camera";
|
||||
@ -16,7 +15,6 @@ import { BaseHUDPart } from "../base_hud_part";
|
||||
|
||||
/* typehints:start */
|
||||
// @ts-ignore
|
||||
import { Component } from "../../component";
|
||||
/* typehints:end */
|
||||
|
||||
const logger = createLogger("hud/mass_selector");
|
||||
@ -121,8 +119,6 @@ export class HUDMassSelector extends BaseHUDPart {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
this.root.signals.achievementCheck.dispatch(ACHIEVEMENTS.destroy1000, count);
|
||||
});
|
||||
|
||||
// Clear uids later
|
||||
|
||||
@ -15,7 +15,6 @@ import {
|
||||
removeAllChildren,
|
||||
} from "../../../core/utils";
|
||||
import { Vector } from "../../../core/vector";
|
||||
import { ACHIEVEMENTS } from "../../../platform/achievement_provider";
|
||||
import { T } from "../../../translations";
|
||||
import { BaseItem } from "../../base_item";
|
||||
import { MetaHubBuilding } from "../../buildings/hub";
|
||||
@ -337,10 +336,6 @@ export class HUDWaypoints extends BaseHUDPart {
|
||||
T.ingame.waypoints.creationSuccessNotification,
|
||||
enumNotificationType.success
|
||||
);
|
||||
this.root.signals.achievementCheck.dispatch(
|
||||
ACHIEVEMENTS.mapMarkers15,
|
||||
this.waypoints.length - 1 // Disregard HUB
|
||||
);
|
||||
|
||||
// Re-render the list and thus add it
|
||||
this.rerenderWaypointList();
|
||||
|
||||
@ -1,39 +1,39 @@
|
||||
/* typehints:start */
|
||||
import { GameRoot } from "../root";
|
||||
import { MetaBuilding } from "../meta_building";
|
||||
import { GameRoot } from "../root";
|
||||
/* typehints:end */
|
||||
|
||||
import { IS_MOBILE } from "../../core/config";
|
||||
import { findNiceIntegerValue } from "../../core/utils";
|
||||
import { MOD_SIGNALS } from "../../mods/mod_signals";
|
||||
import { MetaBlockBuilding } from "../buildings/block";
|
||||
import { MetaConstantProducerBuilding } from "../buildings/constant_producer";
|
||||
import { MetaGoalAcceptorBuilding } from "../buildings/goal_acceptor";
|
||||
import { MetaItemProducerBuilding } from "../buildings/item_producer";
|
||||
import { enumGameModeIds, enumGameModeTypes, GameMode } from "../game_mode";
|
||||
import { HUDConstantSignalEdit } from "../hud/parts/constant_signal_edit";
|
||||
import { HUDGameMenu } from "../hud/parts/game_menu";
|
||||
import { HUDInteractiveTutorial } from "../hud/parts/interactive_tutorial";
|
||||
import { HUDKeybindingOverlay } from "../hud/parts/keybinding_overlay";
|
||||
import { HUDLayerPreview } from "../hud/parts/layer_preview";
|
||||
import { HUDLeverToggle } from "../hud/parts/lever_toggle";
|
||||
import { HUDMassSelector } from "../hud/parts/mass_selector";
|
||||
import { HUDMinerHighlight } from "../hud/parts/miner_highlight";
|
||||
import { HUDNotifications } from "../hud/parts/notifications";
|
||||
import { HUDPinnedShapes } from "../hud/parts/pinned_shapes";
|
||||
import { HUDScreenshotExporter } from "../hud/parts/screenshot_exporter";
|
||||
import { HUDShapeViewer } from "../hud/parts/shape_viewer";
|
||||
import { HUDShop } from "../hud/parts/shop";
|
||||
import { HUDStatistics } from "../hud/parts/statistics";
|
||||
import { HUDPartTutorialHints } from "../hud/parts/tutorial_hints";
|
||||
import { HUDTutorialVideoOffer } from "../hud/parts/tutorial_video_offer";
|
||||
import { HUDUnlockNotification } from "../hud/parts/unlock_notification";
|
||||
import { HUDWaypoints } from "../hud/parts/waypoints";
|
||||
import { HUDWireInfo } from "../hud/parts/wire_info";
|
||||
import { HUDWiresOverlay } from "../hud/parts/wires_overlay";
|
||||
import { HUDWiresToolbar } from "../hud/parts/wires_toolbar";
|
||||
import { ShapeDefinition } from "../shape_definition";
|
||||
import { enumHubGoalRewards } from "../tutorial_goals";
|
||||
import { HUDWiresToolbar } from "../hud/parts/wires_toolbar";
|
||||
import { HUDUnlockNotification } from "../hud/parts/unlock_notification";
|
||||
import { HUDMassSelector } from "../hud/parts/mass_selector";
|
||||
import { HUDShop } from "../hud/parts/shop";
|
||||
import { HUDWaypoints } from "../hud/parts/waypoints";
|
||||
import { HUDStatistics } from "../hud/parts/statistics";
|
||||
import { HUDWireInfo } from "../hud/parts/wire_info";
|
||||
import { HUDLeverToggle } from "../hud/parts/lever_toggle";
|
||||
import { HUDPinnedShapes } from "../hud/parts/pinned_shapes";
|
||||
import { HUDNotifications } from "../hud/parts/notifications";
|
||||
import { HUDScreenshotExporter } from "../hud/parts/screenshot_exporter";
|
||||
import { HUDWiresOverlay } from "../hud/parts/wires_overlay";
|
||||
import { HUDShapeViewer } from "../hud/parts/shape_viewer";
|
||||
import { HUDLayerPreview } from "../hud/parts/layer_preview";
|
||||
import { HUDTutorialVideoOffer } from "../hud/parts/tutorial_video_offer";
|
||||
import { HUDMinerHighlight } from "../hud/parts/miner_highlight";
|
||||
import { HUDGameMenu } from "../hud/parts/game_menu";
|
||||
import { HUDConstantSignalEdit } from "../hud/parts/constant_signal_edit";
|
||||
import { IS_MOBILE } from "../../core/config";
|
||||
import { HUDKeybindingOverlay } from "../hud/parts/keybinding_overlay";
|
||||
import { HUDPartTutorialHints } from "../hud/parts/tutorial_hints";
|
||||
import { HUDInteractiveTutorial } from "../hud/parts/interactive_tutorial";
|
||||
import { MetaBlockBuilding } from "../buildings/block";
|
||||
import { MetaItemProducerBuilding } from "../buildings/item_producer";
|
||||
import { MOD_SIGNALS } from "../../mods/mod_signals";
|
||||
import { finalGameShape, REGULAR_MODE_LEVELS } from "./levels";
|
||||
|
||||
/** @typedef {{
|
||||
@ -390,9 +390,4 @@ export class RegularGameMode extends GameMode {
|
||||
getIsFreeplayAvailable() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/** @returns {boolean} */
|
||||
hasAchievements() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,33 +1,32 @@
|
||||
import { Signal } from "../core/signal";
|
||||
import { RandomNumberGenerator } from "../core/rng";
|
||||
import { createLogger } from "../core/logging";
|
||||
import { RandomNumberGenerator } from "../core/rng";
|
||||
import { Signal } from "../core/signal";
|
||||
|
||||
// Type hints
|
||||
/* typehints:start */
|
||||
import { GameTime } from "./time/game_time";
|
||||
import { EntityManager } from "./entity_manager";
|
||||
import { GameSystemManager } from "./game_system_manager";
|
||||
import { AchievementProxy } from "./achievement_proxy";
|
||||
import { GameHUD } from "./hud/hud";
|
||||
import { MapView } from "./map_view";
|
||||
import { Camera } from "./camera";
|
||||
import { Application } from "../application";
|
||||
import { BufferMaintainer } from "../core/buffer_maintainer";
|
||||
import { Vector } from "../core/vector";
|
||||
import { Savegame } from "../savegame/savegame";
|
||||
import { InGameState } from "../states/ingame";
|
||||
import { AutomaticSave } from "./automatic_save";
|
||||
import { Application } from "../application";
|
||||
import { SoundProxy } from "./sound_proxy";
|
||||
import { Savegame } from "../savegame/savegame";
|
||||
import { GameLogic } from "./logic";
|
||||
import { ShapeDefinitionManager } from "./shape_definition_manager";
|
||||
import { HubGoals } from "./hub_goals";
|
||||
import { BufferMaintainer } from "../core/buffer_maintainer";
|
||||
import { ProductionAnalytics } from "./production_analytics";
|
||||
import { Entity } from "./entity";
|
||||
import { ShapeDefinition } from "./shape_definition";
|
||||
import { BaseItem } from "./base_item";
|
||||
import { Camera } from "./camera";
|
||||
import { DynamicTickrate } from "./dynamic_tickrate";
|
||||
import { KeyActionMapper } from "./key_action_mapper";
|
||||
import { Vector } from "../core/vector";
|
||||
import { Entity } from "./entity";
|
||||
import { EntityManager } from "./entity_manager";
|
||||
import { GameMode } from "./game_mode";
|
||||
import { GameSystemManager } from "./game_system_manager";
|
||||
import { HubGoals } from "./hub_goals";
|
||||
import { GameHUD } from "./hud/hud";
|
||||
import { KeyActionMapper } from "./key_action_mapper";
|
||||
import { GameLogic } from "./logic";
|
||||
import { MapView } from "./map_view";
|
||||
import { ProductionAnalytics } from "./production_analytics";
|
||||
import { ShapeDefinition } from "./shape_definition";
|
||||
import { ShapeDefinitionManager } from "./shape_definition_manager";
|
||||
import { SoundProxy } from "./sound_proxy";
|
||||
import { GameTime } from "./time/game_time";
|
||||
/* typehints:end */
|
||||
|
||||
const logger = createLogger("game/root");
|
||||
@ -124,9 +123,6 @@ export class GameRoot {
|
||||
/** @type {SoundProxy} */
|
||||
this.soundProxy = null;
|
||||
|
||||
/** @type {AchievementProxy} */
|
||||
this.achievementProxy = null;
|
||||
|
||||
/** @type {ShapeDefinitionManager} */
|
||||
this.shapeDefinitionMgr = null;
|
||||
|
||||
@ -185,10 +181,6 @@ export class GameRoot {
|
||||
// for freeing space before actually placing.
|
||||
freeEntityAreaBeforeBuild: /** @type {Signal<[Entity]>} */ (new Signal()),
|
||||
|
||||
// Called with an achievement key and necessary args to validate it can be unlocked.
|
||||
achievementCheck: /** @type {Signal<[string, any]>} */ (new Signal()),
|
||||
bulkAchievementCheck: /** @type {Signal<(string|any)[]>} */ (new Signal()),
|
||||
|
||||
// Puzzle mode
|
||||
puzzleComplete: /** @type {Signal<[]>} */ (new Signal()),
|
||||
};
|
||||
|
||||
@ -4,7 +4,6 @@ import { enumColors } from "./colors";
|
||||
import { ShapeItem } from "./items/shape_item";
|
||||
import { GameRoot } from "./root";
|
||||
import { enumSubShape, ShapeDefinition } from "./shape_definition";
|
||||
import { ACHIEVEMENTS } from "../platform/achievement_provider";
|
||||
|
||||
const logger = createLogger("shape_definition_manager");
|
||||
|
||||
@ -97,8 +96,6 @@ export class ShapeDefinitionManager extends BasicSerializableObject {
|
||||
const rightSide = definition.cloneFilteredByQuadrants([2, 3]);
|
||||
const leftSide = definition.cloneFilteredByQuadrants([0, 1]);
|
||||
|
||||
this.root.signals.achievementCheck.dispatch(ACHIEVEMENTS.cutShape, null);
|
||||
|
||||
return /** @type {[ShapeDefinition, ShapeDefinition]} */ (
|
||||
this.operationCache[key] = [
|
||||
this.registerOrReturnHandle(rightSide),
|
||||
@ -143,8 +140,6 @@ export class ShapeDefinitionManager extends BasicSerializableObject {
|
||||
|
||||
const rotated = definition.cloneRotateCW();
|
||||
|
||||
this.root.signals.achievementCheck.dispatch(ACHIEVEMENTS.rotateShape, null);
|
||||
|
||||
return /** @type {ShapeDefinition} */ (
|
||||
this.operationCache[key] = this.registerOrReturnHandle(rotated)
|
||||
);
|
||||
@ -198,8 +193,6 @@ export class ShapeDefinitionManager extends BasicSerializableObject {
|
||||
return /** @type {ShapeDefinition} */ (this.operationCache[key]);
|
||||
}
|
||||
|
||||
this.root.signals.achievementCheck.dispatch(ACHIEVEMENTS.stackShape, null);
|
||||
|
||||
const stacked = lowerDefinition.cloneAndStackWith(upperDefinition);
|
||||
return /** @type {ShapeDefinition} */ (
|
||||
this.operationCache[key] = this.registerOrReturnHandle(stacked)
|
||||
@ -218,8 +211,6 @@ export class ShapeDefinitionManager extends BasicSerializableObject {
|
||||
return /** @type {ShapeDefinition} */ (this.operationCache[key]);
|
||||
}
|
||||
|
||||
this.root.signals.achievementCheck.dispatch(ACHIEVEMENTS.paintShape, null);
|
||||
|
||||
const colorized = definition.cloneAndPaintWith(color);
|
||||
return /** @type {ShapeDefinition} */ (
|
||||
this.operationCache[key] = this.registerOrReturnHandle(colorized)
|
||||
|
||||
@ -13,16 +13,14 @@ import {
|
||||
enumInvertedDirections,
|
||||
Vector,
|
||||
} from "../../core/vector";
|
||||
import { ACHIEVEMENTS } from "../../platform/achievement_provider";
|
||||
import { BaseItem } from "../base_item";
|
||||
import { arrayWireRotationVariantToType, MetaWireBuilding } from "../buildings/wire";
|
||||
import { getCodeFromBuildingData } from "../building_codes";
|
||||
import { arrayWireRotationVariantToType, MetaWireBuilding } from "../buildings/wire";
|
||||
import { enumWireType, enumWireVariant, WireComponent } from "../components/wire";
|
||||
import { enumPinSlotType, WiredPinsComponent } from "../components/wired_pins";
|
||||
import { WireTunnelComponent } from "../components/wire_tunnel";
|
||||
import { enumPinSlotType, WiredPinsComponent } from "../components/wired_pins";
|
||||
import { Entity } from "../entity";
|
||||
import { GameSystem } from "../game_system";
|
||||
import { GameSystemWithFilter } from "../game_system_with_filter";
|
||||
import { isTruthyItem } from "../items/boolean_item";
|
||||
import { MapChunkView } from "../map_chunk_view";
|
||||
|
||||
@ -699,8 +697,6 @@ export class WireSystem extends GameSystem {
|
||||
return;
|
||||
}
|
||||
|
||||
this.root.signals.achievementCheck.dispatch(ACHIEVEMENTS.place5000Wires, entity);
|
||||
|
||||
// Invalidate affected area
|
||||
const originalRect = staticComp.getTileSpaceBounds();
|
||||
const affectedArea = originalRect.expandedInAllDirections(1);
|
||||
|
||||
@ -1,647 +0,0 @@
|
||||
/* typehints:start */
|
||||
import { Application } from "../application";
|
||||
import { Entity } from "../game/entity";
|
||||
import { GameRoot } from "../game/root";
|
||||
import { THEMES } from "../game/theme";
|
||||
/* typehints:end */
|
||||
|
||||
import { globalConfig } from "../core/config";
|
||||
import { ShapeItem } from "../game/items/shape_item";
|
||||
import { enumAnalyticsDataSource } from "../game/production_analytics";
|
||||
import { ShapeDefinition } from "../game/shape_definition";
|
||||
|
||||
export const ACHIEVEMENTS = {
|
||||
belt500Tiles: "belt500Tiles",
|
||||
blueprint100k: "blueprint100k",
|
||||
blueprint1m: "blueprint1m",
|
||||
completeLvl26: "completeLvl26",
|
||||
cutShape: "cutShape",
|
||||
darkMode: "darkMode",
|
||||
destroy1000: "destroy1000",
|
||||
irrelevantShape: "irrelevantShape",
|
||||
level100: "level100",
|
||||
level50: "level50",
|
||||
logoBefore18: "logoBefore18",
|
||||
mam: "mam",
|
||||
mapMarkers15: "mapMarkers15",
|
||||
noBeltUpgradesUntilBp: "noBeltUpgradesUntilBp",
|
||||
noInverseRotator: "noInverseRotator",
|
||||
oldLevel17: "oldLevel17",
|
||||
openWires: "openWires",
|
||||
paintShape: "paintShape",
|
||||
place5000Wires: "place5000Wires",
|
||||
placeBlueprint: "placeBlueprint",
|
||||
placeBp1000: "placeBp1000",
|
||||
play1h: "play1h",
|
||||
play10h: "play10h",
|
||||
play20h: "play20h",
|
||||
produceLogo: "produceLogo",
|
||||
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",
|
||||
};
|
||||
|
||||
/** @type {keyof typeof THEMES} */
|
||||
const DARK_MODE = "dark";
|
||||
|
||||
const HOUR_1 = 3600; // Seconds
|
||||
const HOUR_10 = HOUR_1 * 10;
|
||||
const HOUR_20 = HOUR_1 * 20;
|
||||
const ITEM_SHAPE = ShapeItem.getId();
|
||||
const MINUTE_30 = 1800; // Seconds
|
||||
const MINUTE_60 = MINUTE_30 * 2;
|
||||
const MINUTE_120 = MINUTE_30 * 4;
|
||||
const ROTATOR_CCW_CODE = 12;
|
||||
const ROTATOR_180_CODE = 13;
|
||||
const SHAPE_BP = "CbCbCbRb:CwCwCwCw";
|
||||
const SHAPE_LOGO = "RuCw--Cw:----Ru--";
|
||||
const SHAPE_MS_LOGO = "RgRyRbRr";
|
||||
const SHAPE_OLD_LEVEL_17 = "WrRgWrRg:CwCrCwCr:SgSgSgSg";
|
||||
const SHAPE_ROCKET = "CbCuCbCu:Sr------:--CrSrCr:CwCwCwCw";
|
||||
|
||||
/** @type {Layer} */
|
||||
const WIRE_LAYER = "wires";
|
||||
|
||||
export class AchievementProviderInterface {
|
||||
/* typehints:start */
|
||||
collection = /** @type {AchievementCollection|undefined} */ (null);
|
||||
/* typehints:end */
|
||||
|
||||
/** @param {Application} app */
|
||||
constructor(app) {
|
||||
this.app = app;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the achievement provider.
|
||||
* @returns {Promise<void>}
|
||||
* @abstract
|
||||
*/
|
||||
initialize() {
|
||||
abstract;
|
||||
return Promise.reject();
|
||||
}
|
||||
|
||||
/**
|
||||
* Opportunity to do additional initialization work with the GameRoot.
|
||||
* @param {GameRoot} root
|
||||
* @returns {Promise<void>}
|
||||
* @abstract
|
||||
*/
|
||||
onLoad(root) {
|
||||
abstract;
|
||||
return Promise.reject();
|
||||
}
|
||||
|
||||
/** @returns {boolean} */
|
||||
hasLoaded() {
|
||||
abstract;
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Call to activate an achievement with the provider
|
||||
* @param {string} key - Maps to an Achievement
|
||||
* @returns {Promise<void>}
|
||||
* @abstract
|
||||
*/
|
||||
activate(key) {
|
||||
abstract;
|
||||
return Promise.reject();
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if achievements are supported in the current build
|
||||
* @returns {boolean}
|
||||
* @abstract
|
||||
*/
|
||||
hasAchievements() {
|
||||
abstract;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
export class Achievement {
|
||||
/** @param {string} key - An ACHIEVEMENTS key */
|
||||
constructor(key) {
|
||||
this.key = key;
|
||||
this.activate = null;
|
||||
this.activatePromise = null;
|
||||
this.receiver = null;
|
||||
this.signal = null;
|
||||
}
|
||||
|
||||
init() {}
|
||||
|
||||
isValid() {
|
||||
return true;
|
||||
}
|
||||
|
||||
unlock() {
|
||||
if (!this.activatePromise) {
|
||||
this.activatePromise = this.activate(this.key);
|
||||
}
|
||||
|
||||
return this.activatePromise;
|
||||
}
|
||||
}
|
||||
|
||||
export class AchievementCollection {
|
||||
/**
|
||||
* @param {function} activate - Resolves when provider activation is complete
|
||||
*/
|
||||
constructor(activate) {
|
||||
this.map = new Map();
|
||||
this.activate = activate;
|
||||
|
||||
this.add(ACHIEVEMENTS.belt500Tiles, {
|
||||
isValid: this.isBelt500TilesValid,
|
||||
signal: "entityAdded",
|
||||
});
|
||||
this.add(ACHIEVEMENTS.blueprint100k, this.createBlueprintOptions(100000));
|
||||
this.add(ACHIEVEMENTS.blueprint1m, this.createBlueprintOptions(1000000));
|
||||
this.add(ACHIEVEMENTS.completeLvl26, this.createLevelOptions(26));
|
||||
this.add(ACHIEVEMENTS.cutShape);
|
||||
this.add(ACHIEVEMENTS.darkMode, {
|
||||
isValid: this.isDarkModeValid,
|
||||
});
|
||||
this.add(ACHIEVEMENTS.destroy1000, {
|
||||
isValid: this.isDestroy1000Valid,
|
||||
});
|
||||
this.add(ACHIEVEMENTS.irrelevantShape, {
|
||||
isValid: this.isIrrelevantShapeValid,
|
||||
signal: "shapeDelivered",
|
||||
});
|
||||
this.add(ACHIEVEMENTS.level100, this.createLevelOptions(100));
|
||||
this.add(ACHIEVEMENTS.level50, this.createLevelOptions(50));
|
||||
this.add(ACHIEVEMENTS.logoBefore18, {
|
||||
isValid: this.isLogoBefore18Valid,
|
||||
signal: "itemProduced",
|
||||
});
|
||||
this.add(ACHIEVEMENTS.mam, {
|
||||
isValid: this.isMamValid,
|
||||
});
|
||||
this.add(ACHIEVEMENTS.mapMarkers15, {
|
||||
isValid: this.isMapMarkers15Valid,
|
||||
});
|
||||
this.add(ACHIEVEMENTS.noBeltUpgradesUntilBp, {
|
||||
isValid: this.isNoBeltUpgradesUntilBpValid,
|
||||
signal: "storyGoalCompleted",
|
||||
});
|
||||
this.add(ACHIEVEMENTS.noInverseRotator, {
|
||||
init: this.initNoInverseRotator,
|
||||
isValid: this.isNoInverseRotatorValid,
|
||||
signal: "storyGoalCompleted",
|
||||
});
|
||||
this.add(ACHIEVEMENTS.oldLevel17, this.createShapeOptions(SHAPE_OLD_LEVEL_17));
|
||||
this.add(ACHIEVEMENTS.openWires, {
|
||||
isValid: this.isOpenWiresValid,
|
||||
signal: "editModeChanged",
|
||||
});
|
||||
this.add(ACHIEVEMENTS.paintShape);
|
||||
this.add(ACHIEVEMENTS.place5000Wires, {
|
||||
isValid: this.isPlace5000WiresValid,
|
||||
});
|
||||
this.add(ACHIEVEMENTS.placeBlueprint, {
|
||||
isValid: this.isPlaceBlueprintValid,
|
||||
});
|
||||
this.add(ACHIEVEMENTS.placeBp1000, {
|
||||
isValid: this.isPlaceBp1000Valid,
|
||||
});
|
||||
this.add(ACHIEVEMENTS.play1h, this.createTimeOptions(HOUR_1));
|
||||
this.add(ACHIEVEMENTS.play10h, this.createTimeOptions(HOUR_10));
|
||||
this.add(ACHIEVEMENTS.play20h, this.createTimeOptions(HOUR_20));
|
||||
this.add(ACHIEVEMENTS.produceLogo, this.createShapeOptions(SHAPE_LOGO));
|
||||
this.add(ACHIEVEMENTS.produceRocket, this.createShapeOptions(SHAPE_ROCKET));
|
||||
this.add(ACHIEVEMENTS.produceMsLogo, this.createShapeOptions(SHAPE_MS_LOGO));
|
||||
this.add(ACHIEVEMENTS.rotateShape);
|
||||
this.add(ACHIEVEMENTS.speedrunBp30, this.createSpeedOptions(12, MINUTE_30));
|
||||
this.add(ACHIEVEMENTS.speedrunBp60, this.createSpeedOptions(12, MINUTE_60));
|
||||
this.add(ACHIEVEMENTS.speedrunBp120, this.createSpeedOptions(12, MINUTE_120));
|
||||
this.add(ACHIEVEMENTS.stack4Layers, {
|
||||
isValid: this.isStack4LayersValid,
|
||||
signal: "itemProduced",
|
||||
});
|
||||
this.add(ACHIEVEMENTS.stackShape);
|
||||
this.add(ACHIEVEMENTS.store100Unique, {
|
||||
init: this.initStore100Unique,
|
||||
isValid: this.isStore100UniqueValid,
|
||||
signal: "shapeDelivered",
|
||||
});
|
||||
this.add(ACHIEVEMENTS.storeShape, {
|
||||
init: this.initStoreShape,
|
||||
isValid: this.isStoreShapeValid,
|
||||
});
|
||||
this.add(ACHIEVEMENTS.throughputBp25, this.createRateOptions(SHAPE_BP, 25));
|
||||
this.add(ACHIEVEMENTS.throughputBp50, this.createRateOptions(SHAPE_BP, 50));
|
||||
this.add(ACHIEVEMENTS.throughputLogo25, this.createRateOptions(SHAPE_LOGO, 25));
|
||||
this.add(ACHIEVEMENTS.throughputLogo50, this.createRateOptions(SHAPE_LOGO, 50));
|
||||
this.add(ACHIEVEMENTS.throughputRocket10, this.createRateOptions(SHAPE_ROCKET, 10));
|
||||
this.add(ACHIEVEMENTS.throughputRocket20, this.createRateOptions(SHAPE_ROCKET, 20));
|
||||
this.add(ACHIEVEMENTS.trash1000, {
|
||||
init: this.initTrash1000,
|
||||
isValid: this.isTrash1000Valid,
|
||||
});
|
||||
this.add(ACHIEVEMENTS.unlockWires, this.createLevelOptions(20));
|
||||
this.add(ACHIEVEMENTS.upgradesTier5, this.createUpgradeOptions(5));
|
||||
this.add(ACHIEVEMENTS.upgradesTier8, this.createUpgradeOptions(8));
|
||||
}
|
||||
|
||||
/** @param {GameRoot} root */
|
||||
initialize(root) {
|
||||
this.root = root;
|
||||
this.root.signals.achievementCheck.add(this.unlock, this);
|
||||
this.root.signals.bulkAchievementCheck.add(this.bulkUnlock, this);
|
||||
|
||||
for (let [key, achievement] of this.map.entries()) {
|
||||
if (achievement.signal) {
|
||||
achievement.receiver = this.unlock.bind(this, key);
|
||||
this.root.signals[achievement.signal].add(achievement.receiver);
|
||||
}
|
||||
|
||||
if (achievement.init) {
|
||||
achievement.init();
|
||||
}
|
||||
}
|
||||
|
||||
if (!this.hasDefaultReceivers()) {
|
||||
this.root.signals.achievementCheck.remove(this.unlock);
|
||||
this.root.signals.bulkAchievementCheck.remove(this.bulkUnlock);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} key - Maps to an Achievement
|
||||
* @param {object} [options]
|
||||
* @param {function} [options.init]
|
||||
* @param {function} [options.isValid]
|
||||
* @param {string} [options.signal]
|
||||
*/
|
||||
add(key, options = {}) {
|
||||
if (G_IS_DEV) {
|
||||
assert(ACHIEVEMENTS[key], "Achievement key not found: ", key);
|
||||
}
|
||||
|
||||
const achievement = new Achievement(key);
|
||||
|
||||
achievement.activate = this.activate;
|
||||
|
||||
if (options.init) {
|
||||
achievement.init = options.init.bind(this, achievement);
|
||||
}
|
||||
|
||||
if (options.isValid) {
|
||||
achievement.isValid = options.isValid.bind(this);
|
||||
}
|
||||
|
||||
if (options.signal) {
|
||||
achievement.signal = options.signal;
|
||||
}
|
||||
|
||||
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 {any} data - Data received from signal dispatches for validation
|
||||
*/
|
||||
unlock(key, data) {
|
||||
if (!this.map.has(key)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const achievement = this.map.get(key);
|
||||
|
||||
if (!achievement.isValid(data)) {
|
||||
return;
|
||||
}
|
||||
|
||||
achievement
|
||||
.unlock()
|
||||
.then(() => {
|
||||
this.onActivate(null, key);
|
||||
})
|
||||
.catch(err => {
|
||||
this.onActivate(err, key);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Cleans up after achievement activation attempt with the provider. Could
|
||||
* utilize err to retry some number of times if needed.
|
||||
* @param {?Error} err - Error is null if activation was successful
|
||||
* @param {string} key - Maps to an Achievement
|
||||
*/
|
||||
onActivate(err, key) {
|
||||
this.remove(key);
|
||||
|
||||
if (!this.hasDefaultReceivers()) {
|
||||
this.root.signals.achievementCheck.remove(this.unlock);
|
||||
}
|
||||
}
|
||||
|
||||
/** @param {string} key - Maps to an Achievement */
|
||||
remove(key) {
|
||||
const achievement = this.map.get(key);
|
||||
if (achievement) {
|
||||
if (achievement.receiver) {
|
||||
this.root.signals[achievement.signal].remove(achievement.receiver);
|
||||
}
|
||||
|
||||
this.map.delete(key);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the collection-level achievementCheck receivers are still
|
||||
* necessary.
|
||||
*/
|
||||
hasDefaultReceivers() {
|
||||
if (!this.map.size) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (let achievement of this.map.values()) {
|
||||
if (!achievement.signal) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Remaining methods exist to extend Achievement instances within the
|
||||
* collection.
|
||||
*/
|
||||
|
||||
hasAllUpgradesAtLeastAtTier(tier) {
|
||||
const upgrades = this.root.gameMode.getUpgrades();
|
||||
|
||||
for (let upgradeId in upgrades) {
|
||||
if (this.root.hubGoals.getUpgradeLevel(upgradeId) < tier - 1) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {ShapeItem} item
|
||||
* @param {string} shape
|
||||
* @returns {boolean}
|
||||
*/
|
||||
isShape(item, shape) {
|
||||
return item.getItemType() === ITEM_SHAPE && item.definition.getHash() === shape;
|
||||
}
|
||||
|
||||
createBlueprintOptions(count) {
|
||||
return {
|
||||
init: ({ key }) => this.unlock(key, ShapeDefinition.fromShortKey(SHAPE_BP)),
|
||||
isValid: definition =>
|
||||
definition.cachedHash === SHAPE_BP &&
|
||||
this.root.hubGoals.getShapesStoredByKey(SHAPE_BP) >= count,
|
||||
signal: "shapeDelivered",
|
||||
};
|
||||
}
|
||||
|
||||
createLevelOptions(level) {
|
||||
return {
|
||||
init: ({ key }) => this.unlock(key, this.root.hubGoals.level),
|
||||
isValid: currentLevel => currentLevel > level,
|
||||
signal: "storyGoalCompleted",
|
||||
};
|
||||
}
|
||||
|
||||
createRateOptions(shape, rate) {
|
||||
return {
|
||||
isValid: () => {
|
||||
return (
|
||||
this.root.productionAnalytics.getCurrentShapeRateRaw(
|
||||
enumAnalyticsDataSource.delivered,
|
||||
this.root.shapeDefinitionMgr.getShapeFromShortKey(shape)
|
||||
) /
|
||||
globalConfig.analyticsSliceDurationSeconds >=
|
||||
rate
|
||||
);
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
createShapeOptions(shape) {
|
||||
return {
|
||||
isValid: item => this.isShape(item, shape),
|
||||
signal: "itemProduced",
|
||||
};
|
||||
}
|
||||
|
||||
createSpeedOptions(level, time) {
|
||||
return {
|
||||
isValid: currentLevel => currentLevel >= level && this.root.time.now() < time,
|
||||
signal: "storyGoalCompleted",
|
||||
};
|
||||
}
|
||||
|
||||
createTimeOptions(duration) {
|
||||
return {
|
||||
isValid: () => this.root.time.now() >= duration,
|
||||
};
|
||||
}
|
||||
|
||||
createUpgradeOptions(tier) {
|
||||
return {
|
||||
init: ({ key }) => this.unlock(key, null),
|
||||
isValid: () => this.hasAllUpgradesAtLeastAtTier(tier),
|
||||
signal: "upgradePurchased",
|
||||
};
|
||||
}
|
||||
|
||||
/** @param {Entity} entity @returns {boolean} */
|
||||
isBelt500TilesValid(entity) {
|
||||
return entity.components.Belt && entity.components.Belt.assignedPath.totalLength >= 500;
|
||||
}
|
||||
|
||||
/** @returns {boolean} */
|
||||
isDarkModeValid() {
|
||||
return this.root.app.settings.currentData.settings.theme === DARK_MODE;
|
||||
}
|
||||
|
||||
/** @param {number} count @returns {boolean} */
|
||||
isDestroy1000Valid(count) {
|
||||
return count >= 1000;
|
||||
}
|
||||
|
||||
/** @param {ShapeDefinition} definition @returns {boolean} */
|
||||
isIrrelevantShapeValid(definition) {
|
||||
const levels = this.root.gameMode.getLevelDefinitions();
|
||||
for (let i = 0; i < levels.length; i++) {
|
||||
if (definition.cachedHash === levels[i].shape) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
const upgrades = this.root.gameMode.getUpgrades();
|
||||
for (let upgradeId in upgrades) {
|
||||
for (const tier in upgrades[upgradeId]) {
|
||||
const requiredShapes = upgrades[upgradeId][tier].required;
|
||||
for (let i = 0; i < requiredShapes.length; i++) {
|
||||
if (definition.cachedHash === requiredShapes[i].shape) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/** @param {ShapeItem} item @returns {boolean} */
|
||||
isLogoBefore18Valid(item) {
|
||||
return this.root.hubGoals.level < 18 && this.isShape(item, SHAPE_LOGO);
|
||||
}
|
||||
|
||||
/** @returns {boolean} */
|
||||
isMamValid() {
|
||||
return this.root.hubGoals.level > 27 && !this.root.savegame.currentData.stats.failedMam;
|
||||
}
|
||||
|
||||
/** @param {number} count @returns {boolean} */
|
||||
isMapMarkers15Valid(count) {
|
||||
return count >= 15;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {number} level
|
||||
* @returns {boolean}
|
||||
*/
|
||||
isNoBeltUpgradesUntilBpValid(level) {
|
||||
return level >= 12 && this.root.hubGoals.upgradeLevels.belt === 0;
|
||||
}
|
||||
|
||||
initNoInverseRotator() {
|
||||
if (this.root.savegame.currentData.stats.usedInverseRotator === true) {
|
||||
return;
|
||||
}
|
||||
|
||||
const entities = this.root.entityMgr.componentToEntity.StaticMapEntity;
|
||||
|
||||
let usedInverseRotator = false;
|
||||
for (var i = 0; i < entities.length; i++) {
|
||||
const entity = entities[i].components.StaticMapEntity;
|
||||
|
||||
if (entity.code === ROTATOR_CCW_CODE || entity.code === ROTATOR_180_CODE) {
|
||||
usedInverseRotator = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
this.root.savegame.currentData.stats.usedInverseRotator = usedInverseRotator;
|
||||
}
|
||||
|
||||
/** @param {number} level @returns {boolean} */
|
||||
isNoInverseRotatorValid(level) {
|
||||
return level >= 14 && !this.root.savegame.currentData.stats.usedInverseRotator;
|
||||
}
|
||||
|
||||
/** @param {string} currentLayer @returns {boolean} */
|
||||
isOpenWiresValid(currentLayer) {
|
||||
return currentLayer === WIRE_LAYER;
|
||||
}
|
||||
|
||||
/** @param {Entity} entity @returns {boolean} */
|
||||
isPlace5000WiresValid(entity) {
|
||||
return (
|
||||
entity.components.Wire &&
|
||||
entity.registered &&
|
||||
entity.root.entityMgr.componentToEntity.Wire.length >= 5000
|
||||
);
|
||||
}
|
||||
|
||||
/** @param {number} count @returns {boolean} */
|
||||
isPlaceBlueprintValid(count) {
|
||||
return count != 0;
|
||||
}
|
||||
|
||||
/** @param {number} count @returns {boolean} */
|
||||
isPlaceBp1000Valid(count) {
|
||||
return count >= 1000;
|
||||
}
|
||||
|
||||
/** @param {ShapeItem} item @returns {boolean} */
|
||||
isStack4LayersValid(item) {
|
||||
return item.getItemType() === ITEM_SHAPE && item.definition.layers.length === 4;
|
||||
}
|
||||
|
||||
/** @param {Achievement} achievement */
|
||||
initStore100Unique({ key }) {
|
||||
this.unlock(key, null);
|
||||
}
|
||||
|
||||
/** @returns {boolean} */
|
||||
isStore100UniqueValid() {
|
||||
return Object.keys(this.root.hubGoals.storedShapes).length >= 100;
|
||||
}
|
||||
|
||||
/** @param {Achievement} achievement */
|
||||
initStoreShape({ key }) {
|
||||
this.unlock(key, null);
|
||||
}
|
||||
|
||||
/** @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;
|
||||
}
|
||||
|
||||
/** @param {Achievement} achievement */
|
||||
initTrash1000({ key }) {
|
||||
if (Number(this.root.savegame.currentData.stats.trashedCount)) {
|
||||
this.unlock(key, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
this.root.savegame.currentData.stats.trashedCount = 0;
|
||||
}
|
||||
|
||||
/** @param {number} count @returns {boolean} */
|
||||
isTrash1000Valid(count) {
|
||||
this.root.savegame.currentData.stats.trashedCount += count;
|
||||
|
||||
return this.root.savegame.currentData.stats.trashedCount >= 1000;
|
||||
}
|
||||
}
|
||||
@ -1,23 +0,0 @@
|
||||
import { AchievementProviderInterface } from "./achievement_provider";
|
||||
|
||||
export class NoAchievementProvider extends AchievementProviderInterface {
|
||||
hasAchievements() {
|
||||
return false;
|
||||
}
|
||||
|
||||
hasLoaded() {
|
||||
return false;
|
||||
}
|
||||
|
||||
initialize() {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
onLoad() {
|
||||
return Promise.reject(new Error("No achievements to load"));
|
||||
}
|
||||
|
||||
activate() {
|
||||
return Promise.resolve();
|
||||
}
|
||||
}
|
||||
@ -5,7 +5,6 @@ import { Application } from "../application";
|
||||
import { IS_MOBILE } from "../core/config";
|
||||
import { createLogger } from "../core/logging";
|
||||
import { clamp } from "../core/utils";
|
||||
import { NoAchievementProvider } from "./no_achievement_provider";
|
||||
|
||||
const logger = createLogger("electron-wrapper");
|
||||
|
||||
@ -16,10 +15,8 @@ export class PlatformWrapperImplElectron {
|
||||
}
|
||||
|
||||
initialize() {
|
||||
return this.initializeAchievementProvider().then(() => {
|
||||
document.documentElement.classList.add("p-" + this.getId());
|
||||
return Promise.resolve();
|
||||
});
|
||||
document.documentElement.classList.add("p-" + this.getId());
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
getId() {
|
||||
@ -61,14 +58,6 @@ export class PlatformWrapperImplElectron {
|
||||
window.location.reload();
|
||||
}
|
||||
|
||||
initializeAchievementProvider() {
|
||||
return this.app.achievementProvider.initialize().catch(err => {
|
||||
logger.error("Failed to initialize achievement provider, disabling:", err);
|
||||
|
||||
this.app.achievementProvider = new NoAchievementProvider(this.app);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the UI scale, called on every resize
|
||||
* @returns {number} */
|
||||
|
||||
@ -24,7 +24,6 @@ const logger = createLogger("savegame");
|
||||
* @typedef {import("../game/root").GameRoot} GameRoot
|
||||
* @typedef {import("./savegame_typedefs").SavegameData} SavegameData
|
||||
* @typedef {import("./savegame_typedefs").SavegameMetadata} SavegameMetadata
|
||||
* @typedef {import("./savegame_typedefs").SavegameStats} SavegameStats
|
||||
* @typedef {import("./savegame_typedefs").SerializedGame} SerializedGame
|
||||
*/
|
||||
|
||||
@ -99,11 +98,6 @@ export class Savegame extends ReadWriteProxy {
|
||||
return {
|
||||
version: this.getCurrentVersion(),
|
||||
dump: null,
|
||||
stats: {
|
||||
failedMam: false,
|
||||
trashedCount: 0,
|
||||
usedInverseRotator: false,
|
||||
},
|
||||
lastUpdate: Date.now(),
|
||||
mods: MODS.getModsListForSavegame(),
|
||||
};
|
||||
@ -196,13 +190,6 @@ export class Savegame extends ReadWriteProxy {
|
||||
isSaveable() {
|
||||
return true;
|
||||
}
|
||||
/**
|
||||
* Returns the statistics of the savegame
|
||||
* @returns {SavegameStats}
|
||||
*/
|
||||
getStatistics() {
|
||||
return this.currentData.stats;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the *real* last update of the savegame, not the one of the metadata
|
||||
@ -273,7 +260,7 @@ export class Savegame extends ReadWriteProxy {
|
||||
return false;
|
||||
}
|
||||
|
||||
const shadowData = Object.assign({}, this.currentData);
|
||||
const shadowData = {};
|
||||
shadowData.dump = dump;
|
||||
shadowData.lastUpdate = new Date().getTime();
|
||||
shadowData.version = this.getCurrentVersion();
|
||||
|
||||
@ -10,12 +10,6 @@
|
||||
* }[]} SavegameStoredMods
|
||||
*
|
||||
* @typedef {{
|
||||
* failedMam: boolean,
|
||||
* trashedCount: number,
|
||||
* usedInverseRotator: boolean
|
||||
* }} SavegameStats
|
||||
*
|
||||
* @typedef {{
|
||||
* camera: any,
|
||||
* time: any,
|
||||
* entityMgr: any,
|
||||
@ -32,7 +26,6 @@
|
||||
* @typedef {{
|
||||
* version: number,
|
||||
* dump: SerializedGame,
|
||||
* stats: SavegameStats,
|
||||
* lastUpdate: number,
|
||||
* mods: SavegameStoredMods
|
||||
* }} SavegameData
|
||||
|
||||
@ -17,16 +17,7 @@ export class SavegameInterface_V1008 extends SavegameInterface_V1007 {
|
||||
* @param {import("../savegame_typedefs.js").SavegameData} data
|
||||
*/
|
||||
static migrate1007to1008(data) {
|
||||
// Note: no-op since achievement removal
|
||||
logger.log("Migrating 1007 to 1008");
|
||||
const dump = data.dump;
|
||||
if (!dump) {
|
||||
return true;
|
||||
}
|
||||
|
||||
Object.assign(data.stats, {
|
||||
failedMam: true,
|
||||
trashedCount: 0,
|
||||
usedInverseRotator: true,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user