1
0
mirror of https://github.com/tobspr/shapez.io.git synced 2025-06-13 13:04:03 +00:00

Merge pull request #9 from tobspr/master

Update
This commit is contained in:
Killgaru 2020-06-22 14:18:08 +03:00 committed by GitHub
commit 375b581c28
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
138 changed files with 8961 additions and 4609 deletions

1
.gitignore vendored
View File

@ -115,3 +115,4 @@ tmp_standalone_files
# Local config
config.local.js
.DS_Store

9
.vscode/extensions.json vendored Normal file
View File

@ -0,0 +1,9 @@
{
// See https://go.microsoft.com/fwlink/?LinkId=827846 to learn about workspace recommendations.
// Extension identifier format: ${publisher}.${name}. Example: vscode.csharp
// List of extensions which should be recommended for users of this workspace.
"recommendations": ["esbenp.prettier-vscode"],
// List of extensions recommended by VS Code that should not be recommended for users of this workspace.
"unwantedRecommendations": []
}

View File

@ -16,7 +16,7 @@ Your goal is to produce shapes by cutting, rotating, merging and painting parts
- Make sure git `git lfs` extension is on your path
- Run `git lfs pull` to download sound assets
- Make sure `ffmpeg` is on your path
- Install Yarn and Node.js 10
- Install Node.js and Yarn
- Run `yarn` in the root folder, then run `yarn` in the `gulp/` folder
- Cd into `gulp` and run `yarn gulp` - it should now open in your browser

View File

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:6463b33b2cae50d1ecb11f0a845f06633aff331a5c2c0998d9eb93e40ad576b1
size 636254
oid sha256:7d05e340acb18f7b6b6f05fa7536f14179cda54a9ead0923fbb8e39c68da148c
size 703229

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 MiB

BIN
artwork/reddit/banner.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 597 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 63 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 17 KiB

View File

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:47b6aca7fe07f4628b041f32ce813a840793cfdce8ffa27c7ff4562858ac05f9
size 194245
oid sha256:ebde52e75e54d2f4add0cf498c85f059082a0745212a23c4de7328a7d78b00a5
size 238170

BIN
artwork/steam/devlog.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

3
artwork/steam/devlog.psd Normal file
View File

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:746c6cf3f0284798a78c08f77d7e9d0c28b02323081fda42b5fa876a7ade29a0
size 205925

Binary file not shown.

After

Width:  |  Height:  |  Size: 380 KiB

View File

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:e0cd2d82917e470202d38d32277f7519ccfd1821cb21791266539ddf07486d1b
size 7314327

BIN
artwork/wires/prefab.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 132 KiB

3
artwork/wires/prefab.psd Normal file
View File

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:498dea7314b8720c40dcd8bdd64b1b4a7a35259b2ffe7e896fc3db22878d6414
size 1954036

BIN
electron/favicon.icns Normal file

Binary file not shown.

27
gulp/cordova.js vendored
View File

@ -2,13 +2,15 @@ const path = require("path");
const fs = require("fs");
const buildUtils = require("./buildutils");
export function gulptasksCordova($, gulp, buildFolder) {
function gulptasksCordova($, gulp, buildFolder) {
const cdvRes = path.join("..", "..", "res");
// Cleans up the app assets
// Removes all temporary folders used while optimizing the assets
gulp.task("cleanupAppAssetsBuiltFolder", () => {
return gulp.src(path.join(cdvRes, "built"), { read: false }).pipe($.clean({ force: true }));
return gulp
.src(path.join(cdvRes, "built"), { read: false, allowEmpty: true })
.pipe($.clean({ force: true }));
});
// Optimizes all built assets
@ -64,7 +66,7 @@ export function gulptasksCordova($, gulp, buildFolder) {
.pipe(gulp.dest(path.join(cdvRes, "built", "ios")));
});
gulp.task("prepareIosRes", ["scaleIconIos", "copyOtherIosResources"]);
gulp.task("prepareIosRes", gulp.series("scaleIconIos", "copyOtherIosResources"));
gulp.task("copyAndroidResources", () => {
return gulp
@ -72,19 +74,20 @@ export function gulptasksCordova($, gulp, buildFolder) {
.pipe(gulp.dest(path.join(cdvRes, "built", "android")));
});
gulp.task("prepareAndroidRes", ["copyAndroidResources"]);
gulp.task("prepareAndroidRes", gulp.series("copyAndroidResources"));
gulp.task("prepareCordovaAssets", cb => {
return $.sequence(
gulp.task(
"prepareCordovaAssets",
gulp.series(
"cleanupAppAssetsBuiltFolder",
["prepareIosRes", "prepareAndroidRes"],
gulp.parallel("prepareIosRes", "prepareAndroidRes"),
"optimizeBuiltAppAssets"
)(cb);
});
)
);
// Patches the config.xml by replacing the app id to app_beta
gulp.task("patchConfigXML", () => {
gulp.task("patchConfigXML", cb => {
const configUrl = path.join("..", "..", "config.xml");
let configContent = fs.readFileSync(configUrl).toString();
const version = buildUtils.getVersion();
@ -92,14 +95,16 @@ export function gulptasksCordova($, gulp, buildFolder) {
configContent = configContent.replace(' id="io.shapez.app" ', ' id="io.shapez.app_beta" ');
configContent = configContent.replace("<name>Shapez.io</name>", "<name>Shapez.io BETA</name>");
fs.writeFileSync(configUrl, configContent);
cb();
});
gulp.task("patchConfigXMLChangeStagingToProd", () => {
gulp.task("patchConfigXMLChangeStagingToProd", cb => {
const configUrl = path.join("..", "..", "config.xml");
let configContent = fs.readFileSync(configUrl).toString();
configContent = configContent.replace(' id="io.shapez.app_beta" ', ' id="io.shapez.app" ');
configContent = configContent.replace("<name>Shapez.io BETA</name>", "<name>Shapez.io</name>");
fs.writeFileSync(configUrl, configContent);
cb();
});
// Triggers a new build on phonegap

View File

@ -13,7 +13,7 @@ function gulptasksDocs($, gulp, buildFolder) {
.pipe(gulp.dest(path.join("..", "tsc_temp")));
});
gulp.task("docs.copyTsconfigForHints", () => {
gulp.task("docs.copyTsconfigForHints", cb => {
const src = fs.readFileSync(path.join("..", "src", "js", "tsconfig.json")).toString();
const baseConfig = JSON.parse($.stripJsonComments(src));
@ -28,9 +28,10 @@ function gulptasksDocs($, gulp, buildFolder) {
baseConfig.composite = true;
baseConfig.outFile = "bundled-ts.js";
fs.writeFileSync(path.join("..", "tsc_temp", "tsconfig.json"), JSON.stringify(baseConfig));
cb();
});
gulp.task("main.prepareDocs", $.sequence("docs.convertJsToTs", "docs.copyTsconfigForHints"));
gulp.task("main.prepareDocs", gulp.series("docs.convertJsToTs", "docs.copyTsconfigForHints"));
}
module.exports = {

View File

@ -28,7 +28,7 @@ function gulptasksFTP($, gulp, buildFolder) {
};
// Write the "commit.txt" file
gulp.task("ftp.writeVersion", () => {
gulp.task("ftp.writeVersion", cb => {
fs.writeFileSync(
path.join(buildFolder, "version.json"),
JSON.stringify(
@ -41,6 +41,7 @@ function gulptasksFTP($, gulp, buildFolder) {
4
)
);
cb();
});
const gameSrcGlobs = [
@ -78,14 +79,15 @@ function gulptasksFTP($, gulp, buildFolder) {
.pipe($.sftp(deployCredentials));
});
gulp.task(`ftp.upload.${deployEnv}`, cb => {
$.sequence(
gulp.task(
`ftp.upload.${deployEnv}`,
gulp.series(
"ftp.writeVersion",
`ftp.upload.${deployEnv}.game`,
`ftp.upload.${deployEnv}.indexHtml`,
`ftp.upload.${deployEnv}.additionalFiles`
)(cb);
});
)
);
}
}

View File

@ -1,11 +1,5 @@
/* eslint-disable */
const nodeVersion = process.versions.node.split(".")[0];
if (nodeVersion !== "10") {
console.error("This cli requires exactly Node.js 10. You are using Node.js " + nodeVersion);
process.exit(1);
}
require("colors");
const gulp = require("gulp");
@ -95,15 +89,15 @@ translations.gulptasksTranslations($, gulp, buildFolder);
// Cleans up everything
gulp.task("utils.cleanBuildFolder", () => {
return gulp.src(buildFolder, { read: false }).pipe($.clean({ force: true }));
return gulp.src(buildFolder, { read: false, allowEmpty: true }).pipe($.clean({ force: true }));
});
gulp.task("utils.cleanBuildTempFolder", () => {
return gulp
.src(path.join(__dirname, "..", "src", "js", "built-temp"), { read: false })
.src(path.join(__dirname, "..", "src", "js", "built-temp"), { read: false, allowEmpty: true })
.pipe($.clean({ force: true }));
});
gulp.task("utils.cleanup", $.sequence("utils.cleanBuildFolder", "utils.cleanBuildTempFolder"));
gulp.task("utils.cleanup", gulp.series("utils.cleanBuildFolder", "utils.cleanBuildTempFolder"));
// Requires no uncomitted files
gulp.task("utils.requireCleanWorkingTree", cb => {
@ -166,71 +160,66 @@ function serve({ standalone }) {
});
// Watch .scss files, those trigger a css rebuild
gulp.watch(["../src/**/*.scss"], ["css.dev"]);
gulp.watch(["../src/**/*.scss"], gulp.series("css.dev"));
// Watch .html files, those trigger a html rebuild
gulp.watch("../src/**/*.html", [standalone ? "html.standalone-dev" : "html.dev"]);
gulp.watch("../src/**/*.html", gulp.series(standalone ? "html.standalone-dev" : "html.dev"));
// Watch sound files
// gulp.watch(["../res_raw/sounds/**/*.mp3", "../res_raw/sounds/**/*.wav"], ["sounds.dev"]);
// gulp.watch(["../res_raw/sounds/**/*.mp3", "../res_raw/sounds/**/*.wav"], gulp.series("sounds.dev"));
// Watch translations
gulp.watch("../translations/**/*.yaml", ["translations.convertToJson"]);
gulp.watch("../translations/**/*.yaml", gulp.series("translations.convertToJson"));
gulp.watch(
["../res_raw/sounds/sfx/*.mp3", "../res_raw/sounds/sfx/*.wav"],
$.sequence("sounds.sfx", "sounds.copy")
gulp.series("sounds.sfx", "sounds.copy")
);
gulp.watch(
["../res_raw/sounds/music/*.mp3", "../res_raw/sounds/music/*.wav"],
$.sequence("sounds.music", "sounds.copy")
gulp.series("sounds.music", "sounds.copy")
);
// Watch resource files and copy them on change
gulp.watch(imgres.nonImageResourcesGlobs, ["imgres.copyNonImageResources"]);
gulp.watch(imgres.imageResourcesGlobs, ["imgres.copyImageResources"]);
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/*.json", ["imgres.atlas"]);
gulp.watch("../res_built/atlas/*.json", gulp.series("imgres.atlas"));
// Watch the build folder and reload when anything changed
const extensions = ["html", "js", "png", "gif", "jpg", "svg", "mp3", "ico", "woff2", "json"];
gulp.watch(extensions.map(ext => path.join(buildFolder, "**", "*." + ext))).on("change", function (e) {
return gulp.src(e.path).pipe(browserSync.reload({ stream: true }));
gulp.watch(extensions.map(ext => path.join(buildFolder, "**", "*." + ext))).on("change", function (path) {
return gulp.src(path).pipe(browserSync.reload({ stream: true }));
});
gulp.watch("../src/js/built-temp/*.json").on("change", function (e) {
return gulp.src(e.path).pipe(browserSync.reload({ stream: true }));
gulp.watch("../src/js/built-temp/*.json").on("change", function (path) {
return gulp.src(path).pipe(browserSync.reload({ stream: true }));
});
// Start the webpack watching server (Will never return)
if (standalone) {
$.sequence("js.standalone-dev.watch")(() => true);
gulp.series("js.standalone-dev.watch")(() => true);
} else {
$.sequence("js.dev.watch")(() => true);
gulp.series("js.dev.watch")(() => true);
}
}
// Live-development
gulp.task("main.serveDev", ["build.dev"], () => serve({ standalone: false }));
gulp.task("main.serveStandalone", ["build.standalone.dev"], () => serve({ standalone: true }));
gulp.task("default", ["main.serveDev"]);
///////////////////// RUNNABLE TASKS /////////////////////
// Pre and postbuild
gulp.task("step.baseResources", cb => $.sequence("imgres.allOptimized")(cb));
gulp.task("step.baseResources", gulp.series("imgres.allOptimized"));
gulp.task("step.deleteEmpty", cb => {
deleteEmpty.sync(buildFolder);
cb();
});
gulp.task("step.postbuild", $.sequence("imgres.cleanupUnusedCssInlineImages", "step.deleteEmpty"));
gulp.task("step.postbuild", gulp.series("imgres.cleanupUnusedCssInlineImages", "step.deleteEmpty"));
// Builds everything (dev)
gulp.task("build.dev", cb => {
$.sequence(
gulp.task(
"build.dev",
gulp.series(
"utils.cleanup",
"utils.copyAdditionalBuildFiles",
"imgres.atlas",
@ -240,12 +229,13 @@ gulp.task("build.dev", cb => {
"translations.fullBuild",
"css.dev",
"html.dev"
)(cb);
});
)
);
// Builds everything (standalone -dev)
gulp.task("build.standalone.dev", cb => {
$.sequence(
gulp.task(
"build.standalone.dev",
gulp.series(
"utils.cleanup",
"imgres.atlas",
"sounds.dev",
@ -255,58 +245,74 @@ gulp.task("build.standalone.dev", cb => {
"js.standalone-dev",
"css.dev",
"html.standalone-dev"
)(cb);
});
)
);
// Builds everything (staging)
gulp.task("step.staging.code", $.sequence("sounds.fullbuild", "translations.fullBuild", "js.staging"));
gulp.task("step.staging.mainbuild", cb =>
$.multiProcess(["utils.copyAdditionalBuildFiles", "step.baseResources", "step.staging.code"], cb, false)
gulp.task("step.staging.code", gulp.series("sounds.fullbuild", "translations.fullBuild", "js.staging"));
gulp.task(
"step.staging.mainbuild",
gulp.parallel("utils.copyAdditionalBuildFiles", "step.baseResources", "step.staging.code")
);
gulp.task("step.staging.all", $.sequence("step.staging.mainbuild", "css.prod", "html.staging"));
gulp.task("build.staging", $.sequence("utils.cleanup", "step.staging.all", "step.postbuild"));
gulp.task("step.staging.all", gulp.series("step.staging.mainbuild", "css.prod", "html.staging"));
gulp.task("build.staging", gulp.series("utils.cleanup", "step.staging.all", "step.postbuild"));
// Builds everything (prod)
gulp.task("step.prod.code", $.sequence("sounds.fullbuild", "translations.fullBuild", "js.prod"));
gulp.task("step.prod.mainbuild", cb =>
$.multiProcess(["utils.copyAdditionalBuildFiles", "step.baseResources", "step.prod.code"], cb, false)
gulp.task("step.prod.code", gulp.series("sounds.fullbuild", "translations.fullBuild", "js.prod"));
gulp.task(
"step.prod.mainbuild",
gulp.parallel("utils.copyAdditionalBuildFiles", "step.baseResources", "step.prod.code")
);
gulp.task("step.prod.all", $.sequence("step.prod.mainbuild", "css.prod", "html.prod"));
gulp.task("build.prod", $.sequence("utils.cleanup", "step.prod.all", "step.postbuild"));
gulp.task("step.prod.all", gulp.series("step.prod.mainbuild", "css.prod", "html.prod"));
gulp.task("build.prod", gulp.series("utils.cleanup", "step.prod.all", "step.postbuild"));
// Builds everything (standalone-beta)
gulp.task(
"step.standalone-beta.code",
$.sequence("sounds.fullbuild", "translations.fullBuild", "js.standalone-beta")
);
gulp.task("step.standalone-beta.mainbuild", cb =>
$.multiProcess(["step.baseResources", "step.standalone-beta.code"], cb, false)
gulp.series("sounds.fullbuildHQ", "translations.fullBuild", "js.standalone-beta")
);
gulp.task("step.standalone-beta.mainbuild", gulp.parallel("step.baseResources", "step.standalone-beta.code"));
gulp.task(
"step.standalone-beta.all",
$.sequence("step.standalone-beta.mainbuild", "css.prod-standalone", "html.standalone-beta")
gulp.series("step.standalone-beta.mainbuild", "css.prod-standalone", "html.standalone-beta")
);
gulp.task(
"build.standalone-beta",
gulp.series("utils.cleanup", "step.standalone-beta.all", "step.postbuild")
);
gulp.task("build.standalone-beta", $.sequence("utils.cleanup", "step.standalone-beta.all", "step.postbuild"));
// Builds everything (standalone-prod)
gulp.task(
"step.standalone-prod.code",
$.sequence("sounds.fullbuild", "translations.fullBuild", "js.standalone-prod")
);
gulp.task("step.standalone-prod.mainbuild", cb =>
$.multiProcess(["step.baseResources", "step.standalone-prod.code"], cb, false)
gulp.series("sounds.fullbuildHQ", "translations.fullBuild", "js.standalone-prod")
);
gulp.task("step.standalone-prod.mainbuild", gulp.parallel("step.baseResources", "step.standalone-prod.code"));
gulp.task(
"step.standalone-prod.all",
$.sequence("step.standalone-prod.mainbuild", "css.prod-standalone", "html.standalone-prod")
gulp.series("step.standalone-prod.mainbuild", "css.prod-standalone", "html.standalone-prod")
);
gulp.task(
"build.standalone-prod",
gulp.series("utils.cleanup", "step.standalone-prod.all", "step.postbuild")
);
gulp.task("build.standalone-prod", $.sequence("utils.cleanup", "step.standalone-prod.all", "step.postbuild"));
// Deploying!
gulp.task(
"main.deploy.staging",
$.sequence("utils.requireCleanWorkingTree", "build.staging", "ftp.upload.staging")
gulp.series("utils.requireCleanWorkingTree", "build.staging", "ftp.upload.staging")
);
gulp.task("main.deploy.prod", $.sequence("utils.requireCleanWorkingTree", "build.prod", "ftp.upload.prod"));
gulp.task("main.deploy.all", $.sequence("main.deploy.staging", "main.deploy.prod"));
gulp.task("main.standalone", $.sequence("build.standalone-prod", "standalone.package.prod"));
gulp.task("main.deploy.prod", gulp.series("utils.requireCleanWorkingTree", "build.prod", "ftp.upload.prod"));
gulp.task("main.deploy.all", gulp.series("main.deploy.staging", "main.deploy.prod"));
gulp.task("main.standalone", gulp.series("build.standalone-prod", "standalone.package.prod"));
// Live-development
gulp.task(
"main.serveDev",
gulp.series("build.dev", () => serve({ standalone: false }))
);
gulp.task(
"main.serveStandalone",
gulp.series("build.standalone.dev", () => serve({ standalone: true }))
);
gulp.task("default", gulp.series("main.serveDev"));

View File

@ -10,7 +10,7 @@ const imageResourcesGlobs = ["../res/**/*.png", "../res/**/*.svg", "../res/**/*.
function gulptasksImageResources($, gulp, buildFolder) {
// Lossless options
const minifyImagesOptsLossless = () => [
$.imagemin.jpegtran({
$.imageminJpegtran({
progressive: true,
}),
$.imagemin.svgo({}),
@ -25,7 +25,7 @@ function gulptasksImageResources($, gulp, buildFolder) {
// Lossy options
const minifyImagesOpts = () => [
$.imageminMozjpeg({
$.imagemin.mozjpeg({
quality: 80,
maxMemory: 1024 * 1024 * 8,
}),
@ -116,11 +116,12 @@ function gulptasksImageResources($, gulp, buildFolder) {
});
// Copies all resources and optimizes them
gulp.task("imgres.allOptimized", cb =>
$.multiProcess(
["imgres.atlasOptimized", "imgres.copyNonImageResources", "imgres.copyImageResourcesOptimized"],
cb,
false
gulp.task(
"imgres.allOptimized",
gulp.parallel(
"imgres.atlasOptimized",
"imgres.copyNonImageResources",
"imgres.copyImageResourcesOptimized"
)
);

View File

@ -68,7 +68,7 @@ function gulptasksJS($, gulp, buildFolder, browserSync) {
)
.pipe(gulp.dest(buildFolder));
});
gulp.task("js.staging", cb => $.multiProcess(["js.staging.transpiled", "js.staging.latest"], cb, false));
gulp.task("js.staging", gulp.parallel("js.staging.transpiled", "js.staging.latest"));
//// PROD
gulp.task("js.prod.transpiled", () => {
@ -104,7 +104,7 @@ function gulptasksJS($, gulp, buildFolder, browserSync) {
.pipe(browserSync.stream());
});
gulp.task("js.prod", cb => $.multiProcess(["js.prod.transpiled", "js.prod.latest"], cb, false));
gulp.task("js.prod", gulp.parallel("js.prod.transpiled", "js.prod.latest"));
//// STANDALONE

View File

@ -70,40 +70,38 @@
"css-mqpacker": "^7.0.0",
"cssnano": "^4.1.10",
"electron-packager": "^14.0.6",
"imagemin-gifsicle": "^7.0.0",
"faster.js": "^1.1.0",
"glob": "^7.1.3",
"gulp": "^3.9.1",
"gulp": "^4.0.2",
"gulp-cache": "^1.1.3",
"gulp-cached": "^1.1.1",
"gulp-clean": "^0.4.0",
"gulp-cssbeautify": "^1.0.1",
"gulp-cssbeautify": "^2.0.1",
"gulp-csslint": "^1.0.1",
"gulp-dom": "^1.0.0",
"gulp-flatten": "^0.4.0",
"gulp-fluent-ffmpeg": "^1.0.2",
"gulp-fluent-ffmpeg": "^2.0.0",
"gulp-html-beautify": "^1.0.1",
"gulp-htmlmin": "^5.0.1",
"gulp-if": "^2.0.2",
"gulp-imagemin": "^5.0.3",
"gulp-if": "^3.0.0",
"gulp-imagemin": "^7.1.0",
"gulp-javascript-obfuscator": "^1.1.5",
"gulp-jsbeautifier": "^3.0.0",
"gulp-load-plugins": "^1.5.0",
"gulp-multi-process": "^1.3.1",
"gulp-load-plugins": "^2.0.3",
"gulp-phonegap-build": "^0.1.5",
"gulp-plumber": "^1.2.1",
"gulp-pngquant": "^1.0.12",
"gulp-pngquant": "^1.0.13",
"gulp-postcss": "^8.0.0",
"gulp-rename": "^1.4.0",
"gulp-sass": "^4.0.1",
"gulp-rename": "^2.0.0",
"gulp-sass": "^4.1.0",
"gulp-sass-lint": "^1.4.0",
"gulp-sequence": "^1.0.0",
"gulp-sftp": "^0.1.5",
"gulp-sftp": "git+https://git@github.com/webksde/gulp-sftp",
"gulp-terser": "^1.2.0",
"gulp-webserver": "^0.9.1",
"gulp-yaml": "^2.0.4",
"imagemin-mozjpeg": "^8.0.0",
"imagemin-pngquant": "^8.0.0",
"imagemin-gifsicle": "^7.0.0",
"imagemin-jpegtran": "^7.0.0",
"imagemin-pngquant": "^9.0.0",
"jimp": "^0.6.1",
"js-yaml": "^3.13.1",
"onesky-fetch": "^0.0.7",

View File

@ -3,11 +3,11 @@ const audiosprite = require("gulp-audiosprite");
function gulptasksSounds($, gulp, buildFolder) {
// Gather some basic infos
const soundsDir = path.join("..", "res_raw", "sounds");
const builtSoundsDir = path.join("..", "res_built", "sounds");
const soundsDir = path.join(__dirname, "..", "res_raw", "sounds");
const builtSoundsDir = path.join(__dirname, "..", "res_built", "sounds");
gulp.task("sounds.clear", () => {
return gulp.src(builtSoundsDir).pipe($.clean({ force: true }));
return gulp.src(builtSoundsDir, { read: false, allowEmpty: true }).pipe($.clean({ force: true }));
});
const filters = ["volume=0.2"];
@ -29,7 +29,7 @@ function gulptasksSounds($, gulp, buildFolder) {
.audioChannels(1)
.audioFrequency(22050)
.audioCodec("libmp3lame")
.audioFilters(["volume=0.3"]);
.audioFilters(["volume=0.15"]);
}),
{
name: "music",
@ -40,6 +40,30 @@ function gulptasksSounds($, gulp, buildFolder) {
.pipe(gulp.dest(path.join(builtSoundsDir, "music")));
});
// Encodes the game music in high quality for the standalone
gulp.task("sounds.musicHQ", () => {
return gulp
.src([path.join(soundsDir, "music", "**", "*.wav"), path.join(soundsDir, "music", "**", "*.mp3")])
.pipe($.plumber())
.pipe(
$.cache(
$.fluentFfmpeg("mp3", function (cmd) {
return cmd
.audioBitrate(256)
.audioChannels(2)
.audioFrequency(44100)
.audioCodec("libmp3lame")
.audioFilters(["volume=0.15"]);
}),
{
name: "music-high-quality",
fileCache,
}
)
)
.pipe(gulp.dest(path.join(builtSoundsDir, "music")));
});
// Encodes the ui sounds
gulp.task("sounds.sfxGenerateSprites", () => {
return gulp
@ -79,7 +103,7 @@ function gulptasksSounds($, gulp, buildFolder) {
gulp.task(
"sounds.sfx",
$.sequence("sounds.sfxGenerateSprites", "sounds.sfxOptimize", "sounds.sfxCopyAtlas")
gulp.series("sounds.sfxGenerateSprites", "sounds.sfxOptimize", "sounds.sfxCopyAtlas")
);
gulp.task("sounds.copy", () => {
@ -90,10 +114,12 @@ function gulptasksSounds($, gulp, buildFolder) {
.pipe(gulp.dest(path.join(buildFolder, "res", "sounds")));
});
gulp.task("sounds.buildall", cb => $.multiProcess(["sounds.music", "sounds.sfx"], cb, true));
gulp.task("sounds.buildall", gulp.parallel("sounds.music", "sounds.sfx"));
gulp.task("sounds.buildallHQ", gulp.parallel("sounds.musicHQ", "sounds.sfx"));
gulp.task("sounds.fullbuild", cb => $.sequence("sounds.clear", "sounds.buildall", "sounds.copy")(cb));
gulp.task("sounds.dev", cb => $.sequence("sounds.buildall", "sounds.copy")(cb));
gulp.task("sounds.fullbuild", gulp.series("sounds.clear", "sounds.buildall", "sounds.copy"));
gulp.task("sounds.fullbuildHQ", gulp.series("sounds.clear", "sounds.buildallHQ", "sounds.copy"));
gulp.task("sounds.dev", gulp.series("sounds.buildall", "sounds.copy"));
}
module.exports = {

View File

@ -6,13 +6,13 @@ const fse = require("fs-extra");
const execSync = require("child_process").execSync;
function gulptasksStandalone($, gulp, buildFolder) {
const electronBaseDir = path.join("../electron");
const electronBaseDir = path.join(__dirname, "..", "electron");
const tempDestDir = path.join("..", "tmp_standalone_files");
const tempDestDir = path.join(__dirname, "..", "tmp_standalone_files");
const tempDestBuildDir = path.join(tempDestDir, "built");
gulp.task("standalone.prepare.cleanup", () => {
return gulp.src(tempDestDir, { read: false }).pipe($.clean({ force: true }));
return gulp.src(tempDestDir, { read: false, allowEmpty: true }).pipe($.clean({ force: true }));
});
gulp.task("standalone.prepare.copyPrefab", () => {
@ -30,7 +30,7 @@ function gulptasksStandalone($, gulp, buildFolder) {
return gulp.src(requiredFiles, { base: electronBaseDir }).pipe(gulp.dest(tempDestBuildDir));
});
gulp.task("standalone.prepare.writePackageJson", () => {
gulp.task("standalone.prepare.writePackageJson", cb => {
fs.writeFileSync(
path.join(tempDestBuildDir, "package.json"),
JSON.stringify(
@ -43,67 +43,71 @@ function gulptasksStandalone($, gulp, buildFolder) {
4
)
);
cb();
});
gulp.task("standalone.prepare.minifyCode", () => {
return gulp
.src(path.join(electronBaseDir, "*.js"))
.pipe(
$.terser({
ecma: 6,
parse: {},
module: false,
toplevel: true,
keep_classnames: false,
keep_fnames: false,
safari10: false,
compress: {
arguments: false, // breaks
drop_console: false,
// keep_fargs: false,
keep_infinity: true,
passes: 2,
module: false,
toplevel: true,
unsafe_math: true,
unsafe_arrows: false,
warnings: true,
},
mangle: {
eval: true,
keep_classnames: false,
keep_fnames: false,
module: false,
toplevel: true,
safari10: false,
},
output: {
comments: false,
ascii_only: true,
beautify: false,
braces: false,
ecma: 6,
},
})
)
.pipe(gulp.dest(tempDestBuildDir));
return (
gulp
.src(path.join(electronBaseDir, "*.js"))
// .pipe(
// $.terser({
// ecma: 6,
// parse: {},
// module: false,
// toplevel: true,
// keep_classnames: false,
// keep_fnames: false,
// safari10: false,
// compress: {
// arguments: false, // breaks
// drop_console: false,
// // keep_fargs: false,
// keep_infinity: true,
// passes: 2,
// module: false,
// toplevel: true,
// unsafe_math: true,
// unsafe_arrows: false,
// warnings: true,
// },
// mangle: {
// eval: true,
// keep_classnames: false,
// keep_fnames: false,
// module: false,
// toplevel: true,
// safari10: false,
// },
// output: {
// comments: false,
// ascii_only: true,
// beautify: false,
// braces: false,
// ecma: 6,
// },
// })
// )
.pipe(gulp.dest(tempDestBuildDir))
);
});
gulp.task("standalone.prepare.copyGamefiles", () => {
return gulp.src("../build/**/*.*", { base: "../build" }).pipe(gulp.dest(tempDestBuildDir));
});
gulp.task("standalone.killRunningInstances", () => {
gulp.task("standalone.killRunningInstances", cb => {
try {
execSync("taskkill /F /IM shapezio.exe");
} catch (ex) {
console.warn("Failed to kill running instances, maybe none are up.");
}
cb();
});
gulp.task(
"standalone.prepare",
$.sequence(
gulp.series(
"standalone.killRunningInstances",
"standalone.prepare.cleanup",
"standalone.prepare.copyPrefab",
@ -190,13 +194,16 @@ function gulptasksStandalone($, gulp, buildFolder) {
gulp.task(
"standalone.package.prod",
$.sequence("standalone.prepare", [
"standalone.package.prod.win64",
"standalone.package.prod.linux64",
"standalone.package.prod.darwin64",
// "standalone.package.prod.win32",
// "standalone.package.prod.linux32",
])
gulp.series(
"standalone.prepare",
gulp.parallel(
"standalone.package.prod.win64",
"standalone.package.prod.linux64",
"standalone.package.prod.darwin64"
// "standalone.package.prod.win32",
// "standalone.package.prod.linux32",
)
)
);
}

View File

@ -14,7 +14,7 @@ function gulptasksTranslations($, gulp, buildFolder) {
.pipe(gulp.dest(translationsJsonDir));
});
gulp.task("translations.fullBuild", $.sequence("translations.convertToJson"));
gulp.task("translations.fullBuild", gulp.series("translations.convertToJson"));
}
module.exports = {

File diff suppressed because it is too large Load Diff

View File

@ -7,7 +7,7 @@
"license": "MIT",
"private": true,
"scripts": {
"dev": "./gulp/gulp main.serveDev",
"dev": "cd gulp && yarn gulp main.serveDev",
"tslint": "cd src/js && tsc",
"lint": "npx eslint src/js",
"prettier-all": "prettier --write src/**/*.* && prettier --write gulp/**/*.*",

Binary file not shown.

Before

Width:  |  Height:  |  Size: 35 KiB

After

Width:  |  Height:  |  Size: 111 KiB

View File

@ -1,60 +1,25 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" id="Layer_1" x="0px" y="0px" viewBox="0 0 512 512" style="enable-background:new 0 0 512 512;" xml:space="preserve">
<path style="fill:#C8414B;" d="M400,0H112C50.144,0,0,50.144,0,112v288c0,61.856,50.144,112,112,112h288 c61.856,0,112-50.144,112-112V112C512,50.144,461.856,0,400,0z"/>
<rect y="106.63" style="fill:#FFD250;" width="512" height="298.74"/>
<path style="fill:#C8414B;" d="M223.091,256.412l8.255-33.665c0.76-3.1-1.843-6.041-5.347-6.041h-5.815 c-3.504,0-6.108,2.941-5.347,6.041L223.091,256.412z"/>
<rect x="213.35" y="238.76" style="fill:#F5F5F5;" width="19.473" height="75"/>
<rect x="208.49" y="229.94" style="fill:#FAB446;" width="29.21" height="8.823"/>
<g>
<rect x="189.01" y="256.41" style="fill:#C8414B;" width="48.681" height="8.823"/>
<polygon style="fill:#C8414B;" points="237.696,291.706 208.487,282.882 208.487,274.059 237.696,282.882 "/>
<path style="fill:#C8414B;" d="M77.047,256.412l8.255-33.665c0.76-3.1-1.843-6.041-5.347-6.041H74.14 c-3.504,0-6.108,2.941-5.347,6.041L77.047,256.412z"/>
</g>
<path style="fill:#F5F5F5;" d="M111.124,229.941c-5.377,0-9.736,3.95-9.736,8.824v57.353c0,10.721,11.041,30.882,48.682,30.882 s48.682-20.162,48.682-30.882v-57.353c0-4.873-4.359-8.824-9.736-8.824L111.124,229.941L111.124,229.941z"/>
<g>
<path style="fill:#C8414B;" d="M150.069,274.059h-48.682V239.21c0-5.119,4.15-9.269,9.269-9.269h39.413V274.059z"/>
<path style="fill:#C8414B;" d="M150.069,274.059h48.682v20.946c0,12.797-10.374,23.172-23.172,23.172h-2.338 c-12.797,0-23.172-10.374-23.172-23.172L150.069,274.059L150.069,274.059z"/>
</g>
<path style="fill:#FAB446;" d="M101.387,274.059h48.682v20.946c0,12.797-10.374,23.172-23.172,23.172h-2.338 c-12.797,0-23.172-10.374-23.172-23.172C101.387,295.005,101.387,274.059,101.387,274.059z"/>
<g>
<path style="fill:#C8414B;" d="M140.333,313.665v-39.606h-9.736v43.673C134.217,317.065,137.49,315.612,140.333,313.665z"/>
<path style="fill:#C8414B;" d="M120.86,317.732v-43.673h-9.736v39.606C113.967,315.612,117.239,317.065,120.86,317.732z"/>
</g>
<rect x="111.12" y="256.41" style="fill:#FFB441;" width="29.21" height="8.823"/>
<g>
<rect x="111.12" y="238.76" style="fill:#FAB446;" width="29.21" height="8.824"/>
<rect x="115.99" y="244.01" style="fill:#FAB446;" width="19.473" height="15.985"/>
</g>
<rect x="67.31" y="238.76" style="fill:#F5F5F5;" width="19.473" height="75"/>
<g>
<rect x="62.44" y="309.35" style="fill:#FAB446;" width="29.21" height="8.823"/>
<rect x="62.44" y="229.94" style="fill:#FAB446;" width="29.21" height="8.823"/>
</g>
<rect x="57.57" y="318.18" style="fill:#5064AA;" width="38.945" height="8.823"/>
<rect x="213.35" y="309.35" style="fill:#FAB446;" width="29.21" height="8.823"/>
<rect x="203.62" y="318.18" style="fill:#5064AA;" width="38.945" height="8.823"/>
<rect x="120.86" y="221.12" style="fill:#FAB446;" width="58.42" height="8.823"/>
<rect x="145.2" y="194.65" style="fill:#FFB441;" width="9.736" height="26.471"/>
<g>
<path style="fill:#F5F5F5;" d="M140.333,207.882c-8.053,0-14.604-5.937-14.604-13.235s6.551-13.235,14.604-13.235 c8.053,0,14.604,5.937,14.604,13.235S148.386,207.882,140.333,207.882z M140.333,190.235c-2.686,0-4.868,1.978-4.868,4.412 s2.182,4.412,4.868,4.412c2.686,0,4.868-1.978,4.868-4.412C145.201,192.213,143.019,190.235,140.333,190.235z"/>
<path style="fill:#F5F5F5;" d="M159.805,207.882c-8.053,0-14.604-5.937-14.604-13.235s6.551-13.235,14.604-13.235 c8.053,0,14.604,5.937,14.604,13.235S167.859,207.882,159.805,207.882z M159.805,190.235c-2.686,0-4.868,1.978-4.868,4.412 s2.182,4.412,4.868,4.412c2.686,0,4.868-1.978,4.868-4.412C164.673,192.213,162.491,190.235,159.805,190.235z"/>
<path style="fill:#F5F5F5;" d="M179.278,216.706c-8.053,0-14.604-5.937-14.604-13.235s6.551-13.235,14.604-13.235 c8.053,0,14.605,5.937,14.605,13.235S187.331,216.706,179.278,216.706z M179.278,199.059c-2.686,0-4.868,1.978-4.868,4.412 s2.182,4.412,4.868,4.412c2.686,0,4.868-1.978,4.868-4.412C184.146,201.036,181.964,199.059,179.278,199.059z"/>
<path style="fill:#F5F5F5;" d="M120.86,216.706c-8.053,0-14.604-5.937-14.604-13.235s6.551-13.235,14.604-13.235 s14.604,5.937,14.604,13.235S128.913,216.706,120.86,216.706z M120.86,199.059c-2.686,0-4.868,1.978-4.868,4.412 s2.182,4.412,4.868,4.412s4.868-1.978,4.868-4.412C125.728,201.036,123.546,199.059,120.86,199.059z"/>
</g>
<path style="fill:#FAB446;" d="M179.278,291.706v4.412c0,2.433-2.184,4.412-4.868,4.412c-2.684,0-4.868-1.979-4.868-4.412v-4.412 H179.278 M189.014,282.882h-29.209v13.235c0,7.298,6.552,13.235,14.604,13.235c8.053,0,14.605-5.938,14.605-13.235V282.882 L189.014,282.882z"/>
<path style="fill:#FFA0D2;" d="M174.877,265.235h-0.935c-5.119,0-9.269-4.15-9.269-9.269v-7.933c0-5.119,4.15-9.269,9.269-9.269 h0.935c5.119,0,9.269,4.15,9.269,9.269v7.933C184.146,261.086,179.996,265.235,174.877,265.235z"/>
<ellipse style="fill:#5064AA;" cx="150.07" cy="274.06" rx="14.604" ry="13.235"/>
<rect x="145.2" y="177" style="fill:#FAB446;" width="9.736" height="26.471"/>
<path style="fill:#C8414B;" d="M120.86,221.118l-9.736-8.824l5.703-5.169c8.816-7.99,20.774-12.478,33.242-12.478l0,0 c12.468,0,24.426,4.489,33.242,12.478l5.703,5.169l-9.736,8.824H120.86z"/>
<g>
<ellipse style="fill:#FFD250;" cx="150.07" cy="212.29" rx="4.868" ry="4.412"/>
<ellipse style="fill:#FFD250;" cx="130.6" cy="212.29" rx="4.868" ry="4.412"/>
<ellipse style="fill:#FFD250;" cx="169.54" cy="212.29" rx="4.868" ry="4.412"/>
</g>
<g>
<rect x="62.44" y="256.41" style="fill:#C8414B;" width="48.681" height="8.823"/>
<polygon style="fill:#C8414B;" points="62.442,291.706 91.651,282.882 91.651,274.059 62.442,282.882 "/>
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 512 512" style="enable-background:new 0 0 512 512;" xml:space="preserve">
<g transform="translate(-1)">
<path style="fill:#46B29D;" d="M328.61,98.163h0.088c1.971-0.012,3.923,0.379,5.738,1.148l71.683,29.484
c4.07,1.723,7.249,5.049,8.787,9.193c1.537,4.144,1.297,8.739-0.665,12.699l-11.652,24.099
c-5.942,12.252-10.388,25.174-13.242,38.488l-12.624,58.086c-1.107,5.424-5.003,9.857-10.24,11.652l-11.653,3.972
c-5.094,1.809-8.94,6.053-10.241,11.299l-6.885,28.513c-0.25,1.103-0.635,2.17-1.148,3.178l-5.473,11.211
c-2.003,4.139-5.709,7.201-10.152,8.386l-18.715,4.855c-7.018,1.83-11.893,8.196-11.829,15.448v11.211
c-0.023,3.42-1.102,6.75-3.09,9.534l-19.51,26.748c-3.683,5.056-5.967,10.993-6.621,17.214l-6.091,56.585
c-0.638,5.71-3.3,11.002-7.503,14.919c-4.172,3.812-9.621,5.922-15.272,5.914c-10.207-0.042-19.147-6.854-21.896-16.684
L187.45,416.75c-0.269-0.922-0.447-1.868-0.53-2.825l-17.656-163.84c-0.585-5.323-3.801-9.997-8.563-12.447l-21.629-11.211
c-5.391-2.781-9.662-7.331-12.094-12.888l-26.661-61.793c-4.326-9.941-2.235-21.509,5.297-29.308l10.064-10.417
c3.583-3.658,5.192-8.813,4.326-13.859l-4.414-27.63c-2.316-13.91,2.107-28.094,11.918-38.223l18.715-19.244
C154.266,4.72,165.356,0.003,176.945,0h29.662c11.59,0.003,22.679,4.72,30.721,13.065l16.244,16.684L328.61,98.163z"/>
<path style="fill:#BDC3C7;" d="M283.478,97.103h35.31V220.69c0,9.751-7.904,17.655-17.655,17.655l0,0
c-9.751,0-17.655-7.904-17.655-17.655V97.103z"/>
<circle style="fill:#CC4B4C;" cx="301.133" cy="52.966" r="52.966"/>
<path style="fill:#FB7B76;" d="M283.478,61.793c-4.875,0-8.828-3.952-8.828-8.828c0.016-14.619,11.863-26.467,26.483-26.483
c4.875,0,8.828,3.952,8.828,8.828s-3.952,8.828-8.828,8.828c-4.873,0.006-8.821,3.955-8.828,8.828
C292.305,57.841,288.353,61.793,283.478,61.793z"/>
</g>
<g>
</g>

Before

Width:  |  Height:  |  Size: 5.8 KiB

After

Width:  |  Height:  |  Size: 2.2 KiB

41
res/ui/languages/no.svg Normal file
View File

@ -0,0 +1,41 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 512 512" style="enable-background:new 0 0 512 512;" xml:space="preserve">
<path style="fill:#FF4B55;" d="M400,0H112C50.144,0,0,50.144,0,112v288c0,61.856,50.144,112,112,112h288
c61.856,0,112-50.144,112-112V112C512,50.144,461.856,0,400,0z"/>
<polygon style="fill:#F5F5F5;" points="512,211.862 229.517,211.862 229.517,0 141.241,0 141.241,211.862 0,211.862 0,300.138
141.241,300.138 141.241,512 229.517,512 229.517,300.138 512,300.138 "/>
<polygon style="fill:#41479B;" points="512,229.517 211.862,229.517 211.862,0 158.897,0 158.897,229.517 0,229.517 0,282.483
158.897,282.483 158.897,512 211.862,512 211.862,282.483 512,282.483 "/>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.0 KiB

View File

@ -0,0 +1,64 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 512 512" style="enable-background:new 0 0 512 512;" xml:space="preserve">
<path style="fill:#FF4B55;" d="M400,0H185.379v512H400c61.856,0,112-50.144,112-112V112C512,50.144,461.856,0,400,0z"/>
<path style="fill:#73AF00;" d="M112,0C50.144,0,0,50.144,0,112v288c0,61.856,50.144,112,112,112h73.379V0H112z"/>
<circle style="fill:#FFE15A;" cx="185.45" cy="256" r="112.38"/>
<path style="fill:#FF4B55;" d="M222.941,218.508v49.99c0,20.673-16.819,37.492-37.492,37.492s-37.492-16.819-37.492-37.492v-49.99
L222.941,218.508 M235.438,193.513h-99.98c-6.902,0-12.497,5.595-12.497,12.497v62.487c0,34.511,27.977,62.487,62.487,62.487
s62.487-27.977,62.487-62.487V206.01C247.936,199.108,242.34,193.513,235.438,193.513L235.438,193.513z"/>
<path style="fill:#F5F5F5;" d="M211.931,229.517v35.31c0,14.603-11.88,26.483-26.483,26.483s-26.483-11.88-26.483-26.483v-35.31
H211.931"/>
<g>
<circle style="fill:#FFE15A;" cx="135.36" cy="206.01" r="6.249"/>
<circle style="fill:#FFE15A;" cx="235.34" cy="206.01" r="6.249"/>
<circle style="fill:#FFE15A;" cx="135.36" cy="256" r="6.249"/>
<circle style="fill:#FFE15A;" cx="235.34" cy="256" r="6.249"/>
<circle style="fill:#FFE15A;" cx="185.35" cy="206.01" r="6.249"/>
<circle style="fill:#FFE15A;" cx="222.87" cy="302.08" r="6.249"/>
<circle style="fill:#FFE15A;" cx="148.57" cy="302.08" r="6.249"/>
</g>
<g>
<path style="fill:#41479B;" d="M193.52,252.832v10.762c0,4.451-3.621,8.071-8.071,8.071s-8.071-3.621-8.071-8.071v-10.762H193.52"
/>
<path style="fill:#41479B;" d="M193.52,227.317v10.762c0,4.451-3.621,8.071-8.071,8.071s-8.071-3.621-8.071-8.071v-10.762H193.52"
/>
<path style="fill:#41479B;" d="M193.52,278.608v10.762c0,4.451-3.621,8.071-8.071,8.071s-8.071-3.621-8.071-8.071v-10.762H193.52"
/>
<path style="fill:#41479B;" d="M215.26,252.832v10.762c0,4.451-3.621,8.071-8.071,8.071s-8.071-3.621-8.071-8.071v-10.762H215.26"
/>
<path style="fill:#41479B;" d="M171.779,252.832v10.762c0,4.451-3.621,8.071-8.071,8.071s-8.071-3.621-8.071-8.071v-10.762H171.779
"/>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.4 KiB

View File

@ -0,0 +1,42 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" id="Layer_1" x="0px" y="0px" viewBox="0 0 512 512" style="enable-background:new 0 0 512 512;" xml:space="preserve">
<path style="fill:#FF4B55;" d="M400,0H112C50.144,0,0,50.144,0,112v288c0,61.856,50.144,112,112,112h288 c61.856,0,112-50.144,112-112V112C512,50.144,461.856,0,400,0z"/>
<g>
<path style="fill:#FFE15A;" d="M114.021,87.182l12.722,38.146l40.21,0.312c5.206,0.04,7.365,6.684,3.177,9.777l-32.348,23.887 l12.129,38.339c1.57,4.964-4.081,9.07-8.317,6.042l-32.714-23.383l-32.714,23.383c-4.235,3.027-9.887-1.079-8.317-6.042 l12.129-38.339L47.63,135.417c-4.188-3.093-2.029-9.736,3.177-9.777l40.21-0.312l12.722-38.146 C105.388,82.243,112.374,82.243,114.021,87.182z"/>
<path style="fill:#FFE15A;" d="M260.037,96.582l9.122,12.44l14.723-4.604c1.906-0.596,3.474,1.577,2.307,3.198l-9.012,12.52 l8.928,12.58c1.156,1.629-0.427,3.791-2.329,3.183l-14.692-4.702l-9.205,12.378c-1.192,1.603-3.738,0.766-3.746-1.231 l-0.068-15.426l-14.617-4.929c-1.893-0.638-1.883-3.318,0.013-3.944l14.65-4.831l0.171-15.425 C256.305,95.791,258.856,94.971,260.037,96.582z"/>
<path style="fill:#FFE15A;" d="M204.496,59.501l15.336,1.667l6.542-13.97c0.847-1.809,3.509-1.499,3.917,0.457l3.154,15.1 l15.308,1.905c1.982,0.247,2.509,2.874,0.776,3.866l-13.387,7.665l2.919,15.147c0.378,1.961-1.958,3.275-3.437,1.933 l-11.427-10.363l-13.504,7.457c-1.748,0.965-3.719-0.85-2.901-2.672l6.324-14.07l-11.265-10.539 C201.393,61.721,202.511,59.285,204.496,59.501z"/>
<path style="fill:#FFE15A;" d="M228.739,208.997l-9.122,12.44l-14.723-4.604c-1.906-0.596-3.474,1.577-2.307,3.198l9.012,12.52 l-8.928,12.58c-1.156,1.629,0.426,3.791,2.329,3.183l14.692-4.702l9.205,12.378c1.192,1.603,3.738,0.766,3.746-1.231l0.068-15.426 l14.617-4.929c1.892-0.638,1.883-3.318-0.013-3.943l-14.65-4.831l-0.171-15.425C232.472,208.206,229.92,207.386,228.739,208.997z"/>
<path style="fill:#FFE15A;" d="M284.281,174.151l-15.336,1.667l-6.542-13.97c-0.847-1.809-3.509-1.499-3.917,0.456l-3.154,15.1 l-15.308,1.905c-1.982,0.247-2.509,2.874-0.776,3.866l13.387,7.665l-2.919,15.147c-0.378,1.961,1.958,3.275,3.437,1.933 l11.427-10.363l13.504,7.457c1.748,0.965,3.719-0.85,2.901-2.672l-6.324-14.07l11.265-10.539 C287.384,176.371,286.266,173.935,284.281,174.151z"/>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

View File

@ -74,7 +74,7 @@
},
"sprites/belt/left_3.png":
{
"frame": {"x":313,"y":112,"w":13,"h":13},
"frame": {"x":289,"y":49,"w":13,"h":13},
"rotated": false,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":13,"h":13},
@ -82,7 +82,7 @@
},
"sprites/belt/left_4.png":
{
"frame": {"x":289,"y":26,"w":13,"h":13},
"frame": {"x":306,"y":49,"w":13,"h":13},
"rotated": false,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":13,"h":13},
@ -90,7 +90,7 @@
},
"sprites/belt/left_5.png":
{
"frame": {"x":306,"y":26,"w":13,"h":13},
"frame": {"x":323,"y":49,"w":13,"h":13},
"rotated": false,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":13,"h":13},
@ -98,7 +98,7 @@
},
"sprites/belt/right_0.png":
{
"frame": {"x":330,"y":112,"w":13,"h":13},
"frame": {"x":313,"y":112,"w":13,"h":13},
"rotated": false,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":13,"h":13},
@ -106,7 +106,7 @@
},
"sprites/belt/right_1.png":
{
"frame": {"x":347,"y":112,"w":13,"h":13},
"frame": {"x":330,"y":112,"w":13,"h":13},
"rotated": false,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":13,"h":13},
@ -114,7 +114,7 @@
},
"sprites/belt/right_2.png":
{
"frame": {"x":323,"y":26,"w":13,"h":13},
"frame": {"x":340,"y":49,"w":13,"h":13},
"rotated": false,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":13,"h":13},
@ -122,7 +122,7 @@
},
"sprites/belt/right_3.png":
{
"frame": {"x":364,"y":111,"w":13,"h":13},
"frame": {"x":347,"y":112,"w":13,"h":13},
"rotated": false,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":13,"h":13},
@ -130,7 +130,7 @@
},
"sprites/belt/right_4.png":
{
"frame": {"x":381,"y":111,"w":13,"h":13},
"frame": {"x":357,"y":49,"w":13,"h":13},
"rotated": false,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":13,"h":13},
@ -138,7 +138,7 @@
},
"sprites/belt/right_5.png":
{
"frame": {"x":340,"y":25,"w":13,"h":13},
"frame": {"x":374,"y":49,"w":13,"h":13},
"rotated": false,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":13,"h":13},
@ -146,7 +146,7 @@
},
"sprites/blueprints/belt_left.png":
{
"frame": {"x":357,"y":23,"w":13,"h":13},
"frame": {"x":391,"y":48,"w":13,"h":13},
"rotated": false,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":13,"h":13},
@ -154,7 +154,7 @@
},
"sprites/blueprints/belt_right.png":
{
"frame": {"x":374,"y":23,"w":13,"h":13},
"frame": {"x":404,"y":25,"w":13,"h":13},
"rotated": false,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":13,"h":13},
@ -162,7 +162,7 @@
},
"sprites/blueprints/belt_top.png":
{
"frame": {"x":391,"y":23,"w":13,"h":13},
"frame": {"x":400,"y":85,"w":13,"h":13},
"rotated": false,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":13,"h":13},
@ -178,7 +178,7 @@
},
"sprites/blueprints/cutter.png":
{
"frame": {"x":207,"y":43,"w":36,"h":19},
"frame": {"x":245,"y":66,"w":36,"h":19},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":1,"y":0,"w":36,"h":19},
@ -186,7 +186,7 @@
},
"sprites/blueprints/miner-chainable.png":
{
"frame": {"x":285,"y":3,"w":19,"h":19},
"frame": {"x":285,"y":66,"w":19,"h":19},
"rotated": false,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":19,"h":19},
@ -194,7 +194,7 @@
},
"sprites/blueprints/miner.png":
{
"frame": {"x":245,"y":89,"w":19,"h":19},
"frame": {"x":285,"y":89,"w":19,"h":19},
"rotated": false,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":19,"h":19},
@ -202,7 +202,7 @@
},
"sprites/blueprints/mixer.png":
{
"frame": {"x":166,"y":45,"w":37,"h":19},
"frame": {"x":204,"y":68,"w":37,"h":19},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":0,"y":0,"w":37,"h":19},
@ -216,6 +216,14 @@
"spriteSourceSize": {"x":0,"y":0,"w":38,"h":38},
"sourceSize": {"w":38,"h":38}
},
"sprites/blueprints/painter-mirrored.png":
{
"frame": {"x":82,"y":49,"w":38,"h":19},
"rotated": false,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":38,"h":19},
"sourceSize": {"w":38,"h":19}
},
"sprites/blueprints/painter-quad.png":
{
"frame": {"x":3,"y":83,"w":77,"h":19},
@ -226,7 +234,7 @@
},
"sprites/blueprints/painter.png":
{
"frame": {"x":82,"y":49,"w":38,"h":19},
"frame": {"x":124,"y":49,"w":38,"h":19},
"rotated": false,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":38,"h":19},
@ -234,7 +242,7 @@
},
"sprites/blueprints/rotater-ccw.png":
{
"frame": {"x":268,"y":89,"w":19,"h":19},
"frame": {"x":289,"y":26,"w":19,"h":19},
"rotated": false,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":19,"h":19},
@ -242,7 +250,7 @@
},
"sprites/blueprints/rotater.png":
{
"frame": {"x":285,"y":66,"w":19,"h":19},
"frame": {"x":312,"y":26,"w":19,"h":19},
"rotated": false,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":19,"h":19},
@ -250,7 +258,7 @@
},
"sprites/blueprints/splitter-compact-inverse.png":
{
"frame": {"x":291,"y":89,"w":19,"h":19},
"frame": {"x":327,"y":3,"w":19,"h":19},
"rotated": false,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":19,"h":19},
@ -258,7 +266,7 @@
},
"sprites/blueprints/splitter-compact.png":
{
"frame": {"x":287,"y":43,"w":19,"h":19},
"frame": {"x":308,"y":66,"w":19,"h":19},
"rotated": false,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":19,"h":19},
@ -266,7 +274,7 @@
},
"sprites/blueprints/splitter.png":
{
"frame": {"x":245,"y":3,"w":36,"h":19},
"frame": {"x":249,"y":43,"w":36,"h":19},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":1,"y":0,"w":36,"h":19},
@ -274,7 +282,7 @@
},
"sprites/blueprints/stacker.png":
{
"frame": {"x":204,"y":3,"w":37,"h":19},
"frame": {"x":204,"y":91,"w":37,"h":19},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":0,"y":0,"w":37,"h":19},
@ -290,7 +298,7 @@
},
"sprites/blueprints/trash.png":
{
"frame": {"x":308,"y":66,"w":19,"h":19},
"frame": {"x":335,"y":26,"w":19,"h":19},
"rotated": false,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":19,"h":19},
@ -298,7 +306,7 @@
},
"sprites/blueprints/underground_belt_entry-tier2.png":
{
"frame": {"x":360,"y":89,"w":19,"h":18},
"frame": {"x":381,"y":26,"w":19,"h":18},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":0,"y":1,"w":19,"h":18},
@ -306,7 +314,7 @@
},
"sprites/blueprints/underground_belt_entry.png":
{
"frame": {"x":354,"y":3,"w":19,"h":16},
"frame": {"x":354,"y":89,"w":19,"h":16},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":0,"y":3,"w":19,"h":16},
@ -314,7 +322,7 @@
},
"sprites/blueprints/underground_belt_exit-tier2.png":
{
"frame": {"x":356,"y":42,"w":19,"h":16},
"frame": {"x":364,"y":109,"w":19,"h":16},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":0,"y":0,"w":19,"h":16},
@ -322,7 +330,7 @@
},
"sprites/blueprints/underground_belt_exit.png":
{
"frame": {"x":377,"y":62,"w":19,"h":16},
"frame": {"x":377,"y":66,"w":19,"h":16},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":0,"y":0,"w":19,"h":16},
@ -338,7 +346,7 @@
},
"sprites/buildings/belt_right.png":
{
"frame": {"x":330,"y":112,"w":13,"h":13},
"frame": {"x":313,"y":112,"w":13,"h":13},
"rotated": false,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":13,"h":13},
@ -362,7 +370,7 @@
},
"sprites/buildings/cutter.png":
{
"frame": {"x":245,"y":66,"w":36,"h":19},
"frame": {"x":287,"y":3,"w":36,"h":19},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":1,"y":0,"w":36,"h":19},
@ -378,7 +386,7 @@
},
"sprites/buildings/miner-chainable.png":
{
"frame": {"x":314,"y":89,"w":19,"h":19},
"frame": {"x":350,"y":3,"w":19,"h":19},
"rotated": false,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":19,"h":19},
@ -386,7 +394,7 @@
},
"sprites/buildings/miner.png":
{
"frame": {"x":310,"y":43,"w":19,"h":19},
"frame": {"x":308,"y":89,"w":19,"h":19},
"rotated": false,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":19,"h":19},
@ -394,7 +402,7 @@
},
"sprites/buildings/mixer.png":
{
"frame": {"x":204,"y":68,"w":37,"h":19},
"frame": {"x":208,"y":43,"w":37,"h":19},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":0,"y":0,"w":37,"h":19},
@ -408,6 +416,14 @@
"spriteSourceSize": {"x":0,"y":0,"w":38,"h":38},
"sourceSize": {"w":38,"h":38}
},
"sprites/buildings/painter-mirrored.png":
{
"frame": {"x":166,"y":45,"w":38,"h":19},
"rotated": false,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":38,"h":19},
"sourceSize": {"w":38,"h":19}
},
"sprites/buildings/painter-quad.png":
{
"frame": {"x":3,"y":106,"w":77,"h":19},
@ -418,7 +434,7 @@
},
"sprites/buildings/painter.png":
{
"frame": {"x":124,"y":49,"w":38,"h":19},
"frame": {"x":204,"y":3,"w":38,"h":19},
"rotated": false,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":38,"h":19},
@ -434,7 +450,7 @@
},
"sprites/buildings/rotater.png":
{
"frame": {"x":337,"y":89,"w":19,"h":19},
"frame": {"x":331,"y":89,"w":19,"h":19},
"rotated": false,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":19,"h":19},
@ -442,7 +458,7 @@
},
"sprites/buildings/splitter-compact-inverse.png":
{
"frame": {"x":308,"y":3,"w":19,"h":19},
"frame": {"x":354,"y":66,"w":19,"h":19},
"rotated": false,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":19,"h":19},
@ -450,7 +466,7 @@
},
"sprites/buildings/splitter-compact.png":
{
"frame": {"x":333,"y":43,"w":19,"h":19},
"frame": {"x":358,"y":26,"w":19,"h":19},
"rotated": false,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":19,"h":19},
@ -458,7 +474,7 @@
},
"sprites/buildings/splitter.png":
{
"frame": {"x":247,"y":43,"w":36,"h":19},
"frame": {"x":245,"y":89,"w":36,"h":19},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":1,"y":0,"w":36,"h":19},
@ -466,7 +482,7 @@
},
"sprites/buildings/stacker.png":
{
"frame": {"x":204,"y":91,"w":37,"h":19},
"frame": {"x":246,"y":3,"w":37,"h":19},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":0,"y":0,"w":37,"h":19},
@ -482,7 +498,7 @@
},
"sprites/buildings/trash.png":
{
"frame": {"x":354,"y":66,"w":19,"h":19},
"frame": {"x":373,"y":3,"w":19,"h":19},
"rotated": false,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":19,"h":19},
@ -490,7 +506,7 @@
},
"sprites/buildings/underground_belt_entry-tier2.png":
{
"frame": {"x":331,"y":3,"w":19,"h":18},
"frame": {"x":396,"y":3,"w":19,"h":18},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":0,"y":1,"w":19,"h":18},
@ -498,7 +514,7 @@
},
"sprites/buildings/underground_belt_entry.png":
{
"frame": {"x":383,"y":82,"w":19,"h":16},
"frame": {"x":377,"y":86,"w":19,"h":16},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":0,"y":3,"w":19,"h":16},
@ -506,7 +522,7 @@
},
"sprites/buildings/underground_belt_exit-tier2.png":
{
"frame": {"x":377,"y":3,"w":19,"h":16},
"frame": {"x":387,"y":106,"w":19,"h":16},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":0,"y":0,"w":19,"h":16},
@ -514,7 +530,7 @@
},
"sprites/buildings/underground_belt_exit.png":
{
"frame": {"x":379,"y":40,"w":19,"h":16},
"frame": {"x":400,"y":65,"w":19,"h":16},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":0,"y":0,"w":19,"h":16},
@ -538,7 +554,7 @@
},
"sprites/map_overview/belt_forward.png":
{
"frame": {"x":102,"y":72,"w":3,"h":3},
"frame": {"x":111,"y":72,"w":3,"h":3},
"rotated": false,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":3,"h":3},
@ -546,7 +562,7 @@
},
"sprites/map_overview/belt_left.png":
{
"frame": {"x":109,"y":72,"w":3,"h":3},
"frame": {"x":118,"y":72,"w":3,"h":3},
"rotated": false,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":3,"h":3},
@ -554,7 +570,7 @@
},
"sprites/map_overview/belt_right.png":
{
"frame": {"x":116,"y":72,"w":3,"h":3},
"frame": {"x":125,"y":72,"w":3,"h":3},
"rotated": false,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":3,"h":3},
@ -568,6 +584,22 @@
"spriteSourceSize": {"x":0,"y":0,"w":10,"h":10},
"sourceSize": {"w":10,"h":10}
},
"sprites/misc/hub_direction_indicator.png":
{
"frame": {"x":132,"y":72,"w":3,"h":3},
"rotated": false,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":3,"h":3},
"sourceSize": {"w":3,"h":3}
},
"sprites/misc/lock_direction_indicator.png":
{
"frame": {"x":102,"y":72,"w":5,"h":5},
"rotated": false,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":5,"h":5},
"sourceSize": {"w":5,"h":5}
},
"sprites/misc/slot_bad_arrow.png":
{
"frame": {"x":187,"y":114,"w":10,"h":10},
@ -594,7 +626,7 @@
},
"sprites/misc/waypoint.png":
{
"frame": {"x":123,"y":72,"w":3,"h":3},
"frame": {"x":139,"y":72,"w":3,"h":3},
"rotated": false,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":3,"h":3},
@ -605,8 +637,8 @@
"version": "1.0",
"image": "atlas0_10.png",
"format": "RGBA8888",
"size": {"w":407,"h":128},
"size": {"w":422,"h":128},
"scale": "0.1",
"smartupdate": "$TexturePacker:SmartUpdate:3dd7a89f30024dd4787ad4af6b14588a:9ba11f8b02134c4376ab4e0a44f8b850:f159918d23e5952766c6d23ab52278c6$"
"smartupdate": "$TexturePacker:SmartUpdate:8985524bba1a3f16cecab3c03b6aaa06:d614d20bfce033d8a8ab0990af085d16:f159918d23e5952766c6d23ab52278c6$"
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 50 KiB

After

Width:  |  Height:  |  Size: 52 KiB

View File

@ -2,7 +2,7 @@
"sprites/belt/forward_0.png":
{
"frame": {"x":1871,"y":1504,"w":100,"h":126},
"frame": {"x":1876,"y":1166,"w":100,"h":126},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":13,"y":0,"w":100,"h":126},
@ -10,7 +10,7 @@
},
"sprites/belt/forward_1.png":
{
"frame": {"x":1871,"y":240,"w":100,"h":126},
"frame": {"x":1876,"y":1296,"w":100,"h":126},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":13,"y":0,"w":100,"h":126},
@ -18,7 +18,7 @@
},
"sprites/belt/forward_2.png":
{
"frame": {"x":1844,"y":394,"w":100,"h":126},
"frame": {"x":1869,"y":1543,"w":100,"h":126},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":13,"y":0,"w":100,"h":126},
@ -26,7 +26,7 @@
},
"sprites/belt/forward_3.png":
{
"frame": {"x":1871,"y":1634,"w":100,"h":126},
"frame": {"x":1857,"y":395,"w":100,"h":126},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":13,"y":0,"w":100,"h":126},
@ -34,7 +34,7 @@
},
"sprites/belt/forward_4.png":
{
"frame": {"x":1433,"y":785,"w":100,"h":126},
"frame": {"x":1865,"y":1690,"w":100,"h":126},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":13,"y":0,"w":100,"h":126},
@ -42,7 +42,7 @@
},
"sprites/belt/forward_5.png":
{
"frame": {"x":917,"y":1564,"w":100,"h":126},
"frame": {"x":920,"y":1370,"w":100,"h":126},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":13,"y":0,"w":100,"h":126},
@ -50,7 +50,7 @@
},
"sprites/belt/left_0.png":
{
"frame": {"x":1021,"y":1563,"w":113,"h":113},
"frame": {"x":1870,"y":1426,"w":113,"h":113},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":0,"y":13,"w":113,"h":113},
@ -58,7 +58,7 @@
},
"sprites/belt/left_1.png":
{
"frame": {"x":1138,"y":1563,"w":113,"h":113},
"frame": {"x":920,"y":1500,"w":113,"h":113},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":0,"y":13,"w":113,"h":113},
@ -66,7 +66,7 @@
},
"sprites/belt/left_2.png":
{
"frame": {"x":1255,"y":1563,"w":113,"h":113},
"frame": {"x":935,"y":1617,"w":113,"h":113},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":0,"y":13,"w":113,"h":113},
@ -74,7 +74,7 @@
},
"sprites/belt/left_3.png":
{
"frame": {"x":1372,"y":1562,"w":113,"h":113},
"frame": {"x":935,"y":1734,"w":113,"h":113},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":0,"y":13,"w":113,"h":113},
@ -82,7 +82,7 @@
},
"sprites/belt/left_4.png":
{
"frame": {"x":1489,"y":1562,"w":113,"h":113},
"frame": {"x":1052,"y":1721,"w":113,"h":113},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":0,"y":13,"w":113,"h":113},
@ -90,7 +90,7 @@
},
"sprites/belt/left_5.png":
{
"frame": {"x":1021,"y":1680,"w":113,"h":113},
"frame": {"x":1169,"y":1721,"w":113,"h":113},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":0,"y":13,"w":113,"h":113},
@ -98,7 +98,7 @@
},
"sprites/belt/right_0.png":
{
"frame": {"x":1138,"y":1680,"w":113,"h":113},
"frame": {"x":1286,"y":1721,"w":113,"h":113},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":13,"y":13,"w":113,"h":113},
@ -106,7 +106,7 @@
},
"sprites/belt/right_1.png":
{
"frame": {"x":1255,"y":1680,"w":113,"h":113},
"frame": {"x":1403,"y":1721,"w":113,"h":113},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":13,"y":13,"w":113,"h":113},
@ -114,7 +114,7 @@
},
"sprites/belt/right_2.png":
{
"frame": {"x":1372,"y":1679,"w":113,"h":113},
"frame": {"x":1520,"y":1721,"w":113,"h":113},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":13,"y":13,"w":113,"h":113},
@ -122,7 +122,7 @@
},
"sprites/belt/right_3.png":
{
"frame": {"x":1489,"y":1679,"w":113,"h":113},
"frame": {"x":1052,"y":1552,"w":113,"h":113},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":13,"y":13,"w":113,"h":113},
@ -130,7 +130,7 @@
},
"sprites/belt/right_4.png":
{
"frame": {"x":1606,"y":1676,"w":113,"h":113},
"frame": {"x":1169,"y":1552,"w":113,"h":113},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":13,"y":13,"w":113,"h":113},
@ -138,7 +138,7 @@
},
"sprites/belt/right_5.png":
{
"frame": {"x":1723,"y":1676,"w":113,"h":113},
"frame": {"x":1286,"y":1554,"w":113,"h":113},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":13,"y":13,"w":113,"h":113},
@ -162,7 +162,7 @@
},
"sprites/blueprints/belt_top.png":
{
"frame": {"x":1871,"y":1374,"w":102,"h":126},
"frame": {"x":1871,"y":240,"w":102,"h":126},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":12,"y":0,"w":102,"h":126},
@ -178,7 +178,7 @@
},
"sprites/blueprints/cutter.png":
{
"frame": {"x":726,"y":979,"w":341,"h":191},
"frame": {"x":1433,"y":785,"w":341,"h":191},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":23,"y":0,"w":341,"h":191},
@ -186,7 +186,7 @@
},
"sprites/blueprints/miner-chainable.png":
{
"frame": {"x":1500,"y":1368,"w":182,"h":190},
"frame": {"x":749,"y":1655,"w":182,"h":190},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":6,"y":0,"w":182,"h":190},
@ -194,7 +194,7 @@
},
"sprites/blueprints/miner.png":
{
"frame": {"x":1437,"y":590,"w":182,"h":190},
"frame": {"x":1690,"y":1174,"w":182,"h":190},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":6,"y":0,"w":182,"h":190},
@ -202,7 +202,7 @@
},
"sprites/blueprints/mixer.png":
{
"frame": {"x":735,"y":590,"w":347,"h":191},
"frame": {"x":1123,"y":590,"w":347,"h":191},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":18,"y":0,"w":347,"h":191},
@ -216,6 +216,14 @@
"spriteSourceSize": {"x":0,"y":0,"w":384,"h":382},
"sourceSize": {"w":384,"h":384}
},
"sprites/blueprints/painter-mirrored.png":
{
"frame": {"x":1485,"y":3,"w":384,"h":192},
"rotated": false,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":384,"h":192},
"sourceSize": {"w":384,"h":192}
},
"sprites/blueprints/painter-quad.png":
{
"frame": {"x":735,"y":3,"w":746,"h":192},
@ -226,7 +234,7 @@
},
"sprites/blueprints/painter.png":
{
"frame": {"x":1485,"y":3,"w":384,"h":192},
"frame": {"x":1483,"y":199,"w":384,"h":192},
"rotated": false,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":384,"h":192},
@ -234,7 +242,7 @@
},
"sprites/blueprints/rotater-ccw.png":
{
"frame": {"x":1116,"y":1368,"w":189,"h":191},
"frame": {"x":922,"y":1174,"w":189,"h":191},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":2,"y":0,"w":189,"h":191},
@ -242,7 +250,7 @@
},
"sprites/blueprints/rotater.png":
{
"frame": {"x":724,"y":1564,"w":189,"h":191},
"frame": {"x":1115,"y":1173,"w":189,"h":191},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":2,"y":0,"w":189,"h":191},
@ -250,7 +258,7 @@
},
"sprites/blueprints/splitter-compact-inverse.png":
{
"frame": {"x":1652,"y":394,"w":188,"h":182},
"frame": {"x":1756,"y":980,"w":188,"h":182},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":0,"y":4,"w":188,"h":182},
@ -258,7 +266,7 @@
},
"sprites/blueprints/splitter-compact.png":
{
"frame": {"x":1623,"y":587,"w":185,"h":182},
"frame": {"x":1306,"y":1368,"w":185,"h":182},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":7,"y":4,"w":185,"h":182},
@ -266,7 +274,7 @@
},
"sprites/blueprints/splitter.png":
{
"frame": {"x":1071,"y":979,"w":340,"h":191},
"frame": {"x":726,"y":979,"w":340,"h":191},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":23,"y":0,"w":340,"h":191},
@ -274,7 +282,7 @@
},
"sprites/blueprints/stacker.png":
{
"frame": {"x":1086,"y":590,"w":347,"h":191},
"frame": {"x":1474,"y":590,"w":347,"h":191},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":18,"y":0,"w":347,"h":191},
@ -290,7 +298,7 @@
},
"sprites/blueprints/trash.png":
{
"frame": {"x":724,"y":1368,"w":192,"h":192},
"frame": {"x":726,"y":1174,"w":192,"h":192},
"rotated": false,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":192,"h":192},
@ -298,7 +306,7 @@
},
"sprites/blueprints/underground_belt_entry-tier2.png":
{
"frame": {"x":1791,"y":1035,"w":183,"h":166},
"frame": {"x":1683,"y":1368,"w":183,"h":166},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":5,"y":26,"w":183,"h":166},
@ -306,7 +314,7 @@
},
"sprites/blueprints/underground_belt_entry.png":
{
"frame": {"x":1812,"y":580,"w":182,"h":148},
"frame": {"x":192,"y":1702,"w":182,"h":148},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":6,"y":44,"w":182,"h":148},
@ -314,7 +322,7 @@
},
"sprites/blueprints/underground_belt_exit-tier2.png":
{
"frame": {"x":1623,"y":773,"w":185,"h":148},
"frame": {"x":3,"y":1702,"w":185,"h":148},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":5,"y":0,"w":185,"h":148},
@ -322,7 +330,7 @@
},
"sprites/blueprints/underground_belt_exit.png":
{
"frame": {"x":1812,"y":732,"w":182,"h":148},
"frame": {"x":1683,"y":1538,"w":182,"h":148},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":6,"y":0,"w":182,"h":148},
@ -330,7 +338,7 @@
},
"sprites/buildings/belt_left.png":
{
"frame": {"x":1021,"y":1563,"w":113,"h":113},
"frame": {"x":1870,"y":1426,"w":113,"h":113},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":0,"y":13,"w":113,"h":113},
@ -338,7 +346,7 @@
},
"sprites/buildings/belt_right.png":
{
"frame": {"x":1138,"y":1680,"w":113,"h":113},
"frame": {"x":1286,"y":1721,"w":113,"h":113},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":13,"y":13,"w":113,"h":113},
@ -346,7 +354,7 @@
},
"sprites/buildings/belt_top.png":
{
"frame": {"x":1871,"y":1504,"w":100,"h":126},
"frame": {"x":1876,"y":1166,"w":100,"h":126},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":13,"y":0,"w":100,"h":126},
@ -362,7 +370,7 @@
},
"sprites/buildings/cutter.png":
{
"frame": {"x":726,"y":1174,"w":339,"h":190},
"frame": {"x":1070,"y":979,"w":339,"h":190},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":24,"y":0,"w":339,"h":190},
@ -378,7 +386,7 @@
},
"sprites/buildings/miner-chainable.png":
{
"frame": {"x":1469,"y":395,"w":179,"h":188},
"frame": {"x":1825,"y":590,"w":179,"h":188},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":8,"y":1,"w":179,"h":188},
@ -386,7 +394,7 @@
},
"sprites/buildings/miner.png":
{
"frame": {"x":1415,"y":979,"w":179,"h":189},
"frame": {"x":1778,"y":785,"w":179,"h":189},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":8,"y":0,"w":179,"h":189},
@ -408,6 +416,14 @@
"spriteSourceSize": {"x":0,"y":0,"w":384,"h":381},
"sourceSize": {"w":384,"h":384}
},
"sprites/buildings/painter-mirrored.png":
{
"frame": {"x":735,"y":590,"w":384,"h":191},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":0,"y":0,"w":384,"h":191},
"sourceSize": {"w":384,"h":192}
},
"sprites/buildings/painter-quad.png":
{
"frame": {"x":735,"y":199,"w":744,"h":192},
@ -418,7 +434,7 @@
},
"sprites/buildings/painter.png":
{
"frame": {"x":1483,"y":199,"w":384,"h":191},
"frame": {"x":1469,"y":395,"w":384,"h":191},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":0,"y":0,"w":384,"h":191},
@ -426,7 +442,7 @@
},
"sprites/buildings/rotater-ccw.png":
{
"frame": {"x":1309,"y":1368,"w":187,"h":190},
"frame": {"x":1308,"y":1174,"w":187,"h":190},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":3,"y":0,"w":187,"h":190},
@ -434,7 +450,7 @@
},
"sprites/buildings/rotater.png":
{
"frame": {"x":1412,"y":1174,"w":187,"h":190},
"frame": {"x":1499,"y":1174,"w":187,"h":190},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":3,"y":0,"w":187,"h":190},
@ -442,7 +458,7 @@
},
"sprites/buildings/splitter-compact-inverse.png":
{
"frame": {"x":1598,"y":925,"w":187,"h":180},
"frame": {"x":1115,"y":1368,"w":187,"h":180},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":0,"y":5,"w":187,"h":180},
@ -450,7 +466,7 @@
},
"sprites/buildings/splitter-compact.png":
{
"frame": {"x":1603,"y":1109,"w":184,"h":180},
"frame": {"x":1495,"y":1368,"w":184,"h":180},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":8,"y":5,"w":184,"h":180},
@ -458,7 +474,7 @@
},
"sprites/buildings/splitter.png":
{
"frame": {"x":1069,"y":1174,"w":339,"h":190},
"frame": {"x":1413,"y":980,"w":339,"h":190},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":24,"y":0,"w":339,"h":190},
@ -482,7 +498,7 @@
},
"sprites/buildings/trash.png":
{
"frame": {"x":920,"y":1368,"w":192,"h":191},
"frame": {"x":724,"y":1370,"w":192,"h":191},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":0,"y":1,"w":192,"h":191},
@ -490,7 +506,7 @@
},
"sprites/buildings/underground_belt_entry-tier2.png":
{
"frame": {"x":1791,"y":1205,"w":181,"h":165},
"frame": {"x":1495,"y":1552,"w":181,"h":165},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":7,"y":27,"w":181,"h":165},
@ -498,7 +514,7 @@
},
"sprites/buildings/underground_belt_entry.png":
{
"frame": {"x":1686,"y":1374,"w":181,"h":147},
"frame": {"x":564,"y":1707,"w":181,"h":147},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":7,"y":45,"w":181,"h":147},
@ -506,7 +522,7 @@
},
"sprites/buildings/underground_belt_exit-tier2.png":
{
"frame": {"x":1812,"y":884,"w":182,"h":147},
"frame": {"x":378,"y":1707,"w":182,"h":147},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":7,"y":0,"w":182,"h":147},
@ -514,7 +530,7 @@
},
"sprites/buildings/underground_belt_exit.png":
{
"frame": {"x":1686,"y":1525,"w":181,"h":147},
"frame": {"x":1680,"y":1690,"w":181,"h":147},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":7,"y":0,"w":181,"h":147},
@ -522,7 +538,7 @@
},
"sprites/debug/acceptor_slot.png":
{
"frame": {"x":1603,"y":1293,"w":50,"h":64},
"frame": {"x":1961,"y":782,"w":50,"h":64},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":7,"y":0,"w":50,"h":64},
@ -530,7 +546,7 @@
},
"sprites/debug/ejector_slot.png":
{
"frame": {"x":1606,"y":1562,"w":50,"h":64},
"frame": {"x":1961,"y":850,"w":50,"h":64},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":7,"y":0,"w":50,"h":64},
@ -538,7 +554,7 @@
},
"sprites/map_overview/belt_forward.png":
{
"frame": {"x":353,"y":1702,"w":24,"h":32},
"frame": {"x":1637,"y":1721,"w":24,"h":32},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":4,"y":0,"w":24,"h":32},
@ -546,7 +562,7 @@
},
"sprites/map_overview/belt_left.png":
{
"frame": {"x":1433,"y":915,"w":28,"h":28},
"frame": {"x":1893,"y":525,"w":28,"h":28},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":0,"y":4,"w":28,"h":28},
@ -554,7 +570,7 @@
},
"sprites/map_overview/belt_right.png":
{
"frame": {"x":1433,"y":947,"w":28,"h":28},
"frame": {"x":1080,"y":1669,"w":28,"h":28},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":4,"y":4,"w":28,"h":28},
@ -562,15 +578,31 @@
},
"sprites/misc/deletion_marker.png":
{
"frame": {"x":267,"y":1702,"w":82,"h":82},
"frame": {"x":1403,"y":1554,"w":82,"h":82},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":7,"y":7,"w":82,"h":82},
"sourceSize": {"w":96,"h":96}
},
"sprites/misc/hub_direction_indicator.png":
{
"frame": {"x":1857,"y":525,"w":32,"h":32},
"rotated": false,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
"sourceSize": {"w":32,"h":32}
},
"sprites/misc/lock_direction_indicator.png":
{
"frame": {"x":1961,"y":918,"w":48,"h":30},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":0,"y":9,"w":48,"h":30},
"sourceSize": {"w":48,"h":48}
},
"sprites/misc/slot_bad_arrow.png":
{
"frame": {"x":267,"y":1702,"w":82,"h":82},
"frame": {"x":1403,"y":1554,"w":82,"h":82},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":7,"y":7,"w":82,"h":82},
@ -578,7 +610,7 @@
},
"sprites/misc/slot_good_arrow.png":
{
"frame": {"x":183,"y":1702,"w":80,"h":96},
"frame": {"x":1024,"y":1369,"w":80,"h":96},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":8,"y":0,"w":80,"h":96},
@ -586,7 +618,7 @@
},
"sprites/misc/storage_overlay.png":
{
"frame": {"x":3,"y":1702,"w":176,"h":86},
"frame": {"x":724,"y":1565,"w":176,"h":86},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":3,"y":4,"w":176,"h":86},
@ -594,7 +626,7 @@
},
"sprites/misc/waypoint.png":
{
"frame": {"x":1844,"y":524,"w":24,"h":32},
"frame": {"x":1052,"y":1669,"w":24,"h":32},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":4,"y":0,"w":24,"h":32},
@ -605,8 +637,8 @@
"version": "1.0",
"image": "atlas0_100.png",
"format": "RGBA8888",
"size": {"w":1997,"h":1801},
"size": {"w":2014,"h":1857},
"scale": "1",
"smartupdate": "$TexturePacker:SmartUpdate:3dd7a89f30024dd4787ad4af6b14588a:9ba11f8b02134c4376ab4e0a44f8b850:f159918d23e5952766c6d23ab52278c6$"
"smartupdate": "$TexturePacker:SmartUpdate:8985524bba1a3f16cecab3c03b6aaa06:d614d20bfce033d8a8ab0990af085d16:f159918d23e5952766c6d23ab52278c6$"
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 743 KiB

After

Width:  |  Height:  |  Size: 776 KiB

View File

@ -2,7 +2,7 @@
"sprites/belt/forward_0.png":
{
"frame": {"x":479,"y":103,"w":28,"h":32},
"frame": {"x":3,"y":1010,"w":28,"h":32},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":2,"y":0,"w":28,"h":32},
@ -10,7 +10,7 @@
},
"sprites/belt/forward_1.png":
{
"frame": {"x":479,"y":139,"w":28,"h":32},
"frame": {"x":3,"y":967,"w":28,"h":32},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":2,"y":0,"w":28,"h":32},
@ -18,7 +18,7 @@
},
"sprites/belt/forward_2.png":
{
"frame": {"x":479,"y":175,"w":28,"h":32},
"frame": {"x":3,"y":1046,"w":28,"h":32},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":2,"y":0,"w":28,"h":32},
@ -26,7 +26,7 @@
},
"sprites/belt/forward_3.png":
{
"frame": {"x":262,"y":331,"w":28,"h":32},
"frame": {"x":35,"y":1044,"w":28,"h":32},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":2,"y":0,"w":28,"h":32},
@ -34,7 +34,7 @@
},
"sprites/belt/forward_4.png":
{
"frame": {"x":285,"y":383,"w":28,"h":32},
"frame": {"x":67,"y":1044,"w":28,"h":32},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":2,"y":0,"w":28,"h":32},
@ -42,7 +42,7 @@
},
"sprites/belt/forward_5.png":
{
"frame": {"x":317,"y":383,"w":28,"h":32},
"frame": {"x":133,"y":1053,"w":28,"h":32},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":2,"y":0,"w":28,"h":32},
@ -50,7 +50,7 @@
},
"sprites/belt/left_0.png":
{
"frame": {"x":343,"y":159,"w":30,"h":30},
"frame": {"x":143,"y":883,"w":30,"h":30},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":0,"y":2,"w":30,"h":30},
@ -58,7 +58,7 @@
},
"sprites/belt/left_1.png":
{
"frame": {"x":343,"y":193,"w":30,"h":30},
"frame": {"x":143,"y":917,"w":30,"h":30},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":0,"y":2,"w":30,"h":30},
@ -66,7 +66,7 @@
},
"sprites/belt/left_2.png":
{
"frame": {"x":477,"y":211,"w":30,"h":30},
"frame": {"x":143,"y":951,"w":30,"h":30},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":0,"y":2,"w":30,"h":30},
@ -74,7 +74,7 @@
},
"sprites/belt/left_3.png":
{
"frame": {"x":477,"y":245,"w":30,"h":30},
"frame": {"x":35,"y":960,"w":30,"h":30},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":0,"y":2,"w":30,"h":30},
@ -82,7 +82,7 @@
},
"sprites/belt/left_4.png":
{
"frame": {"x":469,"y":279,"w":30,"h":30},
"frame": {"x":69,"y":967,"w":30,"h":30},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":0,"y":2,"w":30,"h":30},
@ -90,7 +90,7 @@
},
"sprites/belt/left_5.png":
{
"frame": {"x":3,"y":331,"w":30,"h":30},
"frame": {"x":35,"y":994,"w":30,"h":30},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":0,"y":2,"w":30,"h":30},
@ -98,7 +98,7 @@
},
"sprites/belt/right_0.png":
{
"frame": {"x":37,"y":331,"w":30,"h":30},
"frame": {"x":103,"y":967,"w":30,"h":30},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":2,"y":2,"w":30,"h":30},
@ -106,7 +106,7 @@
},
"sprites/belt/right_1.png":
{
"frame": {"x":71,"y":331,"w":30,"h":30},
"frame": {"x":137,"y":985,"w":30,"h":30},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":2,"y":2,"w":30,"h":30},
@ -114,7 +114,7 @@
},
"sprites/belt/right_2.png":
{
"frame": {"x":3,"y":296,"w":30,"h":30},
"frame": {"x":171,"y":997,"w":30,"h":30},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":2,"y":2,"w":30,"h":30},
@ -122,7 +122,7 @@
},
"sprites/belt/right_3.png":
{
"frame": {"x":37,"y":296,"w":30,"h":30},
"frame": {"x":205,"y":1010,"w":30,"h":30},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":2,"y":2,"w":30,"h":30},
@ -130,7 +130,7 @@
},
"sprites/belt/right_4.png":
{
"frame": {"x":71,"y":296,"w":30,"h":30},
"frame": {"x":99,"y":1001,"w":30,"h":30},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":2,"y":2,"w":30,"h":30},
@ -138,7 +138,7 @@
},
"sprites/belt/right_5.png":
{
"frame": {"x":105,"y":331,"w":30,"h":30},
"frame": {"x":133,"y":1019,"w":30,"h":30},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":2,"y":2,"w":30,"h":30},
@ -146,7 +146,7 @@
},
"sprites/blueprints/belt_left.png":
{
"frame": {"x":139,"y":331,"w":30,"h":30},
"frame": {"x":99,"y":1035,"w":30,"h":30},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":0,"y":2,"w":30,"h":30},
@ -154,7 +154,7 @@
},
"sprites/blueprints/belt_right.png":
{
"frame": {"x":173,"y":331,"w":30,"h":30},
"frame": {"x":167,"y":1031,"w":30,"h":30},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":2,"y":2,"w":30,"h":30},
@ -162,7 +162,7 @@
},
"sprites/blueprints/belt_top.png":
{
"frame": {"x":467,"y":416,"w":28,"h":32},
"frame": {"x":201,"y":1044,"w":28,"h":32},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":2,"y":0,"w":28,"h":32},
@ -170,7 +170,7 @@
},
"sprites/blueprints/cutter-quad.png":
{
"frame": {"x":191,"y":55,"w":184,"h":48},
"frame": {"x":3,"y":296,"w":184,"h":48},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":5,"y":0,"w":184,"h":48},
@ -178,7 +178,7 @@
},
"sprites/blueprints/cutter.png":
{
"frame": {"x":95,"y":244,"w":87,"h":48},
"frame": {"x":155,"y":419,"w":87,"h":48},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":5,"y":0,"w":87,"h":48},
@ -186,7 +186,7 @@
},
"sprites/blueprints/miner-chainable.png":
{
"frame": {"x":262,"y":419,"w":47,"h":48},
"frame": {"x":195,"y":3,"w":47,"h":48},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":1,"y":0,"w":47,"h":48},
@ -194,7 +194,7 @@
},
"sprites/blueprints/miner.png":
{
"frame": {"x":313,"y":419,"w":47,"h":48},
"frame": {"x":195,"y":55,"w":47,"h":48},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":1,"y":0,"w":47,"h":48},
@ -202,7 +202,7 @@
},
"sprites/blueprints/mixer.png":
{
"frame": {"x":191,"y":211,"w":89,"h":48},
"frame": {"x":3,"y":808,"w":89,"h":48},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":3,"y":0,"w":89,"h":48},
@ -210,12 +210,20 @@
},
"sprites/blueprints/painter-double.png":
{
"frame": {"x":387,"y":3,"w":96,"h":96},
"frame": {"x":3,"y":400,"w":96,"h":96},
"rotated": false,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":96,"h":96},
"sourceSize": {"w":96,"h":96}
},
"sprites/blueprints/painter-mirrored.png":
{
"frame": {"x":3,"y":600,"w":96,"h":48},
"rotated": false,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":96,"h":48},
"sourceSize": {"w":96,"h":48}
},
"sprites/blueprints/painter-quad.png":
{
"frame": {"x":3,"y":3,"w":188,"h":48},
@ -226,7 +234,7 @@
},
"sprites/blueprints/painter.png":
{
"frame": {"x":191,"y":159,"w":96,"h":48},
"frame": {"x":3,"y":652,"w":96,"h":48},
"rotated": false,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":96,"h":48},
@ -234,7 +242,7 @@
},
"sprites/blueprints/rotater-ccw.png":
{
"frame": {"x":291,"y":159,"w":48,"h":48},
"frame": {"x":191,"y":107,"w":48,"h":48},
"rotated": false,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":48,"h":48},
@ -242,7 +250,7 @@
},
"sprites/blueprints/rotater.png":
{
"frame": {"x":459,"y":313,"w":48,"h":48},
"frame": {"x":191,"y":159,"w":48,"h":48},
"rotated": false,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":48,"h":48},
@ -250,7 +258,7 @@
},
"sprites/blueprints/splitter-compact-inverse.png":
{
"frame": {"x":210,"y":315,"w":48,"h":48},
"frame": {"x":191,"y":211,"w":48,"h":48},
"rotated": false,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":48,"h":48},
@ -258,7 +266,7 @@
},
"sprites/blueprints/splitter-compact.png":
{
"frame": {"x":415,"y":416,"w":47,"h":47},
"frame": {"x":103,"y":780,"w":47,"h":47},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":1,"y":0,"w":47,"h":47},
@ -266,7 +274,7 @@
},
"sprites/blueprints/splitter.png":
{
"frame": {"x":186,"y":263,"w":87,"h":48},
"frame": {"x":155,"y":471,"w":87,"h":48},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":5,"y":0,"w":87,"h":48},
@ -274,7 +282,7 @@
},
"sprites/blueprints/stacker.png":
{
"frame": {"x":284,"y":227,"w":89,"h":48},
"frame": {"x":96,"y":831,"w":89,"h":48},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":3,"y":0,"w":89,"h":48},
@ -282,7 +290,7 @@
},
"sprites/blueprints/trash-storage.png":
{
"frame": {"x":3,"y":365,"w":85,"h":96},
"frame": {"x":155,"y":627,"w":85,"h":96},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":6,"y":0,"w":85,"h":96},
@ -290,7 +298,7 @@
},
"sprites/blueprints/trash.png":
{
"frame": {"x":181,"y":391,"w":48,"h":48},
"frame": {"x":191,"y":263,"w":48,"h":48},
"rotated": false,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":48,"h":48},
@ -298,7 +306,7 @@
},
"sprites/blueprints/underground_belt_entry-tier2.png":
{
"frame": {"x":3,"y":465,"w":48,"h":43},
"frame": {"x":103,"y":503,"w":48,"h":43},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":0,"y":5,"w":48,"h":43},
@ -306,7 +314,7 @@
},
"sprites/blueprints/underground_belt_entry.png":
{
"frame": {"x":106,"y":465,"w":48,"h":38},
"frame": {"x":103,"y":550,"w":48,"h":38},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":0,"y":10,"w":48,"h":38},
@ -314,7 +322,7 @@
},
"sprites/blueprints/underground_belt_exit-tier2.png":
{
"frame": {"x":158,"y":465,"w":48,"h":38},
"frame": {"x":103,"y":592,"w":48,"h":38},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":0,"y":0,"w":48,"h":38},
@ -322,7 +330,7 @@
},
"sprites/blueprints/underground_belt_exit.png":
{
"frame": {"x":262,"y":471,"w":48,"h":38},
"frame": {"x":103,"y":634,"w":48,"h":38},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":0,"y":0,"w":48,"h":38},
@ -330,7 +338,7 @@
},
"sprites/buildings/belt_left.png":
{
"frame": {"x":343,"y":159,"w":30,"h":30},
"frame": {"x":143,"y":883,"w":30,"h":30},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":0,"y":2,"w":30,"h":30},
@ -338,7 +346,7 @@
},
"sprites/buildings/belt_right.png":
{
"frame": {"x":37,"y":331,"w":30,"h":30},
"frame": {"x":103,"y":967,"w":30,"h":30},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":2,"y":2,"w":30,"h":30},
@ -346,7 +354,7 @@
},
"sprites/buildings/belt_top.png":
{
"frame": {"x":479,"y":103,"w":28,"h":32},
"frame": {"x":3,"y":1010,"w":28,"h":32},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":2,"y":0,"w":28,"h":32},
@ -354,7 +362,7 @@
},
"sprites/buildings/cutter-quad.png":
{
"frame": {"x":191,"y":107,"w":184,"h":48},
"frame": {"x":3,"y":348,"w":184,"h":48},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":5,"y":0,"w":184,"h":48},
@ -362,7 +370,7 @@
},
"sprites/buildings/cutter.png":
{
"frame": {"x":277,"y":279,"w":87,"h":48},
"frame": {"x":155,"y":523,"w":87,"h":48},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":5,"y":0,"w":87,"h":48},
@ -370,7 +378,7 @@
},
"sprites/buildings/hub.png":
{
"frame": {"x":3,"y":55,"w":184,"h":185},
"frame": {"x":3,"y":107,"w":184,"h":185},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":4,"y":4,"w":184,"h":185},
@ -378,7 +386,7 @@
},
"sprites/buildings/miner-chainable.png":
{
"frame": {"x":349,"y":365,"w":47,"h":48},
"frame": {"x":103,"y":676,"w":47,"h":48},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":1,"y":0,"w":47,"h":48},
@ -386,7 +394,7 @@
},
"sprites/buildings/miner.png":
{
"frame": {"x":364,"y":417,"w":47,"h":48},
"frame": {"x":103,"y":728,"w":47,"h":48},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":1,"y":0,"w":47,"h":48},
@ -394,7 +402,7 @@
},
"sprites/buildings/mixer.png":
{
"frame": {"x":377,"y":255,"w":88,"h":48},
"frame": {"x":154,"y":727,"w":88,"h":48},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":4,"y":0,"w":88,"h":48},
@ -402,15 +410,23 @@
},
"sprites/buildings/painter-double.png":
{
"frame": {"x":379,"y":103,"w":96,"h":96},
"frame": {"x":3,"y":500,"w":96,"h":96},
"rotated": false,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":96,"h":96},
"sourceSize": {"w":96,"h":96}
},
"sprites/buildings/painter-mirrored.png":
{
"frame": {"x":3,"y":704,"w":96,"h":48},
"rotated": false,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":96,"h":48},
"sourceSize": {"w":96,"h":48}
},
"sprites/buildings/painter-quad.png":
{
"frame": {"x":195,"y":3,"w":188,"h":48},
"frame": {"x":3,"y":55,"w":188,"h":48},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":1,"y":0,"w":188,"h":48},
@ -418,7 +434,7 @@
},
"sprites/buildings/painter.png":
{
"frame": {"x":377,"y":203,"w":96,"h":48},
"frame": {"x":3,"y":756,"w":96,"h":48},
"rotated": false,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":96,"h":48},
@ -426,7 +442,7 @@
},
"sprites/buildings/rotater-ccw.png":
{
"frame": {"x":210,"y":443,"w":48,"h":48},
"frame": {"x":191,"y":315,"w":48,"h":48},
"rotated": false,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":48,"h":48},
@ -434,7 +450,7 @@
},
"sprites/buildings/rotater.png":
{
"frame": {"x":233,"y":367,"w":48,"h":48},
"frame": {"x":191,"y":367,"w":48,"h":48},
"rotated": false,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":48,"h":48},
@ -442,7 +458,7 @@
},
"sprites/buildings/splitter-compact-inverse.png":
{
"frame": {"x":400,"y":365,"w":48,"h":47},
"frame": {"x":103,"y":452,"w":48,"h":47},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":0,"y":0,"w":48,"h":47},
@ -450,7 +466,7 @@
},
"sprites/buildings/splitter-compact.png":
{
"frame": {"x":452,"y":365,"w":47,"h":47},
"frame": {"x":189,"y":831,"w":47,"h":47},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":1,"y":0,"w":47,"h":47},
@ -458,7 +474,7 @@
},
"sprites/buildings/splitter.png":
{
"frame": {"x":368,"y":307,"w":87,"h":48},
"frame": {"x":155,"y":575,"w":87,"h":48},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":5,"y":0,"w":87,"h":48},
@ -466,7 +482,7 @@
},
"sprites/buildings/stacker.png":
{
"frame": {"x":3,"y":244,"w":88,"h":48},
"frame": {"x":154,"y":779,"w":88,"h":48},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":4,"y":0,"w":88,"h":48},
@ -474,7 +490,7 @@
},
"sprites/buildings/trash-storage.png":
{
"frame": {"x":92,"y":365,"w":85,"h":96},
"frame": {"x":3,"y":860,"w":85,"h":96},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":6,"y":0,"w":85,"h":96},
@ -482,7 +498,7 @@
},
"sprites/buildings/trash.png":
{
"frame": {"x":294,"y":331,"w":48,"h":48},
"frame": {"x":103,"y":400,"w":48,"h":48},
"rotated": false,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":48,"h":48},
@ -490,7 +506,7 @@
},
"sprites/buildings/underground_belt_entry-tier2.png":
{
"frame": {"x":55,"y":465,"w":47,"h":42},
"frame": {"x":189,"y":882,"w":47,"h":42},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":1,"y":6,"w":47,"h":42},
@ -498,7 +514,7 @@
},
"sprites/buildings/underground_belt_entry.png":
{
"frame": {"x":314,"y":471,"w":47,"h":38},
"frame": {"x":92,"y":883,"w":47,"h":38},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":1,"y":10,"w":47,"h":38},
@ -506,7 +522,7 @@
},
"sprites/buildings/underground_belt_exit-tier2.png":
{
"frame": {"x":365,"y":469,"w":47,"h":38},
"frame": {"x":92,"y":925,"w":47,"h":38},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":1,"y":0,"w":47,"h":38},
@ -514,7 +530,7 @@
},
"sprites/buildings/underground_belt_exit.png":
{
"frame": {"x":416,"y":467,"w":47,"h":38},
"frame": {"x":189,"y":928,"w":47,"h":38},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":1,"y":0,"w":47,"h":38},
@ -522,7 +538,7 @@
},
"sprites/debug/acceptor_slot.png":
{
"frame": {"x":487,"y":3,"w":14,"h":16},
"frame": {"x":226,"y":970,"w":14,"h":16},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":1,"y":0,"w":14,"h":16},
@ -530,7 +546,7 @@
},
"sprites/debug/ejector_slot.png":
{
"frame": {"x":487,"y":23,"w":14,"h":16},
"frame": {"x":226,"y":990,"w":14,"h":16},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":1,"y":0,"w":14,"h":16},
@ -538,7 +554,7 @@
},
"sprites/map_overview/belt_forward.png":
{
"frame": {"x":487,"y":43,"w":8,"h":8},
"frame": {"x":171,"y":400,"w":8,"h":8},
"rotated": false,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":8,"h":8},
@ -546,7 +562,7 @@
},
"sprites/map_overview/belt_left.png":
{
"frame": {"x":499,"y":43,"w":8,"h":8},
"frame": {"x":177,"y":883,"w":8,"h":8},
"rotated": false,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":8,"h":8},
@ -554,7 +570,7 @@
},
"sprites/map_overview/belt_right.png":
{
"frame": {"x":487,"y":55,"w":8,"h":8},
"frame": {"x":177,"y":895,"w":8,"h":8},
"rotated": false,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":8,"h":8},
@ -562,15 +578,31 @@
},
"sprites/misc/deletion_marker.png":
{
"frame": {"x":181,"y":365,"w":22,"h":22},
"frame": {"x":165,"y":1065,"w":22,"h":22},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":1,"y":1,"w":22,"h":22},
"sourceSize": {"w":24,"h":24}
},
"sprites/misc/hub_direction_indicator.png":
{
"frame": {"x":177,"y":907,"w":8,"h":8},
"rotated": false,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":8,"h":8},
"sourceSize": {"w":8,"h":8}
},
"sprites/misc/lock_direction_indicator.png":
{
"frame": {"x":155,"y":400,"w":12,"h":10},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":0,"y":1,"w":12,"h":10},
"sourceSize": {"w":12,"h":12}
},
"sprites/misc/slot_bad_arrow.png":
{
"frame": {"x":181,"y":365,"w":22,"h":22},
"frame": {"x":165,"y":1065,"w":22,"h":22},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":1,"y":1,"w":22,"h":22},
@ -578,7 +610,7 @@
},
"sprites/misc/slot_good_arrow.png":
{
"frame": {"x":105,"y":296,"w":22,"h":24},
"frame": {"x":69,"y":1001,"w":22,"h":24},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":1,"y":0,"w":22,"h":24},
@ -586,7 +618,7 @@
},
"sprites/misc/storage_overlay.png":
{
"frame": {"x":131,"y":296,"w":45,"h":23},
"frame": {"x":177,"y":970,"w":45,"h":23},
"rotated": false,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":45,"h":23},
@ -594,7 +626,7 @@
},
"sprites/misc/waypoint.png":
{
"frame": {"x":499,"y":55,"w":8,"h":8},
"frame": {"x":177,"y":919,"w":8,"h":8},
"rotated": false,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":8,"h":8},
@ -605,8 +637,8 @@
"version": "1.0",
"image": "atlas0_25.png",
"format": "RGBA8888",
"size": {"w":510,"h":512},
"size": {"w":245,"h":1090},
"scale": "0.25",
"smartupdate": "$TexturePacker:SmartUpdate:3dd7a89f30024dd4787ad4af6b14588a:9ba11f8b02134c4376ab4e0a44f8b850:f159918d23e5952766c6d23ab52278c6$"
"smartupdate": "$TexturePacker:SmartUpdate:8985524bba1a3f16cecab3c03b6aaa06:d614d20bfce033d8a8ab0990af085d16:f159918d23e5952766c6d23ab52278c6$"
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 160 KiB

After

Width:  |  Height:  |  Size: 166 KiB

View File

@ -2,7 +2,7 @@
"sprites/belt/forward_0.png":
{
"frame": {"x":49,"y":1765,"w":51,"h":63},
"frame": {"x":1966,"y":3,"w":51,"h":63},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":6,"y":0,"w":51,"h":63},
@ -10,7 +10,7 @@
},
"sprites/belt/forward_1.png":
{
"frame": {"x":3,"y":1902,"w":51,"h":63},
"frame": {"x":1835,"y":203,"w":51,"h":63},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":6,"y":0,"w":51,"h":63},
@ -18,7 +18,7 @@
},
"sprites/belt/forward_2.png":
{
"frame": {"x":58,"y":1902,"w":51,"h":63},
"frame": {"x":1879,"y":304,"w":51,"h":63},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":6,"y":0,"w":51,"h":63},
@ -26,7 +26,7 @@
},
"sprites/belt/forward_3.png":
{
"frame": {"x":113,"y":1887,"w":51,"h":63},
"frame": {"x":1934,"y":304,"w":51,"h":63},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":6,"y":0,"w":51,"h":63},
@ -34,7 +34,7 @@
},
"sprites/belt/forward_4.png":
{
"frame": {"x":168,"y":1830,"w":51,"h":63},
"frame": {"x":1844,"y":381,"w":51,"h":63},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":6,"y":0,"w":51,"h":63},
@ -42,7 +42,7 @@
},
"sprites/belt/forward_5.png":
{
"frame": {"x":168,"y":1897,"w":51,"h":63},
"frame": {"x":1899,"y":371,"w":51,"h":63},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":6,"y":0,"w":51,"h":63},
@ -50,7 +50,7 @@
},
"sprites/belt/left_0.png":
{
"frame": {"x":104,"y":1765,"w":57,"h":57},
"frame": {"x":1890,"y":243,"w":57,"h":57},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":0,"y":6,"w":57,"h":57},
@ -58,7 +58,7 @@
},
"sprites/belt/left_1.png":
{
"frame": {"x":165,"y":1769,"w":57,"h":57},
"frame": {"x":1951,"y":243,"w":57,"h":57},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":0,"y":6,"w":57,"h":57},
@ -66,7 +66,7 @@
},
"sprites/belt/left_2.png":
{
"frame": {"x":104,"y":1826,"w":57,"h":57},
"frame": {"x":1783,"y":381,"w":57,"h":57},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":0,"y":6,"w":57,"h":57},
@ -74,7 +74,7 @@
},
"sprites/belt/left_3.png":
{
"frame": {"x":226,"y":1782,"w":57,"h":57},
"frame": {"x":1954,"y":371,"w":57,"h":57},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":0,"y":6,"w":57,"h":57},
@ -82,7 +82,7 @@
},
"sprites/belt/left_4.png":
{
"frame": {"x":287,"y":1782,"w":57,"h":57},
"frame": {"x":1954,"y":432,"w":57,"h":57},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":0,"y":6,"w":57,"h":57},
@ -90,7 +90,7 @@
},
"sprites/belt/left_5.png":
{
"frame": {"x":348,"y":1835,"w":57,"h":57},
"frame": {"x":1363,"y":403,"w":57,"h":57},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":0,"y":6,"w":57,"h":57},
@ -98,7 +98,7 @@
},
"sprites/belt/right_0.png":
{
"frame": {"x":409,"y":1835,"w":57,"h":57},
"frame": {"x":1424,"y":403,"w":57,"h":57},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":6,"y":6,"w":57,"h":57},
@ -106,7 +106,7 @@
},
"sprites/belt/right_1.png":
{
"frame": {"x":223,"y":1896,"w":57,"h":57},
"frame": {"x":1485,"y":403,"w":57,"h":57},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":6,"y":6,"w":57,"h":57},
@ -114,7 +114,7 @@
},
"sprites/belt/right_2.png":
{
"frame": {"x":284,"y":1843,"w":57,"h":57},
"frame": {"x":1546,"y":403,"w":57,"h":57},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":6,"y":6,"w":57,"h":57},
@ -122,7 +122,7 @@
},
"sprites/belt/right_3.png":
{
"frame": {"x":284,"y":1904,"w":57,"h":57},
"frame": {"x":1607,"y":402,"w":57,"h":57},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":6,"y":6,"w":57,"h":57},
@ -130,7 +130,7 @@
},
"sprites/belt/right_4.png":
{
"frame": {"x":345,"y":1896,"w":57,"h":57},
"frame": {"x":1668,"y":402,"w":57,"h":57},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":6,"y":6,"w":57,"h":57},
@ -138,7 +138,7 @@
},
"sprites/belt/right_5.png":
{
"frame": {"x":406,"y":1896,"w":57,"h":57},
"frame": {"x":1952,"y":181,"w":57,"h":57},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":6,"y":6,"w":57,"h":57},
@ -146,7 +146,7 @@
},
"sprites/blueprints/belt_left.png":
{
"frame": {"x":178,"y":1707,"w":58,"h":58},
"frame": {"x":1301,"y":400,"w":58,"h":58},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":0,"y":5,"w":58,"h":58},
@ -154,7 +154,7 @@
},
"sprites/blueprints/belt_right.png":
{
"frame": {"x":370,"y":1773,"w":58,"h":58},
"frame": {"x":1890,"y":181,"w":58,"h":58},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":5,"y":5,"w":58,"h":58},
@ -162,7 +162,7 @@
},
"sprites/blueprints/belt_top.png":
{
"frame": {"x":3,"y":1835,"w":53,"h":63},
"frame": {"x":1151,"y":403,"w":53,"h":63},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":5,"y":0,"w":53,"h":63},
@ -170,7 +170,7 @@
},
"sprites/blueprints/cutter-quad.png":
{
"frame": {"x":3,"y":574,"w":366,"h":96},
"frame": {"x":3,"y":374,"w":366,"h":96},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":11,"y":0,"w":366,"h":96},
@ -178,7 +178,7 @@
},
"sprites/blueprints/cutter.png":
{
"frame": {"x":3,"y":1465,"w":172,"h":96},
"frame": {"x":1285,"y":203,"w":172,"h":96},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":11,"y":0,"w":172,"h":96},
@ -186,7 +186,7 @@
},
"sprites/blueprints/miner-chainable.png":
{
"frame": {"x":179,"y":1507,"w":92,"h":96},
"frame": {"x":1401,"y":303,"w":92,"h":96},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":3,"y":0,"w":92,"h":96},
@ -194,7 +194,7 @@
},
"sprites/blueprints/miner.png":
{
"frame": {"x":178,"y":1607,"w":92,"h":96},
"frame": {"x":1497,"y":303,"w":92,"h":96},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":3,"y":0,"w":92,"h":96},
@ -202,7 +202,7 @@
},
"sprites/blueprints/mixer.png":
{
"frame": {"x":296,"y":1217,"w":175,"h":96},
"frame": {"x":1143,"y":103,"w":175,"h":96},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":8,"y":0,"w":175,"h":96},
@ -210,15 +210,23 @@
},
"sprites/blueprints/painter-double.png":
{
"frame": {"x":3,"y":774,"w":192,"h":192},
"frame": {"x":373,"y":203,"w":192,"h":192},
"rotated": false,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":192,"h":192},
"sourceSize": {"w":192,"h":192}
},
"sprites/blueprints/painter-mirrored.png":
{
"frame": {"x":751,"y":103,"w":192,"h":96},
"rotated": false,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":192,"h":96},
"sourceSize": {"w":192,"h":96}
},
"sprites/blueprints/painter-quad.png":
{
"frame": {"x":3,"y":3,"w":374,"h":96},
"frame": {"x":373,"y":3,"w":374,"h":96},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":3,"y":0,"w":374,"h":96},
@ -226,7 +234,7 @@
},
"sprites/blueprints/painter.png":
{
"frame": {"x":3,"y":1165,"w":192,"h":96},
"frame": {"x":1121,"y":3,"w":192,"h":96},
"rotated": false,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":192,"h":96},
@ -234,7 +242,7 @@
},
"sprites/blueprints/rotater-ccw.png":
{
"frame": {"x":373,"y":249,"w":96,"h":96},
"frame": {"x":1866,"y":3,"w":96,"h":96},
"rotated": false,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":96,"h":96},
@ -242,7 +250,7 @@
},
"sprites/blueprints/rotater.png":
{
"frame": {"x":373,"y":349,"w":96,"h":96},
"frame": {"x":1675,"y":103,"w":96,"h":96},
"rotated": false,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":96,"h":96},
@ -250,7 +258,7 @@
},
"sprites/blueprints/splitter-compact-inverse.png":
{
"frame": {"x":370,"y":849,"w":95,"h":93},
"frame": {"x":1205,"y":303,"w":95,"h":93},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":0,"y":1,"w":95,"h":93},
@ -258,7 +266,7 @@
},
"sprites/blueprints/splitter-compact.png":
{
"frame": {"x":369,"y":1120,"w":93,"h":93},
"frame": {"x":1304,"y":303,"w":93,"h":93},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":3,"y":1,"w":93,"h":93},
@ -266,7 +274,7 @@
},
"sprites/blueprints/splitter.png":
{
"frame": {"x":3,"y":1565,"w":171,"h":96},
"frame": {"x":1691,"y":3,"w":171,"h":96},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":11,"y":0,"w":171,"h":96},
@ -274,7 +282,7 @@
},
"sprites/blueprints/stacker.png":
{
"frame": {"x":296,"y":1317,"w":175,"h":96},
"frame": {"x":1106,"y":203,"w":175,"h":96},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":8,"y":0,"w":175,"h":96},
@ -282,7 +290,7 @@
},
"sprites/blueprints/trash-storage.png":
{
"frame": {"x":199,"y":774,"w":167,"h":192},
"frame": {"x":765,"y":203,"w":167,"h":192},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":14,"y":0,"w":167,"h":192},
@ -290,7 +298,7 @@
},
"sprites/blueprints/trash.png":
{
"frame": {"x":373,"y":449,"w":96,"h":96},
"frame": {"x":1636,"y":203,"w":96,"h":96},
"rotated": false,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":96,"h":96},
@ -298,7 +306,7 @@
},
"sprites/blueprints/underground_belt_entry-tier2.png":
{
"frame": {"x":199,"y":1261,"w":93,"h":84},
"frame": {"x":764,"y":399,"w":93,"h":84},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":2,"y":12,"w":93,"h":84},
@ -306,7 +314,7 @@
},
"sprites/blueprints/underground_belt_entry.png":
{
"frame": {"x":199,"y":1349,"w":93,"h":75},
"frame": {"x":373,"y":399,"w":93,"h":75},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":2,"y":21,"w":93,"h":75},
@ -314,7 +322,7 @@
},
"sprites/blueprints/underground_belt_exit-tier2.png":
{
"frame": {"x":369,"y":1041,"w":94,"h":75},
"frame": {"x":957,"y":399,"w":94,"h":75},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":2,"y":0,"w":94,"h":75},
@ -322,7 +330,7 @@
},
"sprites/blueprints/underground_belt_exit.png":
{
"frame": {"x":181,"y":1428,"w":93,"h":75},
"frame": {"x":470,"y":399,"w":93,"h":75},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":2,"y":0,"w":93,"h":75},
@ -330,7 +338,7 @@
},
"sprites/buildings/belt_left.png":
{
"frame": {"x":104,"y":1765,"w":57,"h":57},
"frame": {"x":1890,"y":243,"w":57,"h":57},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":0,"y":6,"w":57,"h":57},
@ -338,7 +346,7 @@
},
"sprites/buildings/belt_right.png":
{
"frame": {"x":409,"y":1835,"w":57,"h":57},
"frame": {"x":1424,"y":403,"w":57,"h":57},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":6,"y":6,"w":57,"h":57},
@ -346,7 +354,7 @@
},
"sprites/buildings/belt_top.png":
{
"frame": {"x":49,"y":1765,"w":51,"h":63},
"frame": {"x":1966,"y":3,"w":51,"h":63},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":6,"y":0,"w":51,"h":63},
@ -354,7 +362,7 @@
},
"sprites/buildings/cutter-quad.png":
{
"frame": {"x":3,"y":674,"w":366,"h":96},
"frame": {"x":751,"y":3,"w":366,"h":96},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":11,"y":0,"w":366,"h":96},
@ -362,7 +370,7 @@
},
"sprites/buildings/cutter.png":
{
"frame": {"x":275,"y":1517,"w":171,"h":96},
"frame": {"x":1500,"y":103,"w":171,"h":96},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":11,"y":0,"w":171,"h":96},
@ -370,7 +378,7 @@
},
"sprites/buildings/hub.png":
{
"frame": {"x":3,"y":203,"w":366,"h":367},
"frame": {"x":3,"y":3,"w":366,"h":367},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":9,"y":10,"w":366,"h":367},
@ -378,7 +386,7 @@
},
"sprites/buildings/miner-chainable.png":
{
"frame": {"x":381,"y":3,"w":91,"h":95},
"frame": {"x":1593,"y":303,"w":91,"h":95},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":3,"y":0,"w":91,"h":95},
@ -386,7 +394,7 @@
},
"sprites/buildings/miner.png":
{
"frame": {"x":381,"y":102,"w":91,"h":95},
"frame": {"x":1688,"y":303,"w":91,"h":95},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":3,"y":0,"w":91,"h":95},
@ -394,7 +402,7 @@
},
"sprites/buildings/mixer.png":
{
"frame": {"x":296,"y":1417,"w":174,"h":96},
"frame": {"x":1513,"y":3,"w":174,"h":96},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":9,"y":0,"w":174,"h":96},
@ -402,15 +410,23 @@
},
"sprites/buildings/painter-double.png":
{
"frame": {"x":3,"y":970,"w":192,"h":191},
"frame": {"x":569,"y":203,"w":192,"h":191},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":0,"y":0,"w":192,"h":191},
"sourceSize": {"w":192,"h":192}
},
"sprites/buildings/painter-mirrored.png":
{
"frame": {"x":947,"y":103,"w":192,"h":96},
"rotated": false,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":192,"h":96},
"sourceSize": {"w":192,"h":96}
},
"sprites/buildings/painter-quad.png":
{
"frame": {"x":3,"y":103,"w":374,"h":96},
"frame": {"x":373,"y":103,"w":374,"h":96},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":3,"y":0,"w":374,"h":96},
@ -418,7 +434,7 @@
},
"sprites/buildings/painter.png":
{
"frame": {"x":3,"y":1265,"w":192,"h":96},
"frame": {"x":1317,"y":3,"w":192,"h":96},
"rotated": false,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":192,"h":96},
@ -426,7 +442,7 @@
},
"sprites/buildings/rotater-ccw.png":
{
"frame": {"x":373,"y":649,"w":95,"h":96},
"frame": {"x":1736,"y":203,"w":95,"h":96},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":1,"y":0,"w":95,"h":96},
@ -434,7 +450,7 @@
},
"sprites/buildings/rotater.png":
{
"frame": {"x":373,"y":749,"w":95,"h":96},
"frame": {"x":1106,"y":303,"w":95,"h":96},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":1,"y":0,"w":95,"h":96},
@ -442,7 +458,7 @@
},
"sprites/buildings/splitter-compact-inverse.png":
{
"frame": {"x":370,"y":946,"w":94,"h":91},
"frame": {"x":569,"y":398,"w":94,"h":91},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":0,"y":2,"w":94,"h":91},
@ -450,7 +466,7 @@
},
"sprites/buildings/splitter-compact.png":
{
"frame": {"x":199,"y":1166,"w":93,"h":91},
"frame": {"x":667,"y":398,"w":93,"h":91},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":3,"y":2,"w":93,"h":91},
@ -458,7 +474,7 @@
},
"sprites/buildings/splitter.png":
{
"frame": {"x":3,"y":1665,"w":171,"h":96},
"frame": {"x":1461,"y":203,"w":171,"h":96},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":11,"y":0,"w":171,"h":96},
@ -466,7 +482,7 @@
},
"sprites/buildings/stacker.png":
{
"frame": {"x":3,"y":1365,"w":174,"h":96},
"frame": {"x":1322,"y":103,"w":174,"h":96},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":9,"y":0,"w":174,"h":96},
@ -474,7 +490,7 @@
},
"sprites/buildings/trash-storage.png":
{
"frame": {"x":199,"y":970,"w":166,"h":192},
"frame": {"x":936,"y":203,"w":166,"h":192},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":14,"y":0,"w":166,"h":192},
@ -482,7 +498,7 @@
},
"sprites/buildings/trash.png":
{
"frame": {"x":373,"y":549,"w":96,"h":96},
"frame": {"x":1775,"y":103,"w":96,"h":96},
"rotated": false,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":96,"h":96},
@ -490,7 +506,7 @@
},
"sprites/buildings/underground_belt_entry-tier2.png":
{
"frame": {"x":274,"y":1617,"w":92,"h":83},
"frame": {"x":861,"y":399,"w":92,"h":83},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":3,"y":13,"w":92,"h":83},
@ -498,7 +514,7 @@
},
"sprites/buildings/underground_belt_entry.png":
{
"frame": {"x":370,"y":1617,"w":92,"h":74},
"frame": {"x":1875,"y":103,"w":92,"h":74},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":3,"y":22,"w":92,"h":74},
@ -506,7 +522,7 @@
},
"sprites/buildings/underground_belt_exit-tier2.png":
{
"frame": {"x":370,"y":1695,"w":92,"h":74},
"frame": {"x":1783,"y":303,"w":92,"h":74},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":3,"y":0,"w":92,"h":74},
@ -514,7 +530,7 @@
},
"sprites/buildings/underground_belt_exit.png":
{
"frame": {"x":274,"y":1704,"w":92,"h":74},
"frame": {"x":1055,"y":403,"w":92,"h":74},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":3,"y":0,"w":92,"h":74},
@ -522,7 +538,7 @@
},
"sprites/debug/acceptor_slot.png":
{
"frame": {"x":240,"y":1707,"w":26,"h":32},
"frame": {"x":1989,"y":304,"w":26,"h":32},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":3,"y":0,"w":26,"h":32},
@ -530,7 +546,7 @@
},
"sprites/debug/ejector_slot.png":
{
"frame": {"x":240,"y":1743,"w":26,"h":32},
"frame": {"x":1971,"y":116,"w":26,"h":32},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":3,"y":0,"w":26,"h":32},
@ -538,7 +554,7 @@
},
"sprites/map_overview/belt_forward.png":
{
"frame": {"x":181,"y":1365,"w":14,"h":16},
"frame": {"x":1835,"y":270,"w":14,"h":16},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":1,"y":0,"w":14,"h":16},
@ -546,7 +562,7 @@
},
"sprites/map_overview/belt_left.png":
{
"frame": {"x":342,"y":1166,"w":15,"h":15},
"frame": {"x":3,"y":474,"w":15,"h":15},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":0,"y":1,"w":15,"h":15},
@ -554,7 +570,7 @@
},
"sprites/map_overview/belt_right.png":
{
"frame": {"x":342,"y":1185,"w":15,"h":15},
"frame": {"x":22,"y":474,"w":15,"h":15},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":1,"y":1,"w":15,"h":15},
@ -562,15 +578,31 @@
},
"sprites/misc/deletion_marker.png":
{
"frame": {"x":296,"y":1166,"w":42,"h":42},
"frame": {"x":1971,"y":70,"w":42,"h":42},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":3,"y":3,"w":42,"h":42},
"sourceSize": {"w":48,"h":48}
},
"sprites/misc/hub_direction_indicator.png":
{
"frame": {"x":2001,"y":116,"w":16,"h":16},
"rotated": false,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":16,"h":16},
"sourceSize": {"w":16,"h":16}
},
"sprites/misc/lock_direction_indicator.png":
{
"frame": {"x":1208,"y":448,"w":24,"h":16},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":0,"y":4,"w":24,"h":16},
"sourceSize": {"w":24,"h":24}
},
"sprites/misc/slot_bad_arrow.png":
{
"frame": {"x":296,"y":1166,"w":42,"h":42},
"frame": {"x":1971,"y":70,"w":42,"h":42},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":3,"y":3,"w":42,"h":42},
@ -578,7 +610,7 @@
},
"sprites/misc/slot_good_arrow.png":
{
"frame": {"x":3,"y":1782,"w":42,"h":48},
"frame": {"x":1729,"y":402,"w":42,"h":48},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":3,"y":0,"w":42,"h":48},
@ -586,7 +618,7 @@
},
"sprites/misc/storage_overlay.png":
{
"frame": {"x":381,"y":201,"w":89,"h":44},
"frame": {"x":1208,"y":400,"w":89,"h":44},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":1,"y":1,"w":89,"h":44},
@ -594,7 +626,7 @@
},
"sprites/misc/waypoint.png":
{
"frame": {"x":181,"y":1385,"w":14,"h":16},
"frame": {"x":1989,"y":340,"w":14,"h":16},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":1,"y":0,"w":14,"h":16},
@ -605,8 +637,8 @@
"version": "1.0",
"image": "atlas0_50.png",
"format": "RGBA8888",
"size": {"w":475,"h":1968},
"size": {"w":2020,"h":492},
"scale": "0.5",
"smartupdate": "$TexturePacker:SmartUpdate:3dd7a89f30024dd4787ad4af6b14588a:9ba11f8b02134c4376ab4e0a44f8b850:f159918d23e5952766c6d23ab52278c6$"
"smartupdate": "$TexturePacker:SmartUpdate:8985524bba1a3f16cecab3c03b6aaa06:d614d20bfce033d8a8ab0990af085d16:f159918d23e5952766c6d23ab52278c6$"
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 374 KiB

After

Width:  |  Height:  |  Size: 397 KiB

View File

@ -2,7 +2,7 @@
"sprites/belt/forward_0.png":
{
"frame": {"x":1936,"y":151,"w":77,"h":95},
"frame": {"x":1963,"y":102,"w":77,"h":95},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":9,"y":0,"w":77,"h":95},
@ -10,7 +10,7 @@
},
"sprites/belt/forward_1.png":
{
"frame": {"x":1936,"y":250,"w":77,"h":95},
"frame": {"x":1963,"y":201,"w":77,"h":95},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":9,"y":0,"w":77,"h":95},
@ -18,7 +18,7 @@
},
"sprites/belt/forward_2.png":
{
"frame": {"x":1600,"y":708,"w":77,"h":95},
"frame": {"x":1967,"y":300,"w":77,"h":95},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":9,"y":0,"w":77,"h":95},
@ -26,7 +26,7 @@
},
"sprites/belt/forward_3.png":
{
"frame": {"x":1544,"y":808,"w":77,"h":95},
"frame": {"x":1967,"y":399,"w":77,"h":95},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":9,"y":0,"w":77,"h":95},
@ -34,7 +34,7 @@
},
"sprites/belt/forward_4.png":
{
"frame": {"x":1625,"y":807,"w":77,"h":95},
"frame": {"x":1967,"y":498,"w":77,"h":95},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":9,"y":0,"w":77,"h":95},
@ -42,7 +42,7 @@
},
"sprites/belt/forward_5.png":
{
"frame": {"x":1544,"y":907,"w":77,"h":95},
"frame": {"x":1679,"y":952,"w":77,"h":95},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":9,"y":0,"w":77,"h":95},
@ -50,7 +50,7 @@
},
"sprites/belt/left_0.png":
{
"frame": {"x":1680,"y":593,"w":86,"h":86},
"frame": {"x":1217,"y":969,"w":86,"h":86},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":0,"y":9,"w":86,"h":86},
@ -58,7 +58,7 @@
},
"sprites/belt/left_1.png":
{
"frame": {"x":1770,"y":592,"w":86,"h":86},
"frame": {"x":1307,"y":969,"w":86,"h":86},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":0,"y":9,"w":86,"h":86},
@ -66,7 +66,7 @@
},
"sprites/belt/left_2.png":
{
"frame": {"x":1860,"y":592,"w":86,"h":86},
"frame": {"x":1916,"y":597,"w":86,"h":86},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":0,"y":9,"w":86,"h":86},
@ -74,7 +74,7 @@
},
"sprites/belt/left_3.png":
{
"frame": {"x":1681,"y":683,"w":86,"h":86},
"frame": {"x":1916,"y":687,"w":86,"h":86},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":0,"y":9,"w":86,"h":86},
@ -82,7 +82,7 @@
},
"sprites/belt/left_4.png":
{
"frame": {"x":1771,"y":682,"w":86,"h":86},
"frame": {"x":1916,"y":777,"w":86,"h":86},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":0,"y":9,"w":86,"h":86},
@ -90,7 +90,7 @@
},
"sprites/belt/left_5.png":
{
"frame": {"x":1861,"y":682,"w":86,"h":86},
"frame": {"x":1914,"y":867,"w":86,"h":86},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":0,"y":9,"w":86,"h":86},
@ -98,7 +98,7 @@
},
"sprites/belt/right_0.png":
{
"frame": {"x":1706,"y":773,"w":86,"h":86},
"frame": {"x":1499,"y":852,"w":86,"h":86},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":9,"y":9,"w":86,"h":86},
@ -106,7 +106,7 @@
},
"sprites/belt/right_1.png":
{
"frame": {"x":1796,"y":772,"w":86,"h":86},
"frame": {"x":1397,"y":967,"w":86,"h":86},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":9,"y":9,"w":86,"h":86},
@ -114,7 +114,7 @@
},
"sprites/belt/right_2.png":
{
"frame": {"x":1886,"y":772,"w":86,"h":86},
"frame": {"x":1589,"y":862,"w":86,"h":86},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":9,"y":9,"w":86,"h":86},
@ -122,7 +122,7 @@
},
"sprites/belt/right_3.png":
{
"frame": {"x":1716,"y":863,"w":86,"h":86},
"frame": {"x":1679,"y":862,"w":86,"h":86},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":9,"y":9,"w":86,"h":86},
@ -130,7 +130,7 @@
},
"sprites/belt/right_4.png":
{
"frame": {"x":1806,"y":862,"w":86,"h":86},
"frame": {"x":1499,"y":942,"w":86,"h":86},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":9,"y":9,"w":86,"h":86},
@ -138,7 +138,7 @@
},
"sprites/belt/right_5.png":
{
"frame": {"x":1896,"y":862,"w":86,"h":86},
"frame": {"x":1589,"y":952,"w":86,"h":86},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":9,"y":9,"w":86,"h":86},
@ -146,7 +146,7 @@
},
"sprites/blueprints/belt_left.png":
{
"frame": {"x":1924,"y":349,"w":87,"h":87},
"frame": {"x":1397,"y":593,"w":87,"h":87},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":0,"y":8,"w":87,"h":87},
@ -154,7 +154,7 @@
},
"sprites/blueprints/belt_right.png":
{
"frame": {"x":1625,"y":906,"w":87,"h":87},
"frame": {"x":1397,"y":684,"w":87,"h":87},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":8,"y":8,"w":87,"h":87},
@ -162,7 +162,7 @@
},
"sprites/blueprints/belt_top.png":
{
"frame": {"x":1517,"y":709,"w":79,"h":95},
"frame": {"x":1963,"y":3,"w":79,"h":95},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":8,"y":0,"w":79,"h":95},
@ -186,7 +186,7 @@
},
"sprites/blueprints/miner-chainable.png":
{
"frame": {"x":1784,"y":299,"w":136,"h":143},
"frame": {"x":1827,"y":447,"w":136,"h":143},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":5,"y":0,"w":136,"h":143},
@ -194,7 +194,7 @@
},
"sprites/blueprints/miner.png":
{
"frame": {"x":1544,"y":446,"w":136,"h":143},
"frame": {"x":1076,"y":739,"w":136,"h":143},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":5,"y":0,"w":136,"h":143},
@ -202,7 +202,7 @@
},
"sprites/blueprints/mixer.png":
{
"frame": {"x":1671,"y":151,"w":261,"h":144},
"frame": {"x":547,"y":738,"w":261,"h":144},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":13,"y":0,"w":261,"h":144},
@ -216,6 +216,14 @@
"spriteSourceSize": {"x":0,"y":0,"w":288,"h":287},
"sourceSize": {"w":288,"h":288}
},
"sprites/blueprints/painter-mirrored.png":
{
"frame": {"x":1119,"y":150,"w":288,"h":144},
"rotated": false,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":288,"h":144},
"sourceSize": {"w":288,"h":144}
},
"sprites/blueprints/painter-quad.png":
{
"frame": {"x":555,"y":3,"w":560,"h":144},
@ -226,7 +234,7 @@
},
"sprites/blueprints/painter.png":
{
"frame": {"x":1119,"y":150,"w":288,"h":144},
"frame": {"x":1671,"y":3,"w":288,"h":144},
"rotated": false,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":288,"h":144},
@ -234,7 +242,7 @@
},
"sprites/blueprints/rotater-ccw.png":
{
"frame": {"x":1397,"y":445,"w":143,"h":144},
"frame": {"x":1639,"y":299,"w":143,"h":144},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":1,"y":0,"w":143,"h":144},
@ -242,7 +250,7 @@
},
"sprites/blueprints/rotater.png":
{
"frame": {"x":1084,"y":594,"w":143,"h":144},
"frame": {"x":1786,"y":299,"w":143,"h":144},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":1,"y":0,"w":143,"h":144},
@ -250,7 +258,7 @@
},
"sprites/blueprints/splitter-compact-inverse.png":
{
"frame": {"x":1071,"y":742,"w":142,"h":138},
"frame": {"x":1071,"y":886,"w":142,"h":138},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":0,"y":2,"w":142,"h":138},
@ -258,7 +266,7 @@
},
"sprites/blueprints/splitter-compact.png":
{
"frame": {"x":1217,"y":742,"w":139,"h":138},
"frame": {"x":1488,"y":594,"w":139,"h":138},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":5,"y":2,"w":139,"h":138},
@ -266,7 +274,7 @@
},
"sprites/blueprints/splitter.png":
{
"frame": {"x":1119,"y":298,"w":256,"h":144},
"frame": {"x":811,"y":886,"w":256,"h":144},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":17,"y":0,"w":256,"h":144},
@ -274,7 +282,7 @@
},
"sprites/blueprints/stacker.png":
{
"frame": {"x":555,"y":590,"w":261,"h":144},
"frame": {"x":847,"y":591,"w":261,"h":144},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":13,"y":0,"w":261,"h":144},
@ -290,7 +298,7 @@
},
"sprites/blueprints/trash.png":
{
"frame": {"x":1101,"y":446,"w":144,"h":144},
"frame": {"x":1241,"y":445,"w":144,"h":144},
"rotated": false,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":144,"h":144},
@ -298,7 +306,7 @@
},
"sprites/blueprints/underground_belt_entry-tier2.png":
{
"frame": {"x":835,"y":885,"w":138,"h":125},
"frame": {"x":1774,"y":594,"w":138,"h":125},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":4,"y":19,"w":138,"h":125},
@ -306,7 +314,7 @@
},
"sprites/blueprints/underground_belt_entry.png":
{
"frame": {"x":1261,"y":884,"w":138,"h":112},
"frame": {"x":1774,"y":723,"w":138,"h":112},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":4,"y":32,"w":138,"h":112},
@ -314,7 +322,7 @@
},
"sprites/blueprints/underground_belt_exit-tier2.png":
{
"frame": {"x":1118,"y":884,"w":139,"h":112},
"frame": {"x":1488,"y":736,"w":139,"h":112},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":4,"y":0,"w":139,"h":112},
@ -322,7 +330,7 @@
},
"sprites/blueprints/underground_belt_exit.png":
{
"frame": {"x":1397,"y":593,"w":138,"h":112},
"frame": {"x":1772,"y":839,"w":138,"h":112},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":4,"y":0,"w":138,"h":112},
@ -330,7 +338,7 @@
},
"sprites/buildings/belt_left.png":
{
"frame": {"x":1680,"y":593,"w":86,"h":86},
"frame": {"x":1217,"y":969,"w":86,"h":86},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":0,"y":9,"w":86,"h":86},
@ -338,7 +346,7 @@
},
"sprites/buildings/belt_right.png":
{
"frame": {"x":1706,"y":773,"w":86,"h":86},
"frame": {"x":1499,"y":852,"w":86,"h":86},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":9,"y":9,"w":86,"h":86},
@ -346,7 +354,7 @@
},
"sprites/buildings/belt_top.png":
{
"frame": {"x":1936,"y":151,"w":77,"h":95},
"frame": {"x":1963,"y":102,"w":77,"h":95},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":9,"y":0,"w":77,"h":95},
@ -362,7 +370,7 @@
},
"sprites/buildings/cutter.png":
{
"frame": {"x":811,"y":738,"w":256,"h":143},
"frame": {"x":1119,"y":298,"w":256,"h":143},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":17,"y":0,"w":256,"h":143},
@ -378,7 +386,7 @@
},
"sprites/buildings/miner-chainable.png":
{
"frame": {"x":1684,"y":446,"w":136,"h":142},
"frame": {"x":1101,"y":445,"w":136,"h":142},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":5,"y":0,"w":136,"h":142},
@ -386,7 +394,7 @@
},
"sprites/buildings/miner.png":
{
"frame": {"x":1824,"y":446,"w":136,"h":142},
"frame": {"x":1112,"y":593,"w":136,"h":142},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":5,"y":0,"w":136,"h":142},
@ -394,7 +402,7 @@
},
"sprites/buildings/mixer.png":
{
"frame": {"x":547,"y":738,"w":260,"h":143},
"frame": {"x":812,"y":739,"w":260,"h":143},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":14,"y":0,"w":260,"h":143},
@ -408,6 +416,14 @@
"spriteSourceSize": {"x":0,"y":0,"w":288,"h":286},
"sourceSize": {"w":288,"h":288}
},
"sprites/buildings/painter-mirrored.png":
{
"frame": {"x":1671,"y":151,"w":288,"h":144},
"rotated": false,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":288,"h":144},
"sourceSize": {"w":288,"h":144}
},
"sprites/buildings/painter-quad.png":
{
"frame": {"x":555,"y":151,"w":560,"h":144},
@ -418,7 +434,7 @@
},
"sprites/buildings/painter.png":
{
"frame": {"x":1671,"y":3,"w":288,"h":144},
"frame": {"x":555,"y":590,"w":288,"h":144},
"rotated": false,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":288,"h":144},
@ -426,7 +442,7 @@
},
"sprites/buildings/rotater-ccw.png":
{
"frame": {"x":1231,"y":594,"w":141,"h":143},
"frame": {"x":1537,"y":447,"w":141,"h":143},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":2,"y":0,"w":141,"h":143},
@ -434,7 +450,7 @@
},
"sprites/buildings/rotater.png":
{
"frame": {"x":1639,"y":299,"w":141,"h":143},
"frame": {"x":1682,"y":447,"w":141,"h":143},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":2,"y":0,"w":141,"h":143},
@ -442,7 +458,7 @@
},
"sprites/buildings/splitter-compact-inverse.png":
{
"frame": {"x":547,"y":885,"w":141,"h":136},
"frame": {"x":1252,"y":593,"w":141,"h":136},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":0,"y":3,"w":141,"h":136},
@ -450,7 +466,7 @@
},
"sprites/buildings/splitter-compact.png":
{
"frame": {"x":692,"y":885,"w":139,"h":136},
"frame": {"x":1631,"y":594,"w":139,"h":136},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":5,"y":3,"w":139,"h":136},
@ -466,7 +482,7 @@
},
"sprites/buildings/stacker.png":
{
"frame": {"x":820,"y":591,"w":260,"h":143},
"frame": {"x":547,"y":886,"w":260,"h":143},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":14,"y":0,"w":260,"h":143},
@ -482,7 +498,7 @@
},
"sprites/buildings/trash.png":
{
"frame": {"x":1249,"y":446,"w":144,"h":144},
"frame": {"x":1389,"y":445,"w":144,"h":144},
"rotated": false,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":144,"h":144},
@ -490,7 +506,7 @@
},
"sprites/buildings/underground_belt_entry-tier2.png":
{
"frame": {"x":977,"y":885,"w":137,"h":124},
"frame": {"x":1631,"y":734,"w":137,"h":124},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":5,"y":20,"w":137,"h":124},
@ -498,7 +514,7 @@
},
"sprites/buildings/underground_belt_entry.png":
{
"frame": {"x":1539,"y":593,"w":137,"h":111},
"frame": {"x":1216,"y":739,"w":137,"h":111},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":5,"y":33,"w":137,"h":111},
@ -506,7 +522,7 @@
},
"sprites/buildings/underground_belt_exit-tier2.png":
{
"frame": {"x":1376,"y":709,"w":137,"h":111},
"frame": {"x":1217,"y":854,"w":137,"h":111},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":5,"y":0,"w":137,"h":111},
@ -514,7 +530,7 @@
},
"sprites/buildings/underground_belt_exit.png":
{
"frame": {"x":1403,"y":824,"w":137,"h":111},
"frame": {"x":1358,"y":852,"w":137,"h":111},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":5,"y":0,"w":137,"h":111},
@ -522,7 +538,7 @@
},
"sprites/debug/acceptor_slot.png":
{
"frame": {"x":1963,"y":3,"w":38,"h":48},
"frame": {"x":2006,"y":597,"w":38,"h":48},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":5,"y":0,"w":38,"h":48},
@ -530,7 +546,7 @@
},
"sprites/debug/ejector_slot.png":
{
"frame": {"x":1963,"y":55,"w":38,"h":48},
"frame": {"x":2006,"y":649,"w":38,"h":48},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":5,"y":0,"w":38,"h":48},
@ -538,7 +554,7 @@
},
"sprites/map_overview/belt_forward.png":
{
"frame": {"x":1625,"y":997,"w":20,"h":24},
"frame": {"x":1826,"y":955,"w":20,"h":24},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":2,"y":0,"w":20,"h":24},
@ -546,7 +562,7 @@
},
"sprites/map_overview/belt_left.png":
{
"frame": {"x":3,"y":994,"w":22,"h":22},
"frame": {"x":206,"y":994,"w":22,"h":22},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":0,"y":2,"w":22,"h":22},
@ -554,7 +570,7 @@
},
"sprites/map_overview/belt_right.png":
{
"frame": {"x":1963,"y":107,"w":22,"h":22},
"frame": {"x":2006,"y":701,"w":22,"h":22},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":2,"y":2,"w":22,"h":22},
@ -562,15 +578,31 @@
},
"sprites/misc/deletion_marker.png":
{
"frame": {"x":1716,"y":953,"w":62,"h":62},
"frame": {"x":140,"y":994,"w":62,"h":62},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":5,"y":5,"w":62,"h":62},
"sourceSize": {"w":72,"h":72}
},
"sprites/misc/hub_direction_indicator.png":
{
"frame": {"x":1933,"y":299,"w":24,"h":24},
"rotated": false,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":24,"h":24},
"sourceSize": {"w":24,"h":24}
},
"sprites/misc/lock_direction_indicator.png":
{
"frame": {"x":1357,"y":733,"w":36,"h":24},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":0,"y":6,"w":36,"h":24},
"sourceSize": {"w":36,"h":36}
},
"sprites/misc/slot_bad_arrow.png":
{
"frame": {"x":1716,"y":953,"w":62,"h":62},
"frame": {"x":140,"y":994,"w":62,"h":62},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":5,"y":5,"w":62,"h":62},
@ -578,7 +610,7 @@
},
"sprites/misc/slot_good_arrow.png":
{
"frame": {"x":1950,"y":592,"w":62,"h":72},
"frame": {"x":1760,"y":955,"w":62,"h":72},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":5,"y":0,"w":62,"h":72},
@ -586,7 +618,7 @@
},
"sprites/misc/storage_overlay.png":
{
"frame": {"x":1403,"y":939,"w":133,"h":66},
"frame": {"x":3,"y":994,"w":133,"h":66},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":2,"y":2,"w":133,"h":66},
@ -594,7 +626,7 @@
},
"sprites/misc/waypoint.png":
{
"frame": {"x":1649,"y":997,"w":20,"h":24},
"frame": {"x":1357,"y":761,"w":20,"h":24},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":2,"y":0,"w":20,"h":24},
@ -605,8 +637,8 @@
"version": "1.0",
"image": "atlas0_75.png",
"format": "RGBA8888",
"size": {"w":2016,"h":1024},
"size": {"w":2047,"h":1063},
"scale": "0.75",
"smartupdate": "$TexturePacker:SmartUpdate:3dd7a89f30024dd4787ad4af6b14588a:9ba11f8b02134c4376ab4e0a44f8b850:f159918d23e5952766c6d23ab52278c6$"
"smartupdate": "$TexturePacker:SmartUpdate:8985524bba1a3f16cecab3c03b6aaa06:d614d20bfce033d8a8ab0990af085d16:f159918d23e5952766c6d23ab52278c6$"
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 735 KiB

After

Width:  |  Height:  |  Size: 780 KiB

View File

@ -324,9 +324,11 @@
</struct>
<key type="filename">sprites/blueprints/cutter.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/splitter.png</key>
<key type="filename">sprites/blueprints/stacker.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>
@ -445,6 +447,7 @@
<key type="filename">sprites/map_overview/belt_forward.png</key>
<key type="filename">sprites/map_overview/belt_left.png</key>
<key type="filename">sprites/map_overview/belt_right.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>
@ -477,6 +480,21 @@
<key>scale9FromFile</key>
<false/>
</struct>
<key type="filename">sprites/misc/lock_direction_indicator.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>12,12,24,24</rect>
<key>scale9Paddings</key>
<rect>12,12,24,24</rect>
<key>scale9FromFile</key>
<false/>
</struct>
<key type="filename">sprites/misc/storage_overlay.png</key>
<struct type="IndividualSpriteSettings">
<key>pivotPoint</key>

View File

@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:f61e851402fbc92d6909912fb203c63258fedbdea83e81f7ececb5091f4bee03
size 3732550

View File

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:8c334a9f100fce4647b4803d2a8270b30e26d53622b3717bdb81b3ea07f84aed
size 150286082

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 495 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

@ -38,6 +38,10 @@ html {
right: 0;
background: #dee1ea;
@include DarkThemeOverride {
background: $darkModeGameBackground;
}
}
body {
@ -413,6 +417,10 @@ canvas {
display: inline-block;
vertical-align: middle;
}
@include DarkThemeOverride {
color: #fff;
}
}
.prefab_LoadingTextWithAnimDelayed {

View File

@ -15,6 +15,11 @@ $buildingsAndVariants: belt, splitter, splitter-compact, splitter-compact-invers
}
}
// Special case
[data-icon="building_tutorials/painter-mirrored.png"] {
background-image: uiResource("res/ui/building_tutorials/painter.png") !important;
}
$icons: notification_saved, notification_success, notification_upgrade;
@each $icon in $icons {
[data-icon="icons/#{$icon}.png"] {
@ -22,8 +27,8 @@ $icons: notification_saved, notification_success, notification_upgrade;
}
}
$languages: en, de, cs, da, et, es-419, fr, it, pt-BR, sv, tr, el, ru, uk, zh-TW, nb, mt-MT, ar, nl, vi, th,
hu, pl, ja, kor;
$languages: en, de, cs, da, et, es-419, fr, it, pt-BR, sv, tr, el, ru, uk, zh-TW, zh-CN, nb, mt-MT, ar, nl, vi, th,
hu, pl, ja, kor, no, pt-PT;
@each $language in $languages {
[data-languageicon="#{$language}"] {

View File

@ -75,6 +75,15 @@
@include StyleBelowWidth(700px) {
display: none !important;
}
&.compact {
width: unset !important;
grid-template-columns: 1fr;
.buildingImage,
.description > .text {
display: none;
}
}
}
#ingame_HUD_PlacerVariants {
@ -86,6 +95,10 @@
flex-direction: column;
align-items: flex-end;
&.compact {
@include S(top, 150px);
}
.explanation {
text-transform: uppercase;
grid-row: 1 / 2;

View File

@ -21,15 +21,32 @@
}
}
$darkModeDialogBg: darken($darkModeGameBackground, 10);
@include DarkThemeOverride {
background: rgba(#33363d, 0.9);
background: rgba($darkModeDialogBg, 0.9);
@include InlineAnimation(0.12s ease-in-out) {
0% {
background-color: transparent;
opacity: 0.5;
}
100% {
background-color: rgba(#33363d, 0.9);
background-color: rgba($darkModeDialogBg, 0.9);
}
}
> .dialogInner.optionChooserDialog .optionParent {
.option {
background: #3d3f42;
&:hover {
background-color: #424348;
}
&.active {
background: $colorBlueBright;
color: #fff;
}
}
}
}
@ -122,6 +139,10 @@
color: #aaa;
}
a {
color: $colorBlueBright;
}
strong {
font-weight: bold;
}

View File

@ -14,6 +14,10 @@
}
> .binding {
&:not(.visible) {
display: none !important;
}
display: inline-grid;
@include PlainText;
align-items: center;
@ -57,42 +61,6 @@
@include S(margin-left, 5px);
}
}
&:not(.placementActive) .binding.placementOnly,
&.mapOverviewActive .binding.placementOnly {
display: none;
}
&.placementActive:not(.mapOverviewActive) .noPlacementOnly {
display: none;
}
&:not(.mapOverviewActive) .binding.overviewOnly {
display: none;
}
&.mapOverviewActive .noOverviewOnly {
display: none;
}
.binding.placementOnly,
&:not(.placementActive) .binding.noPlacementOnly {
transform-origin: 0% 50%;
@include InlineAnimation(0.3s ease-in-out) {
0% {
color: $colorRedBright;
transform: scale(1.2);
}
}
}
.keybinding.builtinKey {
transition: all 0.1s ease-in-out;
transition-property: background-color, color, border-color;
background: $colorRedBright;
border-color: $colorRedBright;
color: #fff;
}
}
body.uiHidden #ingame_HUD_KeybindingOverlay .binding:not(.hudToggle) {

View File

@ -1,22 +0,0 @@
#ingame_HUD_MassSelector {
position: absolute;
@include S(top, 50px);
left: 50%;
transform: translateX(-50%);
background: $ingameHudBg;
@include S(padding, 6px, 10px);
@include SuperSmallText;
color: #fff;
// color: #f77;
.keybinding {
vertical-align: middle;
@include S(margin, 0, 1px);
position: relative;
top: unset;
left: unset;
right: unset;
bottom: unset;
@include S(margin-top, -2px);
}
}

View File

@ -241,6 +241,10 @@
&.complete {
background-color: $colorGreenBright;
@include DarkThemeOverride {
background-color: $colorGreenBright;
}
}
}
}

View File

@ -29,7 +29,7 @@
#ingame_HUD_Waypoints {
position: absolute;
@include S(right, 10px);
@include S(top, 60px);
@include S(top, 45px);
display: flex;
flex-direction: column;
@include DarkThemeInvert();
@ -47,6 +47,7 @@
opacity: 0.7;
@include S(margin-bottom, 1px);
font-weight: bold;
&:hover {
opacity: 1;
}
@ -63,5 +64,29 @@
transform: scale(1.5);
}
}
&.hub {
// Transform because there is a canvas before
@include S(margin-left, -2px);
grid-template-columns: auto 1fr;
background: none !important;
@include S(padding-left, 0);
canvas {
@include S(width, 12px);
@include S(height, 12px);
@include S(margin-right, 1px);
}
}
&.shapeIcon {
canvas {
@include S(width, 15px);
@include S(height, 15px);
pointer-events: none;
// Double invert, to make sure it has the right color
@include DarkThemeInvert();
}
}
}
}

View File

@ -37,7 +37,6 @@
@import "ingame_hud/shop";
@import "ingame_hud/game_menu";
@import "ingame_hud/dialogs";
@import "ingame_hud/mass_selector";
@import "ingame_hud/vignette_overlay";
@import "ingame_hud/statistics";
@import "ingame_hud/pinned_shapes";
@ -67,7 +66,6 @@ ingame_HUD_PinnedShapes,
ingame_HUD_GameMenu,
ingame_HUD_KeybindingOverlay,
ingame_HUD_Notifications,
ingame_HUD_MassSelector,
ingame_HUD_DebugInfo,
ingame_HUD_EntityDebugger,
ingame_HUD_InteractiveTutorial,
@ -101,7 +99,6 @@ body.uiHidden {
#ingame_HUD_buildings_toolbar,
#ingame_HUD_PlacementHints,
#ingame_HUD_GameMenu,
#ingame_HUD_MassSelector,
#ingame_HUD_PinnedShapes,
#ingame_HUD_Notifications,
#ingame_HUD_TutorialHints,
@ -115,6 +112,6 @@ body.modalDialogActive,
body.externalAdOpen,
body.ingameDialogOpen {
> *:not(.ingameDialog):not(.modalDialogParent):not(.loadingDialog):not(.gameLoadingOverlay):not(#ingame_HUD_ModalDialogs):not(.noBlur) {
filter: blur(5px) !important;
// filter: blur(5px) !important;
}
}

View File

@ -350,7 +350,7 @@ button,
}
@mixin DarkThemeOverride {
@at-root body[data-theme="dark"] &,
@at-root html[data-theme="dark"] &,
&[data-theme="dark"] {
@content;
}

View File

@ -28,4 +28,10 @@
right: 0;
bottom: 0;
}
@include DarkThemeOverride {
.gameLoadingOverlay {
background: $darkModeGameBackground;
}
}
}

View File

@ -51,4 +51,21 @@
}
}
}
@include DarkThemeOverride {
.content {
.hint {
background: #3b3d40;
}
.category .entry {
color: #c0c4c8;
border-bottom-color: #888;
button {
filter: invert(1);
}
}
}
}
}

View File

@ -37,6 +37,7 @@
.languageChoose {
@include S(border-radius, 8px);
border: solid #222428;
background-color: #fff;
@include S(border-width, 2px);
background-size: cover;
}
@ -233,7 +234,8 @@
@include S(width, 300px);
}
.playButton {
.playButton,
.continueButton {
@include SuperHeading;
@include S(min-width, 130px);
@include S(padding, 15px, 20px);
@ -246,12 +248,21 @@
&:hover {
transform: scale(1.02);
}
&.continueButton {
@include Heading;
}
}
.importButton {
@include S(margin-top, 15px);
}
.newGameButton {
@include S(margin-top, 15px);
@include S(margin-left, 15px);
}
.savegames {
@include S(max-height, 105px);
overflow-y: auto;
@ -390,4 +401,44 @@
}
}
}
@include DarkThemeOverride {
background: $darkModeGameBackground center center / cover !important;
.topButtons {
filter: invert(1);
.languageChoose {
filter: invert(1);
}
}
.mainContainer {
background: darken($darkModeGameBackground, 10);
.savegames .savegame {
background: darken($darkModeGameBackground, 15);
color: white;
}
}
.footer {
> a {
background: darken($darkModeGameBackground, 10);
color: #eee;
}
.author {
color: #bdbdbd;
> a {
color: white;
}
}
.thirdpartyLogo.githubLogo {
filter: invert(1);
}
}
}
}

View File

@ -14,6 +14,10 @@
padding: 10px;
box-sizing: border-box;
background: #eef1f4;
@include DarkThemeOverride {
background: #424242;
}
.version {
@include Heading;

View File

@ -88,4 +88,26 @@
}
}
}
@include DarkThemeOverride {
.content {
.setting {
background: darken($darkModeGameBackground, 10);
.value.enum {
// dirty but works
filter: invert(0.85);
color: #222;
}
.value.checkbox {
background-color: #74767b;
&.checked {
background-color: $colorBlueBright;
}
}
}
}
}
}

View File

@ -61,4 +61,21 @@
}
}
}
@include DarkThemeOverride {
.headerBar {
h1 {
color: #e2e0db;
}
.backButton {
filter: invert(1);
}
}
> .container > .content {
background: darken($darkModeGameBackground, 3);
color: #eee;
}
}
}

View File

@ -38,6 +38,8 @@ $ingameHudBg: rgba(#333438, 0.9);
$text3dColor: #f4ffff;
$darkModeGameBackground: #5c606c;
// Dialog properties
$modalDialogBg: rgba(160, 165, 180, 0.8);
$dialogBgColor: lighten($mainBgColor, 10);

View File

@ -1,4 +1,83 @@
export const CHANGELOG = [
{
version: "1.1.17",
date: "unreleased",
entries: [
"Allow configuring autosave interval and disabling it in the settings",
"The smart-tunnel placement has been reworked to properly replace belts. Thus the setting has been turned on again by default",
"The soundtrack now has a higher quality on the standalone version than the web version",
"Add setting to disable cut/delete warnings (by hexy)",
"Fix bug where belts in blueprints don't orient correctly (by hexy)",
"Fix camera moving weird after dragging and holding (by hexy)",
"Fix keybinding for pipette showing while pasting blueprints",
"Update tutorial image for tier 2 tunnels to explain mix/match (by jimmyshadow1)",
"Prevent default actions on all keybindings in the web version so you don't accidentally use builtin browser shortcuts",
],
},
{
version: "1.1.16",
date: "21.06.2020",
entries: [
"You can now pickup buildings below your cursor with 'Q'!",
"The game soundtrack has been extended! There are now 4 songs with over 13 minutes of playtime from <a href='https://soundcloud.com/pettersumelius' target='blank'>Peppsen</a>!",
"Refactor keybindings overlay to show more appropriate keybindings",
"Show keybindings for area-select in the upper left instead",
"Automatically deselect area when selecting a new building",
"Raise markers limit from 14 characters to 71 (by Joker-vD)",
"Optimize performance by caching extractor items (by Phlosioneer)",
"Added setting to enable compact building infos, which only show ratios and hide the image / description",
"Apply dark theme to menu as well (by dengr1065)",
"Fix belt planner not placing the last belt",
"Fix buildings getting deleted when right clicking while placing a blueprint",
"Fix for exporting screenshots for huge bases (It was showing an empty file) (by xSparfuchs)",
"Fix buttons not responding when using right click directly after left click (by davidburhans)",
"Fix hub marker being hidden by building info panel",
"Disable dialog background blur since it can cause performance issues",
"Added simplified chinese translations",
"Update translations (Thanks to all translators!)",
],
},
{
version: "1.1.15",
date: "17.06.2020",
entries: [
"You can now place straight belts (and tunnels) by holding SHIFT! (For you, @giantwaffle ❤️)",
"Added continue button to main menu and add seperate 'New game' button (by jaysc)",
"Added setting to disable smart tunnel placement introduced with the last update",
"Added setting to disable vignette",
"Update translations",
],
},
{
version: "1.1.14",
date: "16.06.2020",
entries: [
"There is now an indicator (compass) to the HUB for the HUB Marker!",
"You can now include shape short keys in markers to render shape icons instead of text!",
"Added mirrored variant of the painter",
"When placing tunnels, unnecessary belts inbetween are now removed!",
"You can now drag tunnels and they will automatically expand! (Just try it out, its intuitive)",
],
},
{
version: "1.1.13",
date: "15.06.2020",
entries: [
"Added shift modifier for faster pan (by jaysc)",
"Added Japanese translations",
"Added Portuguese (Portugal) translations",
"Updated icon for Spanish (Latin America) - It was showing a Spanish flag before",
"Updated existing translations",
],
},
{
version: "1.1.12",
date: "14.06.2020",
entries: [
"Huge performance improvements! The game should now run up to 60% faster!",
"Added norwegian translation",
],
},
{
version: "1.1.11",
date: "13.06.2020",

View File

@ -3,7 +3,7 @@ import { createLogger } from "../core/logging";
import { Signal } from "../core/signal";
import { fastArrayDelete, fastArrayDeleteValueIfContained } from "./utils";
import { Vector } from "./vector";
import { IS_MOBILE } from "./config";
import { IS_MOBILE, SUPPORT_TOUCH } from "./config";
import { SOUNDS } from "../platform/sound";
import { GLOBAL_APP } from "./globals";
@ -119,16 +119,21 @@ export class ClickDetector {
}
}
const options = this.internalGetEventListenerOptions();
this.element.removeEventListener("touchstart", this.handlerTouchStart, options);
this.element.removeEventListener("touchend", this.handlerTouchEnd, options);
this.element.removeEventListener("touchcancel", this.handlerTouchCancel, options);
if (SUPPORT_TOUCH) {
this.element.removeEventListener("touchstart", this.handlerTouchStart, options);
this.element.removeEventListener("touchend", this.handlerTouchEnd, options);
this.element.removeEventListener("touchcancel", this.handlerTouchCancel, options);
}
this.element.removeEventListener("mouseup", this.handlerTouchStart, options);
this.element.removeEventListener("mousedown", this.handlerTouchEnd, options);
this.element.removeEventListener("mouseout", this.handlerTouchCancel, options);
if (this.captureTouchmove) {
this.element.removeEventListener("touchmove", this.handlerTouchMove, options);
if (SUPPORT_TOUCH) {
this.element.removeEventListener("touchmove", this.handlerTouchMove, options);
}
this.element.removeEventListener("mousemove", this.handlerTouchMove, options);
}
@ -186,16 +191,20 @@ export class ClickDetector {
element.addEventListener("click", this.handlerPreventClick, options);
}
element.addEventListener("touchstart", this.handlerTouchStart, options);
element.addEventListener("touchend", this.handlerTouchEnd, options);
element.addEventListener("touchcancel", this.handlerTouchCancel, options);
if (SUPPORT_TOUCH) {
element.addEventListener("touchstart", this.handlerTouchStart, options);
element.addEventListener("touchend", this.handlerTouchEnd, options);
element.addEventListener("touchcancel", this.handlerTouchCancel, options);
}
element.addEventListener("mousedown", this.handlerTouchStart, options);
element.addEventListener("mouseup", this.handlerTouchEnd, options);
element.addEventListener("mouseout", this.handlerTouchCancel, options);
if (this.captureTouchmove) {
element.addEventListener("touchmove", this.handlerTouchMove, options);
if (SUPPORT_TOUCH) {
element.addEventListener("touchmove", this.handlerTouchMove, options);
}
element.addEventListener("mousemove", this.handlerTouchMove, options);
}
@ -316,6 +325,7 @@ export class ClickDetector {
// Ignore right clicks
this.rightClick.dispatch(position, event);
this.cancelled = true;
this.clickDownPosition = null;
return;
}
}

View File

@ -12,6 +12,8 @@ export const IS_DEMO = queryParamOptions.fullVersion
: (G_IS_PROD && !G_IS_STANDALONE) ||
(typeof window !== "undefined" && window.location.search.indexOf("demo") >= 0);
export const SUPPORT_TOUCH = false;
const smoothCanvas = true;
export const THIRDPARTY_URLS = {

View File

@ -191,17 +191,7 @@ export class InputDistributor {
*/
handleKeyMouseDown(event) {
const keyCode = event instanceof MouseEvent ? event.button + 1 : event.keyCode;
if (
keyCode === 4 || // MB4
keyCode === 5 || // MB5
keyCode === 9 || // TAB
keyCode === 16 || // SHIFT
keyCode === 17 || // CTRL
keyCode === 18 || // ALT
(keyCode >= 112 && keyCode < 122) // F1 - F10
) {
event.preventDefault();
}
event.preventDefault();
const isInitial = !this.keysDown.has(keyCode);
this.keysDown.add(keyCode);

View File

@ -646,13 +646,12 @@ export function measure(name, target) {
}
/**
* Helper method to create a new div
* @param {Element} parent
* Helper method to create a new div element
* @param {string=} id
* @param {Array<string>=} classes
* @param {string=} innerHTML
*/
export function makeDiv(parent, id = null, classes = [], innerHTML = "") {
export function makeDivElement(id = null, classes = [], innerHTML = "") {
const div = document.createElement("div");
if (id) {
div.id = id;
@ -661,10 +660,51 @@ export function makeDiv(parent, id = null, classes = [], innerHTML = "") {
div.classList.add(classes[i]);
}
div.innerHTML = innerHTML;
return div;
}
/**
* Helper method to create a new div
* @param {Element} parent
* @param {string=} id
* @param {Array<string>=} classes
* @param {string=} innerHTML
*/
export function makeDiv(parent, id = null, classes = [], innerHTML = "") {
const div = makeDivElement(id, classes, innerHTML);
parent.appendChild(div);
return div;
}
/**
* Helper method to create a new div and place before reference Node
* @param {Element} parent
* @param {Element} referenceNode
* @param {string=} id
* @param {Array<string>=} classes
* @param {string=} innerHTML
*/
export function makeDivBefore(parent, referenceNode, id = null, classes = [], innerHTML = "") {
const div = makeDivElement(id, classes, innerHTML);
parent.insertBefore(div, referenceNode);
return div;
}
/**
* Helper method to create a new button element
* @param {Array<string>=} classes
* @param {string=} innerHTML
*/
export function makeButtonElement(classes = [], innerHTML = "") {
const element = document.createElement("button");
for (let i = 0; i < classes.length; ++i) {
element.classList.add(classes[i]);
}
element.classList.add("styledButton");
element.innerHTML = innerHTML;
return element;
}
/**
* Helper method to create a new button
* @param {Element} parent
@ -672,16 +712,24 @@ export function makeDiv(parent, id = null, classes = [], innerHTML = "") {
* @param {string=} innerHTML
*/
export function makeButton(parent, classes = [], innerHTML = "") {
const element = document.createElement("button");
for (let i = 0; i < classes.length; ++i) {
element.classList.add(classes[i]);
}
element.classList.add("styledButton");
element.innerHTML = innerHTML;
const element = makeButtonElement(classes, innerHTML);
parent.appendChild(element);
return element;
}
/**
* Helper method to create a new button and place before reference Node
* @param {Element} parent
* @param {Element} referenceNode
* @param {Array<string>=} classes
* @param {string=} innerHTML
*/
export function makeButtonBefore(parent, referenceNode, classes = [], innerHTML = "") {
const element = makeButtonElement(classes, innerHTML);
parent.insertBefore(element, referenceNode);
return element;
}
/**
* Removes all children of the given element
* @param {Element} elem

View File

@ -47,10 +47,16 @@ export class AutomaticSave {
return;
}
const saveInterval = this.root.app.settings.getAutosaveIntervalSeconds();
if (!saveInterval) {
// Disabled
return;
}
// Check when the last save was, but make sure that if it fails, we don't spam
const lastSaveTime = Math_max(this.lastSaveAttempt, this.root.savegame.getRealLastUpdate());
let secondsSinceLastSave = (Date.now() - lastSaveTime) / 1000.0;
const secondsSinceLastSave = (Date.now() - lastSaveTime) / 1000.0;
let shouldSave = false;
switch (this.saveImportance) {
@ -61,7 +67,7 @@ export class AutomaticSave {
case enumSavePriority.regular:
// Could determine if there is a good / bad point here
shouldSave = secondsSinceLastSave > MIN_INTERVAL_SECS;
shouldSave = secondsSinceLastSave > saveInterval;
break;
default:

View File

@ -22,6 +22,10 @@ export class MetaBeltBaseBuilding extends MetaBuilding {
return "#777";
}
getHasDirectionLockAvailable() {
return true;
}
/**
* @param {GameRoot} root
* @param {string} variant

View File

@ -11,7 +11,7 @@ import { T } from "../../translations";
import { formatItemsPerSecond } from "../../core/utils";
/** @enum {string} */
export const enumPainterVariants = { double: "double", quad: "quad" };
export const enumPainterVariants = { mirrored: "mirrored", double: "double", quad: "quad" };
export class MetaPainterBuilding extends MetaBuilding {
constructor() {
@ -21,6 +21,7 @@ export class MetaPainterBuilding extends MetaBuilding {
getDimensions(variant) {
switch (variant) {
case defaultBuildingVariant:
case enumPainterVariants.mirrored:
return new Vector(2, 1);
case enumPainterVariants.double:
return new Vector(2, 2);
@ -42,7 +43,8 @@ export class MetaPainterBuilding extends MetaBuilding {
*/
getAdditionalStatistics(root, variant) {
switch (variant) {
case defaultBuildingVariant: {
case defaultBuildingVariant:
case enumPainterVariants.mirrored: {
const speed = root.hubGoals.getProcessorBaseSpeed(enumItemProcessorTypes.painter);
return [[T.ingame.buildingPlacement.infoTexts.speed, formatItemsPerSecond(speed)]];
}
@ -61,7 +63,7 @@ export class MetaPainterBuilding extends MetaBuilding {
* @param {GameRoot} root
*/
getAvailableVariants(root) {
let variants = [defaultBuildingVariant];
let variants = [defaultBuildingVariant, enumPainterVariants.mirrored];
if (root.hubGoals.isRewardUnlocked(enumHubGoalRewards.reward_painter_double)) {
variants.push(enumPainterVariants.double);
}
@ -116,7 +118,8 @@ export class MetaPainterBuilding extends MetaBuilding {
*/
updateVariants(entity, rotationVariant, variant) {
switch (variant) {
case defaultBuildingVariant: {
case defaultBuildingVariant:
case enumPainterVariants.mirrored: {
entity.components.ItemAcceptor.setSlots([
{
pos: new Vector(0, 0),
@ -125,7 +128,9 @@ export class MetaPainterBuilding extends MetaBuilding {
},
{
pos: new Vector(1, 0),
directions: [enumDirection.top],
directions: [
variant === defaultBuildingVariant ? enumDirection.top : enumDirection.bottom,
],
filter: enumItemAcceptorItemFilter.color,
},
]);

View File

@ -8,7 +8,7 @@ import {
performanceNow,
} from "../core/builtins";
import { clickDetectorGlobals } from "../core/click_detector";
import { globalConfig } from "../core/config";
import { globalConfig, SUPPORT_TOUCH } from "../core/config";
import { createLogger } from "../core/logging";
import { Rectangle } from "../core/rectangle";
import { Signal, STOP_PROPAGATION } from "../core/signal";
@ -28,6 +28,7 @@ const velocitySmoothing = 0.5;
const velocityFade = 0.98;
const velocityStrength = 0.4;
const velocityMax = 20;
const ticksBeforeErasingVelocity = 10;
/**
* @enum {string}
@ -58,6 +59,8 @@ export class Camera extends BasicSerializableObject {
// Input handling
this.currentlyMoving = false;
this.lastMovingPosition = null;
this.lastMovingPositionLastTick = null;
this.numTicksStandingStill = null;
this.cameraUpdateTimeBucket = 0.0;
this.didMoveSinceTouchStart = false;
this.currentlyPinching = false;
@ -312,32 +315,36 @@ export class Camera extends BasicSerializableObject {
this.eventListenerMouseMove = this.onMouseMove.bind(this);
this.eventListenerMouseUp = this.onMouseUp.bind(this);
this.root.canvas.addEventListener("touchstart", this.eventListenerTouchStart);
this.root.canvas.addEventListener("touchend", this.eventListenerTouchEnd);
this.root.canvas.addEventListener("touchcancel", this.eventListenerTouchEnd);
this.root.canvas.addEventListener("touchmove", this.eventListenerTouchMove);
if (SUPPORT_TOUCH) {
this.root.canvas.addEventListener("touchstart", this.eventListenerTouchStart);
this.root.canvas.addEventListener("touchend", this.eventListenerTouchEnd);
this.root.canvas.addEventListener("touchcancel", this.eventListenerTouchEnd);
this.root.canvas.addEventListener("touchmove", this.eventListenerTouchMove);
}
this.root.canvas.addEventListener("wheel", this.eventListenerMousewheel);
this.root.canvas.addEventListener("mousedown", this.eventListenerMouseDown);
this.root.canvas.addEventListener("mousemove", this.eventListenerMouseMove);
this.root.canvas.addEventListener("mouseup", this.eventListenerMouseUp);
this.root.canvas.addEventListener("mouseout", this.eventListenerMouseUp);
window.addEventListener("mouseup", this.eventListenerMouseUp);
// this.root.canvas.addEventListener("mouseout", this.eventListenerMouseUp);
}
/**
* Cleans up all event listeners
*/
cleanup() {
this.root.canvas.removeEventListener("touchstart", this.eventListenerTouchStart);
this.root.canvas.removeEventListener("touchend", this.eventListenerTouchEnd);
this.root.canvas.removeEventListener("touchcancel", this.eventListenerTouchEnd);
this.root.canvas.removeEventListener("touchmove", this.eventListenerTouchMove);
if (SUPPORT_TOUCH) {
this.root.canvas.removeEventListener("touchstart", this.eventListenerTouchStart);
this.root.canvas.removeEventListener("touchend", this.eventListenerTouchEnd);
this.root.canvas.removeEventListener("touchcancel", this.eventListenerTouchEnd);
this.root.canvas.removeEventListener("touchmove", this.eventListenerTouchMove);
}
this.root.canvas.removeEventListener("wheel", this.eventListenerMousewheel);
this.root.canvas.removeEventListener("mousedown", this.eventListenerMouseDown);
this.root.canvas.removeEventListener("mousemove", this.eventListenerMouseMove);
this.root.canvas.removeEventListener("mouseup", this.eventListenerMouseUp);
this.root.canvas.removeEventListener("mouseout", this.eventListenerMouseUp);
window.removeEventListener("mouseup", this.eventListenerMouseUp);
// this.root.canvas.removeEventListener("mouseout", this.eventListenerMouseUp);
}
/**
@ -663,6 +670,8 @@ export class Camera extends BasicSerializableObject {
this.touchPostMoveVelocity = new Vector(0, 0);
this.currentlyMoving = true;
this.lastMovingPosition = pos;
this.lastMovingPositionLastTick = null;
this.numTicksStandingStill = 0;
this.didMoveSinceTouchStart = false;
}
@ -712,6 +721,8 @@ export class Camera extends BasicSerializableObject {
this.currentlyMoving = false;
this.currentlyPinching = false;
this.lastMovingPosition = null;
this.lastMovingPositionLastTick = null;
this.numTicksStandingStill = 0;
this.lastPinchPositions = null;
this.userInteraction.dispatch(USER_INTERACT_TOUCHEND);
this.didMoveSinceTouchStart = false;
@ -809,6 +820,23 @@ export class Camera extends BasicSerializableObject {
this.touchPostMoveVelocity = this.touchPostMoveVelocity.multiplyScalar(velocityFade);
// Check if the camera is being dragged but standing still: if not, zero out `touchPostMoveVelocity`.
if (this.currentlyMoving && this.desiredCenter === null) {
if (
this.lastMovingPositionLastTick !== null &&
this.lastMovingPositionLastTick.equalsEpsilon(this.lastMovingPosition)
) {
this.numTicksStandingStill++;
} else {
this.numTicksStandingStill = 0;
}
this.lastMovingPositionLastTick = this.lastMovingPosition.copy();
if (this.numTicksStandingStill >= ticksBeforeErasingVelocity) {
this.touchPostMoveVelocity.x = 0;
this.touchPostMoveVelocity.y = 0;
}
}
// Check influence of past points
if (!this.currentlyMoving && !this.currentlyPinching) {
const len = this.touchPostMoveVelocity.length();
@ -885,24 +913,28 @@ export class Camera extends BasicSerializableObject {
let forceY = 0;
const actionMapper = this.root.keyMapper;
if (actionMapper.getBinding(KEYMAPPINGS.navigation.mapMoveUp).isCurrentlyPressed()) {
if (actionMapper.getBinding(KEYMAPPINGS.navigation.mapMoveUp).pressed) {
forceY -= 1;
}
if (actionMapper.getBinding(KEYMAPPINGS.navigation.mapMoveDown).isCurrentlyPressed()) {
if (actionMapper.getBinding(KEYMAPPINGS.navigation.mapMoveDown).pressed) {
forceY += 1;
}
if (actionMapper.getBinding(KEYMAPPINGS.navigation.mapMoveLeft).isCurrentlyPressed()) {
if (actionMapper.getBinding(KEYMAPPINGS.navigation.mapMoveLeft).pressed) {
forceX -= 1;
}
if (actionMapper.getBinding(KEYMAPPINGS.navigation.mapMoveRight).isCurrentlyPressed()) {
if (actionMapper.getBinding(KEYMAPPINGS.navigation.mapMoveRight).pressed) {
forceX += 1;
}
this.center.x += moveAmount * forceX * this.root.app.settings.getMovementSpeed();
this.center.y += moveAmount * forceY * this.root.app.settings.getMovementSpeed();
let movementSpeed =
this.root.app.settings.getMovementSpeed() *
(actionMapper.getBinding(KEYMAPPINGS.navigation.mapMoveFaster).pressed ? 4 : 1);
this.center.x += moveAmount * forceX * movementSpeed;
this.center.y += moveAmount * forceY * movementSpeed;
}
}
}

View File

@ -1,70 +0,0 @@
import { STOP_PROPAGATION } from "../core/signal";
import { GameRoot } from "./root";
import { ClickDetector } from "../core/click_detector";
import { createLogger } from "../core/logging";
const logger = createLogger("canvas_click_interceptor");
export class CanvasClickInterceptor {
/**
* @param {GameRoot} root
*/
constructor(root) {
this.root = root;
this.root.signals.postLoadHook.add(this.initialize, this);
this.root.signals.aboutToDestruct.add(this.cleanup, this);
/** @type {Array<object>} */
this.interceptors = [];
}
initialize() {
this.clickDetector = new ClickDetector(this.root.canvas, {
applyCssClass: null,
captureTouchmove: false,
targetOnly: true,
preventDefault: true,
maxDistance: 13,
clickSound: null,
});
this.clickDetector.click.add(this.onCanvasClick, this);
this.clickDetector.rightClick.add(this.onCanvasRightClick, this);
if (this.root.hud.parts.buildingPlacer) {
this.interceptors.push(this.root.hud.parts.buildingPlacer);
}
logger.log("Registered", this.interceptors.length, "interceptors");
}
cleanup() {
if (this.clickDetector) {
this.clickDetector.cleanup();
}
this.interceptors = [];
}
onCanvasClick(position, event, cancelAction = false) {
if (!this.root.gameInitialized) {
logger.warn("Skipping click outside of game initiaization!");
return;
}
if (this.root.hud.hasBlockingOverlayOpen()) {
return;
}
for (let i = 0; i < this.interceptors.length; ++i) {
const interceptor = this.interceptors[i];
if (interceptor.onCanvasClick(position, cancelAction) === STOP_PROPAGATION) {
// log(this, "Interceptor", interceptor.constructor.name, "catched click");
break;
}
}
}
onCanvasRightClick(position, event) {
this.onCanvasClick(position, event, true);
}
}

View File

@ -64,7 +64,7 @@ export class BeltComponent extends Component {
/**
* Returns if the belt can currently accept an item from the given direction
*/
canAcceptItem(leftoverProgress = 0.0) {
canAcceptItem() {
const firstItem = this.sortedItems[0];
if (!firstItem) {
return true;

View File

@ -20,6 +20,14 @@ export const enumItemAcceptorItemFilter = {
* filter?: enumItemAcceptorItemFilter
* }} ItemAcceptorSlot */
/**
* Contains information about a slot plus its location
* @typedef {{
* slot: ItemAcceptorSlot,
* index: number,
* acceptedDirection: enumDirection
* }} ItemAcceptorLocatedSlot */
export class ItemAcceptorComponent extends Component {
static getId() {
return "ItemAcceptor";
@ -164,11 +172,7 @@ export class ItemAcceptorComponent extends Component {
* Tries to find a slot which accepts the current item
* @param {Vector} targetLocalTile
* @param {enumDirection} fromLocalDirection
* @returns {{
* slot: ItemAcceptorSlot,
* index: number,
* acceptedDirection: enumDirection
* }|null}
* @returns {ItemAcceptorLocatedSlot|null}
*/
findMatchingSlot(targetLocalTile, fromLocalDirection) {
// We need to invert our direction since the acceptor specifies *from* which direction

View File

@ -12,6 +12,7 @@ export class MinerComponent extends Component {
}
static getSchema() {
// cachedMinedItem is not serialized.
return {
lastMiningTime: types.ufloat,
chainable: types.bool,
@ -25,8 +26,6 @@ export class MinerComponent extends Component {
});
}
/**
*/
constructor({ chainable = false }) {
super();
this.lastMiningTime = 0;
@ -38,6 +37,11 @@ export class MinerComponent extends Component {
* @type {Array<BaseItem>}
*/
this.itemChainBuffer = [];
/**
* @type {BaseItem}
*/
this.cachedMinedItem = null;
}
/**

View File

@ -17,7 +17,6 @@ import { SavegameSerializer } from "../savegame/savegame_serializer";
import { AutomaticSave } from "./automatic_save";
import { MetaHubBuilding } from "./buildings/hub";
import { Camera } from "./camera";
import { CanvasClickInterceptor } from "./canvas_click_interceptor";
import { EntityManager } from "./entity_manager";
import { GameSystemManager } from "./game_system_manager";
import { HubGoals } from "./hub_goals";
@ -98,7 +97,6 @@ export class GameCore {
root.logic = new GameLogic(root);
root.hud = new GameHUD(root);
root.time = new GameTime(root);
root.canvasClickInterceptor = new CanvasClickInterceptor(root);
root.automaticSave = new AutomaticSave(root);
root.soundProxy = new SoundProxy(root);

View File

@ -92,6 +92,9 @@ export class GameSystemManager {
add("staticMapEntities", StaticMapEntitySystem);
// IMPORTANT: Must be after belt system since belt system can change the
// orientation of an entity after it is placed -> the item acceptor cache
// then would be invalid
add("itemAcceptor", ItemAcceptorSystem);
logger.log("📦 There are", this.systemUpdateOrder.length, "game systems");

View File

@ -34,6 +34,7 @@ import { HUDPartTutorialHints } from "./parts/tutorial_hints";
import { HUDWaypoints } from "./parts/waypoints";
import { HUDInteractiveTutorial } from "./parts/interactive_tutorial";
import { HUDScreenshotExporter } from "./parts/screenshot_exporter";
import { Entity } from "../entity";
export class GameHUD {
/**
@ -58,7 +59,6 @@ export class GameHUD {
shop: new HUDShop(this.root),
statistics: new HUDStatistics(this.root),
waypoints: new HUDWaypoints(this.root),
vignetteOverlay: new HUDVignetteOverlay(this.root),
// Must always exist
pinnedShapes: new HUDPinnedShapes(this.root),
@ -90,11 +90,16 @@ export class GameHUD {
if (IS_DEMO) {
this.parts.watermark = new HUDWatermark(this.root);
}
if (this.root.app.settings.getAllSettings().offerHints) {
this.parts.tutorialHints = new HUDPartTutorialHints(this.root);
this.parts.interactiveTutorial = new HUDInteractiveTutorial(this.root);
}
if (this.root.app.settings.getAllSettings().vignette) {
this.parts.vignetteOverlay = new HUDVignetteOverlay(this.root);
}
const frag = document.createDocumentFragment();
for (const key in this.parts) {
this.parts[key].createElements(frag);

View File

@ -176,6 +176,7 @@ export class Blueprint {
tryPlace(root, tile) {
return root.logic.performBulkOperation(() => {
let anyPlaced = false;
const beltsToRegisterLater = [];
for (let i = 0; i < this.entities.length; ++i) {
let placeable = true;
const entity = this.entities[i];
@ -202,10 +203,10 @@ export class Blueprint {
"Can not delete entity for blueprint"
);
if (!root.logic.tryDeleteBuilding(contents)) {
logger.error(
assertAlways(
false,
"Building has replaceable component but is also unremovable in blueprint"
);
return false;
}
}
}
@ -215,10 +216,22 @@ export class Blueprint {
clone.components.StaticMapEntity.origin.addInplace(tile);
root.map.placeStaticEntity(clone);
root.entityMgr.registerEntity(clone);
// Registering a belt immediately triggers a recalculation of surrounding belt
// directions, which is no good when not all belts have been placed. To resolve
// this, only register belts after all entities have been placed.
if (!clone.components.Belt) {
root.entityMgr.registerEntity(clone);
} else {
beltsToRegisterLater.push(clone);
}
anyPlaced = true;
}
}
for (let i = 0; i < beltsToRegisterLater.length; i++) {
root.entityMgr.registerEntity(beltsToRegisterLater[i]);
}
return anyPlaced;
});
}

View File

@ -1,15 +1,15 @@
import { DrawParameters } from "../../../core/draw_parameters";
import { STOP_PROPAGATION } from "../../../core/signal";
import { TrackedState } from "../../../core/tracked_state";
import { makeDiv } from "../../../core/utils";
import { Vector } from "../../../core/vector";
import { T } from "../../../translations";
import { enumMouseButton } from "../../camera";
import { KEYMAPPINGS } from "../../key_action_mapper";
import { BaseHUDPart } from "../base_hud_part";
import { Blueprint } from "./blueprint";
import { makeDiv } from "../../../core/utils";
import { DynamicDomAttach } from "../dynamic_dom_attach";
import { blueprintShape } from "../../upgrades";
import { T } from "../../../translations";
import { BaseHUDPart } from "../base_hud_part";
import { DynamicDomAttach } from "../dynamic_dom_attach";
import { Blueprint } from "./blueprint";
export class HUDBlueprintPlacer extends BaseHUDPart {
createElements(parent) {
@ -34,9 +34,7 @@ export class HUDBlueprintPlacer extends BaseHUDPart {
const keyActionMapper = this.root.keyMapper;
keyActionMapper.getBinding(KEYMAPPINGS.general.back).add(this.abortPlacement, this);
keyActionMapper
.getBinding(KEYMAPPINGS.placement.abortBuildingPlacement)
.add(this.abortPlacement, this);
keyActionMapper.getBinding(KEYMAPPINGS.placement.pipette).add(this.abortPlacement, this);
keyActionMapper.getBinding(KEYMAPPINGS.placement.rotateWhilePlacing).add(this.rotateBlueprint, this);
keyActionMapper.getBinding(KEYMAPPINGS.massSelect.pasteLastBlueprint).add(this.pasteBlueprint, this);
@ -62,10 +60,9 @@ export class HUDBlueprintPlacer extends BaseHUDPart {
}
update() {
this.domAttach.update(this.currentBlueprint.get());
this.trackedCanAfford.set(
this.currentBlueprint.get() && this.currentBlueprint.get().canAfford(this.root)
);
const currentBlueprint = this.currentBlueprint.get();
this.domAttach.update(currentBlueprint && currentBlueprint.getCost() > 0);
this.trackedCanAfford.set(currentBlueprint && currentBlueprint.canAfford(this.root));
}
/**
@ -108,7 +105,7 @@ export class HUDBlueprintPlacer extends BaseHUDPart {
this.root.hubGoals.takeShapeByKey(blueprintShape, cost);
// This actually feels weird
// if (!this.root.keyMapper.getBinding(KEYMAPPINGS.placementModifiers.placeMultiple).isCurrentlyPressed()) {
// if (!this.root.keyMapper.getBinding(KEYMAPPINGS.placementModifiers.placeMultiple).pressed) {
// this.currentBlueprint.set(null);
// }
}
@ -133,11 +130,7 @@ export class HUDBlueprintPlacer extends BaseHUDPart {
rotateBlueprint() {
if (this.currentBlueprint.get()) {
if (
this.root.keyMapper
.getBinding(KEYMAPPINGS.placement.rotateInverseModifier)
.isCurrentlyPressed()
) {
if (this.root.keyMapper.getBinding(KEYMAPPINGS.placement.rotateInverseModifier).pressed) {
this.currentBlueprint.get().rotateCcw();
} else {
this.currentBlueprint.get().rotateCw();

View File

@ -1,85 +1,26 @@
import { Math_abs, Math_degrees, Math_radians } from "../../../core/builtins";
import { Math_radians } from "../../../core/builtins";
import { globalConfig } from "../../../core/config";
import { DrawParameters } from "../../../core/draw_parameters";
import { drawRotatedSprite } from "../../../core/draw_utils";
import { Loader } from "../../../core/loader";
import { STOP_PROPAGATION } from "../../../core/signal";
import { TrackedState } from "../../../core/tracked_state";
import { makeDiv, removeAllChildren } from "../../../core/utils";
import { makeDiv, removeAllChildren, pulseAnimation, clamp } from "../../../core/utils";
import {
enumDirectionToAngle,
enumDirectionToVector,
enumInvertedDirections,
Vector,
} from "../../../core/vector";
import { enumMouseButton } from "../../camera";
import { StaticMapEntityComponent } from "../../components/static_map_entity";
import { Entity } from "../../entity";
import { defaultBuildingVariant, MetaBuilding } from "../../meta_building";
import { BaseHUDPart } from "../base_hud_part";
import { DynamicDomAttach } from "../dynamic_dom_attach";
import { T } from "../../../translations";
import { KEYMAPPINGS } from "../../key_action_mapper";
import { defaultBuildingVariant } from "../../meta_building";
import { THEME } from "../../theme";
import { DynamicDomAttach } from "../dynamic_dom_attach";
import { HUDBuildingPlacerLogic } from "./building_placer_logic";
export class HUDBuildingPlacer extends BaseHUDPart {
initialize() {
/** @type {TypedTrackedState<MetaBuilding?>} */
this.currentMetaBuilding = new TrackedState(this.onSelectedMetaBuildingChanged, this);
this.currentBaseRotation = 0;
/** @type {Entity} */
this.fakeEntity = null;
const keyActionMapper = this.root.keyMapper;
keyActionMapper
.getBinding(KEYMAPPINGS.placement.abortBuildingPlacement)
.add(this.abortPlacement, this);
keyActionMapper.getBinding(KEYMAPPINGS.general.back).add(this.abortPlacement, this);
keyActionMapper.getBinding(KEYMAPPINGS.placement.rotateWhilePlacing).add(this.tryRotate, this);
keyActionMapper.getBinding(KEYMAPPINGS.placement.cycleBuildingVariants).add(this.cycleVariants, this);
this.root.hud.signals.buildingsSelectedForCopy.add(this.abortPlacement, this);
this.root.hud.signals.pasteBlueprintRequested.add(this.abortPlacement, this);
this.domAttach = new DynamicDomAttach(this.root, this.element, {});
this.root.camera.downPreHandler.add(this.onMouseDown, this);
this.root.camera.movePreHandler.add(this.onMouseMove, this);
this.root.camera.upPostHandler.add(this.abortDragging, this);
this.currentlyDragging = false;
this.currentVariant = new TrackedState(this.rerenderVariants, this);
this.variantsAttach = new DynamicDomAttach(this.root, this.variantsElement, {});
/**
* Whether we are currently drag-deleting
*/
this.currentlyDeleting = false;
/**
* Stores which variants for each building we prefer, this is based on what
* the user last selected
*/
this.preferredVariants = {};
/**
* The tile we last dragged onto
* @type {Vector}
* */
this.lastDragTile = null;
/**
* The tile we initially dragged from
* @type {Vector}
*/
this.initialDragTile = null;
this.root.signals.storyGoalCompleted.add(this.rerenderVariants, this);
this.root.signals.upgradePurchased.add(this.rerenderVariants, this);
}
export class HUDBuildingPlacer extends HUDBuildingPlacerLogic {
/**
* @param {HTMLElement} parent
*/
createElements(parent) {
this.element = makeDiv(parent, "ingame_HUD_PlacementHints", [], ``);
@ -97,183 +38,24 @@ export class HUDBuildingPlacer extends BaseHUDPart {
this.buildingInfoElements.tutorialImage = makeDiv(this.element, null, ["buildingImage"]);
this.variantsElement = makeDiv(parent, "ingame_HUD_PlacerVariants");
const compact = this.root.app.settings.getAllSettings().compactBuildingInfo;
this.element.classList.toggle("compact", compact);
this.variantsElement.classList.toggle("compact", compact);
}
abortPlacement() {
if (this.currentMetaBuilding.get()) {
this.currentMetaBuilding.set(null);
return STOP_PROPAGATION;
}
}
initialize() {
super.initialize();
/**
* mouse down pre handler
* @param {Vector} pos
* @param {enumMouseButton} button
*/
onMouseDown(pos, button) {
if (this.root.camera.getIsMapOverlayActive()) {
return;
}
// Bind to signals
this.signals.variantChanged.add(this.rerenderVariants, this);
// Placement
if (button === enumMouseButton.left && this.currentMetaBuilding.get()) {
this.currentlyDragging = true;
this.currentlyDeleting = false;
this.lastDragTile = this.root.camera.screenToWorld(pos).toTileSpace();
this.domAttach = new DynamicDomAttach(this.root, this.element, {});
this.variantsAttach = new DynamicDomAttach(this.root, this.variantsElement, {});
// Place initial building
this.tryPlaceCurrentBuildingAt(this.lastDragTile);
this.currentInterpolatedCornerTile = new Vector();
return STOP_PROPAGATION;
}
// Deletion
if (button === enumMouseButton.right && !this.currentMetaBuilding.get()) {
this.currentlyDragging = true;
this.currentlyDeleting = true;
this.lastDragTile = this.root.camera.screenToWorld(pos).toTileSpace();
this.currentMetaBuilding.set(null);
return STOP_PROPAGATION;
}
}
/**
* mouse move pre handler
* @param {Vector} pos
*/
onMouseMove(pos) {
if (this.root.camera.getIsMapOverlayActive()) {
return;
}
const metaBuilding = this.currentMetaBuilding.get();
if ((metaBuilding || this.currentlyDeleting) && this.lastDragTile) {
const oldPos = this.lastDragTile;
const newPos = this.root.camera.screenToWorld(pos).toTileSpace();
if (this.root.camera.desiredCenter) {
// Camera is moving
this.lastDragTile = newPos;
return;
}
if (!oldPos.equals(newPos)) {
if (
metaBuilding &&
metaBuilding.getRotateAutomaticallyWhilePlacing(this.currentVariant.get()) &&
!this.root.keyMapper
.getBinding(KEYMAPPINGS.placementModifiers.placementDisableAutoOrientation)
.isCurrentlyPressed()
) {
const delta = newPos.sub(oldPos);
const angleDeg = Math_degrees(delta.angle());
this.currentBaseRotation = (Math.round(angleDeg / 90) * 90 + 360) % 360;
// Holding alt inverts the placement
if (
this.root.keyMapper
.getBinding(KEYMAPPINGS.placementModifiers.placeInverse)
.isCurrentlyPressed()
) {
this.currentBaseRotation = (180 + this.currentBaseRotation) % 360;
}
}
// - Using bresenhams algorithmus
let x0 = oldPos.x;
let y0 = oldPos.y;
let x1 = newPos.x;
let y1 = newPos.y;
var dx = Math_abs(x1 - x0);
var dy = Math_abs(y1 - y0);
var sx = x0 < x1 ? 1 : -1;
var sy = y0 < y1 ? 1 : -1;
var err = dx - dy;
while (this.currentlyDeleting || this.currentMetaBuilding.get()) {
if (this.currentlyDeleting) {
const contents = this.root.map.getTileContentXY(x0, y0);
if (contents && !contents.queuedForDestroy && !contents.destroyed) {
this.root.logic.tryDeleteBuilding(contents);
}
} else {
this.tryPlaceCurrentBuildingAt(new Vector(x0, y0));
}
if (x0 === x1 && y0 === y1) break;
var e2 = 2 * err;
if (e2 > -dy) {
err -= dy;
x0 += sx;
}
if (e2 < dx) {
err += dx;
y0 += sy;
}
}
}
this.lastDragTile = newPos;
return STOP_PROPAGATION;
}
}
update() {
// ALways update since the camera might have moved
const mousePos = this.root.app.mousePosition;
if (mousePos) {
this.onMouseMove(mousePos);
}
}
/**
* aborts any dragging op
*/
abortDragging() {
this.currentlyDragging = true;
this.currentlyDeleting = false;
this.lastDragTile = null;
}
/**
*
* @param {MetaBuilding} metaBuilding
*/
startSelection(metaBuilding) {
this.currentMetaBuilding.set(metaBuilding);
}
/**
* @param {MetaBuilding} metaBuilding
*/
onSelectedMetaBuildingChanged(metaBuilding) {
this.abortDragging();
this.root.hud.signals.selectedPlacementBuildingChanged.dispatch(metaBuilding);
if (metaBuilding) {
const variant = this.preferredVariants[metaBuilding.getId()] || defaultBuildingVariant;
this.currentVariant.set(variant);
this.fakeEntity = new Entity(null);
metaBuilding.setupEntityComponents(this.fakeEntity, null);
this.fakeEntity.addComponent(
new StaticMapEntityComponent({
origin: new Vector(0, 0),
rotation: 0,
tileSize: metaBuilding.getDimensions(this.currentVariant.get()).copy(),
blueprintSpriteKey: "",
})
);
metaBuilding.updateVariants(this.fakeEntity, 0, this.currentVariant.get());
} else {
this.fakeEntity = null;
}
// Since it depends on both, rerender twice
this.rerenderVariants();
this.lockIndicatorSprite = Loader.getSprite("sprites/misc/lock_direction_indicator.png");
}
/**
@ -368,147 +150,6 @@ export class HUDBuildingPlacer extends BaseHUDPart {
}
}
/**
* Cycles through the variants
*/
cycleVariants() {
const metaBuilding = this.currentMetaBuilding.get();
if (!metaBuilding) {
this.currentVariant.set(defaultBuildingVariant);
} else {
const availableVariants = metaBuilding.getAvailableVariants(this.root);
const index = availableVariants.indexOf(this.currentVariant.get());
assert(
index >= 0,
"Current variant was invalid: " + this.currentVariant.get() + " out of " + availableVariants
);
const newIndex = (index + 1) % availableVariants.length;
const newVariant = availableVariants[newIndex];
this.currentVariant.set(newVariant);
this.preferredVariants[metaBuilding.getId()] = newVariant;
}
}
/**
* Tries to rotate
*/
tryRotate() {
const selectedBuilding = this.currentMetaBuilding.get();
if (selectedBuilding) {
if (
this.root.keyMapper
.getBinding(KEYMAPPINGS.placement.rotateInverseModifier)
.isCurrentlyPressed()
) {
this.currentBaseRotation = (this.currentBaseRotation + 270) % 360;
} else {
this.currentBaseRotation = (this.currentBaseRotation + 90) % 360;
}
const staticComp = this.fakeEntity.components.StaticMapEntity;
staticComp.rotation = this.currentBaseRotation;
}
}
/**
* Tries to delete the building under the mouse
*/
deleteBelowCursor() {
const mousePosition = this.root.app.mousePosition;
if (!mousePosition) {
// Not on screen
return;
}
const worldPos = this.root.camera.screenToWorld(mousePosition);
const tile = worldPos.toTileSpace();
const contents = this.root.map.getTileContent(tile);
if (contents) {
this.root.logic.tryDeleteBuilding(contents);
}
}
/**
* Canvas click handler
* @param {Vector} mousePos
* @param {boolean} cancelAction
*/
onCanvasClick(mousePos, cancelAction = false) {
if (cancelAction) {
if (this.currentMetaBuilding.get()) {
this.currentMetaBuilding.set(null);
} else {
this.deleteBelowCursor();
}
return STOP_PROPAGATION;
}
if (!this.currentMetaBuilding.get()) {
return;
}
return STOP_PROPAGATION;
}
/**
* Tries to place the current building at the given tile
* @param {Vector} tile
*/
tryPlaceCurrentBuildingAt(tile) {
if (this.root.camera.zoomLevel < globalConfig.mapChunkOverviewMinZoom) {
// Dont allow placing in overview mode
return;
}
// Transform to world space
const metaBuilding = this.currentMetaBuilding.get();
const { rotation, rotationVariant } = metaBuilding.computeOptimalDirectionAndRotationVariantAtTile(
this.root,
tile,
this.currentBaseRotation,
this.currentVariant.get()
);
if (
this.root.logic.tryPlaceBuilding({
origin: tile,
rotation,
rotationVariant,
originalRotation: this.currentBaseRotation,
building: this.currentMetaBuilding.get(),
variant: this.currentVariant.get(),
})
) {
// Succesfully placed
if (
metaBuilding.getFlipOrientationAfterPlacement() &&
!this.root.keyMapper
.getBinding(KEYMAPPINGS.placementModifiers.placementDisableAutoOrientation)
.isCurrentlyPressed()
) {
this.currentBaseRotation = (180 + this.currentBaseRotation) % 360;
}
if (
!metaBuilding.getStayInPlacementMode() &&
!this.root.keyMapper
.getBinding(KEYMAPPINGS.placementModifiers.placeMultiple)
.isCurrentlyPressed() &&
!this.root.app.settings.getAllSettings().alwaysMultiplace
) {
// Stop placement
this.currentMetaBuilding.set(null);
}
return true;
} else {
return false;
}
}
/**
*
* @param {DrawParameters} parameters
@ -529,14 +170,28 @@ export class HUDBuildingPlacer extends BaseHUDPart {
return;
}
// Draw direction lock
if (this.isDirectionLockActive) {
this.drawDirectionLock(parameters);
} else {
this.drawRegularPlacement(parameters);
}
}
/**
* @param {DrawParameters} parameters
*/
drawRegularPlacement(parameters) {
const mousePosition = this.root.app.mousePosition;
if (!mousePosition) {
// Not on screen
return;
}
const metaBuilding = this.currentMetaBuilding.get();
const worldPos = this.root.camera.screenToWorld(mousePosition);
const tile = worldPos.toTileSpace();
const mouseTile = worldPos.toTileSpace();
// Compute best rotation variant
const {
@ -545,7 +200,7 @@ export class HUDBuildingPlacer extends BaseHUDPart {
connectedEntities,
} = metaBuilding.computeOptimalDirectionAndRotationVariantAtTile(
this.root,
tile,
mouseTile,
this.currentBaseRotation,
this.currentVariant.get()
);
@ -558,7 +213,7 @@ export class HUDBuildingPlacer extends BaseHUDPart {
.getCenter()
.toWorldSpace();
const startWsPoint = tile.toWorldSpaceCenterOfTile();
const startWsPoint = mouseTile.toWorldSpaceCenterOfTile();
const startOffset = connectedWsPoint
.sub(startWsPoint)
@ -583,14 +238,14 @@ export class HUDBuildingPlacer extends BaseHUDPart {
// Synchronize rotation and origin
const staticComp = this.fakeEntity.components.StaticMapEntity;
staticComp.origin = tile;
staticComp.origin = mouseTile;
staticComp.rotation = rotation;
staticComp.tileSize = metaBuilding.getDimensions(this.currentVariant.get());
metaBuilding.updateVariants(this.fakeEntity, rotationVariant, this.currentVariant.get());
// Check if we could place the buildnig
const canBuild = this.root.logic.checkCanPlaceBuilding({
origin: tile,
origin: mouseTile,
rotation,
rotationVariant,
building: metaBuilding,
@ -627,7 +282,7 @@ export class HUDBuildingPlacer extends BaseHUDPart {
const previewSprite = metaBuilding.getBlueprintSprite(rotationVariant, this.currentVariant.get());
staticComp.origin = worldPos.divideScalar(globalConfig.tileSize).subScalars(0.5, 0.5);
staticComp.drawSpriteOnFullEntityBounds(parameters, previewSprite);
staticComp.origin = tile;
staticComp.origin = mouseTile;
// Draw ejectors
if (canBuild) {
@ -636,7 +291,63 @@ export class HUDBuildingPlacer extends BaseHUDPart {
}
/**
*
* @param {DrawParameters} parameters
*/
drawDirectionLock(parameters) {
const mousePosition = this.root.app.mousePosition;
if (!mousePosition) {
// Not on screen
return;
}
const mouseWorld = this.root.camera.screenToWorld(mousePosition);
const mouseTile = mouseWorld.toTileSpace();
parameters.context.fillStyle = THEME.map.directionLock;
parameters.context.strokeStyle = THEME.map.directionLockTrack;
parameters.context.lineWidth = 10;
parameters.context.beginCircle(mouseWorld.x, mouseWorld.y, 4);
parameters.context.fill();
if (this.lastDragTile) {
const startLine = this.lastDragTile.toWorldSpaceCenterOfTile();
const endLine = mouseTile.toWorldSpaceCenterOfTile();
const midLine = this.currentDirectionLockCorner.toWorldSpaceCenterOfTile();
parameters.context.beginCircle(startLine.x, startLine.y, 8);
parameters.context.fill();
parameters.context.beginPath();
parameters.context.moveTo(startLine.x, startLine.y);
parameters.context.lineTo(midLine.x, midLine.y);
parameters.context.lineTo(endLine.x, endLine.y);
parameters.context.stroke();
parameters.context.beginCircle(endLine.x, endLine.y, 5);
parameters.context.fill();
// Draw arrows
const path = this.computeDirectionLockPath();
for (let i = 0; i < path.length - 1; i += 1) {
const { rotation, tile } = path[i];
const worldPos = tile.toWorldSpaceCenterOfTile();
drawRotatedSprite({
parameters,
sprite: this.lockIndicatorSprite,
x: worldPos.x,
y: worldPos.y,
angle: Math_radians(rotation),
size: 12,
offsetY:
-globalConfig.halfTileSize -
clamp((this.root.time.now() * 1.5) % 1.0, 0, 1) * 1 * globalConfig.tileSize +
globalConfig.halfTileSize,
});
}
}
}
/**
* @param {DrawParameters} parameters
*/
drawMatchingAcceptorsAndEjectors(parameters) {

View File

@ -0,0 +1,690 @@
import { Math_abs, Math_degrees, Math_round } from "../../../core/builtins";
import { globalConfig } from "../../../core/config";
import { gMetaBuildingRegistry } from "../../../core/global_registries";
import { Signal, STOP_PROPAGATION } from "../../../core/signal";
import { TrackedState } from "../../../core/tracked_state";
import { Vector } from "../../../core/vector";
import { enumMouseButton } from "../../camera";
import { StaticMapEntityComponent } from "../../components/static_map_entity";
import { Entity } from "../../entity";
import { KEYMAPPINGS } from "../../key_action_mapper";
import { defaultBuildingVariant, MetaBuilding } from "../../meta_building";
import { BaseHUDPart } from "../base_hud_part";
/**
* Contains all logic for the building placer - this doesn't include the rendering
* of info boxes or drawing.
*/
export class HUDBuildingPlacerLogic extends BaseHUDPart {
/**
* Initializes the logic
* @see BaseHUDPart.initialize
*/
initialize() {
/**
* We use a fake entity to get information about how a building will look
* once placed
* @type {Entity}
*/
this.fakeEntity = null;
// Signals
this.signals = {
variantChanged: new Signal(),
draggingStarted: new Signal(),
};
/**
* The current building
* @type {TypedTrackedState<MetaBuilding?>}
*/
this.currentMetaBuilding = new TrackedState(this.onSelectedMetaBuildingChanged, this);
/**
* The current rotation
* @type {number}
*/
this.currentBaseRotation = 0;
/**
* Whether we are currently dragging
* @type {boolean}
*/
this.currentlyDragging = false;
/**
* Current building variant
* @type {TypedTrackedState<string>}
*/
this.currentVariant = new TrackedState(() => this.signals.variantChanged.dispatch());
/**
* Whether we are currently drag-deleting
* @type {boolean}
*/
this.currentlyDeleting = false;
/**
* Stores which variants for each building we prefer, this is based on what
* the user last selected
* @type {Object.<string, string>}
*/
this.preferredVariants = {};
/**
* The tile we last dragged from
* @type {Vector}
*/
this.lastDragTile = null;
/**
* The side for direction lock
* @type {number} (0|1)
*/
this.currentDirectionLockSide = 0;
this.initializeBindings();
}
/**
* Initializes all bindings
*/
initializeBindings() {
// KEYBINDINGS
const keyActionMapper = this.root.keyMapper;
keyActionMapper.getBinding(KEYMAPPINGS.placement.rotateWhilePlacing).add(this.tryRotate, this);
keyActionMapper.getBinding(KEYMAPPINGS.placement.cycleBuildingVariants).add(this.cycleVariants, this);
keyActionMapper
.getBinding(KEYMAPPINGS.placement.switchDirectionLockSide)
.add(this.switchDirectionLockSide, this);
keyActionMapper.getBinding(KEYMAPPINGS.general.back).add(this.abortPlacement, this);
keyActionMapper.getBinding(KEYMAPPINGS.placement.pipette).add(this.startPipette, this);
this.root.gameState.inputReciever.keyup.add(this.checkForDirectionLockSwitch, this);
// BINDINGS TO GAME EVENTS
this.root.hud.signals.buildingsSelectedForCopy.add(this.abortPlacement, this);
this.root.hud.signals.pasteBlueprintRequested.add(this.abortPlacement, this);
this.root.signals.storyGoalCompleted.add(() => this.signals.variantChanged.dispatch());
this.root.signals.upgradePurchased.add(() => this.signals.variantChanged.dispatch());
// MOUSE BINDINGS
this.root.camera.downPreHandler.add(this.onMouseDown, this);
this.root.camera.movePreHandler.add(this.onMouseMove, this);
this.root.camera.upPostHandler.add(this.onMouseUp, this);
}
/**
* Returns if the direction lock is currently active
* @returns {boolean}
*/
get isDirectionLockActive() {
const metaBuilding = this.currentMetaBuilding.get();
return (
metaBuilding &&
metaBuilding.getHasDirectionLockAvailable() &&
this.root.keyMapper.getBinding(KEYMAPPINGS.placementModifiers.lockBeltDirection).pressed
);
}
/**
* Returns the current direction lock corner, that is, the corner between
* mouse and original start point
* @returns {Vector|null}
*/
get currentDirectionLockCorner() {
const mousePosition = this.root.app.mousePosition;
if (!mousePosition) {
// Not on screen
return null;
}
if (!this.lastDragTile) {
// Haven't dragged yet
return null;
}
// Figure which points the line visits
const worldPos = this.root.camera.screenToWorld(mousePosition);
const mouseTile = worldPos.toTileSpace();
if (this.currentDirectionLockSide === 0) {
return new Vector(this.lastDragTile.x, mouseTile.y);
} else {
return new Vector(mouseTile.x, this.lastDragTile.y);
}
}
/**
* Aborts the placement
*/
abortPlacement() {
if (this.currentMetaBuilding.get()) {
this.currentMetaBuilding.set(null);
return STOP_PROPAGATION;
}
}
/**
* Aborts any dragging
*/
abortDragging() {
this.currentlyDragging = true;
this.currentlyDeleting = false;
this.initialPlacementVector = null;
this.lastDragTile = null;
}
/**
* @see BaseHUDPart.update
*/
update() {
// Always update since the camera might have moved
const mousePos = this.root.app.mousePosition;
if (mousePos) {
this.onMouseMove(mousePos);
}
}
/**
* Tries to rotate the current building
*/
tryRotate() {
const selectedBuilding = this.currentMetaBuilding.get();
if (selectedBuilding) {
if (this.root.keyMapper.getBinding(KEYMAPPINGS.placement.rotateInverseModifier).pressed) {
this.currentBaseRotation = (this.currentBaseRotation + 270) % 360;
} else {
this.currentBaseRotation = (this.currentBaseRotation + 90) % 360;
}
const staticComp = this.fakeEntity.components.StaticMapEntity;
staticComp.rotation = this.currentBaseRotation;
}
}
/**
* Tries to delete the building under the mouse
*/
deleteBelowCursor() {
const mousePosition = this.root.app.mousePosition;
if (!mousePosition) {
// Not on screen
return;
}
const worldPos = this.root.camera.screenToWorld(mousePosition);
const tile = worldPos.toTileSpace();
const contents = this.root.map.getTileContent(tile);
if (contents) {
this.root.logic.tryDeleteBuilding(contents);
}
}
/**
* Starts the pipette function
*/
startPipette() {
// Disable in overview
if (this.root.camera.getIsMapOverlayActive()) {
return;
}
const mousePosition = this.root.app.mousePosition;
if (!mousePosition) {
// Not on screen
return;
}
const worldPos = this.root.camera.screenToWorld(mousePosition);
const tile = worldPos.toTileSpace();
const contents = this.root.map.getTileContent(tile);
if (!contents) {
this.currentMetaBuilding.set(null);
return;
}
// Try to extract the building
const extracted = this.hack_reconstructMetaBuildingAndVariantFromBuilding(contents);
if (!extracted) {
this.currentMetaBuilding.set(null);
return;
}
this.currentMetaBuilding.set(extracted.metaBuilding);
this.currentVariant.set(extracted.variant);
this.currentBaseRotation = contents.components.StaticMapEntity.rotation;
// Make sure we selected something, and also make sure it's not a special entity
// if (contents && !contents.components.Unremovable) {
// }
}
/**
* HACK!
*
* This attempts to reconstruct the meta building and its variant from a given entity
* @param {Entity} entity
* @returns {{ metaBuilding: MetaBuilding, variant: string }}
*/
hack_reconstructMetaBuildingAndVariantFromBuilding(entity) {
if (entity.components.Hub) {
// Hub is not copyable
return null;
}
const matches = [];
const metaBuildings = gMetaBuildingRegistry.entries;
for (let i = 0; i < metaBuildings.length; ++i) {
const metaBuilding = metaBuildings[i];
const availableVariants = metaBuilding.getAvailableVariants(this.root);
checkVariant: for (let k = 0; k < availableVariants.length; ++k) {
const variant = availableVariants[k];
let unplaced = metaBuilding.createEntity({
root: this.root,
variant,
origin: new Vector(0, 0),
rotation: 0,
originalRotation: 0,
rotationVariant: 0,
});
// Compare if both entities share the same components
for (let component in entity.components) {
if ((entity.components[component] == null) !== (unplaced.components[component] == null)) {
continue checkVariant;
}
}
// Check for same item processor
if (
entity.components.ItemProcessor &&
entity.components.ItemProcessor.type != unplaced.components.ItemProcessor.type
) {
continue checkVariant;
}
// Check for underground belt
if (
entity.components.UndergroundBelt &&
entity.components.UndergroundBelt.tier != unplaced.components.UndergroundBelt.tier
) {
continue checkVariant;
}
// Check for same sprite key - except for underground belts
// since the sprite may vary here
if (
!entity.components.UndergroundBelt &&
entity.components.StaticMapEntity.spriteKey !=
unplaced.components.StaticMapEntity.spriteKey
) {
continue checkVariant;
}
matches.push({ metaBuilding, variant });
}
}
if (matches.length == 1) {
const staticEntity = entity.components.StaticMapEntity;
const key = staticEntity.spriteKey || staticEntity.blueprintSpriteKey;
assert(
key &&
key.includes(matches[0].metaBuilding.id) &&
(matches[0].variant === defaultBuildingVariant || key.includes(matches[0].variant))
);
return matches[0];
}
return null;
}
switchDirectionLockSide() {
this.currentDirectionLockSide = 1 - this.currentDirectionLockSide;
}
/**
* Checks if the direction lock key got released and if such, resets the placement
* @param {any} args
*/
checkForDirectionLockSwitch({ keyCode }) {
if (
keyCode ===
this.root.keyMapper.getBinding(KEYMAPPINGS.placementModifiers.lockBeltDirection).keyCode
) {
this.abortDragging();
}
}
/**
* Tries to place the current building at the given tile
* @param {Vector} tile
*/
tryPlaceCurrentBuildingAt(tile) {
if (this.root.camera.zoomLevel < globalConfig.mapChunkOverviewMinZoom) {
// Dont allow placing in overview mode
return;
}
const metaBuilding = this.currentMetaBuilding.get();
const { rotation, rotationVariant } = metaBuilding.computeOptimalDirectionAndRotationVariantAtTile(
this.root,
tile,
this.currentBaseRotation,
this.currentVariant.get()
);
const entity = this.root.logic.tryPlaceBuilding({
origin: tile,
rotation,
rotationVariant,
originalRotation: this.currentBaseRotation,
building: this.currentMetaBuilding.get(),
variant: this.currentVariant.get(),
});
if (entity) {
// Succesfully placed, find which entity we actually placed
this.root.signals.entityManuallyPlaced.dispatch(entity);
// Check if we should flip the orientation (used for tunnels)
if (
metaBuilding.getFlipOrientationAfterPlacement() &&
!this.root.keyMapper.getBinding(
KEYMAPPINGS.placementModifiers.placementDisableAutoOrientation
).pressed
) {
this.currentBaseRotation = (180 + this.currentBaseRotation) % 360;
}
// Check if we should stop placement
if (
!metaBuilding.getStayInPlacementMode() &&
!this.root.keyMapper.getBinding(KEYMAPPINGS.placementModifiers.placeMultiple).pressed &&
!this.root.app.settings.getAllSettings().alwaysMultiplace
) {
// Stop placement
this.currentMetaBuilding.set(null);
}
return true;
} else {
return false;
}
}
/**
* Cycles through the variants
*/
cycleVariants() {
const metaBuilding = this.currentMetaBuilding.get();
if (!metaBuilding) {
this.currentVariant.set(defaultBuildingVariant);
} else {
const availableVariants = metaBuilding.getAvailableVariants(this.root);
const index = availableVariants.indexOf(this.currentVariant.get());
assert(
index >= 0,
"Current variant was invalid: " + this.currentVariant.get() + " out of " + availableVariants
);
const newIndex = (index + 1) % availableVariants.length;
const newVariant = availableVariants[newIndex];
this.currentVariant.set(newVariant);
this.preferredVariants[metaBuilding.getId()] = newVariant;
}
}
/**
* Performs the direction locked placement between two points after
* releasing the mouse
*/
executeDirectionLockedPlacement() {
const path = this.computeDirectionLockPath();
this.root.logic.performBulkOperation(() => {
for (let i = 0; i < path.length; ++i) {
const { rotation, tile } = path[i];
this.currentBaseRotation = rotation;
this.tryPlaceCurrentBuildingAt(tile);
}
});
}
/**
* Finds the path which the current direction lock will use
* @returns {Array<{ tile: Vector, rotation: number }>}
*/
computeDirectionLockPath() {
const mousePosition = this.root.app.mousePosition;
if (!mousePosition) {
// Not on screen
return [];
}
let result = [];
// Figure which points the line visits
const worldPos = this.root.camera.screenToWorld(mousePosition);
const mouseTile = worldPos.toTileSpace();
const startTile = this.lastDragTile;
// Place from start to corner
const pathToCorner = this.currentDirectionLockCorner.sub(startTile);
const deltaToCorner = pathToCorner.normalize().round();
const lengthToCorner = Math_round(pathToCorner.length());
let currentPos = startTile.copy();
let rotation = (Math.round(Math_degrees(deltaToCorner.angle()) / 90) * 90 + 360) % 360;
if (lengthToCorner > 0) {
for (let i = 0; i < lengthToCorner; ++i) {
result.push({
tile: currentPos.copy(),
rotation,
});
currentPos.addInplace(deltaToCorner);
}
}
// Place from corner to end
const pathFromCorner = mouseTile.sub(this.currentDirectionLockCorner);
const deltaFromCorner = pathFromCorner.normalize().round();
const lengthFromCorner = Math_round(pathFromCorner.length());
if (lengthFromCorner > 0) {
rotation = (Math.round(Math_degrees(deltaFromCorner.angle()) / 90) * 90 + 360) % 360;
for (let i = 0; i < lengthFromCorner + 1; ++i) {
result.push({
tile: currentPos.copy(),
rotation,
});
currentPos.addInplace(deltaFromCorner);
}
} else {
// Finish last one
result.push({
tile: currentPos.copy(),
rotation,
});
}
return result;
}
/**
* Selects a given building
* @param {MetaBuilding} metaBuilding
*/
startSelection(metaBuilding) {
this.currentMetaBuilding.set(metaBuilding);
}
/**
* Called when the selected buildings changed
* @param {MetaBuilding} metaBuilding
*/
onSelectedMetaBuildingChanged(metaBuilding) {
this.abortDragging();
this.root.hud.signals.selectedPlacementBuildingChanged.dispatch(metaBuilding);
if (metaBuilding) {
const variant = this.preferredVariants[metaBuilding.getId()] || defaultBuildingVariant;
this.currentVariant.set(variant);
this.fakeEntity = new Entity(null);
metaBuilding.setupEntityComponents(this.fakeEntity, null);
this.fakeEntity.addComponent(
new StaticMapEntityComponent({
origin: new Vector(0, 0),
rotation: 0,
tileSize: metaBuilding.getDimensions(this.currentVariant.get()).copy(),
blueprintSpriteKey: "",
})
);
metaBuilding.updateVariants(this.fakeEntity, 0, this.currentVariant.get());
} else {
this.fakeEntity = null;
}
// Since it depends on both, rerender twice
this.signals.variantChanged.dispatch();
}
/**
* mouse down pre handler
* @param {Vector} pos
* @param {enumMouseButton} button
*/
onMouseDown(pos, button) {
if (this.root.camera.getIsMapOverlayActive()) {
// We do not allow dragging if the overlay is active
return;
}
const metaBuilding = this.currentMetaBuilding.get();
// Placement
if (button === enumMouseButton.left && metaBuilding) {
this.currentlyDragging = true;
this.currentlyDeleting = false;
this.lastDragTile = this.root.camera.screenToWorld(pos).toTileSpace();
// Place initial building, but only if direction lock is not active
if (!this.isDirectionLockActive) {
this.tryPlaceCurrentBuildingAt(this.lastDragTile);
}
return STOP_PROPAGATION;
}
// Deletion
if (button === enumMouseButton.right && !metaBuilding) {
this.currentlyDragging = true;
this.currentlyDeleting = true;
this.lastDragTile = this.root.camera.screenToWorld(pos).toTileSpace();
this.deleteBelowCursor();
return STOP_PROPAGATION;
}
// Cancel placement
if (button === enumMouseButton.right && metaBuilding) {
this.currentMetaBuilding.set(null);
}
}
/**
* mouse move pre handler
* @param {Vector} pos
*/
onMouseMove(pos) {
if (this.root.camera.getIsMapOverlayActive()) {
return;
}
// Check for direction lock
if (this.isDirectionLockActive) {
return;
}
const metaBuilding = this.currentMetaBuilding.get();
if ((metaBuilding || this.currentlyDeleting) && this.lastDragTile) {
const oldPos = this.lastDragTile;
let newPos = this.root.camera.screenToWorld(pos).toTileSpace();
// Check if camera is moving, since then we do nothing
if (this.root.camera.desiredCenter) {
this.lastDragTile = newPos;
return;
}
// Check if anything changed
if (!oldPos.equals(newPos)) {
// Automatic Direction
if (
metaBuilding &&
metaBuilding.getRotateAutomaticallyWhilePlacing(this.currentVariant.get()) &&
!this.root.keyMapper.getBinding(
KEYMAPPINGS.placementModifiers.placementDisableAutoOrientation
).pressed
) {
const delta = newPos.sub(oldPos);
const angleDeg = Math_degrees(delta.angle());
this.currentBaseRotation = (Math.round(angleDeg / 90) * 90 + 360) % 360;
// Holding alt inverts the placement
if (this.root.keyMapper.getBinding(KEYMAPPINGS.placementModifiers.placeInverse).pressed) {
this.currentBaseRotation = (180 + this.currentBaseRotation) % 360;
}
}
// bresenham
let x0 = oldPos.x;
let y0 = oldPos.y;
let x1 = newPos.x;
let y1 = newPos.y;
var dx = Math_abs(x1 - x0);
var dy = Math_abs(y1 - y0);
var sx = x0 < x1 ? 1 : -1;
var sy = y0 < y1 ? 1 : -1;
var err = dx - dy;
while (this.currentlyDeleting || this.currentMetaBuilding.get()) {
if (this.currentlyDeleting) {
const contents = this.root.map.getTileContentXY(x0, y0);
if (contents && !contents.queuedForDestroy && !contents.destroyed) {
this.root.logic.tryDeleteBuilding(contents);
}
} else {
this.tryPlaceCurrentBuildingAt(new Vector(x0, y0));
}
if (x0 === x1 && y0 === y1) break;
var e2 = 2 * err;
if (e2 > -dy) {
err -= dy;
x0 += sx;
}
if (e2 < dx) {
err += dx;
y0 += sy;
}
}
}
this.lastDragTile = newPos;
return STOP_PROPAGATION;
}
}
/**
* Mouse up handler
*/
onMouseUp() {
if (this.root.camera.getIsMapOverlayActive()) {
return;
}
// Check for direction lock
if (this.lastDragTile && this.currentlyDragging && this.isDirectionLockActive) {
this.executeDirectionLockedPlacement();
}
this.abortDragging();
}
}

View File

@ -1,102 +1,316 @@
import { makeDiv } from "../../../core/utils";
import { T } from "../../../translations";
import { getStringForKeyCode, KEYMAPPINGS } from "../../key_action_mapper";
import {
getStringForKeyCode,
KEYCODE_LMB,
KEYCODE_MMB,
KEYCODE_RMB,
KEYMAPPINGS,
} from "../../key_action_mapper";
import { BaseHUDPart } from "../base_hud_part";
import { TrackedState } from "../../../core/tracked_state";
import { DynamicDomAttach } from "../dynamic_dom_attach";
const DIVIDER_TOKEN = "/";
const ADDER_TOKEN = "+";
/**
* @typedef {{ keyCode: number }} KeyCode
*/
/**
* @typedef {{
* condition: () => boolean,
* keys: Array<KeyCode|number|string>,
* label: string,
* cachedElement?: HTMLElement,
* cachedVisibility?: boolean
* }} KeyBinding
*/
export class HUDKeybindingOverlay extends BaseHUDPart {
initialize() {
this.root.hud.signals.selectedPlacementBuildingChanged.add(
this.onSelectedBuildingForPlacementChanged,
this
);
initialize() {}
this.trackedMapOverviewActive = new TrackedState(this.applyCssClasses, this);
/**
* HELPER / Returns if there is a building selected for placement
* @returns {boolean}
*/
get buildingPlacementActive() {
const placer = this.root.hud.parts.buildingPlacer;
return !this.mapOverviewActive && placer && !!placer.currentMetaBuilding.get();
}
/**
* HELPER / Returns if there is a building selected for placement and
* it supports the belt planner
* @returns {boolean}
*/
get buildingPlacementSupportsBeltPlanner() {
const placer = this.root.hud.parts.buildingPlacer;
return (
!this.mapOverviewActive &&
placer &&
placer.currentMetaBuilding.get() &&
placer.currentMetaBuilding.get().getHasDirectionLockAvailable()
);
}
/**
* HELPER / Returns if there is a building selected for placement and
* it has multiplace enabled by default
* @returns {boolean}
*/
get buildingPlacementStaysInPlacement() {
const placer = this.root.hud.parts.buildingPlacer;
return (
!this.mapOverviewActive &&
placer &&
placer.currentMetaBuilding.get() &&
placer.currentMetaBuilding.get().getStayInPlacementMode()
);
}
/**
* HELPER / Returns if there is a blueprint selected for placement
* @returns {boolean}
*/
get blueprintPlacementActive() {
const placer = this.root.hud.parts.blueprintPlacer;
return placer && !!placer.currentBlueprint.get();
}
/**
* HELPER / Returns if the belt planner is currently active
* @returns {boolean}
*/
get beltPlannerActive() {
const placer = this.root.hud.parts.buildingPlacer;
return !this.mapOverviewActive && placer && placer.isDirectionLockActive;
}
/**
* HELPER / Returns if there is a last blueprint available
* @returns {boolean}
*/
get lastBlueprintAvailable() {
const placer = this.root.hud.parts.blueprintPlacer;
return placer && !!placer.lastBlueprintUsed;
}
/**
* HELPER / Returns if there is anything selected on the map
* @returns {boolean}
*/
get anythingSelectedOnMap() {
const selector = this.root.hud.parts.massSelector;
return selector && selector.selectedUids.size > 0;
}
/**
* HELPER / Returns if there is a building or blueprint selected for placement
* @returns {boolean}
*/
get anyPlacementActive() {
return this.buildingPlacementActive || this.blueprintPlacementActive;
}
/**
* HELPER / Returns if the map overview is active
* @returns {boolean}
*/
get mapOverviewActive() {
return this.root.camera.getIsMapOverlayActive();
}
/**
* Initializes the element
* @param {HTMLElement} parent
*/
createElements(parent) {
const mapper = this.root.keyMapper;
const k = KEYMAPPINGS;
const getKeycode = id => {
return getStringForKeyCode(mapper.getBinding(id).keyCode);
};
/** @type {Array<KeyBinding>} */
this.keybindings = [
{
// Move map - Including mouse
label: T.ingame.keybindingsOverlay.moveMap,
keys: [
KEYCODE_LMB,
DIVIDER_TOKEN,
k.navigation.mapMoveUp,
k.navigation.mapMoveLeft,
k.navigation.mapMoveDown,
k.navigation.mapMoveRight,
],
condition: () => !this.anyPlacementActive,
},
this.element = makeDiv(
parent,
"ingame_HUD_KeybindingOverlay",
[],
`
{
// Move map - No mouse
label: T.ingame.keybindingsOverlay.moveMap,
keys: [
k.navigation.mapMoveUp,
k.navigation.mapMoveLeft,
k.navigation.mapMoveDown,
k.navigation.mapMoveRight,
],
condition: () => this.anyPlacementActive,
},
<div class="binding">
<code class="keybinding leftMouse noPlacementOnly"></code><i class="noPlacementOnly"></i>
<code class="keybinding">${getKeycode(KEYMAPPINGS.navigation.mapMoveUp)}</code>
<code class="keybinding">${getKeycode(KEYMAPPINGS.navigation.mapMoveLeft)}</code>
<code class="keybinding">${getKeycode(KEYMAPPINGS.navigation.mapMoveDown)}</code>
<code class="keybinding">${getKeycode(KEYMAPPINGS.navigation.mapMoveRight)}</code>
<label>${T.ingame.keybindingsOverlay.moveMap}</label>
</div>
{
// [OVERVIEW] Create marker with right click
label: T.ingame.keybindingsOverlay.createMarker,
keys: [KEYCODE_RMB],
condition: () => this.mapOverviewActive && !this.blueprintPlacementActive,
},
{
// Pipette
label: T.ingame.keybindingsOverlay.pipette,
keys: [k.placement.pipette],
condition: () => !this.mapOverviewActive && !this.blueprintPlacementActive,
},
{
// Cancel placement
label: T.ingame.keybindingsOverlay.stopPlacement,
keys: [KEYCODE_RMB],
condition: () => this.anyPlacementActive,
},
<div class="binding noPlacementOnly noOverviewOnly">
<code class="keybinding rightMouse"></code>
<label>${T.ingame.keybindingsOverlay.delete}</label>
</div>
{
// Delete with right click
label: T.ingame.keybindingsOverlay.delete,
keys: [KEYCODE_RMB],
condition: () =>
!this.anyPlacementActive && !this.mapOverviewActive && !this.anythingSelectedOnMap,
},
<div class="binding noPlacementOnly overviewOnly">
<code class="keybinding rightMouse"></code>
<label>${T.ingame.keybindingsOverlay.createMarker}</label>
</div>
{
// Area select
label: T.ingame.keybindingsOverlay.selectBuildings,
keys: [k.massSelect.massSelectStart, ADDER_TOKEN, KEYCODE_LMB],
condition: () => !this.anyPlacementActive && !this.anythingSelectedOnMap,
},
{
// Place building
label: T.ingame.keybindingsOverlay.placeBuilding,
keys: [KEYCODE_LMB],
condition: () => this.anyPlacementActive,
},
<div class="binding noPlacementOnly">
<code class="keybinding builtinKey">${getKeycode(
KEYMAPPINGS.massSelect.massSelectStart
)}</code>+
<code class="keybinding leftMouse"></code>
<label>${T.ingame.keybindingsOverlay.selectBuildings}</label>
</div>
{
// Rotate
label: T.ingame.keybindingsOverlay.rotateBuilding,
keys: [k.placement.rotateWhilePlacing],
condition: () => this.anyPlacementActive && !this.beltPlannerActive,
},
<div class="binding placementOnly">
<code class="keybinding leftMouse"></code>
<label>${T.ingame.keybindingsOverlay.placeBuilding}</label>
</div>
{
// [BELT PLANNER] Flip Side
label: T.ingame.keybindingsOverlay.plannerSwitchSide,
keys: [k.placement.switchDirectionLockSide],
condition: () => this.beltPlannerActive,
},
<div class="binding placementOnly">
<code class="keybinding rightMouse"></code><i></i>
<code class="keybinding">${getKeycode(KEYMAPPINGS.placement.abortBuildingPlacement)}</code>
<label>${T.ingame.keybindingsOverlay.stopPlacement}</label>
</div>
{
// Place last blueprint
label: T.ingame.keybindingsOverlay.pasteLastBlueprint,
keys: [k.massSelect.pasteLastBlueprint],
condition: () => !this.blueprintPlacementActive && this.lastBlueprintAvailable,
},
<div class="binding placementOnly">
<code class="keybinding">${getKeycode(KEYMAPPINGS.placement.rotateWhilePlacing)}</code>
<label>${T.ingame.keybindingsOverlay.rotateBuilding}</label>
</div>
{
// Belt planner
label: T.ingame.keybindingsOverlay.lockBeltDirection,
keys: [k.placementModifiers.lockBeltDirection],
condition: () => this.buildingPlacementSupportsBeltPlanner && !this.beltPlannerActive,
},
` +
(this.root.app.settings.getAllSettings().alwaysMultiplace
? ""
: `
<div class="binding placementOnly">
<code class="keybinding builtinKey shift">${getKeycode(
KEYMAPPINGS.placementModifiers.placeMultiple
)}</code>
<label>${T.ingame.keybindingsOverlay.placeMultiple}</label>
</div>`) +
`
`
);
}
{
// [SELECTION] Destroy
label: T.ingame.keybindingsOverlay.delete,
keys: [k.massSelect.confirmMassDelete],
condition: () => this.anythingSelectedOnMap,
},
onSelectedBuildingForPlacementChanged(selectedMetaBuilding) {
this.element.classList.toggle("placementActive", !!selectedMetaBuilding);
}
{
// [SELECTION] Cancel
label: T.ingame.keybindingsOverlay.clearSelection,
keys: [k.general.back],
condition: () => this.anythingSelectedOnMap,
},
{
// [SELECTION] Cut
label: T.ingame.keybindingsOverlay.cutSelection,
keys: [k.massSelect.massSelectCut],
condition: () => this.anythingSelectedOnMap,
},
applyCssClasses() {
this.element.classList.toggle("mapOverviewActive", this.root.camera.getIsMapOverlayActive());
{
// [SELECTION] Copy
label: T.ingame.keybindingsOverlay.copySelection,
keys: [k.massSelect.massSelectCopy],
condition: () => this.anythingSelectedOnMap,
},
];
if (!this.root.app.settings.getAllSettings().alwaysMultiplace) {
this.keybindings.push({
// Multiplace
label: T.ingame.keybindingsOverlay.placeMultiple,
keys: [k.placementModifiers.placeMultiple],
condition: () => this.anyPlacementActive && !this.buildingPlacementStaysInPlacement,
});
}
this.element = makeDiv(parent, "ingame_HUD_KeybindingOverlay", []);
for (let i = 0; i < this.keybindings.length; ++i) {
let html = "";
const handle = this.keybindings[i];
for (let k = 0; k < handle.keys.length; ++k) {
const key = handle.keys[k];
switch (key) {
case KEYCODE_LMB:
html += `<code class="keybinding leftMouse"></code>`;
break;
case KEYCODE_RMB:
html += `<code class="keybinding rightMouse"></code>`;
break;
case KEYCODE_MMB:
html += `<code class="keybinding middleMouse"></code>`;
break;
case DIVIDER_TOKEN:
html += `<i></i>`;
break;
case ADDER_TOKEN:
html += `+`;
break;
default:
html += `<code class="keybinding">${getStringForKeyCode(
mapper.getBinding(/** @type {KeyCode} */ (key)).keyCode
)}</code>`;
}
}
html += `<label>${handle.label}</label>`;
handle.cachedElement = makeDiv(this.element, null, ["binding"], html);
handle.cachedVisibility = false;
}
}
update() {
this.trackedMapOverviewActive.set(this.root.camera.getIsMapOverlayActive());
for (let i = 0; i < this.keybindings.length; ++i) {
const handle = this.keybindings[i];
const visibility = handle.condition();
if (visibility !== handle.cachedVisibility) {
handle.cachedVisibility = visibility;
handle.cachedElement.classList.toggle("visible", visibility);
}
}
}
}

View File

@ -17,29 +17,7 @@ import { enumHubGoalRewards } from "../../tutorial_goals";
const logger = createLogger("hud/mass_selector");
export class HUDMassSelector extends BaseHUDPart {
createElements(parent) {
const removalKeybinding = this.root.keyMapper
.getBinding(KEYMAPPINGS.massSelect.confirmMassDelete)
.getKeyCodeString();
const abortKeybinding = this.root.keyMapper.getBinding(KEYMAPPINGS.general.back).getKeyCodeString();
const cutKeybinding = this.root.keyMapper
.getBinding(KEYMAPPINGS.massSelect.massSelectCut)
.getKeyCodeString();
const copyKeybinding = this.root.keyMapper
.getBinding(KEYMAPPINGS.massSelect.massSelectCopy)
.getKeyCodeString();
this.element = makeDiv(
parent,
"ingame_HUD_MassSelector",
[],
T.ingame.massSelect.infoText
.replace("<keyDelete>", `<code class='keybinding'>${removalKeybinding}</code>`)
.replace("<keyCut>", `<code class='keybinding'>${cutKeybinding}</code>`)
.replace("<keyCopy>", `<code class='keybinding'>${copyKeybinding}</code>`)
.replace("<keyCancel>", `<code class='keybinding'>${abortKeybinding}</code>`)
);
}
createElements(parent) {}
initialize() {
this.deletionMarker = Loader.getSprite("sprites/misc/deletion_marker.png");
@ -49,6 +27,7 @@ export class HUDMassSelector extends BaseHUDPart {
this.selectedUids = new Set();
this.root.signals.entityQueuedForDestroy.add(this.onEntityDestroyed, this);
this.root.hud.signals.pasteBlueprintRequested.add(this.clearSelection, this);
this.root.camera.downPreHandler.add(this.onMouseDown, this);
this.root.camera.movePreHandler.add(this.onMouseMove, this);
@ -61,7 +40,7 @@ export class HUDMassSelector extends BaseHUDPart {
this.root.keyMapper.getBinding(KEYMAPPINGS.massSelect.massSelectCut).add(this.confirmCut, this);
this.root.keyMapper.getBinding(KEYMAPPINGS.massSelect.massSelectCopy).add(this.startCopy, this);
this.domAttach = new DynamicDomAttach(this.root, this.element);
this.root.hud.signals.selectedPlacementBuildingChanged.add(this.clearSelection, this);
}
/**
@ -83,15 +62,25 @@ export class HUDMassSelector extends BaseHUDPart {
}
}
/**
* Clears the entire selection
*/
clearSelection() {
this.selectedUids = new Set();
}
confirmDelete() {
if (this.selectedUids.size > 100) {
if (
!this.root.app.settings.getAllSettings().disableCutDeleteWarnings &&
this.selectedUids.size > 100
) {
const { ok } = this.root.hud.parts.dialogs.showWarning(
T.dialogs.massDeleteConfirm.title,
T.dialogs.massDeleteConfirm.desc.replace(
"<count>",
"" + formatBigNumberFull(this.selectedUids.size)
),
["cancel:good", "ok:bad"]
["cancel:good:escape", "ok:bad:enter"]
);
ok.add(() => this.doDelete());
} else {
@ -134,14 +123,17 @@ export class HUDMassSelector extends BaseHUDPart {
T.dialogs.blueprintsNotUnlocked.title,
T.dialogs.blueprintsNotUnlocked.desc
);
} else if (this.selectedUids.size > 100) {
} else if (
!this.root.app.settings.getAllSettings().disableCutDeleteWarnings &&
this.selectedUids.size > 100
) {
const { ok } = this.root.hud.parts.dialogs.showWarning(
T.dialogs.massCutConfirm.title,
T.dialogs.massCutConfirm.desc.replace(
"<count>",
"" + formatBigNumberFull(this.selectedUids.size)
),
["cancel:good", "ok:bad"]
["cancel:good:escape", "ok:bad:enter"]
);
ok.add(() => this.doCut());
} else {
@ -177,7 +169,7 @@ export class HUDMassSelector extends BaseHUDPart {
* @param {enumMouseButton} mouseButton
*/
onMouseDown(pos, mouseButton) {
if (!this.root.keyMapper.getBinding(KEYMAPPINGS.massSelect.massSelectStart).isCurrentlyPressed()) {
if (!this.root.keyMapper.getBinding(KEYMAPPINGS.massSelect.massSelectStart).pressed) {
return;
}
@ -185,11 +177,7 @@ export class HUDMassSelector extends BaseHUDPart {
return;
}
if (
!this.root.keyMapper
.getBinding(KEYMAPPINGS.massSelect.massSelectSelectMultiple)
.isCurrentlyPressed()
) {
if (!this.root.keyMapper.getBinding(KEYMAPPINGS.massSelect.massSelectSelectMultiple).pressed) {
// Start new selection
this.selectedUids = new Set();
}
@ -234,10 +222,6 @@ export class HUDMassSelector extends BaseHUDPart {
}
}
update() {
this.domAttach.update(this.selectedUids.size > 0);
}
/**
*
* @param {DrawParameters} parameters

View File

@ -5,7 +5,7 @@ import { T } from "../../../translations";
import { createLogger } from "../../../core/logging";
import { StaticMapEntityComponent } from "../../components/static_map_entity";
import { Vector } from "../../../core/vector";
import { Math_max, Math_min } from "../../../core/builtins";
import { Math_max, Math_min, Math_floor } from "../../../core/builtins";
import { makeOffscreenBuffer } from "../../../core/buffer_utils";
import { DrawParameters } from "../../../core/draw_parameters";
import { Rectangle } from "../../../core/rectangle";
@ -56,7 +56,14 @@ export class HUDScreenshotExporter extends BaseHUDPart {
const dimensions = maxChunk.sub(minChunk);
logger.log("Dimensions:", dimensions);
const chunkSizePixels = 128;
let chunkSizePixels = 128;
const maxDimensions = Math_max(dimensions.x, dimensions.y);
if (maxDimensions > 128) {
chunkSizePixels = Math_max(1, Math_floor(128 * (128 / maxDimensions)));
}
logger.log("ChunkSizePixels:", chunkSizePixels);
const chunkScale = chunkSizePixels / (globalConfig.mapChunkSize * globalConfig.tileSize);
logger.log("Scale:", chunkScale);

View File

@ -1,5 +1,5 @@
import { makeOffscreenBuffer } from "../../../core/buffer_utils";
import { Math_max } from "../../../core/builtins";
import { Math_max, Math_PI, Math_radians } from "../../../core/builtins";
import { globalConfig, IS_DEMO } from "../../../core/config";
import { DrawParameters } from "../../../core/draw_parameters";
import { Loader } from "../../../core/loader";
@ -7,7 +7,7 @@ import { DialogWithForm } from "../../../core/modal_dialog_elements";
import { FormElementInput } from "../../../core/modal_dialog_forms";
import { Rectangle } from "../../../core/rectangle";
import { STOP_PROPAGATION } from "../../../core/signal";
import { arrayDeleteValue, lerp, makeDiv, removeAllChildren } from "../../../core/utils";
import { arrayDeleteValue, lerp, makeDiv, removeAllChildren, clamp } from "../../../core/utils";
import { Vector } from "../../../core/vector";
import { T } from "../../../translations";
import { enumMouseButton } from "../../camera";
@ -15,16 +15,28 @@ import { KEYMAPPINGS } from "../../key_action_mapper";
import { BaseHUDPart } from "../base_hud_part";
import { DynamicDomAttach } from "../dynamic_dom_attach";
import { enumNotificationType } from "./notifications";
import { ShapeDefinition } from "../../shape_definition";
/** @typedef {{
* label: string,
* label: string | null,
* center: { x: number, y: number },
* zoomLevel: number,
* deletable: boolean
* zoomLevel: number
* }} Waypoint */
/**
* Used when a shape icon is rendered instead
*/
const SHAPE_LABEL_PLACEHOLDER = " ";
const MAX_LABEL_LENGTH = 71;
export class HUDWaypoints extends BaseHUDPart {
/**
* Creates the overview of waypoints
* @param {HTMLElement} parent
*/
createElements(parent) {
// Create the helper box on the lower right when zooming out
if (this.root.app.settings.getAllSettings().offerHints) {
this.hintElement = makeDiv(
parent,
@ -42,17 +54,23 @@ export class HUDWaypoints extends BaseHUDPart {
);
}
this.waypointSprite = Loader.getSprite("sprites/misc/waypoint.png");
// Create the waypoint list on the upper right
this.waypointsListElement = makeDiv(parent, "ingame_HUD_Waypoints", [], "Waypoints");
}
/**
* Serializes the waypoints
*/
serialize() {
return {
waypoints: this.waypoints,
};
}
/**
* Deserializes the waypoints
* @param {{waypoints: Array<Waypoint>}} data
*/
deserialize(data) {
if (!data || !data.waypoints || !Array.isArray(data.waypoints)) {
return "Invalid waypoints data";
@ -61,21 +79,97 @@ export class HUDWaypoints extends BaseHUDPart {
this.rerenderWaypointList();
}
/**
* Initializes everything
*/
initialize() {
// Cache the sprite for the waypoints
this.waypointSprite = Loader.getSprite("sprites/misc/waypoint.png");
this.directionIndicatorSprite = Loader.getSprite("sprites/misc/hub_direction_indicator.png");
/** @type {Array<Waypoint>}
*/
this.waypoints = [
{
label: null,
center: { x: 0, y: 0 },
zoomLevel: 3,
},
];
// Create a buffer we can use to measure text
this.dummyBuffer = makeOffscreenBuffer(1, 1, {
reusable: false,
label: "waypoints-measure-canvas",
})[1];
// Dynamically attach/detach the lower right hint in the map overview
if (this.hintElement) {
this.domAttach = new DynamicDomAttach(this.root, this.hintElement);
}
// Catch mouse and key events
this.root.camera.downPreHandler.add(this.onMouseDown, this);
this.root.keyMapper
.getBinding(KEYMAPPINGS.navigation.createMarker)
.add(this.requestCreateMarker, this);
/**
* Stores at how much opacity the markers should be rendered on the map.
* This is interpolated over multiple frames so we have some sort of fade effect
*/
this.currentMarkerOpacity = 1;
this.currentCompassOpacity = 0;
// Create buffer which is used to indicate the hub direction
const [canvas, context] = makeOffscreenBuffer(48, 48, {
smooth: true,
reusable: false,
label: "waypoints-compass",
});
this.compassBuffer = { canvas, context };
/**
* Stores a cache from a shape short key to its canvas representation
*/
this.cachedKeyToCanvas = {};
// Initial render
this.rerenderWaypointList();
}
/**
* Re-renders the waypoint list to account for changes
*/
rerenderWaypointList() {
removeAllChildren(this.waypointsListElement);
this.cleanupClickDetectors();
for (let i = 0; i < this.waypoints.length; ++i) {
const waypoint = this.waypoints[i];
const label = this.getWaypointLabel(waypoint);
const element = makeDiv(this.waypointsListElement, null, ["waypoint"]);
element.innerText = waypoint.label;
if (waypoint.deletable) {
if (ShapeDefinition.isValidShortKey(label)) {
const canvas = this.getWaypointCanvas(waypoint);
element.appendChild(canvas);
element.classList.add("shapeIcon");
} else {
element.innerText = label;
}
if (this.isWaypointDeletable(waypoint)) {
const deleteButton = makeDiv(element, null, ["deleteButton"]);
this.trackClicks(deleteButton, () => this.deleteWaypoint(waypoint));
}
if (!waypoint.label) {
// This must be the hub label
element.classList.add("hub");
element.insertBefore(this.compassBuffer.canvas, element.childNodes[0]);
}
this.trackClicks(element, () => this.moveToWaypoint(waypoint), {
targetOnly: true,
});
@ -83,6 +177,7 @@ export class HUDWaypoints extends BaseHUDPart {
}
/**
* Moves the camera to a given waypoint
* @param {Waypoint} waypoint
*/
moveToWaypoint(waypoint) {
@ -91,6 +186,7 @@ export class HUDWaypoints extends BaseHUDPart {
}
/**
* Deletes a waypoint from the list
* @param {Waypoint} waypoint
*/
deleteWaypoint(waypoint) {
@ -98,86 +194,132 @@ export class HUDWaypoints extends BaseHUDPart {
this.rerenderWaypointList();
}
initialize() {
/** @type {Array<Waypoint>}
*/
this.waypoints = [
{
label: T.ingame.waypoints.hub,
center: { x: 0, y: 0 },
zoomLevel: 3,
deletable: false,
},
];
this.dummyBuffer = makeOffscreenBuffer(1, 1, {
reusable: false,
label: "waypoints-measure-canvas",
})[1];
this.root.camera.downPreHandler.add(this.onMouseDown, this);
if (this.hintElement) {
this.domAttach = new DynamicDomAttach(this.root, this.hintElement);
/**
* Gets the canvas for a given waypoint
* @param {Waypoint} waypoint
* @returns {HTMLCanvasElement}
*/
getWaypointCanvas(waypoint) {
const key = waypoint.label;
if (this.cachedKeyToCanvas[key]) {
return this.cachedKeyToCanvas[key];
}
this.root.keyMapper
.getBinding(KEYMAPPINGS.navigation.createMarker)
.add(this.requestCreateMarker, this);
this.currentMarkerOpacity = 1;
this.rerenderWaypointList();
assert(ShapeDefinition.isValidShortKey(key), "Invalid short key: " + key);
const definition = ShapeDefinition.fromShortKey(key);
const preRendered = definition.generateAsCanvas(48);
return (this.cachedKeyToCanvas[key] = preRendered);
}
/**
* Requests to create a marker at the current camera position. If worldPos is set,
* uses that position instead.
* @param {Vector=} worldPos Override the world pos, otherwise it is the camera position
*/
requestCreateMarker(worldPos = null) {
// Construct dialog with input field
const markerNameInput = new FormElementInput({
id: "markerName",
label: null,
placeholder: "",
validator: val => val.length > 0 && val.length < 15,
validator: val =>
val.length > 0 && (val.length < MAX_LABEL_LENGTH || ShapeDefinition.isValidShortKey(val)),
});
const dialog = new DialogWithForm({
app: this.root.app,
title: T.dialogs.createMarker.title,
desc: T.dialogs.createMarker.desc,
formElements: [markerNameInput],
});
this.root.hud.parts.dialogs.internalShowDialog(dialog);
// Compute where to create the marker
const center = worldPos || this.root.camera.center;
dialog.buttonSignals.ok.add(() => {
// 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) {
this.root.hud.parts.dialogs.showFeatureRestrictionInfo("", T.dialogs.markerDemoLimit.desc);
return;
}
this.waypoints.push({
label: markerNameInput.getValue(),
center: { x: center.x, y: center.y },
zoomLevel: Math_max(this.root.camera.zoomLevel, globalConfig.mapChunkOverviewMinZoom + 0.05),
deletable: true,
});
this.waypoints.sort((a, b) => a.label.padStart(20, "0").localeCompare(b.label.padStart(20, "0")));
this.root.hud.signals.notification.dispatch(
T.ingame.waypoints.creationSuccessNotification,
enumNotificationType.success
);
this.rerenderWaypointList();
// Actually create the waypoint
this.addWaypoint(markerNameInput.getValue(), center);
});
}
/**
* Adds a new waypoint at the given location with the given label
* @param {string} label
* @param {Vector} position
*/
addWaypoint(label, position) {
this.waypoints.push({
label,
center: { x: position.x, y: position.y },
// Make sure the zoom is *just* a bit above the zoom level where the map overview
// starts, so you always see all buildings
zoomLevel: Math_max(this.root.camera.zoomLevel, globalConfig.mapChunkOverviewMinZoom + 0.05),
});
// Sort waypoints by name
this.waypoints.sort((a, b) => {
if (!a.label) {
return -1;
}
if (!b.label) {
return 1;
}
return this.getWaypointLabel(a)
.padEnd(MAX_LABEL_LENGTH, "0")
.localeCompare(this.getWaypointLabel(b).padEnd(MAX_LABEL_LENGTH, "0"));
});
// Show notification about creation
this.root.hud.signals.notification.dispatch(
T.ingame.waypoints.creationSuccessNotification,
enumNotificationType.success
);
// Re-render the list and thus add it
this.rerenderWaypointList();
}
/**
* Called every frame to update stuff
*/
update() {
if (this.domAttach) {
this.domAttach.update(this.root.camera.getIsMapOverlayActive());
}
}
/**
* Returns the label for a given waypoint
* @param {Waypoint} waypoint
* @returns {string}
*/
getWaypointLabel(waypoint) {
return waypoint.label || T.ingame.waypoints.hub;
}
/**
* Returns if a waypoint is deletable
* @param {Waypoint} waypoint
* @returns {boolean}
*/
isWaypointDeletable(waypoint) {
return waypoint.label !== null;
}
/**
* Finds the currently intersected waypoint on the map overview under
* the cursor.
*
* @returns {Waypoint | null}
*/
findCurrentIntersectedWaypoint() {
const mousePos = this.root.app.mousePosition;
if (!mousePos) {
@ -197,10 +339,18 @@ export class HUDWaypoints extends BaseHUDPart {
const screenPos = this.root.camera.worldToScreen(
new Vector(waypoint.center.x, waypoint.center.y)
);
let label = this.getWaypointLabel(waypoint);
// Special case for icons
if (ShapeDefinition.isValidShortKey(label)) {
label = SHAPE_LABEL_PLACEHOLDER;
}
const intersectionRect = new Rectangle(
screenPos.x - 7 * scale,
screenPos.y - 12 * scale,
15 * scale + this.dummyBuffer.measureText(waypoint.label).width,
15 * scale + this.dummyBuffer.measureText(label).width,
15 * scale
);
if (intersectionRect.containsPoint(mousePos.x, mousePos.y)) {
@ -210,7 +360,7 @@ export class HUDWaypoints extends BaseHUDPart {
}
/**
*
* Mouse-Down handler
* @param {Vector} pos
* @param {enumMouseButton} button
*/
@ -221,7 +371,7 @@ export class HUDWaypoints extends BaseHUDPart {
this.root.soundProxy.playUiClick();
this.moveToWaypoint(waypoint);
} else if (button === enumMouseButton.right) {
if (waypoint.deletable) {
if (this.isWaypointDeletable(waypoint)) {
this.root.soundProxy.playUiClick();
this.deleteWaypoint(waypoint);
} else {
@ -243,50 +393,111 @@ export class HUDWaypoints extends BaseHUDPart {
}
/**
*
* Rerenders the compass
*/
rerenderWaypointsCompass() {
const context = this.compassBuffer.context;
const dims = 48;
context.clearRect(0, 0, dims, dims);
const indicatorSize = 30;
const cameraPos = this.root.camera.center;
const distanceToHub = cameraPos.length();
const compassVisible = distanceToHub > (10 * globalConfig.tileSize) / this.root.camera.zoomLevel;
const targetCompassAlpha = compassVisible ? 1 : 0;
this.currentCompassOpacity = lerp(this.currentCompassOpacity, targetCompassAlpha, 0.08);
if (this.currentCompassOpacity > 0.01) {
context.globalAlpha = this.currentCompassOpacity;
const angle = cameraPos.angle() + Math_radians(45) + Math_PI / 2;
context.translate(dims / 2, dims / 2);
context.rotate(angle);
this.directionIndicatorSprite.drawCentered(context, 0, 0, indicatorSize);
context.rotate(-angle);
context.translate(-dims / 2, -dims / 2);
context.globalAlpha = 1;
}
const iconOpacity = 1 - this.currentCompassOpacity;
if (iconOpacity > 0.01) {
// Draw icon
context.globalAlpha = iconOpacity;
this.waypointSprite.drawCentered(context, dims / 2, dims / 2, dims * 0.7);
context.globalAlpha = 1;
}
}
/**
* Draws the waypoints on the map
* @param {DrawParameters} parameters
*/
draw(parameters) {
const desiredOpacity = this.root.camera.getIsMapOverlayActive() ? 1 : 0;
this.currentMarkerOpacity = lerp(this.currentMarkerOpacity, desiredOpacity, 0.08);
this.rerenderWaypointsCompass();
// Don't render with low opacity
if (this.currentMarkerOpacity < 0.01) {
return;
}
// Find waypoint below cursor
const selected = this.findCurrentIntersectedWaypoint();
// Determine rendering scale
const scale = (1 / this.root.camera.zoomLevel) * this.root.app.getEffectiveUiScale();
// Render all of 'em
for (let i = 0; i < this.waypoints.length; ++i) {
const waypoint = this.waypoints[i];
const pos = waypoint.center;
parameters.context.globalAlpha = this.currentMarkerOpacity * (selected === waypoint ? 1 : 0.7);
const yOffset = -5 * scale;
const originalLabel = this.getWaypointLabel(waypoint);
let renderLabel = originalLabel;
let isShapeIcon = false;
if (ShapeDefinition.isValidShortKey(originalLabel)) {
renderLabel = SHAPE_LABEL_PLACEHOLDER;
isShapeIcon = true;
}
// Render the background rectangle
parameters.context.font = "bold " + 12 * scale + "px GameFont";
parameters.context.fillStyle = "rgba(255, 255, 255, 0.7)";
parameters.context.fillRect(
pos.x - 7 * scale,
pos.y - 12 * scale,
15 * scale + this.dummyBuffer.measureText(waypoint.label).width / this.root.camera.zoomLevel,
15 * scale + this.dummyBuffer.measureText(renderLabel).width / this.root.camera.zoomLevel,
15 * scale
);
parameters.context.fillStyle = "#000";
parameters.context.textAlign = "left";
parameters.context.textBaseline = "middle";
parameters.context.fillText(waypoint.label, pos.x + 6 * scale, pos.y + 0.5 * scale + yOffset);
parameters.context.textBaseline = "alphabetic";
parameters.context.textAlign = "left";
// Render the text
if (isShapeIcon) {
const canvas = this.getWaypointCanvas(waypoint);
parameters.context.drawImage(
canvas,
pos.x + 6 * scale,
pos.y - 11.5 * scale,
14 * scale,
14 * scale
);
} else {
// Render the text
parameters.context.fillStyle = "#000";
parameters.context.textBaseline = "middle";
parameters.context.fillText(renderLabel, pos.x + 6 * scale, pos.y + 0.5 * scale + yOffset);
parameters.context.textBaseline = "alphabetic";
}
// Render the small icon on the left
this.waypointSprite.drawCentered(parameters.context, pos.x, pos.y + yOffset, 10 * scale);
}
parameters.context.globalAlpha = 1;
}
}

View File

@ -24,7 +24,7 @@ export const KEYMAPPINGS = {
menuOpenStats: { keyCode: key("G") },
toggleHud: { keyCode: 113 }, // F2
exportScreenshot: { keyCode: 114 }, // F3
exportScreenshot: { keyCode: 114 }, // F3PS
toggleFPSInfo: { keyCode: 115 }, // F4
},
@ -33,6 +33,7 @@ export const KEYMAPPINGS = {
mapMoveRight: { keyCode: key("D") },
mapMoveDown: { keyCode: key("S") },
mapMoveLeft: { keyCode: key("A") },
mapMoveFaster: { keyCode: 16 }, //shift
centerMap: { keyCode: 32 }, // SPACE
mapZoomIn: { keyCode: 187, repeated: true }, // "+"
@ -55,11 +56,12 @@ export const KEYMAPPINGS = {
},
placement: {
abortBuildingPlacement: { keyCode: key("Q") },
pipette: { keyCode: key("Q") },
rotateWhilePlacing: { keyCode: key("R") },
rotateInverseModifier: { keyCode: 16 }, // SHIFT
cycleBuildingVariants: { keyCode: key("T") },
cycleBuildings: { keyCode: 9 }, // TAB
switchDirectionLockSide: { keyCode: key("R") },
},
massSelect: {
@ -72,6 +74,7 @@ export const KEYMAPPINGS = {
},
placementModifiers: {
lockBeltDirection: { keyCode: 16 }, // SHIFT
placementDisableAutoOrientation: { keyCode: 17 }, // CTRL
placeMultiple: { keyCode: 16 }, // SHIFT
placeInverse: { keyCode: 18 }, // ALT
@ -85,6 +88,10 @@ for (const categoryId in KEYMAPPINGS) {
}
}
export const KEYCODE_LMB = 1;
export const KEYCODE_MMB = 2;
export const KEYCODE_RMB = 3;
/**
* Returns a keycode -> string
* @param {number} code
@ -92,11 +99,11 @@ for (const categoryId in KEYMAPPINGS) {
*/
export function getStringForKeyCode(code) {
switch (code) {
case 1:
case KEYCODE_LMB:
return "LMB";
case 2:
case KEYCODE_MMB:
return "MMB";
case 3:
case KEYCODE_RMB:
return "RMB";
case 4:
return "MB4";
@ -259,14 +266,16 @@ export class Keybinding {
/**
* Returns whether this binding is currently pressed
* @returns {boolean}
*/
isCurrentlyPressed() {
get pressed() {
// Check if the key is down
if (this.app.inputMgr.keysDown.has(this.keyCode)) {
// Check if it is the top reciever
const reciever = this.keyMapper.inputReceiver;
return this.app.inputMgr.getTopReciever() === reciever;
}
return false;
}
/**

View File

@ -151,6 +151,7 @@ export class GameLogic {
* @param {number} param0.rotationVariant
* @param {string} param0.variant
* @param {MetaBuilding} param0.building
* @returns {Entity}
*/
tryPlaceBuilding({ origin, rotation, rotationVariant, originalRotation, variant, building }) {
if (this.checkCanPlaceBuilding({ origin, rotation, rotationVariant, variant, building })) {
@ -170,13 +171,13 @@ export class GameLogic {
if (contents) {
if (!this.tryDeleteBuilding(contents)) {
logger.error("Building has replaceable component but is also unremovable");
return false;
return null;
}
}
}
}
building.createAndPlaceEntity({
const entity = building.createAndPlaceEntity({
root: this.root,
origin,
rotation,
@ -186,10 +187,9 @@ export class GameLogic {
});
this.root.soundProxy.playUi(building.getPlacementSound());
return true;
return entity;
}
return false;
return null;
}
/**

View File

@ -31,6 +31,13 @@ export class MetaBuilding {
return new Vector(1, 1);
}
/**
* Returns whether the building has the direction lock switch available
*/
getHasDirectionLockAvailable() {
return false;
}
/**
* Whether to stay in placement mode after having placed a building
*/
@ -140,10 +147,32 @@ export class MetaBuilding {
* @param {string} param0.variant
*/
createAndPlaceEntity({ root, origin, rotation, originalRotation, rotationVariant, variant }) {
const entity = this.createEntity({
root,
origin,
rotation,
originalRotation,
rotationVariant,
variant,
});
root.map.placeStaticEntity(entity);
root.entityMgr.registerEntity(entity);
return entity;
}
/**
* Creates the entity without placing it
* @param {object} param0
* @param {GameRoot} param0.root
* @param {Vector} param0.origin Origin tile
* @param {number=} param0.rotation Rotation
* @param {number} param0.originalRotation Original Rotation
* @param {number} param0.rotationVariant Rotation variant
* @param {string} param0.variant
*/
createEntity({ root, origin, rotation, originalRotation, rotationVariant, variant }) {
const entity = new Entity(root);
const blueprintSprite = this.getBlueprintSprite(rotationVariant, variant);
entity.addComponent(
new StaticMapEntityComponent({
spriteKey:
@ -159,12 +188,8 @@ export class MetaBuilding {
blueprintSpriteKey: blueprintSprite ? blueprintSprite.spriteName : "",
})
);
this.setupEntityComponents(entity, root);
this.updateVariants(entity, rotationVariant, variant);
root.map.placeStaticEntity(entity);
root.entityMgr.registerEntity(entity);
return entity;
}

View File

@ -19,7 +19,6 @@ import { SoundProxy } from "./sound_proxy";
import { Savegame } from "../savegame/savegame";
import { GameLogic } from "./logic";
import { ShapeDefinitionManager } from "./shape_definition_manager";
import { CanvasClickInterceptor } from "./canvas_click_interceptor";
import { HubGoals } from "./hub_goals";
import { BufferMaintainer } from "../core/buffer_maintainer";
import { ProductionAnalytics } from "./production_analytics";
@ -110,9 +109,6 @@ export class GameRoot {
/** @type {BufferMaintainer} */
this.buffers = null;
/** @type {CanvasClickInterceptor} */
this.canvasClickInterceptor = null;
/** @type {AutomaticSave} */
this.automaticSave = null;
@ -130,6 +126,7 @@ export class GameRoot {
this.signals = {
// Entities
entityManuallyPlaced: /** @type {TypedSignal<[Entity]>} */ (new Signal()),
entityAdded: /** @type {TypedSignal<[Entity]>} */ (new Signal()),
entityGotNewComponent: /** @type {TypedSignal<[Entity]>} */ (new Signal()),
entityComponentRemoved: /** @type {TypedSignal<[Entity]>} */ (new Signal()),

View File

@ -70,6 +70,12 @@ export function createSimpleShape(layers) {
return layers;
}
/**
* Cache which shapes are valid short keys and which not
* @type {Map<string, boolean>}
*/
const SHORT_KEY_CACHE = new Map();
export class ShapeDefinition extends BasicSerializableObject {
static getId() {
return "ShapeDefinition";
@ -114,6 +120,8 @@ export class ShapeDefinition extends BasicSerializableObject {
/**
* Generates the definition from the given short key
* @param {string} key
* @returns {ShapeDefinition}
*/
static fromShortKey(key) {
const sourceLayers = key.split(":");
@ -147,6 +155,81 @@ export class ShapeDefinition extends BasicSerializableObject {
return definition;
}
/**
* Checks if a given string is a valid short key
* @param {string} key
* @returns {boolean}
*/
static isValidShortKey(key) {
if (SHORT_KEY_CACHE.has(key)) {
return SHORT_KEY_CACHE.get(key);
}
const result = ShapeDefinition.isValidShortKeyInternal(key);
SHORT_KEY_CACHE.set(key, result);
return result;
}
/**
* INTERNAL
* Checks if a given string is a valid short key
* @param {string} key
* @returns {boolean}
*/
static isValidShortKeyInternal(key) {
const sourceLayers = key.split(":");
let layers = [];
for (let i = 0; i < sourceLayers.length; ++i) {
const text = sourceLayers[i];
if (text.length !== 8) {
return false;
}
/** @type {ShapeLayer} */
const quads = [null, null, null, null];
let anyFilled = false;
for (let quad = 0; quad < 4; ++quad) {
const shapeText = text[quad * 2 + 0];
const colorText = text[quad * 2 + 1];
const subShape = enumShortcodeToSubShape[shapeText];
const color = enumShortcodeToColor[colorText];
// Valid shape
if (subShape) {
if (!color) {
// Invalid color
return false;
}
quads[quad] = {
subShape,
color,
};
anyFilled = true;
} else if (shapeText === "-") {
// Make sure color is empty then, too
if (colorText !== "-") {
return false;
}
} else {
// Invalid shape key
return false;
}
}
if (!anyFilled) {
// Empty layer
return false;
}
layers.push(quads);
}
if (layers.length === 0 || layers.length > 4) {
return false;
}
return true;
}
/**
* Internal method to clone the shape definition
* @returns {Array<ShapeLayer>}

View File

@ -6,7 +6,9 @@ import { Vector } from "../core/vector";
import { SOUNDS } from "../platform/sound";
const avgSoundDurationSeconds = 0.25;
const maxOngoingSounds = 10;
const maxOngoingSounds = 2;
const maxOngoingUiSounds = 25;
// Proxy to the application sound instance
export class SoundProxy {
@ -17,7 +19,8 @@ export class SoundProxy {
this.root = root;
// Store a list of sounds and when we started them
this.playingSounds = [];
this.playing3DSounds = [];
this.playingUiSounds = [];
}
/**
@ -26,7 +29,14 @@ export class SoundProxy {
*/
playUi(id) {
assert(typeof id === "string", "Not a valid sound id: " + id);
this.internalUpdateOngoingSounds();
if (this.playingUiSounds.length > maxOngoingUiSounds) {
// Too many ongoing sounds
return false;
}
this.root.app.sound.playUiSound(id);
this.playingUiSounds.push(this.root.time.realtimeNow());
}
/**
@ -53,13 +63,13 @@ export class SoundProxy {
assert(pos instanceof Vector, "Invalid sound position");
this.internalUpdateOngoingSounds();
if (this.playingSounds.length > maxOngoingSounds) {
if (this.playing3DSounds.length > maxOngoingSounds) {
// Too many ongoing sounds
return false;
}
this.root.app.sound.play3DSound(id, pos, this.root);
this.playingSounds.push(this.root.time.realtimeNow());
this.playing3DSounds.push(this.root.time.realtimeNow());
return true;
}
@ -68,9 +78,16 @@ export class SoundProxy {
*/
internalUpdateOngoingSounds() {
const now = this.root.time.realtimeNow();
for (let i = 0; i < this.playingSounds.length; ++i) {
if (now - this.playingSounds[i] > avgSoundDurationSeconds) {
this.playingSounds.splice(i, 1);
for (let i = 0; i < this.playing3DSounds.length; ++i) {
if (now - this.playing3DSounds[i] > avgSoundDurationSeconds) {
this.playing3DSounds.splice(i, 1);
i -= 1;
}
}
for (let i = 0; i < this.playingUiSounds.length; ++i) {
if (now - this.playingUiSounds[i] > avgSoundDurationSeconds) {
this.playingUiSounds.splice(i, 1);
i -= 1;
}
}

View File

@ -1,4 +1,4 @@
import { Math_radians, Math_min, Math_max } from "../../core/builtins";
import { Math_radians, Math_min, Math_max, Math_sqrt } from "../../core/builtins";
import { globalConfig } from "../../core/config";
import { DrawParameters } from "../../core/draw_parameters";
import { Loader } from "../../core/loader";
@ -15,6 +15,7 @@ import { GameRoot } from "../root";
import { createLogger } from "../../core/logging";
const BELT_ANIM_COUNT = 6;
const SQRT_2 = Math_sqrt(2);
const logger = createLogger("belt");
@ -211,6 +212,7 @@ export class BeltSystem extends GameSystemWithFilter {
this.root.hubGoals.getBeltBaseSpeed() *
this.root.dynamicTickrate.deltaSeconds *
globalConfig.itemSpacingOnBelts;
if (G_IS_DEV && globalConfig.debug.instantBelts) {
beltSpeed *= 100;
}
@ -229,35 +231,43 @@ export class BeltSystem extends GameSystemWithFilter {
const ejectorComp = entity.components.ItemEjector;
let maxProgress = 1;
/* PERFORMANCE OPTIMIZATION */
// Original:
// const isCurrentlyEjecting = ejectorComp.isAnySlotEjecting();
// Replaced (Since belts always have just one slot):
const ejectorSlot = ejectorComp.slots[0];
const isCurrentlyEjecting = ejectorSlot.item;
// When ejecting, we can not go further than the item spacing since it
// will be on the corner
if (ejectorComp.isAnySlotEjecting()) {
if (isCurrentlyEjecting) {
maxProgress = 1 - globalConfig.itemSpacingOnBelts;
} else {
// Otherwise our progress depends on the follow up
if (followUp) {
const spacingOnBelt = followUp.components.Belt.getDistanceToFirstItemCenter();
maxProgress = Math_min(2, 1 - globalConfig.itemSpacingOnBelts + spacingOnBelt);
assert(maxProgress >= 0.0, "max progress < 0 (I)");
maxProgress = Math.min(2, 1 - globalConfig.itemSpacingOnBelts + spacingOnBelt);
// Useful check, but hurts performance
// assert(maxProgress >= 0.0, "max progress < 0 (I)");
}
}
let speedMultiplier = 1;
if (beltComp.direction !== enumDirection.top) {
// Shaped belts are longer, thus being quicker
speedMultiplier = 1.41;
// Curved belts are shorter, thus being quicker (Looks weird otherwise)
speedMultiplier = SQRT_2;
}
// Not really nice. haven't found the reason for this yet.
if (items.length > 2 / globalConfig.itemSpacingOnBelts) {
logger.error("Fixing broken belt:", entity, items);
beltComp.sortedItems = [];
}
for (let itemIndex = items.length - 1; itemIndex >= 0; --itemIndex) {
const progressAndItem = items[itemIndex];
progressAndItem[0] = Math_min(maxProgress, progressAndItem[0] + speedMultiplier * beltSpeed);
progressAndItem[0] = Math.min(maxProgress, progressAndItem[0] + speedMultiplier * beltSpeed);
if (progressAndItem[0] >= 1.0) {
if (followUp) {
@ -273,14 +283,18 @@ export class BeltSystem extends GameSystemWithFilter {
}
} else {
// Try to give this item to a new belt
const freeSlot = ejectorComp.getFirstFreeSlot();
if (freeSlot === null) {
/* PERFORMANCE OPTIMIZATION */
// Original:
// const freeSlot = ejectorComp.getFirstFreeSlot();
// Replaced
if (ejectorSlot.item) {
// So, we don't have a free slot - damned!
progressAndItem[0] = 1.0;
maxProgress = 1 - globalConfig.itemSpacingOnBelts;
} else {
// We got a free slot, remove this item and keep it on the ejector slot
if (!ejectorComp.tryEject(freeSlot, progressAndItem[1])) {
if (!ejectorComp.tryEject(0, progressAndItem[1])) {
assert(false, "Ejection failed");
}
items.splice(itemIndex, 1);
@ -290,7 +304,7 @@ export class BeltSystem extends GameSystemWithFilter {
}
} else {
// We just moved this item forward, so determine the maximum progress of other items
maxProgress = Math_max(0, progressAndItem[0] - globalConfig.itemSpacingOnBelts);
maxProgress = Math.max(0, progressAndItem[0] - globalConfig.itemSpacingOnBelts);
}
}
}

View File

@ -6,19 +6,40 @@ import { ItemEjectorComponent } from "../components/item_ejector";
import { Entity } from "../entity";
import { GameSystemWithFilter } from "../game_system_with_filter";
import { Math_min } from "../../core/builtins";
import { createLogger } from "../../core/logging";
const logger = createLogger("systems/ejector");
export class ItemEjectorSystem extends GameSystemWithFilter {
constructor(root) {
super(root, [ItemEjectorComponent]);
/**
* @type {Array<{
* targetEntity: Entity,
* sourceSlot: import("../components/item_ejector").ItemEjectorSlot,
* destSlot: import("../components/item_acceptor").ItemAcceptorLocatedSlot
* }>}
*/
this.cache = [];
this.cacheNeedsUpdate = true;
this.root.signals.entityAdded.add(this.invalidateCache, this);
this.root.signals.entityDestroyed.add(this.invalidateCache, this);
}
update() {
const effectiveBeltSpeed = this.root.hubGoals.getBeltBaseSpeed() * globalConfig.itemSpacingOnBelts;
let progressGrowth = (effectiveBeltSpeed / 0.5) * this.root.dynamicTickrate.deltaSeconds;
invalidateCache() {
this.cacheNeedsUpdate = true;
}
if (G_IS_DEV && globalConfig.debug.instantBelts) {
progressGrowth = 1;
}
/**
* Precomputes the cache, which makes up for a huge performance improvement
*/
recomputeCache() {
logger.log("Recomputing cache");
const cache = [];
// Try to find acceptors for every ejector
for (let i = 0; i < this.allEntities.length; ++i) {
@ -29,17 +50,6 @@ export class ItemEjectorSystem extends GameSystemWithFilter {
// For every ejector slot, try to find an acceptor
for (let ejectorSlotIndex = 0; ejectorSlotIndex < ejectorComp.slots.length; ++ejectorSlotIndex) {
const ejectorSlot = ejectorComp.slots[ejectorSlotIndex];
const ejectingItem = ejectorSlot.item;
if (!ejectingItem) {
// No item ejected
continue;
}
ejectorSlot.progress = Math_min(1, ejectorSlot.progress + progressGrowth);
if (ejectorSlot.progress < 1.0) {
// Still ejecting
continue;
}
// Figure out where and into which direction we eject items
const ejectSlotWsTile = staticComp.localTileToWorld(ejectorSlot.pos);
@ -71,20 +81,63 @@ export class ItemEjectorSystem extends GameSystemWithFilter {
continue;
}
if (!targetAcceptorComp.canAcceptItem(matchingSlot.index, ejectingItem)) {
// Can not accept item
continue;
}
// Ok we found a connection
cache.push({
targetEntity,
sourceSlot: ejectorSlot,
destSlot: matchingSlot,
});
}
}
if (this.tryPassOverItem(ejectingItem, targetEntity, matchingSlot.index)) {
targetAcceptorComp.onItemAccepted(
matchingSlot.index,
matchingSlot.acceptedDirection,
ejectingItem
);
ejectorSlot.item = null;
continue;
}
this.cache = cache;
logger.log("Found", cache.length, "entries to update");
}
update() {
if (this.cacheNeedsUpdate) {
this.cacheNeedsUpdate = false;
this.recomputeCache();
}
// Precompute effective belt speed
const effectiveBeltSpeed = this.root.hubGoals.getBeltBaseSpeed() * globalConfig.itemSpacingOnBelts;
let progressGrowth = (effectiveBeltSpeed / 0.5) * this.root.dynamicTickrate.deltaSeconds;
if (G_IS_DEV && globalConfig.debug.instantBelts) {
progressGrowth = 1;
}
// Go over all cache entries
for (let i = 0; i < this.cache.length; ++i) {
const { sourceSlot, destSlot, targetEntity } = this.cache[i];
const item = sourceSlot.item;
if (!item) {
// No item available to be ejected
continue;
}
// Advance items on the slot
sourceSlot.progress = Math_min(1, sourceSlot.progress + progressGrowth);
// Check if we are still in the process of ejecting, can't proceed then
if (sourceSlot.progress < 1.0) {
continue;
}
// Check if the target acceptor can actually accept this item
const targetAcceptorComp = targetEntity.components.ItemAcceptor;
if (!targetAcceptorComp.canAcceptItem(destSlot.index, item)) {
continue;
}
// Try to hand over the item
if (this.tryPassOverItem(item, targetEntity, destSlot.index)) {
// Handover successful, clear slot
targetAcceptorComp.onItemAccepted(destSlot.index, destSlot.acceptedDirection, item);
sourceSlot.item = null;
continue;
}
}
}

View File

@ -24,11 +24,17 @@ export class MinerSystem extends GameSystemWithFilter {
// Check if miner is above an actual tile
const minerComp = entity.components.Miner;
const staticComp = entity.components.StaticMapEntity;
const tileBelow = this.root.map.getLowerLayerContentXY(staticComp.origin.x, staticComp.origin.y);
if (!tileBelow) {
continue;
if (!minerComp.cachedMinedItem) {
const staticComp = entity.components.StaticMapEntity;
const tileBelow = this.root.map.getLowerLayerContentXY(
staticComp.origin.x,
staticComp.origin.y
);
if (!tileBelow) {
continue;
}
minerComp.cachedMinedItem = tileBelow;
}
// First, try to get rid of chained items
@ -40,20 +46,9 @@ export class MinerSystem extends GameSystemWithFilter {
}
if (this.root.time.isIngameTimerExpired(minerComp.lastMiningTime, 1 / miningSpeed)) {
const lowerLayerItem = this.root.map.getLowerLayerContentXY(
staticComp.origin.x,
staticComp.origin.y
);
// TODO: Should not be required actually
if (!lowerLayerItem) {
// Nothing below;
continue;
}
if (this.tryPerformMinerEject(entity, lowerLayerItem)) {
if (this.tryPerformMinerEject(entity, minerComp.cachedMinedItem)) {
// Analytics hook
this.root.signals.itemProduced.dispatch(lowerLayerItem);
this.root.signals.itemProduced.dispatch(minerComp.cachedMinedItem);
// Actually mine
minerComp.lastMiningTime = this.root.time.now();
@ -114,18 +109,17 @@ export class MinerSystem extends GameSystemWithFilter {
if (entity && entity.components.Miner) {
const staticComp = entity.components.StaticMapEntity;
const minerComp = entity.components.Miner;
if (!staticComp.shouldBeDrawn(parameters)) {
continue;
}
if (!minerComp.cachedMinedItem) {
continue;
}
const lowerLayerItem = this.root.map.getLowerLayerContentXY(
staticComp.origin.x,
staticComp.origin.y
);
if (lowerLayerItem) {
if (minerComp.cachedMinedItem) {
const padding = 3;
parameters.context.fillStyle = lowerLayerItem.getBackgroundColorAsResource();
parameters.context.fillStyle = minerComp.cachedMinedItem.getBackgroundColorAsResource();
parameters.context.fillRect(
staticComp.origin.x * globalConfig.tileSize + padding,
staticComp.origin.y * globalConfig.tileSize + padding,
@ -134,8 +128,8 @@ export class MinerSystem extends GameSystemWithFilter {
);
}
if (lowerLayerItem) {
lowerLayerItem.draw(
if (minerComp.cachedMinedItem) {
minerComp.cachedMinedItem.draw(
(0.5 + staticComp.origin.x) * globalConfig.tileSize,
(0.5 + staticComp.origin.y) * globalConfig.tileSize,
parameters

Some files were not shown because too many files have changed in this diff Show More