Merge branch 'master' into patch-1
8
.editorconfig
Executable file
@ -0,0 +1,8 @@
|
|||||||
|
root = true
|
||||||
|
|
||||||
|
[{src, translations}/*]
|
||||||
|
end_of_line = crlf
|
||||||
|
insert_final_newline = true
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 4
|
||||||
|
charset = utf-8
|
||||||
18
.github/workflows/ci.yml
vendored
@ -35,19 +35,23 @@ jobs:
|
|||||||
cd gulp/
|
cd gulp/
|
||||||
yarn
|
yarn
|
||||||
cd ..
|
cd ..
|
||||||
|
|
||||||
- name: Lint
|
- name: Lint
|
||||||
run: |
|
run: |
|
||||||
yarn lint
|
yarn lint
|
||||||
|
|
||||||
- name: YAML Lint
|
|
||||||
uses: ibiqlik/action-yamllint@v1.0.0
|
|
||||||
with:
|
|
||||||
file_or_dir: translations/*.yaml
|
|
||||||
|
|
||||||
- name: TSLint
|
- name: TSLint
|
||||||
run: |
|
run: |
|
||||||
cd gulp
|
cd gulp
|
||||||
yarn gulp translations.fullBuild
|
yarn gulp translations.fullBuild
|
||||||
cd ..
|
cd ..
|
||||||
yarn tslint
|
yarn tslint
|
||||||
|
|
||||||
|
yaml-lint:
|
||||||
|
name: yaml-lint
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout repo
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
- name: YAML Lint
|
||||||
|
uses: ibiqlik/action-yamllint@v1.0.0
|
||||||
|
with:
|
||||||
|
file_or_dir: translations/*.yaml
|
||||||
|
|||||||
66
.gitignore
vendored
@ -15,34 +15,11 @@ pids
|
|||||||
*.seed
|
*.seed
|
||||||
*.pid.lock
|
*.pid.lock
|
||||||
|
|
||||||
# Directory for instrumented libs generated by jscoverage/JSCover
|
|
||||||
lib-cov
|
|
||||||
|
|
||||||
# Coverage directory used by tools like istanbul
|
|
||||||
coverage
|
|
||||||
*.lcov
|
|
||||||
|
|
||||||
# nyc test coverage
|
|
||||||
.nyc_output
|
|
||||||
|
|
||||||
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
|
|
||||||
.grunt
|
|
||||||
|
|
||||||
# Bower dependency directory (https://bower.io/)
|
|
||||||
bower_components
|
|
||||||
|
|
||||||
# node-waf configuration
|
|
||||||
.lock-wscript
|
|
||||||
|
|
||||||
# Compiled binary addons (https://nodejs.org/api/addons.html)
|
# Compiled binary addons (https://nodejs.org/api/addons.html)
|
||||||
build/Release
|
build/Release
|
||||||
|
|
||||||
# Dependency directories
|
# Dependency directories
|
||||||
node_modules/
|
node_modules/
|
||||||
jspm_packages/
|
|
||||||
|
|
||||||
# TypeScript v1 declaration files
|
|
||||||
typings/
|
|
||||||
|
|
||||||
# TypeScript cache
|
# TypeScript cache
|
||||||
*.tsbuildinfo
|
*.tsbuildinfo
|
||||||
@ -53,18 +30,9 @@ typings/
|
|||||||
# Optional eslint cache
|
# Optional eslint cache
|
||||||
.eslintcache
|
.eslintcache
|
||||||
|
|
||||||
# Microbundle cache
|
|
||||||
.rpt2_cache/
|
|
||||||
.rts2_cache_cjs/
|
|
||||||
.rts2_cache_es/
|
|
||||||
.rts2_cache_umd/
|
|
||||||
|
|
||||||
# Optional REPL history
|
# Optional REPL history
|
||||||
.node_repl_history
|
.node_repl_history
|
||||||
|
|
||||||
# Output of 'npm pack'
|
|
||||||
*.tgz
|
|
||||||
|
|
||||||
# Yarn Integrity file
|
# Yarn Integrity file
|
||||||
.yarn-integrity
|
.yarn-integrity
|
||||||
|
|
||||||
@ -72,41 +40,11 @@ typings/
|
|||||||
.env
|
.env
|
||||||
.env.test
|
.env.test
|
||||||
|
|
||||||
# parcel-bundler cache (https://parceljs.org/)
|
|
||||||
.cache
|
|
||||||
|
|
||||||
# Next.js build output
|
|
||||||
.next
|
|
||||||
|
|
||||||
# Nuxt.js build / generate output
|
|
||||||
.nuxt
|
|
||||||
dist
|
|
||||||
|
|
||||||
# Gatsby files
|
|
||||||
.cache/
|
|
||||||
# Comment in the public line in if your project uses Gatsby and *not* Next.js
|
|
||||||
# https://nextjs.org/blog/next-9-1#public-directory-support
|
|
||||||
# public
|
|
||||||
|
|
||||||
# vuepress build output
|
|
||||||
.vuepress/dist
|
|
||||||
|
|
||||||
# Serverless directories
|
|
||||||
.serverless/
|
|
||||||
|
|
||||||
# FuseBox cache
|
|
||||||
.fusebox/
|
|
||||||
|
|
||||||
# DynamoDB Local files
|
|
||||||
.dynamodb/
|
|
||||||
|
|
||||||
# TernJS port file
|
|
||||||
.tern-port
|
|
||||||
|
|
||||||
|
|
||||||
# Buildfiles
|
# Buildfiles
|
||||||
build
|
build
|
||||||
|
res_built
|
||||||
|
|
||||||
|
gulp/runnable-texturepacker.jar
|
||||||
tmp_standalone_files
|
tmp_standalone_files
|
||||||
|
|
||||||
# Local config
|
# Local config
|
||||||
|
|||||||
@ -4,3 +4,4 @@ rules:
|
|||||||
line-length:
|
line-length:
|
||||||
level: warning
|
level: warning
|
||||||
max: 200
|
max: 200
|
||||||
|
document-start: disable
|
||||||
|
|||||||
31
Dockerfile
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
FROM node:12 as base
|
||||||
|
|
||||||
|
EXPOSE 3001 3005
|
||||||
|
|
||||||
|
WORKDIR /shapez.io
|
||||||
|
|
||||||
|
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||||
|
ffmpeg default-jre \
|
||||||
|
&& apt-get clean \
|
||||||
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
COPY package.json yarn.lock ./
|
||||||
|
RUN yarn
|
||||||
|
|
||||||
|
COPY gulp ./gulp
|
||||||
|
WORKDIR /shapez.io/gulp
|
||||||
|
RUN yarn
|
||||||
|
|
||||||
|
WORKDIR /shapez.io
|
||||||
|
COPY res ./res
|
||||||
|
COPY src/html ./src/html
|
||||||
|
COPY src/css ./src/css
|
||||||
|
COPY version ./version
|
||||||
|
COPY sync-translations.js ./
|
||||||
|
COPY translations ./translations
|
||||||
|
COPY src/js ./src/js
|
||||||
|
COPY res_raw ./res_raw
|
||||||
|
COPY .git ./.git
|
||||||
|
|
||||||
|
WORKDIR /shapez.io/gulp
|
||||||
|
ENTRYPOINT ["yarn", "gulp"]
|
||||||
@ -24,11 +24,12 @@ Your goal is to produce shapes by cutting, rotating, merging and painting parts
|
|||||||
|
|
||||||
- Make sure `ffmpeg` is on your path
|
- Make sure `ffmpeg` is on your path
|
||||||
- Install Node.js and Yarn
|
- Install Node.js and Yarn
|
||||||
|
- Install Java (required for textures)
|
||||||
- Run `yarn` in the root folder
|
- Run `yarn` in the root folder
|
||||||
- Cd into `gulp` folder
|
- Cd into `gulp` folder
|
||||||
- Run `yarn` and then `yarn gulp` - it should now open in your browser
|
- Run `yarn` and then `yarn gulp` - it should now open in your browser
|
||||||
|
|
||||||
**Notice**: This will produce a debug build with several debugging flags enabled. If you want to disable them, modify `config.js`.
|
**Notice**: This will produce a debug build with several debugging flags enabled. If you want to disable them, modify [`src/js/core/config.js`](src/js/core/config.js).
|
||||||
|
|
||||||
## Helping translate
|
## Helping translate
|
||||||
|
|
||||||
@ -114,8 +115,8 @@ This is a quick checklist, if a new building is added this points should be fulf
|
|||||||
|
|
||||||
### Assets
|
### Assets
|
||||||
|
|
||||||
For most assets I use Adobe Photoshop, you can find them in `assets/`.
|
For most assets I use Adobe Photoshop, you can find them <a href="//github.com/tobspr/shapez.io-artwork" target="_blank">here</a>.
|
||||||
|
|
||||||
You will need a <a href="https://www.codeandweb.com/texturepacker" target="_blank">Texture Packer</a> license in order to regenerate the atlas. If you don't have one but want to contribute assets, let me know and I might compile it for you. I'm currently switching to an open source solution but I can't give an estimate when that's done.
|
All assets will be automatically rebuilt into the atlas once changed (Thanks to dengr1065!)
|
||||||
|
|
||||||
<img src="https://i.imgur.com/W25Fkl0.png" alt="shapez.io Screenshot">
|
<img src="https://i.imgur.com/W25Fkl0.png" alt="shapez.io Screenshot">
|
||||||
|
|||||||
@ -1,3 +0,0 @@
|
|||||||
The artwork can be found here:
|
|
||||||
|
|
||||||
https://github.com/tobspr/shapez.io-artwork
|
|
||||||
@ -1,16 +1,16 @@
|
|||||||
{
|
{
|
||||||
"name": "electron",
|
"name": "electron",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"startDev": "electron --disable-direct-composition --in-process-gpu . --dev --local",
|
"startDev": "electron --disable-direct-composition --in-process-gpu . --dev --local",
|
||||||
"startDevGpu": "electron --enable-gpu-rasterization --enable-accelerated-2d-canvas --num-raster-threads=8 --enable-zero-copy . --dev --local",
|
"startDevGpu": "electron --enable-gpu-rasterization --enable-accelerated-2d-canvas --num-raster-threads=8 --enable-zero-copy . --dev --local",
|
||||||
"start": "electron --disable-direct-composition --in-process-gpu ."
|
"start": "electron --disable-direct-composition --in-process-gpu ."
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"electron": "^6.1.12"
|
"electron": "10.1.3"
|
||||||
},
|
},
|
||||||
"dependencies": {}
|
"dependencies": {}
|
||||||
}
|
}
|
||||||
|
|||||||
1533
electron/yarn.lock
3
gulp/.gitignore
vendored
@ -1,2 +1 @@
|
|||||||
additional_build_files
|
additional_build_files
|
||||||
steampipe
|
|
||||||
|
|||||||
127
gulp/atlas2json.js
Normal file
@ -0,0 +1,127 @@
|
|||||||
|
const { join, resolve } = require("path");
|
||||||
|
const { readFileSync, readdirSync, writeFileSync } = require("fs");
|
||||||
|
|
||||||
|
const suffixToScale = {
|
||||||
|
lq: "0.25",
|
||||||
|
mq: "0.5",
|
||||||
|
hq: "0.75"
|
||||||
|
};
|
||||||
|
|
||||||
|
function convert(srcDir) {
|
||||||
|
const full = resolve(srcDir);
|
||||||
|
const srcFiles = readdirSync(full)
|
||||||
|
.filter(n => n.endsWith(".atlas"))
|
||||||
|
.map(n => join(full, n));
|
||||||
|
|
||||||
|
for (const atlas of srcFiles) {
|
||||||
|
console.log(`Processing: ${atlas}`);
|
||||||
|
|
||||||
|
// Read all text, split it into line array
|
||||||
|
// and filter all empty lines
|
||||||
|
const lines = readFileSync(atlas, "utf-8")
|
||||||
|
.split("\n")
|
||||||
|
.filter(n => n.trim());
|
||||||
|
|
||||||
|
// Get source image name
|
||||||
|
const image = lines.shift();
|
||||||
|
const srcMeta = {};
|
||||||
|
|
||||||
|
// Read all metadata (supports only one page)
|
||||||
|
while (true) {
|
||||||
|
const kv = lines.shift().split(":");
|
||||||
|
if (kv.length != 2) {
|
||||||
|
lines.unshift(kv[0]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
srcMeta[kv[0]] = kv[1].trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
const frames = {};
|
||||||
|
let current = null;
|
||||||
|
|
||||||
|
lines.push("Dummy line to make it convert last frame");
|
||||||
|
|
||||||
|
for (const line of lines) {
|
||||||
|
if (!line.startsWith(" ")) {
|
||||||
|
// New frame, convert previous if it exists
|
||||||
|
if (current != null) {
|
||||||
|
let { name, rotate, xy, size, orig, offset, index } = current;
|
||||||
|
|
||||||
|
// Convert to arrays because Node.js doesn't
|
||||||
|
// support latest JS features
|
||||||
|
xy = xy.split(",").map(v => Number(v));
|
||||||
|
size = size.split(",").map(v => Number(v));
|
||||||
|
orig = orig.split(",").map(v => Number(v));
|
||||||
|
offset = offset.split(",").map(v => Number(v));
|
||||||
|
|
||||||
|
// GDX TexturePacker removes index suffixes
|
||||||
|
const indexSuff = index != -1 ? `_${index}` : "";
|
||||||
|
const isTrimmed = size != orig;
|
||||||
|
|
||||||
|
frames[`${name}${indexSuff}.png`] = {
|
||||||
|
// Bounds on atlas
|
||||||
|
frame: {
|
||||||
|
x: xy[0],
|
||||||
|
y: xy[1],
|
||||||
|
w: size[0],
|
||||||
|
h: size[1]
|
||||||
|
},
|
||||||
|
|
||||||
|
// Whether image was rotated
|
||||||
|
rotated: rotate == "true",
|
||||||
|
trimmed: isTrimmed,
|
||||||
|
|
||||||
|
// How is the image trimmed
|
||||||
|
spriteSourceSize: {
|
||||||
|
x: offset[0],
|
||||||
|
y: (orig[1] - size[1]) - offset[1],
|
||||||
|
w: size[0],
|
||||||
|
h: size[1]
|
||||||
|
},
|
||||||
|
|
||||||
|
sourceSize: {
|
||||||
|
w: orig[0],
|
||||||
|
h: orig[1]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Simple object that will hold other metadata
|
||||||
|
current = {
|
||||||
|
name: line
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
// Read and set current image metadata
|
||||||
|
const kv = line.split(":").map(v => v.trim());
|
||||||
|
current[kv[0]] = isNaN(Number(kv[1])) ? kv[1] : Number(kv[1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const atlasSize = srcMeta.size.split(",").map(v => Number(v));
|
||||||
|
const atlasScale = suffixToScale[atlas.match(/_(\w+)\.atlas$/)[1]];
|
||||||
|
|
||||||
|
const result = JSON.stringify({
|
||||||
|
frames,
|
||||||
|
meta: {
|
||||||
|
image,
|
||||||
|
format: srcMeta.format,
|
||||||
|
size: {
|
||||||
|
w: atlasSize[0],
|
||||||
|
h: atlasSize[1]
|
||||||
|
},
|
||||||
|
scale: atlasScale.toString()
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
writeFileSync(atlas.replace(".atlas", ".json"), result, {
|
||||||
|
encoding: "utf-8"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (require.main == module) {
|
||||||
|
convert(process.argv[2]);
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = { convert };
|
||||||
@ -8,23 +8,6 @@ const path = require("path");
|
|||||||
const deleteEmpty = require("delete-empty");
|
const deleteEmpty = require("delete-empty");
|
||||||
const execSync = require("child_process").execSync;
|
const execSync = require("child_process").execSync;
|
||||||
|
|
||||||
const lfsOutput = execSync("git lfs install", { encoding: "utf-8" });
|
|
||||||
if (!lfsOutput.toLowerCase().includes("git lfs initialized")) {
|
|
||||||
console.error(`
|
|
||||||
Git LFS is not installed, unable to build.
|
|
||||||
|
|
||||||
To install Git LFS on Linux:
|
|
||||||
- Arch:
|
|
||||||
sudo pacman -S git-lfs
|
|
||||||
- Debian/Ubuntu:
|
|
||||||
sudo apt install git-lfs
|
|
||||||
|
|
||||||
For other systems, see:
|
|
||||||
https://github.com/git-lfs/git-lfs/wiki/Installation
|
|
||||||
`);
|
|
||||||
process.exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Load other plugins dynamically
|
// Load other plugins dynamically
|
||||||
const $ = require("gulp-load-plugins")({
|
const $ = require("gulp-load-plugins")({
|
||||||
scope: ["devDependencies"],
|
scope: ["devDependencies"],
|
||||||
@ -44,8 +27,8 @@ const envVars = [
|
|||||||
"SHAPEZ_CLI_LIVE_FTP_PW",
|
"SHAPEZ_CLI_LIVE_FTP_PW",
|
||||||
"SHAPEZ_CLI_APPLE_ID",
|
"SHAPEZ_CLI_APPLE_ID",
|
||||||
"SHAPEZ_CLI_APPLE_CERT_NAME",
|
"SHAPEZ_CLI_APPLE_CERT_NAME",
|
||||||
"SHAPEZ_CLI_GITHUB_USER",
|
"SHAPEZ_CLI_GITHUB_USER",
|
||||||
"SHAPEZ_CLI_GITHUB_TOKEN",
|
"SHAPEZ_CLI_GITHUB_TOKEN",
|
||||||
];
|
];
|
||||||
|
|
||||||
for (let i = 0; i < envVars.length; ++i) {
|
for (let i = 0; i < envVars.length; ++i) {
|
||||||
@ -82,9 +65,9 @@ docs.gulptasksDocs($, gulp, buildFolder);
|
|||||||
const standalone = require("./standalone");
|
const standalone = require("./standalone");
|
||||||
standalone.gulptasksStandalone($, gulp, buildFolder);
|
standalone.gulptasksStandalone($, gulp, buildFolder);
|
||||||
|
|
||||||
const releaseUploader = require("./release-uploader");
|
const releaseUploader = require("./release-uploader");
|
||||||
releaseUploader.gulptasksReleaseUploader($, gulp, buildFolder);
|
releaseUploader.gulptasksReleaseUploader($, gulp, buildFolder);
|
||||||
|
|
||||||
const translations = require("./translations");
|
const translations = require("./translations");
|
||||||
translations.gulptasksTranslations($, gulp, buildFolder);
|
translations.gulptasksTranslations($, gulp, buildFolder);
|
||||||
|
|
||||||
@ -103,8 +86,16 @@ gulp.task("utils.cleanBuildTempFolder", () => {
|
|||||||
.src(path.join(__dirname, "..", "src", "js", "built-temp"), { read: false, allowEmpty: true })
|
.src(path.join(__dirname, "..", "src", "js", "built-temp"), { read: false, allowEmpty: true })
|
||||||
.pipe($.clean({ force: true }));
|
.pipe($.clean({ force: true }));
|
||||||
});
|
});
|
||||||
|
gulp.task("utils.cleanImageBuildFolder", () => {
|
||||||
|
return gulp
|
||||||
|
.src(path.join(__dirname, "res_built"), { read: false, allowEmpty: true })
|
||||||
|
.pipe($.clean({ force: true }));
|
||||||
|
});
|
||||||
|
|
||||||
gulp.task("utils.cleanup", gulp.series("utils.cleanBuildFolder", "utils.cleanBuildTempFolder"));
|
gulp.task(
|
||||||
|
"utils.cleanup",
|
||||||
|
gulp.series("utils.cleanBuildFolder", "utils.cleanImageBuildFolder", "utils.cleanBuildTempFolder")
|
||||||
|
);
|
||||||
|
|
||||||
// Requires no uncomitted files
|
// Requires no uncomitted files
|
||||||
gulp.task("utils.requireCleanWorkingTree", cb => {
|
gulp.task("utils.requireCleanWorkingTree", cb => {
|
||||||
@ -191,10 +182,12 @@ function serve({ standalone }) {
|
|||||||
);
|
);
|
||||||
|
|
||||||
// Watch resource files and copy them on change
|
// Watch resource files and copy them on change
|
||||||
|
gulp.watch(imgres.rawImageResourcesGlobs, gulp.series("imgres.buildAtlas"));
|
||||||
gulp.watch(imgres.nonImageResourcesGlobs, gulp.series("imgres.copyNonImageResources"));
|
gulp.watch(imgres.nonImageResourcesGlobs, gulp.series("imgres.copyNonImageResources"));
|
||||||
gulp.watch(imgres.imageResourcesGlobs, gulp.series("imgres.copyImageResources"));
|
gulp.watch(imgres.imageResourcesGlobs, gulp.series("imgres.copyImageResources"));
|
||||||
|
|
||||||
// Watch .atlas files and recompile the atlas on change
|
// Watch .atlas files and recompile the atlas on change
|
||||||
|
gulp.watch("../res_built/atlas/*.atlas", gulp.series("imgres.atlasToJson"));
|
||||||
gulp.watch("../res_built/atlas/*.json", gulp.series("imgres.atlas"));
|
gulp.watch("../res_built/atlas/*.json", gulp.series("imgres.atlas"));
|
||||||
|
|
||||||
// Watch the build folder and reload when anything changed
|
// Watch the build folder and reload when anything changed
|
||||||
@ -232,6 +225,8 @@ gulp.task(
|
|||||||
gulp.series(
|
gulp.series(
|
||||||
"utils.cleanup",
|
"utils.cleanup",
|
||||||
"utils.copyAdditionalBuildFiles",
|
"utils.copyAdditionalBuildFiles",
|
||||||
|
"imgres.buildAtlas",
|
||||||
|
"imgres.atlasToJson",
|
||||||
"imgres.atlas",
|
"imgres.atlas",
|
||||||
"sounds.dev",
|
"sounds.dev",
|
||||||
"imgres.copyImageResources",
|
"imgres.copyImageResources",
|
||||||
@ -247,12 +242,13 @@ gulp.task(
|
|||||||
"build.standalone.dev",
|
"build.standalone.dev",
|
||||||
gulp.series(
|
gulp.series(
|
||||||
"utils.cleanup",
|
"utils.cleanup",
|
||||||
|
"imgres.buildAtlas",
|
||||||
|
"imgres.atlasToJson",
|
||||||
"imgres.atlas",
|
"imgres.atlas",
|
||||||
"sounds.dev",
|
"sounds.dev",
|
||||||
"imgres.copyImageResources",
|
"imgres.copyImageResources",
|
||||||
"imgres.copyNonImageResources",
|
"imgres.copyNonImageResources",
|
||||||
"translations.fullBuild",
|
"translations.fullBuild",
|
||||||
"js.standalone-dev",
|
|
||||||
"css.dev",
|
"css.dev",
|
||||||
"html.standalone-dev"
|
"html.standalone-dev"
|
||||||
)
|
)
|
||||||
@ -306,17 +302,17 @@ gulp.task(
|
|||||||
gulp.series("utils.cleanup", "step.standalone-prod.all", "step.postbuild")
|
gulp.series("utils.cleanup", "step.standalone-prod.all", "step.postbuild")
|
||||||
);
|
);
|
||||||
|
|
||||||
// OS X build and release upload
|
// OS X build and release upload
|
||||||
gulp.task(
|
gulp.task(
|
||||||
"build.darwin64-prod",
|
"build.darwin64-prod",
|
||||||
gulp.series(
|
gulp.series(
|
||||||
"build.standalone-prod",
|
"build.standalone-prod",
|
||||||
"standalone.prepare",
|
"standalone.prepare",
|
||||||
"standalone.package.prod.darwin64",
|
"standalone.package.prod.darwin64",
|
||||||
"standalone.uploadRelease.darwin64"
|
"standalone.uploadRelease.darwin64"
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
// Deploying!
|
// Deploying!
|
||||||
gulp.task(
|
gulp.task(
|
||||||
"main.deploy.alpha",
|
"main.deploy.alpha",
|
||||||
|
|||||||
@ -1,5 +1,15 @@
|
|||||||
|
const { existsSync } = require("fs");
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
const path = require("path");
|
const path = require("path");
|
||||||
|
const atlasToJson = require("./atlas2json");
|
||||||
|
|
||||||
|
const execute = command =>
|
||||||
|
require("child_process").execSync(command, {
|
||||||
|
encoding: "utf-8",
|
||||||
|
});
|
||||||
|
|
||||||
|
// Globs for atlas resources
|
||||||
|
const rawImageResourcesGlobs = ["../res_raw/atlas.json", "../res_raw/**/*.png"];
|
||||||
|
|
||||||
// Globs for non-ui resources
|
// Globs for non-ui resources
|
||||||
const nonImageResourcesGlobs = ["../res/**/*.woff2", "../res/*.ico", "../res/**/*.webm"];
|
const nonImageResourcesGlobs = ["../res/**/*.woff2", "../res/*.ico", "../res/**/*.webm"];
|
||||||
@ -7,6 +17,9 @@ const nonImageResourcesGlobs = ["../res/**/*.woff2", "../res/*.ico", "../res/**/
|
|||||||
// Globs for ui resources
|
// Globs for ui resources
|
||||||
const imageResourcesGlobs = ["../res/**/*.png", "../res/**/*.svg", "../res/**/*.jpg", "../res/**/*.gif"];
|
const imageResourcesGlobs = ["../res/**/*.png", "../res/**/*.svg", "../res/**/*.jpg", "../res/**/*.gif"];
|
||||||
|
|
||||||
|
// Link to download LibGDX runnable-texturepacker.jar
|
||||||
|
const runnableTPSource = "https://libgdx.badlogicgames.com/ci/nightlies/runnables/runnable-texturepacker.jar";
|
||||||
|
|
||||||
function gulptasksImageResources($, gulp, buildFolder) {
|
function gulptasksImageResources($, gulp, buildFolder) {
|
||||||
// Lossless options
|
// Lossless options
|
||||||
const minifyImagesOptsLossless = () => [
|
const minifyImagesOptsLossless = () => [
|
||||||
@ -59,6 +72,54 @@ function gulptasksImageResources($, gulp, buildFolder) {
|
|||||||
|
|
||||||
/////////////// ATLAS /////////////////////
|
/////////////// ATLAS /////////////////////
|
||||||
|
|
||||||
|
gulp.task("imgres.buildAtlas", cb => {
|
||||||
|
const config = JSON.stringify("../res_raw/atlas.json");
|
||||||
|
const source = JSON.stringify("../res_raw");
|
||||||
|
const dest = JSON.stringify("../res_built/atlas");
|
||||||
|
|
||||||
|
try {
|
||||||
|
// First check whether Java is installed
|
||||||
|
execute("java -version");
|
||||||
|
// Now check and try downloading runnable-texturepacker.jar (22MB)
|
||||||
|
if (!existsSync("./runnable-texturepacker.jar")) {
|
||||||
|
const safeLink = JSON.stringify(runnableTPSource);
|
||||||
|
const commands = [
|
||||||
|
// linux/macos if installed
|
||||||
|
`wget -O runnable-texturepacker.jar ${safeLink}`,
|
||||||
|
// linux/macos, latest windows 10
|
||||||
|
`curl -o runnable-texturepacker.jar ${safeLink}`,
|
||||||
|
// windows 10 / updated windows 7+
|
||||||
|
"powershell.exe -Command (new-object System.Net.WebClient)" +
|
||||||
|
`.DownloadFile(${safeLink.replace(/"/g, "'")}, 'runnable-texturepacker.jar')`,
|
||||||
|
// windows 7+, vulnerability exploit
|
||||||
|
`certutil.exe -urlcache -split -f ${safeLink} runnable-texturepacker.jar`,
|
||||||
|
];
|
||||||
|
|
||||||
|
while (commands.length) {
|
||||||
|
try {
|
||||||
|
execute(commands.shift());
|
||||||
|
break;
|
||||||
|
} catch {
|
||||||
|
if (!commands.length) {
|
||||||
|
throw new Error("Failed to download runnable-texturepacker.jar!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
execute(`java -jar runnable-texturepacker.jar ${source} ${dest} atlas0 ${config}`);
|
||||||
|
} catch {
|
||||||
|
console.warn("Building atlas failed. Java not found / unsupported version?");
|
||||||
|
}
|
||||||
|
cb();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Converts .atlas LibGDX files to JSON
|
||||||
|
gulp.task("imgres.atlasToJson", cb => {
|
||||||
|
atlasToJson.convert("../res_built/atlas");
|
||||||
|
cb();
|
||||||
|
});
|
||||||
|
|
||||||
// Copies the atlas to the final destination
|
// Copies the atlas to the final destination
|
||||||
gulp.task("imgres.atlas", () => {
|
gulp.task("imgres.atlas", () => {
|
||||||
return gulp.src(["../res_built/atlas/*.png"]).pipe(gulp.dest(resourcesDestFolder));
|
return gulp.src(["../res_built/atlas/*.png"]).pipe(gulp.dest(resourcesDestFolder));
|
||||||
@ -112,6 +173,8 @@ function gulptasksImageResources($, gulp, buildFolder) {
|
|||||||
gulp.task(
|
gulp.task(
|
||||||
"imgres.allOptimized",
|
"imgres.allOptimized",
|
||||||
gulp.parallel(
|
gulp.parallel(
|
||||||
|
"imgres.buildAtlas",
|
||||||
|
"imgres.atlasToJson",
|
||||||
"imgres.atlasOptimized",
|
"imgres.atlasOptimized",
|
||||||
"imgres.copyNonImageResources",
|
"imgres.copyNonImageResources",
|
||||||
"imgres.copyImageResourcesOptimized"
|
"imgres.copyImageResourcesOptimized"
|
||||||
@ -135,6 +198,7 @@ function gulptasksImageResources($, gulp, buildFolder) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
|
rawImageResourcesGlobs,
|
||||||
nonImageResourcesGlobs,
|
nonImageResourcesGlobs,
|
||||||
imageResourcesGlobs,
|
imageResourcesGlobs,
|
||||||
gulptasksImageResources,
|
gulptasksImageResources,
|
||||||
|
|||||||
@ -47,6 +47,7 @@
|
|||||||
"serialize-error": "^3.0.0",
|
"serialize-error": "^3.0.0",
|
||||||
"strictdom": "^1.0.1",
|
"strictdom": "^1.0.1",
|
||||||
"string-replace-webpack-plugin": "^0.1.3",
|
"string-replace-webpack-plugin": "^0.1.3",
|
||||||
|
"strip-indent": "^3.0.0",
|
||||||
"terser-webpack-plugin": "^1.1.0",
|
"terser-webpack-plugin": "^1.1.0",
|
||||||
"through2": "^3.0.1",
|
"through2": "^3.0.1",
|
||||||
"uglify-template-string-loader": "^1.1.0",
|
"uglify-template-string-loader": "^1.1.0",
|
||||||
@ -66,7 +67,6 @@
|
|||||||
"babel-plugin-danger-remove-unused-import": "^1.1.2",
|
"babel-plugin-danger-remove-unused-import": "^1.1.2",
|
||||||
"css-mqpacker": "^7.0.0",
|
"css-mqpacker": "^7.0.0",
|
||||||
"cssnano": "^4.1.10",
|
"cssnano": "^4.1.10",
|
||||||
"postcss-critical-split": "^2.5.3",
|
|
||||||
"electron-packager": "^14.0.6",
|
"electron-packager": "^14.0.6",
|
||||||
"faster.js": "^1.1.0",
|
"faster.js": "^1.1.0",
|
||||||
"glob": "^7.1.3",
|
"glob": "^7.1.3",
|
||||||
@ -99,6 +99,7 @@
|
|||||||
"jimp": "^0.6.1",
|
"jimp": "^0.6.1",
|
||||||
"js-yaml": "^3.13.1",
|
"js-yaml": "^3.13.1",
|
||||||
"postcss-assets": "^5.0.0",
|
"postcss-assets": "^5.0.0",
|
||||||
|
"postcss-critical-split": "^2.5.3",
|
||||||
"postcss-preset-env": "^6.5.0",
|
"postcss-preset-env": "^6.5.0",
|
||||||
"postcss-round-subpixels": "^1.2.0",
|
"postcss-round-subpixels": "^1.2.0",
|
||||||
"postcss-unprefix": "^2.1.3",
|
"postcss-unprefix": "^2.1.3",
|
||||||
|
|||||||
@ -1,9 +1,10 @@
|
|||||||
require('colors');
|
require("colors");
|
||||||
const packager = require("electron-packager");
|
const packager = require("electron-packager");
|
||||||
const path = require("path");
|
const path = require("path");
|
||||||
const { getVersion } = require("./buildutils");
|
const { getVersion } = require("./buildutils");
|
||||||
const fs = require("fs");
|
const fs = require("fs");
|
||||||
const fse = require("fs-extra");
|
const fse = require("fs-extra");
|
||||||
|
const buildutils = require("./buildutils");
|
||||||
const execSync = require("child_process").execSync;
|
const execSync = require("child_process").execSync;
|
||||||
|
|
||||||
function gulptasksStandalone($, gulp) {
|
function gulptasksStandalone($, gulp) {
|
||||||
@ -47,6 +48,20 @@ function gulptasksStandalone($, gulp) {
|
|||||||
cb();
|
cb();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
gulp.task("standalone.prepareVDF", cb => {
|
||||||
|
const hash = buildutils.getRevision();
|
||||||
|
|
||||||
|
const steampipeDir = path.join(__dirname, "steampipe", "scripts");
|
||||||
|
const templateContents = fs
|
||||||
|
.readFileSync(path.join(steampipeDir, "app.vdf.template"), { encoding: "utf-8" })
|
||||||
|
.toString();
|
||||||
|
|
||||||
|
const convertedContents = templateContents.replace("$DESC$", "Commit " + hash);
|
||||||
|
fs.writeFileSync(path.join(steampipeDir, "app.vdf"), convertedContents);
|
||||||
|
|
||||||
|
cb();
|
||||||
|
});
|
||||||
|
|
||||||
gulp.task("standalone.prepare.minifyCode", () => {
|
gulp.task("standalone.prepare.minifyCode", () => {
|
||||||
return gulp.src(path.join(electronBaseDir, "*.js")).pipe(gulp.dest(tempDestBuildDir));
|
return gulp.src(path.join(electronBaseDir, "*.js")).pipe(gulp.dest(tempDestBuildDir));
|
||||||
});
|
});
|
||||||
@ -101,20 +116,21 @@ function gulptasksStandalone($, gulp) {
|
|||||||
overwrite: true,
|
overwrite: true,
|
||||||
appBundleId: "io.shapez.standalone",
|
appBundleId: "io.shapez.standalone",
|
||||||
appCategoryType: "public.app-category.games",
|
appCategoryType: "public.app-category.games",
|
||||||
...(isRelease && platform === "darwin" && {
|
...(isRelease &&
|
||||||
osxSign: {
|
platform === "darwin" && {
|
||||||
identity: process.env.SHAPEZ_CLI_APPLE_CERT_NAME,
|
osxSign: {
|
||||||
"hardened-runtime": true,
|
"identity": process.env.SHAPEZ_CLI_APPLE_CERT_NAME,
|
||||||
hardenedRuntime: true,
|
"hardened-runtime": true,
|
||||||
entitlements: 'entitlements.plist',
|
"hardenedRuntime": true,
|
||||||
'entitlements-inherit': 'entitlements.plist',
|
"entitlements": "entitlements.plist",
|
||||||
'signature-flags': 'library'
|
"entitlements-inherit": "entitlements.plist",
|
||||||
},
|
"signature-flags": "library",
|
||||||
osxNotarize: {
|
},
|
||||||
appleId: process.env.SHAPEZ_CLI_APPLE_ID,
|
osxNotarize: {
|
||||||
appleIdPassword: "@keychain:SHAPEZ_CLI_APPLE_ID"
|
appleId: process.env.SHAPEZ_CLI_APPLE_ID,
|
||||||
}
|
appleIdPassword: "@keychain:SHAPEZ_CLI_APPLE_ID",
|
||||||
})
|
},
|
||||||
|
}),
|
||||||
}).then(
|
}).then(
|
||||||
appPaths => {
|
appPaths => {
|
||||||
console.log("Packages created:", appPaths);
|
console.log("Packages created:", appPaths);
|
||||||
@ -140,9 +156,13 @@ function gulptasksStandalone($, gulp) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (process.platform === "win32" && platform === "darwin") {
|
if (process.platform === "win32" && platform === "darwin") {
|
||||||
console.warn("Cross-building for macOS on Windows: dereferencing symlinks.\n".red +
|
console.warn(
|
||||||
"This will nearly double app size and make code signature invalid. Sorry!\n".red.bold +
|
"Cross-building for macOS on Windows: dereferencing symlinks.\n".red +
|
||||||
"For more information, see " + "https://github.com/electron/electron-packager/issues/71".underline);
|
"This will nearly double app size and make code signature invalid. Sorry!\n"
|
||||||
|
.red.bold +
|
||||||
|
"For more information, see " +
|
||||||
|
"https://github.com/electron/electron-packager/issues/71".underline
|
||||||
|
);
|
||||||
|
|
||||||
// Clear up framework folders
|
// Clear up framework folders
|
||||||
fs.writeFileSync(
|
fs.writeFileSync(
|
||||||
@ -195,7 +215,9 @@ function gulptasksStandalone($, gulp) {
|
|||||||
gulp.task("standalone.package.prod.linux64", cb => packageStandalone("linux", "x64", cb));
|
gulp.task("standalone.package.prod.linux64", cb => packageStandalone("linux", "x64", cb));
|
||||||
gulp.task("standalone.package.prod.linux32", cb => packageStandalone("linux", "ia32", cb));
|
gulp.task("standalone.package.prod.linux32", cb => packageStandalone("linux", "ia32", cb));
|
||||||
gulp.task("standalone.package.prod.darwin64", cb => packageStandalone("darwin", "x64", cb));
|
gulp.task("standalone.package.prod.darwin64", cb => packageStandalone("darwin", "x64", cb));
|
||||||
gulp.task("standalone.package.prod.darwin64.unsigned", cb => packageStandalone("darwin", "x64", cb, false));
|
gulp.task("standalone.package.prod.darwin64.unsigned", cb =>
|
||||||
|
packageStandalone("darwin", "x64", cb, false)
|
||||||
|
);
|
||||||
|
|
||||||
gulp.task(
|
gulp.task(
|
||||||
"standalone.package.prod",
|
"standalone.package.prod",
|
||||||
|
|||||||
2
gulp/steampipe/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
steamtemp
|
||||||
|
app.vdf
|
||||||
15
gulp/steampipe/scripts/app.vdf.template
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
"appbuild"
|
||||||
|
{
|
||||||
|
"appid" "1318690"
|
||||||
|
"desc" "$DESC$"
|
||||||
|
"buildoutput" "C:\work\shapez\shapez.io\gulp\steampipe\steamtemp"
|
||||||
|
"contentroot" ""
|
||||||
|
"setlive" ""
|
||||||
|
"preview" "0"
|
||||||
|
"local" ""
|
||||||
|
"depots"
|
||||||
|
{
|
||||||
|
"1318691" "C:\work\shapez\shapez.io\gulp\steampipe\scripts\windows.vdf"
|
||||||
|
"1318692" "C:\work\shapez\shapez.io\gulp\steampipe\scripts\linux.vdf"
|
||||||
|
}
|
||||||
|
}
|
||||||
12
gulp/steampipe/scripts/linux.vdf
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
"DepotBuildConfig"
|
||||||
|
{
|
||||||
|
"DepotID" "1318692"
|
||||||
|
"contentroot" "C:\work\shapez\shapez.io\tmp_standalone_files\shapez.io-standalone-linux-x64"
|
||||||
|
"FileMapping"
|
||||||
|
{
|
||||||
|
"LocalPath" "*"
|
||||||
|
"DepotPath" "."
|
||||||
|
"recursive" "1"
|
||||||
|
}
|
||||||
|
"FileExclusion" "*.pdb"
|
||||||
|
}
|
||||||
12
gulp/steampipe/scripts/windows.vdf
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
"DepotBuildConfig"
|
||||||
|
{
|
||||||
|
"DepotID" "1318691"
|
||||||
|
"contentroot" "C:\work\shapez\shapez.io\tmp_standalone_files\shapez.io-standalone-win32-x64"
|
||||||
|
"FileMapping"
|
||||||
|
{
|
||||||
|
"LocalPath" "*"
|
||||||
|
"DepotPath" "."
|
||||||
|
"recursive" "1"
|
||||||
|
}
|
||||||
|
"FileExclusion" "*.pdb"
|
||||||
|
}
|
||||||
4
gulp/steampipe/upload.bat
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
@echo off
|
||||||
|
cmd /c gulp standalone.prepareVDF
|
||||||
|
steamcmd +login %STEAM_UPLOAD_SHAPEZ_ID% %STEAM_UPLOAD_SHAPEZ_USER% +run_app_build %cd%/scripts/app.vdf +quit
|
||||||
|
start https://partner.steamgames.com/apps/builds/1318690
|
||||||
@ -1,22 +1,89 @@
|
|||||||
const path = require("path");
|
const path = require("path");
|
||||||
|
const fs = require("fs");
|
||||||
const yaml = require("gulp-yaml");
|
const gulpYaml = require("gulp-yaml");
|
||||||
|
const YAML = require("yaml");
|
||||||
const translationsSourceDir = path.join(__dirname, "..", "translations");
|
const stripIndent = require("strip-indent");
|
||||||
const translationsJsonDir = path.join(__dirname, "..", "src", "js", "built-temp");
|
const trim = require("trim");
|
||||||
|
|
||||||
function gulptasksTranslations($, gulp) {
|
const translationsSourceDir = path.join(__dirname, "..", "translations");
|
||||||
gulp.task("translations.convertToJson", () => {
|
const translationsJsonDir = path.join(__dirname, "..", "src", "js", "built-temp");
|
||||||
return gulp
|
|
||||||
.src(path.join(translationsSourceDir, "*.yaml"))
|
function gulptasksTranslations($, gulp) {
|
||||||
.pipe($.plumber())
|
gulp.task("translations.convertToJson", () => {
|
||||||
.pipe(yaml({ space: 2, safe: true }))
|
return gulp
|
||||||
.pipe(gulp.dest(translationsJsonDir));
|
.src(path.join(translationsSourceDir, "*.yaml"))
|
||||||
});
|
.pipe($.plumber())
|
||||||
|
.pipe(gulpYaml({ space: 2, safe: true }))
|
||||||
gulp.task("translations.fullBuild", gulp.series("translations.convertToJson"));
|
.pipe(gulp.dest(translationsJsonDir));
|
||||||
}
|
});
|
||||||
|
|
||||||
module.exports = {
|
gulp.task("translations.fullBuild", gulp.series("translations.convertToJson"));
|
||||||
gulptasksTranslations,
|
|
||||||
};
|
gulp.task("translations.prepareSteamPage", cb => {
|
||||||
|
const files = fs.readdirSync(translationsSourceDir);
|
||||||
|
|
||||||
|
files
|
||||||
|
.filter(name => name.endsWith(".yaml"))
|
||||||
|
.forEach(fname => {
|
||||||
|
const languageName = fname.replace(".yaml", "");
|
||||||
|
const abspath = path.join(translationsSourceDir, fname);
|
||||||
|
|
||||||
|
const destpath = path.join(translationsSourceDir, "tmp", languageName + "-store.txt");
|
||||||
|
|
||||||
|
const contents = fs.readFileSync(abspath, { encoding: "utf-8" });
|
||||||
|
const data = YAML.parse(contents);
|
||||||
|
|
||||||
|
const storePage = data.steamPage;
|
||||||
|
|
||||||
|
const content = `
|
||||||
|
[img]{STEAM_APP_IMAGE}/extras/store_page_gif.gif[/img]
|
||||||
|
|
||||||
|
${storePage.intro.replace(/\n/gi, "\n\n")}
|
||||||
|
|
||||||
|
[h2]${storePage.title_advantages}[/h2]
|
||||||
|
|
||||||
|
[list]
|
||||||
|
${storePage.advantages
|
||||||
|
.map(x => "[*] " + x.replace(/<b>/, "[b]").replace(/<\/b>/, "[/b]"))
|
||||||
|
.join("\n")}
|
||||||
|
[/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")), {
|
||||||
|
encoding: "utf-8",
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
cb();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
gulptasksTranslations,
|
||||||
|
};
|
||||||
|
|||||||
@ -8198,6 +8198,11 @@ min-document@^2.19.0:
|
|||||||
dependencies:
|
dependencies:
|
||||||
dom-walk "^0.1.0"
|
dom-walk "^0.1.0"
|
||||||
|
|
||||||
|
min-indent@^1.0.0:
|
||||||
|
version "1.0.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/min-indent/-/min-indent-1.0.1.tgz#a63f681673b30571fbe8bc25686ae746eefa9869"
|
||||||
|
integrity sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==
|
||||||
|
|
||||||
minimalistic-assert@^1.0.0, minimalistic-assert@^1.0.1:
|
minimalistic-assert@^1.0.0, minimalistic-assert@^1.0.1:
|
||||||
version "1.0.1"
|
version "1.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7"
|
resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7"
|
||||||
@ -11945,6 +11950,13 @@ strip-indent@^1.0.1:
|
|||||||
dependencies:
|
dependencies:
|
||||||
get-stdin "^4.0.1"
|
get-stdin "^4.0.1"
|
||||||
|
|
||||||
|
strip-indent@^3.0.0:
|
||||||
|
version "3.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-3.0.0.tgz#c32e1cee940b6b3432c771bc2c54bcce73cd3001"
|
||||||
|
integrity sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==
|
||||||
|
dependencies:
|
||||||
|
min-indent "^1.0.0"
|
||||||
|
|
||||||
strip-json-comments@^2.0.1, strip-json-comments@~2.0.1:
|
strip-json-comments@^2.0.1, strip-json-comments@~2.0.1:
|
||||||
version "2.0.1"
|
version "2.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a"
|
resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a"
|
||||||
|
|||||||
BIN
res/ui/get_on_steam_with_price.png
Normal file
|
After Width: | Height: | Size: 33 KiB |
BIN
res/ui/memes/cat1.png
Normal file
|
After Width: | Height: | Size: 236 KiB |
2
res_built/.gitignore
vendored
@ -1,2 +0,0 @@
|
|||||||
# Ignore built sounds
|
|
||||||
sounds
|
|
||||||
|
Before Width: | Height: | Size: 1.3 MiB |
|
Before Width: | Height: | Size: 286 KiB |
|
Before Width: | Height: | Size: 723 KiB |
22
res_raw/atlas.json
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
{
|
||||||
|
"pot": true,
|
||||||
|
"paddingX": 2,
|
||||||
|
"paddingY": 2,
|
||||||
|
"edgePadding": true,
|
||||||
|
"rotation": false,
|
||||||
|
"maxWidth": 2048,
|
||||||
|
"useIndexes": false,
|
||||||
|
"alphaThreshold": 1,
|
||||||
|
"maxHeight": 2048,
|
||||||
|
"stripWhitespaceX": true,
|
||||||
|
"stripWhitespaceY": true,
|
||||||
|
"duplicatePadding": true,
|
||||||
|
"alias": true,
|
||||||
|
"fast": false,
|
||||||
|
"limitMemory": false,
|
||||||
|
"combineSubdirectories": true,
|
||||||
|
"flattenPaths": false,
|
||||||
|
"bleedIterations": 4,
|
||||||
|
"scale": [0.25, 0.5, 0.75],
|
||||||
|
"scaleSuffix": ["_lq", "_mq", "_hq"]
|
||||||
|
}
|
||||||
@ -1,623 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<data version="1.0">
|
|
||||||
<struct type="Settings">
|
|
||||||
<key>fileFormatVersion</key>
|
|
||||||
<int>4</int>
|
|
||||||
<key>texturePackerVersion</key>
|
|
||||||
<string>5.4.0</string>
|
|
||||||
<key>autoSDSettings</key>
|
|
||||||
<array>
|
|
||||||
<struct type="AutoSDSettings">
|
|
||||||
<key>scale</key>
|
|
||||||
<double>0.75</double>
|
|
||||||
<key>extension</key>
|
|
||||||
<string>_hq</string>
|
|
||||||
<key>spriteFilter</key>
|
|
||||||
<string></string>
|
|
||||||
<key>acceptFractionalValues</key>
|
|
||||||
<true/>
|
|
||||||
<key>maxTextureSize</key>
|
|
||||||
<QSize>
|
|
||||||
<key>width</key>
|
|
||||||
<int>2048</int>
|
|
||||||
<key>height</key>
|
|
||||||
<int>2048</int>
|
|
||||||
</QSize>
|
|
||||||
</struct>
|
|
||||||
<struct type="AutoSDSettings">
|
|
||||||
<key>scale</key>
|
|
||||||
<double>0.5</double>
|
|
||||||
<key>extension</key>
|
|
||||||
<string>_mq</string>
|
|
||||||
<key>spriteFilter</key>
|
|
||||||
<string></string>
|
|
||||||
<key>acceptFractionalValues</key>
|
|
||||||
<true/>
|
|
||||||
<key>maxTextureSize</key>
|
|
||||||
<QSize>
|
|
||||||
<key>width</key>
|
|
||||||
<int>2048</int>
|
|
||||||
<key>height</key>
|
|
||||||
<int>2048</int>
|
|
||||||
</QSize>
|
|
||||||
</struct>
|
|
||||||
<struct type="AutoSDSettings">
|
|
||||||
<key>scale</key>
|
|
||||||
<double>0.25</double>
|
|
||||||
<key>extension</key>
|
|
||||||
<string>_lq</string>
|
|
||||||
<key>spriteFilter</key>
|
|
||||||
<string></string>
|
|
||||||
<key>acceptFractionalValues</key>
|
|
||||||
<true/>
|
|
||||||
<key>maxTextureSize</key>
|
|
||||||
<QSize>
|
|
||||||
<key>width</key>
|
|
||||||
<int>2048</int>
|
|
||||||
<key>height</key>
|
|
||||||
<int>2048</int>
|
|
||||||
</QSize>
|
|
||||||
</struct>
|
|
||||||
</array>
|
|
||||||
<key>allowRotation</key>
|
|
||||||
<false/>
|
|
||||||
<key>shapeDebug</key>
|
|
||||||
<false/>
|
|
||||||
<key>dpi</key>
|
|
||||||
<uint>72</uint>
|
|
||||||
<key>dataFormat</key>
|
|
||||||
<string>json</string>
|
|
||||||
<key>textureFileName</key>
|
|
||||||
<filename></filename>
|
|
||||||
<key>flipPVR</key>
|
|
||||||
<false/>
|
|
||||||
<key>pvrCompressionQuality</key>
|
|
||||||
<enum type="SettingsBase::PvrCompressionQuality">PVR_QUALITY_NORMAL</enum>
|
|
||||||
<key>atfCompressData</key>
|
|
||||||
<false/>
|
|
||||||
<key>mipMapMinSize</key>
|
|
||||||
<uint>32768</uint>
|
|
||||||
<key>etc1CompressionQuality</key>
|
|
||||||
<enum type="SettingsBase::Etc1CompressionQuality">ETC1_QUALITY_LOW_PERCEPTUAL</enum>
|
|
||||||
<key>etc2CompressionQuality</key>
|
|
||||||
<enum type="SettingsBase::Etc2CompressionQuality">ETC2_QUALITY_LOW_PERCEPTUAL</enum>
|
|
||||||
<key>dxtCompressionMode</key>
|
|
||||||
<enum type="SettingsBase::DxtCompressionMode">DXT_PERCEPTUAL</enum>
|
|
||||||
<key>jxrColorFormat</key>
|
|
||||||
<enum type="SettingsBase::JpegXrColorMode">JXR_YUV444</enum>
|
|
||||||
<key>jxrTrimFlexBits</key>
|
|
||||||
<uint>0</uint>
|
|
||||||
<key>jxrCompressionLevel</key>
|
|
||||||
<uint>0</uint>
|
|
||||||
<key>ditherType</key>
|
|
||||||
<enum type="SettingsBase::DitherType">NearestNeighbour</enum>
|
|
||||||
<key>backgroundColor</key>
|
|
||||||
<uint>0</uint>
|
|
||||||
<key>libGdx</key>
|
|
||||||
<struct type="LibGDX">
|
|
||||||
<key>filtering</key>
|
|
||||||
<struct type="LibGDXFiltering">
|
|
||||||
<key>x</key>
|
|
||||||
<enum type="LibGDXFiltering::Filtering">Linear</enum>
|
|
||||||
<key>y</key>
|
|
||||||
<enum type="LibGDXFiltering::Filtering">Linear</enum>
|
|
||||||
</struct>
|
|
||||||
</struct>
|
|
||||||
<key>shapePadding</key>
|
|
||||||
<uint>2</uint>
|
|
||||||
<key>jpgQuality</key>
|
|
||||||
<uint>80</uint>
|
|
||||||
<key>pngOptimizationLevel</key>
|
|
||||||
<uint>0</uint>
|
|
||||||
<key>webpQualityLevel</key>
|
|
||||||
<uint>101</uint>
|
|
||||||
<key>textureSubPath</key>
|
|
||||||
<string></string>
|
|
||||||
<key>atfFormats</key>
|
|
||||||
<string></string>
|
|
||||||
<key>textureFormat</key>
|
|
||||||
<enum type="SettingsBase::TextureFormat">png</enum>
|
|
||||||
<key>borderPadding</key>
|
|
||||||
<uint>4</uint>
|
|
||||||
<key>maxTextureSize</key>
|
|
||||||
<QSize>
|
|
||||||
<key>width</key>
|
|
||||||
<int>2048</int>
|
|
||||||
<key>height</key>
|
|
||||||
<int>2048</int>
|
|
||||||
</QSize>
|
|
||||||
<key>fixedTextureSize</key>
|
|
||||||
<QSize>
|
|
||||||
<key>width</key>
|
|
||||||
<int>-1</int>
|
|
||||||
<key>height</key>
|
|
||||||
<int>-1</int>
|
|
||||||
</QSize>
|
|
||||||
<key>algorithmSettings</key>
|
|
||||||
<struct type="AlgorithmSettings">
|
|
||||||
<key>algorithm</key>
|
|
||||||
<enum type="AlgorithmSettings::AlgorithmId">MaxRects</enum>
|
|
||||||
<key>freeSizeMode</key>
|
|
||||||
<enum type="AlgorithmSettings::AlgorithmFreeSizeMode">Best</enum>
|
|
||||||
<key>sizeConstraints</key>
|
|
||||||
<enum type="AlgorithmSettings::SizeConstraints">POT</enum>
|
|
||||||
<key>forceSquared</key>
|
|
||||||
<false/>
|
|
||||||
<key>maxRects</key>
|
|
||||||
<struct type="AlgorithmMaxRectsSettings">
|
|
||||||
<key>heuristic</key>
|
|
||||||
<enum type="AlgorithmMaxRectsSettings::Heuristic">Best</enum>
|
|
||||||
</struct>
|
|
||||||
<key>basic</key>
|
|
||||||
<struct type="AlgorithmBasicSettings">
|
|
||||||
<key>sortBy</key>
|
|
||||||
<enum type="AlgorithmBasicSettings::SortBy">Best</enum>
|
|
||||||
<key>order</key>
|
|
||||||
<enum type="AlgorithmBasicSettings::Order">Ascending</enum>
|
|
||||||
</struct>
|
|
||||||
<key>polygon</key>
|
|
||||||
<struct type="AlgorithmPolygonSettings">
|
|
||||||
<key>alignToGrid</key>
|
|
||||||
<uint>1</uint>
|
|
||||||
</struct>
|
|
||||||
</struct>
|
|
||||||
<key>dataFileNames</key>
|
|
||||||
<map type="GFileNameMap">
|
|
||||||
<key>data</key>
|
|
||||||
<struct type="DataFile">
|
|
||||||
<key>name</key>
|
|
||||||
<filename>../res_built/atlas/atlas{n}{v}.json</filename>
|
|
||||||
</struct>
|
|
||||||
</map>
|
|
||||||
<key>multiPack</key>
|
|
||||||
<true/>
|
|
||||||
<key>forceIdenticalLayout</key>
|
|
||||||
<false/>
|
|
||||||
<key>outputFormat</key>
|
|
||||||
<enum type="SettingsBase::OutputFormat">RGBA8888</enum>
|
|
||||||
<key>alphaHandling</key>
|
|
||||||
<enum type="SettingsBase::AlphaHandling">ClearTransparentPixels</enum>
|
|
||||||
<key>contentProtection</key>
|
|
||||||
<struct type="ContentProtection">
|
|
||||||
<key>key</key>
|
|
||||||
<string></string>
|
|
||||||
</struct>
|
|
||||||
<key>autoAliasEnabled</key>
|
|
||||||
<true/>
|
|
||||||
<key>trimSpriteNames</key>
|
|
||||||
<false/>
|
|
||||||
<key>prependSmartFolderName</key>
|
|
||||||
<true/>
|
|
||||||
<key>autodetectAnimations</key>
|
|
||||||
<true/>
|
|
||||||
<key>globalSpriteSettings</key>
|
|
||||||
<struct type="SpriteSettings">
|
|
||||||
<key>scale</key>
|
|
||||||
<double>1</double>
|
|
||||||
<key>scaleMode</key>
|
|
||||||
<enum type="ScaleMode">Smooth</enum>
|
|
||||||
<key>extrude</key>
|
|
||||||
<uint>2</uint>
|
|
||||||
<key>trimThreshold</key>
|
|
||||||
<uint>2</uint>
|
|
||||||
<key>trimMargin</key>
|
|
||||||
<uint>1</uint>
|
|
||||||
<key>trimMode</key>
|
|
||||||
<enum type="SpriteSettings::TrimMode">Trim</enum>
|
|
||||||
<key>tracerTolerance</key>
|
|
||||||
<int>200</int>
|
|
||||||
<key>heuristicMask</key>
|
|
||||||
<false/>
|
|
||||||
<key>defaultPivotPoint</key>
|
|
||||||
<point_f>0.5,0.5</point_f>
|
|
||||||
<key>writePivotPoints</key>
|
|
||||||
<false/>
|
|
||||||
</struct>
|
|
||||||
<key>individualSpriteSettings</key>
|
|
||||||
<map type="IndividualSpriteSettingsMap">
|
|
||||||
<key type="filename">sprites/belt/built/forward_0.png</key>
|
|
||||||
<key type="filename">sprites/belt/built/forward_1.png</key>
|
|
||||||
<key type="filename">sprites/belt/built/forward_10.png</key>
|
|
||||||
<key type="filename">sprites/belt/built/forward_11.png</key>
|
|
||||||
<key type="filename">sprites/belt/built/forward_12.png</key>
|
|
||||||
<key type="filename">sprites/belt/built/forward_13.png</key>
|
|
||||||
<key type="filename">sprites/belt/built/forward_2.png</key>
|
|
||||||
<key type="filename">sprites/belt/built/forward_3.png</key>
|
|
||||||
<key type="filename">sprites/belt/built/forward_4.png</key>
|
|
||||||
<key type="filename">sprites/belt/built/forward_5.png</key>
|
|
||||||
<key type="filename">sprites/belt/built/forward_6.png</key>
|
|
||||||
<key type="filename">sprites/belt/built/forward_7.png</key>
|
|
||||||
<key type="filename">sprites/belt/built/forward_8.png</key>
|
|
||||||
<key type="filename">sprites/belt/built/forward_9.png</key>
|
|
||||||
<key type="filename">sprites/belt/built/left_0.png</key>
|
|
||||||
<key type="filename">sprites/belt/built/left_1.png</key>
|
|
||||||
<key type="filename">sprites/belt/built/left_10.png</key>
|
|
||||||
<key type="filename">sprites/belt/built/left_11.png</key>
|
|
||||||
<key type="filename">sprites/belt/built/left_12.png</key>
|
|
||||||
<key type="filename">sprites/belt/built/left_13.png</key>
|
|
||||||
<key type="filename">sprites/belt/built/left_2.png</key>
|
|
||||||
<key type="filename">sprites/belt/built/left_3.png</key>
|
|
||||||
<key type="filename">sprites/belt/built/left_4.png</key>
|
|
||||||
<key type="filename">sprites/belt/built/left_5.png</key>
|
|
||||||
<key type="filename">sprites/belt/built/left_6.png</key>
|
|
||||||
<key type="filename">sprites/belt/built/left_7.png</key>
|
|
||||||
<key type="filename">sprites/belt/built/left_8.png</key>
|
|
||||||
<key type="filename">sprites/belt/built/left_9.png</key>
|
|
||||||
<key type="filename">sprites/belt/built/right_0.png</key>
|
|
||||||
<key type="filename">sprites/belt/built/right_1.png</key>
|
|
||||||
<key type="filename">sprites/belt/built/right_10.png</key>
|
|
||||||
<key type="filename">sprites/belt/built/right_11.png</key>
|
|
||||||
<key type="filename">sprites/belt/built/right_12.png</key>
|
|
||||||
<key type="filename">sprites/belt/built/right_13.png</key>
|
|
||||||
<key type="filename">sprites/belt/built/right_2.png</key>
|
|
||||||
<key type="filename">sprites/belt/built/right_3.png</key>
|
|
||||||
<key type="filename">sprites/belt/built/right_4.png</key>
|
|
||||||
<key type="filename">sprites/belt/built/right_5.png</key>
|
|
||||||
<key type="filename">sprites/belt/built/right_6.png</key>
|
|
||||||
<key type="filename">sprites/belt/built/right_7.png</key>
|
|
||||||
<key type="filename">sprites/belt/built/right_8.png</key>
|
|
||||||
<key type="filename">sprites/belt/built/right_9.png</key>
|
|
||||||
<key type="filename">sprites/blueprints/analyzer.png</key>
|
|
||||||
<key type="filename">sprites/blueprints/balancer-merger-inverse.png</key>
|
|
||||||
<key type="filename">sprites/blueprints/balancer-merger.png</key>
|
|
||||||
<key type="filename">sprites/blueprints/balancer-splitter-inverse.png</key>
|
|
||||||
<key type="filename">sprites/blueprints/balancer-splitter.png</key>
|
|
||||||
<key type="filename">sprites/blueprints/belt_left.png</key>
|
|
||||||
<key type="filename">sprites/blueprints/belt_right.png</key>
|
|
||||||
<key type="filename">sprites/blueprints/belt_top.png</key>
|
|
||||||
<key type="filename">sprites/blueprints/comparator.png</key>
|
|
||||||
<key type="filename">sprites/blueprints/constant_signal.png</key>
|
|
||||||
<key type="filename">sprites/blueprints/display.png</key>
|
|
||||||
<key type="filename">sprites/blueprints/lever.png</key>
|
|
||||||
<key type="filename">sprites/blueprints/logic_gate-not.png</key>
|
|
||||||
<key type="filename">sprites/blueprints/logic_gate-or.png</key>
|
|
||||||
<key type="filename">sprites/blueprints/logic_gate-xor.png</key>
|
|
||||||
<key type="filename">sprites/blueprints/logic_gate.png</key>
|
|
||||||
<key type="filename">sprites/blueprints/miner-chainable.png</key>
|
|
||||||
<key type="filename">sprites/blueprints/miner.png</key>
|
|
||||||
<key type="filename">sprites/blueprints/reader.png</key>
|
|
||||||
<key type="filename">sprites/blueprints/rotater-ccw.png</key>
|
|
||||||
<key type="filename">sprites/blueprints/rotater-rotate180.png</key>
|
|
||||||
<key type="filename">sprites/blueprints/rotater.png</key>
|
|
||||||
<key type="filename">sprites/blueprints/transistor-mirrored.png</key>
|
|
||||||
<key type="filename">sprites/blueprints/transistor.png</key>
|
|
||||||
<key type="filename">sprites/blueprints/trash.png</key>
|
|
||||||
<key type="filename">sprites/blueprints/underground_belt_entry-tier2.png</key>
|
|
||||||
<key type="filename">sprites/blueprints/underground_belt_entry.png</key>
|
|
||||||
<key type="filename">sprites/blueprints/underground_belt_exit-tier2.png</key>
|
|
||||||
<key type="filename">sprites/blueprints/underground_belt_exit.png</key>
|
|
||||||
<key type="filename">sprites/blueprints/virtual_processor-painter.png</key>
|
|
||||||
<key type="filename">sprites/blueprints/virtual_processor-rotater.png</key>
|
|
||||||
<key type="filename">sprites/blueprints/virtual_processor-stacker.png</key>
|
|
||||||
<key type="filename">sprites/blueprints/virtual_processor-unstacker.png</key>
|
|
||||||
<key type="filename">sprites/blueprints/virtual_processor.png</key>
|
|
||||||
<key type="filename">sprites/blueprints/wire_tunnel.png</key>
|
|
||||||
<key type="filename">sprites/buildings/analyzer.png</key>
|
|
||||||
<key type="filename">sprites/buildings/balancer-merger-inverse.png</key>
|
|
||||||
<key type="filename">sprites/buildings/balancer-merger.png</key>
|
|
||||||
<key type="filename">sprites/buildings/balancer-splitter-inverse.png</key>
|
|
||||||
<key type="filename">sprites/buildings/balancer-splitter.png</key>
|
|
||||||
<key type="filename">sprites/buildings/comparator.png</key>
|
|
||||||
<key type="filename">sprites/buildings/constant_signal.png</key>
|
|
||||||
<key type="filename">sprites/buildings/display.png</key>
|
|
||||||
<key type="filename">sprites/buildings/lever.png</key>
|
|
||||||
<key type="filename">sprites/buildings/logic_gate-not.png</key>
|
|
||||||
<key type="filename">sprites/buildings/logic_gate-or.png</key>
|
|
||||||
<key type="filename">sprites/buildings/logic_gate-xor.png</key>
|
|
||||||
<key type="filename">sprites/buildings/logic_gate.png</key>
|
|
||||||
<key type="filename">sprites/buildings/miner-chainable.png</key>
|
|
||||||
<key type="filename">sprites/buildings/reader.png</key>
|
|
||||||
<key type="filename">sprites/buildings/rotater-ccw.png</key>
|
|
||||||
<key type="filename">sprites/buildings/rotater-rotate180.png</key>
|
|
||||||
<key type="filename">sprites/buildings/transistor-mirrored.png</key>
|
|
||||||
<key type="filename">sprites/buildings/transistor.png</key>
|
|
||||||
<key type="filename">sprites/buildings/underground_belt_entry-tier2.png</key>
|
|
||||||
<key type="filename">sprites/buildings/underground_belt_entry.png</key>
|
|
||||||
<key type="filename">sprites/buildings/underground_belt_exit-tier2.png</key>
|
|
||||||
<key type="filename">sprites/buildings/underground_belt_exit.png</key>
|
|
||||||
<key type="filename">sprites/buildings/virtual_processor-painter.png</key>
|
|
||||||
<key type="filename">sprites/buildings/virtual_processor-rotater.png</key>
|
|
||||||
<key type="filename">sprites/buildings/virtual_processor-stacker.png</key>
|
|
||||||
<key type="filename">sprites/buildings/virtual_processor-unstacker.png</key>
|
|
||||||
<key type="filename">sprites/buildings/virtual_processor.png</key>
|
|
||||||
<key type="filename">sprites/buildings/wire_tunnel.png</key>
|
|
||||||
<key type="filename">sprites/misc/reader_overlay.png</key>
|
|
||||||
<key type="filename">sprites/wires/lever_on.png</key>
|
|
||||||
<key type="filename">sprites/wires/sets/conflict_cross.png</key>
|
|
||||||
<key type="filename">sprites/wires/sets/conflict_forward.png</key>
|
|
||||||
<key type="filename">sprites/wires/sets/conflict_split.png</key>
|
|
||||||
<key type="filename">sprites/wires/sets/conflict_turn.png</key>
|
|
||||||
<key type="filename">sprites/wires/sets/first_cross.png</key>
|
|
||||||
<key type="filename">sprites/wires/sets/first_forward.png</key>
|
|
||||||
<key type="filename">sprites/wires/sets/first_split.png</key>
|
|
||||||
<key type="filename">sprites/wires/sets/first_turn.png</key>
|
|
||||||
<key type="filename">sprites/wires/sets/second_cross.png</key>
|
|
||||||
<key type="filename">sprites/wires/sets/second_forward.png</key>
|
|
||||||
<key type="filename">sprites/wires/sets/second_split.png</key>
|
|
||||||
<key type="filename">sprites/wires/sets/second_turn.png</key>
|
|
||||||
<struct type="IndividualSpriteSettings">
|
|
||||||
<key>pivotPoint</key>
|
|
||||||
<point_f>0.5,0.5</point_f>
|
|
||||||
<key>spriteScale</key>
|
|
||||||
<double>1</double>
|
|
||||||
<key>scale9Enabled</key>
|
|
||||||
<false/>
|
|
||||||
<key>scale9Borders</key>
|
|
||||||
<rect>48,48,96,96</rect>
|
|
||||||
<key>scale9Paddings</key>
|
|
||||||
<rect>48,48,96,96</rect>
|
|
||||||
<key>scale9FromFile</key>
|
|
||||||
<false/>
|
|
||||||
</struct>
|
|
||||||
<key type="filename">sprites/blueprints/balancer.png</key>
|
|
||||||
<key type="filename">sprites/blueprints/cutter.png</key>
|
|
||||||
<key type="filename">sprites/blueprints/filter.png</key>
|
|
||||||
<key type="filename">sprites/blueprints/mixer.png</key>
|
|
||||||
<key type="filename">sprites/blueprints/painter-mirrored.png</key>
|
|
||||||
<key type="filename">sprites/blueprints/painter.png</key>
|
|
||||||
<key type="filename">sprites/blueprints/stacker.png</key>
|
|
||||||
<key type="filename">sprites/buildings/balancer.png</key>
|
|
||||||
<key type="filename">sprites/buildings/filter.png</key>
|
|
||||||
<key type="filename">sprites/buildings/painter-mirrored.png</key>
|
|
||||||
<struct type="IndividualSpriteSettings">
|
|
||||||
<key>pivotPoint</key>
|
|
||||||
<point_f>0.5,0.5</point_f>
|
|
||||||
<key>spriteScale</key>
|
|
||||||
<double>1</double>
|
|
||||||
<key>scale9Enabled</key>
|
|
||||||
<false/>
|
|
||||||
<key>scale9Borders</key>
|
|
||||||
<rect>96,48,192,96</rect>
|
|
||||||
<key>scale9Paddings</key>
|
|
||||||
<rect>96,48,192,96</rect>
|
|
||||||
<key>scale9FromFile</key>
|
|
||||||
<false/>
|
|
||||||
</struct>
|
|
||||||
<key type="filename">sprites/blueprints/cutter-quad.png</key>
|
|
||||||
<key type="filename">sprites/blueprints/painter-quad.png</key>
|
|
||||||
<key type="filename">sprites/buildings/cutter-quad.png</key>
|
|
||||||
<key type="filename">sprites/buildings/painter-quad.png</key>
|
|
||||||
<struct type="IndividualSpriteSettings">
|
|
||||||
<key>pivotPoint</key>
|
|
||||||
<point_f>0.5,0.5</point_f>
|
|
||||||
<key>spriteScale</key>
|
|
||||||
<double>1</double>
|
|
||||||
<key>scale9Enabled</key>
|
|
||||||
<false/>
|
|
||||||
<key>scale9Borders</key>
|
|
||||||
<rect>192,48,384,96</rect>
|
|
||||||
<key>scale9Paddings</key>
|
|
||||||
<rect>192,48,384,96</rect>
|
|
||||||
<key>scale9FromFile</key>
|
|
||||||
<false/>
|
|
||||||
</struct>
|
|
||||||
<key type="filename">sprites/blueprints/painter-double.png</key>
|
|
||||||
<key type="filename">sprites/blueprints/storage.png</key>
|
|
||||||
<key type="filename">sprites/buildings/painter-double.png</key>
|
|
||||||
<key type="filename">sprites/buildings/storage.png</key>
|
|
||||||
<struct type="IndividualSpriteSettings">
|
|
||||||
<key>pivotPoint</key>
|
|
||||||
<point_f>0.5,0.5</point_f>
|
|
||||||
<key>spriteScale</key>
|
|
||||||
<double>1</double>
|
|
||||||
<key>scale9Enabled</key>
|
|
||||||
<false/>
|
|
||||||
<key>scale9Borders</key>
|
|
||||||
<rect>96,96,192,192</rect>
|
|
||||||
<key>scale9Paddings</key>
|
|
||||||
<rect>96,96,192,192</rect>
|
|
||||||
<key>scale9FromFile</key>
|
|
||||||
<false/>
|
|
||||||
</struct>
|
|
||||||
<key type="filename">sprites/buildings/belt_left.png</key>
|
|
||||||
<key type="filename">sprites/buildings/belt_right.png</key>
|
|
||||||
<key type="filename">sprites/buildings/belt_top.png</key>
|
|
||||||
<struct type="IndividualSpriteSettings">
|
|
||||||
<key>pivotPoint</key>
|
|
||||||
<point_f>0.5,0.5</point_f>
|
|
||||||
<key>spriteScale</key>
|
|
||||||
<double>1</double>
|
|
||||||
<key>scale9Enabled</key>
|
|
||||||
<false/>
|
|
||||||
<key>scale9Borders</key>
|
|
||||||
<rect>32,32,63,63</rect>
|
|
||||||
<key>scale9Paddings</key>
|
|
||||||
<rect>32,32,63,63</rect>
|
|
||||||
<key>scale9FromFile</key>
|
|
||||||
<false/>
|
|
||||||
</struct>
|
|
||||||
<key type="filename">sprites/buildings/cutter.png</key>
|
|
||||||
<key type="filename">sprites/buildings/mixer.png</key>
|
|
||||||
<key type="filename">sprites/buildings/painter.png</key>
|
|
||||||
<key type="filename">sprites/buildings/stacker.png</key>
|
|
||||||
<struct type="IndividualSpriteSettings">
|
|
||||||
<key>pivotPoint</key>
|
|
||||||
<point_f>0.5,0.5</point_f>
|
|
||||||
<key>spriteScale</key>
|
|
||||||
<double>1</double>
|
|
||||||
<key>scale9Enabled</key>
|
|
||||||
<false/>
|
|
||||||
<key>scale9Borders</key>
|
|
||||||
<rect>64,32,128,64</rect>
|
|
||||||
<key>scale9Paddings</key>
|
|
||||||
<rect>64,32,128,64</rect>
|
|
||||||
<key>scale9FromFile</key>
|
|
||||||
<false/>
|
|
||||||
</struct>
|
|
||||||
<key type="filename">sprites/buildings/hub.png</key>
|
|
||||||
<struct type="IndividualSpriteSettings">
|
|
||||||
<key>pivotPoint</key>
|
|
||||||
<point_f>0.5,0.5</point_f>
|
|
||||||
<key>spriteScale</key>
|
|
||||||
<double>1</double>
|
|
||||||
<key>scale9Enabled</key>
|
|
||||||
<false/>
|
|
||||||
<key>scale9Borders</key>
|
|
||||||
<rect>192,192,384,384</rect>
|
|
||||||
<key>scale9Paddings</key>
|
|
||||||
<rect>192,192,384,384</rect>
|
|
||||||
<key>scale9FromFile</key>
|
|
||||||
<false/>
|
|
||||||
</struct>
|
|
||||||
<key type="filename">sprites/buildings/miner.png</key>
|
|
||||||
<key type="filename">sprites/buildings/rotater.png</key>
|
|
||||||
<key type="filename">sprites/buildings/trash.png</key>
|
|
||||||
<key type="filename">sprites/misc/processor_disabled.png</key>
|
|
||||||
<key type="filename">sprites/misc/processor_disconnected.png</key>
|
|
||||||
<key type="filename">sprites/wires/logical_acceptor.png</key>
|
|
||||||
<key type="filename">sprites/wires/logical_ejector.png</key>
|
|
||||||
<key type="filename">sprites/wires/overlay_tile.png</key>
|
|
||||||
<struct type="IndividualSpriteSettings">
|
|
||||||
<key>pivotPoint</key>
|
|
||||||
<point_f>0.5,0.5</point_f>
|
|
||||||
<key>spriteScale</key>
|
|
||||||
<double>1</double>
|
|
||||||
<key>scale9Enabled</key>
|
|
||||||
<false/>
|
|
||||||
<key>scale9Borders</key>
|
|
||||||
<rect>32,32,64,64</rect>
|
|
||||||
<key>scale9Paddings</key>
|
|
||||||
<rect>32,32,64,64</rect>
|
|
||||||
<key>scale9FromFile</key>
|
|
||||||
<false/>
|
|
||||||
</struct>
|
|
||||||
<key type="filename">sprites/colors/blue.png</key>
|
|
||||||
<key type="filename">sprites/colors/cyan.png</key>
|
|
||||||
<key type="filename">sprites/colors/green.png</key>
|
|
||||||
<key type="filename">sprites/colors/purple.png</key>
|
|
||||||
<key type="filename">sprites/colors/red.png</key>
|
|
||||||
<key type="filename">sprites/colors/uncolored.png</key>
|
|
||||||
<key type="filename">sprites/colors/white.png</key>
|
|
||||||
<key type="filename">sprites/colors/yellow.png</key>
|
|
||||||
<struct type="IndividualSpriteSettings">
|
|
||||||
<key>pivotPoint</key>
|
|
||||||
<point_f>0.5,0.5</point_f>
|
|
||||||
<key>spriteScale</key>
|
|
||||||
<double>1</double>
|
|
||||||
<key>scale9Enabled</key>
|
|
||||||
<false/>
|
|
||||||
<key>scale9Borders</key>
|
|
||||||
<rect>18,18,36,36</rect>
|
|
||||||
<key>scale9Paddings</key>
|
|
||||||
<rect>18,18,36,36</rect>
|
|
||||||
<key>scale9FromFile</key>
|
|
||||||
<false/>
|
|
||||||
</struct>
|
|
||||||
<key type="filename">sprites/debug/acceptor_slot.png</key>
|
|
||||||
<key type="filename">sprites/debug/ejector_slot.png</key>
|
|
||||||
<key type="filename">sprites/misc/hub_direction_indicator.png</key>
|
|
||||||
<key type="filename">sprites/misc/waypoint.png</key>
|
|
||||||
<struct type="IndividualSpriteSettings">
|
|
||||||
<key>pivotPoint</key>
|
|
||||||
<point_f>0.5,0.5</point_f>
|
|
||||||
<key>spriteScale</key>
|
|
||||||
<double>1</double>
|
|
||||||
<key>scale9Enabled</key>
|
|
||||||
<false/>
|
|
||||||
<key>scale9Borders</key>
|
|
||||||
<rect>8,8,16,16</rect>
|
|
||||||
<key>scale9Paddings</key>
|
|
||||||
<rect>8,8,16,16</rect>
|
|
||||||
<key>scale9FromFile</key>
|
|
||||||
<false/>
|
|
||||||
</struct>
|
|
||||||
<key type="filename">sprites/misc/slot_bad_arrow.png</key>
|
|
||||||
<key type="filename">sprites/misc/slot_good_arrow.png</key>
|
|
||||||
<struct type="IndividualSpriteSettings">
|
|
||||||
<key>pivotPoint</key>
|
|
||||||
<point_f>0.5,0.5</point_f>
|
|
||||||
<key>spriteScale</key>
|
|
||||||
<double>1</double>
|
|
||||||
<key>scale9Enabled</key>
|
|
||||||
<false/>
|
|
||||||
<key>scale9Borders</key>
|
|
||||||
<rect>24,24,48,48</rect>
|
|
||||||
<key>scale9Paddings</key>
|
|
||||||
<rect>24,24,48,48</rect>
|
|
||||||
<key>scale9FromFile</key>
|
|
||||||
<false/>
|
|
||||||
</struct>
|
|
||||||
<key type="filename">sprites/misc/storage_overlay.png</key>
|
|
||||||
<struct type="IndividualSpriteSettings">
|
|
||||||
<key>pivotPoint</key>
|
|
||||||
<point_f>0.5,0.5</point_f>
|
|
||||||
<key>spriteScale</key>
|
|
||||||
<double>1</double>
|
|
||||||
<key>scale9Enabled</key>
|
|
||||||
<false/>
|
|
||||||
<key>scale9Borders</key>
|
|
||||||
<rect>44,22,89,43</rect>
|
|
||||||
<key>scale9Paddings</key>
|
|
||||||
<rect>44,22,89,43</rect>
|
|
||||||
<key>scale9FromFile</key>
|
|
||||||
<false/>
|
|
||||||
</struct>
|
|
||||||
<key type="filename">sprites/wires/boolean_false.png</key>
|
|
||||||
<key type="filename">sprites/wires/boolean_true.png</key>
|
|
||||||
<key type="filename">sprites/wires/network_conflict.png</key>
|
|
||||||
<key type="filename">sprites/wires/network_empty.png</key>
|
|
||||||
<key type="filename">sprites/wires/wires_preview.png</key>
|
|
||||||
<struct type="IndividualSpriteSettings">
|
|
||||||
<key>pivotPoint</key>
|
|
||||||
<point_f>0.5,0.5</point_f>
|
|
||||||
<key>spriteScale</key>
|
|
||||||
<double>1</double>
|
|
||||||
<key>scale9Enabled</key>
|
|
||||||
<false/>
|
|
||||||
<key>scale9Borders</key>
|
|
||||||
<rect>16,16,32,32</rect>
|
|
||||||
<key>scale9Paddings</key>
|
|
||||||
<rect>16,16,32,32</rect>
|
|
||||||
<key>scale9FromFile</key>
|
|
||||||
<false/>
|
|
||||||
</struct>
|
|
||||||
<key type="filename">sprites/wires/display/blue.png</key>
|
|
||||||
<key type="filename">sprites/wires/display/cyan.png</key>
|
|
||||||
<key type="filename">sprites/wires/display/green.png</key>
|
|
||||||
<key type="filename">sprites/wires/display/purple.png</key>
|
|
||||||
<key type="filename">sprites/wires/display/red.png</key>
|
|
||||||
<key type="filename">sprites/wires/display/white.png</key>
|
|
||||||
<key type="filename">sprites/wires/display/yellow.png</key>
|
|
||||||
<struct type="IndividualSpriteSettings">
|
|
||||||
<key>pivotPoint</key>
|
|
||||||
<point_f>0.5,0.5</point_f>
|
|
||||||
<key>spriteScale</key>
|
|
||||||
<double>1</double>
|
|
||||||
<key>scale9Enabled</key>
|
|
||||||
<false/>
|
|
||||||
<key>scale9Borders</key>
|
|
||||||
<rect>11,11,22,22</rect>
|
|
||||||
<key>scale9Paddings</key>
|
|
||||||
<rect>11,11,22,22</rect>
|
|
||||||
<key>scale9FromFile</key>
|
|
||||||
<false/>
|
|
||||||
</struct>
|
|
||||||
</map>
|
|
||||||
<key>fileList</key>
|
|
||||||
<array>
|
|
||||||
<filename>sprites</filename>
|
|
||||||
</array>
|
|
||||||
<key>ignoreFileList</key>
|
|
||||||
<array/>
|
|
||||||
<key>replaceList</key>
|
|
||||||
<array/>
|
|
||||||
<key>ignoredWarnings</key>
|
|
||||||
<array/>
|
|
||||||
<key>commonDivisorX</key>
|
|
||||||
<uint>1</uint>
|
|
||||||
<key>commonDivisorY</key>
|
|
||||||
<uint>1</uint>
|
|
||||||
<key>packNormalMaps</key>
|
|
||||||
<false/>
|
|
||||||
<key>autodetectNormalMaps</key>
|
|
||||||
<true/>
|
|
||||||
<key>normalMapFilter</key>
|
|
||||||
<string></string>
|
|
||||||
<key>normalMapSuffix</key>
|
|
||||||
<string></string>
|
|
||||||
<key>normalMapSheetFileName</key>
|
|
||||||
<filename></filename>
|
|
||||||
<key>exporterProperties</key>
|
|
||||||
<map type="ExporterProperties"/>
|
|
||||||
</struct>
|
|
||||||
</data>
|
|
||||||
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 17 KiB |
|
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 17 KiB |
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 21 KiB After Width: | Height: | Size: 17 KiB |
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 9.7 KiB After Width: | Height: | Size: 9.6 KiB |
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 9.5 KiB |
|
Before Width: | Height: | Size: 9.0 KiB After Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 9.0 KiB After Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 9.3 KiB |
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 9.0 KiB |
|
Before Width: | Height: | Size: 7.7 KiB After Width: | Height: | Size: 9.2 KiB |
|
Before Width: | Height: | Size: 9.8 KiB After Width: | Height: | Size: 9.6 KiB |
|
Before Width: | Height: | Size: 7.3 KiB After Width: | Height: | Size: 8.9 KiB |
|
Before Width: | Height: | Size: 9.7 KiB After Width: | Height: | Size: 9.4 KiB |
|
Before Width: | Height: | Size: 9.6 KiB After Width: | Height: | Size: 8.5 KiB |
23
src/css/ingame_hud/cat_memes.scss
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
#ingame_HUD_CatMemes {
|
||||||
|
position: absolute;
|
||||||
|
@include S(width, 150px);
|
||||||
|
@include S(height, 150px);
|
||||||
|
background: transparent center center / contain no-repeat;
|
||||||
|
|
||||||
|
right: 0;
|
||||||
|
@include S(bottom, 150px);
|
||||||
|
|
||||||
|
& {
|
||||||
|
/* @load-async */
|
||||||
|
background-image: uiResource("res/ui/memes/cat1.png") !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
@include InlineAnimation(0.5s ease-in-out) {
|
||||||
|
0% {
|
||||||
|
transform: translateX(100%);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
transform: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -17,13 +17,10 @@
|
|||||||
grid-template-rows: 1fr 1fr;
|
grid-template-rows: 1fr 1fr;
|
||||||
@include S(margin-bottom, 4px);
|
@include S(margin-bottom, 4px);
|
||||||
color: #333438;
|
color: #333438;
|
||||||
// text-shadow: #{D(1px)} #{D(1px)} 0 rgba(0, 10, 20, 0.2);
|
|
||||||
|
|
||||||
&.unpinable {
|
&.removable {
|
||||||
> canvas {
|
cursor: pointer;
|
||||||
cursor: pointer;
|
pointer-events: all;
|
||||||
pointer-events: all;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
> canvas {
|
> canvas {
|
||||||
@ -31,16 +28,9 @@
|
|||||||
@include S(height, 25px);
|
@include S(height, 25px);
|
||||||
grid-column: 1 / 2;
|
grid-column: 1 / 2;
|
||||||
grid-row: 1 / 3;
|
grid-row: 1 / 3;
|
||||||
pointer-events: all;
|
pointer-events: none;
|
||||||
transition: transform 0.1s ease-in-out;
|
|
||||||
transform-origin: D(2px) center;
|
|
||||||
will-change: transform;
|
|
||||||
position: relative;
|
|
||||||
z-index: 20;
|
z-index: 20;
|
||||||
&:hover {
|
position: relative;
|
||||||
transform: scale(2);
|
|
||||||
z-index: 21;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
> .amountLabel,
|
> .amountLabel,
|
||||||
|
|||||||
@ -16,6 +16,7 @@
|
|||||||
grid-template-rows: #{D(40px)};
|
grid-template-rows: #{D(40px)};
|
||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.lowerBar {
|
.lowerBar {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
display: flex;
|
display: flex;
|
||||||
@ -57,10 +58,7 @@
|
|||||||
@include S(margin, 0);
|
@include S(margin, 0);
|
||||||
@include S(width, 180px);
|
@include S(width, 180px);
|
||||||
@include S(height, 40px);
|
@include S(height, 40px);
|
||||||
& {
|
background: #171a23 center center / contain no-repeat;
|
||||||
/* @load-async */
|
|
||||||
background: #171a23 uiResource("get_on_steam.png") center center / contain no-repeat;
|
|
||||||
}
|
|
||||||
|
|
||||||
@include S(border-radius, $globalBorderRadius);
|
@include S(border-radius, $globalBorderRadius);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -53,6 +53,7 @@
|
|||||||
@import "ingame_hud/shape_viewer";
|
@import "ingame_hud/shape_viewer";
|
||||||
@import "ingame_hud/sandbox_controller";
|
@import "ingame_hud/sandbox_controller";
|
||||||
@import "ingame_hud/standalone_advantages";
|
@import "ingame_hud/standalone_advantages";
|
||||||
|
@import "ingame_hud/cat_memes";
|
||||||
|
|
||||||
// prettier-ignore
|
// prettier-ignore
|
||||||
$elements:
|
$elements:
|
||||||
@ -74,7 +75,7 @@ ingame_HUD_DebugInfo,
|
|||||||
ingame_HUD_EntityDebugger,
|
ingame_HUD_EntityDebugger,
|
||||||
ingame_HUD_InteractiveTutorial,
|
ingame_HUD_InteractiveTutorial,
|
||||||
ingame_HUD_TutorialHints,
|
ingame_HUD_TutorialHints,
|
||||||
ingame_HUD_buildings_toolbar,
|
ingame_HUD_BuildingsToolbar,
|
||||||
ingame_HUD_wires_toolbar,
|
ingame_HUD_wires_toolbar,
|
||||||
ingame_HUD_BlueprintPlacer,
|
ingame_HUD_BlueprintPlacer,
|
||||||
ingame_HUD_Waypoints_Hint,
|
ingame_HUD_Waypoints_Hint,
|
||||||
@ -93,7 +94,8 @@ ingame_HUD_ShapeViewer,
|
|||||||
ingame_HUD_StandaloneAdvantages,
|
ingame_HUD_StandaloneAdvantages,
|
||||||
ingame_HUD_UnlockNotification,
|
ingame_HUD_UnlockNotification,
|
||||||
ingame_HUD_SettingsMenu,
|
ingame_HUD_SettingsMenu,
|
||||||
ingame_HUD_ModalDialogs;
|
ingame_HUD_ModalDialogs,
|
||||||
|
ingame_HUD_CatMemes;
|
||||||
|
|
||||||
$zindex: 100;
|
$zindex: 100;
|
||||||
|
|
||||||
|
|||||||
@ -75,3 +75,17 @@ $languages: en, de, cs, da, et, es-419, fr, it, pt-BR, sv, tr, el, ru, uk, zh-TW
|
|||||||
background-image: uiResource("languages/#{$language}.svg") !important;
|
background-image: uiResource("languages/#{$language}.svg") !important;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
PRICE
|
||||||
|
*/
|
||||||
|
|
||||||
|
.steam_1_pr {
|
||||||
|
/* @load-async */
|
||||||
|
background-image: uiResource("get_on_steam_with_price.png") !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.steam_2_npr {
|
||||||
|
/* @load-async */
|
||||||
|
background-image: uiResource("get_on_steam.png") !important;
|
||||||
|
}
|
||||||
|
|||||||
@ -133,10 +133,7 @@
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
@include S(height, 40px);
|
@include S(height, 40px);
|
||||||
@include S(width, 180px);
|
@include S(width, 180px);
|
||||||
& {
|
background: #171a23 center center / contain no-repeat;
|
||||||
/* @load-async */
|
|
||||||
background: #171a23 uiResource("get_on_steam.png") center center / contain no-repeat;
|
|
||||||
}
|
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
display: block;
|
display: block;
|
||||||
text-indent: -999em;
|
text-indent: -999em;
|
||||||
|
|||||||
@ -29,6 +29,7 @@ import { MobileWarningState } from "./states/mobile_warning";
|
|||||||
import { PreloadState } from "./states/preload";
|
import { PreloadState } from "./states/preload";
|
||||||
import { SettingsState } from "./states/settings";
|
import { SettingsState } from "./states/settings";
|
||||||
import { ShapezGameAnalytics } from "./platform/browser/game_analytics";
|
import { ShapezGameAnalytics } from "./platform/browser/game_analytics";
|
||||||
|
import { RestrictionManager } from "./core/restriction_manager";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @typedef {import("./platform/game_analytics").GameAnalyticsInterface} GameAnalyticsInterface
|
* @typedef {import("./platform/game_analytics").GameAnalyticsInterface} GameAnalyticsInterface
|
||||||
@ -70,6 +71,9 @@ export class Application {
|
|||||||
this.inputMgr = new InputDistributor(this);
|
this.inputMgr = new InputDistributor(this);
|
||||||
this.backgroundResourceLoader = new BackgroundResourcesLoader(this);
|
this.backgroundResourceLoader = new BackgroundResourcesLoader(this);
|
||||||
|
|
||||||
|
// Restrictions (Like demo etc)
|
||||||
|
this.restrictionMgr = new RestrictionManager(this);
|
||||||
|
|
||||||
// Platform dependent stuff
|
// Platform dependent stuff
|
||||||
|
|
||||||
/** @type {StorageInterface} */
|
/** @type {StorageInterface} */
|
||||||
|
|||||||
@ -6,14 +6,6 @@ export const CHANGELOG = [
|
|||||||
"⚠️⚠️This update is HUGE, view the full changelog <a href='https://shapez.io/wires/' target='_blank'>here</a>! ⚠️⚠️",
|
"⚠️⚠️This update is HUGE, view the full changelog <a href='https://shapez.io/wires/' target='_blank'>here</a>! ⚠️⚠️",
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
|
||||||
version: "1.1.19",
|
|
||||||
date: "02.07.2020",
|
|
||||||
entries: [
|
|
||||||
"There are now notifications every 15 minutes in the demo version to buy the full version (For further details and the reason, check the #surveys channel in the Discord)",
|
|
||||||
"I'm still working on the wires update, I hope to release it mid july!",
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
version: "1.1.18",
|
version: "1.1.18",
|
||||||
date: "27.06.2020",
|
date: "27.06.2020",
|
||||||
|
|||||||
@ -1,5 +1,3 @@
|
|||||||
import { queryParamOptions } from "./query_parameters";
|
|
||||||
|
|
||||||
export const IS_DEBUG =
|
export const IS_DEBUG =
|
||||||
G_IS_DEV &&
|
G_IS_DEV &&
|
||||||
typeof window !== "undefined" &&
|
typeof window !== "undefined" &&
|
||||||
@ -7,13 +5,10 @@ export const IS_DEBUG =
|
|||||||
(window.location.host.indexOf("localhost:") >= 0 || window.location.host.indexOf("192.168.0.") >= 0) &&
|
(window.location.host.indexOf("localhost:") >= 0 || window.location.host.indexOf("192.168.0.") >= 0) &&
|
||||||
window.location.search.indexOf("nodebug") < 0;
|
window.location.search.indexOf("nodebug") < 0;
|
||||||
|
|
||||||
export const IS_DEMO = queryParamOptions.fullVersion
|
|
||||||
? false
|
|
||||||
: (!G_IS_DEV && !G_IS_STANDALONE) ||
|
|
||||||
(typeof window !== "undefined" && window.location.search.indexOf("demo") >= 0);
|
|
||||||
|
|
||||||
export const SUPPORT_TOUCH = false;
|
export const SUPPORT_TOUCH = false;
|
||||||
|
|
||||||
|
export const IS_MAC = navigator.platform.toLowerCase().indexOf("mac") >= 0;
|
||||||
|
|
||||||
const smoothCanvas = true;
|
const smoothCanvas = true;
|
||||||
|
|
||||||
export const THIRDPARTY_URLS = {
|
export const THIRDPARTY_URLS = {
|
||||||
@ -25,6 +20,8 @@ export const THIRDPARTY_URLS = {
|
|||||||
standaloneStorePage: "https://store.steampowered.com/app/1318690/shapezio/",
|
standaloneStorePage: "https://store.steampowered.com/app/1318690/shapezio/",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const A_B_TESTING_LINK_TYPE = Math.random() > 0.5 ? "steam_1_pr" : "steam_2_npr";
|
||||||
|
|
||||||
export const globalConfig = {
|
export const globalConfig = {
|
||||||
// Size of a single tile in Pixels.
|
// Size of a single tile in Pixels.
|
||||||
// NOTICE: Update webpack.production.config too!
|
// NOTICE: Update webpack.production.config too!
|
||||||
@ -62,7 +59,7 @@ export const globalConfig = {
|
|||||||
|
|
||||||
undergroundBeltMaxTilesByTier: [5, 9],
|
undergroundBeltMaxTilesByTier: [5, 9],
|
||||||
|
|
||||||
readerAnalyzeIntervalSeconds: G_IS_DEV ? 3 : 10,
|
readerAnalyzeIntervalSeconds: 10,
|
||||||
|
|
||||||
buildingSpeeds: {
|
buildingSpeeds: {
|
||||||
cutter: 1 / 4,
|
cutter: 1 / 4,
|
||||||
|
|||||||
@ -81,10 +81,6 @@ export class ReadWriteProxy {
|
|||||||
return this.writeAsync();
|
return this.writeAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
getCurrentData() {
|
|
||||||
return this.currentData;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param {object} obj
|
* @param {object} obj
|
||||||
|
|||||||
155
src/js/core/restriction_manager.js
Normal file
@ -0,0 +1,155 @@
|
|||||||
|
/* typehints:start */
|
||||||
|
import { Application } from "../application";
|
||||||
|
/* typehints:end */
|
||||||
|
import { IS_MAC } from "./config";
|
||||||
|
import { ExplainedResult } from "./explained_result";
|
||||||
|
import { queryParamOptions } from "./query_parameters";
|
||||||
|
import { ReadWriteProxy } from "./read_write_proxy";
|
||||||
|
|
||||||
|
export class RestrictionManager extends ReadWriteProxy {
|
||||||
|
/**
|
||||||
|
* @param {Application} app
|
||||||
|
*/
|
||||||
|
constructor(app) {
|
||||||
|
super(app, "restriction-flags.bin");
|
||||||
|
|
||||||
|
this.currentData = this.getDefaultData();
|
||||||
|
}
|
||||||
|
|
||||||
|
// -- RW Proxy Impl
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {any} data
|
||||||
|
*/
|
||||||
|
verify(data) {
|
||||||
|
return ExplainedResult.good();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
getDefaultData() {
|
||||||
|
return {
|
||||||
|
version: this.getCurrentVersion(),
|
||||||
|
savegameV1119Imported: false,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
getCurrentVersion() {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {any} data
|
||||||
|
*/
|
||||||
|
migrate(data) {
|
||||||
|
// Todo
|
||||||
|
return ExplainedResult.good();
|
||||||
|
}
|
||||||
|
|
||||||
|
initialize() {
|
||||||
|
return this.readAsync().then(() => {
|
||||||
|
if (this.currentData.savegameV1119Imported) {
|
||||||
|
console.warn("Levelunlock is granted to current user due to past savegame");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// -- End RW Proxy Impl
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if there are any savegames from the 1.1.19 version
|
||||||
|
*/
|
||||||
|
onHasLegacySavegamesChanged(has119Savegames = false) {
|
||||||
|
if (has119Savegames && !this.currentData.savegameV1119Imported) {
|
||||||
|
this.currentData.savegameV1119Imported = true;
|
||||||
|
console.warn("Current user now has access to all levels due to 1119 savegame");
|
||||||
|
return this.writeAsync();
|
||||||
|
}
|
||||||
|
return Promise.resolve();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns if the app is currently running as the limited version
|
||||||
|
* @returns {boolean}
|
||||||
|
*/
|
||||||
|
isLimitedVersion() {
|
||||||
|
if (IS_MAC) {
|
||||||
|
// On mac, the full version is always active
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (G_IS_STANDALONE) {
|
||||||
|
// Standalone is never limited
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (queryParamOptions.fullVersion) {
|
||||||
|
// Full version is activated via flag
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (G_IS_DEV) {
|
||||||
|
return typeof window !== "undefined" && window.location.search.indexOf("demo") >= 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns if the app markets the standalone version on steam
|
||||||
|
* @returns {boolean}
|
||||||
|
*/
|
||||||
|
getIsStandaloneMarketingActive() {
|
||||||
|
return this.isLimitedVersion();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns if exporting the base as a screenshot is possible
|
||||||
|
* @returns {boolean}
|
||||||
|
*/
|
||||||
|
getIsExportingScreenshotsPossible() {
|
||||||
|
return !this.isLimitedVersion();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the maximum number of supported waypoints
|
||||||
|
* @returns {number}
|
||||||
|
*/
|
||||||
|
getMaximumWaypoints() {
|
||||||
|
return this.isLimitedVersion() ? 2 : 1e20;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns if the user has unlimited savegames
|
||||||
|
* @returns {boolean}
|
||||||
|
*/
|
||||||
|
getHasUnlimitedSavegames() {
|
||||||
|
return !this.isLimitedVersion();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns if the app has all settings available
|
||||||
|
* @returns {boolean}
|
||||||
|
*/
|
||||||
|
getHasExtendedSettings() {
|
||||||
|
return !this.isLimitedVersion();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns if all upgrades are available
|
||||||
|
* @returns {boolean}
|
||||||
|
*/
|
||||||
|
getHasExtendedUpgrades() {
|
||||||
|
return !this.isLimitedVersion() || this.currentData.savegameV1119Imported;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns if all levels & freeplay is available
|
||||||
|
* @returns {boolean}
|
||||||
|
*/
|
||||||
|
getHasExtendedLevelsAndFreeplay() {
|
||||||
|
return !this.isLimitedVersion() || this.currentData.savegameV1119Imported;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -266,7 +266,6 @@ export function findNiceIntegerValue(num) {
|
|||||||
* Formats a big number
|
* Formats a big number
|
||||||
* @param {number} num
|
* @param {number} num
|
||||||
* @param {string=} separator The decimal separator for numbers like 50.1 (separator='.')
|
* @param {string=} separator The decimal separator for numbers like 50.1 (separator='.')
|
||||||
* @param {number=} number of significant figures to include (for values >= 1000)
|
|
||||||
* @returns {string}
|
* @returns {string}
|
||||||
*/
|
*/
|
||||||
export function formatBigNumber(num, separator = T.global.decimalSeparator, precision = 3) {
|
export function formatBigNumber(num, separator = T.global.decimalSeparator, precision = 3) {
|
||||||
@ -678,3 +677,72 @@ export function fillInLinkIntoTranslation(translation, link) {
|
|||||||
.replace("<link>", "<a href='" + link + "' target='_blank'>")
|
.replace("<link>", "<a href='" + link + "' target='_blank'>")
|
||||||
.replace("</link>", "</a>");
|
.replace("</link>", "</a>");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates a file download
|
||||||
|
* @param {string} filename
|
||||||
|
* @param {string} text
|
||||||
|
*/
|
||||||
|
export function generateFileDownload(filename, text) {
|
||||||
|
var element = document.createElement("a");
|
||||||
|
element.setAttribute("href", "data:text/plain;charset=utf-8," + encodeURIComponent(text));
|
||||||
|
element.setAttribute("download", filename);
|
||||||
|
|
||||||
|
element.style.display = "none";
|
||||||
|
document.body.appendChild(element);
|
||||||
|
|
||||||
|
element.click();
|
||||||
|
document.body.removeChild(element);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Starts a file chooser
|
||||||
|
* @param {string} acceptedType
|
||||||
|
*/
|
||||||
|
export function startFileChoose(acceptedType = ".bin") {
|
||||||
|
var input = document.createElement("input");
|
||||||
|
input.type = "file";
|
||||||
|
input.accept = acceptedType;
|
||||||
|
|
||||||
|
return new Promise(resolve => {
|
||||||
|
input.onchange = _ => resolve(input.files[0]);
|
||||||
|
input.click();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const romanLiterals = [
|
||||||
|
"0", // NULL
|
||||||
|
"I",
|
||||||
|
"II",
|
||||||
|
"III",
|
||||||
|
"IV",
|
||||||
|
"V",
|
||||||
|
"VI",
|
||||||
|
"VII",
|
||||||
|
"VIII",
|
||||||
|
"IX",
|
||||||
|
"X",
|
||||||
|
"XI",
|
||||||
|
"XII",
|
||||||
|
"XIII",
|
||||||
|
"XIV",
|
||||||
|
"XV",
|
||||||
|
"XVI",
|
||||||
|
"XVII",
|
||||||
|
"XVIII",
|
||||||
|
"XIX",
|
||||||
|
"XX",
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {number} number
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
export function getRomanNumber(number) {
|
||||||
|
number = Math.max(0, Math.round(number));
|
||||||
|
if (number < romanLiterals.length) {
|
||||||
|
return romanLiterals[number];
|
||||||
|
}
|
||||||
|
return String(number);
|
||||||
|
}
|
||||||
|
|||||||
@ -1111,7 +1111,7 @@ export class BeltPath extends BasicSerializableObject {
|
|||||||
|
|
||||||
isFirstItemProcessed = false;
|
isFirstItemProcessed = false;
|
||||||
this.spacingToFirstItem += clampedProgress;
|
this.spacingToFirstItem += clampedProgress;
|
||||||
if (remainingVelocity < 0.01) {
|
if (remainingVelocity < 1e-7) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,13 +1,9 @@
|
|||||||
import { globalConfig } from "../core/config";
|
import { globalConfig } from "../core/config";
|
||||||
import { DrawParameters } from "../core/draw_parameters";
|
import { DrawParameters } from "../core/draw_parameters";
|
||||||
import { createLogger } from "../core/logging";
|
|
||||||
import { findNiceIntegerValue } from "../core/utils";
|
import { findNiceIntegerValue } from "../core/utils";
|
||||||
import { Vector } from "../core/vector";
|
import { Vector } from "../core/vector";
|
||||||
import { Entity } from "./entity";
|
import { Entity } from "./entity";
|
||||||
import { GameRoot } from "./root";
|
import { GameRoot } from "./root";
|
||||||
import { blueprintShape } from "./upgrades";
|
|
||||||
|
|
||||||
const logger = createLogger("blueprint");
|
|
||||||
|
|
||||||
export class Blueprint {
|
export class Blueprint {
|
||||||
/**
|
/**
|
||||||
@ -142,7 +138,7 @@ export class Blueprint {
|
|||||||
* @param {GameRoot} root
|
* @param {GameRoot} root
|
||||||
*/
|
*/
|
||||||
canAfford(root) {
|
canAfford(root) {
|
||||||
return root.hubGoals.getShapesStoredByKey(blueprintShape) >= this.getCost();
|
return root.hubGoals.getShapesStoredByKey(root.gameMode.getBlueprintShapeKey()) >= this.getCost();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -110,12 +110,7 @@ export class MetaVirtualProcessorBuilding extends MetaBuilding {
|
|||||||
pinComp.setSlots([
|
pinComp.setSlots([
|
||||||
{
|
{
|
||||||
pos: new Vector(0, 0),
|
pos: new Vector(0, 0),
|
||||||
direction: enumDirection.left,
|
direction: enumDirection.top,
|
||||||
type: enumPinSlotType.logicalEjector,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
pos: new Vector(0, 0),
|
|
||||||
direction: enumDirection.right,
|
|
||||||
type: enumPinSlotType.logicalEjector,
|
type: enumPinSlotType.logicalEjector,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@ -511,7 +511,11 @@ export class Camera extends BasicSerializableObject {
|
|||||||
this.clampZoomLevel();
|
this.clampZoomLevel();
|
||||||
this.desiredZoom = null;
|
this.desiredZoom = null;
|
||||||
|
|
||||||
const mousePosition = this.root.app.mousePosition;
|
let mousePosition = this.root.app.mousePosition;
|
||||||
|
if (!this.root.app.settings.getAllSettings().zoomToCursor) {
|
||||||
|
mousePosition = new Vector(this.root.gameWidth / 2, this.root.gameHeight / 2);
|
||||||
|
}
|
||||||
|
|
||||||
if (mousePosition) {
|
if (mousePosition) {
|
||||||
const worldPos = this.root.camera.screenToWorld(mousePosition);
|
const worldPos = this.root.camera.screenToWorld(mousePosition);
|
||||||
const worldDelta = worldPos.sub(this.center);
|
const worldDelta = worldPos.sub(this.center);
|
||||||
|
|||||||
@ -31,6 +31,7 @@ import { KeyActionMapper } from "./key_action_mapper";
|
|||||||
import { GameLogic } from "./logic";
|
import { GameLogic } from "./logic";
|
||||||
import { MapView } from "./map_view";
|
import { MapView } from "./map_view";
|
||||||
import { defaultBuildingVariant } from "./meta_building";
|
import { defaultBuildingVariant } from "./meta_building";
|
||||||
|
import { RegularGameMode } from "./modes/regular";
|
||||||
import { ProductionAnalytics } from "./production_analytics";
|
import { ProductionAnalytics } from "./production_analytics";
|
||||||
import { GameRoot } from "./root";
|
import { GameRoot } from "./root";
|
||||||
import { ShapeDefinitionManager } from "./shape_definition_manager";
|
import { ShapeDefinitionManager } from "./shape_definition_manager";
|
||||||
@ -101,6 +102,9 @@ export class GameCore {
|
|||||||
// Needs to come first
|
// Needs to come first
|
||||||
root.dynamicTickrate = new DynamicTickrate(root);
|
root.dynamicTickrate = new DynamicTickrate(root);
|
||||||
|
|
||||||
|
// Init game mode
|
||||||
|
root.gameMode = new RegularGameMode(root);
|
||||||
|
|
||||||
// Init classes
|
// Init classes
|
||||||
root.camera = new Camera(root);
|
root.camera = new Camera(root);
|
||||||
root.map = new MapView(root);
|
root.map = new MapView(root);
|
||||||
|
|||||||
71
src/js/game/game_mode.js
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
/* typehints:start */
|
||||||
|
import { enumHubGoalRewards } from "./tutorial_goals";
|
||||||
|
/* typehints:end */
|
||||||
|
|
||||||
|
import { GameRoot } from "./root";
|
||||||
|
|
||||||
|
/** @typedef {{
|
||||||
|
* shape: string,
|
||||||
|
* amount: number
|
||||||
|
* }} UpgradeRequirement */
|
||||||
|
|
||||||
|
/** @typedef {{
|
||||||
|
* required: Array<UpgradeRequirement>
|
||||||
|
* improvement?: number,
|
||||||
|
* excludePrevious?: boolean
|
||||||
|
* }} TierRequirement */
|
||||||
|
|
||||||
|
/** @typedef {Array<TierRequirement>} UpgradeTiers */
|
||||||
|
|
||||||
|
/** @typedef {{
|
||||||
|
* shape: string,
|
||||||
|
* required: number,
|
||||||
|
* reward: enumHubGoalRewards,
|
||||||
|
* throughputOnly?: boolean
|
||||||
|
* }} LevelDefinition */
|
||||||
|
|
||||||
|
export class GameMode {
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {GameRoot} root
|
||||||
|
*/
|
||||||
|
constructor(root) {
|
||||||
|
this.root = root;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Should return all available upgrades
|
||||||
|
* @returns {Object<string, UpgradeTiers>}
|
||||||
|
*/
|
||||||
|
getUpgrades() {
|
||||||
|
abstract;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the blueprint shape key
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
getBlueprintShapeKey() {
|
||||||
|
abstract;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the goals for all levels including their reward
|
||||||
|
* @returns {Array<LevelDefinition>}
|
||||||
|
*/
|
||||||
|
getLevelDefinitions() {
|
||||||
|
abstract;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Should return whether free play is available or if the game stops
|
||||||
|
* after the predefined levels
|
||||||
|
* @returns {boolean}
|
||||||
|
*/
|
||||||
|
getIsFreeplayAvailable() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,14 +1,13 @@
|
|||||||
import { globalConfig, IS_DEMO } from "../core/config";
|
import { globalConfig } from "../core/config";
|
||||||
import { RandomNumberGenerator } from "../core/rng";
|
import { RandomNumberGenerator } from "../core/rng";
|
||||||
import { clamp, findNiceIntegerValue, randomChoice, randomInt } from "../core/utils";
|
import { clamp } from "../core/utils";
|
||||||
import { BasicSerializableObject, types } from "../savegame/serialization";
|
import { BasicSerializableObject, types } from "../savegame/serialization";
|
||||||
import { enumColors } from "./colors";
|
import { enumColors } from "./colors";
|
||||||
import { enumItemProcessorTypes } from "./components/item_processor";
|
import { enumItemProcessorTypes } from "./components/item_processor";
|
||||||
import { enumAnalyticsDataSource } from "./production_analytics";
|
import { enumAnalyticsDataSource } from "./production_analytics";
|
||||||
import { GameRoot } from "./root";
|
import { GameRoot } from "./root";
|
||||||
import { enumSubShape, ShapeDefinition } from "./shape_definition";
|
import { enumSubShape, ShapeDefinition } from "./shape_definition";
|
||||||
import { enumHubGoalRewards, tutorialGoals } from "./tutorial_goals";
|
import { enumHubGoalRewards } from "./tutorial_goals";
|
||||||
import { UPGRADES } from "./upgrades";
|
|
||||||
|
|
||||||
export class HubGoals extends BasicSerializableObject {
|
export class HubGoals extends BasicSerializableObject {
|
||||||
static getId() {
|
static getId() {
|
||||||
@ -23,27 +22,36 @@ export class HubGoals extends BasicSerializableObject {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
deserialize(data) {
|
/**
|
||||||
|
*
|
||||||
|
* @param {*} data
|
||||||
|
* @param {GameRoot} root
|
||||||
|
*/
|
||||||
|
deserialize(data, root) {
|
||||||
const errorCode = super.deserialize(data);
|
const errorCode = super.deserialize(data);
|
||||||
if (errorCode) {
|
if (errorCode) {
|
||||||
return errorCode;
|
return errorCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IS_DEMO) {
|
const levels = root.gameMode.getLevelDefinitions();
|
||||||
this.level = Math.min(this.level, tutorialGoals.length);
|
|
||||||
|
// If freeplay is not available, clamp the level
|
||||||
|
if (!root.gameMode.getIsFreeplayAvailable()) {
|
||||||
|
this.level = Math.min(this.level, levels.length);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compute gained rewards
|
// Compute gained rewards
|
||||||
for (let i = 0; i < this.level - 1; ++i) {
|
for (let i = 0; i < this.level - 1; ++i) {
|
||||||
if (i < tutorialGoals.length) {
|
if (i < levels.length) {
|
||||||
const reward = tutorialGoals[i].reward;
|
const reward = levels[i].reward;
|
||||||
this.gainedRewards[reward] = (this.gainedRewards[reward] || 0) + 1;
|
this.gainedRewards[reward] = (this.gainedRewards[reward] || 0) + 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compute upgrade improvements
|
// Compute upgrade improvements
|
||||||
for (const upgradeId in UPGRADES) {
|
const upgrades = this.root.gameMode.getUpgrades();
|
||||||
const tiers = UPGRADES[upgradeId];
|
for (const upgradeId in upgrades) {
|
||||||
|
const tiers = upgrades[upgradeId];
|
||||||
const level = this.upgradeLevels[upgradeId] || 0;
|
const level = this.upgradeLevels[upgradeId] || 0;
|
||||||
let totalImprovement = 1;
|
let totalImprovement = 1;
|
||||||
for (let i = 0; i < level; ++i) {
|
for (let i = 0; i < level; ++i) {
|
||||||
@ -84,17 +92,16 @@ export class HubGoals extends BasicSerializableObject {
|
|||||||
*/
|
*/
|
||||||
this.upgradeLevels = {};
|
this.upgradeLevels = {};
|
||||||
|
|
||||||
// Reset levels
|
|
||||||
for (const key in UPGRADES) {
|
|
||||||
this.upgradeLevels[key] = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Stores the improvements for all upgrades
|
* Stores the improvements for all upgrades
|
||||||
* @type {Object<string, number>}
|
* @type {Object<string, number>}
|
||||||
*/
|
*/
|
||||||
this.upgradeImprovements = {};
|
this.upgradeImprovements = {};
|
||||||
for (const key in UPGRADES) {
|
|
||||||
|
// Reset levels first
|
||||||
|
const upgrades = this.root.gameMode.getUpgrades();
|
||||||
|
for (const key in upgrades) {
|
||||||
|
this.upgradeLevels[key] = 0;
|
||||||
this.upgradeImprovements[key] = 1;
|
this.upgradeImprovements[key] = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -120,7 +127,10 @@ export class HubGoals extends BasicSerializableObject {
|
|||||||
* @returns {boolean}
|
* @returns {boolean}
|
||||||
*/
|
*/
|
||||||
isEndOfDemoReached() {
|
isEndOfDemoReached() {
|
||||||
return IS_DEMO && this.level >= tutorialGoals.length;
|
return (
|
||||||
|
!this.root.gameMode.getIsFreeplayAvailable() &&
|
||||||
|
this.level >= this.root.gameMode.getLevelDefinitions().length
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -215,8 +225,9 @@ export class HubGoals extends BasicSerializableObject {
|
|||||||
*/
|
*/
|
||||||
computeNextGoal() {
|
computeNextGoal() {
|
||||||
const storyIndex = this.level - 1;
|
const storyIndex = this.level - 1;
|
||||||
if (storyIndex < tutorialGoals.length) {
|
const levels = this.root.gameMode.getLevelDefinitions();
|
||||||
const { shape, required, reward, throughputOnly } = tutorialGoals[storyIndex];
|
if (storyIndex < levels.length) {
|
||||||
|
const { shape, required, reward, throughputOnly } = levels[storyIndex];
|
||||||
this.currentGoal = {
|
this.currentGoal = {
|
||||||
/** @type {ShapeDefinition} */
|
/** @type {ShapeDefinition} */
|
||||||
definition: this.root.shapeDefinitionMgr.getShapeFromShortKey(shape),
|
definition: this.root.shapeDefinitionMgr.getShapeFromShortKey(shape),
|
||||||
@ -254,7 +265,7 @@ export class HubGoals extends BasicSerializableObject {
|
|||||||
* Returns whether we are playing in free-play
|
* Returns whether we are playing in free-play
|
||||||
*/
|
*/
|
||||||
isFreePlay() {
|
isFreePlay() {
|
||||||
return this.level >= tutorialGoals.length;
|
return this.level >= this.root.gameMode.getLevelDefinitions().length;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -262,7 +273,7 @@ export class HubGoals extends BasicSerializableObject {
|
|||||||
* @param {string} upgradeId
|
* @param {string} upgradeId
|
||||||
*/
|
*/
|
||||||
canUnlockUpgrade(upgradeId) {
|
canUnlockUpgrade(upgradeId) {
|
||||||
const tiers = UPGRADES[upgradeId];
|
const tiers = this.root.gameMode.getUpgrades()[upgradeId];
|
||||||
const currentLevel = this.getUpgradeLevel(upgradeId);
|
const currentLevel = this.getUpgradeLevel(upgradeId);
|
||||||
|
|
||||||
if (currentLevel >= tiers.length) {
|
if (currentLevel >= tiers.length) {
|
||||||
@ -270,11 +281,6 @@ export class HubGoals extends BasicSerializableObject {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IS_DEMO && currentLevel >= 4) {
|
|
||||||
// DEMO
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (G_IS_DEV && globalConfig.debug.upgradesNoCost) {
|
if (G_IS_DEV && globalConfig.debug.upgradesNoCost) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -296,7 +302,7 @@ export class HubGoals extends BasicSerializableObject {
|
|||||||
*/
|
*/
|
||||||
getAvailableUpgradeCount() {
|
getAvailableUpgradeCount() {
|
||||||
let count = 0;
|
let count = 0;
|
||||||
for (const upgradeId in UPGRADES) {
|
for (const upgradeId in this.root.gameMode.getUpgrades()) {
|
||||||
if (this.canUnlockUpgrade(upgradeId)) {
|
if (this.canUnlockUpgrade(upgradeId)) {
|
||||||
++count;
|
++count;
|
||||||
}
|
}
|
||||||
@ -314,7 +320,7 @@ export class HubGoals extends BasicSerializableObject {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const upgradeTiers = UPGRADES[upgradeId];
|
const upgradeTiers = this.root.gameMode.getUpgrades()[upgradeId];
|
||||||
const currentLevel = this.getUpgradeLevel(upgradeId);
|
const currentLevel = this.getUpgradeLevel(upgradeId);
|
||||||
|
|
||||||
const tierData = upgradeTiers[currentLevel];
|
const tierData = upgradeTiers[currentLevel];
|
||||||
|
|||||||
@ -15,7 +15,7 @@ import { HUDKeybindingOverlay } from "./parts/keybinding_overlay";
|
|||||||
import { HUDUnlockNotification } from "./parts/unlock_notification";
|
import { HUDUnlockNotification } from "./parts/unlock_notification";
|
||||||
import { HUDGameMenu } from "./parts/game_menu";
|
import { HUDGameMenu } from "./parts/game_menu";
|
||||||
import { HUDShop } from "./parts/shop";
|
import { HUDShop } from "./parts/shop";
|
||||||
import { IS_MOBILE, globalConfig, IS_DEMO } from "../../core/config";
|
import { IS_MOBILE, globalConfig } from "../../core/config";
|
||||||
import { HUDMassSelector } from "./parts/mass_selector";
|
import { HUDMassSelector } from "./parts/mass_selector";
|
||||||
import { HUDVignetteOverlay } from "./parts/vignette_overlay";
|
import { HUDVignetteOverlay } from "./parts/vignette_overlay";
|
||||||
import { HUDStatistics } from "./parts/statistics";
|
import { HUDStatistics } from "./parts/statistics";
|
||||||
@ -45,8 +45,8 @@ import { HUDLeverToggle } from "./parts/lever_toggle";
|
|||||||
import { HUDLayerPreview } from "./parts/layer_preview";
|
import { HUDLayerPreview } from "./parts/layer_preview";
|
||||||
import { HUDMinerHighlight } from "./parts/miner_highlight";
|
import { HUDMinerHighlight } from "./parts/miner_highlight";
|
||||||
import { HUDBetaOverlay } from "./parts/beta_overlay";
|
import { HUDBetaOverlay } from "./parts/beta_overlay";
|
||||||
import { HUDPerformanceWarning } from "./parts/performance_warning";
|
|
||||||
import { HUDStandaloneAdvantages } from "./parts/standalone_advantages";
|
import { HUDStandaloneAdvantages } from "./parts/standalone_advantages";
|
||||||
|
import { HUDCatMemes } from "./parts/cat_memes";
|
||||||
|
|
||||||
export class GameHUD {
|
export class GameHUD {
|
||||||
/**
|
/**
|
||||||
@ -87,7 +87,6 @@ export class GameHUD {
|
|||||||
layerPreview: new HUDLayerPreview(this.root),
|
layerPreview: new HUDLayerPreview(this.root),
|
||||||
|
|
||||||
minerHighlight: new HUDMinerHighlight(this.root),
|
minerHighlight: new HUDMinerHighlight(this.root),
|
||||||
performanceWarning: new HUDPerformanceWarning(this.root),
|
|
||||||
|
|
||||||
// Typing hints
|
// Typing hints
|
||||||
/* typehints:start */
|
/* typehints:start */
|
||||||
@ -115,9 +114,10 @@ export class GameHUD {
|
|||||||
this.parts.entityDebugger = new HUDEntityDebugger(this.root);
|
this.parts.entityDebugger = new HUDEntityDebugger(this.root);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IS_DEMO) {
|
if (this.root.app.restrictionMgr.getIsStandaloneMarketingActive()) {
|
||||||
this.parts.watermark = new HUDWatermark(this.root);
|
this.parts.watermark = new HUDWatermark(this.root);
|
||||||
this.parts.standaloneAdvantages = new HUDStandaloneAdvantages(this.root);
|
this.parts.standaloneAdvantages = new HUDStandaloneAdvantages(this.root);
|
||||||
|
this.parts.catMemes = new HUDCatMemes(this.root);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (G_IS_DEV && globalConfig.debug.renderChanges) {
|
if (G_IS_DEV && globalConfig.debug.renderChanges) {
|
||||||
|
|||||||
@ -7,7 +7,7 @@ export class HUDBetaOverlay extends BaseHUDPart {
|
|||||||
parent,
|
parent,
|
||||||
"ingame_HUD_BetaOverlay",
|
"ingame_HUD_BetaOverlay",
|
||||||
[],
|
[],
|
||||||
"<h2>UNSTABLE BETA VERSION</h2><span>Steam Release: 9th October 2020!</span>"
|
"<h2>UNSTABLE BETA VERSION</h2><span>Unfinalized & potential buggy content!</span>"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,202 +1,203 @@
|
|||||||
import { DrawParameters } from "../../../core/draw_parameters";
|
import { DrawParameters } from "../../../core/draw_parameters";
|
||||||
import { STOP_PROPAGATION } from "../../../core/signal";
|
import { STOP_PROPAGATION } from "../../../core/signal";
|
||||||
import { TrackedState } from "../../../core/tracked_state";
|
import { TrackedState } from "../../../core/tracked_state";
|
||||||
import { makeDiv } from "../../../core/utils";
|
import { makeDiv } from "../../../core/utils";
|
||||||
import { Vector } from "../../../core/vector";
|
import { Vector } from "../../../core/vector";
|
||||||
import { T } from "../../../translations";
|
import { SOUNDS } from "../../../platform/sound";
|
||||||
import { enumMouseButton } from "../../camera";
|
import { T } from "../../../translations";
|
||||||
import { KEYMAPPINGS } from "../../key_action_mapper";
|
import { Blueprint } from "../../blueprint";
|
||||||
import { blueprintShape } from "../../upgrades";
|
import { enumMouseButton } from "../../camera";
|
||||||
import { BaseHUDPart } from "../base_hud_part";
|
import { KEYMAPPINGS } from "../../key_action_mapper";
|
||||||
import { DynamicDomAttach } from "../dynamic_dom_attach";
|
import { BaseHUDPart } from "../base_hud_part";
|
||||||
import { Blueprint } from "../../blueprint";
|
import { DynamicDomAttach } from "../dynamic_dom_attach";
|
||||||
import { SOUNDS } from "../../../platform/sound";
|
|
||||||
|
export class HUDBlueprintPlacer extends BaseHUDPart {
|
||||||
export class HUDBlueprintPlacer extends BaseHUDPart {
|
createElements(parent) {
|
||||||
createElements(parent) {
|
const blueprintCostShape = this.root.shapeDefinitionMgr.getShapeFromShortKey(
|
||||||
const blueprintCostShape = this.root.shapeDefinitionMgr.getShapeFromShortKey(blueprintShape);
|
this.root.gameMode.getBlueprintShapeKey()
|
||||||
const blueprintCostShapeCanvas = blueprintCostShape.generateAsCanvas(80);
|
);
|
||||||
|
const blueprintCostShapeCanvas = blueprintCostShape.generateAsCanvas(80);
|
||||||
this.costDisplayParent = makeDiv(parent, "ingame_HUD_BlueprintPlacer", [], ``);
|
|
||||||
|
this.costDisplayParent = makeDiv(parent, "ingame_HUD_BlueprintPlacer", [], ``);
|
||||||
makeDiv(this.costDisplayParent, null, ["label"], T.ingame.blueprintPlacer.cost);
|
|
||||||
const costContainer = makeDiv(this.costDisplayParent, null, ["costContainer"], "");
|
makeDiv(this.costDisplayParent, null, ["label"], T.ingame.blueprintPlacer.cost);
|
||||||
this.costDisplayText = makeDiv(costContainer, null, ["costText"], "");
|
const costContainer = makeDiv(this.costDisplayParent, null, ["costContainer"], "");
|
||||||
costContainer.appendChild(blueprintCostShapeCanvas);
|
this.costDisplayText = makeDiv(costContainer, null, ["costText"], "");
|
||||||
}
|
costContainer.appendChild(blueprintCostShapeCanvas);
|
||||||
|
}
|
||||||
initialize() {
|
|
||||||
this.root.hud.signals.buildingsSelectedForCopy.add(this.createBlueprintFromBuildings, this);
|
initialize() {
|
||||||
|
this.root.hud.signals.buildingsSelectedForCopy.add(this.createBlueprintFromBuildings, this);
|
||||||
/** @type {TypedTrackedState<Blueprint?>} */
|
|
||||||
this.currentBlueprint = new TrackedState(this.onBlueprintChanged, this);
|
/** @type {TypedTrackedState<Blueprint?>} */
|
||||||
/** @type {Blueprint?} */
|
this.currentBlueprint = new TrackedState(this.onBlueprintChanged, this);
|
||||||
this.lastBlueprintUsed = null;
|
/** @type {Blueprint?} */
|
||||||
|
this.lastBlueprintUsed = null;
|
||||||
const keyActionMapper = this.root.keyMapper;
|
|
||||||
keyActionMapper.getBinding(KEYMAPPINGS.general.back).add(this.abortPlacement, this);
|
const keyActionMapper = this.root.keyMapper;
|
||||||
keyActionMapper.getBinding(KEYMAPPINGS.placement.pipette).add(this.abortPlacement, this);
|
keyActionMapper.getBinding(KEYMAPPINGS.general.back).add(this.abortPlacement, this);
|
||||||
keyActionMapper.getBinding(KEYMAPPINGS.placement.rotateWhilePlacing).add(this.rotateBlueprint, this);
|
keyActionMapper.getBinding(KEYMAPPINGS.placement.pipette).add(this.abortPlacement, this);
|
||||||
keyActionMapper.getBinding(KEYMAPPINGS.massSelect.pasteLastBlueprint).add(this.pasteBlueprint, this);
|
keyActionMapper.getBinding(KEYMAPPINGS.placement.rotateWhilePlacing).add(this.rotateBlueprint, this);
|
||||||
|
keyActionMapper.getBinding(KEYMAPPINGS.massSelect.pasteLastBlueprint).add(this.pasteBlueprint, this);
|
||||||
this.root.camera.downPreHandler.add(this.onMouseDown, this);
|
|
||||||
this.root.camera.movePreHandler.add(this.onMouseMove, this);
|
this.root.camera.downPreHandler.add(this.onMouseDown, this);
|
||||||
|
this.root.camera.movePreHandler.add(this.onMouseMove, this);
|
||||||
this.root.hud.signals.selectedPlacementBuildingChanged.add(this.abortPlacement, this);
|
|
||||||
this.root.signals.editModeChanged.add(this.onEditModeChanged, this);
|
this.root.hud.signals.selectedPlacementBuildingChanged.add(this.abortPlacement, this);
|
||||||
|
this.root.signals.editModeChanged.add(this.onEditModeChanged, this);
|
||||||
this.domAttach = new DynamicDomAttach(this.root, this.costDisplayParent);
|
|
||||||
this.trackedCanAfford = new TrackedState(this.onCanAffordChanged, this);
|
this.domAttach = new DynamicDomAttach(this.root, this.costDisplayParent);
|
||||||
}
|
this.trackedCanAfford = new TrackedState(this.onCanAffordChanged, this);
|
||||||
|
}
|
||||||
abortPlacement() {
|
|
||||||
if (this.currentBlueprint.get()) {
|
abortPlacement() {
|
||||||
this.currentBlueprint.set(null);
|
if (this.currentBlueprint.get()) {
|
||||||
|
this.currentBlueprint.set(null);
|
||||||
return STOP_PROPAGATION;
|
|
||||||
}
|
return STOP_PROPAGATION;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
/**
|
|
||||||
* Called when the layer was changed
|
/**
|
||||||
* @param {Layer} layer
|
* Called when the layer was changed
|
||||||
*/
|
* @param {Layer} layer
|
||||||
onEditModeChanged(layer) {
|
*/
|
||||||
// Check if the layer of the blueprint differs and thus we have to deselect it
|
onEditModeChanged(layer) {
|
||||||
const blueprint = this.currentBlueprint.get();
|
// Check if the layer of the blueprint differs and thus we have to deselect it
|
||||||
if (blueprint) {
|
const blueprint = this.currentBlueprint.get();
|
||||||
if (blueprint.layer !== layer) {
|
if (blueprint) {
|
||||||
this.currentBlueprint.set(null);
|
if (blueprint.layer !== layer) {
|
||||||
}
|
this.currentBlueprint.set(null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
/**
|
|
||||||
* Called when the blueprint is now affordable or not
|
/**
|
||||||
* @param {boolean} canAfford
|
* Called when the blueprint is now affordable or not
|
||||||
*/
|
* @param {boolean} canAfford
|
||||||
onCanAffordChanged(canAfford) {
|
*/
|
||||||
this.costDisplayParent.classList.toggle("canAfford", canAfford);
|
onCanAffordChanged(canAfford) {
|
||||||
}
|
this.costDisplayParent.classList.toggle("canAfford", canAfford);
|
||||||
|
}
|
||||||
update() {
|
|
||||||
const currentBlueprint = this.currentBlueprint.get();
|
update() {
|
||||||
this.domAttach.update(currentBlueprint && currentBlueprint.getCost() > 0);
|
const currentBlueprint = this.currentBlueprint.get();
|
||||||
this.trackedCanAfford.set(currentBlueprint && currentBlueprint.canAfford(this.root));
|
this.domAttach.update(currentBlueprint && currentBlueprint.getCost() > 0);
|
||||||
}
|
this.trackedCanAfford.set(currentBlueprint && currentBlueprint.canAfford(this.root));
|
||||||
|
}
|
||||||
/**
|
|
||||||
* Called when the blueprint was changed
|
/**
|
||||||
* @param {Blueprint} blueprint
|
* Called when the blueprint was changed
|
||||||
*/
|
* @param {Blueprint} blueprint
|
||||||
onBlueprintChanged(blueprint) {
|
*/
|
||||||
if (blueprint) {
|
onBlueprintChanged(blueprint) {
|
||||||
this.lastBlueprintUsed = blueprint;
|
if (blueprint) {
|
||||||
this.costDisplayText.innerText = "" + blueprint.getCost();
|
this.lastBlueprintUsed = blueprint;
|
||||||
}
|
this.costDisplayText.innerText = "" + blueprint.getCost();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
/**
|
|
||||||
* mouse down pre handler
|
/**
|
||||||
* @param {Vector} pos
|
* mouse down pre handler
|
||||||
* @param {enumMouseButton} button
|
* @param {Vector} pos
|
||||||
*/
|
* @param {enumMouseButton} button
|
||||||
onMouseDown(pos, button) {
|
*/
|
||||||
if (button === enumMouseButton.right) {
|
onMouseDown(pos, button) {
|
||||||
if (this.currentBlueprint.get()) {
|
if (button === enumMouseButton.right) {
|
||||||
this.abortPlacement();
|
if (this.currentBlueprint.get()) {
|
||||||
return STOP_PROPAGATION;
|
this.abortPlacement();
|
||||||
}
|
return STOP_PROPAGATION;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
const blueprint = this.currentBlueprint.get();
|
|
||||||
if (!blueprint) {
|
const blueprint = this.currentBlueprint.get();
|
||||||
return;
|
if (!blueprint) {
|
||||||
}
|
return;
|
||||||
|
}
|
||||||
if (!blueprint.canAfford(this.root)) {
|
|
||||||
this.root.soundProxy.playUiError();
|
if (!blueprint.canAfford(this.root)) {
|
||||||
return;
|
this.root.soundProxy.playUiError();
|
||||||
}
|
return;
|
||||||
|
}
|
||||||
const worldPos = this.root.camera.screenToWorld(pos);
|
|
||||||
const tile = worldPos.toTileSpace();
|
const worldPos = this.root.camera.screenToWorld(pos);
|
||||||
if (blueprint.tryPlace(this.root, tile)) {
|
const tile = worldPos.toTileSpace();
|
||||||
const cost = blueprint.getCost();
|
if (blueprint.tryPlace(this.root, tile)) {
|
||||||
this.root.hubGoals.takeShapeByKey(blueprintShape, cost);
|
const cost = blueprint.getCost();
|
||||||
this.root.soundProxy.playUi(SOUNDS.placeBuilding);
|
this.root.hubGoals.takeShapeByKey(this.root.gameMode.getBlueprintShapeKey(), cost);
|
||||||
}
|
this.root.soundProxy.playUi(SOUNDS.placeBuilding);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
/**
|
|
||||||
* Mose move handler
|
/**
|
||||||
*/
|
* Mose move handler
|
||||||
onMouseMove() {
|
*/
|
||||||
// Prevent movement while blueprint is selected
|
onMouseMove() {
|
||||||
if (this.currentBlueprint.get()) {
|
// Prevent movement while blueprint is selected
|
||||||
return STOP_PROPAGATION;
|
if (this.currentBlueprint.get()) {
|
||||||
}
|
return STOP_PROPAGATION;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
/**
|
|
||||||
* Called when an array of bulidings was selected
|
/**
|
||||||
* @param {Array<number>} uids
|
* Called when an array of bulidings was selected
|
||||||
*/
|
* @param {Array<number>} uids
|
||||||
createBlueprintFromBuildings(uids) {
|
*/
|
||||||
if (uids.length === 0) {
|
createBlueprintFromBuildings(uids) {
|
||||||
return;
|
if (uids.length === 0) {
|
||||||
}
|
return;
|
||||||
this.currentBlueprint.set(Blueprint.fromUids(this.root, uids));
|
}
|
||||||
}
|
this.currentBlueprint.set(Blueprint.fromUids(this.root, uids));
|
||||||
|
}
|
||||||
/**
|
|
||||||
* Attempts to rotate the current blueprint
|
/**
|
||||||
*/
|
* Attempts to rotate the current blueprint
|
||||||
rotateBlueprint() {
|
*/
|
||||||
if (this.currentBlueprint.get()) {
|
rotateBlueprint() {
|
||||||
if (this.root.keyMapper.getBinding(KEYMAPPINGS.placement.rotateInverseModifier).pressed) {
|
if (this.currentBlueprint.get()) {
|
||||||
this.currentBlueprint.get().rotateCcw();
|
if (this.root.keyMapper.getBinding(KEYMAPPINGS.placement.rotateInverseModifier).pressed) {
|
||||||
} else {
|
this.currentBlueprint.get().rotateCcw();
|
||||||
this.currentBlueprint.get().rotateCw();
|
} else {
|
||||||
}
|
this.currentBlueprint.get().rotateCw();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
/**
|
|
||||||
* Attempts to paste the last blueprint
|
/**
|
||||||
*/
|
* Attempts to paste the last blueprint
|
||||||
pasteBlueprint() {
|
*/
|
||||||
if (this.lastBlueprintUsed !== null) {
|
pasteBlueprint() {
|
||||||
if (this.lastBlueprintUsed.layer !== this.root.currentLayer) {
|
if (this.lastBlueprintUsed !== null) {
|
||||||
// Not compatible
|
if (this.lastBlueprintUsed.layer !== this.root.currentLayer) {
|
||||||
this.root.soundProxy.playUiError();
|
// Not compatible
|
||||||
return;
|
this.root.soundProxy.playUiError();
|
||||||
}
|
return;
|
||||||
|
}
|
||||||
this.root.hud.signals.pasteBlueprintRequested.dispatch();
|
|
||||||
this.currentBlueprint.set(this.lastBlueprintUsed);
|
this.root.hud.signals.pasteBlueprintRequested.dispatch();
|
||||||
} else {
|
this.currentBlueprint.set(this.lastBlueprintUsed);
|
||||||
this.root.soundProxy.playUiError();
|
} else {
|
||||||
}
|
this.root.soundProxy.playUiError();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
/**
|
|
||||||
*
|
/**
|
||||||
* @param {DrawParameters} parameters
|
*
|
||||||
*/
|
* @param {DrawParameters} parameters
|
||||||
draw(parameters) {
|
*/
|
||||||
const blueprint = this.currentBlueprint.get();
|
draw(parameters) {
|
||||||
if (!blueprint) {
|
const blueprint = this.currentBlueprint.get();
|
||||||
return;
|
if (!blueprint) {
|
||||||
}
|
return;
|
||||||
const mousePosition = this.root.app.mousePosition;
|
}
|
||||||
if (!mousePosition) {
|
const mousePosition = this.root.app.mousePosition;
|
||||||
// Not on screen
|
if (!mousePosition) {
|
||||||
return;
|
// Not on screen
|
||||||
}
|
return;
|
||||||
|
}
|
||||||
const worldPos = this.root.camera.screenToWorld(mousePosition);
|
|
||||||
const tile = worldPos.toTileSpace();
|
const worldPos = this.root.camera.screenToWorld(mousePosition);
|
||||||
blueprint.draw(parameters, tile);
|
const tile = worldPos.toTileSpace();
|
||||||
}
|
blueprint.draw(parameters, tile);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -42,7 +42,7 @@ export class HUDBuildingsToolbar extends HUDBaseToolbar {
|
|||||||
],
|
],
|
||||||
visibilityCondition: () =>
|
visibilityCondition: () =>
|
||||||
!this.root.camera.getIsMapOverlayActive() && this.root.currentLayer === "regular",
|
!this.root.camera.getIsMapOverlayActive() && this.root.currentLayer === "regular",
|
||||||
htmlElementId: "ingame_HUD_buildings_toolbar",
|
htmlElementId: "ingame_HUD_BuildingsToolbar",
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
21
src/js/game/hud/parts/cat_memes.js
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
import { makeDiv } from "../../../core/utils";
|
||||||
|
import { BaseHUDPart } from "../base_hud_part";
|
||||||
|
import { DynamicDomAttach } from "../dynamic_dom_attach";
|
||||||
|
|
||||||
|
const memeShowIntervalSeconds = 70 * 60;
|
||||||
|
const memeShowDuration = 5;
|
||||||
|
|
||||||
|
export class HUDCatMemes extends BaseHUDPart {
|
||||||
|
createElements(parent) {
|
||||||
|
this.element = makeDiv(parent, "ingame_HUD_CatMemes");
|
||||||
|
}
|
||||||
|
|
||||||
|
initialize() {
|
||||||
|
this.domAttach = new DynamicDomAttach(this.root, this.element);
|
||||||
|
}
|
||||||
|
|
||||||
|
update() {
|
||||||
|
const now = this.root.time.realtimeNow();
|
||||||
|
this.domAttach.update(now % memeShowIntervalSeconds > memeShowIntervalSeconds - memeShowDuration);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,16 +0,0 @@
|
|||||||
import { T } from "../../../translations";
|
|
||||||
import { BaseHUDPart } from "../base_hud_part";
|
|
||||||
|
|
||||||
export class HUDPerformanceWarning extends BaseHUDPart {
|
|
||||||
initialize() {
|
|
||||||
this.warningShown = false;
|
|
||||||
this.root.signals.entityManuallyPlaced.add(this.checkAfterPlace, this);
|
|
||||||
}
|
|
||||||
|
|
||||||
checkAfterPlace() {
|
|
||||||
if (!this.warningShown && this.root.entityMgr.entities.length > 10000) {
|
|
||||||
this.root.hud.parts.dialogs.showInfo(T.dialogs.entityWarning.title, T.dialogs.entityWarning.desc);
|
|
||||||
this.warningShown = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,12 +1,11 @@
|
|||||||
import { ClickDetector } from "../../../core/click_detector";
|
import { ClickDetector } from "../../../core/click_detector";
|
||||||
import { formatBigNumber, makeDiv, arrayDeleteValue } from "../../../core/utils";
|
|
||||||
import { ShapeDefinition } from "../../shape_definition";
|
|
||||||
import { BaseHUDPart } from "../base_hud_part";
|
|
||||||
import { blueprintShape, UPGRADES } from "../../upgrades";
|
|
||||||
import { enumHubGoalRewards } from "../../tutorial_goals";
|
|
||||||
import { enumAnalyticsDataSource } from "../../production_analytics";
|
|
||||||
import { T } from "../../../translations";
|
|
||||||
import { globalConfig } from "../../../core/config";
|
import { globalConfig } from "../../../core/config";
|
||||||
|
import { arrayDeleteValue, formatBigNumber, makeDiv } from "../../../core/utils";
|
||||||
|
import { T } from "../../../translations";
|
||||||
|
import { enumAnalyticsDataSource } from "../../production_analytics";
|
||||||
|
import { ShapeDefinition } from "../../shape_definition";
|
||||||
|
import { enumHubGoalRewards } from "../../tutorial_goals";
|
||||||
|
import { BaseHUDPart } from "../base_hud_part";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Manages the pinned shapes on the left side of the screen
|
* Manages the pinned shapes on the left side of the screen
|
||||||
@ -82,7 +81,7 @@ export class HUDPinnedShapes extends BaseHUDPart {
|
|||||||
updateShapesAfterUpgrade() {
|
updateShapesAfterUpgrade() {
|
||||||
for (let i = 0; i < this.pinnedShapes.length; ++i) {
|
for (let i = 0; i < this.pinnedShapes.length; ++i) {
|
||||||
const key = this.pinnedShapes[i];
|
const key = this.pinnedShapes[i];
|
||||||
if (key === blueprintShape) {
|
if (key === this.root.gameMode.getBlueprintShapeKey()) {
|
||||||
// Ignore blueprint shapes
|
// Ignore blueprint shapes
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -107,13 +106,14 @@ export class HUDPinnedShapes extends BaseHUDPart {
|
|||||||
if (key === this.root.hubGoals.currentGoal.definition.getHash()) {
|
if (key === this.root.hubGoals.currentGoal.definition.getHash()) {
|
||||||
return this.root.hubGoals.currentGoal.required;
|
return this.root.hubGoals.currentGoal.required;
|
||||||
}
|
}
|
||||||
if (key === blueprintShape) {
|
if (key === this.root.gameMode.getBlueprintShapeKey()) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if this shape is required for any upgrade
|
// Check if this shape is required for any upgrade
|
||||||
for (const upgradeId in UPGRADES) {
|
const upgrades = this.root.gameMode.getUpgrades();
|
||||||
const upgradeTiers = UPGRADES[upgradeId];
|
for (const upgradeId in upgrades) {
|
||||||
|
const upgradeTiers = upgrades[upgradeId];
|
||||||
const currentTier = this.root.hubGoals.getUpgradeLevel(upgradeId);
|
const currentTier = this.root.hubGoals.getUpgradeLevel(upgradeId);
|
||||||
const tierHandle = upgradeTiers[currentTier];
|
const tierHandle = upgradeTiers[currentTier];
|
||||||
|
|
||||||
@ -138,7 +138,10 @@ export class HUDPinnedShapes extends BaseHUDPart {
|
|||||||
* @param {string} key
|
* @param {string} key
|
||||||
*/
|
*/
|
||||||
isShapePinned(key) {
|
isShapePinned(key) {
|
||||||
if (key === this.root.hubGoals.currentGoal.definition.getHash() || key === blueprintShape) {
|
if (
|
||||||
|
key === this.root.hubGoals.currentGoal.definition.getHash() ||
|
||||||
|
key === this.root.gameMode.getBlueprintShapeKey()
|
||||||
|
) {
|
||||||
// This is a "special" shape which is always pinned
|
// This is a "special" shape which is always pinned
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -178,7 +181,7 @@ export class HUDPinnedShapes extends BaseHUDPart {
|
|||||||
// Pin blueprint shape as well
|
// Pin blueprint shape as well
|
||||||
if (this.root.hubGoals.isRewardUnlocked(enumHubGoalRewards.reward_blueprints)) {
|
if (this.root.hubGoals.isRewardUnlocked(enumHubGoalRewards.reward_blueprints)) {
|
||||||
this.internalPinShape({
|
this.internalPinShape({
|
||||||
key: blueprintShape,
|
key: this.root.gameMode.getBlueprintShapeKey(),
|
||||||
canUnpin: false,
|
canUnpin: false,
|
||||||
className: "blueprint",
|
className: "blueprint",
|
||||||
});
|
});
|
||||||
@ -214,11 +217,11 @@ export class HUDPinnedShapes extends BaseHUDPart {
|
|||||||
|
|
||||||
let detector = null;
|
let detector = null;
|
||||||
if (canUnpin) {
|
if (canUnpin) {
|
||||||
element.classList.add("unpinable");
|
element.classList.add("removable");
|
||||||
detector = new ClickDetector(element, {
|
detector = new ClickDetector(element, {
|
||||||
consumeEvents: true,
|
consumeEvents: true,
|
||||||
preventDefault: true,
|
preventDefault: true,
|
||||||
targetOnly: true,
|
targetOnly: false,
|
||||||
});
|
});
|
||||||
detector.click.add(() => this.unpinShape(key));
|
detector.click.add(() => this.unpinShape(key));
|
||||||
} else {
|
} else {
|
||||||
@ -291,6 +294,7 @@ export class HUDPinnedShapes extends BaseHUDPart {
|
|||||||
* @param {string} key
|
* @param {string} key
|
||||||
*/
|
*/
|
||||||
unpinShape(key) {
|
unpinShape(key) {
|
||||||
|
console.log("unpin", key);
|
||||||
arrayDeleteValue(this.pinnedShapes, key);
|
arrayDeleteValue(this.pinnedShapes, key);
|
||||||
this.rerenderFull();
|
this.rerenderFull();
|
||||||
}
|
}
|
||||||
@ -306,7 +310,7 @@ export class HUDPinnedShapes extends BaseHUDPart {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (key === blueprintShape) {
|
if (key === this.root.gameMode.getBlueprintShapeKey()) {
|
||||||
// Can not pin the blueprint shape
|
// Can not pin the blueprint shape
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,9 +1,7 @@
|
|||||||
import { BaseHUDPart } from "../base_hud_part";
|
|
||||||
import { makeDiv } from "../../../core/utils";
|
import { makeDiv } from "../../../core/utils";
|
||||||
|
import { BaseHUDPart } from "../base_hud_part";
|
||||||
import { DynamicDomAttach } from "../dynamic_dom_attach";
|
import { DynamicDomAttach } from "../dynamic_dom_attach";
|
||||||
import { blueprintShape, UPGRADES } from "../../upgrades";
|
|
||||||
import { enumNotificationType } from "./notifications";
|
import { enumNotificationType } from "./notifications";
|
||||||
import { tutorialGoals } from "../../tutorial_goals";
|
|
||||||
|
|
||||||
export class HUDSandboxController extends BaseHUDPart {
|
export class HUDSandboxController extends BaseHUDPart {
|
||||||
createElements(parent) {
|
createElements(parent) {
|
||||||
@ -75,10 +73,11 @@ export class HUDSandboxController extends BaseHUDPart {
|
|||||||
}
|
}
|
||||||
|
|
||||||
giveBlueprints() {
|
giveBlueprints() {
|
||||||
if (!this.root.hubGoals.storedShapes[blueprintShape]) {
|
const shape = this.root.gameMode.getBlueprintShapeKey();
|
||||||
this.root.hubGoals.storedShapes[blueprintShape] = 0;
|
if (!this.root.hubGoals.storedShapes[shape]) {
|
||||||
|
this.root.hubGoals.storedShapes[shape] = 0;
|
||||||
}
|
}
|
||||||
this.root.hubGoals.storedShapes[blueprintShape] += 1e9;
|
this.root.hubGoals.storedShapes[shape] += 1e9;
|
||||||
}
|
}
|
||||||
|
|
||||||
maxOutAll() {
|
maxOutAll() {
|
||||||
@ -89,7 +88,7 @@ export class HUDSandboxController extends BaseHUDPart {
|
|||||||
}
|
}
|
||||||
|
|
||||||
modifyUpgrade(id, amount) {
|
modifyUpgrade(id, amount) {
|
||||||
const upgradeTiers = UPGRADES[id];
|
const upgradeTiers = this.root.gameMode.getUpgrades()[id];
|
||||||
const maxLevel = upgradeTiers.length;
|
const maxLevel = upgradeTiers.length;
|
||||||
|
|
||||||
this.root.hubGoals.upgradeLevels[id] = Math.max(
|
this.root.hubGoals.upgradeLevels[id] = Math.max(
|
||||||
@ -122,9 +121,10 @@ export class HUDSandboxController extends BaseHUDPart {
|
|||||||
|
|
||||||
// Compute gained rewards
|
// Compute gained rewards
|
||||||
hubGoals.gainedRewards = {};
|
hubGoals.gainedRewards = {};
|
||||||
|
const levels = this.root.gameMode.getLevelDefinitions();
|
||||||
for (let i = 0; i < hubGoals.level - 1; ++i) {
|
for (let i = 0; i < hubGoals.level - 1; ++i) {
|
||||||
if (i < tutorialGoals.length) {
|
if (i < levels.length) {
|
||||||
const reward = tutorialGoals[i].reward;
|
const reward = levels[i].reward;
|
||||||
hubGoals.gainedRewards[reward] = (hubGoals.gainedRewards[reward] || 0) + 1;
|
hubGoals.gainedRewards[reward] = (hubGoals.gainedRewards[reward] || 0) + 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,13 +1,13 @@
|
|||||||
import { BaseHUDPart } from "../base_hud_part";
|
|
||||||
import { KEYMAPPINGS } from "../../key_action_mapper";
|
|
||||||
import { IS_DEMO, globalConfig } from "../../../core/config";
|
|
||||||
import { T } from "../../../translations";
|
|
||||||
import { createLogger } from "../../../core/logging";
|
|
||||||
import { StaticMapEntityComponent } from "../../components/static_map_entity";
|
|
||||||
import { Vector } from "../../../core/vector";
|
|
||||||
import { makeOffscreenBuffer } from "../../../core/buffer_utils";
|
import { makeOffscreenBuffer } from "../../../core/buffer_utils";
|
||||||
|
import { globalConfig } from "../../../core/config";
|
||||||
import { DrawParameters } from "../../../core/draw_parameters";
|
import { DrawParameters } from "../../../core/draw_parameters";
|
||||||
|
import { createLogger } from "../../../core/logging";
|
||||||
import { Rectangle } from "../../../core/rectangle";
|
import { Rectangle } from "../../../core/rectangle";
|
||||||
|
import { Vector } from "../../../core/vector";
|
||||||
|
import { T } from "../../../translations";
|
||||||
|
import { StaticMapEntityComponent } from "../../components/static_map_entity";
|
||||||
|
import { KEYMAPPINGS } from "../../key_action_mapper";
|
||||||
|
import { BaseHUDPart } from "../base_hud_part";
|
||||||
|
|
||||||
const logger = createLogger("screenshot_exporter");
|
const logger = createLogger("screenshot_exporter");
|
||||||
|
|
||||||
@ -19,7 +19,7 @@ export class HUDScreenshotExporter extends BaseHUDPart {
|
|||||||
}
|
}
|
||||||
|
|
||||||
startExport() {
|
startExport() {
|
||||||
if (IS_DEMO) {
|
if (!this.root.app.restrictionMgr.getIsExportingScreenshotsPossible()) {
|
||||||
this.root.hud.parts.dialogs.showFeatureRestrictionInfo(T.demo.features.exportingBase);
|
this.root.hud.parts.dialogs.showFeatureRestrictionInfo(T.demo.features.exportingBase);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -87,7 +87,7 @@ export class HUDScreenshotExporter extends BaseHUDPart {
|
|||||||
const parameters = new DrawParameters({
|
const parameters = new DrawParameters({
|
||||||
context,
|
context,
|
||||||
visibleRect,
|
visibleRect,
|
||||||
desiredAtlasScale: chunkScale,
|
desiredAtlasScale: 0.25,
|
||||||
root: this.root,
|
root: this.root,
|
||||||
zoomLevel: chunkScale,
|
zoomLevel: chunkScale,
|
||||||
});
|
});
|
||||||
|
|||||||
@ -43,7 +43,7 @@ export class HUDSettingsMenu extends BaseHUDPart {
|
|||||||
];
|
];
|
||||||
|
|
||||||
for (let i = 0; i < buttons.length; ++i) {
|
for (let i = 0; i < buttons.length; ++i) {
|
||||||
const { title, action, id } = buttons[i];
|
const { action, id } = buttons[i];
|
||||||
|
|
||||||
const element = document.createElement("button");
|
const element = document.createElement("button");
|
||||||
element.classList.add("styledButton");
|
element.classList.add("styledButton");
|
||||||
|
|||||||
@ -1,9 +1,8 @@
|
|||||||
import { ClickDetector } from "../../../core/click_detector";
|
import { ClickDetector } from "../../../core/click_detector";
|
||||||
import { InputReceiver } from "../../../core/input_receiver";
|
import { InputReceiver } from "../../../core/input_receiver";
|
||||||
import { formatBigNumber, makeDiv } from "../../../core/utils";
|
import { formatBigNumber, getRomanNumber, makeDiv } from "../../../core/utils";
|
||||||
import { T } from "../../../translations";
|
import { T } from "../../../translations";
|
||||||
import { KeyActionMapper, KEYMAPPINGS } from "../../key_action_mapper";
|
import { KeyActionMapper, KEYMAPPINGS } from "../../key_action_mapper";
|
||||||
import { UPGRADES } from "../../upgrades";
|
|
||||||
import { BaseHUDPart } from "../base_hud_part";
|
import { BaseHUDPart } from "../base_hud_part";
|
||||||
import { DynamicDomAttach } from "../dynamic_dom_attach";
|
import { DynamicDomAttach } from "../dynamic_dom_attach";
|
||||||
|
|
||||||
@ -21,7 +20,7 @@ export class HUDShop extends BaseHUDPart {
|
|||||||
this.upgradeToElements = {};
|
this.upgradeToElements = {};
|
||||||
|
|
||||||
// Upgrades
|
// Upgrades
|
||||||
for (const upgradeId in UPGRADES) {
|
for (const upgradeId in this.root.gameMode.getUpgrades()) {
|
||||||
const handle = {};
|
const handle = {};
|
||||||
handle.requireIndexToElement = [];
|
handle.requireIndexToElement = [];
|
||||||
|
|
||||||
@ -59,7 +58,7 @@ export class HUDShop extends BaseHUDPart {
|
|||||||
rerenderFull() {
|
rerenderFull() {
|
||||||
for (const upgradeId in this.upgradeToElements) {
|
for (const upgradeId in this.upgradeToElements) {
|
||||||
const handle = this.upgradeToElements[upgradeId];
|
const handle = this.upgradeToElements[upgradeId];
|
||||||
const upgradeTiers = UPGRADES[upgradeId];
|
const upgradeTiers = this.root.gameMode.getUpgrades()[upgradeId];
|
||||||
|
|
||||||
const currentTier = this.root.hubGoals.getUpgradeLevel(upgradeId);
|
const currentTier = this.root.hubGoals.getUpgradeLevel(upgradeId);
|
||||||
const currentTierMultiplier = this.root.hubGoals.upgradeImprovements[upgradeId];
|
const currentTierMultiplier = this.root.hubGoals.upgradeImprovements[upgradeId];
|
||||||
@ -68,7 +67,7 @@ export class HUDShop extends BaseHUDPart {
|
|||||||
// Set tier
|
// Set tier
|
||||||
handle.elemTierLabel.innerText = T.ingame.shop.tier.replace(
|
handle.elemTierLabel.innerText = T.ingame.shop.tier.replace(
|
||||||
"<x>",
|
"<x>",
|
||||||
"" + T.ingame.shop.tierLabels[currentTier]
|
getRomanNumber(currentTier + 1)
|
||||||
);
|
);
|
||||||
|
|
||||||
handle.elemTierLabel.setAttribute("data-tier", currentTier);
|
handle.elemTierLabel.setAttribute("data-tier", currentTier);
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { THIRDPARTY_URLS } from "../../../core/config";
|
import { A_B_TESTING_LINK_TYPE, THIRDPARTY_URLS } from "../../../core/config";
|
||||||
import { InputReceiver } from "../../../core/input_receiver";
|
import { InputReceiver } from "../../../core/input_receiver";
|
||||||
import { makeDiv } from "../../../core/utils";
|
import { makeDiv } from "../../../core/utils";
|
||||||
import { T } from "../../../translations";
|
import { T } from "../../../translations";
|
||||||
@ -33,16 +33,17 @@ export class HUDStandaloneAdvantages extends BaseHUDPart {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="lowerBar">
|
<div class="lowerBar">
|
||||||
<button class="steamLinkButton">
|
<button class="steamLinkButton ${A_B_TESTING_LINK_TYPE}"></button>
|
||||||
<button class="otherCloseButton">${T.ingame.standaloneAdvantages.no_thanks}</button>
|
<button class="otherCloseButton">${T.ingame.standaloneAdvantages.no_thanks}</button>
|
||||||
</button>
|
|
||||||
</div>
|
</div>
|
||||||
`
|
`
|
||||||
);
|
);
|
||||||
|
|
||||||
this.trackClicks(this.contentDiv.querySelector("button.steamLinkButton"), () => {
|
this.trackClicks(this.contentDiv.querySelector("button.steamLinkButton"), () => {
|
||||||
this.root.app.analytics.trackUiClick("standalone_advantage_visit_steam");
|
this.root.app.analytics.trackUiClick("standalone_advantage_visit_steam");
|
||||||
this.root.app.platformWrapper.openExternalLink(THIRDPARTY_URLS.standaloneStorePage + "?ref=savs");
|
this.root.app.platformWrapper.openExternalLink(
|
||||||
|
THIRDPARTY_URLS.standaloneStorePage + "?ref=savs&prc=" + A_B_TESTING_LINK_TYPE
|
||||||
|
);
|
||||||
this.close();
|
this.close();
|
||||||
});
|
});
|
||||||
this.trackClicks(this.contentDiv.querySelector("button.otherCloseButton"), () => {
|
this.trackClicks(this.contentDiv.querySelector("button.otherCloseButton"), () => {
|
||||||
|
|||||||
@ -1,14 +1,14 @@
|
|||||||
import { globalConfig } from "../../../core/config";
|
import { globalConfig } from "../../../core/config";
|
||||||
import { gMetaBuildingRegistry } from "../../../core/global_registries";
|
import { gMetaBuildingRegistry } from "../../../core/global_registries";
|
||||||
|
import { InputReceiver } from "../../../core/input_receiver";
|
||||||
import { makeDiv } from "../../../core/utils";
|
import { makeDiv } from "../../../core/utils";
|
||||||
import { SOUNDS } from "../../../platform/sound";
|
import { SOUNDS } from "../../../platform/sound";
|
||||||
import { T } from "../../../translations";
|
import { T } from "../../../translations";
|
||||||
import { defaultBuildingVariant } from "../../meta_building";
|
import { defaultBuildingVariant } from "../../meta_building";
|
||||||
import { enumHubGoalRewards, tutorialGoals } from "../../tutorial_goals";
|
import { enumHubGoalRewards } from "../../tutorial_goals";
|
||||||
|
import { enumHubGoalRewardsToContentUnlocked } from "../../tutorial_goals_mappings";
|
||||||
import { BaseHUDPart } from "../base_hud_part";
|
import { BaseHUDPart } from "../base_hud_part";
|
||||||
import { DynamicDomAttach } from "../dynamic_dom_attach";
|
import { DynamicDomAttach } from "../dynamic_dom_attach";
|
||||||
import { enumHubGoalRewardsToContentUnlocked } from "../../tutorial_goals_mappings";
|
|
||||||
import { InputReceiver } from "../../../core/input_receiver";
|
|
||||||
import { enumNotificationType } from "./notifications";
|
import { enumNotificationType } from "./notifications";
|
||||||
|
|
||||||
export class HUDUnlockNotification extends BaseHUDPart {
|
export class HUDUnlockNotification extends BaseHUDPart {
|
||||||
@ -53,7 +53,9 @@ export class HUDUnlockNotification extends BaseHUDPart {
|
|||||||
showForLevel(level, reward) {
|
showForLevel(level, reward) {
|
||||||
this.root.soundProxy.playUi(SOUNDS.levelComplete);
|
this.root.soundProxy.playUi(SOUNDS.levelComplete);
|
||||||
|
|
||||||
if (level > tutorialGoals.length) {
|
const levels = this.root.gameMode.getLevelDefinitions();
|
||||||
|
// Don't use getIsFreeplay() because we want the freeplay level up to show
|
||||||
|
if (level > levels.length) {
|
||||||
this.root.hud.signals.notification.dispatch(
|
this.root.hud.signals.notification.dispatch(
|
||||||
T.ingame.notifications.freeplayLevelComplete.replace("<level>", String(level)),
|
T.ingame.notifications.freeplayLevelComplete.replace("<level>", String(level)),
|
||||||
enumNotificationType.success
|
enumNotificationType.success
|
||||||
|
|||||||
@ -4,6 +4,9 @@ import { T } from "../../../translations";
|
|||||||
import { BaseHUDPart } from "../base_hud_part";
|
import { BaseHUDPart } from "../base_hud_part";
|
||||||
import { DynamicDomAttach } from "../dynamic_dom_attach";
|
import { DynamicDomAttach } from "../dynamic_dom_attach";
|
||||||
|
|
||||||
|
const watermarkShowIntervalSeconds = G_IS_DEV ? 120 : 7 * 60;
|
||||||
|
const watermarkShowDuration = 5;
|
||||||
|
|
||||||
export class HUDWatermark extends BaseHUDPart {
|
export class HUDWatermark extends BaseHUDPart {
|
||||||
createElements(parent) {
|
createElements(parent) {
|
||||||
this.element = makeDiv(
|
this.element = makeDiv(
|
||||||
@ -38,7 +41,9 @@ export class HUDWatermark extends BaseHUDPart {
|
|||||||
}
|
}
|
||||||
|
|
||||||
update() {
|
update() {
|
||||||
this.domAttach.update(this.root.time.realtimeNow() % (G_IS_DEV ? 20 : 180) < 5);
|
this.domAttach.update(
|
||||||
|
this.root.time.realtimeNow() % watermarkShowIntervalSeconds < watermarkShowDuration
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
onWatermarkClick() {
|
onWatermarkClick() {
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { makeOffscreenBuffer } from "../../../core/buffer_utils";
|
import { makeOffscreenBuffer } from "../../../core/buffer_utils";
|
||||||
import { globalConfig, IS_DEMO, THIRDPARTY_URLS } from "../../../core/config";
|
import { globalConfig, THIRDPARTY_URLS } from "../../../core/config";
|
||||||
import { DrawParameters } from "../../../core/draw_parameters";
|
import { DrawParameters } from "../../../core/draw_parameters";
|
||||||
import { Loader } from "../../../core/loader";
|
import { Loader } from "../../../core/loader";
|
||||||
import { DialogWithForm } from "../../../core/modal_dialog_elements";
|
import { DialogWithForm } from "../../../core/modal_dialog_elements";
|
||||||
@ -302,7 +302,7 @@ export class HUDWaypoints extends BaseHUDPart {
|
|||||||
// Show info that you can have only N markers in the demo,
|
// Show info that you can have only N markers in the demo,
|
||||||
// actually show this *after* entering the name so you want the
|
// actually show this *after* entering the name so you want the
|
||||||
// standalone even more (I'm evil :P)
|
// standalone even more (I'm evil :P)
|
||||||
if (IS_DEMO && this.waypoints.length > 2) {
|
if (this.waypoints.length > this.root.app.restrictionMgr.getMaximumWaypoints()) {
|
||||||
this.root.hud.parts.dialogs.showFeatureRestrictionInfo(
|
this.root.hud.parts.dialogs.showFeatureRestrictionInfo(
|
||||||
"",
|
"",
|
||||||
T.dialogs.markerDemoLimit.desc
|
T.dialogs.markerDemoLimit.desc
|
||||||
|
|||||||
@ -248,6 +248,8 @@ export function getStringForKeyCode(code) {
|
|||||||
return ",";
|
return ",";
|
||||||
case 189:
|
case 189:
|
||||||
return "-";
|
return "-";
|
||||||
|
case 190:
|
||||||
|
return ".";
|
||||||
case 191:
|
case 191:
|
||||||
return "/";
|
return "/";
|
||||||
case 219:
|
case 219:
|
||||||
@ -260,7 +262,9 @@ export function getStringForKeyCode(code) {
|
|||||||
return "'";
|
return "'";
|
||||||
}
|
}
|
||||||
|
|
||||||
return String.fromCharCode(code);
|
return (48 <= code && code <= 57) || (65 <= code && code <= 90)
|
||||||
|
? String.fromCharCode(code)
|
||||||
|
: "[" + code + "]";
|
||||||
}
|
}
|
||||||
|
|
||||||
export class Keybinding {
|
export class Keybinding {
|
||||||
|
|||||||
@ -26,11 +26,6 @@ export class MapView extends BaseMap {
|
|||||||
|
|
||||||
/** @type {CanvasRenderingContext2D} */
|
/** @type {CanvasRenderingContext2D} */
|
||||||
this.cachedBackgroundContext = null;
|
this.cachedBackgroundContext = null;
|
||||||
/**
|
|
||||||
* Cached pattern of the stripes background
|
|
||||||
* @type {CanvasPattern} */
|
|
||||||
this.cachedBackgroundPattern = null;
|
|
||||||
|
|
||||||
this.internalInitializeCachedBackgroundCanvases();
|
this.internalInitializeCachedBackgroundCanvases();
|
||||||
this.root.signals.aboutToDestruct.add(this.cleanup, this);
|
this.root.signals.aboutToDestruct.add(this.cleanup, this);
|
||||||
|
|
||||||
@ -42,7 +37,6 @@ export class MapView extends BaseMap {
|
|||||||
cleanup() {
|
cleanup() {
|
||||||
freeCanvas(this.cachedBackgroundCanvas);
|
freeCanvas(this.cachedBackgroundCanvas);
|
||||||
this.cachedBackgroundCanvas = null;
|
this.cachedBackgroundCanvas = null;
|
||||||
this.cachedBackgroundPattern = null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -191,19 +185,15 @@ export class MapView extends BaseMap {
|
|||||||
* @param {DrawParameters} parameters
|
* @param {DrawParameters} parameters
|
||||||
*/
|
*/
|
||||||
drawBackground(parameters) {
|
drawBackground(parameters) {
|
||||||
if (!this.cachedBackgroundPattern) {
|
|
||||||
this.cachedBackgroundPattern = parameters.context.createPattern(
|
|
||||||
this.cachedBackgroundCanvas,
|
|
||||||
"repeat"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Render tile grid
|
// Render tile grid
|
||||||
if (!this.root.app.settings.getAllSettings().disableTileGrid) {
|
if (!this.root.app.settings.getAllSettings().disableTileGrid) {
|
||||||
const dpi = this.backgroundCacheDPI;
|
const dpi = this.backgroundCacheDPI;
|
||||||
parameters.context.scale(1 / dpi, 1 / dpi);
|
parameters.context.scale(1 / dpi, 1 / dpi);
|
||||||
|
|
||||||
parameters.context.fillStyle = this.cachedBackgroundPattern;
|
parameters.context.fillStyle = parameters.context.createPattern(
|
||||||
|
this.cachedBackgroundCanvas,
|
||||||
|
"repeat"
|
||||||
|
);
|
||||||
parameters.context.fillRect(
|
parameters.context.fillRect(
|
||||||
parameters.visibleRect.x * dpi,
|
parameters.visibleRect.x * dpi,
|
||||||
parameters.visibleRect.y * dpi,
|
parameters.visibleRect.y * dpi,
|
||||||
|
|||||||
480
src/js/game/modes/regular.js
Normal file
@ -0,0 +1,480 @@
|
|||||||
|
import { findNiceIntegerValue } from "../../core/utils";
|
||||||
|
import { GameMode } from "../game_mode";
|
||||||
|
import { ShapeDefinition } from "../shape_definition";
|
||||||
|
import { enumHubGoalRewards } from "../tutorial_goals";
|
||||||
|
|
||||||
|
const rocketShape = "CbCuCbCu:Sr------:--CrSrCr:CwCwCwCw";
|
||||||
|
const finalGameShape = "RuCw--Cw:----Ru--";
|
||||||
|
const preparementShape = "CpRpCp--:SwSwSwSw";
|
||||||
|
const blueprintShape = "CbCbCbRb:CwCwCwCw";
|
||||||
|
|
||||||
|
// Tiers need % of the previous tier as requirement too
|
||||||
|
const tierGrowth = 2.5;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates all upgrades
|
||||||
|
* @returns {Object<string, import("../game_mode").UpgradeTiers>} */
|
||||||
|
function generateUpgrades(limitedVersion = false) {
|
||||||
|
const fixedImprovements = [0.5, 0.5, 1, 1, 2, 1, 1];
|
||||||
|
const numEndgameUpgrades = limitedVersion ? 0 : 1000 - fixedImprovements.length - 1;
|
||||||
|
|
||||||
|
function generateInfiniteUnlocks() {
|
||||||
|
return new Array(numEndgameUpgrades).fill(null).map((_, i) => ({
|
||||||
|
required: [
|
||||||
|
{ shape: preparementShape, amount: 30000 + i * 10000 },
|
||||||
|
{ shape: finalGameShape, amount: 20000 + i * 5000 },
|
||||||
|
{ shape: rocketShape, amount: 20000 + i * 5000 },
|
||||||
|
],
|
||||||
|
excludePrevious: true,
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fill in endgame upgrades
|
||||||
|
for (let i = 0; i < numEndgameUpgrades; ++i) {
|
||||||
|
if (i < 20) {
|
||||||
|
fixedImprovements.push(0.1);
|
||||||
|
} else if (i < 50) {
|
||||||
|
fixedImprovements.push(0.05);
|
||||||
|
} else if (i < 100) {
|
||||||
|
fixedImprovements.push(0.025);
|
||||||
|
} else {
|
||||||
|
fixedImprovements.push(0.0125);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const upgrades = {
|
||||||
|
belt: [
|
||||||
|
{
|
||||||
|
required: [{ shape: "CuCuCuCu", amount: 60 }],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
required: [{ shape: "--CuCu--", amount: 500 }],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
required: [{ shape: "CpCpCpCp", amount: 1000 }],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
required: [{ shape: "SrSrSrSr:CyCyCyCy", amount: 6000 }],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
required: [{ shape: "SrSrSrSr:CyCyCyCy:SwSwSwSw", amount: 25000 }],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
required: [{ shape: preparementShape, amount: 25000 }],
|
||||||
|
excludePrevious: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
required: [
|
||||||
|
{ shape: preparementShape, amount: 25000 },
|
||||||
|
{ shape: finalGameShape, amount: 50000 },
|
||||||
|
],
|
||||||
|
excludePrevious: true,
|
||||||
|
},
|
||||||
|
...generateInfiniteUnlocks(),
|
||||||
|
],
|
||||||
|
|
||||||
|
miner: [
|
||||||
|
{
|
||||||
|
required: [{ shape: "RuRuRuRu", amount: 300 }],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
required: [{ shape: "Cu------", amount: 800 }],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
required: [{ shape: "ScScScSc", amount: 3500 }],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
required: [{ shape: "CwCwCwCw:WbWbWbWb", amount: 23000 }],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
required: [{ shape: "CbRbRbCb:CwCwCwCw:WbWbWbWb", amount: 50000 }],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
required: [{ shape: preparementShape, amount: 25000 }],
|
||||||
|
excludePrevious: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
required: [
|
||||||
|
{ shape: preparementShape, amount: 25000 },
|
||||||
|
{ shape: finalGameShape, amount: 50000 },
|
||||||
|
],
|
||||||
|
excludePrevious: true,
|
||||||
|
},
|
||||||
|
...generateInfiniteUnlocks(),
|
||||||
|
],
|
||||||
|
|
||||||
|
processors: [
|
||||||
|
{
|
||||||
|
required: [{ shape: "SuSuSuSu", amount: 500 }],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
required: [{ shape: "RuRu----", amount: 600 }],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
required: [{ shape: "CgScScCg", amount: 3500 }],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
required: [{ shape: "CwCrCwCr:SgSgSgSg", amount: 25000 }],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
required: [{ shape: "WrRgWrRg:CwCrCwCr:SgSgSgSg", amount: 50000 }],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
required: [{ shape: preparementShape, amount: 25000 }],
|
||||||
|
excludePrevious: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
required: [
|
||||||
|
{ shape: preparementShape, amount: 25000 },
|
||||||
|
{ shape: finalGameShape, amount: 50000 },
|
||||||
|
],
|
||||||
|
excludePrevious: true,
|
||||||
|
},
|
||||||
|
...generateInfiniteUnlocks(),
|
||||||
|
],
|
||||||
|
|
||||||
|
painting: [
|
||||||
|
{
|
||||||
|
required: [{ shape: "RbRb----", amount: 600 }],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
required: [{ shape: "WrWrWrWr", amount: 3800 }],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
required: [{ shape: "RpRpRpRp:CwCwCwCw", amount: 6500 }],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
required: [{ shape: "WpWpWpWp:CwCwCwCw:WpWpWpWp", amount: 25000 }],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
required: [{ shape: "WpWpWpWp:CwCwCwCw:WpWpWpWp:CwCwCwCw", amount: 50000 }],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
required: [{ shape: preparementShape, amount: 25000 }],
|
||||||
|
excludePrevious: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
required: [
|
||||||
|
{ shape: preparementShape, amount: 25000 },
|
||||||
|
{ shape: finalGameShape, amount: 50000 },
|
||||||
|
],
|
||||||
|
excludePrevious: true,
|
||||||
|
},
|
||||||
|
...generateInfiniteUnlocks(),
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
// Automatically generate tier levels
|
||||||
|
for (const upgradeId in upgrades) {
|
||||||
|
const upgradeTiers = upgrades[upgradeId];
|
||||||
|
|
||||||
|
let currentTierRequirements = [];
|
||||||
|
for (let i = 0; i < upgradeTiers.length; ++i) {
|
||||||
|
const tierHandle = upgradeTiers[i];
|
||||||
|
tierHandle.improvement = fixedImprovements[i];
|
||||||
|
const originalRequired = tierHandle.required.slice();
|
||||||
|
|
||||||
|
for (let k = currentTierRequirements.length - 1; k >= 0; --k) {
|
||||||
|
const oldTierRequirement = currentTierRequirements[k];
|
||||||
|
if (!tierHandle.excludePrevious) {
|
||||||
|
tierHandle.required.unshift({
|
||||||
|
shape: oldTierRequirement.shape,
|
||||||
|
amount: oldTierRequirement.amount,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
currentTierRequirements.push(
|
||||||
|
...originalRequired.map(req => ({
|
||||||
|
amount: req.amount,
|
||||||
|
shape: req.shape,
|
||||||
|
}))
|
||||||
|
);
|
||||||
|
currentTierRequirements.forEach(tier => {
|
||||||
|
tier.amount = findNiceIntegerValue(tier.amount * tierGrowth);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// VALIDATE
|
||||||
|
if (G_IS_DEV) {
|
||||||
|
for (const upgradeId in upgrades) {
|
||||||
|
upgrades[upgradeId].forEach(tier => {
|
||||||
|
tier.required.forEach(({ shape }) => {
|
||||||
|
try {
|
||||||
|
ShapeDefinition.fromShortKey(shape);
|
||||||
|
} catch (ex) {
|
||||||
|
throw new Error("Invalid upgrade goal: '" + ex + "' for shape" + shape);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return upgrades;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates the level definitions
|
||||||
|
* @param {boolean} limitedVersion
|
||||||
|
*/
|
||||||
|
export function generateLevelDefinitions(limitedVersion = false) {
|
||||||
|
const levelDefinitions = [
|
||||||
|
// 1
|
||||||
|
// Circle
|
||||||
|
{
|
||||||
|
shape: "CuCuCuCu", // belts t1
|
||||||
|
required: 30,
|
||||||
|
reward: enumHubGoalRewards.reward_cutter_and_trash,
|
||||||
|
},
|
||||||
|
|
||||||
|
// 2
|
||||||
|
// Cutter
|
||||||
|
{
|
||||||
|
shape: "----CuCu", //
|
||||||
|
required: 40,
|
||||||
|
reward: enumHubGoalRewards.no_reward,
|
||||||
|
},
|
||||||
|
|
||||||
|
// 3
|
||||||
|
// Rectangle
|
||||||
|
{
|
||||||
|
shape: "RuRuRuRu", // miners t1
|
||||||
|
required: 70,
|
||||||
|
reward: enumHubGoalRewards.reward_balancer,
|
||||||
|
},
|
||||||
|
|
||||||
|
// 4
|
||||||
|
{
|
||||||
|
shape: "RuRu----", // processors t2
|
||||||
|
required: 70,
|
||||||
|
reward: enumHubGoalRewards.reward_rotater,
|
||||||
|
},
|
||||||
|
|
||||||
|
// 5
|
||||||
|
// Rotater
|
||||||
|
{
|
||||||
|
shape: "Cu----Cu", // belts t2
|
||||||
|
required: 170,
|
||||||
|
reward: enumHubGoalRewards.reward_tunnel,
|
||||||
|
},
|
||||||
|
|
||||||
|
// 6
|
||||||
|
{
|
||||||
|
shape: "Cu------", // miners t2
|
||||||
|
required: 270,
|
||||||
|
reward: enumHubGoalRewards.reward_painter,
|
||||||
|
},
|
||||||
|
|
||||||
|
// 7
|
||||||
|
// Painter
|
||||||
|
{
|
||||||
|
shape: "CrCrCrCr", // unused
|
||||||
|
required: 300,
|
||||||
|
reward: enumHubGoalRewards.reward_rotater_ccw,
|
||||||
|
},
|
||||||
|
|
||||||
|
// 8
|
||||||
|
{
|
||||||
|
shape: "RbRb----", // painter t2
|
||||||
|
required: 480,
|
||||||
|
reward: enumHubGoalRewards.reward_mixer,
|
||||||
|
},
|
||||||
|
|
||||||
|
// 9
|
||||||
|
// Mixing (purple)
|
||||||
|
{
|
||||||
|
shape: "CpCpCpCp", // belts t3
|
||||||
|
required: 600,
|
||||||
|
reward: enumHubGoalRewards.reward_merger,
|
||||||
|
},
|
||||||
|
|
||||||
|
// 10
|
||||||
|
// STACKER: Star shape + cyan
|
||||||
|
{
|
||||||
|
shape: "ScScScSc", // miners t3
|
||||||
|
required: 800,
|
||||||
|
reward: enumHubGoalRewards.reward_stacker,
|
||||||
|
},
|
||||||
|
|
||||||
|
// 11
|
||||||
|
// Chainable miner
|
||||||
|
{
|
||||||
|
shape: "CgScScCg", // processors t3
|
||||||
|
required: 1000,
|
||||||
|
reward: enumHubGoalRewards.reward_miner_chainable,
|
||||||
|
},
|
||||||
|
|
||||||
|
// 12
|
||||||
|
// Blueprints
|
||||||
|
{
|
||||||
|
shape: "CbCbCbRb:CwCwCwCw",
|
||||||
|
required: 1000,
|
||||||
|
reward: enumHubGoalRewards.reward_blueprints,
|
||||||
|
},
|
||||||
|
|
||||||
|
// 13
|
||||||
|
// Tunnel Tier 2
|
||||||
|
{
|
||||||
|
shape: "RpRpRpRp:CwCwCwCw", // painting t3
|
||||||
|
required: 3800,
|
||||||
|
reward: enumHubGoalRewards.reward_underground_belt_tier_2,
|
||||||
|
},
|
||||||
|
|
||||||
|
// DEMO STOPS HERE
|
||||||
|
...(limitedVersion
|
||||||
|
? [
|
||||||
|
{
|
||||||
|
shape: "RpRpRpRp:CwCwCwCw",
|
||||||
|
required: 0,
|
||||||
|
reward: enumHubGoalRewards.reward_demo_end,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
: [
|
||||||
|
// 14
|
||||||
|
// Belt reader
|
||||||
|
{
|
||||||
|
shape: "--Cg----:--Cr----", // unused
|
||||||
|
required: 16, // Per second!
|
||||||
|
reward: enumHubGoalRewards.reward_belt_reader,
|
||||||
|
throughputOnly: true,
|
||||||
|
},
|
||||||
|
|
||||||
|
// 15
|
||||||
|
// Storage
|
||||||
|
{
|
||||||
|
shape: "SrSrSrSr:CyCyCyCy", // unused
|
||||||
|
required: 10000,
|
||||||
|
reward: enumHubGoalRewards.reward_storage,
|
||||||
|
},
|
||||||
|
|
||||||
|
// 16
|
||||||
|
// Quad Cutter
|
||||||
|
{
|
||||||
|
shape: "SrSrSrSr:CyCyCyCy:SwSwSwSw", // belts t4 (two variants)
|
||||||
|
required: 6000,
|
||||||
|
reward: enumHubGoalRewards.reward_cutter_quad,
|
||||||
|
},
|
||||||
|
|
||||||
|
// 17
|
||||||
|
// Double painter
|
||||||
|
{
|
||||||
|
shape: "CbRbRbCb:CwCwCwCw:WbWbWbWb", // miner t4 (two variants)
|
||||||
|
required: 20000,
|
||||||
|
reward: enumHubGoalRewards.reward_painter_double,
|
||||||
|
},
|
||||||
|
|
||||||
|
// 18
|
||||||
|
// Rotater (180deg)
|
||||||
|
{
|
||||||
|
shape: "Sg----Sg:CgCgCgCg:--CyCy--", // unused
|
||||||
|
required: 20000,
|
||||||
|
reward: enumHubGoalRewards.reward_rotater_180,
|
||||||
|
},
|
||||||
|
|
||||||
|
// 19
|
||||||
|
// Compact splitter
|
||||||
|
{
|
||||||
|
shape: "CpRpCp--:SwSwSwSw",
|
||||||
|
required: 25000,
|
||||||
|
reward: enumHubGoalRewards.reward_splitter,
|
||||||
|
},
|
||||||
|
|
||||||
|
// 20
|
||||||
|
// WIRES
|
||||||
|
{
|
||||||
|
shape: finalGameShape,
|
||||||
|
required: 25000,
|
||||||
|
reward: enumHubGoalRewards.reward_wires_painter_and_levers,
|
||||||
|
},
|
||||||
|
|
||||||
|
// 21
|
||||||
|
// Filter
|
||||||
|
{
|
||||||
|
shape: "CrCwCrCw:CwCrCwCr:CrCwCrCw:CwCrCwCr",
|
||||||
|
required: 25000,
|
||||||
|
reward: enumHubGoalRewards.reward_filter,
|
||||||
|
},
|
||||||
|
|
||||||
|
// 22
|
||||||
|
// Constant signal
|
||||||
|
{
|
||||||
|
shape: "Cg----Cr:Cw----Cw:Sy------:Cy----Cy",
|
||||||
|
required: 25000,
|
||||||
|
reward: enumHubGoalRewards.reward_constant_signal,
|
||||||
|
},
|
||||||
|
|
||||||
|
// 23
|
||||||
|
// Display
|
||||||
|
{
|
||||||
|
shape: "CcSyCcSy:SyCcSyCc:CcSyCcSy",
|
||||||
|
required: 25000,
|
||||||
|
reward: enumHubGoalRewards.reward_display,
|
||||||
|
},
|
||||||
|
|
||||||
|
// 24 Logic gates
|
||||||
|
{
|
||||||
|
shape: "CcRcCcRc:RwCwRwCw:Sr--Sw--:CyCyCyCy",
|
||||||
|
required: 25000,
|
||||||
|
reward: enumHubGoalRewards.reward_logic_gates,
|
||||||
|
},
|
||||||
|
|
||||||
|
// 25 Virtual Processing
|
||||||
|
{
|
||||||
|
shape: "Rg--Rg--:CwRwCwRw:--Rg--Rg",
|
||||||
|
required: 25000,
|
||||||
|
reward: enumHubGoalRewards.reward_virtual_processing,
|
||||||
|
},
|
||||||
|
|
||||||
|
// 26 Freeplay
|
||||||
|
{
|
||||||
|
shape: "CbCuCbCu:Sr------:--CrSrCr:CwCwCwCw",
|
||||||
|
required: 50000,
|
||||||
|
reward: enumHubGoalRewards.reward_freeplay,
|
||||||
|
},
|
||||||
|
]),
|
||||||
|
];
|
||||||
|
|
||||||
|
if (G_IS_DEV) {
|
||||||
|
levelDefinitions.forEach(({ shape }) => {
|
||||||
|
try {
|
||||||
|
ShapeDefinition.fromShortKey(shape);
|
||||||
|
} catch (ex) {
|
||||||
|
throw new Error("Invalid tutorial goal: '" + ex + "' for shape" + shape);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return levelDefinitions;
|
||||||
|
}
|
||||||
|
|
||||||
|
const fullVersionUpgrades = generateUpgrades(false);
|
||||||
|
const demoVersionUpgrades = generateUpgrades(true);
|
||||||
|
|
||||||
|
const fullVersionLevels = generateLevelDefinitions(false);
|
||||||
|
const demoVersionLevels = generateLevelDefinitions(true);
|
||||||
|
|
||||||
|
export class RegularGameMode extends GameMode {
|
||||||
|
constructor(root) {
|
||||||
|
super(root);
|
||||||
|
}
|
||||||
|
|
||||||
|
getUpgrades() {
|
||||||
|
return this.root.app.restrictionMgr.getHasExtendedUpgrades()
|
||||||
|
? fullVersionUpgrades
|
||||||
|
: demoVersionUpgrades;
|
||||||
|
}
|
||||||
|
|
||||||
|
getIsFreeplayAvailable() {
|
||||||
|
return this.root.app.restrictionMgr.getHasExtendedLevelsAndFreeplay();
|
||||||
|
}
|
||||||
|
|
||||||
|
getBlueprintShapeKey() {
|
||||||
|
return blueprintShape;
|
||||||
|
}
|
||||||
|
|
||||||
|
getLevelDefinitions() {
|
||||||
|
return this.root.app.restrictionMgr.getHasExtendedLevelsAndFreeplay()
|
||||||
|
? fullVersionLevels
|
||||||
|
: demoVersionLevels;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,221 +1,225 @@
|
|||||||
/* eslint-disable no-unused-vars */
|
/* eslint-disable no-unused-vars */
|
||||||
import { Signal } from "../core/signal";
|
import { Signal } from "../core/signal";
|
||||||
import { RandomNumberGenerator } from "../core/rng";
|
import { RandomNumberGenerator } from "../core/rng";
|
||||||
import { createLogger } from "../core/logging";
|
import { createLogger } from "../core/logging";
|
||||||
|
|
||||||
// Type hints
|
// Type hints
|
||||||
/* typehints:start */
|
/* typehints:start */
|
||||||
import { GameTime } from "./time/game_time";
|
import { GameTime } from "./time/game_time";
|
||||||
import { EntityManager } from "./entity_manager";
|
import { EntityManager } from "./entity_manager";
|
||||||
import { GameSystemManager } from "./game_system_manager";
|
import { GameSystemManager } from "./game_system_manager";
|
||||||
import { GameHUD } from "./hud/hud";
|
import { GameHUD } from "./hud/hud";
|
||||||
import { MapView } from "./map_view";
|
import { MapView } from "./map_view";
|
||||||
import { Camera } from "./camera";
|
import { Camera } from "./camera";
|
||||||
import { InGameState } from "../states/ingame";
|
import { InGameState } from "../states/ingame";
|
||||||
import { AutomaticSave } from "./automatic_save";
|
import { AutomaticSave } from "./automatic_save";
|
||||||
import { Application } from "../application";
|
import { Application } from "../application";
|
||||||
import { SoundProxy } from "./sound_proxy";
|
import { SoundProxy } from "./sound_proxy";
|
||||||
import { Savegame } from "../savegame/savegame";
|
import { Savegame } from "../savegame/savegame";
|
||||||
import { GameLogic } from "./logic";
|
import { GameLogic } from "./logic";
|
||||||
import { ShapeDefinitionManager } from "./shape_definition_manager";
|
import { ShapeDefinitionManager } from "./shape_definition_manager";
|
||||||
import { HubGoals } from "./hub_goals";
|
import { HubGoals } from "./hub_goals";
|
||||||
import { BufferMaintainer } from "../core/buffer_maintainer";
|
import { BufferMaintainer } from "../core/buffer_maintainer";
|
||||||
import { ProductionAnalytics } from "./production_analytics";
|
import { ProductionAnalytics } from "./production_analytics";
|
||||||
import { Entity } from "./entity";
|
import { Entity } from "./entity";
|
||||||
import { ShapeDefinition } from "./shape_definition";
|
import { ShapeDefinition } from "./shape_definition";
|
||||||
import { BaseItem } from "./base_item";
|
import { BaseItem } from "./base_item";
|
||||||
import { DynamicTickrate } from "./dynamic_tickrate";
|
import { DynamicTickrate } from "./dynamic_tickrate";
|
||||||
import { KeyActionMapper } from "./key_action_mapper";
|
import { KeyActionMapper } from "./key_action_mapper";
|
||||||
import { Vector } from "../core/vector";
|
import { Vector } from "../core/vector";
|
||||||
/* typehints:end */
|
import { GameMode } from "./game_mode";
|
||||||
|
/* typehints:end */
|
||||||
const logger = createLogger("game/root");
|
|
||||||
|
const logger = createLogger("game/root");
|
||||||
/** @type {Array<Layer>} */
|
|
||||||
export const layers = ["regular", "wires"];
|
/** @type {Array<Layer>} */
|
||||||
|
export const layers = ["regular", "wires"];
|
||||||
/**
|
|
||||||
* The game root is basically the whole game state at a given point,
|
/**
|
||||||
* combining all important classes. We don't have globals, but this
|
* The game root is basically the whole game state at a given point,
|
||||||
* class is passed to almost all game classes.
|
* combining all important classes. We don't have globals, but this
|
||||||
*/
|
* class is passed to almost all game classes.
|
||||||
export class GameRoot {
|
*/
|
||||||
/**
|
export class GameRoot {
|
||||||
* Constructs a new game root
|
/**
|
||||||
* @param {Application} app
|
* Constructs a new game root
|
||||||
*/
|
* @param {Application} app
|
||||||
constructor(app) {
|
*/
|
||||||
this.app = app;
|
constructor(app) {
|
||||||
|
this.app = app;
|
||||||
/** @type {Savegame} */
|
|
||||||
this.savegame = null;
|
/** @type {Savegame} */
|
||||||
|
this.savegame = null;
|
||||||
/** @type {InGameState} */
|
|
||||||
this.gameState = null;
|
/** @type {InGameState} */
|
||||||
|
this.gameState = null;
|
||||||
/** @type {KeyActionMapper} */
|
|
||||||
this.keyMapper = null;
|
/** @type {KeyActionMapper} */
|
||||||
|
this.keyMapper = null;
|
||||||
// Store game dimensions
|
|
||||||
this.gameWidth = 500;
|
// Store game dimensions
|
||||||
this.gameHeight = 500;
|
this.gameWidth = 500;
|
||||||
|
this.gameHeight = 500;
|
||||||
// Stores whether the current session is a fresh game (true), or was continued (false)
|
|
||||||
/** @type {boolean} */
|
// Stores whether the current session is a fresh game (true), or was continued (false)
|
||||||
this.gameIsFresh = true;
|
/** @type {boolean} */
|
||||||
|
this.gameIsFresh = true;
|
||||||
// Stores whether the logic is already initialized
|
|
||||||
/** @type {boolean} */
|
// Stores whether the logic is already initialized
|
||||||
this.logicInitialized = false;
|
/** @type {boolean} */
|
||||||
|
this.logicInitialized = false;
|
||||||
// Stores whether the game is already initialized, that is, all systems etc have been created
|
|
||||||
/** @type {boolean} */
|
// Stores whether the game is already initialized, that is, all systems etc have been created
|
||||||
this.gameInitialized = false;
|
/** @type {boolean} */
|
||||||
|
this.gameInitialized = false;
|
||||||
/**
|
|
||||||
* Whether a bulk operation is running
|
/**
|
||||||
*/
|
* Whether a bulk operation is running
|
||||||
this.bulkOperationRunning = false;
|
*/
|
||||||
|
this.bulkOperationRunning = false;
|
||||||
//////// Other properties ///////
|
|
||||||
|
//////// Other properties ///////
|
||||||
/** @type {Camera} */
|
|
||||||
this.camera = null;
|
/** @type {Camera} */
|
||||||
|
this.camera = null;
|
||||||
/** @type {HTMLCanvasElement} */
|
|
||||||
this.canvas = null;
|
/** @type {HTMLCanvasElement} */
|
||||||
|
this.canvas = null;
|
||||||
/** @type {CanvasRenderingContext2D} */
|
|
||||||
this.context = null;
|
/** @type {CanvasRenderingContext2D} */
|
||||||
|
this.context = null;
|
||||||
/** @type {MapView} */
|
|
||||||
this.map = null;
|
/** @type {MapView} */
|
||||||
|
this.map = null;
|
||||||
/** @type {GameLogic} */
|
|
||||||
this.logic = null;
|
/** @type {GameLogic} */
|
||||||
|
this.logic = null;
|
||||||
/** @type {EntityManager} */
|
|
||||||
this.entityMgr = null;
|
/** @type {EntityManager} */
|
||||||
|
this.entityMgr = null;
|
||||||
/** @type {GameHUD} */
|
|
||||||
this.hud = null;
|
/** @type {GameHUD} */
|
||||||
|
this.hud = null;
|
||||||
/** @type {GameSystemManager} */
|
|
||||||
this.systemMgr = null;
|
/** @type {GameSystemManager} */
|
||||||
|
this.systemMgr = null;
|
||||||
/** @type {GameTime} */
|
|
||||||
this.time = null;
|
/** @type {GameTime} */
|
||||||
|
this.time = null;
|
||||||
/** @type {HubGoals} */
|
|
||||||
this.hubGoals = null;
|
/** @type {HubGoals} */
|
||||||
|
this.hubGoals = null;
|
||||||
/** @type {BufferMaintainer} */
|
|
||||||
this.buffers = null;
|
/** @type {BufferMaintainer} */
|
||||||
|
this.buffers = null;
|
||||||
/** @type {AutomaticSave} */
|
|
||||||
this.automaticSave = null;
|
/** @type {AutomaticSave} */
|
||||||
|
this.automaticSave = null;
|
||||||
/** @type {SoundProxy} */
|
|
||||||
this.soundProxy = null;
|
/** @type {SoundProxy} */
|
||||||
|
this.soundProxy = null;
|
||||||
/** @type {ShapeDefinitionManager} */
|
|
||||||
this.shapeDefinitionMgr = null;
|
/** @type {ShapeDefinitionManager} */
|
||||||
|
this.shapeDefinitionMgr = null;
|
||||||
/** @type {ProductionAnalytics} */
|
|
||||||
this.productionAnalytics = null;
|
/** @type {ProductionAnalytics} */
|
||||||
|
this.productionAnalytics = null;
|
||||||
/** @type {DynamicTickrate} */
|
|
||||||
this.dynamicTickrate = null;
|
/** @type {DynamicTickrate} */
|
||||||
|
this.dynamicTickrate = null;
|
||||||
/** @type {Layer} */
|
|
||||||
this.currentLayer = "regular";
|
/** @type {Layer} */
|
||||||
|
this.currentLayer = "regular";
|
||||||
this.signals = {
|
|
||||||
// Entities
|
/** @type {GameMode} */
|
||||||
entityManuallyPlaced: /** @type {TypedSignal<[Entity]>} */ (new Signal()),
|
this.gameMode = null;
|
||||||
entityAdded: /** @type {TypedSignal<[Entity]>} */ (new Signal()),
|
|
||||||
entityChanged: /** @type {TypedSignal<[Entity]>} */ (new Signal()),
|
this.signals = {
|
||||||
entityGotNewComponent: /** @type {TypedSignal<[Entity]>} */ (new Signal()),
|
// Entities
|
||||||
entityComponentRemoved: /** @type {TypedSignal<[Entity]>} */ (new Signal()),
|
entityManuallyPlaced: /** @type {TypedSignal<[Entity]>} */ (new Signal()),
|
||||||
entityQueuedForDestroy: /** @type {TypedSignal<[Entity]>} */ (new Signal()),
|
entityAdded: /** @type {TypedSignal<[Entity]>} */ (new Signal()),
|
||||||
entityDestroyed: /** @type {TypedSignal<[Entity]>} */ (new Signal()),
|
entityChanged: /** @type {TypedSignal<[Entity]>} */ (new Signal()),
|
||||||
|
entityGotNewComponent: /** @type {TypedSignal<[Entity]>} */ (new Signal()),
|
||||||
// Global
|
entityComponentRemoved: /** @type {TypedSignal<[Entity]>} */ (new Signal()),
|
||||||
resized: /** @type {TypedSignal<[number, number]>} */ (new Signal()),
|
entityQueuedForDestroy: /** @type {TypedSignal<[Entity]>} */ (new Signal()),
|
||||||
readyToRender: /** @type {TypedSignal<[]>} */ (new Signal()),
|
entityDestroyed: /** @type {TypedSignal<[Entity]>} */ (new Signal()),
|
||||||
aboutToDestruct: /** @type {TypedSignal<[]>} */ new Signal(),
|
|
||||||
|
// Global
|
||||||
// Game Hooks
|
resized: /** @type {TypedSignal<[number, number]>} */ (new Signal()),
|
||||||
gameSaved: /** @type {TypedSignal<[]>} */ (new Signal()), // Game got saved
|
readyToRender: /** @type {TypedSignal<[]>} */ (new Signal()),
|
||||||
gameRestored: /** @type {TypedSignal<[]>} */ (new Signal()), // Game got restored
|
aboutToDestruct: /** @type {TypedSignal<[]>} */ new Signal(),
|
||||||
|
|
||||||
gameFrameStarted: /** @type {TypedSignal<[]>} */ (new Signal()), // New frame
|
// Game Hooks
|
||||||
|
gameSaved: /** @type {TypedSignal<[]>} */ (new Signal()), // Game got saved
|
||||||
storyGoalCompleted: /** @type {TypedSignal<[number, string]>} */ (new Signal()),
|
gameRestored: /** @type {TypedSignal<[]>} */ (new Signal()), // Game got restored
|
||||||
upgradePurchased: /** @type {TypedSignal<[string]>} */ (new Signal()),
|
|
||||||
|
gameFrameStarted: /** @type {TypedSignal<[]>} */ (new Signal()), // New frame
|
||||||
// Called right after game is initialized
|
|
||||||
postLoadHook: /** @type {TypedSignal<[]>} */ (new Signal()),
|
storyGoalCompleted: /** @type {TypedSignal<[number, string]>} */ (new Signal()),
|
||||||
|
upgradePurchased: /** @type {TypedSignal<[string]>} */ (new Signal()),
|
||||||
shapeDelivered: /** @type {TypedSignal<[ShapeDefinition]>} */ (new Signal()),
|
|
||||||
itemProduced: /** @type {TypedSignal<[BaseItem]>} */ (new Signal()),
|
// Called right after game is initialized
|
||||||
|
postLoadHook: /** @type {TypedSignal<[]>} */ (new Signal()),
|
||||||
bulkOperationFinished: /** @type {TypedSignal<[]>} */ (new Signal()),
|
|
||||||
|
shapeDelivered: /** @type {TypedSignal<[ShapeDefinition]>} */ (new Signal()),
|
||||||
editModeChanged: /** @type {TypedSignal<[Layer]>} */ (new Signal()),
|
itemProduced: /** @type {TypedSignal<[BaseItem]>} */ (new Signal()),
|
||||||
|
|
||||||
// Called to check if an entity can be placed, second parameter is an additional offset.
|
bulkOperationFinished: /** @type {TypedSignal<[]>} */ (new Signal()),
|
||||||
// Use to introduce additional placement checks
|
|
||||||
prePlacementCheck: /** @type {TypedSignal<[Entity, Vector]>} */ (new Signal()),
|
editModeChanged: /** @type {TypedSignal<[Layer]>} */ (new Signal()),
|
||||||
|
|
||||||
// Called before actually placing an entity, use to perform additional logic
|
// Called to check if an entity can be placed, second parameter is an additional offset.
|
||||||
// for freeing space before actually placing.
|
// Use to introduce additional placement checks
|
||||||
freeEntityAreaBeforeBuild: /** @type {TypedSignal<[Entity]>} */ (new Signal()),
|
prePlacementCheck: /** @type {TypedSignal<[Entity, Vector]>} */ (new Signal()),
|
||||||
};
|
|
||||||
|
// Called before actually placing an entity, use to perform additional logic
|
||||||
// RNG's
|
// for freeing space before actually placing.
|
||||||
/** @type {Object.<string, Object.<string, RandomNumberGenerator>>} */
|
freeEntityAreaBeforeBuild: /** @type {TypedSignal<[Entity]>} */ (new Signal()),
|
||||||
this.rngs = {};
|
};
|
||||||
|
|
||||||
// Work queue
|
// RNG's
|
||||||
this.queue = {
|
/** @type {Object.<string, Object.<string, RandomNumberGenerator>>} */
|
||||||
requireRedraw: false,
|
this.rngs = {};
|
||||||
};
|
|
||||||
}
|
// Work queue
|
||||||
|
this.queue = {
|
||||||
/**
|
requireRedraw: false,
|
||||||
* Destructs the game root
|
};
|
||||||
*/
|
}
|
||||||
destruct() {
|
|
||||||
logger.log("destructing root");
|
/**
|
||||||
this.signals.aboutToDestruct.dispatch();
|
* Destructs the game root
|
||||||
|
*/
|
||||||
this.reset();
|
destruct() {
|
||||||
}
|
logger.log("destructing root");
|
||||||
|
this.signals.aboutToDestruct.dispatch();
|
||||||
/**
|
|
||||||
* Resets the whole root and removes all properties
|
this.reset();
|
||||||
*/
|
}
|
||||||
reset() {
|
|
||||||
if (this.signals) {
|
/**
|
||||||
// Destruct all signals
|
* Resets the whole root and removes all properties
|
||||||
for (let i = 0; i < this.signals.length; ++i) {
|
*/
|
||||||
this.signals[i].removeAll();
|
reset() {
|
||||||
}
|
if (this.signals) {
|
||||||
}
|
// Destruct all signals
|
||||||
|
for (let i = 0; i < this.signals.length; ++i) {
|
||||||
if (this.hud) {
|
this.signals[i].removeAll();
|
||||||
this.hud.cleanup();
|
}
|
||||||
}
|
}
|
||||||
if (this.camera) {
|
|
||||||
this.camera.cleanup();
|
if (this.hud) {
|
||||||
}
|
this.hud.cleanup();
|
||||||
|
}
|
||||||
// Finally free all properties
|
if (this.camera) {
|
||||||
for (let prop in this) {
|
this.camera.cleanup();
|
||||||
if (this.hasOwnProperty(prop)) {
|
}
|
||||||
delete this[prop];
|
|
||||||
}
|
// Finally free all properties
|
||||||
}
|
for (let prop in this) {
|
||||||
}
|
if (this.hasOwnProperty(prop)) {
|
||||||
}
|
delete this[prop];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -12,7 +12,6 @@ import { GameSystemWithFilter } from "../game_system_with_filter";
|
|||||||
import { BOOL_FALSE_SINGLETON, BOOL_TRUE_SINGLETON } from "../items/boolean_item";
|
import { BOOL_FALSE_SINGLETON, BOOL_TRUE_SINGLETON } from "../items/boolean_item";
|
||||||
import { COLOR_ITEM_SINGLETONS } from "../items/color_item";
|
import { COLOR_ITEM_SINGLETONS } from "../items/color_item";
|
||||||
import { ShapeDefinition } from "../shape_definition";
|
import { ShapeDefinition } from "../shape_definition";
|
||||||
import { blueprintShape } from "../upgrades";
|
|
||||||
|
|
||||||
export class ConstantSignalSystem extends GameSystemWithFilter {
|
export class ConstantSignalSystem extends GameSystemWithFilter {
|
||||||
constructor(root) {
|
constructor(root) {
|
||||||
@ -61,7 +60,9 @@ export class ConstantSignalSystem extends GameSystemWithFilter {
|
|||||||
this.root.shapeDefinitionMgr.getShapeItemFromDefinition(
|
this.root.shapeDefinitionMgr.getShapeItemFromDefinition(
|
||||||
this.root.hubGoals.currentGoal.definition
|
this.root.hubGoals.currentGoal.definition
|
||||||
),
|
),
|
||||||
this.root.shapeDefinitionMgr.getShapeItemFromShortKey(blueprintShape),
|
this.root.shapeDefinitionMgr.getShapeItemFromShortKey(
|
||||||
|
this.root.gameMode.getBlueprintShapeKey()
|
||||||
|
),
|
||||||
...this.root.hud.parts.pinnedShapes.pinnedShapes.map(key =>
|
...this.root.hud.parts.pinnedShapes.pinnedShapes.map(key =>
|
||||||
this.root.shapeDefinitionMgr.getShapeItemFromShortKey(key)
|
this.root.shapeDefinitionMgr.getShapeItemFromShortKey(key)
|
||||||
),
|
),
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { globalConfig, IS_DEMO } from "../../core/config";
|
import { globalConfig } from "../../core/config";
|
||||||
import { smoothenDpi } from "../../core/dpi_manager";
|
import { smoothenDpi } from "../../core/dpi_manager";
|
||||||
import { DrawParameters } from "../../core/draw_parameters";
|
import { DrawParameters } from "../../core/draw_parameters";
|
||||||
import { drawSpriteClipped } from "../../core/draw_utils";
|
import { drawSpriteClipped } from "../../core/draw_utils";
|
||||||
|
|||||||
@ -154,22 +154,18 @@ export class LogicGateSystem extends GameSystemWithFilter {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {Array<BaseItem|null>} parameters
|
* @param {Array<BaseItem|null>} parameters
|
||||||
* @returns {[BaseItem, BaseItem]}
|
* @returns {BaseItem}
|
||||||
*/
|
*/
|
||||||
compute_ROTATE(parameters) {
|
compute_ROTATE(parameters) {
|
||||||
const item = parameters[0];
|
const item = parameters[0];
|
||||||
if (!item || item.getItemType() !== "shape") {
|
if (!item || item.getItemType() !== "shape") {
|
||||||
// Not a shape
|
// Not a shape
|
||||||
return [null, null];
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const definition = /** @type {ShapeItem} */ (item).definition;
|
const definition = /** @type {ShapeItem} */ (item).definition;
|
||||||
const rotatedDefinitionCCW = this.root.shapeDefinitionMgr.shapeActionRotateCCW(definition);
|
|
||||||
const rotatedDefinitionCW = this.root.shapeDefinitionMgr.shapeActionRotateCW(definition);
|
const rotatedDefinitionCW = this.root.shapeDefinitionMgr.shapeActionRotateCW(definition);
|
||||||
return [
|
return this.root.shapeDefinitionMgr.getShapeItemFromDefinition(rotatedDefinitionCW);
|
||||||
this.root.shapeDefinitionMgr.getShapeItemFromDefinition(rotatedDefinitionCCW),
|
|
||||||
this.root.shapeDefinitionMgr.getShapeItemFromDefinition(rotatedDefinitionCW),
|
|
||||||
];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -1,7 +1,3 @@
|
|||||||
import { IS_DEMO } from "../core/config";
|
|
||||||
import { ShapeDefinition } from "./shape_definition";
|
|
||||||
import { finalGameShape } from "./upgrades";
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Don't forget to also update tutorial_goals_mappings.js as well as the translations!
|
* Don't forget to also update tutorial_goals_mappings.js as well as the translations!
|
||||||
* @enum {string}
|
* @enum {string}
|
||||||
@ -40,229 +36,3 @@ export const enumHubGoalRewards = {
|
|||||||
no_reward: "no_reward",
|
no_reward: "no_reward",
|
||||||
no_reward_freeplay: "no_reward_freeplay",
|
no_reward_freeplay: "no_reward_freeplay",
|
||||||
};
|
};
|
||||||
|
|
||||||
export const tutorialGoals = [
|
|
||||||
// 1
|
|
||||||
// Circle
|
|
||||||
{
|
|
||||||
shape: "CuCuCuCu", // belts t1
|
|
||||||
required: 30,
|
|
||||||
reward: enumHubGoalRewards.reward_cutter_and_trash,
|
|
||||||
},
|
|
||||||
|
|
||||||
// 2
|
|
||||||
// Cutter
|
|
||||||
{
|
|
||||||
shape: "----CuCu", //
|
|
||||||
required: 40,
|
|
||||||
reward: enumHubGoalRewards.no_reward,
|
|
||||||
},
|
|
||||||
|
|
||||||
// 3
|
|
||||||
// Rectangle
|
|
||||||
{
|
|
||||||
shape: "RuRuRuRu", // miners t1
|
|
||||||
required: 70,
|
|
||||||
reward: enumHubGoalRewards.reward_balancer,
|
|
||||||
},
|
|
||||||
|
|
||||||
// 4
|
|
||||||
{
|
|
||||||
shape: "RuRu----", // processors t2
|
|
||||||
required: 70,
|
|
||||||
reward: enumHubGoalRewards.reward_rotater,
|
|
||||||
},
|
|
||||||
|
|
||||||
// 5
|
|
||||||
// Rotater
|
|
||||||
{
|
|
||||||
shape: "Cu----Cu", // belts t2
|
|
||||||
required: 170,
|
|
||||||
reward: enumHubGoalRewards.reward_tunnel,
|
|
||||||
},
|
|
||||||
|
|
||||||
// 6
|
|
||||||
{
|
|
||||||
shape: "Cu------", // miners t2
|
|
||||||
required: 270,
|
|
||||||
reward: enumHubGoalRewards.reward_painter,
|
|
||||||
},
|
|
||||||
|
|
||||||
// 7
|
|
||||||
// Painter
|
|
||||||
{
|
|
||||||
shape: "CrCrCrCr", // unused
|
|
||||||
required: 300,
|
|
||||||
reward: enumHubGoalRewards.reward_rotater_ccw,
|
|
||||||
},
|
|
||||||
|
|
||||||
// 8
|
|
||||||
{
|
|
||||||
shape: "RbRb----", // painter t2
|
|
||||||
required: 480,
|
|
||||||
reward: enumHubGoalRewards.reward_mixer,
|
|
||||||
},
|
|
||||||
|
|
||||||
// 9
|
|
||||||
// Mixing (purple)
|
|
||||||
{
|
|
||||||
shape: "CpCpCpCp", // belts t3
|
|
||||||
required: 600,
|
|
||||||
reward: enumHubGoalRewards.reward_merger,
|
|
||||||
},
|
|
||||||
|
|
||||||
// 10
|
|
||||||
// STACKER: Star shape + cyan
|
|
||||||
{
|
|
||||||
shape: "ScScScSc", // miners t3
|
|
||||||
required: 800,
|
|
||||||
reward: enumHubGoalRewards.reward_stacker,
|
|
||||||
},
|
|
||||||
|
|
||||||
// 11
|
|
||||||
// Chainable miner
|
|
||||||
{
|
|
||||||
shape: "CgScScCg", // processors t3
|
|
||||||
required: 1000,
|
|
||||||
reward: enumHubGoalRewards.reward_miner_chainable,
|
|
||||||
},
|
|
||||||
|
|
||||||
// 12
|
|
||||||
// Blueprints
|
|
||||||
{
|
|
||||||
shape: "CbCbCbRb:CwCwCwCw",
|
|
||||||
required: 1000,
|
|
||||||
reward: enumHubGoalRewards.reward_blueprints,
|
|
||||||
},
|
|
||||||
|
|
||||||
// 13
|
|
||||||
// Tunnel Tier 2
|
|
||||||
{
|
|
||||||
shape: "RpRpRpRp:CwCwCwCw", // painting t3
|
|
||||||
required: 3800,
|
|
||||||
reward: enumHubGoalRewards.reward_underground_belt_tier_2,
|
|
||||||
},
|
|
||||||
|
|
||||||
// DEMO STOPS HERE
|
|
||||||
...(IS_DEMO
|
|
||||||
? [
|
|
||||||
{
|
|
||||||
shape: "RpRpRpRp:CwCwCwCw",
|
|
||||||
required: 0,
|
|
||||||
reward: enumHubGoalRewards.reward_demo_end,
|
|
||||||
},
|
|
||||||
]
|
|
||||||
: [
|
|
||||||
// 14
|
|
||||||
// Belt reader
|
|
||||||
{
|
|
||||||
shape: "--Cg----:--Cr----", // unused
|
|
||||||
required: 16, // Per second!
|
|
||||||
reward: enumHubGoalRewards.reward_belt_reader,
|
|
||||||
throughputOnly: true,
|
|
||||||
},
|
|
||||||
|
|
||||||
// 15
|
|
||||||
// Storage
|
|
||||||
{
|
|
||||||
shape: "SrSrSrSr:CyCyCyCy", // unused
|
|
||||||
required: 10000,
|
|
||||||
reward: enumHubGoalRewards.reward_storage,
|
|
||||||
},
|
|
||||||
|
|
||||||
// 16
|
|
||||||
// Quad Cutter
|
|
||||||
{
|
|
||||||
shape: "SrSrSrSr:CyCyCyCy:SwSwSwSw", // belts t4 (two variants)
|
|
||||||
required: 6000,
|
|
||||||
reward: enumHubGoalRewards.reward_cutter_quad,
|
|
||||||
},
|
|
||||||
|
|
||||||
// 17
|
|
||||||
// Double painter
|
|
||||||
{
|
|
||||||
shape: "CbRbRbCb:CwCwCwCw:WbWbWbWb", // miner t4 (two variants)
|
|
||||||
required: 20000,
|
|
||||||
reward: enumHubGoalRewards.reward_painter_double,
|
|
||||||
},
|
|
||||||
|
|
||||||
// 18
|
|
||||||
// Rotater (180deg)
|
|
||||||
{
|
|
||||||
shape: "Sg----Sg:CgCgCgCg:--CyCy--", // unused
|
|
||||||
required: 20000,
|
|
||||||
reward: enumHubGoalRewards.reward_rotater_180,
|
|
||||||
},
|
|
||||||
|
|
||||||
// 19
|
|
||||||
// Compact splitter
|
|
||||||
{
|
|
||||||
shape: "CpRpCp--:SwSwSwSw",
|
|
||||||
required: 25000,
|
|
||||||
reward: enumHubGoalRewards.reward_splitter,
|
|
||||||
},
|
|
||||||
|
|
||||||
// 20
|
|
||||||
// WIRES
|
|
||||||
{
|
|
||||||
shape: finalGameShape,
|
|
||||||
required: 25000,
|
|
||||||
reward: enumHubGoalRewards.reward_wires_painter_and_levers,
|
|
||||||
},
|
|
||||||
|
|
||||||
// 21
|
|
||||||
// Filter
|
|
||||||
{
|
|
||||||
shape: "CrCwCrCw:CwCrCwCr:CrCwCrCw:CwCrCwCr",
|
|
||||||
required: 25000,
|
|
||||||
reward: enumHubGoalRewards.reward_filter,
|
|
||||||
},
|
|
||||||
|
|
||||||
// 22
|
|
||||||
// Constant signal
|
|
||||||
{
|
|
||||||
shape: "Cg----Cr:Cw----Cw:Sy------:Cy----Cy",
|
|
||||||
required: 25000,
|
|
||||||
reward: enumHubGoalRewards.reward_constant_signal,
|
|
||||||
},
|
|
||||||
|
|
||||||
// 23
|
|
||||||
// Display
|
|
||||||
{
|
|
||||||
shape: "CcSyCcSy:SyCcSyCc:CcSyCcSy",
|
|
||||||
required: 25000,
|
|
||||||
reward: enumHubGoalRewards.reward_display,
|
|
||||||
},
|
|
||||||
|
|
||||||
// 24 Logic gates
|
|
||||||
{
|
|
||||||
shape: "CcRcCcRc:RwCwRwCw:Sr--Sw--:CyCyCyCy",
|
|
||||||
required: 25000,
|
|
||||||
reward: enumHubGoalRewards.reward_logic_gates,
|
|
||||||
},
|
|
||||||
|
|
||||||
// 25 Virtual Processing
|
|
||||||
{
|
|
||||||
shape: "Rg--Rg--:CwRwCwRw:--Rg--Rg",
|
|
||||||
required: 25000,
|
|
||||||
reward: enumHubGoalRewards.reward_virtual_processing,
|
|
||||||
},
|
|
||||||
|
|
||||||
// 26 Freeplay
|
|
||||||
{
|
|
||||||
shape: "CbCuCbCu:Sr------:--CrSrCr:CwCwCwCw",
|
|
||||||
required: 50000,
|
|
||||||
reward: enumHubGoalRewards.reward_freeplay,
|
|
||||||
},
|
|
||||||
]),
|
|
||||||
];
|
|
||||||
|
|
||||||
if (G_IS_DEV) {
|
|
||||||
tutorialGoals.forEach(({ shape }) => {
|
|
||||||
try {
|
|
||||||
ShapeDefinition.fromShortKey(shape);
|
|
||||||
} catch (ex) {
|
|
||||||
throw new Error("Invalid tutorial goal: '" + ex + "' for shape" + shape);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|||||||
@ -1,211 +0,0 @@
|
|||||||
import { findNiceIntegerValue } from "../core/utils";
|
|
||||||
import { ShapeDefinition } from "./shape_definition";
|
|
||||||
|
|
||||||
export const preparementShape = "CpRpCp--:SwSwSwSw";
|
|
||||||
export const finalGameShape = "RuCw--Cw:----Ru--";
|
|
||||||
export const rocketShape = "CbCuCbCu:Sr------:--CrSrCr:CwCwCwCw";
|
|
||||||
export const blueprintShape = "CbCbCbRb:CwCwCwCw";
|
|
||||||
|
|
||||||
const fixedImprovements = [0.5, 0.5, 1, 1, 2, 1, 1];
|
|
||||||
|
|
||||||
const numEndgameUpgrades = G_IS_DEV || G_IS_STANDALONE ? 20 - fixedImprovements.length - 1 : 0;
|
|
||||||
|
|
||||||
function generateEndgameUpgrades() {
|
|
||||||
return new Array(numEndgameUpgrades).fill(null).map((_, i) => ({
|
|
||||||
required: [
|
|
||||||
{ shape: preparementShape, amount: 30000 + i * 10000 },
|
|
||||||
{ shape: finalGameShape, amount: 20000 + i * 5000 },
|
|
||||||
{ shape: rocketShape, amount: 20000 + i * 5000 },
|
|
||||||
],
|
|
||||||
excludePrevious: true,
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
for (let i = 0; i < numEndgameUpgrades; ++i) {
|
|
||||||
fixedImprovements.push(0.1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @typedef {{
|
|
||||||
* shape: string,
|
|
||||||
* amount: number
|
|
||||||
* }} UpgradeRequirement */
|
|
||||||
|
|
||||||
/** @typedef {{
|
|
||||||
* required: Array<UpgradeRequirement>
|
|
||||||
* improvement?: number,
|
|
||||||
* excludePrevious?: boolean
|
|
||||||
* }} TierRequirement */
|
|
||||||
|
|
||||||
/** @typedef {Array<TierRequirement>} UpgradeTiers */
|
|
||||||
|
|
||||||
/** @type {Object<string, UpgradeTiers>} */
|
|
||||||
export const UPGRADES = {
|
|
||||||
belt: [
|
|
||||||
{
|
|
||||||
required: [{ shape: "CuCuCuCu", amount: 60 }],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
required: [{ shape: "--CuCu--", amount: 500 }],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
required: [{ shape: "CpCpCpCp", amount: 1000 }],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
required: [{ shape: "SrSrSrSr:CyCyCyCy", amount: 6000 }],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
required: [{ shape: "SrSrSrSr:CyCyCyCy:SwSwSwSw", amount: 25000 }],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
required: [{ shape: preparementShape, amount: 25000 }],
|
|
||||||
excludePrevious: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
required: [
|
|
||||||
{ shape: preparementShape, amount: 25000 },
|
|
||||||
{ shape: finalGameShape, amount: 50000 },
|
|
||||||
],
|
|
||||||
excludePrevious: true,
|
|
||||||
},
|
|
||||||
...generateEndgameUpgrades(),
|
|
||||||
],
|
|
||||||
|
|
||||||
miner: [
|
|
||||||
{
|
|
||||||
required: [{ shape: "RuRuRuRu", amount: 300 }],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
required: [{ shape: "Cu------", amount: 800 }],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
required: [{ shape: "ScScScSc", amount: 3500 }],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
required: [{ shape: "CwCwCwCw:WbWbWbWb", amount: 23000 }],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
required: [{ shape: "CbRbRbCb:CwCwCwCw:WbWbWbWb", amount: 50000 }],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
required: [{ shape: preparementShape, amount: 25000 }],
|
|
||||||
excludePrevious: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
required: [
|
|
||||||
{ shape: preparementShape, amount: 25000 },
|
|
||||||
{ shape: finalGameShape, amount: 50000 },
|
|
||||||
],
|
|
||||||
excludePrevious: true,
|
|
||||||
},
|
|
||||||
...generateEndgameUpgrades(),
|
|
||||||
],
|
|
||||||
|
|
||||||
processors: [
|
|
||||||
{
|
|
||||||
required: [{ shape: "SuSuSuSu", amount: 500 }],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
required: [{ shape: "RuRu----", amount: 600 }],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
required: [{ shape: "CgScScCg", amount: 3500 }],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
required: [{ shape: "CwCrCwCr:SgSgSgSg", amount: 25000 }],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
required: [{ shape: "WrRgWrRg:CwCrCwCr:SgSgSgSg", amount: 50000 }],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
required: [{ shape: preparementShape, amount: 25000 }],
|
|
||||||
excludePrevious: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
required: [
|
|
||||||
{ shape: preparementShape, amount: 25000 },
|
|
||||||
{ shape: finalGameShape, amount: 50000 },
|
|
||||||
],
|
|
||||||
excludePrevious: true,
|
|
||||||
},
|
|
||||||
...generateEndgameUpgrades(),
|
|
||||||
],
|
|
||||||
|
|
||||||
painting: [
|
|
||||||
{
|
|
||||||
required: [{ shape: "RbRb----", amount: 600 }],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
required: [{ shape: "WrWrWrWr", amount: 3800 }],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
required: [{ shape: "RpRpRpRp:CwCwCwCw", amount: 6500 }],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
required: [{ shape: "WpWpWpWp:CwCwCwCw:WpWpWpWp", amount: 25000 }],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
required: [{ shape: "WpWpWpWp:CwCwCwCw:WpWpWpWp:CwCwCwCw", amount: 50000 }],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
required: [{ shape: preparementShape, amount: 25000 }],
|
|
||||||
excludePrevious: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
required: [
|
|
||||||
{ shape: preparementShape, amount: 25000 },
|
|
||||||
{ shape: finalGameShape, amount: 50000 },
|
|
||||||
],
|
|
||||||
excludePrevious: true,
|
|
||||||
},
|
|
||||||
...generateEndgameUpgrades(),
|
|
||||||
],
|
|
||||||
};
|
|
||||||
|
|
||||||
// Tiers need % of the previous tier as requirement too
|
|
||||||
const tierGrowth = 2.5;
|
|
||||||
|
|
||||||
// Automatically generate tier levels
|
|
||||||
for (const upgradeId in UPGRADES) {
|
|
||||||
const upgradeTiers = UPGRADES[upgradeId];
|
|
||||||
|
|
||||||
let currentTierRequirements = [];
|
|
||||||
for (let i = 0; i < upgradeTiers.length; ++i) {
|
|
||||||
const tierHandle = upgradeTiers[i];
|
|
||||||
tierHandle.improvement = fixedImprovements[i];
|
|
||||||
const originalRequired = tierHandle.required.slice();
|
|
||||||
|
|
||||||
for (let k = currentTierRequirements.length - 1; k >= 0; --k) {
|
|
||||||
const oldTierRequirement = currentTierRequirements[k];
|
|
||||||
if (!tierHandle.excludePrevious) {
|
|
||||||
tierHandle.required.unshift({
|
|
||||||
shape: oldTierRequirement.shape,
|
|
||||||
amount: oldTierRequirement.amount,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
currentTierRequirements.push(
|
|
||||||
...originalRequired.map(req => ({
|
|
||||||
amount: req.amount,
|
|
||||||
shape: req.shape,
|
|
||||||
}))
|
|
||||||
);
|
|
||||||
currentTierRequirements.forEach(tier => {
|
|
||||||
tier.amount = findNiceIntegerValue(tier.amount * tierGrowth);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// VALIDATE
|
|
||||||
if (G_IS_DEV) {
|
|
||||||
for (const upgradeId in UPGRADES) {
|
|
||||||
UPGRADES[upgradeId].forEach(tier => {
|
|
||||||
tier.required.forEach(({ shape }) => {
|
|
||||||
try {
|
|
||||||
ShapeDefinition.fromShortKey(shape);
|
|
||||||
} catch (ex) {
|
|
||||||
throw new Error("Invalid upgrade goal: '" + ex + "' for shape" + shape);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||