mirror of
https://github.com/tobspr/shapez.io.git
synced 2025-06-13 13:04:03 +00:00
Merge branch 'GeoZ' into component-editor
This commit is contained in:
commit
94f32ad226
@ -163,7 +163,7 @@ function serve({ standalone }) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Watch .scss files, those trigger a css rebuild
|
// Watch .scss files, those trigger a css rebuild
|
||||||
gulp.watch(["../src/**/*.scss"], gulp.series("css.dev"));
|
gulp.watch(["../src/**/*.scss"], { usePolling: true }, gulp.series("css.dev"));
|
||||||
|
|
||||||
// Watch .html files, those trigger a html rebuild
|
// Watch .html files, those trigger a html rebuild
|
||||||
gulp.watch("../src/**/*.html", gulp.series(standalone ? "html.standalone-dev" : "html.dev"));
|
gulp.watch("../src/**/*.html", gulp.series(standalone ? "html.standalone-dev" : "html.dev"));
|
||||||
@ -172,7 +172,7 @@ function serve({ standalone }) {
|
|||||||
// gulp.watch(["../res_raw/sounds/**/*.mp3", "../res_raw/sounds/**/*.wav"], gulp.series("sounds.dev"));
|
// gulp.watch(["../res_raw/sounds/**/*.mp3", "../res_raw/sounds/**/*.wav"], gulp.series("sounds.dev"));
|
||||||
|
|
||||||
// Watch translations
|
// Watch translations
|
||||||
gulp.watch("../translations/**/*.yaml", gulp.series("translations.convertToJson"));
|
gulp.watch("../translations/**/*.yaml", { usePolling: true }, gulp.series("translations.convertToJson"));
|
||||||
|
|
||||||
gulp.watch(
|
gulp.watch(
|
||||||
["../res_raw/sounds/sfx/*.mp3", "../res_raw/sounds/sfx/*.wav"],
|
["../res_raw/sounds/sfx/*.mp3", "../res_raw/sounds/sfx/*.wav"],
|
||||||
|
@ -14,6 +14,9 @@ module.exports = ({ watch = false, standalone = false }) => {
|
|||||||
"bundle.js": [path.resolve(__dirname, "../src/js/main.js")],
|
"bundle.js": [path.resolve(__dirname, "../src/js/main.js")],
|
||||||
},
|
},
|
||||||
watch,
|
watch,
|
||||||
|
watchOptions: {
|
||||||
|
poll: 1000
|
||||||
|
},
|
||||||
node: {
|
node: {
|
||||||
fs: "empty",
|
fs: "empty",
|
||||||
},
|
},
|
||||||
|
@ -1,5 +1,12 @@
|
|||||||
#state_KeybindingsState {
|
#state_SettingsState {
|
||||||
|
|
||||||
|
$colorCategoryButton: #eee;
|
||||||
|
$colorCategoryButtonSelected: #5f748b;
|
||||||
|
|
||||||
.content {
|
.content {
|
||||||
|
display: flex;
|
||||||
|
overflow-y: scroll;
|
||||||
|
|
||||||
.topEntries {
|
.topEntries {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: 1fr auto;
|
grid-template-columns: 1fr auto;
|
||||||
@ -50,6 +57,148 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.categoryContainer {
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
.category {
|
||||||
|
display: none;
|
||||||
|
|
||||||
|
&.active {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.setting {
|
||||||
|
@include S(padding, 10px);
|
||||||
|
background: #eeeff5;
|
||||||
|
@include S(border-radius, $globalBorderRadius);
|
||||||
|
@include S(margin-bottom, 5px);
|
||||||
|
|
||||||
|
label {
|
||||||
|
text-transform: uppercase;
|
||||||
|
@include Text;
|
||||||
|
}
|
||||||
|
|
||||||
|
.desc {
|
||||||
|
@include S(margin-top, 5px);
|
||||||
|
@include SuperSmallText;
|
||||||
|
color: #aaadb2;
|
||||||
|
}
|
||||||
|
|
||||||
|
> .row {
|
||||||
|
display: grid;
|
||||||
|
align-items: center;
|
||||||
|
grid-template-columns: 1fr auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.disabled {
|
||||||
|
// opacity: 0.3;
|
||||||
|
pointer-events: none;
|
||||||
|
* {
|
||||||
|
pointer-events: none !important;
|
||||||
|
cursor: default !important;
|
||||||
|
}
|
||||||
|
position: relative;
|
||||||
|
.standaloneOnlyHint {
|
||||||
|
@include PlainText;
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
pointer-events: all;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
background: rgba(#fff, 0.5);
|
||||||
|
text-transform: uppercase;
|
||||||
|
color: $colorRedBright;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.value.enum {
|
||||||
|
background: #fff;
|
||||||
|
@include PlainText;
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-start;
|
||||||
|
pointer-events: all;
|
||||||
|
cursor: pointer;
|
||||||
|
justify-content: center;
|
||||||
|
@include S(min-width, 100px);
|
||||||
|
@include S(border-radius, $globalBorderRadius);
|
||||||
|
@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;
|
||||||
|
|
||||||
|
transition: background-color 0.12s ease-in-out;
|
||||||
|
&:hover {
|
||||||
|
background-color: #fafafa;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
@include S(min-width, 210px);
|
||||||
|
@include S(max-width, 320px);
|
||||||
|
width: 30%;
|
||||||
|
height: 100%;
|
||||||
|
position: sticky;
|
||||||
|
top: 0;
|
||||||
|
@include S(margin-left, 20px);
|
||||||
|
@include S(margin-right, 32px);
|
||||||
|
|
||||||
|
.other {
|
||||||
|
margin-top: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
@include S(margin-top, 4px);
|
||||||
|
width: calc(100% - #{D(20px)});
|
||||||
|
text-align: start;
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
content: unset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
button.categoryButton,
|
||||||
|
button.about {
|
||||||
|
background-color: $colorCategoryButton;
|
||||||
|
color: #777a7f;
|
||||||
|
|
||||||
|
&.active {
|
||||||
|
background-color: $colorCategoryButtonSelected;
|
||||||
|
color: #fff;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.pressed {
|
||||||
|
transform: none !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.versionbar {
|
||||||
|
@include S(margin-top, 20px);
|
||||||
|
@include SuperSmallText;
|
||||||
|
display: grid;
|
||||||
|
align-items: center;
|
||||||
|
grid-template-columns: 1fr auto;
|
||||||
|
.buildVersion {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
color: #aaadaf;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@include DarkThemeOverride {
|
@include DarkThemeOverride {
|
||||||
|
@ -164,24 +164,28 @@
|
|||||||
|
|
||||||
position: relative;
|
position: relative;
|
||||||
.updateLabel {
|
.updateLabel {
|
||||||
|
background-color: $mainBgColor;
|
||||||
|
border-radius: 999em;
|
||||||
|
padding: 0px 10px;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
transform: translateX(50%) rotate(-5deg);
|
transform: translateX(50%) rotate(-5deg) scale(1.5);
|
||||||
color: $colorRedBright;
|
color: #7d808a;
|
||||||
|
//color: $colorRedBright;
|
||||||
@include Heading;
|
@include Heading;
|
||||||
text-transform: uppercase;
|
//text-transform: uppercase;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
@include S(right, 40px);
|
@include S(right, 40px);
|
||||||
@include S(bottom, 20px);
|
@include S(bottom, 20px);
|
||||||
|
|
||||||
@include InlineAnimation(1.3s ease-in-out infinite) {
|
@include InlineAnimation(1.3s ease-in-out infinite) {
|
||||||
50% {
|
50% {
|
||||||
transform: translateX(50%) rotate(-7deg) scale(1.1);
|
transform: translateX(50%) rotate(-7deg) scale(1.65);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@include DarkThemeOverride {
|
/*@include DarkThemeOverride {
|
||||||
color: $colorBlueBright;
|
color: $colorBlueBright;
|
||||||
}
|
}*/
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
221
src/js/GeoZ/main.js
Normal file
221
src/js/GeoZ/main.js
Normal file
@ -0,0 +1,221 @@
|
|||||||
|
//Mod imports
|
||||||
|
import { MetaModBuilding } from "./mod_building";
|
||||||
|
import { ModComponent } from "./mod_component";
|
||||||
|
import { ModItem } from "./mod_item";
|
||||||
|
import { ModProcessor } from "./mod_processor";
|
||||||
|
import { ModWireProcessor } from "./mod_wireprocessor";
|
||||||
|
import { ModSystem, ModSystemWithFilter } from "./mod_system";
|
||||||
|
import { keyCodeOf } from "./mod_utils";
|
||||||
|
|
||||||
|
//Game imports
|
||||||
|
import { gComponentRegistry, gItemRegistry, gMetaBuildingRegistry } from "../core/global_registries";
|
||||||
|
import { GameSystemManager } from "../game/game_system_manager";
|
||||||
|
import { GameCore } from "../game/core";
|
||||||
|
import { createLogger } from "../core/logging";
|
||||||
|
import { registerBuildingVariant } from "../game/building_codes";
|
||||||
|
import { supportedBuildings } from "../game/hud/parts/buildings_toolbar";
|
||||||
|
import { KEYMAPPINGS, key } from "../game/key_action_mapper";
|
||||||
|
import { T } from "../translations";
|
||||||
|
import { ShapeData, allShapeData, initShapes } from "../game/shapes";
|
||||||
|
import { globalConfig } from "../core/config";
|
||||||
|
|
||||||
|
export { MetaModBuilding } from "./mod_building";
|
||||||
|
export { ModComponent } from "./mod_component";
|
||||||
|
export { ModItem } from "./mod_item";
|
||||||
|
export { ModProcessor } from "./mod_processor";
|
||||||
|
export { ModWireProcessor } from "./mod_wireprocessor";
|
||||||
|
export { ModSystem, ModSystemWithFilter } from "./mod_system";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {Object} Mod
|
||||||
|
* @property {String} name
|
||||||
|
* @property {Array<typeof MetaModBuilding>=} buildings
|
||||||
|
* @property {Array<typeof ModComponent>=} components
|
||||||
|
* @property {Array<typeof ModItem>=} items
|
||||||
|
* @property {Array<typeof ModProcessor>=} processors
|
||||||
|
* @property {Array<typeof ModWireProcessor>=} wireProcessors
|
||||||
|
* @property {Array<typeof ModSystem | typeof ModSystemWithFilter>=} systems
|
||||||
|
* @property {Array<ShapeData>=} shapes
|
||||||
|
*/
|
||||||
|
|
||||||
|
export const logger = createLogger("GeoZ");
|
||||||
|
|
||||||
|
/** @type {Array<Mod>} */
|
||||||
|
export const Mods = [];
|
||||||
|
|
||||||
|
/** @type {Array<typeof ModComponent>} */
|
||||||
|
export const ModComponents = [];
|
||||||
|
|
||||||
|
/** @type {Array<typeof ModSystem | typeof ModSystemWithFilter>} */
|
||||||
|
export const ModSystems = [];
|
||||||
|
|
||||||
|
/** @type {Object.<string, typeof ModProcessor>} */
|
||||||
|
export const ModProcessors = {};
|
||||||
|
|
||||||
|
/** @type {Object.<string, typeof ModWireProcessor>} */
|
||||||
|
export const ModWireProcessors = {};
|
||||||
|
|
||||||
|
/** @type {Array<typeof ModItem>} */
|
||||||
|
export const ModItems = [];
|
||||||
|
|
||||||
|
/** @type {Array<typeof MetaModBuilding>} */
|
||||||
|
export const ModBuildings = [];
|
||||||
|
|
||||||
|
/** @type {Array<ShapeData>} */
|
||||||
|
export const ModShapes = [];
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
|
const webpack_require = require.context("../", true, /\.js$/);
|
||||||
|
|
||||||
|
const GeoZ = {
|
||||||
|
Classes: {
|
||||||
|
MetaModBuilding,
|
||||||
|
ModComponent,
|
||||||
|
ModItem,
|
||||||
|
ModProcessor,
|
||||||
|
ModSystem,
|
||||||
|
ModSystemWithFilter,
|
||||||
|
},
|
||||||
|
|
||||||
|
require(module) {
|
||||||
|
return webpack_require(`./${module}.js`);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export async function initMods() {
|
||||||
|
const style = "font-size: 35px; font-family: Arial;font-weight: bold; padding: 10px 0;";
|
||||||
|
console.log(
|
||||||
|
`%cGeo%cZ%c modloader\nby %cExund\n`,
|
||||||
|
`${style} color: #aaa;`,
|
||||||
|
`${style} color: #7f7;`,
|
||||||
|
`${style} color: #aaa; font-size: 15px;`,
|
||||||
|
"color: #ff4300"
|
||||||
|
);
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
|
window.GeoZ = GeoZ;
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
|
const local_mods = require.context("./mods", true, /.*\.mod\.js/i);
|
||||||
|
for (let key of local_mods.keys()) {
|
||||||
|
let mod = /** @type {Mod} */ (local_mods(key).default);
|
||||||
|
if (mod.name) {
|
||||||
|
Mods.push(mod);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const local_mods_count = Mods.length;
|
||||||
|
logger.log(`${local_mods_count} local mods found`);
|
||||||
|
|
||||||
|
/** @type {Array<string>} */
|
||||||
|
let external_mods = [];
|
||||||
|
let storage = localStorage.getItem("mods.external");
|
||||||
|
|
||||||
|
if (storage) {
|
||||||
|
external_mods = JSON.parse(storage);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const url of external_mods) {
|
||||||
|
try {
|
||||||
|
let temp = await fetch(url);
|
||||||
|
const text = await temp.text();
|
||||||
|
const mod = /** @type {Mod} */ (eval(text));
|
||||||
|
|
||||||
|
if (mod.name) {
|
||||||
|
Mods.push(mod);
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
logger.log(`🛑 Failed to load mod at : ${url}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const external_mods_count = Mods.length - local_mods_count;
|
||||||
|
logger.log(`${external_mods_count} external mods found`);
|
||||||
|
|
||||||
|
for (const mod of Mods) {
|
||||||
|
let mod_infos = `${mod.name} : `;
|
||||||
|
if (mod.components) {
|
||||||
|
mod_infos += `${mod.components.length} components, `;
|
||||||
|
for (const component of mod.components) {
|
||||||
|
ModComponents.push(component);
|
||||||
|
gComponentRegistry.register(component);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mod.systems) {
|
||||||
|
mod_infos += `${mod.systems.length} systems, `;
|
||||||
|
for (const system of mod.systems) {
|
||||||
|
ModSystems.push(system);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mod.processors) {
|
||||||
|
mod_infos += `${mod.processors.length} processors, `;
|
||||||
|
for (const processor of mod.processors) {
|
||||||
|
const type = processor.getType();
|
||||||
|
ModProcessors[type] = processor;
|
||||||
|
globalConfig.buildingSpeeds[type] = processor.getBaseSpeed();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mod.wireProcessors) {
|
||||||
|
mod_infos += `${mod.wireProcessors.length} wire processors, `;
|
||||||
|
for (const wireProcessor of mod.wireProcessors) {
|
||||||
|
const type = wireProcessor.getType();
|
||||||
|
ModWireProcessors[type] = wireProcessor;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mod.items) {
|
||||||
|
mod_infos += `${mod.items.length} items, `;
|
||||||
|
for (const item of mod.items) {
|
||||||
|
ModItems.push(item);
|
||||||
|
gItemRegistry.register(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mod.buildings) {
|
||||||
|
mod_infos += `${mod.buildings.length} buildings, `;
|
||||||
|
for (const building of mod.buildings) {
|
||||||
|
ModBuildings.push(building);
|
||||||
|
gMetaBuildingRegistry.register(building);
|
||||||
|
const base_id = building.getId();
|
||||||
|
registerBuildingVariant(base_id, building);
|
||||||
|
|
||||||
|
for (const variant of building.getVariants()) {
|
||||||
|
registerBuildingVariant(`${base_id}-${variant}`, building, variant);
|
||||||
|
}
|
||||||
|
|
||||||
|
supportedBuildings.push(building);
|
||||||
|
|
||||||
|
KEYMAPPINGS.buildings[base_id] = {
|
||||||
|
keyCode: keyCodeOf(building.getKeybinding()),
|
||||||
|
id: base_id,
|
||||||
|
};
|
||||||
|
|
||||||
|
const translations = building.getTranslations();
|
||||||
|
|
||||||
|
T.keybindings.mappings[base_id] = translations.keybinding;
|
||||||
|
|
||||||
|
T.buildings[base_id] = {};
|
||||||
|
for (const variant in translations.variants) {
|
||||||
|
T.buildings[base_id][variant] = translations.variants[variant];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mod.shapes) {
|
||||||
|
mod_infos += `${mod.shapes.length} shapes, `;
|
||||||
|
for (const shape of mod.shapes) {
|
||||||
|
ModShapes.push(shape);
|
||||||
|
allShapeData[shape.id] = shape;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.log(mod_infos);
|
||||||
|
}
|
||||||
|
|
||||||
|
initShapes();
|
||||||
|
|
||||||
|
logger.log(`${Mods.length} mods loaded`);
|
||||||
|
}
|
157
src/js/GeoZ/mod_building.js
Normal file
157
src/js/GeoZ/mod_building.js
Normal file
@ -0,0 +1,157 @@
|
|||||||
|
import { MetaBuilding, defaultBuildingVariant } from "../game/meta_building";
|
||||||
|
import { AtlasSprite, SpriteAtlasLink } from "../core/sprites";
|
||||||
|
import { atlasFiles } from "../core/atlas_definitions";
|
||||||
|
import { getFileAsDataURI } from "./mod_utils";
|
||||||
|
import { Loader } from "../core/loader";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {{
|
||||||
|
* url: string,
|
||||||
|
* width: number,
|
||||||
|
* height: number
|
||||||
|
* }} ExternalSpriteMeta
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {{
|
||||||
|
* normal: ExternalSpriteMeta
|
||||||
|
* blueprint: ExternalSpriteMeta
|
||||||
|
* }} SpriteTypesMetas
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {{
|
||||||
|
* default: Array<SpriteTypesMetas>
|
||||||
|
* [variant: string]: Array<SpriteTypesMetas>
|
||||||
|
* }} BuildingSpriteMetas
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {{
|
||||||
|
* name: string,
|
||||||
|
* description: string
|
||||||
|
* }} BuildingVariantTranslation
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {{
|
||||||
|
* variants: {[variant: string]: BuildingVariantTranslation, default: BuildingVariantTranslation},
|
||||||
|
* keybinding: string
|
||||||
|
* }} BuildingTranlsations
|
||||||
|
*/
|
||||||
|
|
||||||
|
export class MetaModBuilding extends MetaBuilding {
|
||||||
|
/**
|
||||||
|
* Returns the building IDs
|
||||||
|
* @returns {String}
|
||||||
|
*/
|
||||||
|
static getId() {
|
||||||
|
abstract;
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the building variants IDs
|
||||||
|
* @returns {Array<String>}
|
||||||
|
*/
|
||||||
|
static getVariants() {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the building keybinding
|
||||||
|
* @returns {String | number}
|
||||||
|
*/
|
||||||
|
static getKeybinding() {
|
||||||
|
abstract;
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the building translations
|
||||||
|
* @returns {BuildingTranlsations}
|
||||||
|
*/
|
||||||
|
static getTranslations() {
|
||||||
|
abstract;
|
||||||
|
return { variants: { default: { name: "", description: "" } }, keybinding: "" };
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} id
|
||||||
|
*/
|
||||||
|
constructor(id) {
|
||||||
|
super(id);
|
||||||
|
|
||||||
|
/** @type {Object<string, AtlasSprite>} */
|
||||||
|
this.cachedSprites = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the sprite for a given variant
|
||||||
|
* @param {number} rotationVariant
|
||||||
|
* @param {string} variant
|
||||||
|
* @param {keyof BuildingSpriteMetas} type
|
||||||
|
* @returns {AtlasSprite}
|
||||||
|
*/
|
||||||
|
getSprite(rotationVariant, variant, type = "normal") {
|
||||||
|
const sprite_id =
|
||||||
|
this.id +
|
||||||
|
(variant === defaultBuildingVariant ? "" : "-" + variant) +
|
||||||
|
"-" +
|
||||||
|
rotationVariant +
|
||||||
|
"-" +
|
||||||
|
type;
|
||||||
|
|
||||||
|
if (this.cachedSprites[sprite_id]) {
|
||||||
|
return this.cachedSprites[sprite_id];
|
||||||
|
}
|
||||||
|
|
||||||
|
const sprite = new AtlasSprite(sprite_id);
|
||||||
|
this.cachedSprites[sprite_id] = sprite;
|
||||||
|
|
||||||
|
const meta = this.getSpriteMetas()[variant][rotationVariant][type];
|
||||||
|
const scales = atlasFiles.map(af => af.meta.scale);
|
||||||
|
for (const res of scales) {
|
||||||
|
sprite.linksByResolution[res] = Loader.spriteNotFoundSprite.linksByResolution[res];
|
||||||
|
}
|
||||||
|
|
||||||
|
getFileAsDataURI(meta.url).then(data => {
|
||||||
|
const img = document.createElement("img");
|
||||||
|
img.src = data;
|
||||||
|
|
||||||
|
const link = new SpriteAtlasLink({
|
||||||
|
atlas: img,
|
||||||
|
packOffsetX: 0,
|
||||||
|
packOffsetY: 0,
|
||||||
|
packedX: 0,
|
||||||
|
packedY: 0,
|
||||||
|
packedW: meta.width,
|
||||||
|
packedH: meta.height,
|
||||||
|
w: meta.width,
|
||||||
|
h: meta.width,
|
||||||
|
});
|
||||||
|
for (const res of scales) {
|
||||||
|
sprite.linksByResolution[res] = link;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return sprite;
|
||||||
|
}
|
||||||
|
|
||||||
|
getBlueprintSprite(rotationVariant = 0, variant = defaultBuildingVariant) {
|
||||||
|
return this.getSprite(rotationVariant, variant, "blueprint");
|
||||||
|
}
|
||||||
|
|
||||||
|
getPreviewSprite(rotationVariant = 0, variant = defaultBuildingVariant) {
|
||||||
|
return this.getSprite(rotationVariant, variant);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the sprite metadata for a given variant
|
||||||
|
* @returns {BuildingSpriteMetas}
|
||||||
|
*/
|
||||||
|
getSpriteMetas() {
|
||||||
|
abstract;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
13
src/js/GeoZ/mod_component.js
Normal file
13
src/js/GeoZ/mod_component.js
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
import { Component } from "../game/component";
|
||||||
|
|
||||||
|
export class ModComponent extends Component {
|
||||||
|
static getId() {
|
||||||
|
const className = this.prototype.constructor.name;
|
||||||
|
let id = className;
|
||||||
|
const i = className.lastIndexOf("Component");
|
||||||
|
if(i !== -1) {
|
||||||
|
id = id.slice(0, i);
|
||||||
|
}
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
}
|
5
src/js/GeoZ/mod_item.js
Normal file
5
src/js/GeoZ/mod_item.js
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
import { BaseItem } from "../game/base_item";
|
||||||
|
|
||||||
|
export class ModItem extends BaseItem {
|
||||||
|
|
||||||
|
}
|
50
src/js/GeoZ/mod_processor.js
Normal file
50
src/js/GeoZ/mod_processor.js
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
import { Entity } from "../game/entity";
|
||||||
|
import { ItemProcessorSystem } from "../game/systems/item_processor";
|
||||||
|
import { BaseItem } from "../game/base_item";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {{
|
||||||
|
* items: Array<BaseItem>,
|
||||||
|
* itemsBySlot: Array<{ item: BaseItem, sourceSlot: number }>,
|
||||||
|
* itemsRaw: Array<{ item: BaseItem, sourceSlot: number }>,
|
||||||
|
* entity: Entity,
|
||||||
|
* outItems: Array<{item: BaseItem, requiredSlot?: number, preferredSlot?: number}>,
|
||||||
|
* system: ItemProcessorSystem
|
||||||
|
* }} ProcessorParameters
|
||||||
|
*/
|
||||||
|
|
||||||
|
export class ModProcessor {
|
||||||
|
/**
|
||||||
|
* @returns {String}
|
||||||
|
*/
|
||||||
|
static getType() {
|
||||||
|
return this.prototype.constructor.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns {Number}
|
||||||
|
*/
|
||||||
|
static getBaseSpeed() {
|
||||||
|
abstract;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks whether it's possible to process something
|
||||||
|
* @param {Entity} entity
|
||||||
|
* @returns {Boolean}
|
||||||
|
*/
|
||||||
|
static canProcess(entity) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Process ther current item
|
||||||
|
* @param {ProcessorParameters} param0
|
||||||
|
* @returns {Boolean} Whether to track the production towards the analytics
|
||||||
|
*/
|
||||||
|
static process({}) {
|
||||||
|
abstract;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
121
src/js/GeoZ/mod_system.js
Normal file
121
src/js/GeoZ/mod_system.js
Normal file
@ -0,0 +1,121 @@
|
|||||||
|
import { GameSystem } from "../game/game_system";
|
||||||
|
import { GameSystemWithFilter } from "../game/game_system_with_filter";
|
||||||
|
import { GameRoot } from "../game/root";
|
||||||
|
import { Component } from "../game/component";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {
|
||||||
|
"belt"
|
||||||
|
| "itemEjector"
|
||||||
|
| "mapResources"
|
||||||
|
| "miner"
|
||||||
|
| "itemProcessor"
|
||||||
|
| "undergroundBelt"
|
||||||
|
| "hub"
|
||||||
|
| "staticMapEntities"
|
||||||
|
| "itemAcceptor"
|
||||||
|
| "storage"
|
||||||
|
| "wiredPins"
|
||||||
|
| "beltUnderlays"
|
||||||
|
| "wire"
|
||||||
|
| "constantSignal"
|
||||||
|
| "logicGate"
|
||||||
|
| "lever"
|
||||||
|
| "display"
|
||||||
|
| "itemProcessorOverlays"
|
||||||
|
| "beltReader"
|
||||||
|
| ""
|
||||||
|
* } VanillaSystemId
|
||||||
|
*/
|
||||||
|
|
||||||
|
export class ModSystem extends GameSystem {
|
||||||
|
/**
|
||||||
|
* @returns {String} Mod system ID
|
||||||
|
*/
|
||||||
|
static getId() {
|
||||||
|
//abstract;
|
||||||
|
const className = this.prototype.constructor.name;
|
||||||
|
let id = className;
|
||||||
|
const i = className.lastIndexOf("System");
|
||||||
|
if(i !== -1) {
|
||||||
|
id = id.slice(0, i);
|
||||||
|
}
|
||||||
|
id = id[0].toLowerCase() + id.slice(1);
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Before which vanilla system should this system update
|
||||||
|
* @returns {VanillaSystemId}
|
||||||
|
*/
|
||||||
|
static getUpdateBefore() {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* After which vanilla system should this system update
|
||||||
|
* @returns {VanillaSystemId}
|
||||||
|
*/
|
||||||
|
static getUpdateAfter() {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {GameRoot} root
|
||||||
|
*/
|
||||||
|
constructor(root) {
|
||||||
|
super(root);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class ModSystemWithFilter extends GameSystemWithFilter {
|
||||||
|
/**
|
||||||
|
* @returns {String} Mod system ID
|
||||||
|
*/
|
||||||
|
static getId() {
|
||||||
|
//abstract;
|
||||||
|
const className = this.prototype.constructor.name;
|
||||||
|
let id = className;
|
||||||
|
const i = className.lastIndexOf("System");
|
||||||
|
if(i !== -1) {
|
||||||
|
id = id.slice(0, i);
|
||||||
|
}
|
||||||
|
id = id[0].toLowerCase() + id.slice(1);
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Before which vanilla system should this system update
|
||||||
|
* @returns {VanillaSystemId}
|
||||||
|
*/
|
||||||
|
static getUpdateBefore() {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* After which vanilla system should this system update
|
||||||
|
* @returns {VanillaSystemId}
|
||||||
|
*/
|
||||||
|
static getUpdateAfter() {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns {Array<typeof Component>}
|
||||||
|
*/
|
||||||
|
static getRequiredComponents() {
|
||||||
|
abstract;
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a new game system with the given component filter. It will process
|
||||||
|
* all entities which have *all* of the passed components
|
||||||
|
* @param {GameRoot} root
|
||||||
|
*/
|
||||||
|
constructor(root) {
|
||||||
|
super(root, []);
|
||||||
|
this.requiredComponents = /** @type {Array<typeof Component>} */ (Object.getPrototypeOf(this).getRequiredComponents());
|
||||||
|
this.requiredComponentIds = this.requiredComponents.map(component => component.getId());
|
||||||
|
}
|
||||||
|
}
|
30
src/js/GeoZ/mod_utils.js
Normal file
30
src/js/GeoZ/mod_utils.js
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
/**
|
||||||
|
* Returns a file as a data URI
|
||||||
|
* @param {string} url
|
||||||
|
* @returns {Promise<String>}
|
||||||
|
*/
|
||||||
|
export function getFileAsDataURI(url) {
|
||||||
|
return fetch(url)
|
||||||
|
.then(response => response.blob())
|
||||||
|
.then(blob => {
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
var reader = new FileReader() ;
|
||||||
|
reader.onload = function() { resolve(this.result.toString()) } ; // <--- `this.result` contains a base64 data URI
|
||||||
|
reader.readAsDataURL(blob) ;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {number | string} key
|
||||||
|
*/
|
||||||
|
export function keyCodeOf(key) {
|
||||||
|
if (typeof key === "number") {
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
if (key.match(/F\d+/)) {
|
||||||
|
return 111 + +key.slice(1);
|
||||||
|
}
|
||||||
|
return key.toUpperCase().charCodeAt(0);
|
||||||
|
}
|
24
src/js/GeoZ/mod_wireprocessor.js
Normal file
24
src/js/GeoZ/mod_wireprocessor.js
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
import { BaseItem } from "../game/base_item";
|
||||||
|
import { LogicGateSystem } from "../game/systems/logic_gate";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Custom wire processor (logic gate/virtual processor)
|
||||||
|
*/
|
||||||
|
export class ModWireProcessor {
|
||||||
|
/**
|
||||||
|
* @returns {String}
|
||||||
|
*/
|
||||||
|
static getType() {
|
||||||
|
return this.prototype.constructor.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {Array<BaseItem|null>} parameters
|
||||||
|
* @param {LogicGateSystem} system
|
||||||
|
* @returns {Array<BaseItem>|BaseItem}
|
||||||
|
*/
|
||||||
|
static compute(system, parameters) {
|
||||||
|
abstract;
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}
|
362
src/js/GeoZ/mods/test/test.mod.js
Normal file
362
src/js/GeoZ/mods/test/test.mod.js
Normal file
@ -0,0 +1,362 @@
|
|||||||
|
import * as GeoZ from "../../main";
|
||||||
|
import { Vector, enumDirection } from "../../../core/vector";
|
||||||
|
import { Entity } from "../../../game/entity";
|
||||||
|
import { ModProcessor, ProcessorParameters } from "../../mod_processor";
|
||||||
|
import { ShapeItem } from "../../../game/items/shape_item";
|
||||||
|
import { ShapeDefinition } from "../../../game/shape_definition";
|
||||||
|
import { ItemProcessorComponent } from "../../../game/components/item_processor";
|
||||||
|
import { ItemEjectorComponent } from "../../../game/components/item_ejector";
|
||||||
|
import { ItemAcceptorComponent } from "../../../game/components/item_acceptor";
|
||||||
|
import { ModWireProcessor } from "../../mod_wireprocessor";
|
||||||
|
import { BaseItem } from "../../../game/base_item";
|
||||||
|
import { LogicGateSystem } from "../../../game/systems/logic_gate";
|
||||||
|
import { BOOL_FALSE_SINGLETON, BOOL_TRUE_SINGLETON, isTruthyItem } from "../../../game/items/boolean_item";
|
||||||
|
import { enumPinSlotType, WiredPinsComponent } from "../../../game/components/wired_pins";
|
||||||
|
import { LogicGateComponent } from "../../../game/components/logic_gate";
|
||||||
|
import { defaultBuildingVariant } from "../../../game/meta_building";
|
||||||
|
|
||||||
|
class MetaTestBuilding extends GeoZ.MetaModBuilding {
|
||||||
|
static getId() {
|
||||||
|
return "test";
|
||||||
|
}
|
||||||
|
|
||||||
|
static getKeybinding() {
|
||||||
|
return "0";
|
||||||
|
}
|
||||||
|
|
||||||
|
static getTranslations() {
|
||||||
|
return {
|
||||||
|
variants: {
|
||||||
|
default: {
|
||||||
|
name: "Test",
|
||||||
|
description: "Test GeoZ building",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
keybinding: "Test",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super("test");
|
||||||
|
}
|
||||||
|
|
||||||
|
getSilhouetteColor() {
|
||||||
|
return "#ff00ff";
|
||||||
|
}
|
||||||
|
|
||||||
|
getDimensions() {
|
||||||
|
return new Vector(1, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns {import("../../mod_building").BuildingSpriteMetas}
|
||||||
|
*/
|
||||||
|
getSpriteMetas() {
|
||||||
|
const normal = {
|
||||||
|
url:
|
||||||
|
"https://raw.githubusercontent.com/Exund/shapez.io/master/res_raw/sprites/wires/boolean_false.png",
|
||||||
|
width: 64,
|
||||||
|
height: 64,
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
default: [
|
||||||
|
{
|
||||||
|
normal,
|
||||||
|
blueprint: normal,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates the entity at the given location
|
||||||
|
* @param {Entity} entity
|
||||||
|
*/
|
||||||
|
setupEntityComponents(entity) {
|
||||||
|
entity.addComponent(
|
||||||
|
new ItemProcessorComponent({
|
||||||
|
inputsPerCharge: 1,
|
||||||
|
processorType: SquareConverter.getType(),
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
entity.addComponent(
|
||||||
|
new ItemEjectorComponent({
|
||||||
|
slots: [{ pos: new Vector(0, 0), direction: enumDirection.top }],
|
||||||
|
})
|
||||||
|
);
|
||||||
|
entity.addComponent(
|
||||||
|
new ItemAcceptorComponent({
|
||||||
|
slots: [
|
||||||
|
{
|
||||||
|
pos: new Vector(0, 0),
|
||||||
|
directions: [enumDirection.bottom],
|
||||||
|
filter: "shape",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class MetaInvertedGatesBuilding extends GeoZ.MetaModBuilding {
|
||||||
|
static getId() {
|
||||||
|
return "NANDGate";
|
||||||
|
}
|
||||||
|
|
||||||
|
static getKeybinding() {
|
||||||
|
return "0";
|
||||||
|
}
|
||||||
|
|
||||||
|
static getTranslations() {
|
||||||
|
return {
|
||||||
|
variants: {
|
||||||
|
default: {
|
||||||
|
name: "NAND Gate",
|
||||||
|
description: "Test GeoZ building for custom wire processor",
|
||||||
|
},
|
||||||
|
NORGate: {
|
||||||
|
name: "NOR Gate",
|
||||||
|
description: "Test GeoZ building for custom wire processor",
|
||||||
|
},
|
||||||
|
XNORGate: {
|
||||||
|
name: "XNOR Gate",
|
||||||
|
description: "Test GeoZ building for custom wire processor",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
keybinding: "NAND Gate",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
static getVariants() {
|
||||||
|
return ["NORGate", "XNORGate"];
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super("NANDGate");
|
||||||
|
}
|
||||||
|
|
||||||
|
getSilhouetteColor() {
|
||||||
|
return "#89dc60";
|
||||||
|
}
|
||||||
|
|
||||||
|
getDimensions() {
|
||||||
|
return new Vector(1, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
getAvailableVariants() {
|
||||||
|
return [...super.getAvailableVariants(null), ...MetaInvertedGatesBuilding.getVariants()];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns {Layer}
|
||||||
|
*/
|
||||||
|
getLayer() {
|
||||||
|
return "wires";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns {import("../../mod_building").BuildingSpriteMetas}
|
||||||
|
*/
|
||||||
|
getSpriteMetas() {
|
||||||
|
return {
|
||||||
|
default: [
|
||||||
|
{
|
||||||
|
normal: {
|
||||||
|
url:
|
||||||
|
"https://raw.githubusercontent.com/Exund/shapez.io/master/res_raw/sprites/buildings/logic_gate.png",
|
||||||
|
width: 192,
|
||||||
|
height: 192,
|
||||||
|
},
|
||||||
|
blueprint: {
|
||||||
|
url:
|
||||||
|
"https://raw.githubusercontent.com/Exund/shapez.io/master/res_raw/sprites/blueprints/logic_gate.png",
|
||||||
|
width: 192,
|
||||||
|
height: 192,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
NORGate: [
|
||||||
|
{
|
||||||
|
normal: {
|
||||||
|
url:
|
||||||
|
"https://raw.githubusercontent.com/Exund/shapez.io/master/res_raw/sprites/buildings/logic_gate-or.png",
|
||||||
|
width: 192,
|
||||||
|
height: 192,
|
||||||
|
},
|
||||||
|
blueprint: {
|
||||||
|
url:
|
||||||
|
"https://raw.githubusercontent.com/Exund/shapez.io/master/res_raw/sprites/blueprints/logic_gate-or.png",
|
||||||
|
width: 192,
|
||||||
|
height: 192,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
XNORGate: [
|
||||||
|
{
|
||||||
|
normal: {
|
||||||
|
url:
|
||||||
|
"https://raw.githubusercontent.com/Exund/shapez.io/master/res_raw/sprites/buildings/logic_gate-xor.png",
|
||||||
|
width: 192,
|
||||||
|
height: 192,
|
||||||
|
},
|
||||||
|
blueprint: {
|
||||||
|
url:
|
||||||
|
"https://raw.githubusercontent.com/Exund/shapez.io/master/res_raw/sprites/blueprints/logic_gate-xor.png",
|
||||||
|
width: 192,
|
||||||
|
height: 192,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {Entity} entity
|
||||||
|
* @param {string} variant
|
||||||
|
*/
|
||||||
|
updateVariants(entity, rotationVariant, variant) {
|
||||||
|
entity.components.LogicGate.type = enumInvertedGatesVariants[variant];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates the entity at the given location
|
||||||
|
* @param {Entity} entity
|
||||||
|
*/
|
||||||
|
setupEntityComponents(entity) {
|
||||||
|
entity.addComponent(
|
||||||
|
new WiredPinsComponent({
|
||||||
|
slots: [
|
||||||
|
{
|
||||||
|
pos: new Vector(0, 0),
|
||||||
|
direction: enumDirection.top,
|
||||||
|
type: enumPinSlotType.logicalEjector,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
pos: new Vector(0, 0),
|
||||||
|
direction: enumDirection.left,
|
||||||
|
type: enumPinSlotType.logicalAcceptor,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
pos: new Vector(0, 0),
|
||||||
|
direction: enumDirection.right,
|
||||||
|
type: enumPinSlotType.logicalAcceptor,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
entity.addComponent(new LogicGateComponent({ type: NANDGate.getType() }));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const enumInvertedGatesVariants = {
|
||||||
|
[defaultBuildingVariant]: "NANDGate",
|
||||||
|
};
|
||||||
|
|
||||||
|
for (const v of MetaInvertedGatesBuilding.getVariants()) {
|
||||||
|
enumInvertedGatesVariants[v] = v;
|
||||||
|
}
|
||||||
|
|
||||||
|
class SquareConverter extends ModProcessor {
|
||||||
|
/**
|
||||||
|
* @returns {Number}
|
||||||
|
*/
|
||||||
|
static getBaseSpeed() {
|
||||||
|
return 0.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Process ther current item
|
||||||
|
* @param {ProcessorParameters} param0
|
||||||
|
* @returns {Boolean} Whether to track the production towards the analytics
|
||||||
|
*/
|
||||||
|
static process({ outItems }) {
|
||||||
|
outItems.push({ item: new ShapeItem(ShapeDefinition.fromShortKey("SuSuSuSu")) });
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class NANDGate extends ModWireProcessor {
|
||||||
|
/**
|
||||||
|
* @param {Array<BaseItem|null>} parameters
|
||||||
|
* @param {LogicGateSystem} system
|
||||||
|
* @returns {Array<BaseItem>|BaseItem}
|
||||||
|
*/
|
||||||
|
static compute(system, parameters) {
|
||||||
|
assert(parameters.length === 2, "bad parameter count for NAND");
|
||||||
|
return isTruthyItem(parameters[0]) && isTruthyItem(parameters[1])
|
||||||
|
? BOOL_FALSE_SINGLETON
|
||||||
|
: BOOL_TRUE_SINGLETON;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class NORGate extends ModWireProcessor {
|
||||||
|
/**
|
||||||
|
* @param {Array<BaseItem|null>} parameters
|
||||||
|
* @param {LogicGateSystem} system
|
||||||
|
* @returns {Array<BaseItem>|BaseItem}
|
||||||
|
*/
|
||||||
|
static compute(system, parameters) {
|
||||||
|
assert(parameters.length === 2, "bad parameter count for NOR");
|
||||||
|
return isTruthyItem(parameters[0]) || isTruthyItem(parameters[1])
|
||||||
|
? BOOL_FALSE_SINGLETON
|
||||||
|
: BOOL_TRUE_SINGLETON;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class XNORGate extends ModWireProcessor {
|
||||||
|
/**
|
||||||
|
* @param {Array<BaseItem|null>} parameters
|
||||||
|
* @param {LogicGateSystem} system
|
||||||
|
* @returns {Array<BaseItem>|BaseItem}
|
||||||
|
*/
|
||||||
|
static compute(system, parameters) {
|
||||||
|
assert(parameters.length === 2, "bad parameter count for XNOR");
|
||||||
|
return isTruthyItem(parameters[0]) !== isTruthyItem(parameters[1])
|
||||||
|
? BOOL_FALSE_SINGLETON
|
||||||
|
: BOOL_TRUE_SINGLETON;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class VirtualStacker extends ModWireProcessor {
|
||||||
|
/**
|
||||||
|
* @param {Array<BaseItem|null>} parameters
|
||||||
|
* @param {LogicGateSystem} system
|
||||||
|
* @returns {Array<BaseItem>|BaseItem}
|
||||||
|
*/
|
||||||
|
static compute(system, parameters) {
|
||||||
|
const item1 = parameters[0];
|
||||||
|
const item2 = parameters[0];
|
||||||
|
if (!item1 || !item2 || item1.getItemType() !== "shape" || item2.getItemType() !== "shape") {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const definition1 = /** @type {ShapeItem} */ (item1).definition;
|
||||||
|
const definition2 = /** @type {ShapeItem} */ (item2).definition;
|
||||||
|
const result = system.root.shapeDefinitionMgr.shapeActionStack(definition1, definition2);
|
||||||
|
return system.root.shapeDefinitionMgr.getShapeItemFromDefinition(result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**@type {GeoZ.Mod}*/
|
||||||
|
const test = {
|
||||||
|
name: "test",
|
||||||
|
buildings: [MetaTestBuilding, MetaInvertedGatesBuilding],
|
||||||
|
processors: [SquareConverter],
|
||||||
|
wireProcessors: [NANDGate, NORGate, XNORGate, VirtualStacker],
|
||||||
|
shapes: [
|
||||||
|
{
|
||||||
|
id: "leaf",
|
||||||
|
code: "F",
|
||||||
|
draw: "M 0 0 v 0.5 a 0.5 0.5 0 0 0 0.5 0.5 h 0.5 v -0.5 a 0.5 0.5 0 0 0 -0.5 -0.5 z",
|
||||||
|
tier: 2,
|
||||||
|
spawnData: {
|
||||||
|
color: "yellow",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
export default test;
|
@ -145,7 +145,7 @@ export class Application {
|
|||||||
MobileWarningState,
|
MobileWarningState,
|
||||||
MainMenuState,
|
MainMenuState,
|
||||||
InGameState,
|
InGameState,
|
||||||
SettingsState,
|
//SettingsState,
|
||||||
KeybindingsState,
|
KeybindingsState,
|
||||||
AboutState,
|
AboutState,
|
||||||
ChangelogState,
|
ChangelogState,
|
||||||
|
@ -1,136 +1,136 @@
|
|||||||
import { queryParamOptions } from "./query_parameters";
|
import { queryParamOptions } from "./query_parameters";
|
||||||
|
|
||||||
export const IS_DEBUG =
|
export const IS_DEBUG =
|
||||||
G_IS_DEV &&
|
G_IS_DEV &&
|
||||||
typeof window !== "undefined" &&
|
typeof window !== "undefined" &&
|
||||||
window.location.port === "3005" &&
|
window.location.port === "3005" &&
|
||||||
(window.location.host.indexOf("localhost:") >= 0 || window.location.host.indexOf("192.168.0.") >= 0) &&
|
(window.location.host.indexOf("localhost:") >= 0 || window.location.host.indexOf("192.168.0.") >= 0) &&
|
||||||
window.location.search.indexOf("nodebug") < 0;
|
window.location.search.indexOf("nodebug") < 0;
|
||||||
|
|
||||||
export const IS_DEMO = queryParamOptions.fullVersion
|
export const IS_DEMO = queryParamOptions.fullVersion
|
||||||
? false
|
? false
|
||||||
: (!G_IS_DEV && !G_IS_STANDALONE) ||
|
: (!G_IS_DEV && !G_IS_STANDALONE) ||
|
||||||
(typeof window !== "undefined" && window.location.search.indexOf("demo") >= 0);
|
(typeof window !== "undefined" && window.location.search.indexOf("demo") >= 0);
|
||||||
|
|
||||||
export const SUPPORT_TOUCH = false;
|
export const SUPPORT_TOUCH = false;
|
||||||
|
|
||||||
const smoothCanvas = true;
|
const smoothCanvas = true;
|
||||||
|
|
||||||
export const THIRDPARTY_URLS = {
|
export const THIRDPARTY_URLS = {
|
||||||
discord: "https://discord.gg/HN7EVzV",
|
discord: "https://discord.gg/HN7EVzV",
|
||||||
github: "https://github.com/tobspr/shapez.io",
|
github: "https://github.com/tobspr/shapez.io",
|
||||||
reddit: "https://www.reddit.com/r/shapezio",
|
reddit: "https://www.reddit.com/r/shapezio",
|
||||||
|
|
||||||
standaloneStorePage: "https://store.steampowered.com/app/1318690/shapezio/",
|
standaloneStorePage: "https://store.steampowered.com/app/1318690/shapezio/",
|
||||||
};
|
};
|
||||||
|
|
||||||
export const globalConfig = {
|
export const globalConfig = {
|
||||||
// Size of a single tile in Pixels.
|
// Size of a single tile in Pixels.
|
||||||
// NOTICE: Update webpack.production.config too!
|
// NOTICE: Update webpack.production.config too!
|
||||||
tileSize: 32,
|
tileSize: 32,
|
||||||
halfTileSize: 16,
|
halfTileSize: 16,
|
||||||
|
|
||||||
// Which dpi the assets have
|
// Which dpi the assets have
|
||||||
assetsDpi: 192 / 32,
|
assetsDpi: 192 / 32,
|
||||||
assetsSharpness: 1.5,
|
assetsSharpness: 1.5,
|
||||||
shapesSharpness: 1.4,
|
shapesSharpness: 1.4,
|
||||||
|
|
||||||
// Production analytics
|
// Production analytics
|
||||||
statisticsGraphDpi: 2.5,
|
statisticsGraphDpi: 2.5,
|
||||||
statisticsGraphSlices: 100,
|
statisticsGraphSlices: 100,
|
||||||
analyticsSliceDurationSeconds: G_IS_DEV ? 1 : 10,
|
analyticsSliceDurationSeconds: G_IS_DEV ? 1 : 10,
|
||||||
|
|
||||||
minimumTickRate: 25,
|
minimumTickRate: 25,
|
||||||
maximumTickRate: 500,
|
maximumTickRate: 500,
|
||||||
|
|
||||||
// Map
|
// Map
|
||||||
mapChunkSize: 16,
|
mapChunkSize: 16,
|
||||||
mapChunkOverviewMinZoom: 0.9,
|
mapChunkOverviewMinZoom: 0.9,
|
||||||
mapChunkWorldSize: null, // COMPUTED
|
mapChunkWorldSize: null, // COMPUTED
|
||||||
|
|
||||||
// Belt speeds
|
// Belt speeds
|
||||||
// NOTICE: Update webpack.production.config too!
|
// NOTICE: Update webpack.production.config too!
|
||||||
beltSpeedItemsPerSecond: 2,
|
beltSpeedItemsPerSecond: 2,
|
||||||
minerSpeedItemsPerSecond: 0, // COMPUTED
|
minerSpeedItemsPerSecond: 0, // COMPUTED
|
||||||
|
|
||||||
defaultItemDiameter: 20,
|
defaultItemDiameter: 20,
|
||||||
|
|
||||||
itemSpacingOnBelts: 0.63,
|
itemSpacingOnBelts: 0.63,
|
||||||
|
|
||||||
wiresSpeedItemsPerSecond: 6,
|
wiresSpeedItemsPerSecond: 6,
|
||||||
|
|
||||||
undergroundBeltMaxTilesByTier: [5, 9],
|
undergroundBeltMaxTilesByTier: [5, 9],
|
||||||
|
|
||||||
readerAnalyzeIntervalSeconds: G_IS_DEV ? 3 : 10,
|
readerAnalyzeIntervalSeconds: G_IS_DEV ? 3 : 10,
|
||||||
|
|
||||||
buildingSpeeds: {
|
buildingSpeeds: {
|
||||||
cutter: 1 / 4,
|
cutter: 1 / 4,
|
||||||
cutterQuad: 1 / 4,
|
cutterQuad: 1 / 4,
|
||||||
rotater: 1 / 1,
|
rotater: 1 / 1,
|
||||||
rotaterCCW: 1 / 1,
|
rotaterCCW: 1 / 1,
|
||||||
rotaterFL: 1 / 1,
|
rotaterFL: 1 / 1,
|
||||||
painter: 1 / 6,
|
painter: 1 / 6,
|
||||||
painterDouble: 1 / 8,
|
painterDouble: 1 / 8,
|
||||||
painterQuad: 1 / 8,
|
painterQuad: 1 / 8,
|
||||||
mixer: 1 / 5,
|
mixer: 1 / 5,
|
||||||
stacker: 1 / 6,
|
stacker: 1 / 6,
|
||||||
},
|
},
|
||||||
|
|
||||||
// Zooming
|
// Zooming
|
||||||
initialZoom: 1.9,
|
initialZoom: 1.9,
|
||||||
minZoomLevel: 0.1,
|
minZoomLevel: 0.1,
|
||||||
maxZoomLevel: 3,
|
maxZoomLevel: 3,
|
||||||
|
|
||||||
// Global game speed
|
// Global game speed
|
||||||
gameSpeed: 1,
|
gameSpeed: 1,
|
||||||
|
|
||||||
warmupTimeSecondsFast: 0.1,
|
warmupTimeSecondsFast: 0.1,
|
||||||
warmupTimeSecondsRegular: 1,
|
warmupTimeSecondsRegular: 1,
|
||||||
|
|
||||||
smoothing: {
|
smoothing: {
|
||||||
smoothMainCanvas: smoothCanvas && true,
|
smoothMainCanvas: smoothCanvas && true,
|
||||||
quality: "low", // Low is CRUCIAL for mobile performance!
|
quality: "low", // Low is CRUCIAL for mobile performance!
|
||||||
},
|
},
|
||||||
|
|
||||||
rendering: {},
|
rendering: {},
|
||||||
debug: require("./config.local").default,
|
debug: G_IS_DEV ? require("./config.local").default : {},
|
||||||
|
|
||||||
// Secret vars
|
// Secret vars
|
||||||
info: {
|
info: {
|
||||||
// Binary file salt
|
// Binary file salt
|
||||||
file: "Ec'])@^+*9zMevK3uMV4432x9%iK'=",
|
file: "Ec'])@^+*9zMevK3uMV4432x9%iK'=",
|
||||||
|
|
||||||
// Savegame salt
|
// Savegame salt
|
||||||
sgSalt: "}95Q3%8/.837Lqym_BJx%q7)pAHJbF",
|
sgSalt: "}95Q3%8/.837Lqym_BJx%q7)pAHJbF",
|
||||||
|
|
||||||
// Analytics key
|
// Analytics key
|
||||||
analyticsApiKey: "baf6a50f0cc7dfdec5a0e21c88a1c69a4b34bc4a",
|
analyticsApiKey: "baf6a50f0cc7dfdec5a0e21c88a1c69a4b34bc4a",
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
export const IS_MOBILE = /iPhone|iPad|iPod|Android/i.test(navigator.userAgent);
|
export const IS_MOBILE = /iPhone|iPad|iPod|Android/i.test(navigator.userAgent);
|
||||||
|
|
||||||
// Automatic calculations
|
// Automatic calculations
|
||||||
globalConfig.minerSpeedItemsPerSecond = globalConfig.beltSpeedItemsPerSecond / 5;
|
globalConfig.minerSpeedItemsPerSecond = globalConfig.beltSpeedItemsPerSecond / 5;
|
||||||
|
|
||||||
globalConfig.mapChunkWorldSize = globalConfig.mapChunkSize * globalConfig.tileSize;
|
globalConfig.mapChunkWorldSize = globalConfig.mapChunkSize * globalConfig.tileSize;
|
||||||
|
|
||||||
// Dynamic calculations
|
// Dynamic calculations
|
||||||
if (globalConfig.debug.disableMapOverview) {
|
if (globalConfig.debug.disableMapOverview) {
|
||||||
globalConfig.mapChunkOverviewMinZoom = 0;
|
globalConfig.mapChunkOverviewMinZoom = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stuff for making the trailer
|
// Stuff for making the trailer
|
||||||
if (G_IS_DEV && globalConfig.debug.renderForTrailer) {
|
if (G_IS_DEV && globalConfig.debug.renderForTrailer) {
|
||||||
globalConfig.debug.framePausesBetweenTicks = 32;
|
globalConfig.debug.framePausesBetweenTicks = 32;
|
||||||
// globalConfig.mapChunkOverviewMinZoom = 0.0;
|
// globalConfig.mapChunkOverviewMinZoom = 0.0;
|
||||||
// globalConfig.debug.instantBelts = true;
|
// globalConfig.debug.instantBelts = true;
|
||||||
// globalConfig.debug.instantProcessors = true;
|
// globalConfig.debug.instantProcessors = true;
|
||||||
// globalConfig.debug.instantMiners = true;
|
// globalConfig.debug.instantMiners = true;
|
||||||
globalConfig.debug.disableSavegameWrite = true;
|
globalConfig.debug.disableSavegameWrite = true;
|
||||||
// globalConfig.beltSpeedItemsPerSecond *= 2;
|
// globalConfig.beltSpeedItemsPerSecond *= 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (globalConfig.debug.fastGameEnter) {
|
if (globalConfig.debug.fastGameEnter) {
|
||||||
globalConfig.debug.noArtificalDelays = true;
|
globalConfig.debug.noArtificalDelays = true;
|
||||||
}
|
}
|
||||||
|
@ -1,114 +1,114 @@
|
|||||||
export default {
|
export default {
|
||||||
// You can set any debug options here!
|
// You can set any debug options here!
|
||||||
/* dev:start */
|
/* dev:start */
|
||||||
// -----------------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------------
|
||||||
// Quickly enters the game and skips the main menu - good for fast iterating
|
_fastGameEnter: "Quickly enters the game and skips the main menu - good for fast iterating",
|
||||||
// fastGameEnter: true,
|
fastGameEnter: false,
|
||||||
// -----------------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------------
|
||||||
// Skips any delays like transitions between states and such
|
_noArtificialDelays: "Skips any delays like transitions between states and such",
|
||||||
// noArtificialDelays: true,
|
noArtificialDelays: false,
|
||||||
// -----------------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------------
|
||||||
// Disables writing of savegames, useful for testing the same savegame over and over
|
_disableSavegameWrite: "Disables writing of savegames, useful for testing the same savegame over and over",
|
||||||
// disableSavegameWrite: true,
|
disableSavegameWrite: false,
|
||||||
// -----------------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------------
|
||||||
// Shows bounds of all entities
|
_showEntityBounds: "Shows bounds of all entities",
|
||||||
// showEntityBounds: true,
|
showEntityBounds: false,
|
||||||
// -----------------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------------
|
||||||
// Shows arrows for every ejector / acceptor
|
_showAcceptorEjectors: "Shows arrows for every ejector / acceptor",
|
||||||
// showAcceptorEjectors: true,
|
showAcceptorEjectors: false,
|
||||||
// -----------------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------------
|
||||||
// Disables the music (Overrides any setting, can cause weird behaviour)
|
_disableMusic: "Disables the music (Overrides any setting, can cause weird behaviour)",
|
||||||
// disableMusic: true,
|
disableMusic: false,
|
||||||
// -----------------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------------
|
||||||
// Do not render static map entities (=most buildings)
|
_doNotRenderStatics: "Do not render static map entities (=most buildings)",
|
||||||
// doNotRenderStatics: true,
|
doNotRenderStatics: false,
|
||||||
// -----------------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------------
|
||||||
// Allow to zoom freely without limits
|
_disableZoomLimits: "Allow to zoom freely without limits",
|
||||||
// disableZoomLimits: true,
|
disableZoomLimits: false,
|
||||||
// -----------------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------------
|
||||||
// Shows a border arround every chunk
|
_showChunkBorders: "Shows a border arround every chunk",
|
||||||
// showChunkBorders: true,
|
showChunkBorders: false,
|
||||||
// -----------------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------------
|
||||||
// All rewards can be unlocked by passing just 1 of any shape
|
_rewardsInstant: "All rewards can be unlocked by passing just 1 of any shape",
|
||||||
// rewardsInstant: true,
|
rewardsInstant: false,
|
||||||
// -----------------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------------
|
||||||
// Unlocks all buildings
|
_allBuildingsUnlocked: "Unlocks all buildings",
|
||||||
// allBuildingsUnlocked: true,
|
allBuildingsUnlocked: false,
|
||||||
// -----------------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------------
|
||||||
// Disables cost of blueprints
|
_blueprintsNoCost: "Disables cost of blueprints",
|
||||||
// blueprintsNoCost: true,
|
blueprintsNoCost: false,
|
||||||
// -----------------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------------
|
||||||
// Disables cost of upgrades
|
_upgradesNoCost: "Disables cost of upgrades",
|
||||||
// upgradesNoCost: true,
|
upgradesNoCost: false,
|
||||||
// -----------------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------------
|
||||||
// Disables the dialog when completing a level
|
_disableUnlockDialog: "Disables the dialog when completing a level",
|
||||||
// disableUnlockDialog: true,
|
disableUnlockDialog: false,
|
||||||
// -----------------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------------
|
||||||
// Disables the simulation - This effectively pauses the game.
|
_disableLogicTicks: "Disables the simulation - This effectively pauses the game.",
|
||||||
// disableLogicTicks: true,
|
disableLogicTicks: false,
|
||||||
// -----------------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------------
|
||||||
// Test the rendering if everything is clipped out properly
|
_testClipping: "Test the rendering if everything is clipped out properly",
|
||||||
// testClipping: true,
|
testClipping: false,
|
||||||
// -----------------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------------
|
||||||
// Allows to render slower, useful for recording at half speed to avoid stuttering
|
// Allows to render slower, useful for recording at half speed to avoid stuttering
|
||||||
// framePausesBetweenTicks: 250,
|
// framePausesBetweenTicks: 250,
|
||||||
// -----------------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------------
|
||||||
// Replace all translations with emojis to see which texts are translateable
|
_testTranslations: "Replace all translations with emojis to see which texts are translateable",
|
||||||
// testTranslations: true,
|
testTranslations: false,
|
||||||
// -----------------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------------
|
||||||
// Enables an inspector which shows information about the entity below the curosr
|
_enableEntityInspector: "Enables an inspector which shows information about the entity below the curosr",
|
||||||
// enableEntityInspector: true,
|
enableEntityInspector: false,
|
||||||
// -----------------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------------
|
||||||
// Enables ads in the local build (normally they are deactivated there)
|
_testAds: "Enables ads in the local build (normally they are deactivated there)",
|
||||||
// testAds: true,
|
testAds: false,
|
||||||
// -----------------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------------
|
||||||
// Disables the automatic switch to an overview when zooming out
|
_disableMapOverview: "Disables the automatic switch to an overview when zooming out",
|
||||||
// disableMapOverview: true,
|
disableMapOverview: false,
|
||||||
// -----------------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------------
|
||||||
// Disables the notification when there are new entries in the changelog since last played
|
_disableUpgradeNotification: "Disables the notification when there are new entries in the changelog since last played",
|
||||||
// disableUpgradeNotification: true,
|
disableUpgradeNotification: false,
|
||||||
// -----------------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------------
|
||||||
// Makes belts almost infinitely fast
|
_instantBelts: "Makes belts almost infinitely fast",
|
||||||
// instantBelts: true,
|
instantBelts: false,
|
||||||
// -----------------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------------
|
||||||
// Makes item processors almost infinitely fast
|
_instantProcessors: "Makes item processors almost infinitely fast",
|
||||||
// instantProcessors: true,
|
instantProcessors: false,
|
||||||
// -----------------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------------
|
||||||
// Makes miners almost infinitely fast
|
_instantMiners: "Makes miners almost infinitely fast",
|
||||||
// instantMiners: true,
|
instantMiners: false,
|
||||||
// -----------------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------------
|
||||||
// When using fastGameEnter, controls whether a new game is started or the last one is resumed
|
_resumeGameOnFastEnter: "When using fastGameEnter, controls whether a new game is started or the last one is resumed",
|
||||||
// resumeGameOnFastEnter: true,
|
resumeGameOnFastEnter: false,
|
||||||
// -----------------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------------
|
||||||
// Special option used to render the trailer
|
_renderForTrailer: "Special option used to render the trailer",
|
||||||
// renderForTrailer: true,
|
renderForTrailer: false,
|
||||||
// -----------------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------------
|
||||||
// Whether to render changes
|
_renderChanges: "Whether to render changes",
|
||||||
// renderChanges: true,
|
renderChanges: false,
|
||||||
// -----------------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------------
|
||||||
// Whether to render belt paths
|
_renderBeltPaths: "Whether to render belt paths",
|
||||||
// renderBeltPaths: true,
|
renderBeltPaths: false,
|
||||||
// -----------------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------------
|
||||||
// Whether to check belt paths
|
_checkBeltPaths: "Whether to check belt paths",
|
||||||
// checkBeltPaths: true,
|
checkBeltPaths: false,
|
||||||
// -----------------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------------
|
||||||
// Whether to items / s instead of items / m in stats
|
_detailedStatistics: "Whether to items / s instead of items / m in stats",
|
||||||
// detailedStatistics: true,
|
detailedStatistics: false,
|
||||||
// -----------------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------------
|
||||||
// Shows detailed information about which atlas is used
|
// Shows detailed information about which atlas is used
|
||||||
// showAtlasInfo: true,
|
// showAtlasInfo: true,
|
||||||
// -----------------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------------
|
||||||
// Renders the rotation of all wires
|
// Renders the rotation of all wires
|
||||||
// renderWireRotations: true,
|
// renderWireRotations: true,
|
||||||
// -----------------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------------
|
||||||
// Renders information about wire networks
|
// Renders information about wire networks
|
||||||
// renderWireNetworkInfos: true,
|
// renderWireNetworkInfos: true,
|
||||||
// -----------------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------------
|
||||||
// Disables ejector animations and processing
|
// Disables ejector animations and processing
|
||||||
// disableEjectorProcessing: true,
|
// disableEjectorProcessing: true,
|
||||||
// -----------------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------------
|
||||||
// Allows manual ticking
|
// Allows manual ticking
|
||||||
// manualTickOnly: true,
|
// manualTickOnly: true,
|
||||||
// -----------------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------------
|
||||||
/* dev:end */
|
/* dev:end */
|
||||||
};
|
};
|
||||||
|
@ -71,7 +71,23 @@ export class TextualGameState extends GameState {
|
|||||||
backToStatePayload: this.backToStatePayload,
|
backToStatePayload: this.backToStatePayload,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Goes to a new state, telling him to go back to this state later
|
||||||
|
* @param {string} stateId
|
||||||
|
*/
|
||||||
|
switchToState(stateId) {
|
||||||
|
// debugger;
|
||||||
|
this.moveToState(
|
||||||
|
stateId,
|
||||||
|
{
|
||||||
|
backToStateId: this.backToStateId,
|
||||||
|
backToStatePayload: this.backToStatePayload,
|
||||||
|
},
|
||||||
|
true
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Removes all click detectors, except the one on the back button. Useful when regenerating
|
* Removes all click detectors, except the one on the back button. Useful when regenerating
|
||||||
|
@ -19,7 +19,7 @@ import { Vector } from "../core/vector";
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Stores a lookup table for all building variants (for better performance)
|
* Stores a lookup table for all building variants (for better performance)
|
||||||
* @type {Object<number, BuildingVariantIdentifier>}
|
* @type {{[x: string]: BuildingVariantIdentifier, [x: number]: BuildingVariantIdentifier}}
|
||||||
*/
|
*/
|
||||||
export const gBuildingVariants = {
|
export const gBuildingVariants = {
|
||||||
// Set later
|
// Set later
|
||||||
@ -27,7 +27,7 @@ export const gBuildingVariants = {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Registers a new variant
|
* Registers a new variant
|
||||||
* @param {number} id
|
* @param {number | string} id
|
||||||
* @param {typeof MetaBuilding} meta
|
* @param {typeof MetaBuilding} meta
|
||||||
* @param {string} variant
|
* @param {string} variant
|
||||||
* @param {number} rotationVariant
|
* @param {number} rotationVariant
|
||||||
@ -50,7 +50,7 @@ export function registerBuildingVariant(
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param {number} code
|
* @param {number | string} code
|
||||||
* @returns {BuildingVariantIdentifier}
|
* @returns {BuildingVariantIdentifier}
|
||||||
*/
|
*/
|
||||||
export function getBuildingDataFromCode(code) {
|
export function getBuildingDataFromCode(code) {
|
||||||
@ -72,12 +72,12 @@ export function getCodeFromBuildingData(metaBuilding, variant, rotationVariant)
|
|||||||
data.variant === variant &&
|
data.variant === variant &&
|
||||||
data.rotationVariant === rotationVariant
|
data.rotationVariant === rotationVariant
|
||||||
) {
|
) {
|
||||||
return +key;
|
return key;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
assertAlways(
|
assertAlways(
|
||||||
false,
|
false,
|
||||||
"Building not found by data: " + metaBuilding.getId() + " / " + variant + " / " + rotationVariant
|
"Building not found by data: " + metaBuilding.getId() + " / " + variant + " / " + rotationVariant
|
||||||
);
|
);
|
||||||
return 0;
|
return "0";
|
||||||
}
|
}
|
||||||
|
@ -44,7 +44,7 @@ export function initComponentRegistry() {
|
|||||||
|
|
||||||
assert(
|
assert(
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
require.context("./components", false, /.*\.js/i).keys().length ===
|
require.context("./components", false, /.*\.js/i).keys().length >=
|
||||||
gComponentRegistry.getNumEntries(),
|
gComponentRegistry.getNumEntries(),
|
||||||
"Not all components are registered"
|
"Not all components are registered"
|
||||||
);
|
);
|
||||||
|
@ -19,7 +19,7 @@ export class StaticMapEntityComponent extends Component {
|
|||||||
originalRotation: types.float,
|
originalRotation: types.float,
|
||||||
|
|
||||||
// See building_codes.js
|
// See building_codes.js
|
||||||
code: types.uint,
|
code: types.string,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -79,7 +79,7 @@ export class StaticMapEntityComponent extends Component {
|
|||||||
* @param {Vector=} param0.tileSize Size of the entity in tiles
|
* @param {Vector=} param0.tileSize Size of the entity in tiles
|
||||||
* @param {number=} param0.rotation Rotation in degrees. Must be multiple of 90
|
* @param {number=} param0.rotation Rotation in degrees. Must be multiple of 90
|
||||||
* @param {number=} param0.originalRotation Original Rotation in degrees. Must be multiple of 90
|
* @param {number=} param0.originalRotation Original Rotation in degrees. Must be multiple of 90
|
||||||
* @param {number=} param0.code Building code
|
* @param {(number | string)=} param0.code Building code
|
||||||
*/
|
*/
|
||||||
constructor({
|
constructor({
|
||||||
origin = new Vector(),
|
origin = new Vector(),
|
||||||
@ -96,7 +96,7 @@ export class StaticMapEntityComponent extends Component {
|
|||||||
|
|
||||||
this.origin = origin;
|
this.origin = origin;
|
||||||
this.rotation = rotation;
|
this.rotation = rotation;
|
||||||
this.code = code;
|
this.code = code.toString();
|
||||||
this.originalRotation = originalRotation;
|
this.originalRotation = originalRotation;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -189,7 +189,7 @@ export class Entity extends BasicSerializableObject {
|
|||||||
const acceptorComp = this.components.ItemAcceptor;
|
const acceptorComp = this.components.ItemAcceptor;
|
||||||
|
|
||||||
if (acceptorComp) {
|
if (acceptorComp) {
|
||||||
const acceptorSprite = Loader.getSprite("sprites/misc/acceptor_slot.png");
|
const acceptorSprite = Loader.getSprite("sprites/debug/acceptor_slot.png");
|
||||||
for (let i = 0; i < acceptorComp.slots.length; ++i) {
|
for (let i = 0; i < acceptorComp.slots.length; ++i) {
|
||||||
const slot = acceptorComp.slots[i];
|
const slot = acceptorComp.slots[i];
|
||||||
const slotTile = staticComp.localTileToWorld(slot.pos);
|
const slotTile = staticComp.localTileToWorld(slot.pos);
|
||||||
|
@ -22,6 +22,7 @@ import { LeverSystem } from "./systems/lever";
|
|||||||
import { DisplaySystem } from "./systems/display";
|
import { DisplaySystem } from "./systems/display";
|
||||||
import { ItemProcessorOverlaysSystem } from "./systems/item_processor_overlays";
|
import { ItemProcessorOverlaysSystem } from "./systems/item_processor_overlays";
|
||||||
import { BeltReaderSystem } from "./systems/belt_reader";
|
import { BeltReaderSystem } from "./systems/belt_reader";
|
||||||
|
import { ModSystems, logger as GeoZLogger } from "../GeoZ/main";
|
||||||
|
|
||||||
const logger = createLogger("game_system_manager");
|
const logger = createLogger("game_system_manager");
|
||||||
|
|
||||||
@ -153,6 +154,55 @@ export class GameSystemManager {
|
|||||||
|
|
||||||
add("itemProcessorOverlays", ItemProcessorOverlaysSystem);
|
add("itemProcessorOverlays", ItemProcessorOverlaysSystem);
|
||||||
|
|
||||||
|
for (const system of ModSystems) {
|
||||||
|
const before = system.getUpdateBefore();
|
||||||
|
const after = system.getUpdateAfter();
|
||||||
|
const system_id = system.getId();
|
||||||
|
let override = false;
|
||||||
|
|
||||||
|
if (this.systems[system_id]) {
|
||||||
|
GeoZLogger.log(
|
||||||
|
`⚠️ WARNING ⚠️ A system with the ID "${system_id}" already exists and will be overriden`
|
||||||
|
);
|
||||||
|
override = true;
|
||||||
|
}
|
||||||
|
this.systems[system_id] = new system(this.root);
|
||||||
|
|
||||||
|
if (!override) {
|
||||||
|
if (before) {
|
||||||
|
const i = this.systemUpdateOrder.indexOf(before);
|
||||||
|
if (i !== -1) {
|
||||||
|
this.systemUpdateOrder.splice(i, 0, system_id);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
GeoZLogger.log(
|
||||||
|
`⚠️ WARNING ⚠️ System "${before}" not found and so system "${system_id}" can't be updated before it`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (after) {
|
||||||
|
const i = this.systemUpdateOrder.indexOf(after);
|
||||||
|
if (i !== -1) {
|
||||||
|
this.systemUpdateOrder.splice(i + 1, 0, system_id);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
GeoZLogger.log(
|
||||||
|
`⚠️ WARNING ⚠️ System "${after}" not found and so system "${system_id}" can't be updated after it`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this.systemUpdateOrder.includes(system_id)) {
|
||||||
|
this.systemUpdateOrder.push(system_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (override) {
|
||||||
|
GeoZLogger.log(
|
||||||
|
`System "${system_id}" update order : ${this.systemUpdateOrder.indexOf(system_id)}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
logger.log("📦 There are", this.systemUpdateOrder.length, "game systems");
|
logger.log("📦 There are", this.systemUpdateOrder.length, "game systems");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,11 +2,13 @@ import { globalConfig } from "../core/config";
|
|||||||
import { clamp, findNiceIntegerValue, randomChoice, randomInt } from "../core/utils";
|
import { clamp, findNiceIntegerValue, randomChoice, randomInt } from "../core/utils";
|
||||||
import { BasicSerializableObject, types } from "../savegame/serialization";
|
import { BasicSerializableObject, types } from "../savegame/serialization";
|
||||||
import { enumColors } from "./colors";
|
import { enumColors } from "./colors";
|
||||||
|
import { allShapeData } from "./shapes";
|
||||||
import { enumItemProcessorTypes } from "./components/item_processor";
|
import { enumItemProcessorTypes } from "./components/item_processor";
|
||||||
import { GameRoot } from "./root";
|
import { GameRoot } from "./root";
|
||||||
import { enumSubShape, ShapeDefinition } from "./shape_definition";
|
import { ShapeDefinition, ShapeLayer } from "./shape_definition";
|
||||||
import { enumHubGoalRewards, tutorialGoals } from "./tutorial_goals";
|
import { enumHubGoalRewards, tutorialGoals } from "./tutorial_goals";
|
||||||
import { UPGRADES } from "./upgrades";
|
import { UPGRADES } from "./upgrades";
|
||||||
|
import { ModProcessors } from "../GeoZ/main";
|
||||||
|
|
||||||
export class HubGoals extends BasicSerializableObject {
|
export class HubGoals extends BasicSerializableObject {
|
||||||
static getId() {
|
static getId() {
|
||||||
@ -324,16 +326,16 @@ export class HubGoals extends BasicSerializableObject {
|
|||||||
*/
|
*/
|
||||||
createRandomShape() {
|
createRandomShape() {
|
||||||
const layerCount = clamp(this.level / 25, 2, 4);
|
const layerCount = clamp(this.level / 25, 2, 4);
|
||||||
/** @type {Array<import("./shape_definition").ShapeLayer>} */
|
/** @type {Array<ShapeLayer>} */
|
||||||
let layers = [];
|
let layers = [];
|
||||||
|
|
||||||
const randomColor = () => randomChoice(Object.values(enumColors));
|
const randomColor = () => randomChoice(Object.values(enumColors));
|
||||||
const randomShape = () => randomChoice(Object.values(enumSubShape));
|
const randomShape = () => randomChoice(Object.values(allShapeData).map(d => d.id));
|
||||||
|
|
||||||
let anyIsMissingTwo = false;
|
let anyIsMissingTwo = false;
|
||||||
|
|
||||||
for (let i = 0; i < layerCount; ++i) {
|
for (let i = 0; i < layerCount; ++i) {
|
||||||
/** @type {import("./shape_definition").ShapeLayer} */
|
/** @type {ShapeLayer} */
|
||||||
const layer = [null, null, null, null];
|
const layer = [null, null, null, null];
|
||||||
|
|
||||||
for (let quad = 0; quad < 4; ++quad) {
|
for (let quad = 0; quad < 4; ++quad) {
|
||||||
@ -439,8 +441,17 @@ export class HubGoals extends BasicSerializableObject {
|
|||||||
globalConfig.buildingSpeeds[processorType]
|
globalConfig.buildingSpeeds[processorType]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
default:
|
default: {
|
||||||
|
if (ModProcessors[processorType]) {
|
||||||
|
return (
|
||||||
|
globalConfig.beltSpeedItemsPerSecond *
|
||||||
|
this.upgradeImprovements.processors *
|
||||||
|
globalConfig.buildingSpeeds[processorType]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
assertAlways(false, "invalid processor type: " + processorType);
|
assertAlways(false, "invalid processor type: " + processorType);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 1 / globalConfig.beltSpeedItemsPerSecond;
|
return 1 / globalConfig.beltSpeedItemsPerSecond;
|
||||||
|
@ -13,8 +13,12 @@ import { MetaLeverBuilding } from "../../buildings/lever";
|
|||||||
import { MetaFilterBuilding } from "../../buildings/filter";
|
import { MetaFilterBuilding } from "../../buildings/filter";
|
||||||
import { MetaDisplayBuilding } from "../../buildings/display";
|
import { MetaDisplayBuilding } from "../../buildings/display";
|
||||||
import { MetaReaderBuilding } from "../../buildings/reader";
|
import { MetaReaderBuilding } from "../../buildings/reader";
|
||||||
|
import { MetaBuilding } from "../../meta_building";
|
||||||
|
|
||||||
const supportedBuildings = [
|
/**
|
||||||
|
* @type {Array<typeof MetaBuilding>}
|
||||||
|
*/
|
||||||
|
export const supportedBuildings = [
|
||||||
MetaBeltBaseBuilding,
|
MetaBeltBaseBuilding,
|
||||||
MetaSplitterBuilding,
|
MetaSplitterBuilding,
|
||||||
MetaUndergroundBeltBuilding,
|
MetaUndergroundBeltBuilding,
|
||||||
|
@ -7,7 +7,7 @@ import { Application } from "../application";
|
|||||||
import { Signal, STOP_PROPAGATION } from "../core/signal";
|
import { Signal, STOP_PROPAGATION } from "../core/signal";
|
||||||
import { IS_MOBILE } from "../core/config";
|
import { IS_MOBILE } from "../core/config";
|
||||||
import { T } from "../translations";
|
import { T } from "../translations";
|
||||||
function key(str) {
|
export function key(str) {
|
||||||
return str.toUpperCase().charCodeAt(0);
|
return str.toUpperCase().charCodeAt(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,10 +5,11 @@ import { clamp, fastArrayDeleteValueIfContained, make2DUndefinedArray } from "..
|
|||||||
import { Vector } from "../core/vector";
|
import { Vector } from "../core/vector";
|
||||||
import { BaseItem } from "./base_item";
|
import { BaseItem } from "./base_item";
|
||||||
import { enumColors } from "./colors";
|
import { enumColors } from "./colors";
|
||||||
|
import { allShapeData } from "./shapes";
|
||||||
import { Entity } from "./entity";
|
import { Entity } from "./entity";
|
||||||
import { COLOR_ITEM_SINGLETONS } from "./items/color_item";
|
import { COLOR_ITEM_SINGLETONS } from "./items/color_item";
|
||||||
import { GameRoot } from "./root";
|
import { GameRoot } from "./root";
|
||||||
import { enumSubShape } from "./shape_definition";
|
import { enumSubShape } from "./shapes";
|
||||||
import { Rectangle } from "../core/rectangle";
|
import { Rectangle } from "../core/rectangle";
|
||||||
|
|
||||||
const logger = createLogger("map_chunk");
|
const logger = createLogger("map_chunk");
|
||||||
@ -180,56 +181,58 @@ export class MapChunk {
|
|||||||
*/
|
*/
|
||||||
internalGenerateShapePatch(rng, shapePatchSize, distanceToOriginInChunks) {
|
internalGenerateShapePatch(rng, shapePatchSize, distanceToOriginInChunks) {
|
||||||
/** @type {[enumSubShape, enumSubShape, enumSubShape, enumSubShape]} */
|
/** @type {[enumSubShape, enumSubShape, enumSubShape, enumSubShape]} */
|
||||||
let subShapes = null;
|
let quads = null;
|
||||||
|
|
||||||
let weights = {};
|
let weights = {};
|
||||||
|
for (let s in allShapeData) {
|
||||||
// Later there is a mix of everything
|
const data = allShapeData[s];
|
||||||
weights = {
|
if (!data.spawnData || distanceToOriginInChunks < data.spawnData.minDistance) {
|
||||||
[enumSubShape.rect]: 100,
|
continue;
|
||||||
[enumSubShape.circle]: Math.round(50 + clamp(distanceToOriginInChunks * 2, 0, 50)),
|
}
|
||||||
[enumSubShape.star]: Math.round(20 + clamp(distanceToOriginInChunks, 0, 30)),
|
const chances = data.spawnData.chances;
|
||||||
[enumSubShape.windmill]: Math.round(6 + clamp(distanceToOriginInChunks / 2, 0, 20)),
|
const chance = Math.round(
|
||||||
};
|
clamp(
|
||||||
|
chances.min + (distanceToOriginInChunks - data.spawnData.minDistance) * chances.distanceMultiplier,
|
||||||
if (distanceToOriginInChunks < 7) {
|
0,
|
||||||
// Initial chunks can not spawn the good stuff
|
chances.max
|
||||||
weights[enumSubShape.star] = 0;
|
)
|
||||||
weights[enumSubShape.windmill] = 0;
|
);
|
||||||
}
|
if (chance) {
|
||||||
|
weights[data.id] = chance;
|
||||||
if (distanceToOriginInChunks < 10) {
|
|
||||||
// Initial chunk patches always have the same shape
|
|
||||||
const subShape = this.internalGenerateRandomSubShape(rng, weights);
|
|
||||||
subShapes = [subShape, subShape, subShape, subShape];
|
|
||||||
} else if (distanceToOriginInChunks < 15) {
|
|
||||||
// Later patches can also have mixed ones
|
|
||||||
const subShapeA = this.internalGenerateRandomSubShape(rng, weights);
|
|
||||||
const subShapeB = this.internalGenerateRandomSubShape(rng, weights);
|
|
||||||
subShapes = [subShapeA, subShapeA, subShapeB, subShapeB];
|
|
||||||
} else {
|
|
||||||
// Finally there is a mix of everything
|
|
||||||
subShapes = [
|
|
||||||
this.internalGenerateRandomSubShape(rng, weights),
|
|
||||||
this.internalGenerateRandomSubShape(rng, weights),
|
|
||||||
this.internalGenerateRandomSubShape(rng, weights),
|
|
||||||
this.internalGenerateRandomSubShape(rng, weights),
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Makes sure windmills never spawn as whole
|
|
||||||
let windmillCount = 0;
|
|
||||||
for (let i = 0; i < subShapes.length; ++i) {
|
|
||||||
if (subShapes[i] === enumSubShape.windmill) {
|
|
||||||
++windmillCount;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (windmillCount > 1) {
|
quads = [
|
||||||
subShapes[0] = enumSubShape.rect;
|
this.internalGenerateRandomSubShape(rng, weights),
|
||||||
subShapes[1] = enumSubShape.rect;
|
this.internalGenerateRandomSubShape(rng, weights),
|
||||||
|
this.internalGenerateRandomSubShape(rng, weights),
|
||||||
|
this.internalGenerateRandomSubShape(rng, weights),
|
||||||
|
];
|
||||||
|
if (distanceToOriginInChunks < 10) {
|
||||||
|
// Initial chunk patches always have the same shape
|
||||||
|
quads = [quads[0], quads[0], quads[0], quads[0]];
|
||||||
|
} else if (distanceToOriginInChunks < 15) {
|
||||||
|
// Later patches can also have mixed ones
|
||||||
|
quads = [quads[0], quads[0], quads[1], quads[1]];
|
||||||
|
} else {
|
||||||
|
// if (quads[0] == quads[2] && quads[0] != quads[3] && quads[0] != quads[1]) {
|
||||||
|
// quads = [quads[0], quads[2], quads[1], quads[3]];
|
||||||
|
// }
|
||||||
|
// if (quads[1] == quads[3] && quads[1] != quads[0] && quads[1] != quads[2]) {
|
||||||
|
// quads = [quads[0], quads[2], quads[1], quads[3]];
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
const definition = this.root.shapeDefinitionMgr.getDefinitionFromSimpleShapes(subShapes);
|
if (
|
||||||
|
quads.filter(q => q == quads[0]).length > allShapeData[quads[0]].spawnData.maxQuarters ||
|
||||||
|
quads.filter(q => q == quads[1]).length > allShapeData[quads[1]].spawnData.maxQuarters ||
|
||||||
|
quads.filter(q => q == quads[2]).length > allShapeData[quads[2]].spawnData.maxQuarters
|
||||||
|
) {
|
||||||
|
return this.internalGenerateShapePatch(rng, shapePatchSize, distanceToOriginInChunks);
|
||||||
|
}
|
||||||
|
|
||||||
|
let colors = /** @type {[string, string, string, string]} */ (quads.map(q => allShapeData[q].spawnData.color));
|
||||||
|
|
||||||
|
const definition = this.root.shapeDefinitionMgr.getDefinitionFromSimpleShapesAndColors(quads, colors);
|
||||||
this.internalGeneratePatch(
|
this.internalGeneratePatch(
|
||||||
rng,
|
rng,
|
||||||
shapePatchSize,
|
shapePatchSize,
|
||||||
|
@ -6,6 +6,7 @@ import { Vector } from "../core/vector";
|
|||||||
import { BasicSerializableObject, types } from "../savegame/serialization";
|
import { BasicSerializableObject, types } from "../savegame/serialization";
|
||||||
import { enumColors, enumColorsToHexCode, enumColorToShortcode, enumShortcodeToColor } from "./colors";
|
import { enumColors, enumColorsToHexCode, enumColorToShortcode, enumShortcodeToColor } from "./colors";
|
||||||
import { THEME } from "./theme";
|
import { THEME } from "./theme";
|
||||||
|
import { allShapeData, ShapeData, enumShortcodeToSubShape, enumSubShapeToShortcode, enumSubShape } from "./shapes";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @typedef {{
|
* @typedef {{
|
||||||
@ -26,28 +27,6 @@ const arrayQuadrantIndexToOffset = [
|
|||||||
new Vector(-1, -1), // tl
|
new Vector(-1, -1), // tl
|
||||||
];
|
];
|
||||||
|
|
||||||
/** @enum {string} */
|
|
||||||
export const enumSubShape = {
|
|
||||||
rect: "rect",
|
|
||||||
circle: "circle",
|
|
||||||
star: "star",
|
|
||||||
windmill: "windmill",
|
|
||||||
};
|
|
||||||
|
|
||||||
/** @enum {string} */
|
|
||||||
export const enumSubShapeToShortcode = {
|
|
||||||
[enumSubShape.rect]: "R",
|
|
||||||
[enumSubShape.circle]: "C",
|
|
||||||
[enumSubShape.star]: "S",
|
|
||||||
[enumSubShape.windmill]: "W",
|
|
||||||
};
|
|
||||||
|
|
||||||
/** @enum {enumSubShape} */
|
|
||||||
export const enumShortcodeToSubShape = {};
|
|
||||||
for (const key in enumSubShapeToShortcode) {
|
|
||||||
enumShortcodeToSubShape[enumSubShapeToShortcode[key]] = key;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Converts the given parameters to a valid shape definition
|
* Converts the given parameters to a valid shape definition
|
||||||
* @param {*} layers
|
* @param {*} layers
|
||||||
@ -85,6 +64,7 @@ export class ShapeDefinition extends BasicSerializableObject {
|
|||||||
return errorCode;
|
return errorCode;
|
||||||
}
|
}
|
||||||
const definition = ShapeDefinition.fromShortKey(data);
|
const definition = ShapeDefinition.fromShortKey(data);
|
||||||
|
/** @type {Array<ShapeLayer>} */
|
||||||
this.layers = /** @type {Array<ShapeLayer>} */ (definition.layers);
|
this.layers = /** @type {Array<ShapeLayer>} */ (definition.layers);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -336,97 +316,98 @@ export class ShapeDefinition extends BasicSerializableObject {
|
|||||||
for (let layerIndex = 0; layerIndex < this.layers.length; ++layerIndex) {
|
for (let layerIndex = 0; layerIndex < this.layers.length; ++layerIndex) {
|
||||||
const quadrants = this.layers[layerIndex];
|
const quadrants = this.layers[layerIndex];
|
||||||
|
|
||||||
|
let quads = quadrants
|
||||||
|
.map((e, i) => ({ e, i }))
|
||||||
|
.filter(e => e.e)
|
||||||
|
.map(e => ({ ...e.e, quadrantIndex: e.i }))
|
||||||
const layerScale = Math.max(0.1, 0.9 - layerIndex * 0.22);
|
const layerScale = Math.max(0.1, 0.9 - layerIndex * 0.22);
|
||||||
|
|
||||||
for (let quadrantIndex = 0; quadrantIndex < 4; ++quadrantIndex) {
|
for (let quad of quads) {
|
||||||
if (!quadrants[quadrantIndex]) {
|
if (!quad) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const { subShape, color, quadrantIndex } = quad;
|
||||||
|
if (subShape == "-") {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
const { subShape, color } = quadrants[quadrantIndex];
|
|
||||||
|
|
||||||
const quadrantPos = arrayQuadrantIndexToOffset[quadrantIndex];
|
const quadrantPos = arrayQuadrantIndexToOffset[quadrantIndex];
|
||||||
|
|
||||||
const centerQuadrantX = quadrantPos.x * quadrantHalfSize;
|
const centerQuadrantX = quadrantPos.x * quadrantHalfSize;
|
||||||
const centerQuadrantY = quadrantPos.y * quadrantHalfSize;
|
const centerQuadrantY = quadrantPos.y * quadrantHalfSize;
|
||||||
|
|
||||||
const rotation = Math.radians(quadrantIndex * 90);
|
const rotation = Math.radians(quadrantIndex * 90);
|
||||||
|
|
||||||
|
context.save();
|
||||||
context.translate(centerQuadrantX, centerQuadrantY);
|
context.translate(centerQuadrantX, centerQuadrantY);
|
||||||
context.rotate(rotation);
|
context.rotate(rotation);
|
||||||
|
|
||||||
context.fillStyle = enumColorsToHexCode[color];
|
context.fillStyle = enumColorsToHexCode[color];
|
||||||
context.strokeStyle = THEME.items.outline;
|
context.strokeStyle = THEME.items.outline;
|
||||||
context.lineWidth = THEME.items.outlineWidth;
|
const lineWidth = THEME.items.outlineWidth * Math.pow(0.8, layerIndex);
|
||||||
|
context.lineWidth = lineWidth;
|
||||||
|
|
||||||
const insetPadding = 0.0;
|
const insetPadding = 0.0;
|
||||||
|
|
||||||
switch (subShape) {
|
const dims = quadrantSize * layerScale;
|
||||||
case enumSubShape.rect: {
|
const innerDims = insetPadding - quadrantHalfSize;
|
||||||
context.beginPath();
|
|
||||||
const dims = quadrantSize * layerScale;
|
let began = null;
|
||||||
context.rect(
|
// eslint-disable-next-line no-inner-declarations
|
||||||
insetPadding + -quadrantHalfSize,
|
/** @type {import("./shapes").BeginDrawShape} */
|
||||||
-insetPadding + quadrantHalfSize - dims,
|
function begin(args) {
|
||||||
dims,
|
context.save();
|
||||||
dims
|
context.translate(innerDims, -innerDims);
|
||||||
);
|
context.scale(dims, -dims);
|
||||||
|
context.lineWidth = lineWidth / dims / (args.scale || 1);
|
||||||
break;
|
if (args.scale) {
|
||||||
|
context.scale(args.scale, args.scale);
|
||||||
}
|
}
|
||||||
case enumSubShape.star: {
|
if (args.beginPath) {
|
||||||
context.beginPath();
|
context.beginPath();
|
||||||
const dims = quadrantSize * layerScale;
|
}
|
||||||
|
if (args.moveToZero) {
|
||||||
let originX = insetPadding - quadrantHalfSize;
|
context.moveTo(0, 0);
|
||||||
let originY = -insetPadding + quadrantHalfSize - dims;
|
}
|
||||||
|
began = args;
|
||||||
const moveInwards = dims * 0.4;
|
}
|
||||||
context.moveTo(originX, originY + moveInwards);
|
// eslint-disable-next-line no-inner-declarations
|
||||||
context.lineTo(originX + dims, originY);
|
function end() {
|
||||||
context.lineTo(originX + dims - moveInwards, originY + dims);
|
if (!began) {
|
||||||
context.lineTo(originX, originY + dims);
|
return;
|
||||||
|
}
|
||||||
|
if (began.path) {
|
||||||
context.closePath();
|
context.closePath();
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case enumSubShape.windmill: {
|
|
||||||
context.beginPath();
|
|
||||||
const dims = quadrantSize * layerScale;
|
|
||||||
|
|
||||||
let originX = insetPadding - quadrantHalfSize;
|
|
||||||
let originY = -insetPadding + quadrantHalfSize - dims;
|
|
||||||
const moveInwards = dims * 0.4;
|
|
||||||
context.moveTo(originX, originY + moveInwards);
|
|
||||||
context.lineTo(originX + dims, originY);
|
|
||||||
context.lineTo(originX + dims, originY + dims);
|
|
||||||
context.lineTo(originX, originY + dims);
|
|
||||||
context.closePath();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case enumSubShape.circle: {
|
|
||||||
context.beginPath();
|
|
||||||
context.moveTo(insetPadding + -quadrantHalfSize, -insetPadding + quadrantHalfSize);
|
|
||||||
context.arc(
|
|
||||||
insetPadding + -quadrantHalfSize,
|
|
||||||
-insetPadding + quadrantHalfSize,
|
|
||||||
quadrantSize * layerScale,
|
|
||||||
-Math.PI * 0.5,
|
|
||||||
0
|
|
||||||
);
|
|
||||||
context.closePath();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
default: {
|
|
||||||
assertAlways(false, "Unkown sub shape: " + subShape);
|
|
||||||
}
|
}
|
||||||
|
context.restore();
|
||||||
}
|
}
|
||||||
|
|
||||||
context.fill();
|
/** @type {ShapeData} */
|
||||||
context.stroke();
|
let shape = allShapeData[subShape];
|
||||||
|
assertAlways(shape.draw, "shape should be drawable!");
|
||||||
|
if (typeof shape.draw === "string") {
|
||||||
|
let draw = shape.draw;
|
||||||
|
begin({ scale: 1 });
|
||||||
|
let p = new Path2D(draw);
|
||||||
|
context.fill(p);
|
||||||
|
context.stroke(p);
|
||||||
|
end();
|
||||||
|
} else {
|
||||||
|
shape.draw({
|
||||||
|
dims,
|
||||||
|
innerDims,
|
||||||
|
layer: layerIndex,
|
||||||
|
quadrant: quadrantIndex,
|
||||||
|
context,
|
||||||
|
color,
|
||||||
|
begin,
|
||||||
|
});
|
||||||
|
end();
|
||||||
|
context.fill();
|
||||||
|
context.stroke();
|
||||||
|
}
|
||||||
|
|
||||||
context.rotate(-rotation);
|
context.restore();
|
||||||
context.translate(-centerQuadrantX, -centerQuadrantY);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,8 @@ import { BasicSerializableObject } from "../savegame/serialization";
|
|||||||
import { enumColors } from "./colors";
|
import { enumColors } from "./colors";
|
||||||
import { ShapeItem } from "./items/shape_item";
|
import { ShapeItem } from "./items/shape_item";
|
||||||
import { GameRoot } from "./root";
|
import { GameRoot } from "./root";
|
||||||
import { enumSubShape, ShapeDefinition } from "./shape_definition";
|
import { ShapeDefinition } from "./shape_definition";
|
||||||
|
import { enumSubShape } from "./shapes";
|
||||||
|
|
||||||
const logger = createLogger("shape_definition_manager");
|
const logger = createLogger("shape_definition_manager");
|
||||||
|
|
||||||
@ -256,4 +257,18 @@ export class ShapeDefinitionManager extends BasicSerializableObject {
|
|||||||
|
|
||||||
return this.registerOrReturnHandle(new ShapeDefinition({ layers: [shapeLayer] }));
|
return this.registerOrReturnHandle(new ShapeDefinition({ layers: [shapeLayer] }));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {[enumSubShape, enumSubShape, enumSubShape, enumSubShape]} subShapes
|
||||||
|
* @param {[string, string, string, string]} colors
|
||||||
|
* @returns {ShapeDefinition}
|
||||||
|
*/
|
||||||
|
getDefinitionFromSimpleShapesAndColors(subShapes, colors) {
|
||||||
|
const shapeLayer = /** @type {import("./shape_definition").ShapeLayer} */ (subShapes.map(
|
||||||
|
(subShape, i) => ({ subShape, color: colors[i] })
|
||||||
|
));
|
||||||
|
|
||||||
|
return this.registerOrReturnHandle(new ShapeDefinition({ layers: [shapeLayer] }));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
181
src/js/game/shapes.js
Normal file
181
src/js/game/shapes.js
Normal file
@ -0,0 +1,181 @@
|
|||||||
|
/** @enum {string} */
|
||||||
|
export const enumSubShape = {
|
||||||
|
rect: "rect",
|
||||||
|
circle: "circle",
|
||||||
|
star: "star",
|
||||||
|
windmill: "windmill",
|
||||||
|
};
|
||||||
|
|
||||||
|
/** @enum {string} */
|
||||||
|
export const enumSubShapeToShortcode = {
|
||||||
|
[enumSubShape.rect]: "R",
|
||||||
|
[enumSubShape.circle]: "C",
|
||||||
|
[enumSubShape.star]: "S",
|
||||||
|
[enumSubShape.windmill]: "W",
|
||||||
|
};
|
||||||
|
|
||||||
|
/** @enum {enumSubShape} */
|
||||||
|
export const enumShortcodeToSubShape = {};
|
||||||
|
for (const key in enumSubShapeToShortcode) {
|
||||||
|
enumShortcodeToSubShape[enumSubShapeToShortcode[key]] = key;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @callback BeginDrawShape
|
||||||
|
* @param {{
|
||||||
|
* scale?: number,
|
||||||
|
* beginPath?: boolean,
|
||||||
|
* moveToZero?: true
|
||||||
|
* }} args
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {Object} DrawShapeParams
|
||||||
|
* @property {number} dims
|
||||||
|
* @property {number} innerDims
|
||||||
|
* @property {number} layer
|
||||||
|
* @property {number} quadrant
|
||||||
|
* @property {CanvasRenderingContext2D} context
|
||||||
|
* @property {string} color
|
||||||
|
* @property {BeginDrawShape} begin
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @callback DrawShape
|
||||||
|
* @param {DrawShapeParams} args
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {Object} SpawnChanceData
|
||||||
|
* @property {number} [min=0]
|
||||||
|
* @property {number} [max=100]
|
||||||
|
* @property {number} [distanceMultiplier=1]
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {Object} ShapeSpawnData
|
||||||
|
* @property {string} [color="uncolored"]
|
||||||
|
* @property {number} [minDistance=0]
|
||||||
|
* @property {number} [maxQuarters=4]
|
||||||
|
* @property {SpawnChanceData} [chances]
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {Object} ShapeData
|
||||||
|
* @property {string} id
|
||||||
|
* @property {string} code
|
||||||
|
* @property {DrawShape | string} draw
|
||||||
|
* @property {number} tier
|
||||||
|
* @property {ShapeSpawnData} [spawnData]
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** @type {Object<string, ShapeData>} */
|
||||||
|
export const allShapeData = {
|
||||||
|
rect: {
|
||||||
|
id: "rect",
|
||||||
|
code: "R",
|
||||||
|
draw: "M 0 0 v 1 h 1 v -1 z",
|
||||||
|
tier: 0,
|
||||||
|
spawnData: {
|
||||||
|
color: "uncolored",
|
||||||
|
maxQuarters: 4,
|
||||||
|
minDistance: 0,
|
||||||
|
chances: {
|
||||||
|
min: 100,
|
||||||
|
distanceMultiplier: 0,
|
||||||
|
max: 100,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
circle: {
|
||||||
|
id: "circle",
|
||||||
|
code: "C",
|
||||||
|
draw: "M 0 0 l 1 0 a 1 1 0 0 1 -1 1 z ",
|
||||||
|
tier: 0,
|
||||||
|
spawnData: {
|
||||||
|
color: "uncolored",
|
||||||
|
maxQuarters: 4,
|
||||||
|
minDistance: 0,
|
||||||
|
chances: {
|
||||||
|
min: 50,
|
||||||
|
distanceMultiplier: 15,
|
||||||
|
max: 100,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
star: {
|
||||||
|
id: "star",
|
||||||
|
code: "S",
|
||||||
|
draw: "M 0 0 L 0 0.6 1 1 0.6 0 z",
|
||||||
|
tier: 0.5,
|
||||||
|
spawnData: {
|
||||||
|
color: "uncolored",
|
||||||
|
maxQuarters: 4,
|
||||||
|
minDistance: 5,
|
||||||
|
chances: {
|
||||||
|
min: 20,
|
||||||
|
distanceMultiplier: 10,
|
||||||
|
max: 100,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
windmill: {
|
||||||
|
id: "windmill",
|
||||||
|
code: "W",
|
||||||
|
draw: "M 0 0 L 0 0.6 1 1 1 0 z",
|
||||||
|
tier: 1,
|
||||||
|
spawnData: {
|
||||||
|
color: "uncolored",
|
||||||
|
maxQuarters: 3,
|
||||||
|
minDistance: 7,
|
||||||
|
chances: {
|
||||||
|
min: 20,
|
||||||
|
distanceMultiplier: 5,
|
||||||
|
max: 100,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export function initShapes() {
|
||||||
|
for (let k in enumSubShape) {
|
||||||
|
delete enumSubShape[k];
|
||||||
|
}
|
||||||
|
for (let k in enumSubShapeToShortcode) {
|
||||||
|
delete enumSubShapeToShortcode[k];
|
||||||
|
}
|
||||||
|
for (let k in enumShortcodeToSubShape) {
|
||||||
|
delete enumShortcodeToSubShape[k];
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let s in allShapeData) {
|
||||||
|
let data = allShapeData[s];
|
||||||
|
assert(data.id == s);
|
||||||
|
assert(data.code.toUpperCase() == data.code);
|
||||||
|
assert(data.draw);
|
||||||
|
|
||||||
|
enumSubShape[data.id] = data.id;
|
||||||
|
enumSubShapeToShortcode[data.id] = data.code;
|
||||||
|
enumShortcodeToSubShape[data.code] = data.id;
|
||||||
|
|
||||||
|
if (data.spawnData) {
|
||||||
|
const sdata = data.spawnData;
|
||||||
|
sdata.color = sdata.color || "uncolored";
|
||||||
|
sdata.maxQuarters = sdata.maxQuarters || 4;
|
||||||
|
sdata.minDistance = sdata.minDistance || 0;
|
||||||
|
|
||||||
|
if(sdata.chances) {
|
||||||
|
const chances = sdata.chances;
|
||||||
|
chances.min = chances.min || 0;
|
||||||
|
chances.max = chances.max || 100;
|
||||||
|
chances.distanceMultiplier = chances.distanceMultiplier || 1;
|
||||||
|
} else {
|
||||||
|
sdata.chances = {
|
||||||
|
min: 0,
|
||||||
|
max: 100,
|
||||||
|
distanceMultiplier: 1
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -238,8 +238,8 @@ export class ItemProcessorSystem extends GameSystemWithFilter {
|
|||||||
const items = processorComp.inputSlots;
|
const items = processorComp.inputSlots;
|
||||||
processorComp.inputSlots = [];
|
processorComp.inputSlots = [];
|
||||||
|
|
||||||
/** @type {Object.<string, { item: BaseItem, sourceSlot: number }>} */
|
/** @type {Array<{ item: BaseItem, sourceSlot: number }>} */
|
||||||
const itemsBySlot = {};
|
const itemsBySlot = [];
|
||||||
for (let i = 0; i < items.length; ++i) {
|
for (let i = 0; i < items.length; ++i) {
|
||||||
itemsBySlot[items[i].sourceSlot] = items[i];
|
itemsBySlot[items[i].sourceSlot] = items[i];
|
||||||
}
|
}
|
||||||
@ -251,292 +251,309 @@ export class ItemProcessorSystem extends GameSystemWithFilter {
|
|||||||
let trackProduction = true;
|
let trackProduction = true;
|
||||||
|
|
||||||
// DO SOME MAGIC
|
// DO SOME MAGIC
|
||||||
|
const ModProcessors = require("../../GeoZ/main").ModProcessors;
|
||||||
|
if (ModProcessors[processorComp.type]) {
|
||||||
|
trackProduction = ModProcessors[processorComp.type].process({
|
||||||
|
items: itemsBySlot.map(e => e.item),
|
||||||
|
itemsBySlot,
|
||||||
|
itemsRaw: items,
|
||||||
|
entity,
|
||||||
|
outItems,
|
||||||
|
system: this,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
switch (processorComp.type) {
|
||||||
|
// SPLITTER
|
||||||
|
case enumItemProcessorTypes.splitterWires:
|
||||||
|
case enumItemProcessorTypes.splitter: {
|
||||||
|
trackProduction = false;
|
||||||
|
const availableSlots = entity.components.ItemEjector.slots.length;
|
||||||
|
|
||||||
switch (processorComp.type) {
|
let nextSlot = processorComp.nextOutputSlot++ % availableSlots;
|
||||||
// SPLITTER
|
for (let i = 0; i < items.length; ++i) {
|
||||||
case enumItemProcessorTypes.splitterWires:
|
|
||||||
case enumItemProcessorTypes.splitter: {
|
|
||||||
trackProduction = false;
|
|
||||||
const availableSlots = entity.components.ItemEjector.slots.length;
|
|
||||||
|
|
||||||
let nextSlot = processorComp.nextOutputSlot++ % availableSlots;
|
|
||||||
for (let i = 0; i < items.length; ++i) {
|
|
||||||
outItems.push({
|
|
||||||
item: items[i].item,
|
|
||||||
preferredSlot: (nextSlot + i) % availableSlots,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// CUTTER
|
|
||||||
case enumItemProcessorTypes.cutter: {
|
|
||||||
const inputItem = /** @type {ShapeItem} */ (items[0].item);
|
|
||||||
assert(inputItem instanceof ShapeItem, "Input for cut is not a shape");
|
|
||||||
const inputDefinition = inputItem.definition;
|
|
||||||
|
|
||||||
const cutDefinitions = this.root.shapeDefinitionMgr.shapeActionCutHalf(inputDefinition);
|
|
||||||
|
|
||||||
for (let i = 0; i < cutDefinitions.length; ++i) {
|
|
||||||
const definition = cutDefinitions[i];
|
|
||||||
if (!definition.isEntirelyEmpty()) {
|
|
||||||
outItems.push({
|
outItems.push({
|
||||||
item: this.root.shapeDefinitionMgr.getShapeItemFromDefinition(definition),
|
item: items[i].item,
|
||||||
requiredSlot: i,
|
preferredSlot: (nextSlot + i) % availableSlots,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
// CUTTER
|
||||||
}
|
case enumItemProcessorTypes.cutter: {
|
||||||
|
const inputItem = /** @type {ShapeItem} */ (items[0].item);
|
||||||
|
assert(inputItem instanceof ShapeItem, "Input for cut is not a shape");
|
||||||
|
const inputDefinition = inputItem.definition;
|
||||||
|
|
||||||
// CUTTER (Quad)
|
const cutDefinitions = this.root.shapeDefinitionMgr.shapeActionCutHalf(inputDefinition);
|
||||||
case enumItemProcessorTypes.cutterQuad: {
|
|
||||||
const inputItem = /** @type {ShapeItem} */ (items[0].item);
|
|
||||||
assert(inputItem instanceof ShapeItem, "Input for cut is not a shape");
|
|
||||||
const inputDefinition = inputItem.definition;
|
|
||||||
|
|
||||||
const cutDefinitions = this.root.shapeDefinitionMgr.shapeActionCutQuad(inputDefinition);
|
for (let i = 0; i < cutDefinitions.length; ++i) {
|
||||||
|
const definition = cutDefinitions[i];
|
||||||
for (let i = 0; i < cutDefinitions.length; ++i) {
|
if (!definition.isEntirelyEmpty()) {
|
||||||
const definition = cutDefinitions[i];
|
outItems.push({
|
||||||
if (!definition.isEntirelyEmpty()) {
|
item: this.root.shapeDefinitionMgr.getShapeItemFromDefinition(definition),
|
||||||
outItems.push({
|
requiredSlot: i,
|
||||||
item: this.root.shapeDefinitionMgr.getShapeItemFromDefinition(definition),
|
});
|
||||||
requiredSlot: i,
|
}
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
// CUTTER (Quad)
|
||||||
}
|
case enumItemProcessorTypes.cutterQuad: {
|
||||||
|
const inputItem = /** @type {ShapeItem} */ (items[0].item);
|
||||||
|
assert(inputItem instanceof ShapeItem, "Input for cut is not a shape");
|
||||||
|
const inputDefinition = inputItem.definition;
|
||||||
|
|
||||||
// ROTATER
|
const cutDefinitions = this.root.shapeDefinitionMgr.shapeActionCutQuad(inputDefinition);
|
||||||
case enumItemProcessorTypes.rotater: {
|
|
||||||
const inputItem = /** @type {ShapeItem} */ (items[0].item);
|
|
||||||
assert(inputItem instanceof ShapeItem, "Input for rotation is not a shape");
|
|
||||||
const inputDefinition = inputItem.definition;
|
|
||||||
|
|
||||||
const rotatedDefinition = this.root.shapeDefinitionMgr.shapeActionRotateCW(inputDefinition);
|
for (let i = 0; i < cutDefinitions.length; ++i) {
|
||||||
outItems.push({
|
const definition = cutDefinitions[i];
|
||||||
item: this.root.shapeDefinitionMgr.getShapeItemFromDefinition(rotatedDefinition),
|
if (!definition.isEntirelyEmpty()) {
|
||||||
});
|
outItems.push({
|
||||||
break;
|
item: this.root.shapeDefinitionMgr.getShapeItemFromDefinition(definition),
|
||||||
}
|
requiredSlot: i,
|
||||||
|
});
|
||||||
// ROTATER (CCW)
|
}
|
||||||
case enumItemProcessorTypes.rotaterCCW: {
|
|
||||||
const inputItem = /** @type {ShapeItem} */ (items[0].item);
|
|
||||||
assert(inputItem instanceof ShapeItem, "Input for rotation is not a shape");
|
|
||||||
const inputDefinition = inputItem.definition;
|
|
||||||
|
|
||||||
const rotatedDefinition = this.root.shapeDefinitionMgr.shapeActionRotateCCW(inputDefinition);
|
|
||||||
outItems.push({
|
|
||||||
item: this.root.shapeDefinitionMgr.getShapeItemFromDefinition(rotatedDefinition),
|
|
||||||
});
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ROTATER (FL)
|
|
||||||
case enumItemProcessorTypes.rotaterFL: {
|
|
||||||
const inputItem = /** @type {ShapeItem} */ (items[0].item);
|
|
||||||
assert(inputItem instanceof ShapeItem, "Input for rotation is not a shape");
|
|
||||||
const inputDefinition = inputItem.definition;
|
|
||||||
|
|
||||||
const rotatedDefinition = this.root.shapeDefinitionMgr.shapeActionRotateFL(inputDefinition);
|
|
||||||
outItems.push({
|
|
||||||
item: this.root.shapeDefinitionMgr.getShapeItemFromDefinition(rotatedDefinition),
|
|
||||||
});
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// STACKER
|
|
||||||
|
|
||||||
case enumItemProcessorTypes.stacker: {
|
|
||||||
const lowerItem = /** @type {ShapeItem} */ (itemsBySlot[0].item);
|
|
||||||
const upperItem = /** @type {ShapeItem} */ (itemsBySlot[1].item);
|
|
||||||
|
|
||||||
assert(lowerItem instanceof ShapeItem, "Input for lower stack is not a shape");
|
|
||||||
assert(upperItem instanceof ShapeItem, "Input for upper stack is not a shape");
|
|
||||||
|
|
||||||
const stackedDefinition = this.root.shapeDefinitionMgr.shapeActionStack(
|
|
||||||
lowerItem.definition,
|
|
||||||
upperItem.definition
|
|
||||||
);
|
|
||||||
outItems.push({
|
|
||||||
item: this.root.shapeDefinitionMgr.getShapeItemFromDefinition(stackedDefinition),
|
|
||||||
});
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// TRASH
|
|
||||||
|
|
||||||
case enumItemProcessorTypes.trash: {
|
|
||||||
// Well this one is easy .. simply do nothing with the item
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// MIXER
|
|
||||||
|
|
||||||
case enumItemProcessorTypes.mixer: {
|
|
||||||
// Find both colors and combine them
|
|
||||||
const item1 = /** @type {ColorItem} */ (items[0].item);
|
|
||||||
const item2 = /** @type {ColorItem} */ (items[1].item);
|
|
||||||
assert(item1 instanceof ColorItem, "Input for color mixer is not a color");
|
|
||||||
assert(item2 instanceof ColorItem, "Input for color mixer is not a color");
|
|
||||||
|
|
||||||
const color1 = item1.color;
|
|
||||||
const color2 = item2.color;
|
|
||||||
|
|
||||||
// Try finding mixer color, and if we can't mix it we simply return the same color
|
|
||||||
const mixedColor = enumColorMixingResults[color1][color2];
|
|
||||||
let resultColor = color1;
|
|
||||||
if (mixedColor) {
|
|
||||||
resultColor = mixedColor;
|
|
||||||
}
|
|
||||||
outItems.push({
|
|
||||||
item: COLOR_ITEM_SINGLETONS[resultColor],
|
|
||||||
});
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// PAINTER
|
|
||||||
|
|
||||||
case enumItemProcessorTypes.painter: {
|
|
||||||
const shapeItem = /** @type {ShapeItem} */ (itemsBySlot[0].item);
|
|
||||||
const colorItem = /** @type {ColorItem} */ (itemsBySlot[1].item);
|
|
||||||
|
|
||||||
const colorizedDefinition = this.root.shapeDefinitionMgr.shapeActionPaintWith(
|
|
||||||
shapeItem.definition,
|
|
||||||
colorItem.color
|
|
||||||
);
|
|
||||||
|
|
||||||
outItems.push({
|
|
||||||
item: this.root.shapeDefinitionMgr.getShapeItemFromDefinition(colorizedDefinition),
|
|
||||||
});
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// PAINTER (DOUBLE)
|
|
||||||
|
|
||||||
case enumItemProcessorTypes.painterDouble: {
|
|
||||||
const shapeItem1 = /** @type {ShapeItem} */ (itemsBySlot[0].item);
|
|
||||||
const shapeItem2 = /** @type {ShapeItem} */ (itemsBySlot[1].item);
|
|
||||||
const colorItem = /** @type {ColorItem} */ (itemsBySlot[2].item);
|
|
||||||
|
|
||||||
assert(shapeItem1 instanceof ShapeItem, "Input for painter is not a shape");
|
|
||||||
assert(shapeItem2 instanceof ShapeItem, "Input for painter is not a shape");
|
|
||||||
assert(colorItem instanceof ColorItem, "Input for painter is not a color");
|
|
||||||
|
|
||||||
const colorizedDefinition1 = this.root.shapeDefinitionMgr.shapeActionPaintWith(
|
|
||||||
shapeItem1.definition,
|
|
||||||
colorItem.color
|
|
||||||
);
|
|
||||||
|
|
||||||
const colorizedDefinition2 = this.root.shapeDefinitionMgr.shapeActionPaintWith(
|
|
||||||
shapeItem2.definition,
|
|
||||||
colorItem.color
|
|
||||||
);
|
|
||||||
outItems.push({
|
|
||||||
item: this.root.shapeDefinitionMgr.getShapeItemFromDefinition(colorizedDefinition1),
|
|
||||||
});
|
|
||||||
|
|
||||||
outItems.push({
|
|
||||||
item: this.root.shapeDefinitionMgr.getShapeItemFromDefinition(colorizedDefinition2),
|
|
||||||
});
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// PAINTER (QUAD)
|
|
||||||
|
|
||||||
case enumItemProcessorTypes.painterQuad: {
|
|
||||||
const shapeItem = /** @type {ShapeItem} */ (itemsBySlot[0].item);
|
|
||||||
assert(shapeItem instanceof ShapeItem, "Input for painter is not a shape");
|
|
||||||
|
|
||||||
/** @type {Array<enumColors>} */
|
|
||||||
const colors = [null, null, null, null];
|
|
||||||
for (let i = 0; i < 4; ++i) {
|
|
||||||
if (itemsBySlot[i + 1]) {
|
|
||||||
colors[i] = /** @type {ColorItem} */ (itemsBySlot[i + 1].item).color;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
const colorizedDefinition = this.root.shapeDefinitionMgr.shapeActionPaintWith4Colors(
|
// ROTATER
|
||||||
shapeItem.definition,
|
case enumItemProcessorTypes.rotater: {
|
||||||
/** @type {[string, string, string, string]} */ (colors)
|
const inputItem = /** @type {ShapeItem} */ (items[0].item);
|
||||||
);
|
assert(inputItem instanceof ShapeItem, "Input for rotation is not a shape");
|
||||||
|
const inputDefinition = inputItem.definition;
|
||||||
|
|
||||||
outItems.push({
|
const rotatedDefinition = this.root.shapeDefinitionMgr.shapeActionRotateCW(
|
||||||
item: this.root.shapeDefinitionMgr.getShapeItemFromDefinition(colorizedDefinition),
|
inputDefinition
|
||||||
});
|
);
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// FILTER
|
|
||||||
case enumItemProcessorTypes.filter: {
|
|
||||||
// TODO
|
|
||||||
trackProduction = false;
|
|
||||||
|
|
||||||
const item = itemsBySlot[0].item;
|
|
||||||
|
|
||||||
const network = entity.components.WiredPins.slots[0].linkedNetwork;
|
|
||||||
if (!network || !network.currentValue) {
|
|
||||||
outItems.push({
|
outItems.push({
|
||||||
item,
|
item: this.root.shapeDefinitionMgr.getShapeItemFromDefinition(rotatedDefinition),
|
||||||
requiredSlot: 1,
|
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
const value = network.currentValue;
|
// ROTATER (CCW)
|
||||||
if (value.equals(BOOL_TRUE_SINGLETON) || value.equals(item)) {
|
case enumItemProcessorTypes.rotaterCCW: {
|
||||||
|
const inputItem = /** @type {ShapeItem} */ (items[0].item);
|
||||||
|
assert(inputItem instanceof ShapeItem, "Input for rotation is not a shape");
|
||||||
|
const inputDefinition = inputItem.definition;
|
||||||
|
|
||||||
|
const rotatedDefinition = this.root.shapeDefinitionMgr.shapeActionRotateCCW(
|
||||||
|
inputDefinition
|
||||||
|
);
|
||||||
outItems.push({
|
outItems.push({
|
||||||
item,
|
item: this.root.shapeDefinitionMgr.getShapeItemFromDefinition(rotatedDefinition),
|
||||||
requiredSlot: 0,
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
outItems.push({
|
|
||||||
item,
|
|
||||||
requiredSlot: 1,
|
|
||||||
});
|
});
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
// ROTATER (FL)
|
||||||
}
|
case enumItemProcessorTypes.rotaterFL: {
|
||||||
|
const inputItem = /** @type {ShapeItem} */ (items[0].item);
|
||||||
|
assert(inputItem instanceof ShapeItem, "Input for rotation is not a shape");
|
||||||
|
const inputDefinition = inputItem.definition;
|
||||||
|
|
||||||
// READER
|
const rotatedDefinition = this.root.shapeDefinitionMgr.shapeActionRotateFL(
|
||||||
case enumItemProcessorTypes.reader: {
|
inputDefinition
|
||||||
// Pass through the item
|
);
|
||||||
const item = itemsBySlot[0].item;
|
outItems.push({
|
||||||
outItems.push({ item });
|
item: this.root.shapeDefinitionMgr.getShapeItemFromDefinition(rotatedDefinition),
|
||||||
|
});
|
||||||
// Track the item
|
break;
|
||||||
const readerComp = entity.components.BeltReader;
|
|
||||||
readerComp.lastItemTimes.push(this.root.time.now());
|
|
||||||
readerComp.lastItem = item;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// HUB
|
|
||||||
case enumItemProcessorTypes.hub: {
|
|
||||||
trackProduction = false;
|
|
||||||
|
|
||||||
const hubComponent = entity.components.Hub;
|
|
||||||
assert(hubComponent, "Hub item processor has no hub component");
|
|
||||||
|
|
||||||
for (let i = 0; i < items.length; ++i) {
|
|
||||||
const item = /** @type {ShapeItem} */ (items[i].item);
|
|
||||||
this.root.hubGoals.handleDefinitionDelivered(item.definition);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
// STACKER
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
case enumItemProcessorTypes.stacker: {
|
||||||
assertAlways(false, "Unkown item processor type: " + processorComp.type);
|
const lowerItem = /** @type {ShapeItem} */ (itemsBySlot[0].item);
|
||||||
|
const upperItem = /** @type {ShapeItem} */ (itemsBySlot[1].item);
|
||||||
|
|
||||||
|
assert(lowerItem instanceof ShapeItem, "Input for lower stack is not a shape");
|
||||||
|
assert(upperItem instanceof ShapeItem, "Input for upper stack is not a shape");
|
||||||
|
|
||||||
|
const stackedDefinition = this.root.shapeDefinitionMgr.shapeActionStack(
|
||||||
|
lowerItem.definition,
|
||||||
|
upperItem.definition
|
||||||
|
);
|
||||||
|
outItems.push({
|
||||||
|
item: this.root.shapeDefinitionMgr.getShapeItemFromDefinition(stackedDefinition),
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TRASH
|
||||||
|
|
||||||
|
case enumItemProcessorTypes.trash: {
|
||||||
|
// Well this one is easy .. simply do nothing with the item
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// MIXER
|
||||||
|
|
||||||
|
case enumItemProcessorTypes.mixer: {
|
||||||
|
// Find both colors and combine them
|
||||||
|
const item1 = /** @type {ColorItem} */ (items[0].item);
|
||||||
|
const item2 = /** @type {ColorItem} */ (items[1].item);
|
||||||
|
assert(item1 instanceof ColorItem, "Input for color mixer is not a color");
|
||||||
|
assert(item2 instanceof ColorItem, "Input for color mixer is not a color");
|
||||||
|
|
||||||
|
const color1 = item1.color;
|
||||||
|
const color2 = item2.color;
|
||||||
|
|
||||||
|
// Try finding mixer color, and if we can't mix it we simply return the same color
|
||||||
|
const mixedColor = enumColorMixingResults[color1][color2];
|
||||||
|
let resultColor = color1;
|
||||||
|
if (mixedColor) {
|
||||||
|
resultColor = mixedColor;
|
||||||
|
}
|
||||||
|
outItems.push({
|
||||||
|
item: COLOR_ITEM_SINGLETONS[resultColor],
|
||||||
|
});
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// PAINTER
|
||||||
|
|
||||||
|
case enumItemProcessorTypes.painter: {
|
||||||
|
const shapeItem = /** @type {ShapeItem} */ (itemsBySlot[0].item);
|
||||||
|
const colorItem = /** @type {ColorItem} */ (itemsBySlot[1].item);
|
||||||
|
|
||||||
|
const colorizedDefinition = this.root.shapeDefinitionMgr.shapeActionPaintWith(
|
||||||
|
shapeItem.definition,
|
||||||
|
colorItem.color
|
||||||
|
);
|
||||||
|
|
||||||
|
outItems.push({
|
||||||
|
item: this.root.shapeDefinitionMgr.getShapeItemFromDefinition(colorizedDefinition),
|
||||||
|
});
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// PAINTER (DOUBLE)
|
||||||
|
|
||||||
|
case enumItemProcessorTypes.painterDouble: {
|
||||||
|
const shapeItem1 = /** @type {ShapeItem} */ (itemsBySlot[0].item);
|
||||||
|
const shapeItem2 = /** @type {ShapeItem} */ (itemsBySlot[1].item);
|
||||||
|
const colorItem = /** @type {ColorItem} */ (itemsBySlot[2].item);
|
||||||
|
|
||||||
|
assert(shapeItem1 instanceof ShapeItem, "Input for painter is not a shape");
|
||||||
|
assert(shapeItem2 instanceof ShapeItem, "Input for painter is not a shape");
|
||||||
|
assert(colorItem instanceof ColorItem, "Input for painter is not a color");
|
||||||
|
|
||||||
|
const colorizedDefinition1 = this.root.shapeDefinitionMgr.shapeActionPaintWith(
|
||||||
|
shapeItem1.definition,
|
||||||
|
colorItem.color
|
||||||
|
);
|
||||||
|
|
||||||
|
const colorizedDefinition2 = this.root.shapeDefinitionMgr.shapeActionPaintWith(
|
||||||
|
shapeItem2.definition,
|
||||||
|
colorItem.color
|
||||||
|
);
|
||||||
|
outItems.push({
|
||||||
|
item: this.root.shapeDefinitionMgr.getShapeItemFromDefinition(colorizedDefinition1),
|
||||||
|
});
|
||||||
|
|
||||||
|
outItems.push({
|
||||||
|
item: this.root.shapeDefinitionMgr.getShapeItemFromDefinition(colorizedDefinition2),
|
||||||
|
});
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// PAINTER (QUAD)
|
||||||
|
|
||||||
|
case enumItemProcessorTypes.painterQuad: {
|
||||||
|
const shapeItem = /** @type {ShapeItem} */ (itemsBySlot[0].item);
|
||||||
|
assert(shapeItem instanceof ShapeItem, "Input for painter is not a shape");
|
||||||
|
|
||||||
|
/** @type {Array<enumColors>} */
|
||||||
|
const colors = [null, null, null, null];
|
||||||
|
for (let i = 0; i < 4; ++i) {
|
||||||
|
if (itemsBySlot[i + 1]) {
|
||||||
|
colors[i] = /** @type {ColorItem} */ (itemsBySlot[i + 1].item).color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const colorizedDefinition = this.root.shapeDefinitionMgr.shapeActionPaintWith4Colors(
|
||||||
|
shapeItem.definition,
|
||||||
|
/** @type {[string, string, string, string]} */ (colors)
|
||||||
|
);
|
||||||
|
|
||||||
|
outItems.push({
|
||||||
|
item: this.root.shapeDefinitionMgr.getShapeItemFromDefinition(colorizedDefinition),
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// FILTER
|
||||||
|
case enumItemProcessorTypes.filter: {
|
||||||
|
// TODO
|
||||||
|
trackProduction = false;
|
||||||
|
|
||||||
|
const item = itemsBySlot[0].item;
|
||||||
|
|
||||||
|
const network = entity.components.WiredPins.slots[0].linkedNetwork;
|
||||||
|
if (!network || !network.currentValue) {
|
||||||
|
outItems.push({
|
||||||
|
item,
|
||||||
|
requiredSlot: 1,
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
const value = network.currentValue;
|
||||||
|
if (value.equals(BOOL_TRUE_SINGLETON) || value.equals(item)) {
|
||||||
|
outItems.push({
|
||||||
|
item,
|
||||||
|
requiredSlot: 0,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
outItems.push({
|
||||||
|
item,
|
||||||
|
requiredSlot: 1,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// READER
|
||||||
|
case enumItemProcessorTypes.reader: {
|
||||||
|
// Pass through the item
|
||||||
|
const item = itemsBySlot[0].item;
|
||||||
|
outItems.push({ item });
|
||||||
|
|
||||||
|
// Track the item
|
||||||
|
const readerComp = entity.components.BeltReader;
|
||||||
|
readerComp.lastItemTimes.push(this.root.time.now());
|
||||||
|
readerComp.lastItem = item;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// HUB
|
||||||
|
case enumItemProcessorTypes.hub: {
|
||||||
|
trackProduction = false;
|
||||||
|
|
||||||
|
const hubComponent = entity.components.Hub;
|
||||||
|
assert(hubComponent, "Hub item processor has no hub component");
|
||||||
|
|
||||||
|
for (let i = 0; i < items.length; ++i) {
|
||||||
|
const item = /** @type {ShapeItem} */ (items[i].item);
|
||||||
|
this.root.hubGoals.handleDefinitionDelivered(item.definition);
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
assertAlways(false, "Unkown item processor type: " + processorComp.type);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Track produced items
|
// Track produced items
|
||||||
|
@ -25,6 +25,12 @@ export class LogicGateSystem extends GameSystemWithFilter {
|
|||||||
[enumLogicGateType.unstacker]: this.compute_UNSTACK.bind(this),
|
[enumLogicGateType.unstacker]: this.compute_UNSTACK.bind(this),
|
||||||
[enumLogicGateType.shapecompare]: this.compute_SHAPECOMPARE.bind(this),
|
[enumLogicGateType.shapecompare]: this.compute_SHAPECOMPARE.bind(this),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const { ModWireProcessors } = require("../../GeoZ/main");
|
||||||
|
for (const type in ModWireProcessors) {
|
||||||
|
//@ts-ignore
|
||||||
|
this.boundOperations[type] = ModWireProcessors[type].compute.bind(null, this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
update() {
|
update() {
|
||||||
|
@ -10,6 +10,7 @@ import { initDrawUtils } from "./core/draw_utils";
|
|||||||
import { initItemRegistry } from "./game/item_registry";
|
import { initItemRegistry } from "./game/item_registry";
|
||||||
import { initMetaBuildingRegistry } from "./game/meta_building_registry";
|
import { initMetaBuildingRegistry } from "./game/meta_building_registry";
|
||||||
import { initGameSpeedRegistry } from "./game/game_speed_registry";
|
import { initGameSpeedRegistry } from "./game/game_speed_registry";
|
||||||
|
import { initMods } from "./GeoZ/main";
|
||||||
|
|
||||||
const logger = createLogger("main");
|
const logger = createLogger("main");
|
||||||
|
|
||||||
@ -18,37 +19,6 @@ if (window.coreThreadLoadedCb) {
|
|||||||
window.coreThreadLoadedCb();
|
window.coreThreadLoadedCb();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Logrocket
|
|
||||||
// if (!G_IS_DEV && !G_IS_STANDALONE) {
|
|
||||||
// const monthlyUsers = 300; // thousand
|
|
||||||
// const logrocketLimit = 10; // thousand
|
|
||||||
// const percentageOfUsers = logrocketLimit / monthlyUsers;
|
|
||||||
|
|
||||||
// if (Math.random() <= percentageOfUsers) {
|
|
||||||
// logger.log("Analyzing this session with logrocket");
|
|
||||||
// const logrocket = require("logrocket");
|
|
||||||
// logrocket.init("p1x9zh/shapezio");
|
|
||||||
|
|
||||||
// try {
|
|
||||||
// logrocket.getSessionURL(function (sessionURL) {
|
|
||||||
// logger.log("Connected lockrocket to GA");
|
|
||||||
// // @ts-ignore
|
|
||||||
// try {
|
|
||||||
// window.ga("send", {
|
|
||||||
// hitType: "event",
|
|
||||||
// eventCategory: "LogRocket",
|
|
||||||
// eventAction: sessionURL,
|
|
||||||
// });
|
|
||||||
// } catch (ex) {
|
|
||||||
// logger.warn("Logrocket connection to analytics failed:", ex);
|
|
||||||
// }
|
|
||||||
// });
|
|
||||||
// } catch (ex) {
|
|
||||||
// logger.warn("Logrocket connection to analytics failed:", ex);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
console.log(
|
console.log(
|
||||||
`%cshapez.io ️%c\n© 2020 Tobias Springer IT Solutions\nCommit %c${G_BUILD_COMMIT_HASH}%c on %c${new Date(
|
`%cshapez.io ️%c\n© 2020 Tobias Springer IT Solutions\nCommit %c${G_BUILD_COMMIT_HASH}%c on %c${new Date(
|
||||||
G_BUILD_TIME
|
G_BUILD_TIME
|
||||||
@ -77,12 +47,6 @@ console.log("%cDEVCODE BUILT IN", "color: #f77");
|
|||||||
|
|
||||||
logSection("Boot Process", "#f9a825");
|
logSection("Boot Process", "#f9a825");
|
||||||
|
|
||||||
initDrawUtils();
|
|
||||||
initComponentRegistry();
|
|
||||||
initItemRegistry();
|
|
||||||
initMetaBuildingRegistry();
|
|
||||||
initGameSpeedRegistry();
|
|
||||||
|
|
||||||
let app = null;
|
let app = null;
|
||||||
|
|
||||||
function bootApp() {
|
function bootApp() {
|
||||||
@ -91,4 +55,4 @@ function bootApp() {
|
|||||||
app.boot();
|
app.boot();
|
||||||
}
|
}
|
||||||
|
|
||||||
window.addEventListener("load", bootApp);
|
window.addEventListener("load", bootApp);
|
@ -10,6 +10,7 @@ import { THEMES, THEME, applyGameTheme } from "../game/theme";
|
|||||||
import { IS_DEMO } from "../core/config";
|
import { IS_DEMO } from "../core/config";
|
||||||
import { T } from "../translations";
|
import { T } from "../translations";
|
||||||
import { LANGUAGES } from "../languages";
|
import { LANGUAGES } from "../languages";
|
||||||
|
import { globalConfig, IS_DEBUG } from "../core/config";
|
||||||
|
|
||||||
const logger = createLogger("application_settings");
|
const logger = createLogger("application_settings");
|
||||||
|
|
||||||
@ -21,6 +22,8 @@ export const enumCategories = {
|
|||||||
userInterface: "userInterface",
|
userInterface: "userInterface",
|
||||||
performance: "performance",
|
performance: "performance",
|
||||||
advanced: "advanced",
|
advanced: "advanced",
|
||||||
|
debug: "debug",
|
||||||
|
keybindings: "keybindings",
|
||||||
};
|
};
|
||||||
|
|
||||||
export const uiScales = [
|
export const uiScales = [
|
||||||
@ -278,6 +281,21 @@ export const allApplicationSettings = [
|
|||||||
new BoolSetting("lowQualityTextures", enumCategories.performance, (app, value) => {}),
|
new BoolSetting("lowQualityTextures", enumCategories.performance, (app, value) => {}),
|
||||||
];
|
];
|
||||||
|
|
||||||
|
if (IS_DEBUG) {
|
||||||
|
for (let k in globalConfig.debug) {
|
||||||
|
if (k.startsWith("_")) continue;
|
||||||
|
const setting = new BoolSetting(`debug_${k}`, enumCategories.debug, (app, value) => {
|
||||||
|
globalConfig.debug[k] = value;
|
||||||
|
});
|
||||||
|
setting.validate = () => true;
|
||||||
|
T.settings.labels[`debug_${k}`] = {
|
||||||
|
title: k.replace(/(?!^)([A-Z])/g, " $1"),
|
||||||
|
description: globalConfig.debug[`_${k}`],
|
||||||
|
};
|
||||||
|
allApplicationSettings.push(setting);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export function getApplicationSettingById(id) {
|
export function getApplicationSettingById(id) {
|
||||||
return allApplicationSettings.find(setting => setting.id === id);
|
return allApplicationSettings.find(setting => setting.id === id);
|
||||||
}
|
}
|
||||||
@ -358,7 +376,9 @@ export class ApplicationSettings extends ReadWriteProxy {
|
|||||||
* @param {string} key
|
* @param {string} key
|
||||||
*/
|
*/
|
||||||
getSetting(key) {
|
getSetting(key) {
|
||||||
assert(this.getAllSettings().hasOwnProperty(key), "Setting not known: " + key);
|
if (!key.startsWith("debug_")) {
|
||||||
|
assert(this.getAllSettings().hasOwnProperty(key), "Setting not known: " + key);
|
||||||
|
}
|
||||||
return this.getAllSettings()[key];
|
return this.getAllSettings()[key];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -185,6 +185,10 @@ export class BoolSetting extends BaseSetting {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getHtml() {
|
getHtml() {
|
||||||
|
if (!T.settings.labels[this.id].description) {
|
||||||
|
let a = T;
|
||||||
|
let b = a;
|
||||||
|
}
|
||||||
return `
|
return `
|
||||||
<div class="setting cardbox ${this.enabled ? "enabled" : "disabled"}">
|
<div class="setting cardbox ${this.enabled ? "enabled" : "disabled"}">
|
||||||
${this.enabled ? "" : `<span class="standaloneOnlyHint">${T.demo.settingNotAvailable}</span>`}
|
${this.enabled ? "" : `<span class="standaloneOnlyHint">${T.demo.settingNotAvailable}</span>`}
|
||||||
|
@ -4,39 +4,58 @@ import { T } from "../translations";
|
|||||||
import { KEYMAPPINGS, getStringForKeyCode } from "../game/key_action_mapper";
|
import { KEYMAPPINGS, getStringForKeyCode } from "../game/key_action_mapper";
|
||||||
import { Dialog } from "../core/modal_dialog_elements";
|
import { Dialog } from "../core/modal_dialog_elements";
|
||||||
import { IS_DEMO } from "../core/config";
|
import { IS_DEMO } from "../core/config";
|
||||||
|
import { SettingsState } from "./settings";
|
||||||
|
|
||||||
export class KeybindingsState extends TextualGameState {
|
export class KeybindingsState extends SettingsState {
|
||||||
constructor() {
|
// constructor() {
|
||||||
super("KeybindingsState");
|
// super();
|
||||||
}
|
// super("KeybindingsState");
|
||||||
|
// this.settingsState = settingsState;
|
||||||
|
// }
|
||||||
|
|
||||||
getStateHeaderTitle() {
|
// getStateHeaderTitle() {
|
||||||
return T.keybindings.title;
|
// return T.keybindings.title;
|
||||||
}
|
// }
|
||||||
|
|
||||||
getMainContentHTML() {
|
getMainContentHTML() {
|
||||||
return `
|
return `
|
||||||
|
<div class="sidebar">
|
||||||
|
${this.getCategoryButtonsHtml()}
|
||||||
|
|
||||||
<div class="topEntries">
|
<div class="other">
|
||||||
<span class="hint">${T.keybindings.hint}</span>
|
<button class="styledButton about">${T.about.title}</button>
|
||||||
<button class="styledButton resetBindings">${T.keybindings.resetKeybindings}</button>
|
|
||||||
|
<div class="versionbar">
|
||||||
|
<div class="buildVersion">${T.global.loading} ...</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="keybindings">
|
<div class="categoryContainer">
|
||||||
|
|
||||||
|
<div class="category keybindings" data-category="keybindings">
|
||||||
|
<div class="topEntries">
|
||||||
|
<span class="hint">${T.keybindings.hint}</span>
|
||||||
|
<button class="styledButton resetBindings">${T.keybindings.resetKeybindings}</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
${this.getSettingsHtml()}
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
onEnter() {
|
onEnter() {
|
||||||
|
this.onEnterCommon();
|
||||||
|
|
||||||
const keybindingsElem = this.htmlElement.querySelector(".keybindings");
|
const keybindingsElem = this.htmlElement.querySelector(".keybindings");
|
||||||
|
|
||||||
this.trackClicks(this.htmlElement.querySelector(".resetBindings"), this.resetBindings);
|
this.trackClicks(this.htmlElement.querySelector(".resetBindings"), this.resetBindings);
|
||||||
|
|
||||||
for (const category in KEYMAPPINGS) {
|
for (const category in KEYMAPPINGS) {
|
||||||
const categoryDiv = document.createElement("div");
|
const categoryDiv = document.createElement("div");
|
||||||
categoryDiv.classList.add("category");
|
categoryDiv.classList.add("keyCategory");
|
||||||
keybindingsElem.appendChild(categoryDiv);
|
keybindingsElem.appendChild(categoryDiv);
|
||||||
|
|
||||||
const labelDiv = document.createElement("strong");
|
const labelDiv = document.createElement("strong");
|
||||||
@ -173,7 +192,7 @@ export class KeybindingsState extends TextualGameState {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
getDefaultPreviousState() {
|
// getDefaultPreviousState() {
|
||||||
return "SettingsState";
|
// return "SettingsState";
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
|
@ -75,7 +75,7 @@ export class MainMenuState extends GameState {
|
|||||||
|
|
||||||
<div class="logo">
|
<div class="logo">
|
||||||
<img src="${cachebust("res/logo.png")}" alt="shapez.io Logo">
|
<img src="${cachebust("res/logo.png")}" alt="shapez.io Logo">
|
||||||
<span class="updateLabel">Wires update!</span>
|
<span class="updateLabel">Geo<span style="color:#66bb6a">Z</span></span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
@ -119,7 +119,7 @@ export class MainMenuState extends GameState {
|
|||||||
|
|
||||||
<div class="author">${T.mainMenu.madeBy.replace(
|
<div class="author">${T.mainMenu.madeBy.replace(
|
||||||
"<author-link>",
|
"<author-link>",
|
||||||
'<a class="producerLink" target="_blank">Tobias Springer</a>'
|
'<a class="producerLink" target="_blank">Tobias Springer & modded by Exund</a>'
|
||||||
)}</div>
|
)}</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
@ -8,6 +8,12 @@ import { HUDModalDialogs } from "../game/hud/parts/modal_dialogs";
|
|||||||
import { CHANGELOG } from "../changelog";
|
import { CHANGELOG } from "../changelog";
|
||||||
import { globalConfig } from "../core/config";
|
import { globalConfig } from "../core/config";
|
||||||
|
|
||||||
|
import { initComponentRegistry } from "../game/component_registry";
|
||||||
|
import { initDrawUtils } from "../core/draw_utils";
|
||||||
|
import { initItemRegistry } from "../game/item_registry";
|
||||||
|
import { initMetaBuildingRegistry } from "../game/meta_building_registry";
|
||||||
|
import { initGameSpeedRegistry } from "../game/game_speed_registry";
|
||||||
|
|
||||||
const logger = createLogger("state/preload");
|
const logger = createLogger("state/preload");
|
||||||
|
|
||||||
export class PreloadState extends GameState {
|
export class PreloadState extends GameState {
|
||||||
@ -108,6 +114,18 @@ export class PreloadState extends GameState {
|
|||||||
return this.app.settings.initialize();
|
return this.app.settings.initialize();
|
||||||
})
|
})
|
||||||
|
|
||||||
|
.then(() => this.setStatus("Loading GeoZ mods"))
|
||||||
|
.then(() => require("../GeoZ/main").initMods())
|
||||||
|
|
||||||
|
.then(() => this.setStatus("Initializing registeries"))
|
||||||
|
.then(() => {
|
||||||
|
initDrawUtils();
|
||||||
|
initComponentRegistry();
|
||||||
|
initItemRegistry();
|
||||||
|
initMetaBuildingRegistry();
|
||||||
|
initGameSpeedRegistry();
|
||||||
|
})
|
||||||
|
|
||||||
.then(() => {
|
.then(() => {
|
||||||
// Initialize fullscreen
|
// Initialize fullscreen
|
||||||
if (this.app.platformWrapper.getSupportsFullscreen()) {
|
if (this.app.platformWrapper.getSupportsFullscreen()) {
|
||||||
|
@ -4,8 +4,8 @@ import { allApplicationSettings, enumCategories } from "../profile/application_s
|
|||||||
import { T } from "../translations";
|
import { T } from "../translations";
|
||||||
|
|
||||||
export class SettingsState extends TextualGameState {
|
export class SettingsState extends TextualGameState {
|
||||||
constructor() {
|
constructor(key = "SettingsState") {
|
||||||
super("SettingsState");
|
super(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
getStateHeaderTitle() {
|
getStateHeaderTitle() {
|
||||||
@ -92,7 +92,7 @@ export class SettingsState extends TextualGameState {
|
|||||||
</span>`;
|
</span>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
onEnter(payload) {
|
onEnterCommon() {
|
||||||
this.renderBuildText();
|
this.renderBuildText();
|
||||||
this.trackClicks(this.htmlElement.querySelector(".about"), this.onAboutClicked, {
|
this.trackClicks(this.htmlElement.querySelector(".about"), this.onAboutClicked, {
|
||||||
preventDefault: false,
|
preventDefault: false,
|
||||||
@ -109,6 +109,12 @@ export class SettingsState extends TextualGameState {
|
|||||||
|
|
||||||
this.htmlElement.querySelector(".category").classList.add("active");
|
this.htmlElement.querySelector(".category").classList.add("active");
|
||||||
this.htmlElement.querySelector(".categoryButton").classList.add("active");
|
this.htmlElement.querySelector(".categoryButton").classList.add("active");
|
||||||
|
|
||||||
|
this.setActiveCategory(enumCategories.general);
|
||||||
|
}
|
||||||
|
|
||||||
|
onEnter(payload) {
|
||||||
|
this.onEnterCommon();
|
||||||
}
|
}
|
||||||
|
|
||||||
setActiveCategory(category) {
|
setActiveCategory(category) {
|
||||||
@ -164,6 +170,6 @@ export class SettingsState extends TextualGameState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
onKeybindingsClicked() {
|
onKeybindingsClicked() {
|
||||||
this.moveToStateAddGoBack("KeybindingsState");
|
this.switchToState("KeybindingsState");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -727,6 +727,8 @@ settings:
|
|||||||
userInterface: User Interface
|
userInterface: User Interface
|
||||||
advanced: Advanced
|
advanced: Advanced
|
||||||
performance: Performance
|
performance: Performance
|
||||||
|
debug: Debug
|
||||||
|
keybindings: Keybindings
|
||||||
|
|
||||||
versionBadges:
|
versionBadges:
|
||||||
dev: Development
|
dev: Development
|
||||||
|
Loading…
Reference in New Issue
Block a user