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

Merge pull request #3 from tobspr/master

Updating from base project
This commit is contained in:
BaleineSanguine 2020-09-23 18:35:25 +02:00 committed by GitHub
commit 8a019c285d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
85 changed files with 17213 additions and 16702 deletions

View File

@ -81,7 +81,7 @@ This project is based on ES5. Some ES2015 features are used but most of them are
8. In `translations/base-en.yaml` add it to two sections: `buildings.[my_building].XXX` (See other buildings) and also `keybindings.mappings.[my_building]`. Be sure to do it the same way as other buildings do!
9. Create a icon (128x128, [prefab](https://github.com/tobspr/shapez.io-artwork/blob/master/ui/toolbar-icons.psd)) for your building and save it in `res/ui/buildings_icons` with the id of your building
10. Create a tutorial image (600x600) for your building and save it in `res/ui/building_tutorials`
11. In `src/css/icons.scss` add your building to `$buildings` as well as `$buildingAndVariants`
11. In `src/css/resources.scss` add your building to `$buildings` as well as `$buildingAndVariants`
12. Done! Optional: Add a new reward for unlocking your building at some point.
#### Adding a new game system

View File

@ -1,99 +1,137 @@
const path = require("path");
const buildUtils = require("./buildutils");
function gulptasksCSS($, gulp, buildFolder, browserSync) {
// The assets plugin copies the files
const commitHash = buildUtils.getRevision();
const postcssAssetsPlugin = cachebust =>
$.postcssAssets({
loadPaths: [path.join(buildFolder, "res", "ui")],
basePath: buildFolder,
baseUrl: ".",
cachebuster: cachebust
? (filePath, urlPathname) => ({
pathname: buildUtils.cachebust(urlPathname, commitHash),
})
: "",
});
// Postcss configuration
const postcssPlugins = (prod, { cachebust = false }) => {
const plugins = [postcssAssetsPlugin(cachebust)];
if (prod) {
plugins.unshift(
$.postcssUnprefix(),
$.postcssPresetEnv({
browsers: ["> 0.1%"],
})
);
plugins.push(
$.cssMqpacker({
sort: true,
}),
$.cssnano({
preset: [
"advanced",
{
cssDeclarationSorter: false,
discardUnused: true,
mergeIdents: false,
reduceIdents: true,
zindex: true,
},
],
}),
$.postcssRoundSubpixels()
);
}
return plugins;
};
// Performs linting on css
gulp.task("css.lint", () => {
return gulp
.src(["../src/css/**/*.scss"])
.pipe($.sassLint({ configFile: ".sasslint.yml" }))
.pipe($.sassLint.format())
.pipe($.sassLint.failOnError());
});
// Builds the css in dev mode
gulp.task("css.dev", () => {
return gulp
.src(["../src/css/main.scss"])
.pipe($.plumber())
.pipe($.sass.sync().on("error", $.sass.logError))
.pipe($.postcss(postcssPlugins(false, {})))
.pipe(gulp.dest(buildFolder))
.pipe(browserSync.stream());
});
// Builds the css in production mode (=minified)
gulp.task("css.prod", () => {
return (
gulp
.src("../src/css/main.scss", { cwd: __dirname })
.pipe($.plumber())
.pipe($.sass.sync({ outputStyle: "compressed" }).on("error", $.sass.logError))
.pipe($.postcss(postcssPlugins(true, { cachebust: true })))
.pipe(gulp.dest(buildFolder))
);
});
// Builds the css in production mode (=minified), without cachebusting
gulp.task("css.prod-standalone", () => {
return (
gulp
.src("../src/css/main.scss", { cwd: __dirname })
.pipe($.plumber())
.pipe($.sass.sync({ outputStyle: "compressed" }).on("error", $.sass.logError))
.pipe($.postcss(postcssPlugins(true, { cachebust: false })))
.pipe(gulp.dest(buildFolder))
);
});
}
module.exports = {
gulptasksCSS,
};
const path = require("path");
const buildUtils = require("./buildutils");
function gulptasksCSS($, gulp, buildFolder, browserSync) {
// The assets plugin copies the files
const commitHash = buildUtils.getRevision();
const postcssAssetsPlugin = cachebust =>
$.postcssAssets({
loadPaths: [path.join(buildFolder, "res", "ui")],
basePath: buildFolder,
baseUrl: ".",
cachebuster: cachebust
? (filePath, urlPathname) => ({
pathname: buildUtils.cachebust(urlPathname, commitHash),
})
: "",
});
// Postcss configuration
const postcssPlugins = (prod, { cachebust = false }) => {
const plugins = [postcssAssetsPlugin(cachebust)];
if (prod) {
plugins.unshift(
$.postcssUnprefix(),
$.postcssPresetEnv({
browsers: ["> 0.1%"],
})
);
plugins.push(
$.cssMqpacker({
sort: true,
}),
$.cssnano({
preset: [
"advanced",
{
cssDeclarationSorter: false,
discardUnused: true,
mergeIdents: false,
reduceIdents: true,
zindex: true,
},
],
}),
$.postcssRoundSubpixels()
);
}
return plugins;
};
// Performs linting on css
gulp.task("css.lint", () => {
return gulp
.src(["../src/css/**/*.scss"])
.pipe($.sassLint({ configFile: ".sasslint.yml" }))
.pipe($.sassLint.format())
.pipe($.sassLint.failOnError());
});
function resourcesTask({ cachebust, isProd }) {
return gulp
.src("../src/css/main.scss", { cwd: __dirname })
.pipe($.plumber())
.pipe($.sass.sync().on("error", $.sass.logError))
.pipe(
$.postcss([
$.postcssCriticalSplit({
blockTag: "@load-async",
}),
])
)
.pipe($.rename("async-resources.css"))
.pipe($.postcss(postcssPlugins(isProd, { cachebust })))
.pipe(gulp.dest(buildFolder))
.pipe(browserSync.stream());
}
// Builds the css resources
gulp.task("css.resources.dev", () => {
return resourcesTask({ cachebust: false, isProd: false });
});
// Builds the css resources in prod (=minified)
gulp.task("css.resources.prod", () => {
return resourcesTask({ cachebust: true, isProd: true });
});
// Builds the css resources in prod (=minified), without cachebusting
gulp.task("css.resources.prod-standalone", () => {
return resourcesTask({ cachebust: false, isProd: true });
});
function mainTask({ cachebust, isProd }) {
return gulp
.src("../src/css/main.scss", { cwd: __dirname })
.pipe($.plumber())
.pipe($.sass.sync().on("error", $.sass.logError))
.pipe(
$.postcss([
$.postcssCriticalSplit({
blockTag: "@load-async",
output: "rest",
}),
])
)
.pipe($.postcss(postcssPlugins(isProd, { cachebust })))
.pipe(gulp.dest(buildFolder))
.pipe(browserSync.stream());
}
// Builds the css main
gulp.task("css.main.dev", () => {
return mainTask({ cachebust: false, isProd: false });
});
// Builds the css main in prod (=minified)
gulp.task("css.main.prod", () => {
return mainTask({ cachebust: true, isProd: true });
});
// Builds the css main in prod (=minified), without cachebusting
gulp.task("css.main.prod-standalone", () => {
return mainTask({ cachebust: false, isProd: true });
});
gulp.task("css.dev", gulp.parallel("css.main.dev", "css.resources.dev"));
gulp.task("css.prod", gulp.parallel("css.main.prod", "css.resources.prod"));
gulp.task(
"css.prod-standalone",
gulp.parallel("css.main.prod-standalone", "css.resources.prod-standalone")
);
}
module.exports = {
gulptasksCSS,
};

View File

@ -1,325 +1,325 @@
/* eslint-disable */
require("colors");
const gulp = require("gulp");
const browserSync = require("browser-sync").create({});
const path = require("path");
const deleteEmpty = require("delete-empty");
const execSync = require("child_process").execSync;
const lfsOutput = execSync("git lfs install", { encoding: "utf-8" });
if (!lfsOutput.toLowerCase().includes("git lfs initialized")) {
console.error(`
Git LFS is not installed, unable to build.
To install Git LFS on Linux:
- Arch:
sudo pacman -S git-lfs
- Debian/Ubuntu:
sudo apt install git-lfs
For other systems, see:
https://github.com/git-lfs/git-lfs/wiki/Installation
`);
process.exit(1);
}
// Load other plugins dynamically
const $ = require("gulp-load-plugins")({
scope: ["devDependencies"],
pattern: "*",
});
// Check environment variables
const envVars = [
"SHAPEZ_CLI_SERVER_HOST",
// "SHAPEZ_CLI_PHONEGAP_KEY",
"SHAPEZ_CLI_ALPHA_FTP_USER",
"SHAPEZ_CLI_ALPHA_FTP_PW",
"SHAPEZ_CLI_STAGING_FTP_USER",
"SHAPEZ_CLI_STAGING_FTP_PW",
"SHAPEZ_CLI_LIVE_FTP_USER",
"SHAPEZ_CLI_LIVE_FTP_PW",
];
for (let i = 0; i < envVars.length; ++i) {
if (!process.env[envVars[i]]) {
console.warn("Please set", envVars[i]);
// process.exit(1);
}
}
const baseDir = path.join(__dirname, "..");
const buildFolder = path.join(baseDir, "build");
const imgres = require("./image-resources");
imgres.gulptasksImageResources($, gulp, buildFolder);
const css = require("./css");
css.gulptasksCSS($, gulp, buildFolder, browserSync);
const sounds = require("./sounds");
sounds.gulptasksSounds($, gulp, buildFolder);
const js = require("./js");
js.gulptasksJS($, gulp, buildFolder, browserSync);
const html = require("./html");
html.gulptasksHTML($, gulp, buildFolder, browserSync);
const ftp = require("./ftp");
ftp.gulptasksFTP($, gulp, buildFolder);
const docs = require("./docs");
docs.gulptasksDocs($, gulp, buildFolder);
const standalone = require("./standalone");
standalone.gulptasksStandalone($, gulp, buildFolder);
const translations = require("./translations");
translations.gulptasksTranslations($, gulp, buildFolder);
// FIXME
// const cordova = require("./cordova");
// cordova.gulptasksCordova($, gulp, buildFolder);
///////////////////// BUILD TASKS /////////////////////
// Cleans up everything
gulp.task("utils.cleanBuildFolder", () => {
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, allowEmpty: true })
.pipe($.clean({ force: true }));
});
gulp.task("utils.cleanup", gulp.series("utils.cleanBuildFolder", "utils.cleanBuildTempFolder"));
// Requires no uncomitted files
gulp.task("utils.requireCleanWorkingTree", cb => {
let output = $.trim(execSync("git status -su").toString("ascii")).replace(/\r/gi, "").split("\n");
// Filter files which are OK to be untracked
output = output
.map(x => x.replace(/[\r\n]+/gi, ""))
.filter(x => x.indexOf(".local.js") < 0)
.filter(x => x.length > 0);
if (output.length > 0) {
console.error("\n\nYou have unstaged changes, please commit everything first!");
console.error("Unstaged files:");
console.error(output.map(x => "'" + x + "'").join("\n"));
process.exit(1);
}
cb();
});
gulp.task("utils.copyAdditionalBuildFiles", cb => {
const additionalFolder = path.join("additional_build_files");
const additionalSrcGlobs = [
path.join(additionalFolder, "**/*.*"),
path.join(additionalFolder, "**/.*"),
path.join(additionalFolder, "**/*"),
];
return gulp.src(additionalSrcGlobs).pipe(gulp.dest(buildFolder));
});
// Starts a webserver on the built directory (useful for testing prod build)
gulp.task("main.webserver", () => {
return gulp.src(buildFolder).pipe(
$.webserver({
livereload: {
enable: true,
},
directoryListing: false,
open: true,
port: 3005,
})
);
});
function serve({ standalone }) {
browserSync.init({
server: buildFolder,
port: 3005,
ghostMode: {
clicks: false,
scroll: false,
location: false,
forms: false,
},
logLevel: "info",
logPrefix: "BS",
online: false,
xip: false,
notify: false,
reloadDebounce: 100,
reloadOnRestart: true,
watchEvents: ["add", "change"],
});
// Watch .scss files, those trigger a css rebuild
gulp.watch(["../src/**/*.scss"], gulp.series("css.dev"));
// Watch .html files, those trigger a html rebuild
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"], gulp.series("sounds.dev"));
// Watch translations
gulp.watch("../translations/**/*.yaml", gulp.series("translations.convertToJson"));
gulp.watch(
["../res_raw/sounds/sfx/*.mp3", "../res_raw/sounds/sfx/*.wav"],
gulp.series("sounds.sfx", "sounds.copy")
);
gulp.watch(
["../res_raw/sounds/music/*.mp3", "../res_raw/sounds/music/*.wav"],
gulp.series("sounds.music", "sounds.copy")
);
// Watch resource files and copy them on change
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", 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 (path) {
return gulp.src(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) {
gulp.series("js.standalone-dev.watch")(() => true);
} else {
gulp.series("js.dev.watch")(() => true);
}
}
///////////////////// RUNNABLE TASKS /////////////////////
// Pre and postbuild
gulp.task("step.baseResources", gulp.series("imgres.allOptimized"));
gulp.task("step.deleteEmpty", cb => {
deleteEmpty.sync(buildFolder);
cb();
});
gulp.task("step.postbuild", gulp.series("imgres.cleanupUnusedCssInlineImages", "step.deleteEmpty"));
// Builds everything (dev)
gulp.task(
"build.dev",
gulp.series(
"utils.cleanup",
"utils.copyAdditionalBuildFiles",
"imgres.atlas",
"sounds.dev",
"imgres.copyImageResources",
"imgres.copyNonImageResources",
"translations.fullBuild",
"css.dev",
"html.dev"
)
);
// Builds everything (standalone -dev)
gulp.task(
"build.standalone.dev",
gulp.series(
"utils.cleanup",
"imgres.atlas",
"sounds.dev",
"imgres.copyImageResources",
"imgres.copyNonImageResources",
"translations.fullBuild",
"js.standalone-dev",
"css.dev",
"html.standalone-dev"
)
);
// Builds everything (staging)
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", 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", 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", 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",
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",
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")
);
// Builds everything (standalone-prod)
gulp.task(
"step.standalone-prod.code",
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",
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")
);
// Deploying!
gulp.task(
"main.deploy.alpha",
gulp.series("utils.requireCleanWorkingTree", "build.staging", "ftp.upload.alpha")
);
gulp.task(
"main.deploy.staging",
gulp.series("utils.requireCleanWorkingTree", "build.staging", "ftp.upload.staging")
);
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"));
/* eslint-disable */
require("colors");
const gulp = require("gulp");
const browserSync = require("browser-sync").create({});
const path = require("path");
const deleteEmpty = require("delete-empty");
const execSync = require("child_process").execSync;
const lfsOutput = execSync("git lfs install", { encoding: "utf-8" });
if (!lfsOutput.toLowerCase().includes("git lfs initialized")) {
console.error(`
Git LFS is not installed, unable to build.
To install Git LFS on Linux:
- Arch:
sudo pacman -S git-lfs
- Debian/Ubuntu:
sudo apt install git-lfs
For other systems, see:
https://github.com/git-lfs/git-lfs/wiki/Installation
`);
process.exit(1);
}
// Load other plugins dynamically
const $ = require("gulp-load-plugins")({
scope: ["devDependencies"],
pattern: "*",
});
// Check environment variables
const envVars = [
"SHAPEZ_CLI_SERVER_HOST",
// "SHAPEZ_CLI_PHONEGAP_KEY",
"SHAPEZ_CLI_ALPHA_FTP_USER",
"SHAPEZ_CLI_ALPHA_FTP_PW",
"SHAPEZ_CLI_STAGING_FTP_USER",
"SHAPEZ_CLI_STAGING_FTP_PW",
"SHAPEZ_CLI_LIVE_FTP_USER",
"SHAPEZ_CLI_LIVE_FTP_PW",
];
for (let i = 0; i < envVars.length; ++i) {
if (!process.env[envVars[i]]) {
console.warn("Please set", envVars[i]);
// process.exit(1);
}
}
const baseDir = path.join(__dirname, "..");
const buildFolder = path.join(baseDir, "build");
const imgres = require("./image-resources");
imgres.gulptasksImageResources($, gulp, buildFolder);
const css = require("./css");
css.gulptasksCSS($, gulp, buildFolder, browserSync);
const sounds = require("./sounds");
sounds.gulptasksSounds($, gulp, buildFolder);
const js = require("./js");
js.gulptasksJS($, gulp, buildFolder, browserSync);
const html = require("./html");
html.gulptasksHTML($, gulp, buildFolder, browserSync);
const ftp = require("./ftp");
ftp.gulptasksFTP($, gulp, buildFolder);
const docs = require("./docs");
docs.gulptasksDocs($, gulp, buildFolder);
const standalone = require("./standalone");
standalone.gulptasksStandalone($, gulp, buildFolder);
const translations = require("./translations");
translations.gulptasksTranslations($, gulp, buildFolder);
// FIXME
// const cordova = require("./cordova");
// cordova.gulptasksCordova($, gulp, buildFolder);
///////////////////// BUILD TASKS /////////////////////
// Cleans up everything
gulp.task("utils.cleanBuildFolder", () => {
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, allowEmpty: true })
.pipe($.clean({ force: true }));
});
gulp.task("utils.cleanup", gulp.series("utils.cleanBuildFolder", "utils.cleanBuildTempFolder"));
// Requires no uncomitted files
gulp.task("utils.requireCleanWorkingTree", cb => {
let output = $.trim(execSync("git status -su").toString("ascii")).replace(/\r/gi, "").split("\n");
// Filter files which are OK to be untracked
output = output
.map(x => x.replace(/[\r\n]+/gi, ""))
.filter(x => x.indexOf(".local.js") < 0)
.filter(x => x.length > 0);
if (output.length > 0) {
console.error("\n\nYou have unstaged changes, please commit everything first!");
console.error("Unstaged files:");
console.error(output.map(x => "'" + x + "'").join("\n"));
process.exit(1);
}
cb();
});
gulp.task("utils.copyAdditionalBuildFiles", cb => {
const additionalFolder = path.join("additional_build_files");
const additionalSrcGlobs = [
path.join(additionalFolder, "**/*.*"),
path.join(additionalFolder, "**/.*"),
path.join(additionalFolder, "**/*"),
];
return gulp.src(additionalSrcGlobs).pipe(gulp.dest(buildFolder));
});
// Starts a webserver on the built directory (useful for testing prod build)
gulp.task("main.webserver", () => {
return gulp.src(buildFolder).pipe(
$.webserver({
livereload: {
enable: true,
},
directoryListing: false,
open: true,
port: 3005,
})
);
});
function serve({ standalone }) {
browserSync.init({
server: buildFolder,
port: 3005,
ghostMode: {
clicks: false,
scroll: false,
location: false,
forms: false,
},
logLevel: "info",
logPrefix: "BS",
online: false,
xip: false,
notify: false,
reloadDebounce: 100,
reloadOnRestart: true,
watchEvents: ["add", "change"],
});
// Watch .scss files, those trigger a css rebuild
gulp.watch(["../src/**/*.scss"], gulp.series("css.dev"));
// Watch .html files, those trigger a html rebuild
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"], gulp.series("sounds.dev"));
// Watch translations
gulp.watch("../translations/**/*.yaml", gulp.series("translations.convertToJson"));
gulp.watch(
["../res_raw/sounds/sfx/*.mp3", "../res_raw/sounds/sfx/*.wav"],
gulp.series("sounds.sfx", "sounds.copy")
);
gulp.watch(
["../res_raw/sounds/music/*.mp3", "../res_raw/sounds/music/*.wav"],
gulp.series("sounds.music", "sounds.copy")
);
// Watch resource files and copy them on change
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", 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 (path) {
return gulp.src(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) {
gulp.series("js.standalone-dev.watch")(() => true);
} else {
gulp.series("js.dev.watch")(() => true);
}
}
///////////////////// RUNNABLE TASKS /////////////////////
// Pre and postbuild
gulp.task("step.baseResources", gulp.series("imgres.allOptimized"));
gulp.task("step.deleteEmpty", cb => {
deleteEmpty.sync(buildFolder);
cb();
});
gulp.task("step.postbuild", gulp.series("imgres.cleanupUnusedCssInlineImages", "step.deleteEmpty"));
// Builds everything (dev)
gulp.task(
"build.dev",
gulp.series(
"utils.cleanup",
"utils.copyAdditionalBuildFiles",
"imgres.atlas",
"sounds.dev",
"imgres.copyImageResources",
"imgres.copyNonImageResources",
"translations.fullBuild",
"css.dev",
"html.dev"
)
);
// Builds everything (standalone -dev)
gulp.task(
"build.standalone.dev",
gulp.series(
"utils.cleanup",
"imgres.atlas",
"sounds.dev",
"imgres.copyImageResources",
"imgres.copyNonImageResources",
"translations.fullBuild",
"js.standalone-dev",
"css.dev",
"html.standalone-dev"
)
);
// Builds everything (staging)
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", 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", 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", 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",
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",
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")
);
// Builds everything (standalone-prod)
gulp.task(
"step.standalone-prod.code",
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",
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")
);
// Deploying!
gulp.task(
"main.deploy.alpha",
gulp.series("utils.requireCleanWorkingTree", "build.staging", "ftp.upload.alpha")
);
gulp.task(
"main.deploy.staging",
gulp.series("utils.requireCleanWorkingTree", "build.staging", "ftp.upload.staging")
);
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

@ -1,283 +1,301 @@
const buildUtils = require("./buildutils");
const fs = require("fs");
const path = require("path");
const crypto = require("crypto");
function computeIntegrityHash(fullPath, algorithm = "sha256") {
const file = fs.readFileSync(fullPath);
const hash = crypto.createHash(algorithm).update(file).digest("base64");
return algorithm + "-" + hash;
}
function gulptasksHTML($, gulp, buildFolder) {
const commitHash = buildUtils.getRevision();
async function buildHtml(
apiUrl,
{ analytics = false, standalone = false, app = false, integrity = true, enableCachebust = true }
) {
function cachebust(url) {
if (enableCachebust) {
return buildUtils.cachebust(url, commitHash);
}
return url;
}
const hasLocalFiles = standalone || app;
return gulp
.src("../src/html/" + (standalone ? "index.standalone.html" : "index.html"))
.pipe(
$.dom(/** @this {Document} **/ function () {
const document = this;
// Preconnect to api
const prefetchLink = document.createElement("link");
prefetchLink.rel = "preconnect";
prefetchLink.href = apiUrl;
prefetchLink.setAttribute("crossorigin", "anonymous");
document.head.appendChild(prefetchLink);
// Append css
const css = document.createElement("link");
css.rel = "stylesheet";
css.type = "text/css";
css.media = "none";
css.setAttribute("onload", "this.media='all'");
css.href = cachebust("main.css");
if (integrity) {
css.setAttribute(
"integrity",
computeIntegrityHash(path.join(buildFolder, "main.css"))
);
}
document.head.appendChild(css);
if (app) {
// Append cordova link
const cdv = document.createElement("script");
cdv.src = "cordova.js";
cdv.type = "text/javascript";
document.head.appendChild(cdv);
}
// Google analytics
if (analytics) {
const tagManagerScript = document.createElement("script");
tagManagerScript.src = "https://www.googletagmanager.com/gtag/js?id=UA-165342524-1";
tagManagerScript.setAttribute("async", "");
document.head.appendChild(tagManagerScript);
const initScript = document.createElement("script");
initScript.textContent = `
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'UA-165342524-1', { anonymize_ip: true });
`;
document.head.appendChild(initScript);
const abTestingScript = document.createElement("script");
abTestingScript.setAttribute(
"src",
"https://www.googleoptimize.com/optimize.js?id=OPT-M5NHCV7"
);
abTestingScript.setAttribute("async", "");
document.head.appendChild(abTestingScript);
}
// Do not need to preload in app or standalone
if (!hasLocalFiles) {
// Preload essentials
const preloads = ["fonts/GameFont.woff2"];
preloads.forEach(src => {
const preloadLink = document.createElement("link");
preloadLink.rel = "preload";
preloadLink.href = cachebust("res/" + src);
if (src.endsWith(".woff2")) {
preloadLink.setAttribute("crossorigin", "anonymous");
preloadLink.setAttribute("as", "font");
} else {
preloadLink.setAttribute("as", "image");
}
document.head.appendChild(preloadLink);
});
}
const loadingSvg = `background-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHN0eWxlPSJtYXJnaW46YXV0bztiYWNrZ3JvdW5kOjAgMCIgd2lkdGg9IjIwMCIgaGVpZ2h0PSIyMDAiIHZpZXdCb3g9IjAgMCAxMDAgMTAwIiBwcmVzZXJ2ZUFzcGVjdFJhdGlvPSJ4TWlkWU1pZCIgZGlzcGxheT0iYmxvY2siPjxjaXJjbGUgY3g9IjUwIiBjeT0iNTAiIGZpbGw9Im5vbmUiIHN0cm9rZT0iIzM5Mzc0NyIgc3Ryb2tlLXdpZHRoPSIzIiByPSI0MiIgc3Ryb2tlLWRhc2hhcnJheT0iMTk3LjkyMDMzNzE3NjE1Njk4IDY3Ljk3MzQ0NTcyNTM4NTY2IiB0cmFuc2Zvcm09InJvdGF0ZSg0OC4yNjUgNTAgNTApIj48YW5pbWF0ZVRyYW5zZm9ybSBhdHRyaWJ1dGVOYW1lPSJ0cmFuc2Zvcm0iIHR5cGU9InJvdGF0ZSIgcmVwZWF0Q291bnQ9ImluZGVmaW5pdGUiIGR1cj0iNS41NTU1NTU1NTU1NTU1NTVzIiB2YWx1ZXM9IjAgNTAgNTA7MzYwIDUwIDUwIiBrZXlUaW1lcz0iMDsxIi8+PC9jaXJjbGU+PC9zdmc+")`;
const loadingCss = `
@font-face {
font-family: 'GameFont';
font-style: normal;
font-weight: normal;
font-display: swap;
src: url('${cachebust("res/fonts/GameFont.woff2")}') format('woff2');
}
#ll_fp {
font-family: GameFont;
font-size: 14px;
position: fixed;
z-index: -1;
top: 0;
left: 0;
opacity: 0.05;
}
#ll_p {
display: flex;
position: fixed;
z-index: 99999;
top: 0;
left: 0;
right: 0;
bottom: 0;
justify-content:
center;
align-items: center;
}
#ll_p > div {
position: absolute;
text-align: center;
bottom: 40px;
left: 20px;
right: 20px;
color: #393747;
font-family: 'GameFont', sans-serif;
font-size: 20px;
}
#ll_p > span {
width: 60px;
height: 60px;
display: inline-flex;
background: center center / contain no-repeat;
${loadingSvg};
}
`;
const style = document.createElement("style");
style.setAttribute("type", "text/css");
style.textContent = loadingCss;
document.head.appendChild(style);
// Append loader, but not in standalone (directly include bundle there)
if (standalone) {
const bundleScript = document.createElement("script");
bundleScript.type = "text/javascript";
bundleScript.src = "bundle.js";
if (integrity) {
bundleScript.setAttribute(
"integrity",
computeIntegrityHash(path.join(buildFolder, "bundle.js"))
);
}
document.head.appendChild(bundleScript);
} else {
const loadJs = document.createElement("script");
loadJs.type = "text/javascript";
let scriptContent = "";
scriptContent += `var bundleSrc = '${cachebust("bundle.js")}';\n`;
scriptContent += `var bundleSrcTranspiled = '${cachebust(
"bundle-transpiled.js"
)}';\n`;
if (integrity) {
scriptContent +=
"var bundleIntegrity = '" +
computeIntegrityHash(path.join(buildFolder, "bundle.js")) +
"';\n";
scriptContent +=
"var bundleIntegrityTranspiled = '" +
computeIntegrityHash(path.join(buildFolder, "bundle-transpiled.js")) +
"';\n";
} else {
scriptContent += "var bundleIntegrity = null;\n";
scriptContent += "var bundleIntegrityTranspiled = null;\n";
}
scriptContent += fs.readFileSync("./bundle-loader.js").toString();
loadJs.textContent = scriptContent;
document.head.appendChild(loadJs);
}
const bodyContent = `
<div id="ll_fp">_</div>
<div id="ll_p">
<span></span>
<div>${hasLocalFiles ? "Loading" : "Downloading"} Game Files</div >
</div >
`;
document.body.innerHTML = bodyContent;
})
)
.pipe(
$.htmlmin({
caseSensitive: true,
collapseBooleanAttributes: true,
collapseInlineTagWhitespace: true,
collapseWhitespace: true,
preserveLineBreaks: true,
minifyJS: true,
minifyCSS: true,
quoteCharacter: '"',
useShortDoctype: true,
})
)
.pipe($.htmlBeautify())
.pipe($.rename("index.html"))
.pipe(gulp.dest(buildFolder));
}
gulp.task("html.dev", () => {
return buildHtml("http://localhost:5005", {
analytics: false,
integrity: false,
enableCachebust: false,
});
});
gulp.task("html.staging", () => {
return buildHtml("https://api-staging.shapez.io", {
analytics: true,
});
});
gulp.task("html.prod", () => {
return buildHtml("https://analytics.shapez.io", {
analytics: true,
});
});
gulp.task("html.standalone-dev", () => {
return buildHtml("https://localhost:5005", {
analytics: false,
standalone: true,
integrity: false,
enableCachebust: false,
});
});
gulp.task("html.standalone-beta", () => {
return buildHtml("https://api-staging.shapez.io", {
analytics: false,
standalone: true,
enableCachebust: false,
});
});
gulp.task("html.standalone-prod", () => {
return buildHtml("https://analytics.shapez.io", {
analytics: false,
standalone: true,
enableCachebust: false,
});
});
}
module.exports = {
gulptasksHTML,
};
const buildUtils = require("./buildutils");
const fs = require("fs");
const path = require("path");
const crypto = require("crypto");
function computeIntegrityHash(fullPath, algorithm = "sha256") {
const file = fs.readFileSync(fullPath);
const hash = crypto.createHash(algorithm).update(file).digest("base64");
return algorithm + "-" + hash;
}
function gulptasksHTML($, gulp, buildFolder) {
const commitHash = buildUtils.getRevision();
async function buildHtml(
apiUrl,
{ analytics = false, standalone = false, app = false, integrity = true, enableCachebust = true }
) {
function cachebust(url) {
if (enableCachebust) {
return buildUtils.cachebust(url, commitHash);
}
return url;
}
const hasLocalFiles = standalone || app;
return gulp
.src("../src/html/" + (standalone ? "index.standalone.html" : "index.html"))
.pipe(
$.dom(
/** @this {Document} **/ function () {
const document = this;
// Preconnect to api
const prefetchLink = document.createElement("link");
prefetchLink.rel = "preconnect";
prefetchLink.href = apiUrl;
prefetchLink.setAttribute("crossorigin", "anonymous");
document.head.appendChild(prefetchLink);
// Append css
const css = document.createElement("link");
css.rel = "stylesheet";
css.type = "text/css";
css.media = "none";
css.setAttribute("onload", "this.media='all'");
css.href = cachebust("main.css");
if (integrity) {
css.setAttribute(
"integrity",
computeIntegrityHash(path.join(buildFolder, "main.css"))
);
}
document.head.appendChild(css);
// Append async css
const asyncCss = document.createElement("link");
asyncCss.rel = "stylesheet";
asyncCss.type = "text/css";
asyncCss.media = "none";
asyncCss.setAttribute("onload", "this.media='all'");
asyncCss.href = cachebust("async-resources.css");
if (integrity) {
asyncCss.setAttribute(
"integrity",
computeIntegrityHash(path.join(buildFolder, "async-resources.css"))
);
}
document.head.appendChild(asyncCss);
if (app) {
// Append cordova link
const cdv = document.createElement("script");
cdv.src = "cordova.js";
cdv.type = "text/javascript";
document.head.appendChild(cdv);
}
// Google analytics
if (analytics) {
const tagManagerScript = document.createElement("script");
tagManagerScript.src =
"https://www.googletagmanager.com/gtag/js?id=UA-165342524-1";
tagManagerScript.setAttribute("async", "");
document.head.appendChild(tagManagerScript);
const initScript = document.createElement("script");
initScript.textContent = `
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'UA-165342524-1', { anonymize_ip: true });
`;
document.head.appendChild(initScript);
const abTestingScript = document.createElement("script");
abTestingScript.setAttribute(
"src",
"https://www.googleoptimize.com/optimize.js?id=OPT-M5NHCV7"
);
abTestingScript.setAttribute("async", "");
document.head.appendChild(abTestingScript);
}
// Do not need to preload in app or standalone
if (!hasLocalFiles) {
// Preload essentials
const preloads = ["fonts/GameFont.woff2"];
preloads.forEach(src => {
const preloadLink = document.createElement("link");
preloadLink.rel = "preload";
preloadLink.href = cachebust("res/" + src);
if (src.endsWith(".woff2")) {
preloadLink.setAttribute("crossorigin", "anonymous");
preloadLink.setAttribute("as", "font");
} else {
preloadLink.setAttribute("as", "image");
}
document.head.appendChild(preloadLink);
});
}
const loadingSvg = `background-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHN0eWxlPSJtYXJnaW46YXV0bztiYWNrZ3JvdW5kOjAgMCIgd2lkdGg9IjIwMCIgaGVpZ2h0PSIyMDAiIHZpZXdCb3g9IjAgMCAxMDAgMTAwIiBwcmVzZXJ2ZUFzcGVjdFJhdGlvPSJ4TWlkWU1pZCIgZGlzcGxheT0iYmxvY2siPjxjaXJjbGUgY3g9IjUwIiBjeT0iNTAiIGZpbGw9Im5vbmUiIHN0cm9rZT0iIzM5Mzc0NyIgc3Ryb2tlLXdpZHRoPSIzIiByPSI0MiIgc3Ryb2tlLWRhc2hhcnJheT0iMTk3LjkyMDMzNzE3NjE1Njk4IDY3Ljk3MzQ0NTcyNTM4NTY2IiB0cmFuc2Zvcm09InJvdGF0ZSg0OC4yNjUgNTAgNTApIj48YW5pbWF0ZVRyYW5zZm9ybSBhdHRyaWJ1dGVOYW1lPSJ0cmFuc2Zvcm0iIHR5cGU9InJvdGF0ZSIgcmVwZWF0Q291bnQ9ImluZGVmaW5pdGUiIGR1cj0iNS41NTU1NTU1NTU1NTU1NTVzIiB2YWx1ZXM9IjAgNTAgNTA7MzYwIDUwIDUwIiBrZXlUaW1lcz0iMDsxIi8+PC9jaXJjbGU+PC9zdmc+")`;
const loadingCss = `
@font-face {
font-family: 'GameFont';
font-style: normal;
font-weight: normal;
font-display: swap;
src: url('${cachebust("res/fonts/GameFont.woff2")}') format('woff2');
}
#ll_fp {
font-family: GameFont;
font-size: 14px;
position: fixed;
z-index: -1;
top: 0;
left: 0;
opacity: 0.05;
}
#ll_p {
display: flex;
position: fixed;
z-index: 99999;
top: 0;
left: 0;
right: 0;
bottom: 0;
justify-content:
center;
align-items: center;
}
#ll_p > div {
position: absolute;
text-align: center;
bottom: 40px;
left: 20px;
right: 20px;
color: #393747;
font-family: 'GameFont', sans-serif;
font-size: 20px;
}
#ll_p > span {
width: 60px;
height: 60px;
display: inline-flex;
background: center center / contain no-repeat;
${loadingSvg};
}
`;
const style = document.createElement("style");
style.setAttribute("type", "text/css");
style.textContent = loadingCss;
document.head.appendChild(style);
// Append loader, but not in standalone (directly include bundle there)
if (standalone) {
const bundleScript = document.createElement("script");
bundleScript.type = "text/javascript";
bundleScript.src = "bundle.js";
if (integrity) {
bundleScript.setAttribute(
"integrity",
computeIntegrityHash(path.join(buildFolder, "bundle.js"))
);
}
document.head.appendChild(bundleScript);
} else {
const loadJs = document.createElement("script");
loadJs.type = "text/javascript";
let scriptContent = "";
scriptContent += `var bundleSrc = '${cachebust("bundle.js")}';\n`;
scriptContent += `var bundleSrcTranspiled = '${cachebust(
"bundle-transpiled.js"
)}';\n`;
if (integrity) {
scriptContent +=
"var bundleIntegrity = '" +
computeIntegrityHash(path.join(buildFolder, "bundle.js")) +
"';\n";
scriptContent +=
"var bundleIntegrityTranspiled = '" +
computeIntegrityHash(path.join(buildFolder, "bundle-transpiled.js")) +
"';\n";
} else {
scriptContent += "var bundleIntegrity = null;\n";
scriptContent += "var bundleIntegrityTranspiled = null;\n";
}
scriptContent += fs.readFileSync("./bundle-loader.js").toString();
loadJs.textContent = scriptContent;
document.head.appendChild(loadJs);
}
const bodyContent = `
<div id="ll_fp">_</div>
<div id="ll_p">
<span></span>
<div>${hasLocalFiles ? "Loading" : "Downloading"} Game Files</div >
</div >
`;
document.body.innerHTML = bodyContent;
}
)
)
.pipe(
$.htmlmin({
caseSensitive: true,
collapseBooleanAttributes: true,
collapseInlineTagWhitespace: true,
collapseWhitespace: true,
preserveLineBreaks: true,
minifyJS: true,
minifyCSS: true,
quoteCharacter: '"',
useShortDoctype: true,
})
)
.pipe($.htmlBeautify())
.pipe($.rename("index.html"))
.pipe(gulp.dest(buildFolder));
}
gulp.task("html.dev", () => {
return buildHtml("http://localhost:5005", {
analytics: false,
integrity: false,
enableCachebust: false,
});
});
gulp.task("html.staging", () => {
return buildHtml("https://api-staging.shapez.io", {
analytics: true,
});
});
gulp.task("html.prod", () => {
return buildHtml("https://analytics.shapez.io", {
analytics: true,
});
});
gulp.task("html.standalone-dev", () => {
return buildHtml("https://localhost:5005", {
analytics: false,
standalone: true,
integrity: false,
enableCachebust: false,
});
});
gulp.task("html.standalone-beta", () => {
return buildHtml("https://api-staging.shapez.io", {
analytics: false,
standalone: true,
enableCachebust: false,
});
});
gulp.task("html.standalone-prod", () => {
return buildHtml("https://analytics.shapez.io", {
analytics: false,
standalone: true,
enableCachebust: false,
});
});
}
module.exports = {
gulptasksHTML,
};

View File

@ -1,110 +1,111 @@
{
"name": "builder",
"version": "1.0.0",
"description": "builder",
"private": true,
"scripts": {
"gulp": "gulp"
},
"author": "tobspr",
"license": "private",
"dependencies": {
"@babel/core": "^7.9.0",
"@babel/plugin-transform-block-scoping": "^7.4.4",
"@babel/plugin-transform-classes": "^7.5.5",
"@babel/preset-env": "^7.5.4",
"@types/cordova": "^0.0.34",
"@types/filesystem": "^0.0.29",
"@types/node": "^12.7.5",
"ajv": "^6.10.2",
"audiosprite": "^0.7.2",
"babel-loader": "^8.1.0",
"browser-sync": "^2.26.10",
"circular-dependency-plugin": "^5.0.2",
"circular-json": "^0.5.9",
"clipboard-copy": "^3.1.0",
"colors": "^1.3.3",
"core-js": "3",
"crypto": "^1.0.1",
"cssnano-preset-advanced": "^4.0.7",
"delete-empty": "^3.0.0",
"email-validator": "^2.0.4",
"eslint": "^5.9.0",
"fastdom": "^1.0.9",
"flatted": "^2.0.1",
"fs-extra": "^8.1.0",
"gulp-audiosprite": "^1.1.0",
"howler": "^2.1.2",
"html-loader": "^0.5.5",
"ignore-loader": "^0.1.2",
"lz-string": "^1.4.4",
"markdown-loader": "^5.1.0",
"node-sri": "^1.1.1",
"phonegap-plugin-mobile-accessibility": "^1.0.5",
"promise-polyfill": "^8.1.0",
"query-string": "^6.8.1",
"rusha": "^0.8.13",
"serialize-error": "^3.0.0",
"strictdom": "^1.0.1",
"string-replace-webpack-plugin": "^0.1.3",
"terser-webpack-plugin": "^1.1.0",
"through2": "^3.0.1",
"uglify-template-string-loader": "^1.1.0",
"unused-files-webpack-plugin": "^3.4.0",
"webpack": "^4.43.0",
"webpack-cli": "^3.1.0",
"webpack-deep-scope-plugin": "^1.6.0",
"webpack-plugin-replace": "^1.1.1",
"webpack-strip-block": "^0.2.0",
"whatwg-fetch": "^3.0.0",
"worker-loader": "^2.0.0"
},
"devDependencies": {
"autoprefixer": "^9.4.3",
"babel-plugin-closure-elimination": "^1.3.0",
"babel-plugin-console-source": "^2.0.2",
"babel-plugin-danger-remove-unused-import": "^1.1.2",
"css-mqpacker": "^7.0.0",
"cssnano": "^4.1.10",
"electron-packager": "^14.0.6",
"faster.js": "^1.1.0",
"glob": "^7.1.3",
"gulp": "^4.0.2",
"gulp-cache": "^1.1.3",
"gulp-cached": "^1.1.1",
"gulp-clean": "^0.4.0",
"gulp-dom": "^1.0.0",
"gulp-flatten": "^0.4.0",
"gulp-fluent-ffmpeg": "^2.0.0",
"gulp-html-beautify": "^1.0.1",
"gulp-htmlmin": "^5.0.1",
"gulp-if": "^3.0.0",
"gulp-imagemin": "^7.1.0",
"gulp-load-plugins": "^2.0.3",
"gulp-phonegap-build": "^0.1.5",
"gulp-plumber": "^1.2.1",
"gulp-pngquant": "^1.0.13",
"gulp-postcss": "^8.0.0",
"gulp-rename": "^2.0.0",
"gulp-sass": "^4.1.0",
"gulp-sass-lint": "^1.4.0",
"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-gifsicle": "^7.0.0",
"imagemin-jpegtran": "^7.0.0",
"imagemin-pngquant": "^9.0.0",
"jimp": "^0.6.1",
"js-yaml": "^3.13.1",
"postcss-assets": "^5.0.0",
"postcss-preset-env": "^6.5.0",
"postcss-round-subpixels": "^1.2.0",
"postcss-unprefix": "^2.1.3",
"sass-unused": "^0.3.0",
"strip-json-comments": "^3.0.1",
"trim": "^0.0.1",
"webpack-stream": "^5.2.1",
"yaml-loader": "^0.6.0"
}
}
{
"name": "builder",
"version": "1.0.0",
"description": "builder",
"private": true,
"scripts": {
"gulp": "gulp"
},
"author": "tobspr",
"license": "private",
"dependencies": {
"@babel/core": "^7.9.0",
"@babel/plugin-transform-block-scoping": "^7.4.4",
"@babel/plugin-transform-classes": "^7.5.5",
"@babel/preset-env": "^7.5.4",
"@types/cordova": "^0.0.34",
"@types/filesystem": "^0.0.29",
"@types/node": "^12.7.5",
"ajv": "^6.10.2",
"audiosprite": "^0.7.2",
"babel-loader": "^8.1.0",
"browser-sync": "^2.26.10",
"circular-dependency-plugin": "^5.0.2",
"circular-json": "^0.5.9",
"clipboard-copy": "^3.1.0",
"colors": "^1.3.3",
"core-js": "3",
"crypto": "^1.0.1",
"cssnano-preset-advanced": "^4.0.7",
"delete-empty": "^3.0.0",
"email-validator": "^2.0.4",
"eslint": "^5.9.0",
"fastdom": "^1.0.9",
"flatted": "^2.0.1",
"fs-extra": "^8.1.0",
"gulp-audiosprite": "^1.1.0",
"howler": "^2.1.2",
"html-loader": "^0.5.5",
"ignore-loader": "^0.1.2",
"lz-string": "^1.4.4",
"markdown-loader": "^5.1.0",
"node-sri": "^1.1.1",
"phonegap-plugin-mobile-accessibility": "^1.0.5",
"promise-polyfill": "^8.1.0",
"query-string": "^6.8.1",
"rusha": "^0.8.13",
"serialize-error": "^3.0.0",
"strictdom": "^1.0.1",
"string-replace-webpack-plugin": "^0.1.3",
"terser-webpack-plugin": "^1.1.0",
"through2": "^3.0.1",
"uglify-template-string-loader": "^1.1.0",
"unused-files-webpack-plugin": "^3.4.0",
"webpack": "^4.43.0",
"webpack-cli": "^3.1.0",
"webpack-deep-scope-plugin": "^1.6.0",
"webpack-plugin-replace": "^1.1.1",
"webpack-strip-block": "^0.2.0",
"whatwg-fetch": "^3.0.0",
"worker-loader": "^2.0.0"
},
"devDependencies": {
"autoprefixer": "^9.4.3",
"babel-plugin-closure-elimination": "^1.3.0",
"babel-plugin-console-source": "^2.0.2",
"babel-plugin-danger-remove-unused-import": "^1.1.2",
"css-mqpacker": "^7.0.0",
"cssnano": "^4.1.10",
"postcss-critical-split": "^2.5.3",
"electron-packager": "^14.0.6",
"faster.js": "^1.1.0",
"glob": "^7.1.3",
"gulp": "^4.0.2",
"gulp-cache": "^1.1.3",
"gulp-cached": "^1.1.1",
"gulp-clean": "^0.4.0",
"gulp-dom": "^1.0.0",
"gulp-flatten": "^0.4.0",
"gulp-fluent-ffmpeg": "^2.0.0",
"gulp-html-beautify": "^1.0.1",
"gulp-htmlmin": "^5.0.1",
"gulp-if": "^3.0.0",
"gulp-imagemin": "^7.1.0",
"gulp-load-plugins": "^2.0.3",
"gulp-phonegap-build": "^0.1.5",
"gulp-plumber": "^1.2.1",
"gulp-pngquant": "^1.0.13",
"gulp-postcss": "^8.0.0",
"gulp-rename": "^2.0.0",
"gulp-sass": "^4.1.0",
"gulp-sass-lint": "^1.4.0",
"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-gifsicle": "^7.0.0",
"imagemin-jpegtran": "^7.0.0",
"imagemin-pngquant": "^9.0.0",
"jimp": "^0.6.1",
"js-yaml": "^3.13.1",
"postcss-assets": "^5.0.0",
"postcss-preset-env": "^6.5.0",
"postcss-round-subpixels": "^1.2.0",
"postcss-unprefix": "^2.1.3",
"sass-unused": "^0.3.0",
"strip-json-comments": "^3.0.1",
"trim": "^0.0.1",
"webpack-stream": "^5.2.1",
"yaml-loader": "^0.6.0"
}
}

File diff suppressed because it is too large Load Diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.0 KiB

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 242 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 33 KiB

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 35 KiB

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 40 KiB

View File

@ -2,7 +2,7 @@
"sprites/belt/built/forward_0.png":
{
"frame": {"x":1867,"y":593,"w":116,"h":144},
"frame": {"x":1239,"y":1197,"w":116,"h":144},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":14,"y":0,"w":116,"h":144},
@ -10,7 +10,7 @@
},
"sprites/belt/built/forward_1.png":
{
"frame": {"x":1241,"y":1197,"w":116,"h":144},
"frame": {"x":1361,"y":1195,"w":116,"h":144},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":14,"y":0,"w":116,"h":144},
@ -18,7 +18,7 @@
},
"sprites/belt/built/forward_2.png":
{
"frame": {"x":1558,"y":753,"w":116,"h":144},
"frame": {"x":1436,"y":753,"w":116,"h":144},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":14,"y":0,"w":116,"h":144},
@ -26,7 +26,7 @@
},
"sprites/belt/built/forward_3.png":
{
"frame": {"x":1555,"y":903,"w":116,"h":144},
"frame": {"x":1433,"y":903,"w":116,"h":144},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":14,"y":0,"w":116,"h":144},
@ -34,7 +34,7 @@
},
"sprites/belt/built/forward_4.png":
{
"frame": {"x":1562,"y":1053,"w":116,"h":144},
"frame": {"x":1483,"y":1195,"w":116,"h":144},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":14,"y":0,"w":116,"h":144},
@ -42,7 +42,7 @@
},
"sprites/belt/built/forward_5.png":
{
"frame": {"x":1680,"y":753,"w":116,"h":144},
"frame": {"x":1501,"y":1345,"w":116,"h":144},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":14,"y":0,"w":116,"h":144},
@ -50,7 +50,7 @@
},
"sprites/belt/built/forward_6.png":
{
"frame": {"x":1677,"y":903,"w":116,"h":144},
"frame": {"x":1510,"y":1495,"w":116,"h":144},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":14,"y":0,"w":116,"h":144},
@ -58,7 +58,7 @@
},
"sprites/belt/built/forward_7.png":
{
"frame": {"x":1684,"y":1053,"w":116,"h":144},
"frame": {"x":1555,"y":903,"w":116,"h":144},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":14,"y":0,"w":116,"h":144},
@ -66,7 +66,7 @@
},
"sprites/belt/built/forward_8.png":
{
"frame": {"x":1802,"y":743,"w":116,"h":144},
"frame": {"x":1696,"y":1053,"w":116,"h":144},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":14,"y":0,"w":116,"h":144},
@ -74,7 +74,7 @@
},
"sprites/belt/built/forward_9.png":
{
"frame": {"x":1924,"y":743,"w":116,"h":144},
"frame": {"x":1623,"y":1339,"w":116,"h":144},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":14,"y":0,"w":116,"h":144},
@ -82,7 +82,7 @@
},
"sprites/belt/built/forward_10.png":
{
"frame": {"x":1363,"y":1195,"w":116,"h":144},
"frame": {"x":1379,"y":1345,"w":116,"h":144},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":14,"y":0,"w":116,"h":144},
@ -90,7 +90,7 @@
},
"sprites/belt/built/forward_11.png":
{
"frame": {"x":845,"y":1548,"w":116,"h":144},
"frame": {"x":706,"y":1711,"w":116,"h":144},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":14,"y":0,"w":116,"h":144},
@ -98,7 +98,7 @@
},
"sprites/belt/built/forward_12.png":
{
"frame": {"x":1436,"y":753,"w":116,"h":144},
"frame": {"x":1861,"y":593,"w":116,"h":144},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":14,"y":0,"w":116,"h":144},
@ -106,7 +106,7 @@
},
"sprites/belt/built/forward_13.png":
{
"frame": {"x":1433,"y":903,"w":116,"h":144},
"frame": {"x":1875,"y":743,"w":116,"h":144},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":14,"y":0,"w":116,"h":144},
@ -114,7 +114,7 @@
},
"sprites/belt/built/left_0.png":
{
"frame": {"x":569,"y":1845,"w":130,"h":130},
"frame": {"x":1238,"y":1464,"w":130,"h":130},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":0,"y":14,"w":130,"h":130},
@ -122,7 +122,7 @@
},
"sprites/belt/built/left_1.png":
{
"frame": {"x":1426,"y":1053,"w":130,"h":130},
"frame": {"x":1374,"y":1495,"w":130,"h":130},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":0,"y":14,"w":130,"h":130},
@ -130,7 +130,7 @@
},
"sprites/belt/built/left_2.png":
{
"frame": {"x":1893,"y":1189,"w":130,"h":130},
"frame": {"x":1741,"y":1203,"w":130,"h":130},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":0,"y":14,"w":130,"h":130},
@ -138,7 +138,7 @@
},
"sprites/belt/built/left_3.png":
{
"frame": {"x":1241,"y":1347,"w":130,"h":130},
"frame": {"x":1745,"y":1339,"w":130,"h":130},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":0,"y":14,"w":130,"h":130},
@ -146,7 +146,7 @@
},
"sprites/belt/built/left_4.png":
{
"frame": {"x":1377,"y":1345,"w":130,"h":130},
"frame": {"x":1754,"y":1475,"w":130,"h":130},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":0,"y":14,"w":130,"h":130},
@ -154,7 +154,7 @@
},
"sprites/belt/built/left_5.png":
{
"frame": {"x":1513,"y":1339,"w":130,"h":130},
"frame": {"x":1813,"y":917,"w":130,"h":130},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":0,"y":14,"w":130,"h":130},
@ -162,7 +162,7 @@
},
"sprites/belt/built/left_6.png":
{
"frame": {"x":1649,"y":1339,"w":130,"h":130},
"frame": {"x":1818,"y":1053,"w":130,"h":130},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":0,"y":14,"w":130,"h":130},
@ -170,7 +170,7 @@
},
"sprites/belt/built/left_7.png":
{
"frame": {"x":1785,"y":1339,"w":130,"h":130},
"frame": {"x":1877,"y":1189,"w":130,"h":130},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":0,"y":14,"w":130,"h":130},
@ -178,7 +178,7 @@
},
"sprites/belt/built/left_8.png":
{
"frame": {"x":1377,"y":1481,"w":130,"h":130},
"frame": {"x":1881,"y":1325,"w":130,"h":130},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":0,"y":14,"w":130,"h":130},
@ -186,7 +186,7 @@
},
"sprites/belt/built/left_9.png":
{
"frame": {"x":1802,"y":1475,"w":130,"h":130},
"frame": {"x":1890,"y":1461,"w":130,"h":130},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":0,"y":14,"w":130,"h":130},
@ -194,7 +194,7 @@
},
"sprites/belt/built/left_10.png":
{
"frame": {"x":1485,"y":1203,"w":130,"h":130},
"frame": {"x":939,"y":1712,"w":130,"h":130},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":0,"y":14,"w":130,"h":130},
@ -202,7 +202,7 @@
},
"sprites/belt/built/left_11.png":
{
"frame": {"x":1621,"y":1203,"w":130,"h":130},
"frame": {"x":1677,"y":917,"w":130,"h":130},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":0,"y":14,"w":130,"h":130},
@ -210,7 +210,7 @@
},
"sprites/belt/built/left_12.png":
{
"frame": {"x":1757,"y":1203,"w":130,"h":130},
"frame": {"x":1560,"y":1053,"w":130,"h":130},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":0,"y":14,"w":130,"h":130},
@ -218,7 +218,7 @@
},
"sprites/belt/built/left_13.png":
{
"frame": {"x":1806,"y":1053,"w":130,"h":130},
"frame": {"x":1605,"y":1203,"w":130,"h":130},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":0,"y":14,"w":130,"h":130},
@ -226,7 +226,7 @@
},
"sprites/belt/built/right_0.png":
{
"frame": {"x":1799,"y":1611,"w":130,"h":130},
"frame": {"x":1754,"y":1611,"w":130,"h":130},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":14,"y":14,"w":130,"h":130},
@ -234,7 +234,7 @@
},
"sprites/belt/built/right_1.png":
{
"frame": {"x":294,"y":1885,"w":130,"h":130},
"frame": {"x":1890,"y":1597,"w":130,"h":130},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":14,"y":14,"w":130,"h":130},
@ -242,7 +242,7 @@
},
"sprites/belt/built/right_2.png":
{
"frame": {"x":1239,"y":1483,"w":130,"h":130},
"frame": {"x":842,"y":1848,"w":130,"h":130},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":14,"y":14,"w":130,"h":130},
@ -250,7 +250,7 @@
},
"sprites/belt/built/right_3.png":
{
"frame": {"x":997,"y":1785,"w":130,"h":130},
"frame": {"x":978,"y":1848,"w":130,"h":130},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":14,"y":14,"w":130,"h":130},
@ -258,7 +258,7 @@
},
"sprites/belt/built/right_4.png":
{
"frame": {"x":1375,"y":1617,"w":130,"h":130},
"frame": {"x":1114,"y":1848,"w":130,"h":130},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":14,"y":14,"w":130,"h":130},
@ -266,7 +266,7 @@
},
"sprites/belt/built/right_5.png":
{
"frame": {"x":1511,"y":1710,"w":130,"h":130},
"frame": {"x":271,"y":1885,"w":130,"h":130},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":14,"y":14,"w":130,"h":130},
@ -274,7 +274,7 @@
},
"sprites/belt/built/right_6.png":
{
"frame": {"x":1647,"y":1710,"w":130,"h":130},
"frame": {"x":407,"y":1885,"w":130,"h":130},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":14,"y":14,"w":130,"h":130},
@ -282,7 +282,7 @@
},
"sprites/belt/built/right_7.png":
{
"frame": {"x":1783,"y":1747,"w":130,"h":130},
"frame": {"x":1211,"y":1600,"w":130,"h":130},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":14,"y":14,"w":130,"h":130},
@ -290,7 +290,7 @@
},
"sprites/belt/built/right_8.png":
{
"frame": {"x":1111,"y":1635,"w":130,"h":130},
"frame": {"x":1347,"y":1631,"w":130,"h":130},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":14,"y":14,"w":130,"h":130},
@ -298,7 +298,7 @@
},
"sprites/belt/built/right_9.png":
{
"frame": {"x":1133,"y":1771,"w":130,"h":130},
"frame": {"x":1483,"y":1645,"w":130,"h":130},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":14,"y":14,"w":130,"h":130},
@ -306,7 +306,7 @@
},
"sprites/belt/built/right_10.png":
{
"frame": {"x":430,"y":1885,"w":130,"h":130},
"frame": {"x":1075,"y":1712,"w":130,"h":130},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":14,"y":14,"w":130,"h":130},
@ -314,7 +314,7 @@
},
"sprites/belt/built/right_11.png":
{
"frame": {"x":967,"y":1513,"w":130,"h":130},
"frame": {"x":1890,"y":1733,"w":130,"h":130},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":14,"y":14,"w":130,"h":130},
@ -322,7 +322,7 @@
},
"sprites/belt/built/right_12.png":
{
"frame": {"x":975,"y":1649,"w":130,"h":130},
"frame": {"x":570,"y":1878,"w":130,"h":130},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":14,"y":14,"w":130,"h":130},
@ -330,7 +330,7 @@
},
"sprites/belt/built/right_13.png":
{
"frame": {"x":1103,"y":1444,"w":130,"h":130},
"frame": {"x":706,"y":1861,"w":130,"h":130},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":14,"y":14,"w":130,"h":130},
@ -378,7 +378,7 @@
},
"sprites/blueprints/belt_left.png":
{
"frame": {"x":1168,"y":1907,"w":130,"h":130},
"frame": {"x":1250,"y":1838,"w":130,"h":130},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":0,"y":14,"w":130,"h":130},
@ -386,7 +386,7 @@
},
"sprites/blueprints/belt_right.png":
{
"frame": {"x":1269,"y":1753,"w":130,"h":130},
"frame": {"x":1726,"y":1747,"w":130,"h":130},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":14,"y":14,"w":130,"h":130},
@ -394,7 +394,7 @@
},
"sprites/blueprints/belt_top.png":
{
"frame": {"x":1799,"y":903,"w":116,"h":144},
"frame": {"x":1632,"y":1489,"w":116,"h":144},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":14,"y":0,"w":116,"h":144},
@ -402,7 +402,7 @@
},
"sprites/blueprints/constant_signal.png":
{
"frame": {"x":1921,"y":1325,"w":105,"h":127},
"frame": {"x":828,"y":1709,"w":105,"h":127},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":20,"y":0,"w":105,"h":127},
@ -426,7 +426,7 @@
},
"sprites/blueprints/display.png":
{
"frame": {"x":841,"y":1698,"w":128,"h":136},
"frame": {"x":1426,"y":1053,"w":128,"h":136},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":8,"y":8,"w":128,"h":136},
@ -442,10 +442,10 @@
},
"sprites/blueprints/lever.png":
{
"frame": {"x":1921,"y":893,"w":111,"h":129},
"frame": {"x":1719,"y":453,"w":100,"h":116},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":17,"y":4,"w":111,"h":129},
"spriteSourceSize": {"x":22,"y":9,"w":100,"h":116},
"sourceSize": {"w":144,"h":144}
},
"sprites/blueprints/logic_gate-not.png":
@ -482,7 +482,7 @@
},
"sprites/blueprints/logic_gate.png":
{
"frame": {"x":1821,"y":454,"w":144,"h":133},
"frame": {"x":1825,"y":454,"w":144,"h":133},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":0,"y":0,"w":144,"h":133},
@ -498,7 +498,7 @@
},
"sprites/blueprints/miner.png":
{
"frame": {"x":1725,"y":593,"w":136,"h":143},
"frame": {"x":951,"y":1328,"w":136,"h":143},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":5,"y":0,"w":136,"h":143},
@ -562,10 +562,10 @@
},
"sprites/blueprints/rotater-rotate180.png":
{
"frame": {"x":271,"y":1735,"w":142,"h":144},
"frame": {"x":271,"y":1735,"w":143,"h":144},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":0,"y":0,"w":142,"h":144},
"spriteSourceSize": {"x":1,"y":0,"w":143,"h":144},
"sourceSize": {"w":144,"h":144}
},
"sprites/blueprints/rotater.png":
@ -584,7 +584,7 @@
"spriteSourceSize": {"x":13,"y":0,"w":261,"h":144},
"sourceSize": {"w":288,"h":144}
},
"sprites/blueprints/trash-storage.png":
"sprites/blueprints/storage.png":
{
"frame": {"x":4,"y":1001,"w":250,"h":288},
"rotated": false,
@ -602,7 +602,7 @@
},
"sprites/blueprints/underground_belt_entry-tier2.png":
{
"frame": {"x":954,"y":1188,"w":138,"h":125},
"frame": {"x":806,"y":1461,"w":138,"h":125},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":4,"y":19,"w":138,"h":125},
@ -610,7 +610,7 @@
},
"sprites/blueprints/underground_belt_entry.png":
{
"frame": {"x":954,"y":1319,"w":138,"h":112},
"frame": {"x":950,"y":1477,"w":138,"h":112},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":4,"y":32,"w":138,"h":112},
@ -618,7 +618,7 @@
},
"sprites/blueprints/underground_belt_exit-tier2.png":
{
"frame": {"x":1513,"y":1475,"w":139,"h":112},
"frame": {"x":661,"y":1460,"w":139,"h":112},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":4,"y":0,"w":139,"h":112},
@ -626,7 +626,7 @@
},
"sprites/blueprints/underground_belt_exit.png":
{
"frame": {"x":1658,"y":1475,"w":138,"h":112},
"frame": {"x":1094,"y":1475,"w":138,"h":112},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":4,"y":0,"w":138,"h":112},
@ -666,7 +666,7 @@
},
"sprites/blueprints/virtual_processor-stacker.png":
{
"frame": {"x":569,"y":1695,"w":130,"h":144},
"frame": {"x":560,"y":1578,"w":130,"h":144},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":14,"y":0,"w":130,"h":144},
@ -706,7 +706,7 @@
},
"sprites/blueprints/wire-turn.png":
{
"frame": {"x":557,"y":1456,"w":82,"h":82},
"frame": {"x":1386,"y":1767,"w":82,"h":82},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":62,"y":62,"w":82,"h":82},
@ -714,7 +714,7 @@
},
"sprites/blueprints/wire.png":
{
"frame": {"x":1980,"y":1028,"w":20,"h":144},
"frame": {"x":1954,"y":1033,"w":20,"h":144},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":62,"y":0,"w":20,"h":144},
@ -778,7 +778,7 @@
},
"sprites/buildings/belt_left.png":
{
"frame": {"x":569,"y":1845,"w":130,"h":130},
"frame": {"x":1238,"y":1464,"w":130,"h":130},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":0,"y":14,"w":130,"h":130},
@ -786,7 +786,7 @@
},
"sprites/buildings/belt_right.png":
{
"frame": {"x":1799,"y":1611,"w":130,"h":130},
"frame": {"x":1754,"y":1611,"w":130,"h":130},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":14,"y":14,"w":130,"h":130},
@ -794,7 +794,7 @@
},
"sprites/buildings/belt_top.png":
{
"frame": {"x":1867,"y":593,"w":116,"h":144},
"frame": {"x":1239,"y":1197,"w":116,"h":144},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":14,"y":0,"w":116,"h":144},
@ -802,7 +802,7 @@
},
"sprites/buildings/constant_signal.png":
{
"frame": {"x":1938,"y":1458,"w":104,"h":127},
"frame": {"x":696,"y":1578,"w":104,"h":127},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":20,"y":0,"w":104,"h":127},
@ -826,7 +826,7 @@
},
"sprites/buildings/display.png":
{
"frame": {"x":841,"y":1840,"w":126,"h":135},
"frame": {"x":1558,"y":753,"w":126,"h":135},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":9,"y":9,"w":126,"h":135},
@ -850,10 +850,10 @@
},
"sprites/buildings/lever.png":
{
"frame": {"x":1935,"y":1611,"w":109,"h":127},
"frame": {"x":557,"y":1456,"w":98,"h":114},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":18,"y":5,"w":109,"h":127},
"spriteSourceSize": {"x":23,"y":10,"w":98,"h":114},
"sourceSize": {"w":144,"h":144}
},
"sprites/buildings/logic_gate-not.png":
@ -906,7 +906,7 @@
},
"sprites/buildings/miner.png":
{
"frame": {"x":560,"y":1547,"w":136,"h":142},
"frame": {"x":1097,"y":1197,"w":136,"h":142},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":5,"y":0,"w":136,"h":142},
@ -973,7 +973,7 @@
"frame": {"x":1286,"y":902,"w":141,"h":143},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":1,"y":0,"w":141,"h":143},
"spriteSourceSize": {"x":2,"y":0,"w":141,"h":143},
"sourceSize": {"w":144,"h":144}
},
"sprites/buildings/rotater.png":
@ -992,7 +992,7 @@
"spriteSourceSize": {"x":14,"y":0,"w":260,"h":143},
"sourceSize": {"w":288,"h":144}
},
"sprites/buildings/trash-storage.png":
"sprites/buildings/storage.png":
{
"frame": {"x":4,"y":1295,"w":248,"h":288},
"rotated": false,
@ -1010,7 +1010,7 @@
},
"sprites/buildings/underground_belt_entry-tier2.png":
{
"frame": {"x":1098,"y":1197,"w":137,"h":124},
"frame": {"x":1093,"y":1345,"w":137,"h":124},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":5,"y":20,"w":137,"h":124},
@ -1018,7 +1018,7 @@
},
"sprites/buildings/underground_belt_entry.png":
{
"frame": {"x":1098,"y":1327,"w":137,"h":111},
"frame": {"x":1236,"y":1347,"w":137,"h":111},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":5,"y":33,"w":137,"h":111},
@ -1026,7 +1026,7 @@
},
"sprites/buildings/underground_belt_exit-tier2.png":
{
"frame": {"x":1513,"y":1593,"w":137,"h":111},
"frame": {"x":806,"y":1592,"w":137,"h":111},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":5,"y":0,"w":137,"h":111},
@ -1034,7 +1034,7 @@
},
"sprites/buildings/underground_belt_exit.png":
{
"frame": {"x":1656,"y":1593,"w":137,"h":111},
"frame": {"x":949,"y":1595,"w":137,"h":111},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":5,"y":0,"w":137,"h":111},
@ -1042,7 +1042,7 @@
},
"sprites/buildings/virtual_processor-analyzer.png":
{
"frame": {"x":419,"y":1735,"w":144,"h":144},
"frame": {"x":420,"y":1735,"w":144,"h":144},
"rotated": false,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":144,"h":144},
@ -1050,7 +1050,7 @@
},
"sprites/buildings/virtual_processor-painter.png":
{
"frame": {"x":705,"y":1688,"w":130,"h":144},
"frame": {"x":570,"y":1728,"w":130,"h":144},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":14,"y":0,"w":130,"h":144},
@ -1074,7 +1074,7 @@
},
"sprites/buildings/virtual_processor-stacker.png":
{
"frame": {"x":705,"y":1838,"w":130,"h":144},
"frame": {"x":1725,"y":593,"w":130,"h":144},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":14,"y":0,"w":130,"h":144},
@ -1114,7 +1114,7 @@
},
"sprites/buildings/wire-turn.png":
{
"frame": {"x":997,"y":1921,"w":81,"h":81},
"frame": {"x":1386,"y":1855,"w":81,"h":81},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":63,"y":63,"w":81,"h":81},
@ -1122,7 +1122,7 @@
},
"sprites/buildings/wire.png":
{
"frame": {"x":2006,"y":1028,"w":18,"h":144},
"frame": {"x":2026,"y":116,"w":18,"h":144},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":63,"y":0,"w":18,"h":144},
@ -1130,7 +1130,7 @@
},
"sprites/buildings/wire_tunnel-coating.png":
{
"frame": {"x":1942,"y":1028,"w":32,"h":134},
"frame": {"x":1949,"y":893,"w":32,"h":134},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":56,"y":5,"w":32,"h":134},
@ -1138,7 +1138,7 @@
},
"sprites/buildings/wire_tunnel.png":
{
"frame": {"x":702,"y":1548,"w":137,"h":134},
"frame": {"x":954,"y":1188,"w":137,"h":134},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":5,"y":5,"w":137,"h":134},
@ -1146,7 +1146,7 @@
},
"sprites/colors/blue.png":
{
"frame": {"x":1103,"y":1580,"w":54,"h":49},
"frame": {"x":960,"y":1984,"w":54,"h":49},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":0,"y":4,"w":54,"h":49},
@ -1154,7 +1154,7 @@
},
"sprites/colors/cyan.png":
{
"frame": {"x":1163,"y":1580,"w":54,"h":49},
"frame": {"x":1020,"y":1984,"w":54,"h":49},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":0,"y":4,"w":54,"h":49},
@ -1162,7 +1162,7 @@
},
"sprites/colors/green.png":
{
"frame": {"x":705,"y":1988,"w":54,"h":49},
"frame": {"x":1080,"y":1984,"w":54,"h":49},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":0,"y":4,"w":54,"h":49},
@ -1170,7 +1170,7 @@
},
"sprites/colors/purple.png":
{
"frame": {"x":765,"y":1988,"w":54,"h":49},
"frame": {"x":1140,"y":1984,"w":54,"h":49},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":0,"y":4,"w":54,"h":49},
@ -1178,7 +1178,7 @@
},
"sprites/colors/red.png":
{
"frame": {"x":1492,"y":1846,"w":54,"h":49},
"frame": {"x":1987,"y":928,"w":54,"h":49},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":0,"y":4,"w":54,"h":49},
@ -1186,7 +1186,7 @@
},
"sprites/colors/uncolored.png":
{
"frame": {"x":1552,"y":1846,"w":54,"h":49},
"frame": {"x":1987,"y":983,"w":54,"h":49},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":0,"y":4,"w":54,"h":49},
@ -1194,7 +1194,7 @@
},
"sprites/colors/white.png":
{
"frame": {"x":1612,"y":1846,"w":54,"h":49},
"frame": {"x":1980,"y":1038,"w":54,"h":49},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":0,"y":4,"w":54,"h":49},
@ -1202,7 +1202,7 @@
},
"sprites/colors/yellow.png":
{
"frame": {"x":1672,"y":1846,"w":54,"h":49},
"frame": {"x":1980,"y":1093,"w":54,"h":49},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":0,"y":4,"w":54,"h":49},
@ -1210,7 +1210,7 @@
},
"sprites/debug/acceptor_slot.png":
{
"frame": {"x":1269,"y":1889,"w":12,"h":12},
"frame": {"x":1719,"y":575,"w":12,"h":12},
"rotated": false,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":12,"h":12},
@ -1218,7 +1218,7 @@
},
"sprites/debug/ejector_slot.png":
{
"frame": {"x":1719,"y":555,"w":12,"h":12},
"frame": {"x":1737,"y":575,"w":12,"h":12},
"rotated": false,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":12,"h":12},
@ -1226,7 +1226,7 @@
},
"sprites/misc/hub_direction_indicator.png":
{
"frame": {"x":1247,"y":1619,"w":48,"h":48},
"frame": {"x":1386,"y":1942,"w":48,"h":48},
"rotated": false,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":48,"h":48},
@ -1234,7 +1234,7 @@
},
"sprites/misc/processor_disabled.png":
{
"frame": {"x":1084,"y":1921,"w":78,"h":81},
"frame": {"x":1561,"y":1781,"w":78,"h":81},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":10,"y":10,"w":78,"h":81},
@ -1242,7 +1242,7 @@
},
"sprites/misc/processor_disconnected.png":
{
"frame": {"x":1304,"y":1619,"w":65,"h":84},
"frame": {"x":1645,"y":1765,"w":65,"h":84},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":17,"y":8,"w":65,"h":84},
@ -1250,7 +1250,7 @@
},
"sprites/misc/reader_overlay.png":
{
"frame": {"x":951,"y":1437,"w":104,"h":70},
"frame": {"x":1250,"y":1974,"w":104,"h":70},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":20,"y":38,"w":104,"h":70},
@ -1258,7 +1258,7 @@
},
"sprites/misc/slot_bad_arrow.png":
{
"frame": {"x":1999,"y":161,"w":35,"h":35},
"frame": {"x":1980,"y":1148,"w":35,"h":35},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":2,"y":2,"w":35,"h":35},
@ -1266,7 +1266,7 @@
},
"sprites/misc/slot_good_arrow.png":
{
"frame": {"x":1999,"y":116,"w":35,"h":39},
"frame": {"x":1766,"y":1883,"w":35,"h":39},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":2,"y":0,"w":35,"h":39},
@ -1274,7 +1274,7 @@
},
"sprites/misc/storage_overlay.png":
{
"frame": {"x":566,"y":1981,"w":89,"h":44},
"frame": {"x":865,"y":1984,"w":89,"h":44},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":1,"y":1,"w":89,"h":44},
@ -1282,7 +1282,7 @@
},
"sprites/misc/waypoint.png":
{
"frame": {"x":661,"y":1981,"w":38,"h":48},
"frame": {"x":1414,"y":1996,"w":38,"h":48},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":5,"y":0,"w":38,"h":48},
@ -1290,7 +1290,7 @@
},
"sprites/wires/boolean_false.png":
{
"frame": {"x":1061,"y":1437,"w":31,"h":41},
"frame": {"x":2013,"y":1189,"w":31,"h":41},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":9,"y":5,"w":31,"h":41},
@ -1298,7 +1298,7 @@
},
"sprites/wires/boolean_true.png":
{
"frame": {"x":1999,"y":202,"w":22,"h":41},
"frame": {"x":1862,"y":1747,"w":22,"h":41},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":11,"y":5,"w":22,"h":41},
@ -1306,7 +1306,7 @@
},
"sprites/wires/display/blue.png":
{
"frame": {"x":1391,"y":1927,"w":47,"h":47},
"frame": {"x":706,"y":1997,"w":47,"h":47},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":1,"y":1,"w":47,"h":47},
@ -1314,7 +1314,7 @@
},
"sprites/wires/display/cyan.png":
{
"frame": {"x":1444,"y":1927,"w":47,"h":47},
"frame": {"x":759,"y":1997,"w":47,"h":47},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":1,"y":1,"w":47,"h":47},
@ -1322,7 +1322,7 @@
},
"sprites/wires/display/green.png":
{
"frame": {"x":1370,"y":1980,"w":47,"h":47},
"frame": {"x":812,"y":1997,"w":47,"h":47},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":1,"y":1,"w":47,"h":47},
@ -1330,7 +1330,7 @@
},
"sprites/wires/display/purple.png":
{
"frame": {"x":1423,"y":1980,"w":47,"h":47},
"frame": {"x":1997,"y":716,"w":47,"h":47},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":1,"y":1,"w":47,"h":47},
@ -1338,7 +1338,7 @@
},
"sprites/wires/display/red.png":
{
"frame": {"x":1497,"y":1901,"w":47,"h":47},
"frame": {"x":1997,"y":769,"w":47,"h":47},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":1,"y":1,"w":47,"h":47},
@ -1346,7 +1346,7 @@
},
"sprites/wires/display/white.png":
{
"frame": {"x":1550,"y":1901,"w":47,"h":47},
"frame": {"x":1997,"y":822,"w":47,"h":47},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":1,"y":1,"w":47,"h":47},
@ -1354,7 +1354,7 @@
},
"sprites/wires/display/yellow.png":
{
"frame": {"x":1603,"y":1901,"w":47,"h":47},
"frame": {"x":1997,"y":875,"w":47,"h":47},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":1,"y":1,"w":47,"h":47},
@ -1362,10 +1362,10 @@
},
"sprites/wires/lever_on.png":
{
"frame": {"x":1935,"y":1744,"w":109,"h":127},
"frame": {"x":1619,"y":1645,"w":101,"h":114},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":18,"y":5,"w":109,"h":127},
"spriteSourceSize": {"x":21,"y":10,"w":101,"h":114},
"sourceSize": {"w":144,"h":144}
},
"sprites/wires/logical_acceptor.png":
@ -1378,7 +1378,7 @@
},
"sprites/wires/logical_ejector.png":
{
"frame": {"x":1304,"y":1976,"w":60,"h":67},
"frame": {"x":1647,"y":1855,"w":60,"h":67},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":44,"y":0,"w":60,"h":67},
@ -1386,7 +1386,7 @@
},
"sprites/wires/network_conflict.png":
{
"frame": {"x":1656,"y":1901,"w":47,"h":44},
"frame": {"x":1713,"y":1883,"w":47,"h":44},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":1,"y":2,"w":47,"h":44},
@ -1394,7 +1394,7 @@
},
"sprites/wires/network_empty.png":
{
"frame": {"x":1732,"y":1846,"w":41,"h":48},
"frame": {"x":1200,"y":1984,"w":41,"h":48},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":5,"y":0,"w":41,"h":48},
@ -1402,7 +1402,7 @@
},
"sprites/wires/overlay_tile.png":
{
"frame": {"x":1719,"y":453,"w":96,"h":96},
"frame": {"x":1211,"y":1736,"w":96,"h":96},
"rotated": false,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":96,"h":96},
@ -1418,7 +1418,7 @@
},
"sprites/wires/sets/color_forward.png":
{
"frame": {"x":270,"y":1889,"w":18,"h":144},
"frame": {"x":2026,"y":266,"w":18,"h":144},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":63,"y":0,"w":18,"h":144},
@ -1434,7 +1434,7 @@
},
"sprites/wires/sets/color_turn.png":
{
"frame": {"x":1405,"y":1753,"w":81,"h":81},
"frame": {"x":1474,"y":1781,"w":81,"h":81},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":63,"y":63,"w":81,"h":81},
@ -1450,7 +1450,7 @@
},
"sprites/wires/sets/conflict_forward.png":
{
"frame": {"x":973,"y":1840,"w":18,"h":144},
"frame": {"x":2026,"y":416,"w":18,"h":144},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":63,"y":0,"w":18,"h":144},
@ -1458,7 +1458,7 @@
},
"sprites/wires/sets/conflict_split.png":
{
"frame": {"x":645,"y":1460,"w":144,"h":81},
"frame": {"x":1725,"y":743,"w":144,"h":81},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":0,"y":63,"w":144,"h":81},
@ -1466,7 +1466,7 @@
},
"sprites/wires/sets/conflict_turn.png":
{
"frame": {"x":1304,"y":1889,"w":81,"h":81},
"frame": {"x":1473,"y":1868,"w":81,"h":81},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":63,"y":63,"w":81,"h":81},
@ -1482,7 +1482,7 @@
},
"sprites/wires/sets/regular_forward.png":
{
"frame": {"x":2006,"y":1028,"w":18,"h":144},
"frame": {"x":2026,"y":116,"w":18,"h":144},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":63,"y":0,"w":18,"h":144},
@ -1498,7 +1498,7 @@
},
"sprites/wires/sets/regular_turn.png":
{
"frame": {"x":997,"y":1921,"w":81,"h":81},
"frame": {"x":1386,"y":1855,"w":81,"h":81},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":63,"y":63,"w":81,"h":81},
@ -1514,7 +1514,7 @@
},
"sprites/wires/sets/shape_forward.png":
{
"frame": {"x":1975,"y":116,"w":18,"h":144},
"frame": {"x":2026,"y":566,"w":18,"h":144},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":63,"y":0,"w":18,"h":144},
@ -1522,7 +1522,7 @@
},
"sprites/wires/sets/shape_split.png":
{
"frame": {"x":795,"y":1461,"w":144,"h":81},
"frame": {"x":1690,"y":830,"w":144,"h":81},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":0,"y":63,"w":144,"h":81},
@ -1530,7 +1530,7 @@
},
"sprites/wires/sets/shape_turn.png":
{
"frame": {"x":1405,"y":1840,"w":81,"h":81},
"frame": {"x":1560,"y":1868,"w":81,"h":81},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":63,"y":63,"w":81,"h":81},
@ -1538,7 +1538,7 @@
},
"sprites/wires/wires_preview.png":
{
"frame": {"x":1247,"y":1673,"w":48,"h":48},
"frame": {"x":1360,"y":1996,"w":48,"h":48},
"rotated": false,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":48,"h":48},
@ -1551,6 +1551,6 @@
"format": "RGBA8888",
"size": {"w":2048,"h":2048},
"scale": "0.75",
"smartupdate": "$TexturePacker:SmartUpdate:c57f50d18c59efc0edbd4a3a732323a4:3fcf23da2ddc6370c437cf41f6d44ed0:908b89f5ca8ff73e331a35a3b14d0604$"
"smartupdate": "$TexturePacker:SmartUpdate:5429cdf3b92834776437a91974e89d3c:fa61fb225cd312db144ce6a38d97871b:908b89f5ca8ff73e331a35a3b14d0604$"
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 MiB

After

Width:  |  Height:  |  Size: 1.3 MiB

View File

@ -2,7 +2,7 @@
"sprites/belt/built/forward_0.png":
{
"frame": {"x":157,"y":505,"w":40,"h":48},
"frame": {"x":902,"y":294,"w":40,"h":48},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":4,"y":0,"w":40,"h":48},
@ -10,7 +10,7 @@
},
"sprites/belt/built/forward_1.png":
{
"frame": {"x":154,"y":559,"w":40,"h":48},
"frame": {"x":200,"y":476,"w":40,"h":48},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":4,"y":0,"w":40,"h":48},
@ -18,7 +18,7 @@
},
"sprites/belt/built/forward_2.png":
{
"frame": {"x":200,"y":582,"w":40,"h":48},
"frame": {"x":146,"y":514,"w":40,"h":48},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":4,"y":0,"w":40,"h":48},
@ -26,7 +26,7 @@
},
"sprites/belt/built/forward_3.png":
{
"frame": {"x":150,"y":613,"w":40,"h":48},
"frame": {"x":50,"y":552,"w":40,"h":48},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":4,"y":0,"w":40,"h":48},
@ -34,7 +34,7 @@
},
"sprites/belt/built/forward_4.png":
{
"frame": {"x":100,"y":660,"w":40,"h":48},
"frame": {"x":4,"y":553,"w":40,"h":48},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":4,"y":0,"w":40,"h":48},
@ -42,7 +42,7 @@
},
"sprites/belt/built/forward_5.png":
{
"frame": {"x":50,"y":678,"w":40,"h":48},
"frame": {"x":96,"y":552,"w":40,"h":48},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":4,"y":0,"w":40,"h":48},
@ -50,7 +50,7 @@
},
"sprites/belt/built/forward_6.png":
{
"frame": {"x":4,"y":717,"w":40,"h":48},
"frame": {"x":559,"y":432,"w":40,"h":48},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":4,"y":0,"w":40,"h":48},
@ -58,7 +58,7 @@
},
"sprites/belt/built/forward_7.png":
{
"frame": {"x":776,"y":352,"w":40,"h":48},
"frame": {"x":605,"y":432,"w":40,"h":48},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":4,"y":0,"w":40,"h":48},
@ -66,7 +66,7 @@
},
"sprites/belt/built/forward_8.png":
{
"frame": {"x":715,"y":402,"w":40,"h":48},
"frame": {"x":651,"y":480,"w":40,"h":48},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":4,"y":0,"w":40,"h":48},
@ -74,7 +74,7 @@
},
"sprites/belt/built/forward_9.png":
{
"frame": {"x":665,"y":428,"w":40,"h":48},
"frame": {"x":697,"y":499,"w":40,"h":48},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":4,"y":0,"w":40,"h":48},
@ -82,7 +82,7 @@
},
"sprites/belt/built/forward_10.png":
{
"frame": {"x":104,"y":606,"w":40,"h":48},
"frame": {"x":246,"y":476,"w":40,"h":48},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":4,"y":0,"w":40,"h":48},
@ -90,7 +90,7 @@
},
"sprites/belt/built/forward_11.png":
{
"frame": {"x":54,"y":624,"w":40,"h":48},
"frame": {"x":54,"y":498,"w":40,"h":48},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":4,"y":0,"w":40,"h":48},
@ -98,7 +98,7 @@
},
"sprites/belt/built/forward_12.png":
{
"frame": {"x":4,"y":663,"w":40,"h":48},
"frame": {"x":4,"y":499,"w":40,"h":48},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":4,"y":0,"w":40,"h":48},
@ -106,7 +106,7 @@
},
"sprites/belt/built/forward_13.png":
{
"frame": {"x":253,"y":532,"w":40,"h":48},
"frame": {"x":100,"y":498,"w":40,"h":48},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":4,"y":0,"w":40,"h":48},
@ -114,7 +114,7 @@
},
"sprites/belt/built/left_0.png":
{
"frame": {"x":487,"y":302,"w":44,"h":44},
"frame": {"x":668,"y":380,"w":44,"h":44},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":0,"y":4,"w":44,"h":44},
@ -122,7 +122,7 @@
},
"sprites/belt/built/left_1.png":
{
"frame": {"x":487,"y":352,"w":44,"h":44},
"frame": {"x":718,"y":399,"w":44,"h":44},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":0,"y":4,"w":44,"h":44},
@ -130,7 +130,7 @@
},
"sprites/belt/built/left_2.png":
{
"frame": {"x":565,"y":362,"w":44,"h":44},
"frame": {"x":932,"y":480,"w":44,"h":44},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":0,"y":4,"w":44,"h":44},
@ -138,7 +138,7 @@
},
"sprites/belt/built/left_3.png":
{
"frame": {"x":615,"y":362,"w":44,"h":44},
"frame": {"x":718,"y":449,"w":44,"h":44},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":0,"y":4,"w":44,"h":44},
@ -146,7 +146,7 @@
},
"sprites/belt/built/left_4.png":
{
"frame": {"x":487,"y":402,"w":44,"h":44},
"frame": {"x":768,"y":449,"w":44,"h":44},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":0,"y":4,"w":44,"h":44},
@ -154,7 +154,7 @@
},
"sprites/belt/built/left_5.png":
{
"frame": {"x":431,"y":404,"w":44,"h":44},
"frame": {"x":832,"y":478,"w":44,"h":44},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":0,"y":4,"w":44,"h":44},
@ -162,7 +162,7 @@
},
"sprites/belt/built/left_6.png":
{
"frame": {"x":381,"y":406,"w":44,"h":44},
"frame": {"x":882,"y":500,"w":44,"h":44},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":0,"y":4,"w":44,"h":44},
@ -170,7 +170,7 @@
},
"sprites/belt/built/left_7.png":
{
"frame": {"x":313,"y":436,"w":44,"h":44},
"frame": {"x":932,"y":530,"w":44,"h":44},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":0,"y":4,"w":44,"h":44},
@ -178,7 +178,7 @@
},
"sprites/belt/built/left_8.png":
{
"frame": {"x":205,"y":482,"w":44,"h":44},
"frame": {"x":384,"y":302,"w":44,"h":44},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":0,"y":4,"w":44,"h":44},
@ -186,7 +186,7 @@
},
"sprites/belt/built/left_9.png":
{
"frame": {"x":104,"y":556,"w":44,"h":44},
"frame": {"x":207,"y":376,"w":44,"h":44},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":0,"y":4,"w":44,"h":44},
@ -194,7 +194,7 @@
},
"sprites/belt/built/left_10.png":
{
"frame": {"x":437,"y":354,"w":44,"h":44},
"frame": {"x":668,"y":430,"w":44,"h":44},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":0,"y":4,"w":44,"h":44},
@ -202,7 +202,7 @@
},
"sprites/belt/built/left_11.png":
{
"frame": {"x":381,"y":356,"w":44,"h":44},
"frame": {"x":768,"y":399,"w":44,"h":44},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":0,"y":4,"w":44,"h":44},
@ -210,7 +210,7 @@
},
"sprites/belt/built/left_12.png":
{
"frame": {"x":733,"y":302,"w":44,"h":44},
"frame": {"x":832,"y":428,"w":44,"h":44},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":0,"y":4,"w":44,"h":44},
@ -218,7 +218,7 @@
},
"sprites/belt/built/left_13.png":
{
"frame": {"x":676,"y":328,"w":44,"h":44},
"frame": {"x":882,"y":450,"w":44,"h":44},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":0,"y":4,"w":44,"h":44},
@ -226,7 +226,7 @@
},
"sprites/belt/built/right_0.png":
{
"frame": {"x":54,"y":574,"w":44,"h":44},
"frame": {"x":257,"y":376,"w":44,"h":44},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":4,"y":4,"w":44,"h":44},
@ -234,7 +234,7 @@
},
"sprites/belt/built/right_1.png":
{
"frame": {"x":4,"y":613,"w":44,"h":44},
"frame": {"x":434,"y":302,"w":44,"h":44},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":4,"y":4,"w":44,"h":44},
@ -242,7 +242,7 @@
},
"sprites/belt/built/right_2.png":
{
"frame": {"x":947,"y":328,"w":44,"h":44},
"frame": {"x":252,"y":426,"w":44,"h":44},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":4,"y":4,"w":44,"h":44},
@ -250,7 +250,7 @@
},
"sprites/belt/built/right_3.png":
{
"frame": {"x":726,"y":352,"w":44,"h":44},
"frame": {"x":427,"y":352,"w":44,"h":44},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":4,"y":4,"w":44,"h":44},
@ -258,7 +258,7 @@
},
"sprites/belt/built/right_4.png":
{
"frame": {"x":665,"y":378,"w":44,"h":44},
"frame": {"x":477,"y":352,"w":44,"h":44},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":4,"y":4,"w":44,"h":44},
@ -266,7 +266,7 @@
},
"sprites/belt/built/right_5.png":
{
"frame": {"x":565,"y":412,"w":44,"h":44},
"frame": {"x":561,"y":382,"w":44,"h":44},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":4,"y":4,"w":44,"h":44},
@ -274,7 +274,7 @@
},
"sprites/belt/built/right_6.png":
{
"frame": {"x":615,"y":412,"w":44,"h":44},
"frame": {"x":58,"y":448,"w":44,"h":44},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":4,"y":4,"w":44,"h":44},
@ -282,7 +282,7 @@
},
"sprites/belt/built/right_7.png":
{
"frame": {"x":481,"y":452,"w":44,"h":44},
"frame": {"x":4,"y":449,"w":44,"h":44},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":4,"y":4,"w":44,"h":44},
@ -290,7 +290,7 @@
},
"sprites/belt/built/right_8.png":
{
"frame": {"x":431,"y":454,"w":44,"h":44},
"frame": {"x":108,"y":448,"w":44,"h":44},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":4,"y":4,"w":44,"h":44},
@ -298,7 +298,7 @@
},
"sprites/belt/built/right_9.png":
{
"frame": {"x":377,"y":456,"w":44,"h":44},
"frame": {"x":376,"y":402,"w":44,"h":44},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":4,"y":4,"w":44,"h":44},
@ -306,7 +306,7 @@
},
"sprites/belt/built/right_10.png":
{
"frame": {"x":255,"y":482,"w":44,"h":44},
"frame": {"x":484,"y":302,"w":44,"h":44},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":4,"y":4,"w":44,"h":44},
@ -314,7 +314,7 @@
},
"sprites/belt/built/right_11.png":
{
"frame": {"x":783,"y":302,"w":44,"h":44},
"frame": {"x":377,"y":352,"w":44,"h":44},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":4,"y":4,"w":44,"h":44},
@ -322,7 +322,7 @@
},
"sprites/belt/built/right_12.png":
{
"frame": {"x":833,"y":302,"w":44,"h":44},
"frame": {"x":307,"y":382,"w":44,"h":44},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":4,"y":4,"w":44,"h":44},
@ -330,7 +330,7 @@
},
"sprites/belt/built/right_13.png":
{
"frame": {"x":897,"y":314,"w":44,"h":44},
"frame": {"x":202,"y":426,"w":44,"h":44},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":4,"y":4,"w":44,"h":44},
@ -346,7 +346,7 @@
},
"sprites/blueprints/balancer-merger.png":
{
"frame": {"x":208,"y":376,"w":47,"h":47},
"frame": {"x":678,"y":274,"w":47,"h":47},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":1,"y":0,"w":47,"h":47},
@ -362,7 +362,7 @@
},
"sprites/blueprints/balancer-splitter.png":
{
"frame": {"x":261,"y":376,"w":47,"h":47},
"frame": {"x":731,"y":302,"w":47,"h":47},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":1,"y":0,"w":47,"h":47},
@ -378,7 +378,7 @@
},
"sprites/blueprints/belt_left.png":
{
"frame": {"x":305,"y":486,"w":44,"h":44},
"frame": {"x":302,"y":432,"w":44,"h":44},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":0,"y":4,"w":44,"h":44},
@ -386,7 +386,7 @@
},
"sprites/blueprints/belt_right.png":
{
"frame": {"x":203,"y":532,"w":44,"h":44},
"frame": {"x":426,"y":402,"w":44,"h":44},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":4,"y":4,"w":44,"h":44},
@ -394,7 +394,7 @@
},
"sprites/blueprints/belt_top.png":
{
"frame": {"x":822,"y":352,"w":40,"h":48},
"frame": {"x":743,"y":499,"w":40,"h":48},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":4,"y":0,"w":40,"h":48},
@ -426,7 +426,7 @@
},
"sprites/blueprints/display.png":
{
"frame": {"x":4,"y":561,"w":44,"h":46},
"frame": {"x":618,"y":328,"w":44,"h":46},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":2,"y":2,"w":44,"h":46},
@ -442,10 +442,10 @@
},
"sprites/blueprints/lever.png":
{
"frame": {"x":906,"y":214,"w":38,"h":44},
"frame": {"x":982,"y":483,"w":35,"h":41},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":5,"y":1,"w":38,"h":44},
"spriteSourceSize": {"x":6,"y":2,"w":35,"h":41},
"sourceSize": {"w":48,"h":48}
},
"sprites/blueprints/logic_gate-not.png":
@ -466,7 +466,7 @@
},
"sprites/blueprints/logic_gate-transistor.png":
{
"frame": {"x":166,"y":397,"w":35,"h":48},
"frame": {"x":166,"y":317,"w":35,"h":48},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":0,"y":0,"w":35,"h":48},
@ -490,7 +490,7 @@
},
"sprites/blueprints/miner-chainable.png":
{
"frame": {"x":680,"y":274,"w":47,"h":48},
"frame": {"x":849,"y":268,"w":47,"h":48},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":1,"y":0,"w":47,"h":48},
@ -498,7 +498,7 @@
},
"sprites/blueprints/miner.png":
{
"frame": {"x":570,"y":308,"w":47,"h":48},
"frame": {"x":948,"y":328,"w":47,"h":48},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":1,"y":0,"w":47,"h":48},
@ -584,7 +584,7 @@
"spriteSourceSize": {"x":3,"y":0,"w":89,"h":48},
"sourceSize": {"w":96,"h":48}
},
"sprites/blueprints/trash-storage.png":
"sprites/blueprints/storage.png":
{
"frame": {"x":768,"y":112,"w":85,"h":96},
"rotated": false,
@ -642,7 +642,7 @@
},
"sprites/blueprints/virtual_processor-painter.png":
{
"frame": {"x":57,"y":466,"w":44,"h":48},
"frame": {"x":837,"y":374,"w":44,"h":48},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":4,"y":0,"w":44,"h":48},
@ -666,7 +666,7 @@
},
"sprites/blueprints/virtual_processor-stacker.png":
{
"frame": {"x":4,"y":507,"w":44,"h":48},
"frame": {"x":887,"y":396,"w":44,"h":48},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":4,"y":0,"w":44,"h":48},
@ -698,7 +698,7 @@
},
"sprites/blueprints/wire-split.png":
{
"frame": {"x":741,"y":268,"w":48,"h":28},
"frame": {"x":58,"y":414,"w":48,"h":28},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":0,"y":20,"w":48,"h":28},
@ -706,7 +706,7 @@
},
"sprites/blueprints/wire-turn.png":
{
"frame": {"x":912,"y":364,"w":28,"h":28},
"frame": {"x":166,"y":446,"w":28,"h":28},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":20,"y":20,"w":28,"h":28},
@ -722,7 +722,7 @@
},
"sprites/blueprints/wire_tunnel-coating.png":
{
"frame": {"x":363,"y":345,"w":12,"h":46},
"frame": {"x":550,"y":294,"w":12,"h":46},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":18,"y":1,"w":12,"h":46},
@ -746,7 +746,7 @@
},
"sprites/buildings/balancer-merger.png":
{
"frame": {"x":207,"y":429,"w":47,"h":47},
"frame": {"x":678,"y":327,"w":47,"h":47},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":1,"y":0,"w":47,"h":47},
@ -762,7 +762,7 @@
},
"sprites/buildings/balancer-splitter.png":
{
"frame": {"x":260,"y":429,"w":47,"h":47},
"frame": {"x":784,"y":302,"w":47,"h":47},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":1,"y":0,"w":47,"h":47},
@ -778,7 +778,7 @@
},
"sprites/buildings/belt_left.png":
{
"frame": {"x":487,"y":302,"w":44,"h":44},
"frame": {"x":668,"y":380,"w":44,"h":44},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":0,"y":4,"w":44,"h":44},
@ -786,7 +786,7 @@
},
"sprites/buildings/belt_right.png":
{
"frame": {"x":54,"y":574,"w":44,"h":44},
"frame": {"x":257,"y":376,"w":44,"h":44},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":4,"y":4,"w":44,"h":44},
@ -794,7 +794,7 @@
},
"sprites/buildings/belt_top.png":
{
"frame": {"x":157,"y":505,"w":40,"h":48},
"frame": {"x":902,"y":294,"w":40,"h":48},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":4,"y":0,"w":40,"h":48},
@ -802,7 +802,7 @@
},
"sprites/buildings/constant_signal.png":
{
"frame": {"x":166,"y":317,"w":36,"h":43},
"frame": {"x":906,"y":214,"w":36,"h":43},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":6,"y":0,"w":36,"h":43},
@ -826,7 +826,7 @@
},
"sprites/buildings/display.png":
{
"frame": {"x":437,"y":302,"w":44,"h":46},
"frame": {"x":618,"y":380,"w":44,"h":46},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":2,"y":2,"w":44,"h":46},
@ -850,15 +850,15 @@
},
"sprites/buildings/lever.png":
{
"frame": {"x":906,"y":264,"w":38,"h":44},
"frame": {"x":982,"y":576,"w":34,"h":40},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":5,"y":1,"w":38,"h":44},
"spriteSourceSize": {"x":7,"y":2,"w":34,"h":40},
"sourceSize": {"w":48,"h":48}
},
"sprites/buildings/logic_gate-not.png":
{
"frame": {"x":314,"y":382,"w":43,"h":48},
"frame": {"x":476,"y":402,"w":43,"h":48},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":3,"y":0,"w":43,"h":48},
@ -874,7 +874,7 @@
},
"sprites/buildings/logic_gate-transistor.png":
{
"frame": {"x":164,"y":451,"w":35,"h":48},
"frame": {"x":166,"y":371,"w":35,"h":48},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":0,"y":0,"w":35,"h":48},
@ -890,7 +890,7 @@
},
"sprites/buildings/logic_gate.png":
{
"frame": {"x":208,"y":325,"w":48,"h":45},
"frame": {"x":207,"y":325,"w":48,"h":45},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":0,"y":0,"w":48,"h":45},
@ -898,7 +898,7 @@
},
"sprites/buildings/miner-chainable.png":
{
"frame": {"x":623,"y":308,"w":47,"h":48},
"frame": {"x":572,"y":274,"w":47,"h":48},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":1,"y":0,"w":47,"h":48},
@ -906,7 +906,7 @@
},
"sprites/buildings/miner.png":
{
"frame": {"x":384,"y":302,"w":47,"h":48},
"frame": {"x":625,"y":274,"w":47,"h":48},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":1,"y":0,"w":47,"h":48},
@ -992,7 +992,7 @@
"spriteSourceSize": {"x":4,"y":0,"w":88,"h":48},
"sourceSize": {"w":96,"h":48}
},
"sprites/buildings/trash-storage.png":
"sprites/buildings/storage.png":
{
"frame": {"x":859,"y":112,"w":85,"h":96},
"rotated": false,
@ -1010,7 +1010,7 @@
},
"sprites/buildings/underground_belt_entry-tier2.png":
{
"frame": {"x":4,"y":415,"w":47,"h":42},
"frame": {"x":890,"y":348,"w":47,"h":42},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":1,"y":6,"w":47,"h":42},
@ -1018,7 +1018,7 @@
},
"sprites/buildings/underground_belt_entry.png":
{
"frame": {"x":4,"y":463,"w":47,"h":38},
"frame": {"x":943,"y":382,"w":47,"h":38},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":1,"y":10,"w":47,"h":38},
@ -1026,7 +1026,7 @@
},
"sprites/buildings/underground_belt_exit-tier2.png":
{
"frame": {"x":111,"y":414,"w":47,"h":38},
"frame": {"x":731,"y":355,"w":47,"h":38},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":1,"y":0,"w":47,"h":38},
@ -1034,7 +1034,7 @@
},
"sprites/buildings/underground_belt_exit.png":
{
"frame": {"x":111,"y":458,"w":47,"h":38},
"frame": {"x":784,"y":355,"w":47,"h":38},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":1,"y":0,"w":47,"h":38},
@ -1050,7 +1050,7 @@
},
"sprites/buildings/virtual_processor-painter.png":
{
"frame": {"x":107,"y":502,"w":44,"h":48},
"frame": {"x":937,"y":426,"w":44,"h":48},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":4,"y":0,"w":44,"h":48},
@ -1058,7 +1058,7 @@
},
"sprites/buildings/virtual_processor-rotater.png":
{
"frame": {"x":316,"y":328,"w":41,"h":48},
"frame": {"x":315,"y":328,"w":41,"h":48},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":4,"y":0,"w":41,"h":48},
@ -1066,7 +1066,7 @@
},
"sprites/buildings/virtual_processor-shapecompare.png":
{
"frame": {"x":262,"y":325,"w":48,"h":45},
"frame": {"x":261,"y":325,"w":48,"h":45},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":0,"y":0,"w":48,"h":45},
@ -1074,7 +1074,7 @@
},
"sprites/buildings/virtual_processor-stacker.png":
{
"frame": {"x":54,"y":520,"w":44,"h":48},
"frame": {"x":568,"y":328,"w":44,"h":48},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":4,"y":0,"w":44,"h":48},
@ -1090,7 +1090,7 @@
},
"sprites/buildings/virtual_processor.png":
{
"frame": {"x":950,"y":220,"w":48,"h":48},
"frame": {"x":948,"y":220,"w":48,"h":48},
"rotated": false,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":48,"h":48},
@ -1098,7 +1098,7 @@
},
"sprites/buildings/wire-cross.png":
{
"frame": {"x":950,"y":274,"w":48,"h":48},
"frame": {"x":948,"y":274,"w":48,"h":48},
"rotated": false,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":48,"h":48},
@ -1106,7 +1106,7 @@
},
"sprites/buildings/wire-split.png":
{
"frame": {"x":795,"y":268,"w":48,"h":28},
"frame": {"x":4,"y":415,"w":48,"h":28},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":0,"y":20,"w":48,"h":28},
@ -1114,7 +1114,7 @@
},
"sprites/buildings/wire-turn.png":
{
"frame": {"x":912,"y":398,"w":28,"h":28},
"frame": {"x":527,"y":381,"w":28,"h":28},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":20,"y":20,"w":28,"h":28},
@ -1122,7 +1122,7 @@
},
"sprites/buildings/wire.png":
{
"frame": {"x":537,"y":368,"w":8,"h":48},
"frame": {"x":818,"y":420,"w":8,"h":48},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":20,"y":0,"w":8,"h":48},
@ -1130,7 +1130,7 @@
},
"sprites/buildings/wire_tunnel-coating.png":
{
"frame": {"x":547,"y":316,"w":12,"h":46},
"frame": {"x":996,"y":393,"w":12,"h":46},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":18,"y":1,"w":12,"h":46},
@ -1138,7 +1138,7 @@
},
"sprites/buildings/wire_tunnel.png":
{
"frame": {"x":58,"y":414,"w":47,"h":46},
"frame": {"x":837,"y":322,"w":47,"h":46},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":1,"y":1,"w":47,"h":46},
@ -1202,7 +1202,7 @@
},
"sprites/colors/yellow.png":
{
"frame": {"x":364,"y":261,"w":18,"h":18},
"frame": {"x":1002,"y":221,"w":18,"h":18},
"rotated": false,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":18,"h":18},
@ -1210,7 +1210,7 @@
},
"sprites/debug/acceptor_slot.png":
{
"frame": {"x":537,"y":302,"w":4,"h":4},
"frame": {"x":731,"y":274,"w":4,"h":4},
"rotated": false,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":4,"h":4},
@ -1218,7 +1218,7 @@
},
"sprites/debug/ejector_slot.png":
{
"frame": {"x":537,"y":312,"w":4,"h":4},
"frame": {"x":731,"y":284,"w":4,"h":4},
"rotated": false,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":4,"h":4},
@ -1234,7 +1234,7 @@
},
"sprites/misc/processor_disabled.png":
{
"frame": {"x":531,"y":452,"w":28,"h":29},
"frame": {"x":534,"y":346,"w":28,"h":29},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":2,"y":2,"w":28,"h":29},
@ -1250,7 +1250,7 @@
},
"sprites/misc/reader_overlay.png":
{
"frame": {"x":166,"y":366,"w":36,"h":25},
"frame": {"x":906,"y":263,"w":36,"h":25},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":6,"y":12,"w":36,"h":25},
@ -1258,7 +1258,7 @@
},
"sprites/misc/slot_bad_arrow.png":
{
"frame": {"x":363,"y":307,"w":13,"h":13},
"frame": {"x":1001,"y":355,"w":13,"h":13},
"rotated": false,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":13,"h":13},
@ -1266,7 +1266,7 @@
},
"sprites/misc/slot_good_arrow.png":
{
"frame": {"x":363,"y":326,"w":13,"h":13},
"frame": {"x":1001,"y":374,"w":13,"h":13},
"rotated": false,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":13,"h":13},
@ -1274,7 +1274,7 @@
},
"sprites/misc/storage_overlay.png":
{
"frame": {"x":984,"y":378,"w":30,"h":15},
"frame": {"x":166,"y":425,"w":30,"h":15},
"rotated": false,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":30,"h":15},
@ -1282,7 +1282,7 @@
},
"sprites/misc/waypoint.png":
{
"frame": {"x":550,"y":294,"w":14,"h":16},
"frame": {"x":1001,"y":333,"w":14,"h":16},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":1,"y":0,"w":14,"h":16},
@ -1290,7 +1290,7 @@
},
"sprites/wires/boolean_false.png":
{
"frame": {"x":363,"y":397,"w":12,"h":15},
"frame": {"x":818,"y":399,"w":12,"h":15},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":2,"y":1,"w":12,"h":15},
@ -1330,7 +1330,7 @@
},
"sprites/wires/display/purple.png":
{
"frame": {"x":1004,"y":221,"w":16,"h":16},
"frame": {"x":1002,"y":245,"w":16,"h":16},
"rotated": false,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":16,"h":16},
@ -1338,7 +1338,7 @@
},
"sprites/wires/display/red.png":
{
"frame": {"x":1004,"y":243,"w":16,"h":16},
"frame": {"x":1002,"y":267,"w":16,"h":16},
"rotated": false,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":16,"h":16},
@ -1346,7 +1346,7 @@
},
"sprites/wires/display/white.png":
{
"frame": {"x":1004,"y":265,"w":16,"h":16},
"frame": {"x":1002,"y":289,"w":16,"h":16},
"rotated": false,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":16,"h":16},
@ -1354,7 +1354,7 @@
},
"sprites/wires/display/yellow.png":
{
"frame": {"x":1004,"y":287,"w":16,"h":16},
"frame": {"x":1002,"y":311,"w":16,"h":16},
"rotated": false,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":16,"h":16},
@ -1362,10 +1362,10 @@
},
"sprites/wires/lever_on.png":
{
"frame": {"x":868,"y":364,"w":38,"h":44},
"frame": {"x":982,"y":530,"w":35,"h":40},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":5,"y":1,"w":38,"h":44},
"spriteSourceSize": {"x":6,"y":2,"w":35,"h":40},
"sourceSize": {"w":48,"h":48}
},
"sprites/wires/logical_acceptor.png":
@ -1386,7 +1386,7 @@
},
"sprites/wires/network_conflict.png":
{
"frame": {"x":1004,"y":309,"w":16,"h":16},
"frame": {"x":364,"y":261,"w":16,"h":16},
"rotated": false,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":16,"h":16},
@ -1394,7 +1394,7 @@
},
"sprites/wires/network_empty.png":
{
"frame": {"x":363,"y":285,"w":15,"h":16},
"frame": {"x":363,"y":283,"w":15,"h":16},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":1,"y":0,"w":15,"h":16},
@ -1402,7 +1402,7 @@
},
"sprites/wires/overlay_tile.png":
{
"frame": {"x":946,"y":378,"w":32,"h":32},
"frame": {"x":987,"y":445,"w":32,"h":32},
"rotated": false,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
@ -1418,7 +1418,7 @@
},
"sprites/wires/sets/color_forward.png":
{
"frame": {"x":551,"y":368,"w":8,"h":48},
"frame": {"x":818,"y":474,"w":8,"h":48},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":20,"y":0,"w":8,"h":48},
@ -1426,7 +1426,7 @@
},
"sprites/wires/sets/color_split.png":
{
"frame": {"x":849,"y":268,"w":48,"h":28},
"frame": {"x":112,"y":414,"w":48,"h":28},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":0,"y":20,"w":48,"h":28},
@ -1434,7 +1434,7 @@
},
"sprites/wires/sets/color_turn.png":
{
"frame": {"x":984,"y":399,"w":28,"h":28},
"frame": {"x":525,"y":415,"w":28,"h":28},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":20,"y":20,"w":28,"h":28},
@ -1450,7 +1450,7 @@
},
"sprites/wires/sets/conflict_forward.png":
{
"frame": {"x":363,"y":418,"w":8,"h":48},
"frame": {"x":363,"y":305,"w":8,"h":48},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":20,"y":0,"w":8,"h":48},
@ -1458,7 +1458,7 @@
},
"sprites/wires/sets/conflict_split.png":
{
"frame": {"x":572,"y":274,"w":48,"h":28},
"frame": {"x":741,"y":268,"w":48,"h":28},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":0,"y":20,"w":48,"h":28},
@ -1466,7 +1466,7 @@
},
"sprites/wires/sets/conflict_turn.png":
{
"frame": {"x":946,"y":416,"w":28,"h":28},
"frame": {"x":158,"y":480,"w":28,"h":28},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":20,"y":20,"w":28,"h":28},
@ -1474,7 +1474,7 @@
},
"sprites/wires/sets/regular_cross.png":
{
"frame": {"x":950,"y":274,"w":48,"h":48},
"frame": {"x":948,"y":274,"w":48,"h":48},
"rotated": false,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":48,"h":48},
@ -1482,7 +1482,7 @@
},
"sprites/wires/sets/regular_forward.png":
{
"frame": {"x":537,"y":368,"w":8,"h":48},
"frame": {"x":818,"y":420,"w":8,"h":48},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":20,"y":0,"w":8,"h":48},
@ -1490,7 +1490,7 @@
},
"sprites/wires/sets/regular_split.png":
{
"frame": {"x":795,"y":268,"w":48,"h":28},
"frame": {"x":4,"y":415,"w":48,"h":28},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":0,"y":20,"w":48,"h":28},
@ -1498,7 +1498,7 @@
},
"sprites/wires/sets/regular_turn.png":
{
"frame": {"x":912,"y":398,"w":28,"h":28},
"frame": {"x":527,"y":381,"w":28,"h":28},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":20,"y":20,"w":28,"h":28},
@ -1514,7 +1514,7 @@
},
"sprites/wires/sets/shape_forward.png":
{
"frame": {"x":883,"y":302,"w":8,"h":48},
"frame": {"x":362,"y":359,"w":8,"h":48},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":20,"y":0,"w":8,"h":48},
@ -1522,7 +1522,7 @@
},
"sprites/wires/sets/shape_split.png":
{
"frame": {"x":626,"y":274,"w":48,"h":28},
"frame": {"x":795,"y":268,"w":48,"h":28},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":0,"y":20,"w":48,"h":28},
@ -1530,7 +1530,7 @@
},
"sprites/wires/sets/shape_turn.png":
{
"frame": {"x":980,"y":433,"w":28,"h":28},
"frame": {"x":525,"y":449,"w":28,"h":28},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":20,"y":20,"w":28,"h":28},
@ -1551,6 +1551,6 @@
"format": "RGBA8888",
"size": {"w":1024,"h":1024},
"scale": "0.25",
"smartupdate": "$TexturePacker:SmartUpdate:c57f50d18c59efc0edbd4a3a732323a4:3fcf23da2ddc6370c437cf41f6d44ed0:908b89f5ca8ff73e331a35a3b14d0604$"
"smartupdate": "$TexturePacker:SmartUpdate:5429cdf3b92834776437a91974e89d3c:fa61fb225cd312db144ce6a38d97871b:908b89f5ca8ff73e331a35a3b14d0604$"
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 281 KiB

After

Width:  |  Height:  |  Size: 278 KiB

File diff suppressed because it is too large Load Diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 700 KiB

After

Width:  |  Height:  |  Size: 701 KiB

View File

@ -257,6 +257,10 @@
<key type="filename">sprites/belt/built/right_7.png</key>
<key type="filename">sprites/belt/built/right_8.png</key>
<key type="filename">sprites/belt/built/right_9.png</key>
<key type="filename">sprites/blueprints/balancer-merger-inverse.png</key>
<key type="filename">sprites/blueprints/balancer-merger.png</key>
<key type="filename">sprites/blueprints/balancer-splitter-inverse.png</key>
<key type="filename">sprites/blueprints/balancer-splitter.png</key>
<key type="filename">sprites/blueprints/constant_signal.png</key>
<key type="filename">sprites/blueprints/display.png</key>
<key type="filename">sprites/blueprints/lever.png</key>
@ -271,10 +275,6 @@
<key type="filename">sprites/blueprints/rotater-ccw.png</key>
<key type="filename">sprites/blueprints/rotater-rotate180.png</key>
<key type="filename">sprites/blueprints/rotater.png</key>
<key type="filename">sprites/blueprints/splitter-compact-inverse.png</key>
<key type="filename">sprites/blueprints/splitter-compact-merge-inverse.png</key>
<key type="filename">sprites/blueprints/splitter-compact-merge.png</key>
<key type="filename">sprites/blueprints/splitter-compact.png</key>
<key type="filename">sprites/blueprints/trash.png</key>
<key type="filename">sprites/blueprints/underground_belt_entry-tier2.png</key>
<key type="filename">sprites/blueprints/underground_belt_entry.png</key>
@ -289,6 +289,10 @@
<key type="filename">sprites/blueprints/virtual_processor.png</key>
<key type="filename">sprites/blueprints/wire_tunnel-coating.png</key>
<key type="filename">sprites/blueprints/wire_tunnel.png</key>
<key type="filename">sprites/buildings/balancer-merger-inverse.png</key>
<key type="filename">sprites/buildings/balancer-merger.png</key>
<key type="filename">sprites/buildings/balancer-splitter-inverse.png</key>
<key type="filename">sprites/buildings/balancer-splitter.png</key>
<key type="filename">sprites/buildings/constant_signal.png</key>
<key type="filename">sprites/buildings/display.png</key>
<key type="filename">sprites/buildings/lever.png</key>
@ -301,10 +305,6 @@
<key type="filename">sprites/buildings/reader.png</key>
<key type="filename">sprites/buildings/rotater-ccw.png</key>
<key type="filename">sprites/buildings/rotater-rotate180.png</key>
<key type="filename">sprites/buildings/splitter-compact-inverse.png</key>
<key type="filename">sprites/buildings/splitter-compact-merge-inverse.png</key>
<key type="filename">sprites/buildings/splitter-compact-merge.png</key>
<key type="filename">sprites/buildings/splitter-compact.png</key>
<key type="filename">sprites/buildings/underground_belt_entry-tier2.png</key>
<key type="filename">sprites/buildings/underground_belt_entry.png</key>
<key type="filename">sprites/buildings/underground_belt_exit-tier2.png</key>
@ -350,6 +350,30 @@
<key>scale9FromFile</key>
<false/>
</struct>
<key type="filename">sprites/blueprints/balancer.png</key>
<key type="filename">sprites/blueprints/cutter.png</key>
<key type="filename">sprites/blueprints/filter.png</key>
<key type="filename">sprites/blueprints/mixer.png</key>
<key type="filename">sprites/blueprints/painter-mirrored.png</key>
<key type="filename">sprites/blueprints/painter.png</key>
<key type="filename">sprites/blueprints/stacker.png</key>
<key type="filename">sprites/buildings/balancer.png</key>
<key type="filename">sprites/buildings/filter.png</key>
<key type="filename">sprites/buildings/painter-mirrored.png</key>
<struct type="IndividualSpriteSettings">
<key>pivotPoint</key>
<point_f>0.5,0.5</point_f>
<key>spriteScale</key>
<double>1</double>
<key>scale9Enabled</key>
<false/>
<key>scale9Borders</key>
<rect>96,48,192,96</rect>
<key>scale9Paddings</key>
<rect>96,48,192,96</rect>
<key>scale9FromFile</key>
<false/>
</struct>
<key type="filename">sprites/blueprints/belt_left.png</key>
<key type="filename">sprites/blueprints/belt_right.png</key>
<key type="filename">sprites/blueprints/belt_top.png</key>
@ -396,29 +420,6 @@
<key>scale9FromFile</key>
<false/>
</struct>
<key type="filename">sprites/blueprints/cutter.png</key>
<key type="filename">sprites/blueprints/filter.png</key>
<key type="filename">sprites/blueprints/mixer.png</key>
<key type="filename">sprites/blueprints/painter-mirrored.png</key>
<key type="filename">sprites/blueprints/painter.png</key>
<key type="filename">sprites/blueprints/splitter.png</key>
<key type="filename">sprites/blueprints/stacker.png</key>
<key type="filename">sprites/buildings/filter.png</key>
<key type="filename">sprites/buildings/painter-mirrored.png</key>
<struct type="IndividualSpriteSettings">
<key>pivotPoint</key>
<point_f>0.5,0.5</point_f>
<key>spriteScale</key>
<double>1</double>
<key>scale9Enabled</key>
<false/>
<key>scale9Borders</key>
<rect>96,48,192,96</rect>
<key>scale9Paddings</key>
<rect>96,48,192,96</rect>
<key>scale9FromFile</key>
<false/>
</struct>
<key type="filename">sprites/blueprints/painter-double.png</key>
<key type="filename">sprites/blueprints/trash-storage.png</key>
<key type="filename">sprites/buildings/painter-double.png</key>
@ -439,7 +440,6 @@
<key type="filename">sprites/buildings/cutter.png</key>
<key type="filename">sprites/buildings/mixer.png</key>
<key type="filename">sprites/buildings/painter.png</key>
<key type="filename">sprites/buildings/splitter.png</key>
<key type="filename">sprites/buildings/stacker.png</key>
<struct type="IndividualSpriteSettings">
<key>pivotPoint</key>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 19 KiB

View File

Before

Width:  |  Height:  |  Size: 47 KiB

After

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.1 KiB

After

Width:  |  Height:  |  Size: 9.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 14 KiB

View File

Before

Width:  |  Height:  |  Size: 30 KiB

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.5 KiB

After

Width:  |  Height:  |  Size: 14 KiB

View File

@ -50,7 +50,6 @@
left: 0;
right: 0;
bottom: 0;
background: rgba($mainBgColor, 0.9) uiResource("loading.svg") center center / #{D(60px)} no-repeat;
@include InlineAnimation(0.2s ease-in-out) {
0% {
opacity: 0;
@ -59,6 +58,11 @@
opacity: 1;
}
}
& {
/* @load-async */
background: rgba($mainBgColor, 0.9) uiResource("loading.svg") center center / #{D(60px)} no-repeat;
}
}
}
}

View File

@ -391,11 +391,15 @@ canvas {
color: #393747;
&::after {
content: " ";
background: uiResource("loading.svg") center center / contain no-repeat;
@include S(width, 35px);
@include S(height, 35px);
display: inline-block;
vertical-align: middle;
& {
/* @load-async */
background: uiResource("loading.svg") center center / contain no-repeat;
}
}
@include InlineAnimation(1.5s ease-in-out infinite) {
@ -451,7 +455,6 @@ canvas {
.prefab_InfoIcon {
@include S(width, 25px);
@include S(height, 25px);
// background: uiResource("icons_small/info.png") center center / contain no-repeat;
z-index: 100;
opacity: 0.8;
cursor: pointer;
@ -468,7 +471,6 @@ canvas {
justify-content: center;
flex-direction: column;
.loadingImage {
background: uiResource("loading.svg") center center / #{D(40px)} no-repeat;
width: 100%;
display: flex;
flex-grow: 1;
@ -478,6 +480,11 @@ canvas {
transform: scale(1.2) rotate(160deg);
}
}
& {
/* @load-async */
background: uiResource("loading.svg") center center / #{D(40px)} no-repeat;
}
}
.prefab_GameHint {

View File

@ -4,25 +4,14 @@
left: 50%;
transform: translateX(-50%);
// NOTE: This flex rule may not be necessary. Need to find out intent.
display: flex;
flex-direction: column;
display: grid;
grid-template-rows: auto auto;
justify-items: center;
background: transparent;
transition: transform 120ms ease-in-out;
will-change: transform;
backdrop-filter: blur(D(3px));
background-color: rgba(0, 40, 80, 0.05);
@include S(border-radius, $globalBorderRadius);
@include DarkThemeOverride {
background-color: rgba(darken($darkModeGameBackground, 15), 0.4);
&#ingame_HUD_wires_toolbar {
background-color: rgba(darken($darkModeGameBackground, 5), 0.1);
}
}
&:not(.visible) {
transform: translateX(-50%) translateY(#{D(100px)});
}
@ -30,6 +19,34 @@
.buildings {
display: grid;
grid-auto-flow: column;
justify-items: center;
align-self: center;
grid-row: 2 / 3;
background-color: rgba(240, 241, 243, 0.5);
@include S(border-radius, $globalBorderRadius);
@include DarkThemeOverride {
background-color: rgba(darken($darkModeGameBackground, 15), 0.4);
}
&.secondary {
grid-row: 1 / 2;
border-bottom-left-radius: 0;
border-bottom-right-radius: 0;
.building {
@include S(width, 30px);
@include S(height, 22px);
background-size: 45%;
&:not(.unlocked) {
&::before {
background-size: #{D(13px)};
}
}
}
}
.building {
color: $accentColorDark;
@ -52,14 +69,18 @@
&::before {
content: " ";
background: uiResource("locked_building.png") center center / #{D(20px)} #{D(20px)}
no-repeat;
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
z-index: 4;
& {
/* @load-async */
background: uiResource("locked_building.png") center center / #{D(20px)} #{D(20px)}
no-repeat;
}
}
}

View File

@ -122,13 +122,16 @@
opacity: 0.7;
@include S(width, 20px);
@include S(height, 20px);
background: uiResource("icons/close.png") center center / 80% no-repeat;
cursor: pointer;
pointer-events: all;
transition: opacity 0.2s ease-in-out;
&:hover {
opacity: 0.4;
}
& {
/* @load-async */
background: uiResource("icons/close.png") center center / 80% no-repeat;
}
}
}

View File

@ -38,17 +38,26 @@
@include DarkThemeInvert;
&.shop {
background-image: uiResource("icons/shop.png");
grid-column: 1;
& {
/* @load-async */
background-image: uiResource("icons/shop.png");
}
}
&.stats {
background-image: uiResource("icons/statistics.png");
grid-column: 2;
& {
/* @load-async */
background-image: uiResource("icons/statistics.png");
}
}
&.save {
background-image: uiResource("icons/save.png");
& {
/* @load-async */
background-image: uiResource("icons/save.png");
}
grid-column: 3;
@include MakeAnimationWrappedEvenOdd(0.5s ease-in-out) {
0% {
@ -83,8 +92,11 @@
}
&.settings {
background-image: uiResource("icons/settings_menu_settings.png");
grid-column: 4;
& {
/* @load-async */
background-image: uiResource("icons/settings_menu_settings.png");
}
}
&:hover {
@ -99,9 +111,14 @@
&.hasBadge {
&.shop {
filter: none;
background-image: uiResource("icons/shop_active.png");
opacity: 0.9;
& {
/* @load-async */
background-image: uiResource("icons/shop_active.png");
}
}
transform-origin: 50% 50%;
@include InlineAnimation(0.8s ease-in-out infinite) {
50% {

View File

@ -47,10 +47,12 @@
left: unset;
margin: 0;
&.rightMouse {
/* @load-async */
background: #fff uiResource("icons/mouse_right.png") center center / 85% no-repeat;
}
&.leftMouse {
/* @load-async */
background: #fff uiResource("icons/mouse_left.png") center center / 85% no-repeat;
}
}

View File

@ -77,7 +77,6 @@
> .infoButton {
@include S(width, 8px);
@include S(height, 8px);
background: uiResource("icons/info_button.png") center center / 95% no-repeat;
position: absolute;
opacity: 0.7;
@include S(top, 13px);
@ -90,6 +89,11 @@
&:hover {
opacity: 0.8;
}
& {
/* @load-async */
background: uiResource("icons/info_button.png") center center / 95% no-repeat;
}
}
&.goal,
@ -107,11 +111,13 @@
&.goal .amountLabel {
&::after {
/* @load-async */
background-image: uiResource("icons/current_goal_marker.png");
background-size: 90%;
}
@include DarkThemeOverride {
&::after {
/* @load-async */
background-image: uiResource("icons/current_goal_marker_inverted.png") !important;
}
}
@ -119,11 +125,13 @@
&.blueprint .amountLabel {
&::after {
/* @load-async */
background-image: uiResource("icons/blueprint_marker.png");
background-size: 90%;
}
@include DarkThemeOverride {
&::after {
/* @load-async */
background-image: uiResource("icons/blueprint_marker_inverted.png") !important;
}
}

View File

@ -39,23 +39,29 @@
background: transparent;
filter: invert(1);
background: uiResource("icons/settings_menu_play.png") center top / contain no-repeat;
content: "";
opacity: 0.8;
@include S(width, 35px);
@include S(height, 35px);
&.settings {
/* @load-async */
background-image: uiResource("icons/settings_menu_settings.png");
}
&.menu {
/* @load-async */
background-image: uiResource("icons/settings_menu_exit.png");
}
&:hover {
opacity: 0.6;
}
& {
/* @load-async */
background: uiResource("icons/settings_menu_play.png") center top / contain no-repeat;
}
}
}
}

View File

@ -113,9 +113,13 @@
overflow: hidden;
button.pin {
& {
/* @load-async */
background: uiResource("icons/pin.png") center center / 95% no-repeat;
}
@include S(width, 12px);
@include S(height, 12px);
background: uiResource("icons/pin.png") center center / 95% no-repeat;
position: absolute;
@include S(top, 2px);
@include S(right, 2px);
@ -143,6 +147,7 @@
}
&.isGoal {
/* @load-async */
background: uiResource("icons/current_goal_marker.png") center center / 95%
no-repeat;
opacity: $disabledOpacity !important;
@ -198,7 +203,6 @@
button.showInfo {
@include S(width, 11px);
@include S(height, 11px);
background: uiResource("icons/info_button.png") center center / 95% no-repeat;
position: absolute;
@include S(top, 17px);
@include S(right, 2.5px);
@ -213,6 +217,10 @@
opacity: 0.6;
}
}
button.showInfo {
/* @load-async */
background: uiResource("icons/info_button.png") center center / 95% no-repeat;
}
canvas {
@include S(width, 40px);

View File

@ -39,10 +39,12 @@
}
&.displayDetailed {
/* @load-async */
background-image: uiResource("icons/display_list.png");
}
&.displayIcons {
/* @load-async */
background-image: uiResource("icons/display_icons.png");
background-size: #{D(11.5px)};
}
@ -53,7 +55,10 @@
}
&.displaySorted {
background-image: uiResource("icons/display_sorted.png");
& {
/* @load-async */
background-image: uiResource("icons/display_sorted.png");
}
background-size: #{D(11.5px)};
margin-right: 5px;
@include S(border-top-right-radius, $globalBorderRadius);
@ -63,7 +68,10 @@
}
&.displayIterateUnit {
background-image: uiResource("icons/toggle_unit.png");
& {
/* @load-async */
background-image: uiResource("icons/toggle_unit.png");
}
opacity: 0.8;
@include S(padding, 1px, 0);
}

View File

@ -1,117 +1,120 @@
#ingame_HUD_TutorialHints {
position: absolute;
@include S(left, 10px);
@include S(bottom, 10px);
@include StyleBelowWidth(1430px) {
@include S(bottom, 50px);
}
display: flex;
flex-direction: column;
background: rgba(50, 60, 70, 0);
transition: all 0.2s ease-in-out;
pointer-events: all;
transition-property: background-color, transform, bottom, left;
@include S(padding, 5px);
video {
transition: all 0.2s ease-in-out;
transition-property: opacity, width;
@include S(width, 0px);
opacity: 0;
z-index: 10;
position: relative;
}
.header {
color: #333438;
display: grid;
align-items: center;
@include S(grid-gap, 2px);
grid-template-columns: 1fr;
@include S(margin-bottom, 3px);
z-index: 11;
position: relative;
> span {
@include DarkThemeInvert;
display: flex;
@include SuperSmallText;
justify-content: flex-start;
align-items: center;
&::before {
@include S(margin-right, 4px);
content: " ";
@include S(width, 12px);
@include S(height, 12px);
display: inline-block;
background: uiResource("icons/help.png") center center / 95% no-repeat;
}
}
button.toggleHint {
@include PlainText;
@include IncreasedClickArea(0px);
}
}
button.toggleHint {
.hide {
display: none;
}
}
&.enlarged {
background: $ingameHudBg;
left: 50%;
bottom: 50%;
transform: translate(-50%, 50%);
&::before {
pointer-events: all;
content: " ";
position: fixed;
top: -1000px;
left: -1000px;
right: -1000px;
bottom: -1000px;
z-index: 0;
background: rgba($ingameHudBg, 0.3);
}
.header {
grid-template-columns: 1fr auto;
> span {
display: none;
}
button.toggleHint {
grid-column: 2 / 3;
}
}
video {
@include InlineAnimation(0.2s ease-in-out) {
0% {
opacity: 0;
@include S(width, 0px);
}
}
opacity: 1;
@include S(width, 500px);
}
button.toggleHint {
.hide {
display: block;
}
.show {
display: none;
}
}
}
}
#ingame_HUD_TutorialHints {
position: absolute;
@include S(left, 10px);
@include S(bottom, 10px);
@include StyleBelowWidth(1430px) {
@include S(bottom, 50px);
}
display: flex;
flex-direction: column;
background: rgba(50, 60, 70, 0);
transition: all 0.2s ease-in-out;
pointer-events: all;
transition-property: background-color, transform, bottom, left;
@include S(padding, 5px);
video {
transition: all 0.2s ease-in-out;
transition-property: opacity, width;
@include S(width, 0px);
opacity: 0;
z-index: 10;
position: relative;
}
.header {
color: #333438;
display: grid;
align-items: center;
@include S(grid-gap, 2px);
grid-template-columns: 1fr;
@include S(margin-bottom, 3px);
z-index: 11;
position: relative;
> span {
@include DarkThemeInvert;
display: flex;
@include SuperSmallText;
justify-content: flex-start;
align-items: center;
&::before {
@include S(margin-right, 4px);
content: " ";
@include S(width, 12px);
@include S(height, 12px);
display: inline-block;
& {
/* @load-async */
background: uiResource("icons/help.png") center center / 95% no-repeat;
}
}
}
button.toggleHint {
@include PlainText;
@include IncreasedClickArea(0px);
}
}
button.toggleHint {
.hide {
display: none;
}
}
&.enlarged {
background: $ingameHudBg;
left: 50%;
bottom: 50%;
transform: translate(-50%, 50%);
&::before {
pointer-events: all;
content: " ";
position: fixed;
top: -1000px;
left: -1000px;
right: -1000px;
bottom: -1000px;
z-index: 0;
background: rgba($ingameHudBg, 0.3);
}
.header {
grid-template-columns: 1fr auto;
> span {
display: none;
}
button.toggleHint {
grid-column: 2 / 3;
}
}
video {
@include InlineAnimation(0.2s ease-in-out) {
0% {
opacity: 0;
@include S(width, 0px);
}
}
opacity: 1;
@include S(width, 500px);
}
button.toggleHint {
.hide {
display: block;
}
.show {
display: none;
}
}
}
}

View File

@ -1,177 +1,181 @@
#ingame_HUD_UnlockNotification {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(#333538, 0.98) uiResource("dialog_bg_pattern.png") top left / #{D(10px)} repeat;
display: flex;
justify-content: center;
align-items: center;
pointer-events: all;
@include InlineAnimation(0.1s ease-in-out) {
0% {
opacity: 0;
}
}
.dialog {
// background: rgba(#222428, 0.5);
@include S(border-radius, $globalBorderRadius);
@include S(padding, 30px);
@include InlineAnimation(0.5s ease-in-out) {
0% {
opacity: 0;
}
}
display: flex;
align-items: center;
flex-direction: column;
max-height: 100vh;
color: #fff;
text-align: center;
.title,
.subTitle {
@include SuperHeading;
text-transform: uppercase;
@include S(font-size, 40px);
@include InlineAnimation(0.5s ease-in-out) {
0% {
transform: translateY(-50vh);
}
50% {
transform: translateY(5vh);
}
75% {
transform: translateY(-2vh);
}
}
}
.subTitle {
@include PlainText;
display: inline-block;
@include S(margin, 5px, 0, 20px);
color: $colorGreenBright;
@include S(border-radius, $globalBorderRadius);
@include InlineAnimation(0.5s ease-in-out) {
0% {
transform: translateY(-60vh);
}
50% {
transform: translateY(6vh);
}
75% {
transform: translateY(-3vh);
}
}
}
.contents {
@include S(width, 400px);
@include InlineAnimation(0.5s ease-in-out) {
0% {
transform: translateX(-100vw);
}
50% {
transform: translateX(5vw);
}
75% {
transform: translateX(-2vw);
}
}
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
@include S(grid-gap, 10px);
.rewardName {
grid-column: 1 / 3;
display: none;
@include InlineAnimation(0.5s ease-in-out) {
0% {
transform: translateX(200vw);
}
50% {
transform: translateX(-10vw);
}
75% {
transform: translateX(4vw);
}
}
}
.rewardDesc {
grid-column: 1 / 3;
@include PlainText;
@include S(margin-bottom, 15px);
color: #aaacaf;
@include S(width, 400px);
text-align: left;
strong {
color: #fff;
}
}
.images {
display: flex;
.buildingExplanation {
@include S(width, 200px);
@include S(height, 200px);
display: inline-block;
background-position: center center;
background-size: cover;
background-repeat: no-repeat;
@include S(border-radius, $globalBorderRadius);
box-shadow: #{D(2px)} #{D(3px)} 0 0 rgba(0, 0, 0, 0.15);
}
}
}
button.close {
border: 0;
position: relative;
@include S(margin-top, 30px);
&:not(.unlocked) {
pointer-events: none;
opacity: 0.8;
cursor: default;
}
&.unlocked {
&::after {
animation: none !important;
}
}
&::after {
content: " ";
display: inline-block;
position: absolute;
top: 0;
left: 100%;
right: 0;
bottom: 0;
background: rgba(0, 10, 20, 0.8);
@include InlineAnimation(5s linear) {
0% {
left: 0;
}
100% {
left: 100%;
}
}
}
}
}
}
#ingame_HUD_UnlockNotification {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
display: flex;
justify-content: center;
align-items: center;
pointer-events: all;
& {
/* @load-async */
background: rgba(#333538, 0.98) uiResource("dialog_bg_pattern.png") top left / #{D(10px)} repeat;
}
@include InlineAnimation(0.1s ease-in-out) {
0% {
opacity: 0;
}
}
.dialog {
// background: rgba(#222428, 0.5);
@include S(border-radius, $globalBorderRadius);
@include S(padding, 30px);
@include InlineAnimation(0.5s ease-in-out) {
0% {
opacity: 0;
}
}
display: flex;
align-items: center;
flex-direction: column;
max-height: 100vh;
color: #fff;
text-align: center;
.title,
.subTitle {
@include SuperHeading;
text-transform: uppercase;
@include S(font-size, 40px);
@include InlineAnimation(0.5s ease-in-out) {
0% {
transform: translateY(-50vh);
}
50% {
transform: translateY(5vh);
}
75% {
transform: translateY(-2vh);
}
}
}
.subTitle {
@include PlainText;
display: inline-block;
@include S(margin, 5px, 0, 20px);
color: $colorGreenBright;
@include S(border-radius, $globalBorderRadius);
@include InlineAnimation(0.5s ease-in-out) {
0% {
transform: translateY(-60vh);
}
50% {
transform: translateY(6vh);
}
75% {
transform: translateY(-3vh);
}
}
}
.contents {
@include S(width, 400px);
@include InlineAnimation(0.5s ease-in-out) {
0% {
transform: translateX(-100vw);
}
50% {
transform: translateX(5vw);
}
75% {
transform: translateX(-2vw);
}
}
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
@include S(grid-gap, 10px);
.rewardName {
grid-column: 1 / 3;
display: none;
@include InlineAnimation(0.5s ease-in-out) {
0% {
transform: translateX(200vw);
}
50% {
transform: translateX(-10vw);
}
75% {
transform: translateX(4vw);
}
}
}
.rewardDesc {
grid-column: 1 / 3;
@include PlainText;
@include S(margin-bottom, 15px);
color: #aaacaf;
@include S(width, 400px);
text-align: left;
strong {
color: #fff;
}
}
.images {
display: flex;
.buildingExplanation {
@include S(width, 200px);
@include S(height, 200px);
display: inline-block;
background-position: center center;
background-size: cover;
background-repeat: no-repeat;
@include S(border-radius, $globalBorderRadius);
box-shadow: #{D(2px)} #{D(3px)} 0 0 rgba(0, 0, 0, 0.15);
}
}
}
button.close {
border: 0;
position: relative;
@include S(margin-top, 30px);
&:not(.unlocked) {
pointer-events: none;
opacity: 0.8;
cursor: default;
}
&.unlocked {
&::after {
animation: none !important;
}
}
&::after {
content: " ";
display: inline-block;
position: absolute;
top: 0;
left: 100%;
right: 0;
bottom: 0;
background: rgba(0, 10, 20, 0.8);
@include InlineAnimation(5s linear) {
0% {
left: 0;
}
100% {
left: 100%;
}
}
}
}
}
}

View File

@ -4,7 +4,10 @@
left: 0;
right: 0;
bottom: 0;
background: uiResource("vignette.lossless.png") center center / cover no-repeat;
& {
/* @load-async */
background: uiResource("vignette.lossless.png") center center / cover no-repeat;
}
pointer-events: none;
@include DarkThemeOverride {

View File

@ -1,18 +1,22 @@
#ingame_HUD_Watermark {
position: absolute;
background: uiResource("get_on_steam.png") center center / contain no-repeat;
@include S(width, 110px);
@include S(height, 40px);
@include S(top, 10px);
pointer-events: all;
cursor: pointer;
@include S(left, 160px);
transition: all 0.12s ease-in;
transition-property: opacity, transform;
transform: skewX(-0.5deg);
&:hover {
transform: skewX(-1deg) scale(1.02);
opacity: 0.9;
}
}
#ingame_HUD_Watermark {
position: absolute;
& {
/* @load-async */
background: uiResource("get_on_steam.png") center center / contain no-repeat;
}
@include S(width, 110px);
@include S(height, 40px);
@include S(top, 10px);
pointer-events: all;
cursor: pointer;
@include S(left, 160px);
transition: all 0.12s ease-in;
transition-property: opacity, transform;
transform: skewX(-0.5deg);
&:hover {
transform: skewX(-1deg) scale(1.02);
opacity: 0.9;
}
}

View File

@ -39,6 +39,8 @@
overflow-y: auto;
pointer-events: all;
@include S(padding-right, 5px);
@include S(padding-bottom, 5px);
@include S(padding-top, 5px);
// Scrollbar
&::-webkit-scrollbar {
@ -55,7 +57,10 @@
display: grid;
grid-template-columns: 1fr auto;
align-items: center;
background: uiResource("icons/waypoint.png") left 50% / #{D(8px)} no-repeat;
& {
/* @load-async */
background: uiResource("icons/waypoint.png") left 50% / #{D(8px)} no-repeat;
}
opacity: 0.7;
@include S(margin-bottom, 1px);
font-weight: bold;
@ -68,7 +73,10 @@
@include S(width, 10px);
@include S(height, 10px);
@include S(margin-left, 4px);
background: uiResource("icons/edit_key.png") center center / 70% no-repeat;
& {
/* @load-async */
background: uiResource("icons/edit_key.png") center center / 70% no-repeat;
}
pointer-events: all;
cursor: pointer;
position: relative;

View File

@ -6,7 +6,7 @@
@return inline($pth);
}
@import "icons";
@import "resources";
@import "trigonometry";
@import "material_colors";
@import "dynamic_ui";

View File

@ -1,363 +1,316 @@
// ----------------------------------------
/* Forces an element to get rendered on its own layer, increasing
the performance when animated. Use only transform and opacity in animations! */
@mixin FastAnimation {
will-change: transform, opacity, filter;
// transform: translateZ(0);
backface-visibility: hidden;
-webkit-backface-visibility: hidden;
}
// Helper which includes the translateZ webkit fix, use together with Fast animation
// $hardwareAcc: translateZ(0);
$hardwareAcc: null;
// ----------------------------------------
/** Increased click area for this element, helpful on mobile */
@mixin IncreasedClickArea($size) {
&::after {
content: "";
position: absolute;
top: #{D(-$size)};
bottom: #{D(-$size)};
left: #{D(-$size)};
right: #{D(-$size)};
// background: rgba(255, 0, 0, 0.3);
}
}
button,
.increasedClickArea {
position: relative;
@include IncreasedClickArea(15px);
}
// ----------------------------------------
/* Duplicates an animation and adds two classes .<classPrefix>Even and .<classPrefix>Odd which uses the
animation. This can be used to replay the animation by toggling between the classes, because
it is not possible to restart a css animation */
@mixin MakeAnimationWrappedEvenOdd($duration, $classPrefix: "anim", $childSelector: "") {
$animName: autogen_anim_#{unique-id()};
@at-root {
@keyframes #{$animName}_even {
@content;
}
@keyframes #{$animName}_odd {
@content;
}
}
&.#{$classPrefix}Even #{$childSelector} {
animation: #{$animName}_even $duration;
}
&.#{$classPrefix}Odd #{$childSelector} {
animation: #{$animName}_odd $duration;
}
}
// ----------------------------------------
/* Allows to use and define an animation without specifying its name */
@mixin InlineAnimation($duration) {
$animName: autogen_anim_#{unique-id()};
@at-root {
@keyframes #{$animName} {
@content;
}
}
animation: $animName $duration !important;
}
// ----------------------------------------
/* Animation prefab for a double bounce pop-in animation, useful for dialogs */
@mixin DoubleBounceAnim($duration: 0.5s ease-in-out, $amount: 0.2, $initialOpacity: 0) {
@include InlineAnimation($duration) {
0% {
opacity: $initialOpacity;
transform: scale(0) $hardwareAcc;
}
25% {
opacity: 0.5;
transform: scale(1 + $amount) $hardwareAcc;
}
50% {
opacity: 1;
transform: scale(1 - $amount * 0.5) $hardwareAcc;
}
75% {
transform: scale(1 + $amount * 0.25) $hardwareAcc;
}
100% {
transform: scale(1) $hardwareAcc;
}
}
opacity: 1;
}
// ----------------------------------------
/* Define a style which is only applied in horizontal mode */
@mixin HorizontalStyle {
@include AppendGlobal(".h") {
@content;
}
}
// ----------------------------------------
/* Define a style which is only applied in vertical mode */
@mixin VerticalStyle {
@include AppendGlobal(".v") {
@content;
}
}
// ----------------------------------------
/* Define a style which is only while the hardware keyboard is open */
@mixin AndroidHwKeyboardOpen {
@include AppendGlobal(".kb") {
@content;
}
}
// ----------------------------------------
/* Automatically transforms the game state if a hardware keyboard is open */
@mixin TransformToMatchKeyboard {
transition: transform 0.2s ease-in-out;
@include AndroidHwKeyboardOpen {
@include VerticalStyle {
transform: translateY(#{D(-125px)}) $hardwareAcc;
}
@include HorizontalStyle {
transform: translateY(#{D(-100px)}) $hardwareAcc;
}
}
}
// ----------------------------------------
/* Define a style which is only applied when the viewport is at least X pixels wide */
@mixin StyleAtWidth($minW) {
@media (min-width: #{$minW}) {
@content;
}
}
// ----------------------------------------
/* Define a style which is only applied when the viewport is at least X pixels height */
@mixin StyleAtHeight($minH) {
@media (min-height: #{$minH}) {
@content;
}
}
// ----------------------------------------
/* Define a style which is only applied when the viewport has at least the given dimensions */
@mixin StyleAtDims($minW, $minH) {
@media (min-height: #{$minH}) and (min-width: #{$minW}) {
@content;
}
}
// ----------------------------------------
/* Define a style which is only applied when the viewport has at maximum the given dimensions */
@mixin StyleBelowDims($maxW, $maxH) {
@media (max-height: #{$maxH}) and (max-width: #{$maxW}) {
@content;
}
}
// ----------------------------------------
/* Define a style which is only applied when the viewport has at maximum the given height */
@mixin StyleBelowHeight($maxH) {
@media (max-height: #{$maxH}) {
@content;
}
}
// ----------------------------------------
/* Define a style which is only applied when the viewport has at maximum the given width */
@mixin StyleBelowWidth($maxW) {
@media (max-width: #{$maxW}) {
@content;
}
}
// ----------------------------------------
// Dynamic graphics quality styles
@mixin BoxShadow3D($bgColor, $size: 3px, $pressEffect: true) {
background-color: $bgColor;
$borderSize: 1.5px;
$borderColor: rgb(18, 20, 24);
// box-shadow: 0 0 0 D($borderSize) $borderColor, 0 D($size) 0 0px rgba(mix(darken($bgColor, 9), #b0e2ff, 95%), 1),
// 0 D($size) 0 D($borderSize) $borderColor;
// box-shadow: 0 0 0 D($borderSize) $borderColor, 0 D($size) 0 D($borderSize) $borderColor,
// D(-$size * 1.5) D($size * 2) 0 D($borderSize) rgba(0, 0, 0, 0.1);
// transition: box-shadow 0.1s ease-in-out;
// @if $pressEffect {
// &.pressed {
// transform: none !important;
// $pSize: max(0, $size - 1.5px);
// transition: none !important;
// box-shadow: 0 0 0 D($borderSize) $borderColor, 0 D($pSize) 0 0px rgba(mix(darken($bgColor, 9), #b0e2ff, 95%), 1),
// 0 D($pSize) 0 D($borderSize) $borderColor;
// top: D($size - $pSize);
// }
// }
}
@mixin BorderRadius($v1: 2px, $v2: "", $v3: "", $v4: "") {
@include S(border-radius, $v1, $v2, $v3, $v4);
}
@mixin BoxShadow($x, $y, $blur, $offset, $color) {
box-shadow: D($x) D($y) D($blur) D($offset) $color;
}
@mixin DropShadow($yOffset: 2px, $blur: 2px, $amount: 0.2) {
@include BoxShadow(0, $yOffset, $blur, 0, rgba(#000, $amount));
}
@mixin TextShadow($yOffset: 2px, $blur: 1px, $amount: 0.6) {
text-shadow: 0 D($yOffset) D($blur) rgba(#000, $amount);
}
@mixin Button3D($bgColor, $pressEffect: true) {
@include BoxShadow3D($bgColor, 2px, $pressEffect);
}
@mixin ButtonDisabled3D($bgColor) {
@include BoxShadow3D($bgColor, 0.5px, false);
}
@mixin BoxShadowInset($bgColor, $size: 3px) {
background-color: $bgColor;
$borderSize: 1px;
$borderColor: rgb(15, 19, 24);
box-shadow: 0 0 0 D($borderSize) $borderColor, 0 D($size) 0 rgba(#fff, 0.07);
border-top: D($size) solid rgba(#000, 0.1);
//, 0 D($size) 0 0px rgba(mix(darken($bgColor, 9), #b0e2ff, 95%), 1),
// 0 D($size + $borderSize) 0 0 $borderColor;
}
@mixin TextShadow3D($color: rgb(222, 234, 238), $borderColor: #000) {
color: $color;
}
// ----------------------------------------
/* Shine animation prefab, useful for buttons etc. Adds a bright shine which moves over
the button like a reflection. Performance heavy. */
@mixin ShineAnimation($duration, $bgColor, $w: 200px, $shineAlpha: 0.25, $lightenAmount: 7, $bgAnim: true) {
$bgBase: darken($bgColor, 5);
background-color: $bgBase;
@include HighQualityOrMore {
position: relative;
// overflow: hidden;
// overflow: visible;
&:before {
content: " ";
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: uiResource("misc/shine_bg.png") 0px center / 100% 100% no-repeat;
@include InlineAnimation($duration ease-in-out infinite) {
0% {
background-position-x: #{D(-$w)};
}
100% {
background-position-x: #{D($w)};
}
}
}
@if ($bgAnim) {
@include InlineAnimation($duration ease-in-out infinite) {
0% {
background-color: $bgBase;
}
50% {
background-color: lighten($bgBase, $lightenAmount);
}
100% {
background-color: $bgBase;
}
}
}
}
}
// ----------------------------------------
/* String replacement */
@function str-replace($string, $search, $replace: "") {
$index: str-index($string, $search);
@if $index {
@return str-slice($string, 1, $index - 1) + $replace +
str-replace(str-slice($string, $index + str-length($search)), $search, $replace);
}
@return $string;
}
@mixin BounceInFromSide($mul, $duration: 0.18s ease-in-out) {
@include InlineAnimation($duration) {
0% {
transform: translateY(#{D(-100px * $mul)}) scale(0.9);
opacity: 0;
}
100% {
opacity: 1;
transform: none;
}
}
opacity: 1;
transform: none;
}
@mixin BreakText {
word-wrap: break-word;
word-break: break-all;
overflow-wrap: break-all;
}
@mixin SupportsAndroidNotchQuery {
@supports (color: constant(--notch-inset-left)) {
@content;
}
}
@mixin SupportsiOsNotchQuery {
@supports (color: env(safe-area-inset-left, 0px)) {
@content;
}
}
@mixin DarkThemeOverride {
@at-root html[data-theme="dark"] &,
&[data-theme="dark"] {
@content;
}
}
@mixin DarkThemeInvert {
@include DarkThemeOverride {
filter: invert(1);
}
}
// ----------------------------------------
/* Forces an element to get rendered on its own layer, increasing
the performance when animated. Use only transform and opacity in animations! */
@mixin FastAnimation {
will-change: transform, opacity, filter;
// transform: translateZ(0);
backface-visibility: hidden;
-webkit-backface-visibility: hidden;
}
// Helper which includes the translateZ webkit fix, use together with Fast animation
// $hardwareAcc: translateZ(0);
$hardwareAcc: null;
// ----------------------------------------
/** Increased click area for this element, helpful on mobile */
@mixin IncreasedClickArea($size) {
&::after {
content: "";
position: absolute;
top: #{D(-$size)};
bottom: #{D(-$size)};
left: #{D(-$size)};
right: #{D(-$size)};
// background: rgba(255, 0, 0, 0.3);
}
}
button,
.increasedClickArea {
position: relative;
@include IncreasedClickArea(15px);
}
// ----------------------------------------
/* Duplicates an animation and adds two classes .<classPrefix>Even and .<classPrefix>Odd which uses the
animation. This can be used to replay the animation by toggling between the classes, because
it is not possible to restart a css animation */
@mixin MakeAnimationWrappedEvenOdd($duration, $classPrefix: "anim", $childSelector: "") {
$animName: autogen_anim_#{unique-id()};
@at-root {
@keyframes #{$animName}_even {
@content;
}
@keyframes #{$animName}_odd {
@content;
}
}
&.#{$classPrefix}Even #{$childSelector} {
animation: #{$animName}_even $duration;
}
&.#{$classPrefix}Odd #{$childSelector} {
animation: #{$animName}_odd $duration;
}
}
// ----------------------------------------
/* Allows to use and define an animation without specifying its name */
@mixin InlineAnimation($duration) {
$animName: autogen_anim_#{unique-id()};
@at-root {
@keyframes #{$animName} {
@content;
}
}
animation: $animName $duration !important;
}
// ----------------------------------------
/* Animation prefab for a double bounce pop-in animation, useful for dialogs */
@mixin DoubleBounceAnim($duration: 0.5s ease-in-out, $amount: 0.2, $initialOpacity: 0) {
@include InlineAnimation($duration) {
0% {
opacity: $initialOpacity;
transform: scale(0) $hardwareAcc;
}
25% {
opacity: 0.5;
transform: scale(1 + $amount) $hardwareAcc;
}
50% {
opacity: 1;
transform: scale(1 - $amount * 0.5) $hardwareAcc;
}
75% {
transform: scale(1 + $amount * 0.25) $hardwareAcc;
}
100% {
transform: scale(1) $hardwareAcc;
}
}
opacity: 1;
}
// ----------------------------------------
/* Define a style which is only applied in horizontal mode */
@mixin HorizontalStyle {
@include AppendGlobal(".h") {
@content;
}
}
// ----------------------------------------
/* Define a style which is only applied in vertical mode */
@mixin VerticalStyle {
@include AppendGlobal(".v") {
@content;
}
}
// ----------------------------------------
/* Define a style which is only while the hardware keyboard is open */
@mixin AndroidHwKeyboardOpen {
@include AppendGlobal(".kb") {
@content;
}
}
// ----------------------------------------
/* Automatically transforms the game state if a hardware keyboard is open */
@mixin TransformToMatchKeyboard {
transition: transform 0.2s ease-in-out;
@include AndroidHwKeyboardOpen {
@include VerticalStyle {
transform: translateY(#{D(-125px)}) $hardwareAcc;
}
@include HorizontalStyle {
transform: translateY(#{D(-100px)}) $hardwareAcc;
}
}
}
// ----------------------------------------
/* Define a style which is only applied when the viewport is at least X pixels wide */
@mixin StyleAtWidth($minW) {
@media (min-width: #{$minW}) {
@content;
}
}
// ----------------------------------------
/* Define a style which is only applied when the viewport is at least X pixels height */
@mixin StyleAtHeight($minH) {
@media (min-height: #{$minH}) {
@content;
}
}
// ----------------------------------------
/* Define a style which is only applied when the viewport has at least the given dimensions */
@mixin StyleAtDims($minW, $minH) {
@media (min-height: #{$minH}) and (min-width: #{$minW}) {
@content;
}
}
// ----------------------------------------
/* Define a style which is only applied when the viewport has at maximum the given dimensions */
@mixin StyleBelowDims($maxW, $maxH) {
@media (max-height: #{$maxH}) and (max-width: #{$maxW}) {
@content;
}
}
// ----------------------------------------
/* Define a style which is only applied when the viewport has at maximum the given height */
@mixin StyleBelowHeight($maxH) {
@media (max-height: #{$maxH}) {
@content;
}
}
// ----------------------------------------
/* Define a style which is only applied when the viewport has at maximum the given width */
@mixin StyleBelowWidth($maxW) {
@media (max-width: #{$maxW}) {
@content;
}
}
// ----------------------------------------
// Dynamic graphics quality styles
@mixin BoxShadow3D($bgColor, $size: 3px, $pressEffect: true) {
background-color: $bgColor;
$borderSize: 1.5px;
$borderColor: rgb(18, 20, 24);
// box-shadow: 0 0 0 D($borderSize) $borderColor, 0 D($size) 0 0px rgba(mix(darken($bgColor, 9), #b0e2ff, 95%), 1),
// 0 D($size) 0 D($borderSize) $borderColor;
// box-shadow: 0 0 0 D($borderSize) $borderColor, 0 D($size) 0 D($borderSize) $borderColor,
// D(-$size * 1.5) D($size * 2) 0 D($borderSize) rgba(0, 0, 0, 0.1);
// transition: box-shadow 0.1s ease-in-out;
// @if $pressEffect {
// &.pressed {
// transform: none !important;
// $pSize: max(0, $size - 1.5px);
// transition: none !important;
// box-shadow: 0 0 0 D($borderSize) $borderColor, 0 D($pSize) 0 0px rgba(mix(darken($bgColor, 9), #b0e2ff, 95%), 1),
// 0 D($pSize) 0 D($borderSize) $borderColor;
// top: D($size - $pSize);
// }
// }
}
@mixin BorderRadius($v1: 2px, $v2: "", $v3: "", $v4: "") {
@include S(border-radius, $v1, $v2, $v3, $v4);
}
@mixin BoxShadow($x, $y, $blur, $offset, $color) {
box-shadow: D($x) D($y) D($blur) D($offset) $color;
}
@mixin DropShadow($yOffset: 2px, $blur: 2px, $amount: 0.2) {
@include BoxShadow(0, $yOffset, $blur, 0, rgba(#000, $amount));
}
@mixin TextShadow($yOffset: 2px, $blur: 1px, $amount: 0.6) {
text-shadow: 0 D($yOffset) D($blur) rgba(#000, $amount);
}
@mixin Button3D($bgColor, $pressEffect: true) {
@include BoxShadow3D($bgColor, 2px, $pressEffect);
}
@mixin ButtonDisabled3D($bgColor) {
@include BoxShadow3D($bgColor, 0.5px, false);
}
@mixin BoxShadowInset($bgColor, $size: 3px) {
background-color: $bgColor;
$borderSize: 1px;
$borderColor: rgb(15, 19, 24);
box-shadow: 0 0 0 D($borderSize) $borderColor, 0 D($size) 0 rgba(#fff, 0.07);
border-top: D($size) solid rgba(#000, 0.1);
//, 0 D($size) 0 0px rgba(mix(darken($bgColor, 9), #b0e2ff, 95%), 1),
// 0 D($size + $borderSize) 0 0 $borderColor;
}
@mixin TextShadow3D($color: rgb(222, 234, 238), $borderColor: #000) {
color: $color;
}
// ----------------------------------------
/* String replacement */
@function str-replace($string, $search, $replace: "") {
$index: str-index($string, $search);
@if $index {
@return str-slice($string, 1, $index - 1) + $replace +
str-replace(str-slice($string, $index + str-length($search)), $search, $replace);
}
@return $string;
}
@mixin BounceInFromSide($mul, $duration: 0.18s ease-in-out) {
@include InlineAnimation($duration) {
0% {
transform: translateY(#{D(-100px * $mul)}) scale(0.9);
opacity: 0;
}
100% {
opacity: 1;
transform: none;
}
}
opacity: 1;
transform: none;
}
@mixin BreakText {
word-wrap: break-word;
word-break: break-all;
overflow-wrap: break-all;
}
@mixin SupportsAndroidNotchQuery {
@supports (color: constant(--notch-inset-left)) {
@content;
}
}
@mixin SupportsiOsNotchQuery {
@supports (color: env(safe-area-inset-left, 0px)) {
@content;
}
}
@mixin DarkThemeOverride {
@at-root html[data-theme="dark"] &,
&[data-theme="dark"] {
@content;
}
}
@mixin DarkThemeInvert {
@include DarkThemeOverride {
filter: invert(1);
}
}

View File

@ -1,17 +1,20 @@
$buildings: belt, cutter, miner, mixer, painter, rotater, balancer, stacker, trash, underground_belt, wire,
constant_signal, logic_gate, lever, filter, wire_tunnel, display, virtual_processor, reader;
constant_signal, logic_gate, lever, filter, wire_tunnel, display, virtual_processor, reader, storage;
@each $building in $buildings {
[data-icon="building_icons/#{$building}.png"] {
/* @load-async */
background-image: uiResource("res/ui/building_icons/#{$building}.png") !important;
}
}
$buildingsAndVariants: belt, balancer, balancer-merger, balancer-splitter, underground_belt,
underground_belt-tier2, miner, miner-chainable, cutter, cutter-quad, rotater, rotater-ccw, rotater-fl,
stacker, mixer, painter, painter-double, painter-quad, trash, trash-storage;
underground_belt-tier2, miner, miner-chainable, cutter, cutter-quad, rotater, rotater-ccw, stacker, mixer,
painter, painter-double, painter-quad, trash, storage, reader, rotater-rotate180, lever, display,
constant_signal;
@each $building in $buildingsAndVariants {
[data-icon="building_tutorials/#{$building}.png"] {
/* @load-async */
background-image: uiResource("res/ui/building_tutorials/#{$building}.png") !important;
}
}
@ -20,18 +23,26 @@ $buildingsAndVariants: belt, balancer, balancer-merger, balancer-splitter, under
// Special cases for mirrored vairants
[data-icon="building_tutorials/painter-mirrored.png"] {
/* @load-async */
background-image: uiResource("res/ui/building_tutorials/painter.png") !important;
}
[data-icon="building_tutorials/balancer-merger-inverse.png"] {
/* @load-async */
background-image: uiResource("res/ui/building_tutorials/balancer-merger.png") !important;
}
[data-icon="building_tutorials/balancer-splitter-inverse.png"] {
/* @load-async */
background-image: uiResource("res/ui/building_tutorials/balancer-splitter.png") !important;
}
[data-icon="building_tutorials/filter.png"] {
/* @load-async */
background-image: uiResource("res/ui/building_tutorials/lever.png") !important;
}
$icons: notification_saved, notification_success, notification_upgrade;
@each $icon in $icons {
[data-icon="icons/#{$icon}.png"] {
/* @load-async */
background-image: uiResource("res/ui/icons/#{$icon}.png") !important;
}
}
@ -41,6 +52,7 @@ $languages: en, de, cs, da, et, es-419, fr, it, pt-BR, sv, tr, el, ru, uk, zh-TW
@each $language in $languages {
[data-languageicon="#{$language}"] {
/* @load-async */
background-image: uiResource("languages/#{$language}.svg") !important;
}
}

View File

@ -35,10 +35,12 @@
background: transparent center center / 40% no-repeat;
opacity: 0.9;
&.editKeybinding {
/* @load-async */
background-image: uiResource("icons/edit_key.png");
}
&.resetKeybinding {
/* @load-async */
background-image: uiResource("icons/reset_key.png");
}

View File

@ -22,7 +22,10 @@
@include S(height, 25px);
pointer-events: all;
cursor: pointer;
background: uiResource("icons/main_menu_settings.png") center center / contain no-repeat;
& {
/* @load-async */
background: uiResource("icons/main_menu_settings.png") center center / contain no-repeat;
}
transition: opacity 0.12s ease-in-out;
@include IncreasedClickArea(2px);
opacity: 0.7;
@ -32,6 +35,7 @@
}
.exitAppButton {
/* @load-async */
background-image: uiResource("icons/main_menu_exit.png");
background-size: 90%;
}
@ -129,8 +133,10 @@
width: 100%;
@include S(height, 40px);
@include S(width, 180px);
background: #171a23 uiResource("get_on_steam.png") center center / contain no-repeat;
& {
/* @load-async */
background: #171a23 uiResource("get_on_steam.png") center center / contain no-repeat;
}
overflow: hidden;
display: block;
text-indent: -999em;
@ -167,7 +173,10 @@
@include S(margin, 10px, 0);
@include S(width, 100px);
@include S(height, 30px);
background: uiResource("demo_badge.png") center center / contain no-repeat;
& {
/* @load-async */
background: uiResource("demo_badge.png") center center / contain no-repeat;
}
display: inline-block;
}
@ -335,14 +344,26 @@
align-self: center;
justify-self: center;
@include IncreasedClickArea(0px);
background: #44484a uiResource("icons/play.png") center center / 40% no-repeat;
background: #44484a center center / 40% no-repeat;
}
button.resumeGame {
background-color: #44484a;
& {
/* @load-async */
background-image: uiResource("icons/play.png");
}
}
button.downloadGame {
grid-column: 3 / 4;
grid-row: 1 / 2;
background-color: transparent;
background-image: uiResource("icons/download.png");
& {
/* @load-async */
background-image: uiResource("icons/download.png");
}
@include S(width, 15px);
@include IncreasedClickArea(0px);
@include S(height, 15px);
@ -362,7 +383,11 @@
grid-row: 2 / 3;
background-color: transparent;
@include IncreasedClickArea(0px);
background-image: uiResource("icons/delete.png");
& {
/* @load-async */
background-image: uiResource("icons/delete.png");
}
@include S(width, 15px);
@include S(height, 15px);
align-self: end;
@ -379,7 +404,11 @@
button.renameGame {
background-color: transparent;
@include IncreasedClickArea(2px);
background-image: uiResource("icons/edit_key.png");
& {
/* @load-async */
background-image: uiResource("icons/edit_key.png");
}
@include S(width, 10px);
@include S(height, 10px);
align-self: center;
@ -445,7 +474,11 @@
grid-template-columns: 1fr auto;
justify-content: center;
background: $linkBg uiResource("icons/link.png") top D(3px) right D(3px) / D(9px) no-repeat;
& {
/* @load-async */
background: $linkBg uiResource("icons/link.png") top D(3px) right D(3px) / D(9px) no-repeat;
}
@include S(padding, 5px);
@include S(padding-left, 10px);
@include S(border-radius, $globalBorderRadius);
@ -472,9 +505,11 @@
@include S(height, 50px);
background: center center / 80% no-repeat;
&.githubLogo {
/* @load-async */
background-image: uiResource("main_menu/github.png");
}
&.discordLogo {
/* @load-async */
background-image: uiResource("main_menu/discord.png");
background-size: 95%;
}
@ -516,12 +551,15 @@
transition: background-color 0.12s ease-in-out;
&.redditLink {
/* @load-async */
background-image: uiResource("main_menu/reddit.svg");
}
&.changelog {
/* @load-async */
background-image: uiResource("main_menu/changelog.svg");
}
&.helpTranslate {
/* @load-async */
background-image: uiResource("main_menu/translate.svg");
}
}

View File

@ -1,48 +1,51 @@
#state_MobileWarningState {
display: flex;
align-items: center;
background: #333438 !important;
@include S(padding, 20px);
box-sizing: border-box;
justify-content: center;
flex-direction: column;
.logo {
width: 80%;
max-width: 200px;
margin-bottom: 10px;
}
p {
color: #aaacaf;
display: block;
margin-bottom: 13px;
font-size: 16px;
line-height: 20px;
max-width: 300px;
text-align: left;
a {
color: $colorBlueBright;
}
}
.standaloneLink {
width: 200px;
height: 80px;
min-height: 40px;
background: uiResource("get_on_steam.png") center center / contain no-repeat;
overflow: hidden;
display: block;
text-indent: -999em;
cursor: pointer;
margin-top: 10px;
pointer-events: all;
transition: all 0.12s ease-in;
transition-property: opacity, transform;
transform: skewX(-0.5deg);
&:hover {
transform: skewX(-1deg) scale(1.02);
opacity: 0.9;
}
}
}
#state_MobileWarningState {
display: flex;
align-items: center;
background: #333438 !important;
@include S(padding, 20px);
box-sizing: border-box;
justify-content: center;
flex-direction: column;
.logo {
width: 80%;
max-width: 200px;
margin-bottom: 10px;
}
p {
color: #aaacaf;
display: block;
margin-bottom: 13px;
font-size: 16px;
line-height: 20px;
max-width: 300px;
text-align: left;
a {
color: $colorBlueBright;
}
}
.standaloneLink {
width: 200px;
height: 80px;
min-height: 40px;
& {
/* @load-async */
background: uiResource("get_on_steam.png") center center / contain no-repeat;
}
overflow: hidden;
display: block;
text-indent: -999em;
cursor: pointer;
margin-top: 10px;
pointer-events: all;
transition: all 0.12s ease-in;
transition-property: opacity, transform;
transform: skewX(-0.5deg);
&:hover {
transform: skewX(-1deg) scale(1.02);
opacity: 0.9;
}
}
}

View File

@ -11,6 +11,7 @@
@include StyleBelowWidth($layoutBreak) {
grid-template-columns: 1fr;
grid-template-rows: auto 1fr;
}
.sidebar {
@ -159,8 +160,11 @@
@include S(padding, 4px);
@include S(padding-right, 15px);
background: #fff uiResource("icons/enum_selector.png") calc(100% - #{D(5px)})
calc(50% + #{D(1px)}) / #{D(15px)} no-repeat;
& {
/* @load-async */
background: #fff uiResource("icons/enum_selector.png") calc(100% - #{D(5px)})
calc(50% + #{D(1px)}) / #{D(15px)} no-repeat;
}
transition: background-color 0.12s ease-in-out;
&:hover {
@ -196,7 +200,11 @@
// dirty but works
// color: #222;
background-color: $darkModeControlsBackground;
background-image: uiResource("icons/enum_selector_white.png");
& {
/* @load-async */
background-image: uiResource("icons/enum_selector_white.png");
}
color: #ddd;
&:hover {
background-color: darken($darkModeControlsBackground, 2);

View File

@ -26,9 +26,11 @@
@include S(height, 30px);
@include S(margin-right, 10px);
@include S(margin-left, -5px);
background: uiResource("icons/state_back_button.png") center center / 70% no-repeat;
& {
/* @load-async */
background: uiResource("icons/state_back_button.png") center center / 70% no-repeat;
}
}
@include S(margin-bottom, 20px);
}

View File

@ -31,6 +31,7 @@ export const CHANGELOG = [
"Show mouse and camera tile on debug overlay (F4) (by dengr)",
"Fix belt planner placing the belt when a dialog opens in the meantime",
"Added confirmation when deleting a savegame",
"Make chained mainer the default and only option after unlocking it",
"Fixed tunnels entrances connecting to exits sometimes when they shouldn't",
"You can now pan the map with your mouse by moving the cursor to the edges of the screen!",
"Added setting to auto select the extractor when pipetting a resource patch (by Exund)",

View File

@ -65,13 +65,13 @@ export const globalConfig = {
buildingSpeeds: {
cutter: 1 / 4,
cutterQuad: 1 / 4,
cutterQuad: 1 / 3,
rotater: 1 / 1,
rotaterCCW: 1 / 1,
rotater180: 1 / 1,
painter: 1 / 6,
painterDouble: 1 / 8,
painterQuad: 1 / 8,
painterQuad: 1 / 2,
mixer: 1 / 5,
stacker: 1 / 6,
},

View File

@ -7,7 +7,7 @@ import { MetaBuilding, defaultBuildingVariant } from "../meta_building";
import { GameRoot } from "../root";
import { enumHubGoalRewards } from "../tutorial_goals";
import { T } from "../../translations";
import { formatItemsPerSecond } from "../../core/utils";
import { formatItemsPerSecond, generateMatrixRotations } from "../../core/utils";
import { BeltUnderlaysComponent } from "../components/belt_underlays";
/** @enum {string} */
@ -18,6 +18,14 @@ export const enumBalancerVariants = {
splitterInverse: "splitter-inverse",
};
const overlayMatrices = {
[defaultBuildingVariant]: null,
[enumBalancerVariants.merger]: generateMatrixRotations([0, 1, 0, 0, 1, 1, 0, 1, 0]),
[enumBalancerVariants.mergerInverse]: generateMatrixRotations([0, 1, 0, 1, 1, 0, 0, 1, 0]),
[enumBalancerVariants.splitter]: generateMatrixRotations([0, 1, 0, 0, 1, 1, 0, 1, 0]),
[enumBalancerVariants.splitterInverse]: generateMatrixRotations([0, 1, 0, 1, 1, 0, 0, 1, 0]),
};
export class MetaBalancerBuilding extends MetaBuilding {
constructor() {
super("balancer");
@ -37,18 +45,43 @@ export class MetaBalancerBuilding extends MetaBuilding {
}
}
/**
* @param {number} rotation
* @param {number} rotationVariant
* @param {string} variant
* @param {Entity} entity
* @returns {Array<number>|null}
*/
getSpecialOverlayRenderMatrix(rotation, rotationVariant, variant, entity) {
const matrix = overlayMatrices[variant];
if (matrix) {
return matrix[rotation];
}
return null;
}
/**
* @param {GameRoot} root
* @param {string} variant
* @returns {Array<[string, string]>}
*/
getAdditionalStatistics(root, variant) {
const speed = root.hubGoals.getProcessorBaseSpeed(enumItemProcessorTypes.balancer);
let speedMultiplier = 2;
switch (variant) {
case enumBalancerVariants.merger:
case enumBalancerVariants.mergerInverse:
case enumBalancerVariants.splitter:
case enumBalancerVariants.splitterInverse:
speedMultiplier = 1;
}
const speed =
(root.hubGoals.getProcessorBaseSpeed(enumItemProcessorTypes.balancer) / 2) * speedMultiplier;
return [[T.ingame.buildingPlacement.infoTexts.speed, formatItemsPerSecond(speed)]];
}
getSilhouetteColor() {
return "#444";
return "#555759";
}
/**

View File

@ -1,51 +1,51 @@
import { enumDirection, Vector } from "../../core/vector";
import { enumPinSlotType, WiredPinsComponent } from "../components/wired_pins";
import { Entity } from "../entity";
import { MetaBuilding } from "../meta_building";
import { GameRoot } from "../root";
import { DisplayComponent } from "../components/display";
export class MetaDisplayBuilding extends MetaBuilding {
constructor() {
super("display");
}
getSilhouetteColor() {
return "#aaaaaa";
}
/**
* @param {GameRoot} root
*/
getIsUnlocked(root) {
// @todo
return true;
}
getDimensions() {
return new Vector(1, 1);
}
getShowWiresLayerPreview() {
return true;
}
/**
* Creates the entity at the given location
* @param {Entity} entity
*/
setupEntityComponents(entity) {
entity.addComponent(
new WiredPinsComponent({
slots: [
{
pos: new Vector(0, 0),
direction: enumDirection.bottom,
type: enumPinSlotType.logicalAcceptor,
},
],
})
);
entity.addComponent(new DisplayComponent());
}
}
import { enumDirection, Vector } from "../../core/vector";
import { enumPinSlotType, WiredPinsComponent } from "../components/wired_pins";
import { Entity } from "../entity";
import { MetaBuilding } from "../meta_building";
import { GameRoot } from "../root";
import { DisplayComponent } from "../components/display";
import { enumHubGoalRewards } from "../tutorial_goals";
export class MetaDisplayBuilding extends MetaBuilding {
constructor() {
super("display");
}
getSilhouetteColor() {
return "#aaaaaa";
}
/**
* @param {GameRoot} root
*/
getIsUnlocked(root) {
return root.hubGoals.isRewardUnlocked(enumHubGoalRewards.reward_display);
}
getDimensions() {
return new Vector(1, 1);
}
getShowWiresLayerPreview() {
return true;
}
/**
* Creates the entity at the given location
* @param {Entity} entity
*/
setupEntityComponents(entity) {
entity.addComponent(
new WiredPinsComponent({
slots: [
{
pos: new Vector(0, 0),
direction: enumDirection.bottom,
type: enumPinSlotType.logicalAcceptor,
},
],
})
);
entity.addComponent(new DisplayComponent());
}
}

View File

@ -6,6 +6,7 @@ import { enumPinSlotType, WiredPinsComponent } from "../components/wired_pins";
import { Entity } from "../entity";
import { MetaBuilding } from "../meta_building";
import { GameRoot } from "../root";
import { enumHubGoalRewards } from "../tutorial_goals";
export class MetaFilterBuilding extends MetaBuilding {
constructor() {
@ -20,8 +21,7 @@ export class MetaFilterBuilding extends MetaBuilding {
* @param {GameRoot} root
*/
getIsUnlocked(root) {
// @todo
return true;
return root.hubGoals.isRewardUnlocked(enumHubGoalRewards.reward_wires_filters_and_levers);
}
getDimensions() {

View File

@ -4,6 +4,7 @@ import { Entity } from "../entity";
import { MetaBuilding } from "../meta_building";
import { GameRoot } from "../root";
import { LeverComponent } from "../components/lever";
import { enumHubGoalRewards } from "../tutorial_goals";
export class MetaLeverBuilding extends MetaBuilding {
constructor() {
@ -19,8 +20,7 @@ export class MetaLeverBuilding extends MetaBuilding {
* @param {GameRoot} root
*/
getIsUnlocked(root) {
// @todo
return true;
return root.hubGoals.isRewardUnlocked(enumHubGoalRewards.reward_wires_filters_and_levers);
}
getDimensions() {

View File

@ -1,78 +1,81 @@
import { enumDirection, Vector } from "../../core/vector";
import { ItemEjectorComponent } from "../components/item_ejector";
import { MinerComponent } from "../components/miner";
import { Entity } from "../entity";
import { MetaBuilding, defaultBuildingVariant } from "../meta_building";
import { GameRoot } from "../root";
import { enumHubGoalRewards } from "../tutorial_goals";
import { T } from "../../translations";
import { formatItemsPerSecond } from "../../core/utils";
/** @enum {string} */
export const enumMinerVariants = { chainable: "chainable" };
const overlayMatrix = [1, 1, 1, 1, 0, 1, 1, 1, 1];
export class MetaMinerBuilding extends MetaBuilding {
constructor() {
super("miner");
}
getSilhouetteColor() {
return "#b37dcd";
}
/**
* @param {GameRoot} root
* @param {string} variant
* @returns {Array<[string, string]>}
*/
getAdditionalStatistics(root, variant) {
const speed = root.hubGoals.getMinerBaseSpeed();
return [[T.ingame.buildingPlacement.infoTexts.speed, formatItemsPerSecond(speed)]];
}
/**
*
* @param {GameRoot} root
*/
getAvailableVariants(root) {
if (root.hubGoals.isRewardUnlocked(enumHubGoalRewards.reward_miner_chainable)) {
return [defaultBuildingVariant, enumMinerVariants.chainable];
}
return super.getAvailableVariants(root);
}
/**
* @param {number} rotation
* @param {number} rotationVariant
* @param {string} variant
* @param {Entity} entity
*/
getSpecialOverlayRenderMatrix(rotation, rotationVariant, variant, entity) {
return overlayMatrix;
}
/**
* Creates the entity at the given location
* @param {Entity} entity
*/
setupEntityComponents(entity) {
entity.addComponent(new MinerComponent({}));
entity.addComponent(
new ItemEjectorComponent({
slots: [{ pos: new Vector(0, 0), direction: enumDirection.top }],
})
);
}
/**
*
* @param {Entity} entity
* @param {number} rotationVariant
* @param {string} variant
*/
updateVariants(entity, rotationVariant, variant) {
entity.components.Miner.chainable = variant === enumMinerVariants.chainable;
}
}
import { enumDirection, Vector } from "../../core/vector";
import { ItemEjectorComponent } from "../components/item_ejector";
import { MinerComponent } from "../components/miner";
import { Entity } from "../entity";
import { MetaBuilding, defaultBuildingVariant } from "../meta_building";
import { GameRoot } from "../root";
import { enumHubGoalRewards } from "../tutorial_goals";
import { T } from "../../translations";
import { formatItemsPerSecond, generateMatrixRotations } from "../../core/utils";
/** @enum {string} */
export const enumMinerVariants = { chainable: "chainable" };
const overlayMatrix = {
[defaultBuildingVariant]: generateMatrixRotations([1, 1, 1, 1, 0, 1, 1, 1, 1]),
[enumMinerVariants.chainable]: generateMatrixRotations([0, 1, 0, 1, 1, 1, 1, 1, 1]),
};
export class MetaMinerBuilding extends MetaBuilding {
constructor() {
super("miner");
}
getSilhouetteColor() {
return "#b37dcd";
}
/**
* @param {GameRoot} root
* @param {string} variant
* @returns {Array<[string, string]>}
*/
getAdditionalStatistics(root, variant) {
const speed = root.hubGoals.getMinerBaseSpeed();
return [[T.ingame.buildingPlacement.infoTexts.speed, formatItemsPerSecond(speed)]];
}
/**
*
* @param {GameRoot} root
*/
getAvailableVariants(root) {
if (root.hubGoals.isRewardUnlocked(enumHubGoalRewards.reward_miner_chainable)) {
return [enumMinerVariants.chainable];
}
return super.getAvailableVariants(root);
}
/**
* @param {number} rotation
* @param {number} rotationVariant
* @param {string} variant
* @param {Entity} entity
*/
getSpecialOverlayRenderMatrix(rotation, rotationVariant, variant, entity) {
return overlayMatrix[variant][rotation];
}
/**
* Creates the entity at the given location
* @param {Entity} entity
*/
setupEntityComponents(entity) {
entity.addComponent(new MinerComponent({}));
entity.addComponent(
new ItemEjectorComponent({
slots: [{ pos: new Vector(0, 0), direction: enumDirection.top }],
})
);
}
/**
*
* @param {Entity} entity
* @param {number} rotationVariant
* @param {string} variant
*/
updateVariants(entity, rotationVariant, variant) {
entity.components.Miner.chainable = variant === enumMinerVariants.chainable;
}
}

View File

@ -8,6 +8,10 @@ import { MetaBuilding } from "../meta_building";
import { GameRoot } from "../root";
import { BeltUnderlaysComponent } from "../components/belt_underlays";
import { BeltReaderComponent } from "../components/belt_reader";
import { enumHubGoalRewards } from "../tutorial_goals";
import { generateMatrixRotations } from "../../core/utils";
const overlayMatrix = generateMatrixRotations([0, 1, 0, 0, 1, 0, 0, 1, 0]);
export class MetaReaderBuilding extends MetaBuilding {
constructor() {
@ -22,8 +26,7 @@ export class MetaReaderBuilding extends MetaBuilding {
* @param {GameRoot} root
*/
getIsUnlocked(root) {
// @todo
return true;
return root.hubGoals.isRewardUnlocked(enumHubGoalRewards.reward_belt_reader);
}
getDimensions() {
@ -34,6 +37,17 @@ export class MetaReaderBuilding extends MetaBuilding {
return true;
}
/**
* @param {number} rotation
* @param {number} rotationVariant
* @param {string} variant
* @param {Entity} entity
* @returns {Array<number>|null}
*/
getSpecialOverlayRenderMatrix(rotation, rotationVariant, variant, entity) {
return overlayMatrix[rotation];
}
/**
* Creates the entity at the given location
* @param {Entity} entity

View File

@ -1,4 +1,4 @@
import { formatItemsPerSecond } from "../../core/utils";
import { formatItemsPerSecond, generateMatrixRotations } from "../../core/utils";
import { enumDirection, Vector } from "../../core/vector";
import { T } from "../../translations";
import { ItemAcceptorComponent } from "../components/item_acceptor";
@ -12,6 +12,12 @@ import { enumHubGoalRewards } from "../tutorial_goals";
/** @enum {string} */
export const enumRotaterVariants = { ccw: "ccw", rotate180: "rotate180" };
const overlayMatrices = {
[defaultBuildingVariant]: generateMatrixRotations([0, 1, 1, 1, 1, 0, 0, 1, 1]),
[enumRotaterVariants.ccw]: generateMatrixRotations([1, 1, 0, 0, 1, 1, 1, 1, 0]),
[enumRotaterVariants.rotate180]: generateMatrixRotations([1, 1, 0, 1, 1, 1, 0, 1, 1]),
};
export class MetaRotaterBuilding extends MetaBuilding {
constructor() {
super("rotater");
@ -21,6 +27,21 @@ export class MetaRotaterBuilding extends MetaBuilding {
return "#7dc6cd";
}
/**
* @param {number} rotation
* @param {number} rotationVariant
* @param {string} variant
* @param {Entity} entity
* @returns {Array<number>|null}
*/
getSpecialOverlayRenderMatrix(rotation, rotationVariant, variant, entity) {
const matrix = overlayMatrices[variant];
if (matrix) {
return matrix[rotation];
}
return null;
}
/**
* @param {GameRoot} root
* @param {string} variant

View File

@ -0,0 +1,101 @@
import { formatBigNumber } from "../../core/utils";
import { enumDirection, Vector } from "../../core/vector";
import { T } from "../../translations";
import { ItemAcceptorComponent } from "../components/item_acceptor";
import { ItemEjectorComponent } from "../components/item_ejector";
import { StorageComponent } from "../components/storage";
import { enumPinSlotType, WiredPinsComponent } from "../components/wired_pins";
import { Entity } from "../entity";
import { MetaBuilding } from "../meta_building";
import { GameRoot } from "../root";
import { enumHubGoalRewards } from "../tutorial_goals";
const storageSize = 5000;
export class MetaStorageBuilding extends MetaBuilding {
constructor() {
super("storage");
}
getSilhouetteColor() {
return "#bbdf6d";
}
/**
* @returns {Array<[string, string]>}
*/
getAdditionalStatistics(root, variant) {
return [[T.ingame.buildingPlacement.infoTexts.storage, formatBigNumber(storageSize)]];
}
getDimensions() {
return new Vector(2, 2);
}
/**
* @param {GameRoot} root
*/
getIsUnlocked(root) {
return root.hubGoals.isRewardUnlocked(enumHubGoalRewards.reward_storage);
}
/**
* Creates the entity at the given location
* @param {Entity} entity
*/
setupEntityComponents(entity) {
// Required, since the item processor needs this.
entity.addComponent(
new ItemEjectorComponent({
slots: [
{
pos: new Vector(0, 0),
direction: enumDirection.top,
},
{
pos: new Vector(1, 0),
direction: enumDirection.top,
},
],
})
);
entity.addComponent(
new ItemAcceptorComponent({
slots: [
{
pos: new Vector(0, 1),
directions: [enumDirection.bottom],
},
{
pos: new Vector(1, 1),
directions: [enumDirection.bottom],
},
],
})
);
entity.addComponent(
new StorageComponent({
maximumStorage: storageSize,
})
);
entity.addComponent(
new WiredPinsComponent({
slots: [
{
pos: new Vector(1, 1),
direction: enumDirection.right,
type: enumPinSlotType.logicalEjector,
},
{
pos: new Vector(0, 1),
direction: enumDirection.left,
type: enumPinSlotType.logicalEjector,
},
],
})
);
}
}

View File

@ -1,65 +1,26 @@
import { formatBigNumber } from "../../core/utils";
import { enumDirection, Vector } from "../../core/vector";
import { T } from "../../translations";
import { ItemAcceptorComponent } from "../components/item_acceptor";
import { ItemEjectorComponent } from "../components/item_ejector";
import { enumItemProcessorTypes, ItemProcessorComponent } from "../components/item_processor";
import { StorageComponent } from "../components/storage";
import { enumPinSlotType, WiredPinsComponent } from "../components/wired_pins";
import { Entity } from "../entity";
import { defaultBuildingVariant, MetaBuilding } from "../meta_building";
import { MetaBuilding } from "../meta_building";
import { GameRoot } from "../root";
import { enumHubGoalRewards } from "../tutorial_goals";
/** @enum {string} */
export const enumTrashVariants = { storage: "storage" };
const trashSize = 5000;
export class MetaTrashBuilding extends MetaBuilding {
constructor() {
super("trash");
}
getIsRotateable(variant) {
return variant !== defaultBuildingVariant;
getIsRotateable() {
return false;
}
getSilhouetteColor() {
return "#cd7d86";
}
/**
* @param {GameRoot} root
* @param {string} variant
* @returns {Array<[string, string]>}
*/
getAdditionalStatistics(root, variant) {
if (variant === enumTrashVariants.storage) {
return [[T.ingame.buildingPlacement.infoTexts.storage, formatBigNumber(trashSize)]];
}
return [];
}
getDimensions(variant) {
switch (variant) {
case defaultBuildingVariant:
return new Vector(1, 1);
case enumTrashVariants.storage:
return new Vector(2, 2);
default:
assertAlways(false, "Unknown trash variant: " + variant);
}
}
/**
* @param {GameRoot} root
*/
getAvailableVariants(root) {
if (root.hubGoals.isRewardUnlocked(enumHubGoalRewards.reward_storage)) {
return [defaultBuildingVariant, enumTrashVariants.storage];
}
return super.getAvailableVariants(root);
getDimensions() {
return new Vector(1, 1);
}
/**
@ -74,13 +35,6 @@ export class MetaTrashBuilding extends MetaBuilding {
* @param {Entity} entity
*/
setupEntityComponents(entity) {
// Required, since the item processor needs this.
entity.addComponent(
new ItemEjectorComponent({
slots: [],
})
);
entity.addComponent(
new ItemAcceptorComponent({
slots: [
@ -96,99 +50,11 @@ export class MetaTrashBuilding extends MetaBuilding {
],
})
);
}
/**
*
* @param {Entity} entity
* @param {number} rotationVariant
* @param {string} variant
*/
updateVariants(entity, rotationVariant, variant) {
switch (variant) {
case defaultBuildingVariant: {
if (!entity.components.ItemProcessor) {
entity.addComponent(
new ItemProcessorComponent({
inputsPerCharge: 1,
processorType: enumItemProcessorTypes.trash,
})
);
}
if (entity.components.Storage) {
entity.removeComponent(StorageComponent);
}
if (entity.components.WiredPins) {
entity.removeComponent(WiredPinsComponent);
}
entity.components.ItemAcceptor.setSlots([
{
pos: new Vector(0, 0),
directions: [
enumDirection.top,
enumDirection.right,
enumDirection.bottom,
enumDirection.left,
],
},
]);
entity.components.ItemEjector.setSlots([]);
entity.components.ItemProcessor.type = enumItemProcessorTypes.trash;
break;
}
case enumTrashVariants.storage: {
if (entity.components.ItemProcessor) {
entity.removeComponent(ItemProcessorComponent);
}
if (!entity.components.Storage) {
entity.addComponent(new StorageComponent({}));
}
if (!entity.components.WiredPins) {
entity.addComponent(
new WiredPinsComponent({
slots: [
{
pos: new Vector(1, 1),
direction: enumDirection.right,
type: enumPinSlotType.logicalEjector,
},
{
pos: new Vector(0, 1),
direction: enumDirection.left,
type: enumPinSlotType.logicalEjector,
},
],
})
);
}
entity.components.Storage.maximumStorage = trashSize;
entity.components.ItemAcceptor.setSlots([
{
pos: new Vector(0, 1),
directions: [enumDirection.bottom],
},
{
pos: new Vector(1, 1),
directions: [enumDirection.bottom],
},
]);
entity.components.ItemEjector.setSlots([
{
pos: new Vector(0, 0),
direction: enumDirection.top,
},
{
pos: new Vector(1, 0),
direction: enumDirection.top,
},
]);
break;
}
default:
assertAlways(false, "Unknown trash variant: " + variant);
}
entity.addComponent(
new ItemProcessorComponent({
inputsPerCharge: 1,
processorType: enumItemProcessorTypes.trash,
})
);
}
}

View File

@ -1,266 +1,268 @@
import { Loader } from "../../core/loader";
import { enumDirection, Vector, enumAngleToDirection, enumDirectionToVector } from "../../core/vector";
import { ItemAcceptorComponent } from "../components/item_acceptor";
import { ItemEjectorComponent } from "../components/item_ejector";
import { enumUndergroundBeltMode, UndergroundBeltComponent } from "../components/underground_belt";
import { Entity } from "../entity";
import { MetaBuilding, defaultBuildingVariant } from "../meta_building";
import { GameRoot } from "../root";
import { globalConfig } from "../../core/config";
import { enumHubGoalRewards } from "../tutorial_goals";
import { formatItemsPerSecond, generateMatrixRotations } from "../../core/utils";
import { T } from "../../translations";
/** @enum {string} */
export const arrayUndergroundRotationVariantToMode = [
enumUndergroundBeltMode.sender,
enumUndergroundBeltMode.receiver,
];
/** @enum {string} */
export const enumUndergroundBeltVariants = { tier2: "tier2" };
export const enumUndergroundBeltVariantToTier = {
[defaultBuildingVariant]: 0,
[enumUndergroundBeltVariants.tier2]: 1,
};
const overlayMatrices = [
// Sender
generateMatrixRotations([1, 1, 1, 0, 1, 0, 0, 1, 0]),
// Receiver
generateMatrixRotations([0, 1, 0, 0, 1, 0, 1, 1, 1]),
];
export class MetaUndergroundBeltBuilding extends MetaBuilding {
constructor() {
super("underground_belt");
}
getSilhouetteColor() {
return "#222";
}
getFlipOrientationAfterPlacement() {
return true;
}
getStayInPlacementMode() {
return true;
}
/**
* @param {number} rotation
* @param {number} rotationVariant
* @param {string} variant
* @param {Entity} entity
*/
getSpecialOverlayRenderMatrix(rotation, rotationVariant, variant, entity) {
return overlayMatrices[rotationVariant][rotation];
}
/**
* @param {GameRoot} root
* @param {string} variant
* @returns {Array<[string, string]>}
*/
getAdditionalStatistics(root, variant) {
const rangeTiles =
globalConfig.undergroundBeltMaxTilesByTier[enumUndergroundBeltVariantToTier[variant]];
const beltSpeed = root.hubGoals.getUndergroundBeltBaseSpeed();
return [
[
T.ingame.buildingPlacement.infoTexts.range,
T.ingame.buildingPlacement.infoTexts.tiles.replace("<x>", "" + rangeTiles),
],
[T.ingame.buildingPlacement.infoTexts.speed, formatItemsPerSecond(beltSpeed)],
];
}
/**
* @param {GameRoot} root
*/
getAvailableVariants(root) {
if (root.hubGoals.isRewardUnlocked(enumHubGoalRewards.reward_underground_belt_tier_2)) {
return [defaultBuildingVariant, enumUndergroundBeltVariants.tier2];
}
return super.getAvailableVariants(root);
}
/**
* @param {number} rotationVariant
* @param {string} variant
*/
getPreviewSprite(rotationVariant, variant) {
let suffix = "";
if (variant !== defaultBuildingVariant) {
suffix = "-" + variant;
}
switch (arrayUndergroundRotationVariantToMode[rotationVariant]) {
case enumUndergroundBeltMode.sender:
return Loader.getSprite("sprites/buildings/underground_belt_entry" + suffix + ".png");
case enumUndergroundBeltMode.receiver:
return Loader.getSprite("sprites/buildings/underground_belt_exit" + suffix + ".png");
default:
assertAlways(false, "Invalid rotation variant");
}
}
/**
* @param {number} rotationVariant
* @param {string} variant
*/
getBlueprintSprite(rotationVariant, variant) {
let suffix = "";
if (variant !== defaultBuildingVariant) {
suffix = "-" + variant;
}
switch (arrayUndergroundRotationVariantToMode[rotationVariant]) {
case enumUndergroundBeltMode.sender:
return Loader.getSprite("sprites/blueprints/underground_belt_entry" + suffix + ".png");
case enumUndergroundBeltMode.receiver:
return Loader.getSprite("sprites/blueprints/underground_belt_exit" + suffix + ".png");
default:
assertAlways(false, "Invalid rotation variant");
}
}
/**
* @param {number} rotationVariant
* @param {string} variant
*/
getSprite(rotationVariant, variant) {
return this.getPreviewSprite(rotationVariant, variant);
}
/**
* @param {GameRoot} root
*/
getIsUnlocked(root) {
return root.hubGoals.isRewardUnlocked(enumHubGoalRewards.reward_tunnel);
}
/**
* Creates the entity at the given location
* @param {Entity} entity
*/
setupEntityComponents(entity) {
// Required, since the item processor needs this.
entity.addComponent(
new ItemEjectorComponent({
slots: [],
})
);
entity.addComponent(new UndergroundBeltComponent({}));
entity.addComponent(
new ItemAcceptorComponent({
slots: [],
})
);
}
/**
* Should compute the optimal rotation variant on the given tile
* @param {object} param0
* @param {GameRoot} param0.root
* @param {Vector} param0.tile
* @param {number} param0.rotation
* @param {string} param0.variant
* @param {Layer} param0.layer
* @return {{ rotation: number, rotationVariant: number, connectedEntities?: Array<Entity> }}
*/
computeOptimalDirectionAndRotationVariantAtTile({ root, tile, rotation, variant, layer }) {
const searchDirection = enumAngleToDirection[rotation];
const searchVector = enumDirectionToVector[searchDirection];
const tier = enumUndergroundBeltVariantToTier[variant];
const targetRotation = (rotation + 180) % 360;
const targetSenderRotation = rotation;
for (
let searchOffset = 1;
searchOffset <= globalConfig.undergroundBeltMaxTilesByTier[tier];
++searchOffset
) {
tile = tile.addScalars(searchVector.x, searchVector.y);
/* WIRES: FIXME */
const contents = root.map.getTileContent(tile, "regular");
if (contents) {
const undergroundComp = contents.components.UndergroundBelt;
if (undergroundComp && undergroundComp.tier === tier) {
const staticComp = contents.components.StaticMapEntity;
if (staticComp.rotation === targetRotation) {
if (undergroundComp.mode !== enumUndergroundBeltMode.sender) {
// If we encounter an underground receiver on our way which is also faced in our direction, we don't accept that
break;
}
return {
rotation: targetRotation,
rotationVariant: 1,
connectedEntities: [contents],
};
} else if (staticComp.rotation === targetSenderRotation) {
// Draw connections to receivers
if (undergroundComp.mode === enumUndergroundBeltMode.receiver) {
return {
rotation: rotation,
rotationVariant: 0,
connectedEntities: [contents],
};
} else {
break;
}
}
}
}
}
return {
rotation,
rotationVariant: 0,
};
}
/**
*
* @param {Entity} entity
* @param {number} rotationVariant
* @param {string} variant
*/
updateVariants(entity, rotationVariant, variant) {
entity.components.UndergroundBelt.tier = enumUndergroundBeltVariantToTier[variant];
switch (arrayUndergroundRotationVariantToMode[rotationVariant]) {
case enumUndergroundBeltMode.sender: {
entity.components.UndergroundBelt.mode = enumUndergroundBeltMode.sender;
entity.components.ItemEjector.setSlots([]);
entity.components.ItemAcceptor.setSlots([
{
pos: new Vector(0, 0),
directions: [enumDirection.bottom],
},
]);
return;
}
case enumUndergroundBeltMode.receiver: {
entity.components.UndergroundBelt.mode = enumUndergroundBeltMode.receiver;
entity.components.ItemAcceptor.setSlots([]);
entity.components.ItemEjector.setSlots([
{
pos: new Vector(0, 0),
direction: enumDirection.top,
},
]);
return;
}
default:
assertAlways(false, "Invalid rotation variant");
}
}
}
import { Loader } from "../../core/loader";
import { enumDirection, Vector, enumAngleToDirection, enumDirectionToVector } from "../../core/vector";
import { ItemAcceptorComponent } from "../components/item_acceptor";
import { ItemEjectorComponent } from "../components/item_ejector";
import { enumUndergroundBeltMode, UndergroundBeltComponent } from "../components/underground_belt";
import { Entity } from "../entity";
import { MetaBuilding, defaultBuildingVariant } from "../meta_building";
import { GameRoot } from "../root";
import { globalConfig } from "../../core/config";
import { enumHubGoalRewards } from "../tutorial_goals";
import { formatItemsPerSecond, generateMatrixRotations } from "../../core/utils";
import { T } from "../../translations";
/** @enum {string} */
export const arrayUndergroundRotationVariantToMode = [
enumUndergroundBeltMode.sender,
enumUndergroundBeltMode.receiver,
];
/** @enum {string} */
export const enumUndergroundBeltVariants = { tier2: "tier2" };
export const enumUndergroundBeltVariantToTier = {
[defaultBuildingVariant]: 0,
[enumUndergroundBeltVariants.tier2]: 1,
};
const colorsByRotationVariant = ["#6d9dff", "#9cad40"];
const overlayMatrices = [
// Sender
generateMatrixRotations([1, 1, 1, 0, 1, 0, 0, 1, 0]),
// Receiver
generateMatrixRotations([0, 1, 0, 0, 1, 0, 1, 1, 1]),
];
export class MetaUndergroundBeltBuilding extends MetaBuilding {
constructor() {
super("underground_belt");
}
getSilhouetteColor(variant, rotationVariant) {
return colorsByRotationVariant[rotationVariant];
}
getFlipOrientationAfterPlacement() {
return true;
}
getStayInPlacementMode() {
return true;
}
/**
* @param {number} rotation
* @param {number} rotationVariant
* @param {string} variant
* @param {Entity} entity
*/
getSpecialOverlayRenderMatrix(rotation, rotationVariant, variant, entity) {
return overlayMatrices[rotationVariant][rotation];
}
/**
* @param {GameRoot} root
* @param {string} variant
* @returns {Array<[string, string]>}
*/
getAdditionalStatistics(root, variant) {
const rangeTiles =
globalConfig.undergroundBeltMaxTilesByTier[enumUndergroundBeltVariantToTier[variant]];
const beltSpeed = root.hubGoals.getUndergroundBeltBaseSpeed();
return [
[
T.ingame.buildingPlacement.infoTexts.range,
T.ingame.buildingPlacement.infoTexts.tiles.replace("<x>", "" + rangeTiles),
],
[T.ingame.buildingPlacement.infoTexts.speed, formatItemsPerSecond(beltSpeed)],
];
}
/**
* @param {GameRoot} root
*/
getAvailableVariants(root) {
if (root.hubGoals.isRewardUnlocked(enumHubGoalRewards.reward_underground_belt_tier_2)) {
return [defaultBuildingVariant, enumUndergroundBeltVariants.tier2];
}
return super.getAvailableVariants(root);
}
/**
* @param {number} rotationVariant
* @param {string} variant
*/
getPreviewSprite(rotationVariant, variant) {
let suffix = "";
if (variant !== defaultBuildingVariant) {
suffix = "-" + variant;
}
switch (arrayUndergroundRotationVariantToMode[rotationVariant]) {
case enumUndergroundBeltMode.sender:
return Loader.getSprite("sprites/buildings/underground_belt_entry" + suffix + ".png");
case enumUndergroundBeltMode.receiver:
return Loader.getSprite("sprites/buildings/underground_belt_exit" + suffix + ".png");
default:
assertAlways(false, "Invalid rotation variant");
}
}
/**
* @param {number} rotationVariant
* @param {string} variant
*/
getBlueprintSprite(rotationVariant, variant) {
let suffix = "";
if (variant !== defaultBuildingVariant) {
suffix = "-" + variant;
}
switch (arrayUndergroundRotationVariantToMode[rotationVariant]) {
case enumUndergroundBeltMode.sender:
return Loader.getSprite("sprites/blueprints/underground_belt_entry" + suffix + ".png");
case enumUndergroundBeltMode.receiver:
return Loader.getSprite("sprites/blueprints/underground_belt_exit" + suffix + ".png");
default:
assertAlways(false, "Invalid rotation variant");
}
}
/**
* @param {number} rotationVariant
* @param {string} variant
*/
getSprite(rotationVariant, variant) {
return this.getPreviewSprite(rotationVariant, variant);
}
/**
* @param {GameRoot} root
*/
getIsUnlocked(root) {
return root.hubGoals.isRewardUnlocked(enumHubGoalRewards.reward_tunnel);
}
/**
* Creates the entity at the given location
* @param {Entity} entity
*/
setupEntityComponents(entity) {
// Required, since the item processor needs this.
entity.addComponent(
new ItemEjectorComponent({
slots: [],
})
);
entity.addComponent(new UndergroundBeltComponent({}));
entity.addComponent(
new ItemAcceptorComponent({
slots: [],
})
);
}
/**
* Should compute the optimal rotation variant on the given tile
* @param {object} param0
* @param {GameRoot} param0.root
* @param {Vector} param0.tile
* @param {number} param0.rotation
* @param {string} param0.variant
* @param {Layer} param0.layer
* @return {{ rotation: number, rotationVariant: number, connectedEntities?: Array<Entity> }}
*/
computeOptimalDirectionAndRotationVariantAtTile({ root, tile, rotation, variant, layer }) {
const searchDirection = enumAngleToDirection[rotation];
const searchVector = enumDirectionToVector[searchDirection];
const tier = enumUndergroundBeltVariantToTier[variant];
const targetRotation = (rotation + 180) % 360;
const targetSenderRotation = rotation;
for (
let searchOffset = 1;
searchOffset <= globalConfig.undergroundBeltMaxTilesByTier[tier];
++searchOffset
) {
tile = tile.addScalars(searchVector.x, searchVector.y);
/* WIRES: FIXME */
const contents = root.map.getTileContent(tile, "regular");
if (contents) {
const undergroundComp = contents.components.UndergroundBelt;
if (undergroundComp && undergroundComp.tier === tier) {
const staticComp = contents.components.StaticMapEntity;
if (staticComp.rotation === targetRotation) {
if (undergroundComp.mode !== enumUndergroundBeltMode.sender) {
// If we encounter an underground receiver on our way which is also faced in our direction, we don't accept that
break;
}
return {
rotation: targetRotation,
rotationVariant: 1,
connectedEntities: [contents],
};
} else if (staticComp.rotation === targetSenderRotation) {
// Draw connections to receivers
if (undergroundComp.mode === enumUndergroundBeltMode.receiver) {
return {
rotation: rotation,
rotationVariant: 0,
connectedEntities: [contents],
};
} else {
break;
}
}
}
}
}
return {
rotation,
rotationVariant: 0,
};
}
/**
*
* @param {Entity} entity
* @param {number} rotationVariant
* @param {string} variant
*/
updateVariants(entity, rotationVariant, variant) {
entity.components.UndergroundBelt.tier = enumUndergroundBeltVariantToTier[variant];
switch (arrayUndergroundRotationVariantToMode[rotationVariant]) {
case enumUndergroundBeltMode.sender: {
entity.components.UndergroundBelt.mode = enumUndergroundBeltMode.sender;
entity.components.ItemEjector.setSlots([]);
entity.components.ItemAcceptor.setSlots([
{
pos: new Vector(0, 0),
directions: [enumDirection.bottom],
},
]);
return;
}
case enumUndergroundBeltMode.receiver: {
entity.components.UndergroundBelt.mode = enumUndergroundBeltMode.receiver;
entity.components.ItemAcceptor.setSlots([]);
entity.components.ItemEjector.setSlots([
{
pos: new Vector(0, 0),
direction: enumDirection.top,
},
]);
return;
}
default:
assertAlways(false, "Invalid rotation variant");
}
}
}

View File

@ -212,7 +212,7 @@ export class HubGoals extends BasicSerializableObject {
this.currentGoal = {
/** @type {ShapeDefinition} */
definition: this.createRandomShape(),
required: findNiceIntegerValue(5000 + Math.pow(this.level * 2000, 0.75)),
required: findNiceIntegerValue(1000 + Math.pow(this.level * 2000, 0.8)),
reward: enumHubGoalRewards.no_reward_freeplay,
};
}

View File

@ -1,177 +1,217 @@
import { gMetaBuildingRegistry } from "../../../core/global_registries";
import { Signal, STOP_PROPAGATION } from "../../../core/signal";
import { makeDiv } from "../../../core/utils";
import { KEYMAPPINGS } from "../../key_action_mapper";
import { MetaBuilding } from "../../meta_building";
import { GameRoot } from "../../root";
import { BaseHUDPart } from "../base_hud_part";
import { DynamicDomAttach } from "../dynamic_dom_attach";
export class HUDBaseToolbar extends BaseHUDPart {
/**
* @param {GameRoot} root
* @param {object} param0
* @param {Array<typeof MetaBuilding>} param0.supportedBuildings
* @param {function} param0.visibilityCondition
* @param {string} param0.htmlElementId
*/
constructor(root, { supportedBuildings, visibilityCondition, htmlElementId }) {
super(root);
this.supportedBuildings = supportedBuildings;
this.visibilityCondition = visibilityCondition;
this.htmlElementId = htmlElementId;
/** @type {Object.<string, {
* metaBuilding: MetaBuilding,
* unlocked: boolean,
* selected: boolean,
* element: HTMLElement,
* index: number
* }>} */
this.buildingHandles = {};
}
/**
* Should create all require elements
* @param {HTMLElement} parent
*/
createElements(parent) {
this.element = makeDiv(parent, this.htmlElementId, ["ingame_buildingsToolbar"], "");
}
initialize() {
const actionMapper = this.root.keyMapper;
const items = makeDiv(this.element, null, ["buildings"]);
for (let i = 0; i < this.supportedBuildings.length; ++i) {
const metaBuilding = gMetaBuildingRegistry.findByClass(this.supportedBuildings[i]);
const binding = actionMapper.getBinding(KEYMAPPINGS.buildings[metaBuilding.getId()]);
const itemContainer = makeDiv(items, null, ["building"]);
itemContainer.setAttribute("data-icon", "building_icons/" + metaBuilding.getId() + ".png");
binding.add(() => this.selectBuildingForPlacement(metaBuilding));
this.trackClicks(itemContainer, () => this.selectBuildingForPlacement(metaBuilding), {
clickSound: null,
});
this.buildingHandles[metaBuilding.id] = {
metaBuilding,
element: itemContainer,
unlocked: false,
selected: false,
index: i,
};
}
this.root.hud.signals.selectedPlacementBuildingChanged.add(
this.onSelectedPlacementBuildingChanged,
this
);
this.domAttach = new DynamicDomAttach(this.root, this.element, {
timeToKeepSeconds: 0.12,
attachClass: "visible",
});
this.lastSelectedIndex = 0;
actionMapper.getBinding(KEYMAPPINGS.placement.cycleBuildings).add(this.cycleBuildings, this);
}
/**
* Updates the toolbar
*/
update() {
const visible = this.visibilityCondition();
this.domAttach.update(visible);
if (visible) {
for (const buildingId in this.buildingHandles) {
const handle = this.buildingHandles[buildingId];
const newStatus = handle.metaBuilding.getIsUnlocked(this.root);
if (handle.unlocked !== newStatus) {
handle.unlocked = newStatus;
handle.element.classList.toggle("unlocked", newStatus);
}
}
}
}
/**
* Cycles through all buildings
*/
cycleBuildings() {
const visible = this.visibilityCondition();
if (!visible) {
return;
}
let newBuildingFound = false;
let newIndex = this.lastSelectedIndex;
for (let i = 0; i < this.supportedBuildings.length; ++i, ++newIndex) {
newIndex %= this.supportedBuildings.length;
const metaBuilding = gMetaBuildingRegistry.findByClass(this.supportedBuildings[newIndex]);
const handle = this.buildingHandles[metaBuilding.id];
if (!handle.selected && handle.unlocked) {
newBuildingFound = true;
break;
}
}
if (!newBuildingFound) {
return;
}
const metaBuildingClass = this.supportedBuildings[newIndex];
const metaBuilding = gMetaBuildingRegistry.findByClass(metaBuildingClass);
this.selectBuildingForPlacement(metaBuilding);
}
/**
* Called when the selected building got changed
* @param {MetaBuilding} metaBuilding
*/
onSelectedPlacementBuildingChanged(metaBuilding) {
for (const buildingId in this.buildingHandles) {
const handle = this.buildingHandles[buildingId];
const newStatus = handle.metaBuilding === metaBuilding;
if (handle.selected !== newStatus) {
handle.selected = newStatus;
handle.element.classList.toggle("selected", newStatus);
}
if (handle.selected) {
this.lastSelectedIndex = handle.index;
}
}
this.element.classList.toggle("buildingSelected", !!metaBuilding);
}
/**
* @param {MetaBuilding} metaBuilding
*/
selectBuildingForPlacement(metaBuilding) {
if (!this.visibilityCondition()) {
// Not active
return;
}
if (!metaBuilding.getIsUnlocked(this.root)) {
this.root.soundProxy.playUiError();
return STOP_PROPAGATION;
}
// Allow clicking an item again to deselect it
for (const buildingId in this.buildingHandles) {
const handle = this.buildingHandles[buildingId];
if (handle.selected && handle.metaBuilding === metaBuilding) {
metaBuilding = null;
break;
}
}
this.root.soundProxy.playUiClick();
this.root.hud.signals.buildingSelectedForPlacement.dispatch(metaBuilding);
this.onSelectedPlacementBuildingChanged(metaBuilding);
}
}
import { gMetaBuildingRegistry } from "../../../core/global_registries";
import { Signal, STOP_PROPAGATION } from "../../../core/signal";
import { makeDiv } from "../../../core/utils";
import { KEYMAPPINGS } from "../../key_action_mapper";
import { MetaBuilding } from "../../meta_building";
import { GameRoot } from "../../root";
import { BaseHUDPart } from "../base_hud_part";
import { DynamicDomAttach } from "../dynamic_dom_attach";
export class HUDBaseToolbar extends BaseHUDPart {
/**
* @param {GameRoot} root
* @param {object} param0
* @param {Array<typeof MetaBuilding>} param0.primaryBuildings
* @param {Array<typeof MetaBuilding>=} param0.secondaryBuildings
* @param {function} param0.visibilityCondition
* @param {string} param0.htmlElementId
*/
constructor(root, { primaryBuildings, secondaryBuildings = [], visibilityCondition, htmlElementId }) {
super(root);
this.primaryBuildings = primaryBuildings;
this.secondaryBuildings = secondaryBuildings;
this.visibilityCondition = visibilityCondition;
this.htmlElementId = htmlElementId;
/** @type {Object.<string, {
* metaBuilding: MetaBuilding,
* unlocked: boolean,
* selected: boolean,
* element: HTMLElement,
* index: number
* }>} */
this.buildingHandles = {};
}
/**
* Should create all require elements
* @param {HTMLElement} parent
*/
createElements(parent) {
this.element = makeDiv(parent, this.htmlElementId, ["ingame_buildingsToolbar"], "");
}
/**
* Returns all buildings
* @returns {Array<typeof MetaBuilding>}
*/
get allBuildings() {
return [...this.primaryBuildings, ...this.secondaryBuildings];
}
initialize() {
const actionMapper = this.root.keyMapper;
let rowSecondary;
if (this.secondaryBuildings.length > 0) {
rowSecondary = makeDiv(this.element, null, ["buildings", "secondary"]);
this.secondaryDomAttach = new DynamicDomAttach(this.root, rowSecondary, {
attachClass: "visible",
});
}
const rowPrimary = makeDiv(this.element, null, ["buildings", "primary"]);
const allBuildings = this.allBuildings;
for (let i = 0; i < allBuildings.length; ++i) {
const metaBuilding = gMetaBuildingRegistry.findByClass(allBuildings[i]);
const binding = actionMapper.getBinding(KEYMAPPINGS.buildings[metaBuilding.getId()]);
const itemContainer = makeDiv(
this.primaryBuildings.includes(allBuildings[i]) ? rowPrimary : rowSecondary,
null,
["building"]
);
itemContainer.setAttribute("data-icon", "building_icons/" + metaBuilding.getId() + ".png");
itemContainer.setAttribute("data-id", metaBuilding.getId());
binding.add(() => this.selectBuildingForPlacement(metaBuilding));
this.trackClicks(itemContainer, () => this.selectBuildingForPlacement(metaBuilding), {
clickSound: null,
});
this.buildingHandles[metaBuilding.id] = {
metaBuilding,
element: itemContainer,
unlocked: false,
selected: false,
index: i,
};
}
this.root.hud.signals.selectedPlacementBuildingChanged.add(
this.onSelectedPlacementBuildingChanged,
this
);
this.domAttach = new DynamicDomAttach(this.root, this.element, {
timeToKeepSeconds: 0.12,
attachClass: "visible",
});
this.lastSelectedIndex = 0;
actionMapper.getBinding(KEYMAPPINGS.placement.cycleBuildings).add(this.cycleBuildings, this);
}
/**
* Updates the toolbar
*/
update() {
const visible = this.visibilityCondition();
this.domAttach.update(visible);
if (visible) {
let recomputeSecondaryToolbarVisibility = false;
for (const buildingId in this.buildingHandles) {
const handle = this.buildingHandles[buildingId];
const newStatus = handle.metaBuilding.getIsUnlocked(this.root);
if (handle.unlocked !== newStatus) {
handle.unlocked = newStatus;
handle.element.classList.toggle("unlocked", newStatus);
recomputeSecondaryToolbarVisibility = true;
}
}
if (recomputeSecondaryToolbarVisibility && this.secondaryDomAttach) {
let anyUnlocked = false;
for (let i = 0; i < this.secondaryBuildings.length; ++i) {
const metaClass = gMetaBuildingRegistry.findByClass(this.secondaryBuildings[i]);
if (metaClass.getIsUnlocked(this.root)) {
anyUnlocked = true;
break;
}
}
this.secondaryDomAttach.update(anyUnlocked);
}
}
}
/**
* Cycles through all buildings
*/
cycleBuildings() {
const visible = this.visibilityCondition();
if (!visible) {
return;
}
let newBuildingFound = false;
let newIndex = this.lastSelectedIndex;
for (let i = 0; i < this.primaryBuildings.length; ++i, ++newIndex) {
newIndex %= this.primaryBuildings.length;
const metaBuilding = gMetaBuildingRegistry.findByClass(this.primaryBuildings[newIndex]);
const handle = this.buildingHandles[metaBuilding.id];
if (!handle.selected && handle.unlocked) {
newBuildingFound = true;
break;
}
}
if (!newBuildingFound) {
return;
}
const metaBuildingClass = this.primaryBuildings[newIndex];
const metaBuilding = gMetaBuildingRegistry.findByClass(metaBuildingClass);
this.selectBuildingForPlacement(metaBuilding);
}
/**
* Called when the selected building got changed
* @param {MetaBuilding} metaBuilding
*/
onSelectedPlacementBuildingChanged(metaBuilding) {
for (const buildingId in this.buildingHandles) {
const handle = this.buildingHandles[buildingId];
const newStatus = handle.metaBuilding === metaBuilding;
if (handle.selected !== newStatus) {
handle.selected = newStatus;
handle.element.classList.toggle("selected", newStatus);
}
if (handle.selected) {
this.lastSelectedIndex = handle.index;
}
}
this.element.classList.toggle("buildingSelected", !!metaBuilding);
}
/**
* @param {MetaBuilding} metaBuilding
*/
selectBuildingForPlacement(metaBuilding) {
if (!this.visibilityCondition()) {
// Not active
return;
}
if (!metaBuilding.getIsUnlocked(this.root)) {
this.root.soundProxy.playUiError();
return STOP_PROPAGATION;
}
// Allow clicking an item again to deselect it
for (const buildingId in this.buildingHandles) {
const handle = this.buildingHandles[buildingId];
if (handle.selected && handle.metaBuilding === metaBuilding) {
metaBuilding = null;
break;
}
}
this.root.soundProxy.playUiClick();
this.root.hud.signals.buildingSelectedForPlacement.dispatch(metaBuilding);
this.onSelectedPlacementBuildingChanged(metaBuilding);
}
}

View File

@ -121,6 +121,7 @@ export class HUDBuildingPlacerLogic extends BaseHUDPart {
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.storyGoalCompleted.add(() => this.currentMetaBuilding.set(null));
this.root.signals.upgradePurchased.add(() => this.signals.variantChanged.dispatch());
this.root.signals.editModeChanged.add(this.onEditModeChanged, this);
@ -457,11 +458,11 @@ export class HUDBuildingPlacerLogic extends BaseHUDPart {
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
);
let index = availableVariants.indexOf(this.currentVariant.get());
if (index < 0) {
index = 0;
console.warn("Invalid variant selected:", this.currentVariant.get());
}
const newIndex = (index + 1) % availableVariants.length;
const newVariant = availableVariants[newIndex];
this.setVariant(newVariant);
@ -595,7 +596,17 @@ export class HUDBuildingPlacerLogic extends BaseHUDPart {
this.abortDragging();
this.root.hud.signals.selectedPlacementBuildingChanged.dispatch(metaBuilding);
if (metaBuilding) {
const variant = this.preferredVariants[metaBuilding.getId()] || defaultBuildingVariant;
const availableVariants = metaBuilding.getAvailableVariants(this.root);
const preferredVariant = this.preferredVariants[metaBuilding.getId()];
// Choose last stored variant if possible, otherwise the default one
let variant;
if (!preferredVariant || !availableVariants.includes(preferredVariant)) {
variant = availableVariants[0];
} else {
variant = preferredVariant;
}
this.currentVariant.set(variant);
this.fakeEntity = new Entity(null);

View File

@ -13,28 +13,30 @@ import { MetaStackerBuilding } from "../../buildings/stacker";
import { MetaTrashBuilding } from "../../buildings/trash";
import { MetaUndergroundBeltBuilding } from "../../buildings/underground_belt";
import { HUDBaseToolbar } from "./base_toolbar";
const supportedBuildings = [
MetaBeltBuilding,
MetaBalancerBuilding,
MetaUndergroundBeltBuilding,
MetaMinerBuilding,
MetaCutterBuilding,
MetaRotaterBuilding,
MetaStackerBuilding,
MetaMixerBuilding,
MetaPainterBuilding,
MetaTrashBuilding,
MetaLeverBuilding,
MetaFilterBuilding,
MetaDisplayBuilding,
MetaReaderBuilding,
];
import { MetaStorageBuilding } from "../../buildings/storage";
export class HUDBuildingsToolbar extends HUDBaseToolbar {
constructor(root) {
super(root, {
supportedBuildings,
primaryBuildings: [
MetaBeltBuilding,
MetaBalancerBuilding,
MetaUndergroundBeltBuilding,
MetaMinerBuilding,
MetaCutterBuilding,
MetaRotaterBuilding,
MetaStackerBuilding,
MetaMixerBuilding,
MetaPainterBuilding,
MetaTrashBuilding,
],
secondaryBuildings: [
MetaStorageBuilding,
MetaLeverBuilding,
MetaFilterBuilding,
MetaDisplayBuilding,
MetaReaderBuilding,
],
visibilityCondition: () =>
!this.root.camera.getIsMapOverlayActive() && this.root.currentLayer === "regular",
htmlElementId: "ingame_HUD_buildings_toolbar",

View File

@ -7,6 +7,7 @@ import {
KEYCODE_RMB,
KEYMAPPINGS,
} from "../../key_action_mapper";
import { enumHubGoalRewards } from "../../tutorial_goals";
import { BaseHUDPart } from "../base_hud_part";
import { DynamicDomAttach } from "../dynamic_dom_attach";
@ -257,7 +258,8 @@ export class HUDKeybindingOverlay extends BaseHUDPart {
// Switch layers
label: T.ingame.keybindingsOverlay.switchLayers,
keys: [k.ingame.switchLayers],
condition: () => true,
condition: () =>
this.root.hubGoals.isRewardUnlocked(enumHubGoalRewards.reward_wires_filters_and_levers),
},
];

View File

@ -319,9 +319,7 @@ export class HUDWaypoints extends BaseHUDPart {
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),
zoomLevel: this.root.camera.zoomLevel,
});
this.sortWaypoints();

View File

@ -6,19 +6,17 @@ import { MetaLeverBuilding } from "../../buildings/lever";
import { MetaWireTunnelBuilding } from "../../buildings/wire_tunnel";
import { MetaVirtualProcessorBuilding } from "../../buildings/virtual_processor";
const supportedBuildings = [
MetaWireBuilding,
MetaWireTunnelBuilding,
MetaConstantSignalBuilding,
MetaLogicGateBuilding,
MetaLeverBuilding,
MetaVirtualProcessorBuilding,
];
export class HUDWiresToolbar extends HUDBaseToolbar {
constructor(root) {
super(root, {
supportedBuildings,
primaryBuildings: [
MetaWireBuilding,
MetaWireTunnelBuilding,
MetaConstantSignalBuilding,
MetaLogicGateBuilding,
MetaLeverBuilding,
MetaVirtualProcessorBuilding,
],
visibilityCondition: () =>
!this.root.camera.getIsMapOverlayActive() && this.root.currentLayer === "wires",
htmlElementId: "ingame_HUD_wires_toolbar",

View File

@ -54,6 +54,7 @@ export const KEYMAPPINGS = {
mixer: { keyCode: key("8") },
painter: { keyCode: key("9") },
trash: { keyCode: key("0") },
storage: { keyCode: key("I") },
lever: { keyCode: key("L") },
filter: { keyCode: key("B") },
@ -352,6 +353,13 @@ export class KeyActionMapper {
}
this.keybindings[key] = new Keybinding(this, this.root.app, payload);
if (G_IS_DEV) {
// Sanity
if (!T.keybindings.mappings[key]) {
assertAlways(false, "Keybinding " + key + " has no translation!");
}
}
}
}

View File

@ -170,7 +170,10 @@ export class MapChunkView extends MapChunk {
);
}
context.fillStyle = metaBuilding.getSilhouetteColor();
context.fillStyle = metaBuilding.getSilhouetteColor(
data.variant,
data.rotationVariant
);
for (let dx = 0; dx < 3; ++dx) {
for (let dy = 0; dy < 3; ++dy) {
const isFilled = overlayMatrix[dx + dy * 3];
@ -187,7 +190,10 @@ export class MapChunkView extends MapChunk {
continue;
} else {
context.fillStyle = metaBuilding.getSilhouetteColor();
context.fillStyle = metaBuilding.getSilhouetteColor(
data.variant,
data.rotationVariant
);
context.fillRect(
x * CHUNK_OVERLAY_RES,
y * CHUNK_OVERLAY_RES,
@ -256,7 +262,8 @@ export class MapChunkView extends MapChunk {
data.variant,
entity
);
context.fillStyle = overrideColor || metaBuilding.getSilhouetteColor();
context.fillStyle =
overrideColor || metaBuilding.getSilhouetteColor(data.variant, data.rotationVariant);
if (overlayMatrix) {
for (let dx = 0; dx < 3; ++dx) {
for (let dy = 0; dy < 3; ++dy) {

View File

@ -1,273 +1,275 @@
import { Loader } from "../core/loader";
import { AtlasSprite } from "../core/sprites";
import { Vector } from "../core/vector";
import { SOUNDS } from "../platform/sound";
import { StaticMapEntityComponent } from "./components/static_map_entity";
import { Entity } from "./entity";
import { GameRoot } from "./root";
import { getCodeFromBuildingData } from "./building_codes";
export const defaultBuildingVariant = "default";
export class MetaBuilding {
/**
*
* @param {string} id Building id
*/
constructor(id) {
this.id = id;
}
/**
* Returns the id of this building
*/
getId() {
return this.id;
}
/**
* Returns the edit layer of the building
* @returns {Layer}
*/
getLayer() {
return "regular";
}
/**
* Should return the dimensions of the building
*/
getDimensions(variant = defaultBuildingVariant) {
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
*/
getStayInPlacementMode() {
return false;
}
/**
* Can return a special interlaved 9 elements overlay matrix for rendering
* @param {number} rotation
* @param {number} rotationVariant
* @param {string} variant
* @param {Entity} entity
* @returns {Array<number>|null}
*/
getSpecialOverlayRenderMatrix(rotation, rotationVariant, variant, entity) {
return null;
}
/**
* Should return additional statistics about this building
* @param {GameRoot} root
* @param {string} variant
* @returns {Array<[string, string]>}
*/
getAdditionalStatistics(root, variant) {
return [];
}
/**
* Returns whether this building can get replaced
*/
getIsReplaceable() {
return false;
}
/**
* Whether to flip the orientation after a building has been placed - useful
* for tunnels.
*/
getFlipOrientationAfterPlacement() {
return false;
}
/**
* Whether to show a preview of the wires layer when placing the building
*/
getShowWiresLayerPreview() {
return false;
}
/**
* Whether to rotate automatically in the dragging direction while placing
* @param {string} variant
*/
getRotateAutomaticallyWhilePlacing(variant) {
return false;
}
/**
* Returns whether this building is removable
* @returns {boolean}
*/
getIsRemovable() {
return true;
}
/**
* Returns the placement sound
* @returns {string}
*/
getPlacementSound() {
return SOUNDS.placeBuilding;
}
/**
* @param {GameRoot} root
*/
getAvailableVariants(root) {
return [defaultBuildingVariant];
}
/**
* Returns a preview sprite
* @returns {AtlasSprite}
*/
getPreviewSprite(rotationVariant = 0, variant = defaultBuildingVariant) {
return Loader.getSprite(
"sprites/buildings/" +
this.id +
(variant === defaultBuildingVariant ? "" : "-" + variant) +
".png"
);
}
/**
* Returns a sprite for blueprints
* @returns {AtlasSprite}
*/
getBlueprintSprite(rotationVariant = 0, variant = defaultBuildingVariant) {
return Loader.getSprite(
"sprites/blueprints/" +
this.id +
(variant === defaultBuildingVariant ? "" : "-" + variant) +
".png"
);
}
/**
* Returns whether this building is rotateable
* @param {string} variant
* @returns {boolean}
*/
getIsRotateable(variant) {
return true;
}
/**
* Returns whether this building is unlocked for the given game
* @param {GameRoot} root
*/
getIsUnlocked(root) {
return true;
}
/**
* Should return a silhouette color for the map overview or null if not set
*/
getSilhouetteColor() {
return null;
}
/**
* Should return false if the pins are already included in the sprite of the building
* @returns {boolean}
*/
getRenderPins() {
return true;
}
/**
* 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);
entity.layer = this.getLayer();
entity.addComponent(
new StaticMapEntityComponent({
origin: new Vector(origin.x, origin.y),
rotation,
originalRotation,
tileSize: this.getDimensions(variant).copy(),
code: getCodeFromBuildingData(this, variant, rotationVariant),
})
);
this.setupEntityComponents(entity, root);
this.updateVariants(entity, rotationVariant, variant);
return entity;
}
/**
* Returns the sprite for a given variant
* @param {number} rotationVariant
* @param {string} variant
* @returns {AtlasSprite}
*/
getSprite(rotationVariant, variant) {
return Loader.getSprite(
"sprites/buildings/" +
this.id +
(variant === defaultBuildingVariant ? "" : "-" + variant) +
".png"
);
}
/**
* Should compute the optimal rotation variant on the given tile
* @param {object} param0
* @param {GameRoot} param0.root
* @param {Vector} param0.tile
* @param {number} param0.rotation
* @param {string} param0.variant
* @param {Layer} param0.layer
* @return {{ rotation: number, rotationVariant: number, connectedEntities?: Array<Entity> }}
*/
computeOptimalDirectionAndRotationVariantAtTile({ root, tile, rotation, variant, layer }) {
if (!this.getIsRotateable(variant)) {
return {
rotation: 0,
rotationVariant: 0,
};
}
return {
rotation,
rotationVariant: 0,
};
}
/**
* Should update the entity to match the given variants
* @param {Entity} entity
* @param {number} rotationVariant
* @param {string} variant
*/
updateVariants(entity, rotationVariant, variant) {}
// PRIVATE INTERFACE
/**
* Should setup the entity components
* @param {Entity} entity
* @param {GameRoot} root
*/
setupEntityComponents(entity, root) {
abstract;
}
}
import { Loader } from "../core/loader";
import { AtlasSprite } from "../core/sprites";
import { Vector } from "../core/vector";
import { SOUNDS } from "../platform/sound";
import { StaticMapEntityComponent } from "./components/static_map_entity";
import { Entity } from "./entity";
import { GameRoot } from "./root";
import { getCodeFromBuildingData } from "./building_codes";
export const defaultBuildingVariant = "default";
export class MetaBuilding {
/**
*
* @param {string} id Building id
*/
constructor(id) {
this.id = id;
}
/**
* Returns the id of this building
*/
getId() {
return this.id;
}
/**
* Returns the edit layer of the building
* @returns {Layer}
*/
getLayer() {
return "regular";
}
/**
* Should return the dimensions of the building
*/
getDimensions(variant = defaultBuildingVariant) {
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
*/
getStayInPlacementMode() {
return false;
}
/**
* Can return a special interlaved 9 elements overlay matrix for rendering
* @param {number} rotation
* @param {number} rotationVariant
* @param {string} variant
* @param {Entity} entity
* @returns {Array<number>|null}
*/
getSpecialOverlayRenderMatrix(rotation, rotationVariant, variant, entity) {
return null;
}
/**
* Should return additional statistics about this building
* @param {GameRoot} root
* @param {string} variant
* @returns {Array<[string, string]>}
*/
getAdditionalStatistics(root, variant) {
return [];
}
/**
* Returns whether this building can get replaced
*/
getIsReplaceable() {
return false;
}
/**
* Whether to flip the orientation after a building has been placed - useful
* for tunnels.
*/
getFlipOrientationAfterPlacement() {
return false;
}
/**
* Whether to show a preview of the wires layer when placing the building
*/
getShowWiresLayerPreview() {
return false;
}
/**
* Whether to rotate automatically in the dragging direction while placing
* @param {string} variant
*/
getRotateAutomaticallyWhilePlacing(variant) {
return false;
}
/**
* Returns whether this building is removable
* @returns {boolean}
*/
getIsRemovable() {
return true;
}
/**
* Returns the placement sound
* @returns {string}
*/
getPlacementSound() {
return SOUNDS.placeBuilding;
}
/**
* @param {GameRoot} root
*/
getAvailableVariants(root) {
return [defaultBuildingVariant];
}
/**
* Returns a preview sprite
* @returns {AtlasSprite}
*/
getPreviewSprite(rotationVariant = 0, variant = defaultBuildingVariant) {
return Loader.getSprite(
"sprites/buildings/" +
this.id +
(variant === defaultBuildingVariant ? "" : "-" + variant) +
".png"
);
}
/**
* Returns a sprite for blueprints
* @returns {AtlasSprite}
*/
getBlueprintSprite(rotationVariant = 0, variant = defaultBuildingVariant) {
return Loader.getSprite(
"sprites/blueprints/" +
this.id +
(variant === defaultBuildingVariant ? "" : "-" + variant) +
".png"
);
}
/**
* Returns whether this building is rotateable
* @param {string} variant
* @returns {boolean}
*/
getIsRotateable(variant) {
return true;
}
/**
* Returns whether this building is unlocked for the given game
* @param {GameRoot} root
*/
getIsUnlocked(root) {
return true;
}
/**
* Should return a silhouette color for the map overview or null if not set
* @param {string} variant
* @param {number} rotationVariant
*/
getSilhouetteColor(variant, rotationVariant) {
return null;
}
/**
* Should return false if the pins are already included in the sprite of the building
* @returns {boolean}
*/
getRenderPins() {
return true;
}
/**
* 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);
entity.layer = this.getLayer();
entity.addComponent(
new StaticMapEntityComponent({
origin: new Vector(origin.x, origin.y),
rotation,
originalRotation,
tileSize: this.getDimensions(variant).copy(),
code: getCodeFromBuildingData(this, variant, rotationVariant),
})
);
this.setupEntityComponents(entity, root);
this.updateVariants(entity, rotationVariant, variant);
return entity;
}
/**
* Returns the sprite for a given variant
* @param {number} rotationVariant
* @param {string} variant
* @returns {AtlasSprite}
*/
getSprite(rotationVariant, variant) {
return Loader.getSprite(
"sprites/buildings/" +
this.id +
(variant === defaultBuildingVariant ? "" : "-" + variant) +
".png"
);
}
/**
* Should compute the optimal rotation variant on the given tile
* @param {object} param0
* @param {GameRoot} param0.root
* @param {Vector} param0.tile
* @param {number} param0.rotation
* @param {string} param0.variant
* @param {Layer} param0.layer
* @return {{ rotation: number, rotationVariant: number, connectedEntities?: Array<Entity> }}
*/
computeOptimalDirectionAndRotationVariantAtTile({ root, tile, rotation, variant, layer }) {
if (!this.getIsRotateable(variant)) {
return {
rotation: 0,
rotationVariant: 0,
};
}
return {
rotation,
rotationVariant: 0,
};
}
/**
* Should update the entity to match the given variants
* @param {Entity} entity
* @param {number} rotationVariant
* @param {string} variant
*/
updateVariants(entity, rotationVariant, variant) {}
// PRIVATE INTERFACE
/**
* Should setup the entity components
* @param {Entity} entity
* @param {GameRoot} root
*/
setupEntityComponents(entity, root) {
abstract;
}
}

View File

@ -9,7 +9,7 @@ import { enumPainterVariants, MetaPainterBuilding } from "./buildings/painter";
import { enumRotaterVariants, MetaRotaterBuilding } from "./buildings/rotater";
import { enumBalancerVariants, MetaBalancerBuilding } from "./buildings/balancer";
import { MetaStackerBuilding } from "./buildings/stacker";
import { enumTrashVariants, MetaTrashBuilding } from "./buildings/trash";
import { MetaTrashBuilding } from "./buildings/trash";
import { enumUndergroundBeltVariants, MetaUndergroundBeltBuilding } from "./buildings/underground_belt";
import { MetaWireBuilding } from "./buildings/wire";
import { buildBuildingCodeCache, gBuildingVariants, registerBuildingVariant } from "./building_codes";
@ -22,6 +22,9 @@ import { MetaWireTunnelBuilding, enumWireTunnelVariants } from "./buildings/wire
import { MetaDisplayBuilding } from "./buildings/display";
import { MetaVirtualProcessorBuilding, enumVirtualProcessorVariants } from "./buildings/virtual_processor";
import { MetaReaderBuilding } from "./buildings/reader";
import { MetaStorageBuilding } from "./buildings/storage";
import { KEYMAPPINGS } from "./key_action_mapper";
import { T } from "../translations";
const logger = createLogger("building_registry");
@ -34,6 +37,7 @@ export function initMetaBuildingRegistry() {
gMetaBuildingRegistry.register(MetaMixerBuilding);
gMetaBuildingRegistry.register(MetaPainterBuilding);
gMetaBuildingRegistry.register(MetaTrashBuilding);
gMetaBuildingRegistry.register(MetaStorageBuilding);
gMetaBuildingRegistry.register(MetaBeltBuilding);
gMetaBuildingRegistry.register(MetaUndergroundBeltBuilding);
gMetaBuildingRegistry.register(MetaHubBuilding);
@ -86,7 +90,9 @@ export function initMetaBuildingRegistry() {
// Trash
registerBuildingVariant(20, MetaTrashBuilding);
registerBuildingVariant(21, MetaTrashBuilding, enumTrashVariants.storage);
// Storage
registerBuildingVariant(21, MetaStorageBuilding);
// Underground belt
registerBuildingVariant(22, MetaUndergroundBeltBuilding, defaultBuildingVariant, 0);
@ -157,6 +163,29 @@ export function initMetaBuildingRegistry() {
}
}
// Check for valid keycodes
if (G_IS_DEV) {
gMetaBuildingRegistry.entries.forEach(metaBuilding => {
const id = metaBuilding.getId();
if (!["hub"].includes(id)) {
if (!KEYMAPPINGS.buildings[id]) {
assertAlways(
false,
"Building " + id + " has no keybinding assigned! Add it to key_action_mapper.js"
);
}
if (!T.buildings[id]) {
assertAlways(false, "Translation for building " + id + " missing!");
}
if (!T.buildings[id].default) {
assertAlways(false, "Translation for building " + id + " missing (default variant)!");
}
}
});
}
logger.log("Registered", gMetaBuildingRegistry.getNumEntries(), "buildings");
logger.log("Registered", Object.keys(gBuildingVariants).length, "building codes");
}
@ -174,7 +203,10 @@ export function initBuildingCodesAfterResourcesLoaded() {
variant.rotationVariant,
variant.variant
);
variant.silhouetteColor = variant.metaInstance.getSilhouetteColor();
variant.silhouetteColor = variant.metaInstance.getSilhouetteColor(
variant.variant,
variant.rotationVariant
);
}
// Update caches

View File

@ -94,6 +94,8 @@ export class ItemProcessorSystem extends GameSystemWithFilter {
for (let j = 0; j < itemsToEject.length; ++j) {
const { item, requiredSlot, preferredSlot } = itemsToEject[j];
assert(ejectorComp, "To eject items, the building needs to have an ejector");
let slot = null;
if (requiredSlot !== null && requiredSlot !== undefined) {
// We have a slot override, check if that is free
@ -306,6 +308,10 @@ export class ItemProcessorSystem extends GameSystemWithFilter {
* @param {ProcessorImplementationPayload} payload
*/
process_BALANCER(payload) {
assert(
payload.entity.components.ItemEjector,
"To be a balancer, the building needs to have an ejector"
);
const availableSlots = payload.entity.components.ItemEjector.slots.length;
const processorComp = payload.entity.components.ItemProcessor;

View File

@ -5,7 +5,6 @@ import { BaseItem } from "../base_item";
import { MinerComponent } from "../components/miner";
import { Entity } from "../entity";
import { GameSystemWithFilter } from "../game_system_with_filter";
import { statisticsUnitsSeconds } from "../hud/parts/statistics_handle";
import { MapChunkView } from "../map_chunk_view";
export class MinerSystem extends GameSystemWithFilter {

View File

@ -18,12 +18,19 @@ export const enumHubGoalRewards = {
reward_rotater_180: "reward_rotater_180",
reward_miner_chainable: "reward_miner_chainable",
reward_underground_belt_tier_2: "reward_underground_belt_tier_2",
reward_belt_reader: "reward_belt_reader",
reward_splitter: "reward_splitter",
reward_cutter_quad: "reward_cutter_quad",
reward_painter_double: "reward_painter_double",
reward_painter_quad: "reward_painter_quad",
reward_storage: "reward_storage",
reward_merger: "reward_merger",
reward_wires_filters_and_levers: "reward_wires_filters_and_levers",
reward_display: "reward_display",
reward_constant_signal: "reward_constant_signal",
reward_logic_gates: "reward_logic_gates",
reward_virtual_processing: "reward_virtual_processing",
reward_second_wire: "reward_second_wire",
reward_blueprints: "reward_blueprints",
reward_freeplay: "reward_freeplay",
@ -99,11 +106,11 @@ export const tutorialGoals = [
{
shape: "CpCpCpCp", // belts t3
required: 800,
reward: enumHubGoalRewards.reward_splitter,
reward: enumHubGoalRewards.reward_merger,
},
// 10
// Star shape + cyan
// STACKER: Star shape + cyan
{
shape: "ScScScSc", // miners t3
required: 900,
@ -111,7 +118,7 @@ export const tutorialGoals = [
},
// 11
// Stacker
// Chainable miner
{
shape: "CgScScCg", // processors t3
required: 1000,
@ -127,6 +134,7 @@ export const tutorialGoals = [
},
// 13
// Tunnel Tier 2
{
shape: "RpRpRpRp:CwCwCwCw", // painting t3
required: 5000,
@ -134,44 +142,121 @@ export const tutorialGoals = [
},
// 14
// Belt reader
{
// @todo
shape: "CuCuCuCu",
required: 7000,
reward: enumHubGoalRewards.reward_belt_reader,
},
// 15
// Storage
{
shape: "SrSrSrSr:CyCyCyCy", // unused
required: 7500,
reward: enumHubGoalRewards.reward_storage,
},
// 15
// 16
// Quad Cutter
{
shape: "SrSrSrSr:CyCyCyCy:SwSwSwSw", // belts t4 (two variants)
required: 15000,
required: 12500,
reward: enumHubGoalRewards.reward_cutter_quad,
},
// 16
// 17
// Double painter
{
shape: "CbRbRbCb:CwCwCwCw:WbWbWbWb", // miner t4 (two variants)
required: 20000,
required: 15000,
reward: enumHubGoalRewards.reward_painter_double,
},
// 17
// 18
// Rotater (180deg)
{
shape: "CbRbRbCb:CwCwCwCw:WbWbWbWb", // rotater 180
required: 25000,
// @TODO
shape: "CuCuCuCu",
required: 20000,
reward: enumHubGoalRewards.reward_rotater_180,
},
// 18
// 19
// Compact splitter
{
shape: "WrRgWrRg:CwCrCwCr:SgSgSgSg", // processors t4 (two variants)
required: 30000,
reward: enumHubGoalRewards.reward_painter_quad,
// @TODO
shape: "CuCuCuCu",
required: 25000,
reward: enumHubGoalRewards.reward_splitter,
},
// 19
// 20
// WIRES
{
shape: finalGameShape,
required: 50000,
reward: enumHubGoalRewards.reward_wires_filters_and_levers,
},
// 21
// Display
{
// @TODO
shape: "CuCuCuCu",
required: 25000,
reward: enumHubGoalRewards.reward_display,
},
// 22
// Constant signal
{
// @TODO
shape: "CuCuCuCu",
required: 30000,
reward: enumHubGoalRewards.reward_constant_signal,
},
// 23
// Quad Painter
{
// @TODO
shape: "CuCuCuCu",
// shape: "WrRgWrRg:CwCrCwCr:SgSgSgSg", // processors t4 (two variants)
required: 35000,
reward: enumHubGoalRewards.reward_painter_quad,
},
// 24 Logic gates
{
// @TODO
shape: "CuCuCuCu",
required: 40000,
reward: enumHubGoalRewards.reward_logic_gates,
},
// 25 Virtual Processing
{
// @TODO
shape: "CuCuCuCu",
required: 45000,
reward: enumHubGoalRewards.reward_virtual_processing,
},
// 26 Secondary type of wire
{
// @TODO
shape: "CuCuCuCu",
required: 50000,
reward: enumHubGoalRewards.reward_second_wire,
},
// 27 Freeplay
{
// @TODO
shape: "CuCuCuCu",
required: 100000,
reward: enumHubGoalRewards.reward_freeplay,
},
];

View File

@ -1,16 +1,19 @@
import { MetaBuilding, defaultBuildingVariant } from "./meta_building";
import { MetaCutterBuilding, enumCutterVariants } from "./buildings/cutter";
import { MetaRotaterBuilding, enumRotaterVariants } from "./buildings/rotater";
import { MetaPainterBuilding, enumPainterVariants } from "./buildings/painter";
import { T } from "../translations";
import { enumBalancerVariants, MetaBalancerBuilding } from "./buildings/balancer";
import { MetaConstantSignalBuilding } from "./buildings/constant_signal";
import { enumCutterVariants, MetaCutterBuilding } from "./buildings/cutter";
import { MetaDisplayBuilding } from "./buildings/display";
import { MetaLeverBuilding } from "./buildings/lever";
import { enumMinerVariants, MetaMinerBuilding } from "./buildings/miner";
import { MetaMixerBuilding } from "./buildings/mixer";
import { enumPainterVariants, MetaPainterBuilding } from "./buildings/painter";
import { MetaReaderBuilding } from "./buildings/reader";
import { enumRotaterVariants, MetaRotaterBuilding } from "./buildings/rotater";
import { MetaStackerBuilding } from "./buildings/stacker";
import { MetaBalancerBuilding, enumBalancerVariants } from "./buildings/balancer";
import { MetaUndergroundBeltBuilding, enumUndergroundBeltVariants } from "./buildings/underground_belt";
import { MetaMinerBuilding, enumMinerVariants } from "./buildings/miner";
import { MetaTrashBuilding, enumTrashVariants } from "./buildings/trash";
import { MetaStorageBuilding } from "./buildings/storage";
import { enumUndergroundBeltVariants, MetaUndergroundBeltBuilding } from "./buildings/underground_belt";
import { defaultBuildingVariant, MetaBuilding } from "./meta_building";
/** @typedef {Array<[typeof MetaBuilding, string]>} TutorialGoalReward */
import { enumHubGoalRewards } from "./tutorial_goals";
/**
@ -43,9 +46,41 @@ export const enumHubGoalRewardsToContentUnlocked = {
[enumHubGoalRewards.reward_cutter_quad]: typed([[MetaCutterBuilding, enumCutterVariants.quad]]),
[enumHubGoalRewards.reward_painter_double]: typed([[MetaPainterBuilding, enumPainterVariants.double]]),
[enumHubGoalRewards.reward_painter_quad]: typed([[MetaPainterBuilding, enumPainterVariants.quad]]),
[enumHubGoalRewards.reward_storage]: typed([[MetaTrashBuilding, enumTrashVariants.storage]]),
[enumHubGoalRewards.reward_storage]: typed([[MetaStorageBuilding, defaultBuildingVariant]]),
[enumHubGoalRewards.reward_belt_reader]: typed([[MetaReaderBuilding, defaultBuildingVariant]]),
[enumHubGoalRewards.reward_display]: typed([[MetaDisplayBuilding, defaultBuildingVariant]]),
[enumHubGoalRewards.reward_constant_signal]: typed([
[MetaConstantSignalBuilding, defaultBuildingVariant],
]),
[enumHubGoalRewards.reward_second_wire]: null, // @TODO!
[enumHubGoalRewards.reward_logic_gates]: null, // @TODO!
[enumHubGoalRewards.reward_virtual_processing]: null, // @TODO!
[enumHubGoalRewards.reward_wires_filters_and_levers]: typed([
[MetaLeverBuilding, defaultBuildingVariant],
]),
[enumHubGoalRewards.reward_freeplay]: null,
[enumHubGoalRewards.reward_blueprints]: null,
[enumHubGoalRewards.no_reward]: null,
[enumHubGoalRewards.no_reward_freeplay]: null,
};
if (G_IS_DEV) {
// Sanity check
for (const rewardId in enumHubGoalRewards) {
const mapping = enumHubGoalRewardsToContentUnlocked[rewardId];
if (typeof mapping === "undefined") {
assertAlways(
false,
"Please define a mapping for the reward " + rewardId + " in tutorial_goals_mappings.js"
);
}
const translation = T.storyRewards[rewardId];
if (!translation || !translation.title || !translation.desc) {
assertAlways(false, "Translation for reward " + rewardId + "missing");
}
}
}

View File

@ -38,7 +38,7 @@ export const UPGRADES = {
required: [{ shape: "SrSrSrSr:CyCyCyCy:SwSwSwSw", amount: 20000 }],
},
{
required: [{ shape: finalGameShape, amount: 75000 }],
required: [{ shape: finalGameShape, amount: 50000 }],
excludePrevious: true,
},
],
@ -60,7 +60,7 @@ export const UPGRADES = {
required: [{ shape: "CbRbRbCb:CwCwCwCw:WbWbWbWb", amount: 30000 }],
},
{
required: [{ shape: finalGameShape, amount: 85000 }],
required: [{ shape: finalGameShape, amount: 65000 }],
excludePrevious: true,
},
],
@ -82,7 +82,7 @@ export const UPGRADES = {
required: [{ shape: "WrRgWrRg:CwCrCwCr:SgSgSgSg", amount: 30000 }],
},
{
required: [{ shape: finalGameShape, amount: 100000 }],
required: [{ shape: finalGameShape, amount: 75000 }],
excludePrevious: true,
},
],
@ -104,7 +104,7 @@ export const UPGRADES = {
required: [{ shape: "WpWpWpWp:CwCwCwCw:WpWpWpWp:CwCwCwCw", amount: 30000 }],
},
{
required: [{ shape: finalGameShape, amount: 125000 }],
required: [{ shape: finalGameShape, amount: 100000 }],
excludePrevious: true,
},
],

View File

@ -1,5 +1,6 @@
import { gMetaBuildingRegistry } from "../../core/global_registries.js";
import { createLogger } from "../../core/logging.js";
import { enumBalancerVariants, MetaBalancerBuilding } from "../../game/buildings/balancer.js";
import { MetaBeltBuilding } from "../../game/buildings/belt.js";
import { enumCutterVariants, MetaCutterBuilding } from "../../game/buildings/cutter.js";
import { MetaHubBuilding } from "../../game/buildings/hub.js";
@ -7,9 +8,9 @@ import { enumMinerVariants, MetaMinerBuilding } from "../../game/buildings/miner
import { MetaMixerBuilding } from "../../game/buildings/mixer.js";
import { enumPainterVariants, MetaPainterBuilding } from "../../game/buildings/painter.js";
import { enumRotaterVariants, MetaRotaterBuilding } from "../../game/buildings/rotater.js";
import { enumBalancerVariants, MetaBalancerBuilding } from "../../game/buildings/balancer.js";
import { MetaStackerBuilding } from "../../game/buildings/stacker.js";
import { enumTrashVariants, MetaTrashBuilding } from "../../game/buildings/trash.js";
import { MetaStorageBuilding } from "../../game/buildings/storage.js";
import { MetaTrashBuilding } from "../../game/buildings/trash.js";
import {
enumUndergroundBeltVariants,
MetaUndergroundBeltBuilding,
@ -126,9 +127,11 @@ export class SavegameInterface_V1006 extends SavegameInterface_V1005 {
),
"sprites/blueprints/painter-quad.png": findCode(MetaPainterBuilding, enumPainterVariants.quad),
// Trash / Storage
// Trash
"sprites/blueprints/trash.png": findCode(MetaTrashBuilding),
"sprites/blueprints/trash-storage.png": findCode(MetaTrashBuilding, enumTrashVariants.storage),
// Storage
"sprites/blueprints/trash-storage.png": findCode(MetaStorageBuilding),
};
}

View File

@ -557,9 +557,10 @@ buildings:
name: &trash Trash
description: Accepts inputs from all sides and destroys them. Forever.
storage:
name: Storage
description: Stores excess items, up to a given capacity. Can be used as an overflow gate.
storage:
default:
name: &storage Storage
description: Stores excess items, up to a given capacity. Prioritizes the left output and can be used as an overflow gate.
wire:
default:
@ -578,12 +579,12 @@ buildings:
constant_signal:
default:
name: &constant_signal Constant Signal
description: Emits a constant signal (shape, color or boolean).
description: Emits a constant signal, which can be either a shape, color or boolean.
lever:
default:
name: &lever Switch
description: Can be toggled to emit 1 / 0
description: Can be toggled to emit a boolean signal, which can then be used to control for example an item filter.
logic_gate:
default:
@ -606,20 +607,17 @@ buildings:
filter:
default:
name: &filter Filter
# TEMP
description: Only allows through items which match exactly the provided shape / color. If you put in a boolean 1, it allows everything through, if you put in a 0 it will allow nothing through.
description: Connect with a signal to route all matching items to the top and the remaining to the right. Can be controlled with boolean signals too.
display:
default:
name: &display Display
# TEMP
description: Can be connected on the wires layer to show a color or shape. When inputting a boolean item, the display will be white if the value is 1.
description: Connect a signal to show it on the display - It can be a shape, color or boolean.
reader:
default:
name: &reader Belt Reader
# TEMP
description: Allows to read the current item from a belt, as well as measuring the throughput.
description: Allows to measure belt throughput. Outputs the last read item on the wires layer (once unlocked).
virtual_processor:
default:
@ -670,8 +668,8 @@ storyRewards:
desc: The <strong>mixer</strong> has been unlocked - Combine two colors using <strong>additive blending</strong> with this building!
reward_stacker:
title: Combiner
desc: You can now combine shapes with the <strong>combiner</strong>! Both inputs are combined, and if they can be put next to each other, they will be <strong>fused</strong>. If not, the right input is <strong>stacked on top</strong> of the left input!
title: Stacker
desc: You can now combine shapes with the <strong>stacker</strong>! Both inputs are combined, and if they can be put next to each other, they will be <strong>fused</strong>. If not, the right input is <strong>stacked on top</strong> of the left input!
reward_balancer:
title: Balancer
@ -687,7 +685,9 @@ storyRewards:
reward_miner_chainable:
title: Chaining Extractor
desc: You have unlocked the <strong>chaining extractor</strong>! It can <strong>forward its resources</strong> to other extractors so you can more efficiently extract resources!
desc: >-
You have unlocked the <strong>chained extractor</strong>! It can <strong>forward its resources</strong> to other extractors so you can more efficiently extract resources!<br><br>
PS: The old extractor has been replaced in your toolbar now!
reward_underground_belt_tier_2:
title: Tunnel Tier II
@ -701,10 +701,15 @@ storyRewards:
reward_splitter:
title: Compact Splitter
desc: >-
You have unlocked a merger variant of the <strong>balancer</strong> - It accepts one input and splits them into two!
You have unlocked a splitter variant of the <strong>balancer</strong> - It accepts one input and splits them into two!
reward_belt_reader:
title: Belt reader
desc: >-
You have now unlocked the <strong>belt reader</strong>! It allows you to measure the throughput of a belt.<br><br>And wait until you unlock wires - then it gets really useful!
reward_cutter_quad:
title: Quad Cutting
title: Quad Cutter
desc: You have unlocked a variant of the <strong>cutter</strong> - It allows you to cut shapes in <strong>four parts</strong> instead of just two!
reward_painter_double:
@ -713,15 +718,15 @@ storyRewards:
reward_painter_quad:
title: Quad Painting
desc: You have unlocked a variant of the <strong>painter</strong> - It allows you to paint each part of the shape individually!
desc: >-
You have unlocked a variant of the <strong>painter</strong> - It allows you to paint each part of the shape individually!<br><br>
To use it, connect each slot which should be painted on the wires layer!
reward_storage:
title: Storage Buffer
desc: You have unlocked a variant of the <strong>trash</strong> - It allows you to store items up to a given capacity!
reward_freeplay:
title: Freeplay
desc: You did it! You unlocked the <strong>free-play mode</strong>! This means that shapes are now randomly generated! (No worries, more content is planned for the standalone!)
desc: >-
You have unlocked the <strong>storage</strong> building - It allows you to store items up to a given capacity!<br><br>
It priorities the left output, so you can also use it as an <strong>overflow gate</strong>!
reward_blueprints:
title: Blueprints
@ -731,6 +736,45 @@ storyRewards:
title: Rotater (180 degrees)
desc: You just unlocked the 180 degress <strong>rotater</strong>! - It allows you to rotate a shape by 180 degress (Surprise! :D)
reward_wires_filters_and_levers:
title: >-
Wires: Filters & Levers
desc: >-
You just unlocked the <strong>wires layer</strong>! It is a separate layer on top of the regular layer and introduces a lot of new mechanics!<br><br>
Since it can be overwhelming a bit, I added a small tutorial - Be sure to have <strong>tutorials enabled</strong> in the settings!
reward_display:
title: Display
desc: >-
You have unlocked the <strong>Display</strong>! Connect a wires signal to it to present a color, shape or boolean!
reward_constant_signal:
title: Constant Signal
desc: >-
You can now emit a <strong>constant signal</strong> on the wires layer! This is useful to connect it to <strong>item filters</strong> for example!
reward_logic_gates:
title: Logic Gates
desc: >-
You unlocked <strong>logic gates</strong>! You don't have to be excited about this, but it's actually super cool!<br><br>
With those gates you can now perform AND, OR, XOR and NOT boolean operations!
reward_virtual_processing:
title: Virtual Processing
desc: >-
I just gave a whole bunch of new buildings which allow you to <strong>simulate the processing of shapes</strong>!<br><br>
You can now simulate a cutter, rotater, stacker and more on the wires layer!<br><br>
With this you now have three options to continue the game:<br><br>
- Build an <strong>automated machine</strong> to create any possible shape requested by the hub (This is cool, I swear!).<br><br>
- Build something cool with wires.<br><br>
- Continue to play regulary.
reward_second_wire:
title: Second Wire Type
desc: >-
Annoyed by wires automatically connecting? I just gave you another <strong>type of wire</strong>!<br><br>
Different types of wires do not connect to each other, so you can now build much compacter circuits.
# Special reward, which is shown when there is no reward actually
no_reward:
title: Next level
@ -742,6 +786,12 @@ storyRewards:
desc: >-
Congratulations! By the way, more content is planned for the standalone!
reward_freeplay:
title: Freeplay
desc: >-
You did it! You unlocked the <strong>free-play mode</strong>! This means that shapes are now <strong>randomly</strong> generated!<br><br>
Since the hub will only require low quantities, I highly recommend to build a machine which automatically delivers the requested shape!
settings:
title: Settings
categories:
@ -980,6 +1030,7 @@ keybindings:
mixer: *mixer
painter: *painter
trash: *trash
storage: *storage
wire: *wire
constant_signal: *constant_signal
logic_gate: *logic_gate
@ -988,6 +1039,7 @@ keybindings:
wire_tunnel: *wire_tunnel
display: *display
reader: *reader
virtual_processor: *virtual_processor
# ---
pipette: Pipette
@ -1082,10 +1134,11 @@ tips:
- Use <b>CTRL</b> + Click to select an area.
- Building too close to the hub can get in the way of later projects.
- The pin icon next to each shape in the upgrade list pins it to the screen.
- Mix all primary colours together to make white!
- Mix all primary colors together to make white!
- You have an infinite map, don't cramp your factory, expand!
- Also try Factorio! It's my favourite game.
- Also try Factorio! It's my favorite game.
- The quad cutter cuts clockwise starting from the top right!
- You can download your savegames in the main menu!
- This game has a lot of useful keybindings! Be sure to check out the settings page.
- This game has a lot of settings, be sure to check them out!
- The marker to your hub has a small compass to indicate its direction!