mirror of
https://github.com/tobspr/shapez.io.git
synced 2024-10-27 20:34:29 +00:00
Prepare the achievements update
This commit is contained in:
parent
837b0d8007
commit
226149a40f
@ -62,7 +62,8 @@
|
||||
"webpack-plugin-replace": "^1.1.1",
|
||||
"webpack-strip-block": "^0.2.0",
|
||||
"whatwg-fetch": "^3.0.0",
|
||||
"worker-loader": "^2.0.0"
|
||||
"worker-loader": "^2.0.0",
|
||||
"yaml": "^1.10.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"autoprefixer": "^9.4.3",
|
||||
|
@ -25,6 +25,7 @@ function gulptasksTranslations($, gulp) {
|
||||
files
|
||||
.filter(name => name.endsWith(".yaml"))
|
||||
.forEach(fname => {
|
||||
console.log("Loading", fname);
|
||||
const languageName = fname.replace(".yaml", "");
|
||||
const abspath = path.join(translationsSourceDir, fname);
|
||||
|
||||
@ -40,39 +41,13 @@ function gulptasksTranslations($, gulp) {
|
||||
|
||||
${storePage.intro.replace(/\n/gi, "\n\n")}
|
||||
|
||||
[h2]${storePage.title_advantages}[/h2]
|
||||
[h2]${storePage.what_others_say}[/h2]
|
||||
|
||||
[list]
|
||||
${storePage.advantages
|
||||
.map(x => "[*] " + x.replace(/<b>/, "[b]").replace(/<\/b>/, "[/b]"))
|
||||
.join("\n")}
|
||||
[*] [i]${storePage.northernlion_comment}[/i] [b]- Northernlion, YouTube[/b]
|
||||
[*] [i]${storePage.notch_comment}[/i] [b]- Notch[/b]
|
||||
[*] [i]${storePage.steam_review_comment}[/i] [b]- Steam User[/b]
|
||||
[/list]
|
||||
|
||||
[h2]${storePage.title_future}[/h2]
|
||||
|
||||
[list]
|
||||
${storePage.planned
|
||||
.map(x => "[*] " + x.replace(/<b>/, "[b]").replace(/<\/b>/, "[/b]"))
|
||||
.join("\n")}
|
||||
[/list]
|
||||
|
||||
[h2]${storePage.title_open_source}[/h2]
|
||||
|
||||
${storePage.text_open_source.replace(/\n/gi, "\n\n")}
|
||||
|
||||
[h2]${storePage.title_links}[/h2]
|
||||
|
||||
[list]
|
||||
[*] [url=https://discord.com/invite/HN7EVzV]${storePage.links.discord}[/url]
|
||||
[*] [url=https://trello.com/b/ISQncpJP/shapezio]${storePage.links.roadmap}[/url]
|
||||
[*] [url=https://www.reddit.com/r/shapezio]${storePage.links.subreddit}[/url]
|
||||
[*] [url=https://github.com/tobspr/shapez.io]${storePage.links.source_code}[/url]
|
||||
[*] [url=https://github.com/tobspr/shapez.io/blob/master/translations/README.md]${
|
||||
storePage.links.translate
|
||||
}[/url]
|
||||
[/list]
|
||||
|
||||
|
||||
`;
|
||||
|
||||
fs.writeFileSync(destpath, trim(content.replace(/(\n[ \t\r]*)/gi, "\n")), {
|
||||
|
23902
gulp/yarn.lock
23902
gulp/yarn.lock
File diff suppressed because it is too large
Load Diff
BIN
res/ui/changelog_skins/achievements.noinline.png
Normal file
BIN
res/ui/changelog_skins/achievements.noinline.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 479 KiB |
18
src/css/changelog_skins.scss
Normal file
18
src/css/changelog_skins.scss
Normal file
@ -0,0 +1,18 @@
|
||||
[data-changelog-skin="achievements"] {
|
||||
background: #f8f8f8;
|
||||
|
||||
@include DarkThemeOverride {
|
||||
background: rgba(0, 10, 20, 0.2);
|
||||
}
|
||||
|
||||
@include S(border-radius, 5px);
|
||||
&::before {
|
||||
content: " ";
|
||||
width: 100%;
|
||||
display: block;
|
||||
background: uiResource("changelog_skins/achievements.noinline.png") center center / cover no-repeat !important;
|
||||
@include S(height, 80px);
|
||||
@include S(border-radius, 5px);
|
||||
@include S(margin-bottom, 5px);
|
||||
}
|
||||
}
|
@ -19,6 +19,7 @@
|
||||
@import "application_error";
|
||||
@import "textual_game_state";
|
||||
@import "adinplay";
|
||||
@import "changelog_skins";
|
||||
|
||||
@import "states/preload";
|
||||
@import "states/main_menu";
|
||||
@ -56,8 +57,8 @@
|
||||
@import "ingame_hud/cat_memes";
|
||||
|
||||
// prettier-ignore
|
||||
$elements:
|
||||
// Base
|
||||
$elements:
|
||||
// Base
|
||||
ingame_Canvas,
|
||||
ingame_VignetteOverlay,
|
||||
|
||||
@ -119,11 +120,3 @@ body.uiHidden {
|
||||
display: none !important;
|
||||
}
|
||||
}
|
||||
|
||||
body.modalDialogActive,
|
||||
body.externalAdOpen,
|
||||
body.ingameDialogOpen {
|
||||
> *:not(.ingameDialog):not(.modalDialogParent):not(.loadingDialog):not(.gameLoadingOverlay):not(#ingame_HUD_ModalDialogs):not(.noBlur) {
|
||||
// filter: blur(5px) !important;
|
||||
}
|
||||
}
|
||||
|
@ -184,7 +184,7 @@
|
||||
.updateLabel {
|
||||
position: absolute;
|
||||
transform: translateX(50%) rotate(-5deg);
|
||||
color: rgb(231, 78, 58);
|
||||
color: rgb(133, 58, 231);
|
||||
@include Heading;
|
||||
font-weight: bold;
|
||||
@include S(right, 40px);
|
||||
|
@ -14,6 +14,7 @@
|
||||
padding: 10px;
|
||||
box-sizing: border-box;
|
||||
background: #eef1f4;
|
||||
@include S(border-radius, 3px);
|
||||
|
||||
@include DarkThemeOverride {
|
||||
background: #424242;
|
||||
|
@ -1,10 +1,13 @@
|
||||
export const CHANGELOG = [
|
||||
{
|
||||
version: "1.2.3",
|
||||
date: "unreleased",
|
||||
version: "1.3.0",
|
||||
date: "12.03.2020",
|
||||
skin: "achievements",
|
||||
entries: [
|
||||
"There are now <strong>45 Steam Achievements!</strong>",
|
||||
"Fixed constant signals being editable from the regular layer",
|
||||
"Fixed items still overlapping sometimes between buildings and belts",
|
||||
"Updated translations (Thanks to all contributors!)",
|
||||
],
|
||||
},
|
||||
{
|
||||
|
@ -12,8 +12,6 @@ const logger = createLogger("achievement_proxy");
|
||||
|
||||
const ROTATER = "rotater";
|
||||
const DEFAULT = "default";
|
||||
const BELT = "belt";
|
||||
const LEVEL_26 = 26;
|
||||
|
||||
export class AchievementProxy {
|
||||
/** @param {GameRoot} root */
|
||||
@ -22,7 +20,9 @@ export class AchievementProxy {
|
||||
this.provider = this.root.app.achievementProvider;
|
||||
this.disabled = true;
|
||||
|
||||
if (!this.provider.hasAchievements()) {
|
||||
if (G_IS_DEV && globalConfig.debug.testAchievements) {
|
||||
// still enable the proxy
|
||||
} else if (!this.provider.hasAchievements()) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -34,7 +34,8 @@ export class AchievementProxy {
|
||||
}
|
||||
|
||||
onLoad() {
|
||||
this.provider.onLoad(this.root)
|
||||
this.provider
|
||||
.onLoad(this.root)
|
||||
.then(() => {
|
||||
this.disabled = false;
|
||||
logger.log("Recieving achievement signals");
|
||||
@ -50,6 +51,8 @@ export class AchievementProxy {
|
||||
this.root.signals.achievementCheck.dispatch(ACHIEVEMENTS.darkMode);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
@ -57,10 +60,6 @@ export class AchievementProxy {
|
||||
this.root.signals.entityAdded.add(this.onEntityAdded, this);
|
||||
}
|
||||
|
||||
if (this.has(ACHIEVEMENTS.noBeltUpgradesUntilBp)) {
|
||||
this.root.signals.upgradePurchased.add(this.onUpgradePurchased, this);
|
||||
}
|
||||
|
||||
this.startSlice();
|
||||
}
|
||||
|
||||
@ -73,27 +72,38 @@ export class AchievementProxy {
|
||||
// Every other slice
|
||||
if (this.sliceIteration % 2 === 0) {
|
||||
this.root.signals.bulkAchievementCheck.dispatch(
|
||||
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.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
|
||||
ACHIEVEMENTS.play1h,
|
||||
this.sliceTime,
|
||||
ACHIEVEMENTS.play10h,
|
||||
this.sliceTime,
|
||||
ACHIEVEMENTS.play20h,
|
||||
this.sliceTime
|
||||
);
|
||||
}
|
||||
|
||||
// Every 10th slice
|
||||
if (this.sliceIteration % 10 === 0) {
|
||||
this.provider.collection.clean();
|
||||
if (this.provider.collection) {
|
||||
this.provider.collection.clean();
|
||||
}
|
||||
}
|
||||
|
||||
if (this.sliceIteration === this.sliceIterationLimit) {
|
||||
@ -118,6 +128,9 @@ export class AchievementProxy {
|
||||
* @returns {boolean}
|
||||
*/
|
||||
has(key) {
|
||||
if (!this.provider.collection) {
|
||||
return false;
|
||||
}
|
||||
return this.provider.collection.map.has(key);
|
||||
}
|
||||
|
||||
@ -127,7 +140,7 @@ export class AchievementProxy {
|
||||
return;
|
||||
}
|
||||
|
||||
const building = getBuildingDataFromCode(entity.components.StaticMapEntity.code)
|
||||
const building = getBuildingDataFromCode(entity.components.StaticMapEntity.code);
|
||||
|
||||
if (building.metaInstance.id !== ROTATER) {
|
||||
return;
|
||||
@ -143,28 +156,18 @@ export class AchievementProxy {
|
||||
|
||||
/** @param {number} level */
|
||||
onStoryGoalCompleted(level) {
|
||||
if (level === LEVEL_26) {
|
||||
if (level > 26) {
|
||||
this.root.signals.entityAdded.add(this.onMamFailure, this);
|
||||
this.root.signals.entityDestroyed.add(this.onMamFailure, this);
|
||||
} else if (level === LEVEL_26 + 1) {
|
||||
this.root.signals.storyGoalCompleted.remove(this.onStoryGoalCompleted, this);
|
||||
}
|
||||
|
||||
this.root.signals.achievementCheck.dispatch(ACHIEVEMENTS.mam);
|
||||
|
||||
// reset on every level
|
||||
this.root.savegame.currentData.stats.failedMam = false;
|
||||
}
|
||||
|
||||
onMamFailure() {
|
||||
this.root.savegame.currentData.stats.failedMam = true;
|
||||
this.root.signals.entityAdded.remove(this.onMamFailure);
|
||||
this.root.signals.entityDestroyed.remove(this.onMamFailure);
|
||||
this.root.signals.storyGoalCompleted.remove(this.onStoryGoalCompleted);
|
||||
}
|
||||
|
||||
/** @param {string} upgrade */
|
||||
onUpgradePurchased(upgrade) {
|
||||
if (upgrade !== BELT) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.root.savegame.currentData.stats.upgradedBelt = true;
|
||||
this.root.signals.upgradePurchased.remove(this.onUpgradePurchased);
|
||||
}
|
||||
}
|
||||
|
@ -182,7 +182,7 @@ export class GameRoot {
|
||||
|
||||
// Called with an achievement key and necessary args to validate it can be unlocked.
|
||||
achievementCheck: /** @type {TypedSignal<[string, *]>} */ (new Signal()),
|
||||
bulkAchievementCheck: /** @type {TypedSignal<[string, any]...>} */ (new Signal()),
|
||||
bulkAchievementCheck: /** @type {TypedSignal<(string|any)[]>} */ (new Signal()),
|
||||
};
|
||||
|
||||
// RNG's
|
||||
|
@ -1,12 +1,14 @@
|
||||
/* typehints:start */
|
||||
import { Application } from "../application";
|
||||
import { StorageComponent } from "../game/components/storage";
|
||||
import { ShapeItem } from "../game/items/shape_item";
|
||||
import { Entity } from "../game/entity";
|
||||
import { GameRoot } from "../game/root";
|
||||
import { ShapeDefinition } from "../game/shape_definition";
|
||||
import { THEMES } from "../game/theme";
|
||||
/* typehints:end */
|
||||
|
||||
import { enumAnalyticsDataSource } from "../game/production_analytics";
|
||||
import { ShapeItem } from "../game/items/shape_item";
|
||||
|
||||
export const ACHIEVEMENTS = {
|
||||
belt500Tiles: "belt500Tiles",
|
||||
blueprint100k: "blueprint100k",
|
||||
@ -55,16 +57,16 @@ export const ACHIEVEMENTS = {
|
||||
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 = "shape";
|
||||
const ITEM_SHAPE = ShapeItem.getId();
|
||||
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 ROTATER_CCW_CODE = 12;
|
||||
const ROTATER_180_CODE = 13;
|
||||
const SHAPE_BP = "CbCbCbRb:CwCwCwCw";
|
||||
@ -72,9 +74,15 @@ 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;
|
||||
@ -135,9 +143,7 @@ export class Achievement {
|
||||
this.signal = null;
|
||||
}
|
||||
|
||||
init() {
|
||||
|
||||
}
|
||||
init() {}
|
||||
|
||||
isValid() {
|
||||
return true;
|
||||
@ -193,19 +199,16 @@ export class AchievementCollection {
|
||||
this.add(ACHIEVEMENTS.logoBefore18, {
|
||||
isRelevant: this.isLogoBefore18Relevant,
|
||||
isValid: this.isLogoBefore18Valid,
|
||||
signal: "itemProduced"
|
||||
signal: "itemProduced",
|
||||
});
|
||||
this.add(ACHIEVEMENTS.mam, {
|
||||
isRelevant: this.isMamRelevant,
|
||||
isValid: this.isMamValid,
|
||||
signal: "storyGoalCompleted",
|
||||
});
|
||||
this.add(ACHIEVEMENTS.mapMarkers15, {
|
||||
isRelevant: this.isMapMarkers15Relevant,
|
||||
isValid: this.isMapMarkers15Valid,
|
||||
});
|
||||
this.add(ACHIEVEMENTS.noBeltUpgradesUntilBp, {
|
||||
init: this.initNoBeltUpgradesUntilBp,
|
||||
isRelevant: this.isNoBeltUpgradesUntilBpRelevant,
|
||||
isValid: this.isNoBeltUpgradesUntilBpValid,
|
||||
signal: "storyGoalCompleted",
|
||||
@ -354,7 +357,8 @@ export class AchievementCollection {
|
||||
return;
|
||||
}
|
||||
|
||||
achievement.unlock()
|
||||
achievement
|
||||
.unlock()
|
||||
.then(() => {
|
||||
this.onActivate(null, key);
|
||||
})
|
||||
@ -380,12 +384,13 @@ export class AchievementCollection {
|
||||
/** @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);
|
||||
}
|
||||
|
||||
if (achievement.receiver) {
|
||||
this.root.signals[achievement.signal].remove(achievement.receiver);
|
||||
this.map.delete(key);
|
||||
}
|
||||
|
||||
this.map.delete(key);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -447,7 +452,7 @@ export class AchievementCollection {
|
||||
createLevelOptions(level) {
|
||||
return {
|
||||
isRelevant: () => this.root.hubGoals.level < level,
|
||||
isValid: (currentLevel) => currentLevel === level,
|
||||
isValid: currentLevel => currentLevel === level,
|
||||
signal: "storyGoalCompleted",
|
||||
};
|
||||
}
|
||||
@ -455,17 +460,19 @@ export class AchievementCollection {
|
||||
createRateOptions(shape, rate) {
|
||||
return {
|
||||
isValid: () => {
|
||||
return this.root.productionAnalytics.getCurrentShapeRate(
|
||||
PRODUCED,
|
||||
this.root.shapeDefinitionMgr.getShapeFromShortKey(shape)
|
||||
) >= rate;
|
||||
}
|
||||
return (
|
||||
this.root.productionAnalytics.getCurrentShapeRate(
|
||||
enumAnalyticsDataSource.delivered,
|
||||
this.root.shapeDefinitionMgr.getShapeFromShortKey(shape)
|
||||
) >= rate
|
||||
);
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
createShapeOptions(shape) {
|
||||
return {
|
||||
isValid: (item) => this.isShape(item, shape),
|
||||
isValid: item => this.isShape(item, shape),
|
||||
signal: "itemProduced",
|
||||
};
|
||||
}
|
||||
@ -473,7 +480,7 @@ export class AchievementCollection {
|
||||
createSpeedOptions(level, time) {
|
||||
return {
|
||||
isRelevant: () => this.root.hubGoals.level <= level && this.root.time.now() < time,
|
||||
isValid: (currentLevel) => currentLevel === level && this.root.time.now() < time,
|
||||
isValid: currentLevel => currentLevel === level && this.root.time.now() < time,
|
||||
signal: "storyGoalCompleted",
|
||||
};
|
||||
}
|
||||
@ -500,18 +507,12 @@ export class AchievementCollection {
|
||||
|
||||
/** @param {ShapeDefinition} definition @returns {boolean} */
|
||||
isBlueprint100kValid(definition) {
|
||||
return (
|
||||
definition.cachedHash === SHAPE_BP &&
|
||||
this.root.hubGoals.storedShapes[SHAPE_BP] >= 100000
|
||||
);
|
||||
return definition.cachedHash === SHAPE_BP && this.root.hubGoals.storedShapes[SHAPE_BP] >= 100000;
|
||||
}
|
||||
|
||||
/** @param {ShapeDefinition} definition @returns {boolean} */
|
||||
isBlueprint1mValid(definition) {
|
||||
return (
|
||||
definition.cachedHash === SHAPE_BP &&
|
||||
this.root.hubGoals.storedShapes[SHAPE_BP] >= 1000000
|
||||
);
|
||||
return definition.cachedHash === SHAPE_BP && this.root.hubGoals.storedShapes[SHAPE_BP] >= 1000000;
|
||||
}
|
||||
|
||||
/** @returns {boolean} */
|
||||
@ -530,14 +531,18 @@ export class AchievementCollection {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (definition.cachedHash === this.root.gameMode.getBlueprintShapeKey()) {
|
||||
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;
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -555,28 +560,9 @@ export class AchievementCollection {
|
||||
return this.root.hubGoals.level < 18 && this.isShape(item, SHAPE_LOGO);
|
||||
}
|
||||
|
||||
initMam() {
|
||||
const stats = this.root.savegame.currentData.stats;
|
||||
|
||||
if (stats.failedMam === true) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.root.hubGoals.level === 26 && stats.failedMam === false) {
|
||||
return;
|
||||
}
|
||||
|
||||
stats.failedMam = this.root.hubGoals.level < 26;
|
||||
}
|
||||
|
||||
/** @returns {boolean} */
|
||||
isMamRelevant() {
|
||||
return this.root.hubGoals.level <= 26 && !this.root.savegame.currentData.stats.failedMam;
|
||||
}
|
||||
|
||||
/** @params {number} level @returns {boolean} */
|
||||
isMamValid(level) {
|
||||
return level === 27 && !this.root.savegame.currentData.stats.failedMam;
|
||||
isMamValid() {
|
||||
return this.root.hubGoals.level > 27 && !this.root.savegame.currentData.stats.failedMam;
|
||||
}
|
||||
|
||||
/** @returns {boolean} */
|
||||
@ -589,16 +575,6 @@ export class AchievementCollection {
|
||||
return count === 15;
|
||||
}
|
||||
|
||||
initNoBeltUpgradesUntilBp() {
|
||||
const stats = this.root.savegame.currentData.stats;
|
||||
|
||||
if (stats.upgradedBelt === true) {
|
||||
return;
|
||||
}
|
||||
|
||||
stats.upgradedBelt = this.root.hubGoals.upgradeLevels.belt > 0;
|
||||
}
|
||||
|
||||
/** @returns {boolean} */
|
||||
isNoBeltUpgradesUntilBpRelevant() {
|
||||
return this.root.hubGoals.level <= 12 && this.root.hubGoals.upgradeLevels.belt === 0;
|
||||
@ -631,8 +607,7 @@ export class AchievementCollection {
|
||||
|
||||
/** @returns {boolean} */
|
||||
isNoInverseRotaterRelevant() {
|
||||
return this.root.hubGoals.level < 14 &&
|
||||
!this.root.savegame.currentData.stats.usedInverseRotater;
|
||||
return this.root.hubGoals.level < 14 && !this.root.savegame.currentData.stats.usedInverseRotater;
|
||||
}
|
||||
|
||||
/** @param {number} level @returns {boolean} */
|
||||
|
@ -203,12 +203,11 @@ export class PlatformWrapperImplBrowser extends PlatformWrapperInterface {
|
||||
if (G_IS_DEV && globalConfig.debug.testAchievements) {
|
||||
this.app.achievementProvider = new SteamAchievementProvider(this.app);
|
||||
|
||||
return this.app.achievementProvider.initialize()
|
||||
.catch(err => {
|
||||
logger.error("Failed to initialize achievement provider, disabling:", err);
|
||||
return this.app.achievementProvider.initialize().catch(err => {
|
||||
logger.error("Failed to initialize achievement provider, disabling:", err);
|
||||
|
||||
this.app.achievementProvider = new NoAchievementProvider(this.app);
|
||||
});
|
||||
this.app.achievementProvider = new NoAchievementProvider(this.app);
|
||||
});
|
||||
}
|
||||
|
||||
return this.app.achievementProvider.initialize();
|
||||
|
@ -78,7 +78,11 @@ export class Savegame extends ReadWriteProxy {
|
||||
return {
|
||||
version: this.getCurrentVersion(),
|
||||
dump: null,
|
||||
stats: {},
|
||||
stats: {
|
||||
failedMam: false,
|
||||
trashedCount: 0,
|
||||
usedInverseRotater: false,
|
||||
},
|
||||
lastUpdate: Date.now(),
|
||||
};
|
||||
}
|
||||
|
@ -24,9 +24,9 @@ export class SavegameInterface_V1008 extends SavegameInterface_V1007 {
|
||||
}
|
||||
|
||||
Object.assign(data.stats, {
|
||||
failedMam: false,
|
||||
failedMam: true,
|
||||
trashedCount: 0,
|
||||
usedInverseRotater: false
|
||||
usedInverseRotater: true,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -19,7 +19,7 @@ export class ChangelogState extends TextualGameState {
|
||||
for (let i = 0; i < entries.length; ++i) {
|
||||
const entry = entries[i];
|
||||
html += `
|
||||
<div class="entry">
|
||||
<div class="entry" data-changelog-skin="${entry.skin || "default"}">
|
||||
<span class="version">${entry.version}</span>
|
||||
<span class="date">${entry.date}</span>
|
||||
<ul class="changes">
|
||||
|
@ -66,7 +66,7 @@ export class MainMenuState extends GameState {
|
||||
<img src="${cachebust(
|
||||
G_CHINA_VERSION ? "res/logo_cn.png" : "res/logo.png"
|
||||
)}" alt="shapez.io Logo">
|
||||
<span class="updateLabel">v${G_BUILD_VERSION}</span>
|
||||
<span class="updateLabel">v${G_BUILD_VERSION} - Achievements!</span>
|
||||
</div>
|
||||
|
||||
<div class="mainWrapper ${showDemoBadges ? "demo" : "noDemo"}">
|
||||
|
@ -199,7 +199,9 @@ export class PreloadState extends GameState {
|
||||
for (let i = 0; i < changelogEntries.length; ++i) {
|
||||
const entry = changelogEntries[i];
|
||||
dialogHtml += `
|
||||
<div class="changelogDialogEntry">
|
||||
<div class="changelogDialogEntry" data-changelog-skin="${
|
||||
entry.skin || "default"
|
||||
}">
|
||||
<span class="version">${entry.version}</span>
|
||||
<span class="date">${entry.date}</span>
|
||||
<ul class="changes">
|
||||
|
@ -30,49 +30,20 @@ steamPage:
|
||||
intro: >-
|
||||
Do you like automation games? Then you are in the right place!
|
||||
|
||||
shapez.io is a relaxed game in which you have to build factories for the automated production of geometric shapes. As the level increases, the shapes become more and more complex, and you
|
||||
have to spread out on the infinite map.
|
||||
shapez.io is a relaxed game in which you have to build factories for the automated production of geometric shapes. As the level increases, the shapes become more and more complex, and you have to spread out on the infinite map.
|
||||
|
||||
And as if that wasn't enough, you also have to produce exponentially more to satisfy the demands - the only thing that helps is scaling! While you only have to process shapes at the
|
||||
beginning, you will later have to color them - by extracting and mixing colors!
|
||||
And as if that wasn't enough, you also have to produce exponentially more to satisfy the demands - the only thing that helps is scaling! While you only have to process shapes at the beginning, you will later have to color them - by extracting and mixing colors!
|
||||
|
||||
Buying the game on Steam gives you access to the full version, but you can also play a demo at shapez.io first and decide later!
|
||||
|
||||
title_advantages: Standalone Advantages
|
||||
advantages:
|
||||
- <b>12 New Levels</b> for a total of 26 levels
|
||||
- <b>18 New Buildings</b> for a fully automated factory!
|
||||
- <b>Unlimited Upgrade Tiers</b> for many hours of fun!
|
||||
- <b>Wires Update</b> for an entirely new dimension!
|
||||
- <b>Dark Mode</b>!
|
||||
- Unlimited Savegames
|
||||
- Unlimited Markers
|
||||
- Support me! ❤️
|
||||
what_others_say: What people say about shapez.io
|
||||
|
||||
title_future: Planned Content
|
||||
planned:
|
||||
- Blueprint Library
|
||||
- Steam Achievements
|
||||
- Puzzle Mode
|
||||
- Minimap
|
||||
- Mods
|
||||
- Sandbox mode
|
||||
- ... and a lot more!
|
||||
|
||||
title_open_source: This game is open source!
|
||||
text_open_source: >-
|
||||
Anybody can contribute, I'm actively involved in the community and attempt to review all suggestions and take feedback into consideration where possible.
|
||||
|
||||
Be sure to check out my trello board for the full roadmap!
|
||||
|
||||
title_links: Links
|
||||
|
||||
links:
|
||||
discord: Official Discord
|
||||
roadmap: Roadmap
|
||||
subreddit: Subreddit
|
||||
source_code: Source code (GitHub)
|
||||
translate: Help translate
|
||||
nothernlion_comment: >-
|
||||
This game is great - I'm having a wonderful time playing, and time has flown by.
|
||||
notch_comment: >-
|
||||
Oh crap. I really should sleep, but I think I just figured out how to make a computer in shapez.io
|
||||
steam_review_comment: >-
|
||||
This game has stolen my life and I don't want it back. Very chill factory game that won't let me stop making my lines more efficient.
|
||||
|
||||
global:
|
||||
loading: Loading
|
||||
@ -1207,11 +1178,6 @@ demo:
|
||||
|
||||
settingNotAvailable: Not available in the demo.
|
||||
|
||||
achievements:
|
||||
painting:
|
||||
displayName: Painting
|
||||
description: Paint a shape
|
||||
|
||||
tips:
|
||||
- The hub will accept any input, not just the current shape!
|
||||
- Make sure your factories are modular - it will pay out!
|
||||
|
@ -168,13 +168,14 @@ dialogs:
|
||||
desc: Suorita taso 12 avataksesi piirustukset!
|
||||
keybindingsIntroduction:
|
||||
title: Hyödyllisiä pikanäppäimiä
|
||||
desc: "Tässä pelissä on paljon pikanäppäimiä, jotka tekevät isojen tehtaiden
|
||||
desc: >-
|
||||
Tässä pelissä on paljon pikanäppäimiä, jotka tekevät isojen tehtaiden
|
||||
rakentamisesta helpompaa. Tässä on muutama, mutta <strong>katso
|
||||
kaikki pikanäppäimet</strong>!<br><br> <code
|
||||
class='keybinding'>CTRL</code> + Raahaus: Valitse alue.<br> <code
|
||||
class='keybinding'>SHIFT</code>: Pidä pohjassa sijoittaaksesi
|
||||
useita samoja rakennuksia.<br> <code class='keybinding'>ALT</code>:
|
||||
Käännä sijoitettavien kuljettimien suunta.<br>"
|
||||
Käännä sijoitettavien kuljettimien suunta.<br>
|
||||
createMarker:
|
||||
title: Uusi merkki
|
||||
desc: Anna merkille kuvaava nimi. Voit myös liittää <strong>lyhyen koodin</strong>
|
||||
@ -306,26 +307,31 @@ ingame:
|
||||
hints:
|
||||
1_1_extractor: Laita <strong>Poimija</strong> <strong>ympyrämuodon</strong>
|
||||
päälle käyttääksesi sitä!
|
||||
1_2_conveyor: "Yhdistä poimija <strong>kuljettimella</strong>
|
||||
1_2_conveyor: >-
|
||||
Yhdistä poimija <strong>kuljettimella</strong>
|
||||
keskusrakennukseen!<br><br>Vihje: <strong>Paina ja
|
||||
raahaa</strong> kuljetinta hiirellä!"
|
||||
1_3_expand: "Tämä <strong>EI OLE</strong> tyhjäkäyntipeli! Rakenna lisää
|
||||
raahaa</strong> kuljetinta hiirellä!
|
||||
1_3_expand: >-
|
||||
Tämä <strong>EI OLE</strong> tyhjäkäyntipeli! Rakenna lisää
|
||||
poimijoita ja kuljettimia saavuttaaksesi tavoitteen nopeammin
|
||||
valmiiksi.<br><br>Vihje: Pidä <strong>SHIFT</strong> pohjassa
|
||||
laittaaksesi useampia poimijoita ja käytä <strong>R</strong>
|
||||
kääntääksesi niitä."
|
||||
2_1_place_cutter: "Nyt aseta <strong>Leikkuri</strong> leikataksesi ympyrä
|
||||
kääntääksesi niitä.
|
||||
2_1_place_cutter: >-
|
||||
Nyt aseta <strong>Leikkuri</strong> leikataksesi ympyrä
|
||||
puoliksi!<br><br> PS: Leikkuri aina leikkaa <strong>ylhäältä alaspäin</strong>
|
||||
riippumatta sen asennosta."
|
||||
riippumatta sen asennosta.
|
||||
2_2_place_trash: Leikkuri voi <strong>tukkeutua</strong>!<br><br> Käytä
|
||||
<strong>roskakoria</strong> hävittääksesi (vielä!) tarpeeton jäte.
|
||||
2_3_more_cutters: "Hienoa! Lisää <strong>kaksi leikkuria</strong> nopeuttaaksesi
|
||||
2_3_more_cutters: >-
|
||||
Hienoa! Lisää <strong>kaksi leikkuria</strong> nopeuttaaksesi
|
||||
hidasta prosessia!<br><br> PS: Käytä <strong>pikanäppäimiä 0-9</strong>
|
||||
valitaksesi rakennuksen nopeammin!"
|
||||
3_1_rectangles: "Poimitaanpa nyt neliöitä! <strong>Rakenna 4
|
||||
valitaksesi rakennuksen nopeammin!
|
||||
3_1_rectangles: >-
|
||||
Poimitaanpa nyt neliöitä! <strong>Rakenna 4
|
||||
poimijaa</strong> ja yhdistä ne keskusrakennukseen.<br><br> PS:
|
||||
Pidä <strong>SHIFT</strong> painettuna, kun raahaat kuljetinta
|
||||
aktivoidaksesi kuljetinsuunnittelijan!"
|
||||
aktivoidaksesi kuljetinsuunnittelijan!
|
||||
21_1_place_quad_painter: Aseta <strong>nelimaalain</strong> ja hanki
|
||||
<strong>ympyröitä</strong>, <strong>valkoista</strong> ja
|
||||
<strong>punaista</strong> väriä!
|
||||
@ -333,9 +339,10 @@ ingame:
|
||||
<strong>E</strong>!<br><br> Sitten <strong>yhdistä kaikki neljä tuloa</strong> maalaimeen johdoilla!
|
||||
21_3_place_button: MahtaVATA! Aseta nyt <strong>kytkin</strong> ja yhdistä
|
||||
se johdoilla!
|
||||
21_4_press_button: "Paina kytkintä <strong>lähettääksesi tosi-
|
||||
21_4_press_button: >-
|
||||
Paina kytkintä <strong>lähettääksesi tosi-
|
||||
signaalin</strong> ja aktivoidaksesi maalaimen.<br><br> PS: Kaikkia
|
||||
tuloja ei tarvitse kytkeä! Kokeile vaikka vain kahta."
|
||||
tuloja ei tarvitse kytkeä! Kokeile vaikka vain kahta.
|
||||
connectedMiners:
|
||||
one_miner: 1 poimija
|
||||
n_miners: <amount> poimijaa
|
||||
@ -587,10 +594,11 @@ storyRewards:
|
||||
desc: Avasit <strong>Kääntäjän</strong>! Se kääntää muotoja myötäpäivään 90 astetta.
|
||||
reward_painter:
|
||||
title: Värjäys
|
||||
desc: "Avasit <strong>Maalaimen</strong> - Poimi joitain värialueita
|
||||
desc: >-
|
||||
Avasit <strong>Maalaimen</strong> - Poimi joitain värialueita
|
||||
(Samoin kuin muotoja) ja yhdistä se muotoon maalaimen
|
||||
avulla!<br><br>PS: Jos olet värisokea, asetuksissa on <strong> tila
|
||||
värisokeille</strong>!"
|
||||
värisokeille</strong>!
|
||||
reward_mixer:
|
||||
title: Värin Sekoitus
|
||||
desc: Avasit <strong>Värinsekoittajan</strong> - Yhdistä kaksi väriä
|
||||
@ -617,10 +625,11 @@ storyRewards:
|
||||
<strong>painamalla 'T' vaihtaaksesi sen versioita</strong>!
|
||||
reward_miner_chainable:
|
||||
title: Sarjapoimija
|
||||
desc: "Avasit juuri <strong>Sarjapoimijan</strong>! Se voi
|
||||
desc: >-
|
||||
Avasit juuri <strong>Sarjapoimijan</strong>! Se voi
|
||||
<strong>siirtää resurssejaan</strong> muihin poimijoihin, joten
|
||||
voit hankkia resursseja tehokkaammin!<br><br> PS: Vanha
|
||||
poimija on nyt korvattu työkalupalkissa!"
|
||||
poimija on nyt korvattu työkalupalkissa!
|
||||
reward_underground_belt_tier_2:
|
||||
title: Tunneli Taso II
|
||||
desc: Avasit uuden version <strong>Tunnelista</strong> - Siinä on <strong>pidempi
|
||||
@ -657,9 +666,10 @@ storyRewards:
|
||||
jotta sinulla on varaa siihen! (Ne mitkä juuri toimitit).
|
||||
no_reward:
|
||||
title: Seuraava taso
|
||||
desc: "Et saanut palkintoa tältä tasolta, mutta seuraavalta tasolta saat! <br><br> PS: Parempi
|
||||
desc: >-
|
||||
Et saanut palkintoa tältä tasolta, mutta seuraavalta tasolta saat! <br><br> PS: Parempi
|
||||
olla tuhoamatta vanhoja tehtaita - Tarvitset <strong>kaikkia</strong>
|
||||
muotoja myöhemmin <strong>avataksesi päivityksiä</strong>!"
|
||||
muotoja myöhemmin <strong>avataksesi päivityksiä</strong>!
|
||||
no_reward_freeplay:
|
||||
title: Seuraava taso
|
||||
desc: Onnittelut! Muuten, lisää sisältöä on suunniteltu täysversioon!
|
||||
@ -682,8 +692,9 @@ storyRewards:
|
||||
kääntää muotoa 180 astetta (Ylläripylläri! :D)
|
||||
reward_display:
|
||||
title: Näyttö
|
||||
desc: "Avasit juuri <strong>Näytön</strong> - Yhdistä signaali näyttöön
|
||||
Johto-tasolla visualisoidaksesi sen<br><br> PS: Huomasitko, että kuljetinanturi ja varasto näyttävät viimeisimmän esineen? Yritäpä saada se näkyviin näytölle!"
|
||||
desc: >-
|
||||
Avasit juuri <strong>Näytön</strong> - Yhdistä signaali näyttöön
|
||||
Johto-tasolla visualisoidaksesi sen<br><br> PS: Huomasitko, että kuljetinanturi ja varasto näyttävät viimeisimmän esineen? Yritäpä saada se näkyviin näytölle!
|
||||
reward_constant_signal:
|
||||
title: Jatkuva Signaali
|
||||
desc: Avasit <strong>Jatkuvan Signaalin</strong> laitteen johtotasolla!
|
||||
@ -708,12 +719,13 @@ storyRewards:
|
||||
tavallisesti.<br><br> Mitä valitsetkin, muista pitää hauskaa!
|
||||
reward_wires_painter_and_levers:
|
||||
title: Johdot & Nelimaalain
|
||||
desc: "Avasit juuri <strong>Johtotason</strong>: Se on erillinen
|
||||
desc: >-
|
||||
Avasit juuri <strong>Johtotason</strong>: Se on erillinen
|
||||
taso tavallisen tason päällä ja sieltä löytyy useita uusia
|
||||
mekaniikkoja!<br><br> Aluksi avasin sinulle <strong>Nelimaalaimen</strong>
|
||||
- Yhdistä johtotasolla lokerot, joihin haluat maalia<br><br>
|
||||
Vaihtaaksesi johtotasolle, paina <strong>E</strong>. <br><br>
|
||||
PS: <strong>Aktivoi vinkit</strong> asetuksissa nähdäksesi Johdot-tutoriaalin!"
|
||||
PS: <strong>Aktivoi vinkit</strong> asetuksissa nähdäksesi Johdot-tutoriaalin!
|
||||
reward_filter:
|
||||
title: Esinesuodatin
|
||||
desc: Olet avannut <strong>Esinesuodattimen</strong>! Se lähettää esineet
|
||||
@ -878,8 +890,9 @@ settings:
|
||||
rangeSliderPercentage: <amount> %
|
||||
keybindings:
|
||||
title: Pikanäppäimet
|
||||
hint: "Vinkki: Muista käyttää CTRL, SHIFT ja ALT! Ne ottavat käyttöön erilaisia
|
||||
sijoitteluvaihtoehtoja."
|
||||
hint: >-
|
||||
Vinkki: Muista käyttää CTRL, SHIFT ja ALT! Ne ottavat käyttöön erilaisia
|
||||
sijoitteluvaihtoehtoja.
|
||||
resetKeybindings: Nollaa pikanäppäimet
|
||||
categoryLabels:
|
||||
general: Sovellus
|
||||
|
Loading…
Reference in New Issue
Block a user