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/
|
||||
yarn
|
||||
cd ..
|
||||
|
||||
- name: Lint
|
||||
run: |
|
||||
yarn lint
|
||||
|
||||
- name: YAML Lint
|
||||
uses: ibiqlik/action-yamllint@v1.0.0
|
||||
with:
|
||||
file_or_dir: translations/*.yaml
|
||||
|
||||
- name: TSLint
|
||||
run: |
|
||||
cd gulp
|
||||
yarn gulp translations.fullBuild
|
||||
cd ..
|
||||
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
|
||||
*.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)
|
||||
build/Release
|
||||
|
||||
# Dependency directories
|
||||
node_modules/
|
||||
jspm_packages/
|
||||
|
||||
# TypeScript v1 declaration files
|
||||
typings/
|
||||
|
||||
# TypeScript cache
|
||||
*.tsbuildinfo
|
||||
@ -53,18 +30,9 @@ typings/
|
||||
# Optional eslint cache
|
||||
.eslintcache
|
||||
|
||||
# Microbundle cache
|
||||
.rpt2_cache/
|
||||
.rts2_cache_cjs/
|
||||
.rts2_cache_es/
|
||||
.rts2_cache_umd/
|
||||
|
||||
# Optional REPL history
|
||||
.node_repl_history
|
||||
|
||||
# Output of 'npm pack'
|
||||
*.tgz
|
||||
|
||||
# Yarn Integrity file
|
||||
.yarn-integrity
|
||||
|
||||
@ -72,41 +40,11 @@ typings/
|
||||
.env
|
||||
.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
|
||||
build
|
||||
res_built
|
||||
|
||||
gulp/runnable-texturepacker.jar
|
||||
tmp_standalone_files
|
||||
|
||||
# Local config
|
||||
|
||||
@ -4,3 +4,4 @@ rules:
|
||||
line-length:
|
||||
level: warning
|
||||
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
|
||||
- Install Node.js and Yarn
|
||||
- Install Java (required for textures)
|
||||
- Run `yarn` in the root folder
|
||||
- Cd into `gulp` folder
|
||||
- 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
|
||||
|
||||
@ -114,8 +115,8 @@ This is a quick checklist, if a new building is added this points should be fulf
|
||||
|
||||
### 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">
|
||||
|
||||
@ -1,3 +0,0 @@
|
||||
The artwork can be found here:
|
||||
|
||||
https://github.com/tobspr/shapez.io-artwork
|
||||
@ -10,7 +10,7 @@
|
||||
"start": "electron --disable-direct-composition --in-process-gpu ."
|
||||
},
|
||||
"devDependencies": {
|
||||
"electron": "^6.1.12"
|
||||
"electron": "10.1.3"
|
||||
},
|
||||
"dependencies": {}
|
||||
}
|
||||
|
||||
1087
electron/yarn.lock
1
gulp/.gitignore
vendored
@ -1,2 +1 @@
|
||||
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 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
|
||||
const $ = require("gulp-load-plugins")({
|
||||
scope: ["devDependencies"],
|
||||
@ -103,8 +86,16 @@ gulp.task("utils.cleanBuildTempFolder", () => {
|
||||
.src(path.join(__dirname, "..", "src", "js", "built-temp"), { read: false, allowEmpty: 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
|
||||
gulp.task("utils.requireCleanWorkingTree", cb => {
|
||||
@ -191,10 +182,12 @@ function serve({ standalone }) {
|
||||
);
|
||||
|
||||
// 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.imageResourcesGlobs, gulp.series("imgres.copyImageResources"));
|
||||
|
||||
// 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"));
|
||||
|
||||
// Watch the build folder and reload when anything changed
|
||||
@ -232,6 +225,8 @@ gulp.task(
|
||||
gulp.series(
|
||||
"utils.cleanup",
|
||||
"utils.copyAdditionalBuildFiles",
|
||||
"imgres.buildAtlas",
|
||||
"imgres.atlasToJson",
|
||||
"imgres.atlas",
|
||||
"sounds.dev",
|
||||
"imgres.copyImageResources",
|
||||
@ -247,12 +242,13 @@ gulp.task(
|
||||
"build.standalone.dev",
|
||||
gulp.series(
|
||||
"utils.cleanup",
|
||||
"imgres.buildAtlas",
|
||||
"imgres.atlasToJson",
|
||||
"imgres.atlas",
|
||||
"sounds.dev",
|
||||
"imgres.copyImageResources",
|
||||
"imgres.copyNonImageResources",
|
||||
"translations.fullBuild",
|
||||
"js.standalone-dev",
|
||||
"css.dev",
|
||||
"html.standalone-dev"
|
||||
)
|
||||
|
||||
@ -1,5 +1,15 @@
|
||||
const { existsSync } = require("fs");
|
||||
// @ts-ignore
|
||||
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
|
||||
const nonImageResourcesGlobs = ["../res/**/*.woff2", "../res/*.ico", "../res/**/*.webm"];
|
||||
@ -7,6 +17,9 @@ const nonImageResourcesGlobs = ["../res/**/*.woff2", "../res/*.ico", "../res/**/
|
||||
// Globs for ui resources
|
||||
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) {
|
||||
// Lossless options
|
||||
const minifyImagesOptsLossless = () => [
|
||||
@ -59,6 +72,54 @@ function gulptasksImageResources($, gulp, buildFolder) {
|
||||
|
||||
/////////////// 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
|
||||
gulp.task("imgres.atlas", () => {
|
||||
return gulp.src(["../res_built/atlas/*.png"]).pipe(gulp.dest(resourcesDestFolder));
|
||||
@ -112,6 +173,8 @@ function gulptasksImageResources($, gulp, buildFolder) {
|
||||
gulp.task(
|
||||
"imgres.allOptimized",
|
||||
gulp.parallel(
|
||||
"imgres.buildAtlas",
|
||||
"imgres.atlasToJson",
|
||||
"imgres.atlasOptimized",
|
||||
"imgres.copyNonImageResources",
|
||||
"imgres.copyImageResourcesOptimized"
|
||||
@ -135,6 +198,7 @@ function gulptasksImageResources($, gulp, buildFolder) {
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
rawImageResourcesGlobs,
|
||||
nonImageResourcesGlobs,
|
||||
imageResourcesGlobs,
|
||||
gulptasksImageResources,
|
||||
|
||||
@ -47,6 +47,7 @@
|
||||
"serialize-error": "^3.0.0",
|
||||
"strictdom": "^1.0.1",
|
||||
"string-replace-webpack-plugin": "^0.1.3",
|
||||
"strip-indent": "^3.0.0",
|
||||
"terser-webpack-plugin": "^1.1.0",
|
||||
"through2": "^3.0.1",
|
||||
"uglify-template-string-loader": "^1.1.0",
|
||||
@ -66,7 +67,6 @@
|
||||
"babel-plugin-danger-remove-unused-import": "^1.1.2",
|
||||
"css-mqpacker": "^7.0.0",
|
||||
"cssnano": "^4.1.10",
|
||||
"postcss-critical-split": "^2.5.3",
|
||||
"electron-packager": "^14.0.6",
|
||||
"faster.js": "^1.1.0",
|
||||
"glob": "^7.1.3",
|
||||
@ -99,6 +99,7 @@
|
||||
"jimp": "^0.6.1",
|
||||
"js-yaml": "^3.13.1",
|
||||
"postcss-assets": "^5.0.0",
|
||||
"postcss-critical-split": "^2.5.3",
|
||||
"postcss-preset-env": "^6.5.0",
|
||||
"postcss-round-subpixels": "^1.2.0",
|
||||
"postcss-unprefix": "^2.1.3",
|
||||
|
||||
@ -1,9 +1,10 @@
|
||||
require('colors');
|
||||
require("colors");
|
||||
const packager = require("electron-packager");
|
||||
const path = require("path");
|
||||
const { getVersion } = require("./buildutils");
|
||||
const fs = require("fs");
|
||||
const fse = require("fs-extra");
|
||||
const buildutils = require("./buildutils");
|
||||
const execSync = require("child_process").execSync;
|
||||
|
||||
function gulptasksStandalone($, gulp) {
|
||||
@ -47,6 +48,20 @@ function gulptasksStandalone($, gulp) {
|
||||
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", () => {
|
||||
return gulp.src(path.join(electronBaseDir, "*.js")).pipe(gulp.dest(tempDestBuildDir));
|
||||
});
|
||||
@ -101,20 +116,21 @@ function gulptasksStandalone($, gulp) {
|
||||
overwrite: true,
|
||||
appBundleId: "io.shapez.standalone",
|
||||
appCategoryType: "public.app-category.games",
|
||||
...(isRelease && platform === "darwin" && {
|
||||
osxSign: {
|
||||
identity: process.env.SHAPEZ_CLI_APPLE_CERT_NAME,
|
||||
"hardened-runtime": true,
|
||||
hardenedRuntime: true,
|
||||
entitlements: 'entitlements.plist',
|
||||
'entitlements-inherit': 'entitlements.plist',
|
||||
'signature-flags': 'library'
|
||||
},
|
||||
osxNotarize: {
|
||||
appleId: process.env.SHAPEZ_CLI_APPLE_ID,
|
||||
appleIdPassword: "@keychain:SHAPEZ_CLI_APPLE_ID"
|
||||
}
|
||||
})
|
||||
...(isRelease &&
|
||||
platform === "darwin" && {
|
||||
osxSign: {
|
||||
"identity": process.env.SHAPEZ_CLI_APPLE_CERT_NAME,
|
||||
"hardened-runtime": true,
|
||||
"hardenedRuntime": true,
|
||||
"entitlements": "entitlements.plist",
|
||||
"entitlements-inherit": "entitlements.plist",
|
||||
"signature-flags": "library",
|
||||
},
|
||||
osxNotarize: {
|
||||
appleId: process.env.SHAPEZ_CLI_APPLE_ID,
|
||||
appleIdPassword: "@keychain:SHAPEZ_CLI_APPLE_ID",
|
||||
},
|
||||
}),
|
||||
}).then(
|
||||
appPaths => {
|
||||
console.log("Packages created:", appPaths);
|
||||
@ -140,9 +156,13 @@ function gulptasksStandalone($, gulp) {
|
||||
}
|
||||
|
||||
if (process.platform === "win32" && platform === "darwin") {
|
||||
console.warn("Cross-building for macOS on Windows: dereferencing symlinks.\n".red +
|
||||
"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);
|
||||
console.warn(
|
||||
"Cross-building for macOS on Windows: dereferencing symlinks.\n".red +
|
||||
"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
|
||||
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.linux32", cb => packageStandalone("linux", "ia32", 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(
|
||||
"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,6 +1,9 @@
|
||||
const path = require("path");
|
||||
|
||||
const yaml = require("gulp-yaml");
|
||||
const fs = require("fs");
|
||||
const gulpYaml = require("gulp-yaml");
|
||||
const YAML = require("yaml");
|
||||
const stripIndent = require("strip-indent");
|
||||
const trim = require("trim");
|
||||
|
||||
const translationsSourceDir = path.join(__dirname, "..", "translations");
|
||||
const translationsJsonDir = path.join(__dirname, "..", "src", "js", "built-temp");
|
||||
@ -10,11 +13,75 @@ function gulptasksTranslations($, gulp) {
|
||||
return gulp
|
||||
.src(path.join(translationsSourceDir, "*.yaml"))
|
||||
.pipe($.plumber())
|
||||
.pipe(yaml({ space: 2, safe: true }))
|
||||
.pipe(gulpYaml({ space: 2, safe: true }))
|
||||
.pipe(gulp.dest(translationsJsonDir));
|
||||
});
|
||||
|
||||
gulp.task("translations.fullBuild", gulp.series("translations.convertToJson"));
|
||||
|
||||
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 = {
|
||||
|
||||
@ -8198,6 +8198,11 @@ min-document@^2.19.0:
|
||||
dependencies:
|
||||
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:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7"
|
||||
@ -11945,6 +11950,13 @@ strip-indent@^1.0.1:
|
||||
dependencies:
|
||||
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:
|
||||
version "2.0.1"
|
||||
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;
|
||||
@include S(margin-bottom, 4px);
|
||||
color: #333438;
|
||||
// text-shadow: #{D(1px)} #{D(1px)} 0 rgba(0, 10, 20, 0.2);
|
||||
|
||||
&.unpinable {
|
||||
> canvas {
|
||||
cursor: pointer;
|
||||
pointer-events: all;
|
||||
}
|
||||
&.removable {
|
||||
cursor: pointer;
|
||||
pointer-events: all;
|
||||
}
|
||||
|
||||
> canvas {
|
||||
@ -31,16 +28,9 @@
|
||||
@include S(height, 25px);
|
||||
grid-column: 1 / 2;
|
||||
grid-row: 1 / 3;
|
||||
pointer-events: all;
|
||||
transition: transform 0.1s ease-in-out;
|
||||
transform-origin: D(2px) center;
|
||||
will-change: transform;
|
||||
position: relative;
|
||||
pointer-events: none;
|
||||
z-index: 20;
|
||||
&:hover {
|
||||
transform: scale(2);
|
||||
z-index: 21;
|
||||
}
|
||||
position: relative;
|
||||
}
|
||||
|
||||
> .amountLabel,
|
||||
|
||||
@ -16,6 +16,7 @@
|
||||
grid-template-rows: #{D(40px)};
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.lowerBar {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
@ -57,10 +58,7 @@
|
||||
@include S(margin, 0);
|
||||
@include S(width, 180px);
|
||||
@include S(height, 40px);
|
||||
& {
|
||||
/* @load-async */
|
||||
background: #171a23 uiResource("get_on_steam.png") center center / contain no-repeat;
|
||||
}
|
||||
background: #171a23 center center / contain no-repeat;
|
||||
|
||||
@include S(border-radius, $globalBorderRadius);
|
||||
}
|
||||
|
||||
@ -53,6 +53,7 @@
|
||||
@import "ingame_hud/shape_viewer";
|
||||
@import "ingame_hud/sandbox_controller";
|
||||
@import "ingame_hud/standalone_advantages";
|
||||
@import "ingame_hud/cat_memes";
|
||||
|
||||
// prettier-ignore
|
||||
$elements:
|
||||
@ -74,7 +75,7 @@ ingame_HUD_DebugInfo,
|
||||
ingame_HUD_EntityDebugger,
|
||||
ingame_HUD_InteractiveTutorial,
|
||||
ingame_HUD_TutorialHints,
|
||||
ingame_HUD_buildings_toolbar,
|
||||
ingame_HUD_BuildingsToolbar,
|
||||
ingame_HUD_wires_toolbar,
|
||||
ingame_HUD_BlueprintPlacer,
|
||||
ingame_HUD_Waypoints_Hint,
|
||||
@ -93,7 +94,8 @@ ingame_HUD_ShapeViewer,
|
||||
ingame_HUD_StandaloneAdvantages,
|
||||
ingame_HUD_UnlockNotification,
|
||||
ingame_HUD_SettingsMenu,
|
||||
ingame_HUD_ModalDialogs;
|
||||
ingame_HUD_ModalDialogs,
|
||||
ingame_HUD_CatMemes;
|
||||
|
||||
$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;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
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%;
|
||||
@include S(height, 40px);
|
||||
@include S(width, 180px);
|
||||
& {
|
||||
/* @load-async */
|
||||
background: #171a23 uiResource("get_on_steam.png") center center / contain no-repeat;
|
||||
}
|
||||
background: #171a23 center center / contain no-repeat;
|
||||
overflow: hidden;
|
||||
display: block;
|
||||
text-indent: -999em;
|
||||
|
||||
@ -29,6 +29,7 @@ import { MobileWarningState } from "./states/mobile_warning";
|
||||
import { PreloadState } from "./states/preload";
|
||||
import { SettingsState } from "./states/settings";
|
||||
import { ShapezGameAnalytics } from "./platform/browser/game_analytics";
|
||||
import { RestrictionManager } from "./core/restriction_manager";
|
||||
|
||||
/**
|
||||
* @typedef {import("./platform/game_analytics").GameAnalyticsInterface} GameAnalyticsInterface
|
||||
@ -70,6 +71,9 @@ export class Application {
|
||||
this.inputMgr = new InputDistributor(this);
|
||||
this.backgroundResourceLoader = new BackgroundResourcesLoader(this);
|
||||
|
||||
// Restrictions (Like demo etc)
|
||||
this.restrictionMgr = new RestrictionManager(this);
|
||||
|
||||
// Platform dependent stuff
|
||||
|
||||
/** @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>! ⚠️⚠️",
|
||||
],
|
||||
},
|
||||
{
|
||||
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",
|
||||
date: "27.06.2020",
|
||||
|
||||
@ -1,5 +1,3 @@
|
||||
import { queryParamOptions } from "./query_parameters";
|
||||
|
||||
export const IS_DEBUG =
|
||||
G_IS_DEV &&
|
||||
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.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 IS_MAC = navigator.platform.toLowerCase().indexOf("mac") >= 0;
|
||||
|
||||
const smoothCanvas = true;
|
||||
|
||||
export const THIRDPARTY_URLS = {
|
||||
@ -25,6 +20,8 @@ export const THIRDPARTY_URLS = {
|
||||
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 = {
|
||||
// Size of a single tile in Pixels.
|
||||
// NOTICE: Update webpack.production.config too!
|
||||
@ -62,7 +59,7 @@ export const globalConfig = {
|
||||
|
||||
undergroundBeltMaxTilesByTier: [5, 9],
|
||||
|
||||
readerAnalyzeIntervalSeconds: G_IS_DEV ? 3 : 10,
|
||||
readerAnalyzeIntervalSeconds: 10,
|
||||
|
||||
buildingSpeeds: {
|
||||
cutter: 1 / 4,
|
||||
|
||||
@ -81,10 +81,6 @@ export class ReadWriteProxy {
|
||||
return this.writeAsync();
|
||||
}
|
||||
|
||||
getCurrentData() {
|
||||
return this.currentData;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @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
|
||||
* @param {number} num
|
||||
* @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}
|
||||
*/
|
||||
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>");
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
this.spacingToFirstItem += clampedProgress;
|
||||
if (remainingVelocity < 0.01) {
|
||||
if (remainingVelocity < 1e-7) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,13 +1,9 @@
|
||||
import { globalConfig } from "../core/config";
|
||||
import { DrawParameters } from "../core/draw_parameters";
|
||||
import { createLogger } from "../core/logging";
|
||||
import { findNiceIntegerValue } from "../core/utils";
|
||||
import { Vector } from "../core/vector";
|
||||
import { Entity } from "./entity";
|
||||
import { GameRoot } from "./root";
|
||||
import { blueprintShape } from "./upgrades";
|
||||
|
||||
const logger = createLogger("blueprint");
|
||||
|
||||
export class Blueprint {
|
||||
/**
|
||||
@ -142,7 +138,7 @@ export class Blueprint {
|
||||
* @param {GameRoot} 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([
|
||||
{
|
||||
pos: new Vector(0, 0),
|
||||
direction: enumDirection.left,
|
||||
type: enumPinSlotType.logicalEjector,
|
||||
},
|
||||
{
|
||||
pos: new Vector(0, 0),
|
||||
direction: enumDirection.right,
|
||||
direction: enumDirection.top,
|
||||
type: enumPinSlotType.logicalEjector,
|
||||
},
|
||||
{
|
||||
|
||||
@ -511,7 +511,11 @@ export class Camera extends BasicSerializableObject {
|
||||
this.clampZoomLevel();
|
||||
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) {
|
||||
const worldPos = this.root.camera.screenToWorld(mousePosition);
|
||||
const worldDelta = worldPos.sub(this.center);
|
||||
|
||||
@ -31,6 +31,7 @@ import { KeyActionMapper } from "./key_action_mapper";
|
||||
import { GameLogic } from "./logic";
|
||||
import { MapView } from "./map_view";
|
||||
import { defaultBuildingVariant } from "./meta_building";
|
||||
import { RegularGameMode } from "./modes/regular";
|
||||
import { ProductionAnalytics } from "./production_analytics";
|
||||
import { GameRoot } from "./root";
|
||||
import { ShapeDefinitionManager } from "./shape_definition_manager";
|
||||
@ -101,6 +102,9 @@ export class GameCore {
|
||||
// Needs to come first
|
||||
root.dynamicTickrate = new DynamicTickrate(root);
|
||||
|
||||
// Init game mode
|
||||
root.gameMode = new RegularGameMode(root);
|
||||
|
||||
// Init classes
|
||||
root.camera = new Camera(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 { clamp, findNiceIntegerValue, randomChoice, randomInt } from "../core/utils";
|
||||
import { clamp } from "../core/utils";
|
||||
import { BasicSerializableObject, types } from "../savegame/serialization";
|
||||
import { enumColors } from "./colors";
|
||||
import { enumItemProcessorTypes } from "./components/item_processor";
|
||||
import { enumAnalyticsDataSource } from "./production_analytics";
|
||||
import { GameRoot } from "./root";
|
||||
import { enumSubShape, ShapeDefinition } from "./shape_definition";
|
||||
import { enumHubGoalRewards, tutorialGoals } from "./tutorial_goals";
|
||||
import { UPGRADES } from "./upgrades";
|
||||
import { enumHubGoalRewards } from "./tutorial_goals";
|
||||
|
||||
export class HubGoals extends BasicSerializableObject {
|
||||
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);
|
||||
if (errorCode) {
|
||||
return errorCode;
|
||||
}
|
||||
|
||||
if (IS_DEMO) {
|
||||
this.level = Math.min(this.level, tutorialGoals.length);
|
||||
const levels = root.gameMode.getLevelDefinitions();
|
||||
|
||||
// If freeplay is not available, clamp the level
|
||||
if (!root.gameMode.getIsFreeplayAvailable()) {
|
||||
this.level = Math.min(this.level, levels.length);
|
||||
}
|
||||
|
||||
// Compute gained rewards
|
||||
for (let i = 0; i < this.level - 1; ++i) {
|
||||
if (i < tutorialGoals.length) {
|
||||
const reward = tutorialGoals[i].reward;
|
||||
if (i < levels.length) {
|
||||
const reward = levels[i].reward;
|
||||
this.gainedRewards[reward] = (this.gainedRewards[reward] || 0) + 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Compute upgrade improvements
|
||||
for (const upgradeId in UPGRADES) {
|
||||
const tiers = UPGRADES[upgradeId];
|
||||
const upgrades = this.root.gameMode.getUpgrades();
|
||||
for (const upgradeId in upgrades) {
|
||||
const tiers = upgrades[upgradeId];
|
||||
const level = this.upgradeLevels[upgradeId] || 0;
|
||||
let totalImprovement = 1;
|
||||
for (let i = 0; i < level; ++i) {
|
||||
@ -84,17 +92,16 @@ export class HubGoals extends BasicSerializableObject {
|
||||
*/
|
||||
this.upgradeLevels = {};
|
||||
|
||||
// Reset levels
|
||||
for (const key in UPGRADES) {
|
||||
this.upgradeLevels[key] = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores the improvements for all upgrades
|
||||
* @type {Object<string, number>}
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
@ -120,7 +127,10 @@ export class HubGoals extends BasicSerializableObject {
|
||||
* @returns {boolean}
|
||||
*/
|
||||
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() {
|
||||
const storyIndex = this.level - 1;
|
||||
if (storyIndex < tutorialGoals.length) {
|
||||
const { shape, required, reward, throughputOnly } = tutorialGoals[storyIndex];
|
||||
const levels = this.root.gameMode.getLevelDefinitions();
|
||||
if (storyIndex < levels.length) {
|
||||
const { shape, required, reward, throughputOnly } = levels[storyIndex];
|
||||
this.currentGoal = {
|
||||
/** @type {ShapeDefinition} */
|
||||
definition: this.root.shapeDefinitionMgr.getShapeFromShortKey(shape),
|
||||
@ -254,7 +265,7 @@ export class HubGoals extends BasicSerializableObject {
|
||||
* Returns whether we are playing in free-play
|
||||
*/
|
||||
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
|
||||
*/
|
||||
canUnlockUpgrade(upgradeId) {
|
||||
const tiers = UPGRADES[upgradeId];
|
||||
const tiers = this.root.gameMode.getUpgrades()[upgradeId];
|
||||
const currentLevel = this.getUpgradeLevel(upgradeId);
|
||||
|
||||
if (currentLevel >= tiers.length) {
|
||||
@ -270,11 +281,6 @@ export class HubGoals extends BasicSerializableObject {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (IS_DEMO && currentLevel >= 4) {
|
||||
// DEMO
|
||||
return false;
|
||||
}
|
||||
|
||||
if (G_IS_DEV && globalConfig.debug.upgradesNoCost) {
|
||||
return true;
|
||||
}
|
||||
@ -296,7 +302,7 @@ export class HubGoals extends BasicSerializableObject {
|
||||
*/
|
||||
getAvailableUpgradeCount() {
|
||||
let count = 0;
|
||||
for (const upgradeId in UPGRADES) {
|
||||
for (const upgradeId in this.root.gameMode.getUpgrades()) {
|
||||
if (this.canUnlockUpgrade(upgradeId)) {
|
||||
++count;
|
||||
}
|
||||
@ -314,7 +320,7 @@ export class HubGoals extends BasicSerializableObject {
|
||||
return false;
|
||||
}
|
||||
|
||||
const upgradeTiers = UPGRADES[upgradeId];
|
||||
const upgradeTiers = this.root.gameMode.getUpgrades()[upgradeId];
|
||||
const currentLevel = this.getUpgradeLevel(upgradeId);
|
||||
|
||||
const tierData = upgradeTiers[currentLevel];
|
||||
|
||||
@ -15,7 +15,7 @@ import { HUDKeybindingOverlay } from "./parts/keybinding_overlay";
|
||||
import { HUDUnlockNotification } from "./parts/unlock_notification";
|
||||
import { HUDGameMenu } from "./parts/game_menu";
|
||||
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 { HUDVignetteOverlay } from "./parts/vignette_overlay";
|
||||
import { HUDStatistics } from "./parts/statistics";
|
||||
@ -45,8 +45,8 @@ import { HUDLeverToggle } from "./parts/lever_toggle";
|
||||
import { HUDLayerPreview } from "./parts/layer_preview";
|
||||
import { HUDMinerHighlight } from "./parts/miner_highlight";
|
||||
import { HUDBetaOverlay } from "./parts/beta_overlay";
|
||||
import { HUDPerformanceWarning } from "./parts/performance_warning";
|
||||
import { HUDStandaloneAdvantages } from "./parts/standalone_advantages";
|
||||
import { HUDCatMemes } from "./parts/cat_memes";
|
||||
|
||||
export class GameHUD {
|
||||
/**
|
||||
@ -87,7 +87,6 @@ export class GameHUD {
|
||||
layerPreview: new HUDLayerPreview(this.root),
|
||||
|
||||
minerHighlight: new HUDMinerHighlight(this.root),
|
||||
performanceWarning: new HUDPerformanceWarning(this.root),
|
||||
|
||||
// Typing hints
|
||||
/* typehints:start */
|
||||
@ -115,9 +114,10 @@ export class GameHUD {
|
||||
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.standaloneAdvantages = new HUDStandaloneAdvantages(this.root);
|
||||
this.parts.catMemes = new HUDCatMemes(this.root);
|
||||
}
|
||||
|
||||
if (G_IS_DEV && globalConfig.debug.renderChanges) {
|
||||
|
||||
@ -7,7 +7,7 @@ export class HUDBetaOverlay extends BaseHUDPart {
|
||||
parent,
|
||||
"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>"
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@ -3,18 +3,19 @@ import { STOP_PROPAGATION } from "../../../core/signal";
|
||||
import { TrackedState } from "../../../core/tracked_state";
|
||||
import { makeDiv } from "../../../core/utils";
|
||||
import { Vector } from "../../../core/vector";
|
||||
import { SOUNDS } from "../../../platform/sound";
|
||||
import { T } from "../../../translations";
|
||||
import { Blueprint } from "../../blueprint";
|
||||
import { enumMouseButton } from "../../camera";
|
||||
import { KEYMAPPINGS } from "../../key_action_mapper";
|
||||
import { blueprintShape } from "../../upgrades";
|
||||
import { BaseHUDPart } from "../base_hud_part";
|
||||
import { DynamicDomAttach } from "../dynamic_dom_attach";
|
||||
import { Blueprint } from "../../blueprint";
|
||||
import { SOUNDS } from "../../../platform/sound";
|
||||
|
||||
export class HUDBlueprintPlacer extends BaseHUDPart {
|
||||
createElements(parent) {
|
||||
const blueprintCostShape = this.root.shapeDefinitionMgr.getShapeFromShortKey(blueprintShape);
|
||||
const blueprintCostShape = this.root.shapeDefinitionMgr.getShapeFromShortKey(
|
||||
this.root.gameMode.getBlueprintShapeKey()
|
||||
);
|
||||
const blueprintCostShapeCanvas = blueprintCostShape.generateAsCanvas(80);
|
||||
|
||||
this.costDisplayParent = makeDiv(parent, "ingame_HUD_BlueprintPlacer", [], ``);
|
||||
@ -123,7 +124,7 @@ export class HUDBlueprintPlacer extends BaseHUDPart {
|
||||
const tile = worldPos.toTileSpace();
|
||||
if (blueprint.tryPlace(this.root, tile)) {
|
||||
const cost = blueprint.getCost();
|
||||
this.root.hubGoals.takeShapeByKey(blueprintShape, cost);
|
||||
this.root.hubGoals.takeShapeByKey(this.root.gameMode.getBlueprintShapeKey(), cost);
|
||||
this.root.soundProxy.playUi(SOUNDS.placeBuilding);
|
||||
}
|
||||
}
|
||||
|
||||
@ -42,7 +42,7 @@ export class HUDBuildingsToolbar extends HUDBaseToolbar {
|
||||
],
|
||||
visibilityCondition: () =>
|
||||
!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 { 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 { 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
|
||||
@ -82,7 +81,7 @@ export class HUDPinnedShapes extends BaseHUDPart {
|
||||
updateShapesAfterUpgrade() {
|
||||
for (let i = 0; i < this.pinnedShapes.length; ++i) {
|
||||
const key = this.pinnedShapes[i];
|
||||
if (key === blueprintShape) {
|
||||
if (key === this.root.gameMode.getBlueprintShapeKey()) {
|
||||
// Ignore blueprint shapes
|
||||
continue;
|
||||
}
|
||||
@ -107,13 +106,14 @@ export class HUDPinnedShapes extends BaseHUDPart {
|
||||
if (key === this.root.hubGoals.currentGoal.definition.getHash()) {
|
||||
return this.root.hubGoals.currentGoal.required;
|
||||
}
|
||||
if (key === blueprintShape) {
|
||||
if (key === this.root.gameMode.getBlueprintShapeKey()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Check if this shape is required for any upgrade
|
||||
for (const upgradeId in UPGRADES) {
|
||||
const upgradeTiers = UPGRADES[upgradeId];
|
||||
const upgrades = this.root.gameMode.getUpgrades();
|
||||
for (const upgradeId in upgrades) {
|
||||
const upgradeTiers = upgrades[upgradeId];
|
||||
const currentTier = this.root.hubGoals.getUpgradeLevel(upgradeId);
|
||||
const tierHandle = upgradeTiers[currentTier];
|
||||
|
||||
@ -138,7 +138,10 @@ export class HUDPinnedShapes extends BaseHUDPart {
|
||||
* @param {string} 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
|
||||
return true;
|
||||
}
|
||||
@ -178,7 +181,7 @@ export class HUDPinnedShapes extends BaseHUDPart {
|
||||
// Pin blueprint shape as well
|
||||
if (this.root.hubGoals.isRewardUnlocked(enumHubGoalRewards.reward_blueprints)) {
|
||||
this.internalPinShape({
|
||||
key: blueprintShape,
|
||||
key: this.root.gameMode.getBlueprintShapeKey(),
|
||||
canUnpin: false,
|
||||
className: "blueprint",
|
||||
});
|
||||
@ -214,11 +217,11 @@ export class HUDPinnedShapes extends BaseHUDPart {
|
||||
|
||||
let detector = null;
|
||||
if (canUnpin) {
|
||||
element.classList.add("unpinable");
|
||||
element.classList.add("removable");
|
||||
detector = new ClickDetector(element, {
|
||||
consumeEvents: true,
|
||||
preventDefault: true,
|
||||
targetOnly: true,
|
||||
targetOnly: false,
|
||||
});
|
||||
detector.click.add(() => this.unpinShape(key));
|
||||
} else {
|
||||
@ -291,6 +294,7 @@ export class HUDPinnedShapes extends BaseHUDPart {
|
||||
* @param {string} key
|
||||
*/
|
||||
unpinShape(key) {
|
||||
console.log("unpin", key);
|
||||
arrayDeleteValue(this.pinnedShapes, key);
|
||||
this.rerenderFull();
|
||||
}
|
||||
@ -306,7 +310,7 @@ export class HUDPinnedShapes extends BaseHUDPart {
|
||||
return;
|
||||
}
|
||||
|
||||
if (key === blueprintShape) {
|
||||
if (key === this.root.gameMode.getBlueprintShapeKey()) {
|
||||
// Can not pin the blueprint shape
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1,9 +1,7 @@
|
||||
import { BaseHUDPart } from "../base_hud_part";
|
||||
import { makeDiv } from "../../../core/utils";
|
||||
import { BaseHUDPart } from "../base_hud_part";
|
||||
import { DynamicDomAttach } from "../dynamic_dom_attach";
|
||||
import { blueprintShape, UPGRADES } from "../../upgrades";
|
||||
import { enumNotificationType } from "./notifications";
|
||||
import { tutorialGoals } from "../../tutorial_goals";
|
||||
|
||||
export class HUDSandboxController extends BaseHUDPart {
|
||||
createElements(parent) {
|
||||
@ -75,10 +73,11 @@ export class HUDSandboxController extends BaseHUDPart {
|
||||
}
|
||||
|
||||
giveBlueprints() {
|
||||
if (!this.root.hubGoals.storedShapes[blueprintShape]) {
|
||||
this.root.hubGoals.storedShapes[blueprintShape] = 0;
|
||||
const shape = this.root.gameMode.getBlueprintShapeKey();
|
||||
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() {
|
||||
@ -89,7 +88,7 @@ export class HUDSandboxController extends BaseHUDPart {
|
||||
}
|
||||
|
||||
modifyUpgrade(id, amount) {
|
||||
const upgradeTiers = UPGRADES[id];
|
||||
const upgradeTiers = this.root.gameMode.getUpgrades()[id];
|
||||
const maxLevel = upgradeTiers.length;
|
||||
|
||||
this.root.hubGoals.upgradeLevels[id] = Math.max(
|
||||
@ -122,9 +121,10 @@ export class HUDSandboxController extends BaseHUDPart {
|
||||
|
||||
// Compute gained rewards
|
||||
hubGoals.gainedRewards = {};
|
||||
const levels = this.root.gameMode.getLevelDefinitions();
|
||||
for (let i = 0; i < hubGoals.level - 1; ++i) {
|
||||
if (i < tutorialGoals.length) {
|
||||
const reward = tutorialGoals[i].reward;
|
||||
if (i < levels.length) {
|
||||
const reward = levels[i].reward;
|
||||
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 { globalConfig } from "../../../core/config";
|
||||
import { DrawParameters } from "../../../core/draw_parameters";
|
||||
import { createLogger } from "../../../core/logging";
|
||||
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");
|
||||
|
||||
@ -19,7 +19,7 @@ export class HUDScreenshotExporter extends BaseHUDPart {
|
||||
}
|
||||
|
||||
startExport() {
|
||||
if (IS_DEMO) {
|
||||
if (!this.root.app.restrictionMgr.getIsExportingScreenshotsPossible()) {
|
||||
this.root.hud.parts.dialogs.showFeatureRestrictionInfo(T.demo.features.exportingBase);
|
||||
return;
|
||||
}
|
||||
@ -87,7 +87,7 @@ export class HUDScreenshotExporter extends BaseHUDPart {
|
||||
const parameters = new DrawParameters({
|
||||
context,
|
||||
visibleRect,
|
||||
desiredAtlasScale: chunkScale,
|
||||
desiredAtlasScale: 0.25,
|
||||
root: this.root,
|
||||
zoomLevel: chunkScale,
|
||||
});
|
||||
|
||||
@ -43,7 +43,7 @@ export class HUDSettingsMenu extends BaseHUDPart {
|
||||
];
|
||||
|
||||
for (let i = 0; i < buttons.length; ++i) {
|
||||
const { title, action, id } = buttons[i];
|
||||
const { action, id } = buttons[i];
|
||||
|
||||
const element = document.createElement("button");
|
||||
element.classList.add("styledButton");
|
||||
|
||||
@ -1,9 +1,8 @@
|
||||
import { ClickDetector } from "../../../core/click_detector";
|
||||
import { InputReceiver } from "../../../core/input_receiver";
|
||||
import { formatBigNumber, makeDiv } from "../../../core/utils";
|
||||
import { formatBigNumber, getRomanNumber, makeDiv } from "../../../core/utils";
|
||||
import { T } from "../../../translations";
|
||||
import { KeyActionMapper, KEYMAPPINGS } from "../../key_action_mapper";
|
||||
import { UPGRADES } from "../../upgrades";
|
||||
import { BaseHUDPart } from "../base_hud_part";
|
||||
import { DynamicDomAttach } from "../dynamic_dom_attach";
|
||||
|
||||
@ -21,7 +20,7 @@ export class HUDShop extends BaseHUDPart {
|
||||
this.upgradeToElements = {};
|
||||
|
||||
// Upgrades
|
||||
for (const upgradeId in UPGRADES) {
|
||||
for (const upgradeId in this.root.gameMode.getUpgrades()) {
|
||||
const handle = {};
|
||||
handle.requireIndexToElement = [];
|
||||
|
||||
@ -59,7 +58,7 @@ export class HUDShop extends BaseHUDPart {
|
||||
rerenderFull() {
|
||||
for (const upgradeId in this.upgradeToElements) {
|
||||
const handle = this.upgradeToElements[upgradeId];
|
||||
const upgradeTiers = UPGRADES[upgradeId];
|
||||
const upgradeTiers = this.root.gameMode.getUpgrades()[upgradeId];
|
||||
|
||||
const currentTier = this.root.hubGoals.getUpgradeLevel(upgradeId);
|
||||
const currentTierMultiplier = this.root.hubGoals.upgradeImprovements[upgradeId];
|
||||
@ -68,7 +67,7 @@ export class HUDShop extends BaseHUDPart {
|
||||
// Set tier
|
||||
handle.elemTierLabel.innerText = T.ingame.shop.tier.replace(
|
||||
"<x>",
|
||||
"" + T.ingame.shop.tierLabels[currentTier]
|
||||
getRomanNumber(currentTier + 1)
|
||||
);
|
||||
|
||||
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 { makeDiv } from "../../../core/utils";
|
||||
import { T } from "../../../translations";
|
||||
@ -33,16 +33,17 @@ export class HUDStandaloneAdvantages extends BaseHUDPart {
|
||||
</div>
|
||||
|
||||
<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>
|
||||
</div>
|
||||
`
|
||||
);
|
||||
|
||||
this.trackClicks(this.contentDiv.querySelector("button.steamLinkButton"), () => {
|
||||
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.trackClicks(this.contentDiv.querySelector("button.otherCloseButton"), () => {
|
||||
|
||||
@ -1,14 +1,14 @@
|
||||
import { globalConfig } from "../../../core/config";
|
||||
import { gMetaBuildingRegistry } from "../../../core/global_registries";
|
||||
import { InputReceiver } from "../../../core/input_receiver";
|
||||
import { makeDiv } from "../../../core/utils";
|
||||
import { SOUNDS } from "../../../platform/sound";
|
||||
import { T } from "../../../translations";
|
||||
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 { DynamicDomAttach } from "../dynamic_dom_attach";
|
||||
import { enumHubGoalRewardsToContentUnlocked } from "../../tutorial_goals_mappings";
|
||||
import { InputReceiver } from "../../../core/input_receiver";
|
||||
import { enumNotificationType } from "./notifications";
|
||||
|
||||
export class HUDUnlockNotification extends BaseHUDPart {
|
||||
@ -53,7 +53,9 @@ export class HUDUnlockNotification extends BaseHUDPart {
|
||||
showForLevel(level, reward) {
|
||||
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(
|
||||
T.ingame.notifications.freeplayLevelComplete.replace("<level>", String(level)),
|
||||
enumNotificationType.success
|
||||
|
||||
@ -4,6 +4,9 @@ import { T } from "../../../translations";
|
||||
import { BaseHUDPart } from "../base_hud_part";
|
||||
import { DynamicDomAttach } from "../dynamic_dom_attach";
|
||||
|
||||
const watermarkShowIntervalSeconds = G_IS_DEV ? 120 : 7 * 60;
|
||||
const watermarkShowDuration = 5;
|
||||
|
||||
export class HUDWatermark extends BaseHUDPart {
|
||||
createElements(parent) {
|
||||
this.element = makeDiv(
|
||||
@ -38,7 +41,9 @@ export class HUDWatermark extends BaseHUDPart {
|
||||
}
|
||||
|
||||
update() {
|
||||
this.domAttach.update(this.root.time.realtimeNow() % (G_IS_DEV ? 20 : 180) < 5);
|
||||
this.domAttach.update(
|
||||
this.root.time.realtimeNow() % watermarkShowIntervalSeconds < watermarkShowDuration
|
||||
);
|
||||
}
|
||||
|
||||
onWatermarkClick() {
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
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 { Loader } from "../../../core/loader";
|
||||
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,
|
||||
// actually show this *after* entering the name so you want the
|
||||
// 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(
|
||||
"",
|
||||
T.dialogs.markerDemoLimit.desc
|
||||
|
||||
@ -248,6 +248,8 @@ export function getStringForKeyCode(code) {
|
||||
return ",";
|
||||
case 189:
|
||||
return "-";
|
||||
case 190:
|
||||
return ".";
|
||||
case 191:
|
||||
return "/";
|
||||
case 219:
|
||||
@ -260,7 +262,9 @@ export function getStringForKeyCode(code) {
|
||||
return "'";
|
||||
}
|
||||
|
||||
return String.fromCharCode(code);
|
||||
return (48 <= code && code <= 57) || (65 <= code && code <= 90)
|
||||
? String.fromCharCode(code)
|
||||
: "[" + code + "]";
|
||||
}
|
||||
|
||||
export class Keybinding {
|
||||
|
||||
@ -26,11 +26,6 @@ export class MapView extends BaseMap {
|
||||
|
||||
/** @type {CanvasRenderingContext2D} */
|
||||
this.cachedBackgroundContext = null;
|
||||
/**
|
||||
* Cached pattern of the stripes background
|
||||
* @type {CanvasPattern} */
|
||||
this.cachedBackgroundPattern = null;
|
||||
|
||||
this.internalInitializeCachedBackgroundCanvases();
|
||||
this.root.signals.aboutToDestruct.add(this.cleanup, this);
|
||||
|
||||
@ -42,7 +37,6 @@ export class MapView extends BaseMap {
|
||||
cleanup() {
|
||||
freeCanvas(this.cachedBackgroundCanvas);
|
||||
this.cachedBackgroundCanvas = null;
|
||||
this.cachedBackgroundPattern = null;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -191,19 +185,15 @@ export class MapView extends BaseMap {
|
||||
* @param {DrawParameters} parameters
|
||||
*/
|
||||
drawBackground(parameters) {
|
||||
if (!this.cachedBackgroundPattern) {
|
||||
this.cachedBackgroundPattern = parameters.context.createPattern(
|
||||
this.cachedBackgroundCanvas,
|
||||
"repeat"
|
||||
);
|
||||
}
|
||||
|
||||
// Render tile grid
|
||||
if (!this.root.app.settings.getAllSettings().disableTileGrid) {
|
||||
const dpi = this.backgroundCacheDPI;
|
||||
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.visibleRect.x * 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;
|
||||
}
|
||||
}
|
||||
@ -27,6 +27,7 @@ import { BaseItem } from "./base_item";
|
||||
import { DynamicTickrate } from "./dynamic_tickrate";
|
||||
import { KeyActionMapper } from "./key_action_mapper";
|
||||
import { Vector } from "../core/vector";
|
||||
import { GameMode } from "./game_mode";
|
||||
/* typehints:end */
|
||||
|
||||
const logger = createLogger("game/root");
|
||||
@ -130,6 +131,9 @@ export class GameRoot {
|
||||
/** @type {Layer} */
|
||||
this.currentLayer = "regular";
|
||||
|
||||
/** @type {GameMode} */
|
||||
this.gameMode = null;
|
||||
|
||||
this.signals = {
|
||||
// Entities
|
||||
entityManuallyPlaced: /** @type {TypedSignal<[Entity]>} */ (new Signal()),
|
||||
|
||||
@ -12,7 +12,6 @@ import { GameSystemWithFilter } from "../game_system_with_filter";
|
||||
import { BOOL_FALSE_SINGLETON, BOOL_TRUE_SINGLETON } from "../items/boolean_item";
|
||||
import { COLOR_ITEM_SINGLETONS } from "../items/color_item";
|
||||
import { ShapeDefinition } from "../shape_definition";
|
||||
import { blueprintShape } from "../upgrades";
|
||||
|
||||
export class ConstantSignalSystem extends GameSystemWithFilter {
|
||||
constructor(root) {
|
||||
@ -61,7 +60,9 @@ export class ConstantSignalSystem extends GameSystemWithFilter {
|
||||
this.root.shapeDefinitionMgr.getShapeItemFromDefinition(
|
||||
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.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 { DrawParameters } from "../../core/draw_parameters";
|
||||
import { drawSpriteClipped } from "../../core/draw_utils";
|
||||
|
||||
@ -154,22 +154,18 @@ export class LogicGateSystem extends GameSystemWithFilter {
|
||||
|
||||
/**
|
||||
* @param {Array<BaseItem|null>} parameters
|
||||
* @returns {[BaseItem, BaseItem]}
|
||||
* @returns {BaseItem}
|
||||
*/
|
||||
compute_ROTATE(parameters) {
|
||||
const item = parameters[0];
|
||||
if (!item || item.getItemType() !== "shape") {
|
||||
// Not a shape
|
||||
return [null, null];
|
||||
return null;
|
||||
}
|
||||
|
||||
const definition = /** @type {ShapeItem} */ (item).definition;
|
||||
const rotatedDefinitionCCW = this.root.shapeDefinitionMgr.shapeActionRotateCCW(definition);
|
||||
const rotatedDefinitionCW = this.root.shapeDefinitionMgr.shapeActionRotateCW(definition);
|
||||
return [
|
||||
this.root.shapeDefinitionMgr.getShapeItemFromDefinition(rotatedDefinitionCCW),
|
||||
this.root.shapeDefinitionMgr.getShapeItemFromDefinition(rotatedDefinitionCW),
|
||||
];
|
||||
return 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!
|
||||
* @enum {string}
|
||||
@ -40,229 +36,3 @@ export const enumHubGoalRewards = {
|
||||
no_reward: "no_reward",
|
||||
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);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||