mirror of
https://github.com/tobspr/shapez.io.git
synced 2025-06-13 13:04:03 +00:00
Update to latest version
This commit is contained in:
parent
55f968ea4a
commit
bf17ccf202
@ -23,7 +23,7 @@ Your goal is to produce shapes by cutting, rotating, merging and painting parts
|
||||
## Building
|
||||
|
||||
- Make sure `ffmpeg` is on your path
|
||||
- Install Node.js and Yarn
|
||||
- Install Node.js (v16.0 or earlier) and Yarn
|
||||
- Install Java (required for textures)
|
||||
- Run `yarn` in the root folder
|
||||
- Cd into `gulp` folder
|
||||
|
@ -97,7 +97,6 @@ module.exports = ({ watch = false, standalone = false, chineseVersion = false, w
|
||||
loader: path.resolve(__dirname, "mod.js"),
|
||||
},
|
||||
],
|
||||
],
|
||||
},
|
||||
{
|
||||
test: /\.worker\.js$/,
|
||||
|
@ -50,7 +50,7 @@ To get into shapez.io modding, I highly recommend checking out all of the exampl
|
||||
| [usage_statistics.js](usage_statistics.js) | Displays a percentage on every building showing its utilization | Adding a new component, Adding a new GameSystem, Drawing within a GameSystem, Modifying builtin buildings, Adding custom game logic |
|
||||
| [new_item_type.js](new_item_type.js) | Adds a new type of items to the map (fluids) | Adding a new item type, modifying map generation |
|
||||
| [buildings_have_cost.js](buildings_have_cost.js) | Adds a new currency, and belts cost 1 of that currency | Extending and replacing builtin methods, Adding CSS and custom sprites |
|
||||
| [mirrored_cutter.js](mirrored_cutter.js) | Adds a mirorred variant of the cutter | Adding a new variant to existing buildings |
|
||||
| [mirrored_cutter.js](mirrored_cutter.js) | Adds a mirrored variant of the cutter | Adding a new variant to existing buildings |
|
||||
|
||||
### Creating new sprites
|
||||
|
||||
|
@ -15,9 +15,9 @@ const BeltExtension = ({ $super, $old }) => ({
|
||||
return !$old.getShowWiresLayerPreview();
|
||||
},
|
||||
|
||||
getIsReplaceable() {
|
||||
getIsReplaceable(variant, rotationVariant) {
|
||||
// Instead of super, use $super
|
||||
return $super.getIsReplaceable.call(this);
|
||||
return $super.getIsReplaceable.call(this, variant, rotationVariant);
|
||||
},
|
||||
|
||||
getIsRemoveable() {
|
||||
|
@ -87,7 +87,7 @@ class FluidItem extends shapez.BaseItem {
|
||||
* @param {number} diameter
|
||||
* @param {DrawParameters} parameters
|
||||
*/
|
||||
drawItemCenteredClipped(x, y, parameters, diameter = globalConfig.defaultItemDiameter) {
|
||||
drawItemCenteredClipped(x, y, parameters, diameter = shapez.globalConfig.defaultItemDiameter) {
|
||||
const realDiameter = diameter * 0.6;
|
||||
if (!this.cachedSprite) {
|
||||
this.cachedSprite = shapez.Loader.getSprite(`sprites/fluids/${this.fluidType}.png`);
|
||||
@ -120,19 +120,19 @@ class Mod extends shapez.Mod {
|
||||
this.modInterface.registerSprite("sprites/fluids/water.png", RESOURCES["water.png"]);
|
||||
|
||||
// Make the item spawn on the map
|
||||
this.modInterface.runAfterMethod(
|
||||
shapez.MapChunk,
|
||||
"generatePatches",
|
||||
function ({ rng, chunkCenter, distanceToOriginInChunks }) {
|
||||
// Generate a simple patch
|
||||
// ALWAYS use rng and NEVER use Math.random() otherwise the map will look different
|
||||
// every time you resume the game
|
||||
if (rng.next() > 0.8) {
|
||||
const fluidType = rng.choice(Array.from(Object.keys(enumFluidType)));
|
||||
this.internalGeneratePatch(rng, 4, FLUID_ITEM_SINGLETONS[fluidType]);
|
||||
}
|
||||
this.modInterface.runAfterMethod(shapez.MapChunk, "generatePatches", function ({
|
||||
rng,
|
||||
chunkCenter,
|
||||
distanceToOriginInChunks,
|
||||
}) {
|
||||
// Generate a simple patch
|
||||
// ALWAYS use rng and NEVER use Math.random() otherwise the map will look different
|
||||
// every time you resume the game
|
||||
if (rng.next() > 0.8) {
|
||||
const fluidType = rng.choice(Array.from(Object.keys(enumFluidType)));
|
||||
this.internalGeneratePatch(rng, 4, FLUID_ITEM_SINGLETONS[fluidType]);
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
this.modInterface.registerItem(FluidItem, itemData => FLUID_ITEM_SINGLETONS[itemData]);
|
||||
}
|
||||
|
@ -1,9 +1,10 @@
|
||||
export const CHANGELOG = [
|
||||
{
|
||||
version: "1.5.0",
|
||||
date: "unreleased",
|
||||
version: "1.5.1",
|
||||
date: "25.02.2022",
|
||||
entries: [
|
||||
"This version adds an official modloader! You can now load mods by placing it in the mods/ folder of the game.",
|
||||
"This version adds an official modloader! You can now load mods by extracting them and placing the .js file in the mods/ folder of the game.",
|
||||
"Mods can be found <a href='https://shapez.mod.io'>here</a>",
|
||||
"When holding shift while placing a belt, the indicator now becomes red when crossing buildings",
|
||||
"Lots of performance improvements, leading to up to 50% more FPS",
|
||||
],
|
||||
|
@ -211,6 +211,7 @@ export class GameState {
|
||||
/**
|
||||
* Should return the html code of the state.
|
||||
* @returns {string}
|
||||
* @abstract
|
||||
*/
|
||||
getInnerHTML() {
|
||||
abstract;
|
||||
|
@ -3,20 +3,8 @@ const options = queryString.parse(location.search);
|
||||
|
||||
export let queryParamOptions = {
|
||||
embedProvider: null,
|
||||
fullVersion: false,
|
||||
sandboxMode: false,
|
||||
};
|
||||
|
||||
if (options.embed) {
|
||||
queryParamOptions.embedProvider = options.embed;
|
||||
}
|
||||
|
||||
// Allow testing full version outside of standalone
|
||||
if (options.fullVersion && !G_IS_RELEASE) {
|
||||
queryParamOptions.fullVersion = true;
|
||||
}
|
||||
|
||||
// Allow testing full version outside of standalone
|
||||
if (options.sandboxMode && !G_IS_RELEASE) {
|
||||
queryParamOptions.sandboxMode = true;
|
||||
}
|
||||
|
@ -268,7 +268,7 @@ export class Rectangle {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns if hte rectangle contains the given point
|
||||
* Returns if the rectangle contains the given point
|
||||
* @param {number} x
|
||||
* @param {number} y
|
||||
* @returns {boolean}
|
||||
|
@ -84,11 +84,6 @@ export class RestrictionManager extends ReadWriteProxy {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (queryParamOptions.fullVersion) {
|
||||
// Full version is activated via flag
|
||||
return false;
|
||||
}
|
||||
|
||||
if (queryParamOptions.embedProvider === "gamedistribution") {
|
||||
// also full version on gamedistribution
|
||||
return false;
|
||||
|
@ -11,6 +11,7 @@ export class BaseSprite {
|
||||
/**
|
||||
* Returns the raw handle
|
||||
* @returns {HTMLImageElement|HTMLCanvasElement}
|
||||
* @abstract
|
||||
*/
|
||||
getRawTexture() {
|
||||
abstract;
|
||||
|
@ -29,6 +29,7 @@ export class BaseItem extends BasicSerializableObject {
|
||||
/**
|
||||
* Returns a string id of the item
|
||||
* @returns {string}
|
||||
* @abstract
|
||||
*/
|
||||
getAsCopyableKey() {
|
||||
abstract;
|
||||
@ -49,9 +50,9 @@ export class BaseItem extends BasicSerializableObject {
|
||||
|
||||
/**
|
||||
* Override for custom comparison
|
||||
* @abstract
|
||||
* @param {BaseItem} other
|
||||
* @returns {boolean}
|
||||
* @abstract
|
||||
*/
|
||||
equalsImpl(other) {
|
||||
abstract;
|
||||
@ -62,6 +63,7 @@ export class BaseItem extends BasicSerializableObject {
|
||||
* Draws the item to a canvas
|
||||
* @param {CanvasRenderingContext2D} context
|
||||
* @param {number} size
|
||||
* @abstract
|
||||
*/
|
||||
drawFullSizeOnCanvas(context, size) {
|
||||
abstract;
|
||||
@ -86,6 +88,7 @@ export class BaseItem extends BasicSerializableObject {
|
||||
* @param {number} y
|
||||
* @param {DrawParameters} parameters
|
||||
* @param {number=} diameter
|
||||
* @abstract
|
||||
*/
|
||||
drawItemCenteredImpl(x, y, parameters, diameter = globalConfig.defaultItemDiameter) {
|
||||
abstract;
|
||||
|
@ -1526,7 +1526,17 @@ export class BeltPath extends BasicSerializableObject {
|
||||
|
||||
const sprite = this.root.buffers.getForKey({
|
||||
key: "beltpaths",
|
||||
subKey: "stack-" + directionProp + "-" + dpi + "-" + stack.length + firstItem[1].serialize(),
|
||||
subKey:
|
||||
"stack-" +
|
||||
directionProp +
|
||||
"-" +
|
||||
dpi +
|
||||
"#" +
|
||||
stack.length +
|
||||
"#" +
|
||||
firstItem[1].getItemType() +
|
||||
"#" +
|
||||
firstItem[1].serialize(),
|
||||
dpi,
|
||||
w: dimensions.x,
|
||||
h: dimensions.y,
|
||||
|
@ -4,6 +4,7 @@ export class Component extends BasicSerializableObject {
|
||||
/**
|
||||
* Returns the components unique id
|
||||
* @returns {string}
|
||||
* @abstract
|
||||
*/
|
||||
static getId() {
|
||||
abstract;
|
||||
|
@ -224,6 +224,7 @@ export class Entity extends BasicSerializableObject {
|
||||
/**
|
||||
* override, should draw the entity
|
||||
* @param {DrawParameters} parameters
|
||||
* @abstract
|
||||
*/
|
||||
drawImpl(parameters) {
|
||||
abstract;
|
||||
|
@ -144,6 +144,7 @@ export class GameMode extends BasicSerializableObject {
|
||||
/**
|
||||
* @param {number} w
|
||||
* @param {number} h
|
||||
* @abstract
|
||||
*/
|
||||
adjustZone(w = 0, h = 0) {
|
||||
abstract;
|
||||
|
@ -25,6 +25,7 @@ export class BaseHUDPart {
|
||||
|
||||
/**
|
||||
* Should initialize the element, called *after* the elements have been created
|
||||
* @abstract
|
||||
*/
|
||||
initialize() {
|
||||
abstract;
|
||||
|
@ -192,7 +192,7 @@ export class HUDBuildingPlacerLogic extends BaseHUDPart {
|
||||
const metaBuilding = this.currentMetaBuilding.get();
|
||||
return (
|
||||
metaBuilding &&
|
||||
metaBuilding.getHasDirectionLockAvailable() &&
|
||||
metaBuilding.getHasDirectionLockAvailable(this.currentVariant.get()) &&
|
||||
this.root.keyMapper.getBinding(KEYMAPPINGS.placementModifiers.lockBeltDirection).pressed
|
||||
);
|
||||
}
|
||||
|
@ -49,7 +49,7 @@ export class HUDKeybindingOverlay extends BaseHUDPart {
|
||||
!this.mapOverviewActive &&
|
||||
placer &&
|
||||
placer.currentMetaBuilding.get() &&
|
||||
placer.currentMetaBuilding.get().getHasDirectionLockAvailable()
|
||||
placer.currentMetaBuilding.get().getHasDirectionLockAvailable(placer.currentVariant.get())
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -16,7 +16,7 @@ export function itemResolverSingleton(root, data) {
|
||||
const itemData = data.data;
|
||||
|
||||
if (MODS_ADDITIONAL_ITEMS[itemType]) {
|
||||
return MODS_ADDITIONAL_ITEMS[itemType](itemData);
|
||||
return MODS_ADDITIONAL_ITEMS[itemType](itemData, root);
|
||||
}
|
||||
|
||||
switch (itemType) {
|
||||
|
@ -72,8 +72,13 @@ export class GameLogic {
|
||||
// Check if there is any direct collision
|
||||
const otherEntity = this.root.map.getLayerContentXY(x, y, entity.layer);
|
||||
if (otherEntity) {
|
||||
const metaClass = otherEntity.components.StaticMapEntity.getMetaBuilding();
|
||||
if (!allowReplaceBuildings || !metaClass.getIsReplaceable()) {
|
||||
const staticComp = otherEntity.components.StaticMapEntity;
|
||||
if (
|
||||
!allowReplaceBuildings ||
|
||||
!staticComp
|
||||
.getMetaBuilding()
|
||||
.getIsReplaceable(staticComp.getVariant(), staticComp.getRotationVariant())
|
||||
) {
|
||||
// This one is a direct blocker
|
||||
return false;
|
||||
}
|
||||
@ -140,8 +145,11 @@ export class GameLogic {
|
||||
for (let y = rect.y; y < rect.y + rect.h; ++y) {
|
||||
const contents = this.root.map.getLayerContentXY(x, y, entity.layer);
|
||||
if (contents) {
|
||||
const staticComp = contents.components.StaticMapEntity;
|
||||
assertAlways(
|
||||
contents.components.StaticMapEntity.getMetaBuilding().getIsReplaceable(),
|
||||
staticComp
|
||||
.getMetaBuilding()
|
||||
.getIsReplaceable(staticComp.getVariant(), staticComp.getRotationVariant()),
|
||||
"Tried to replace non-repleaceable entity"
|
||||
);
|
||||
if (!this.tryDeleteBuilding(contents)) {
|
||||
|
@ -52,8 +52,9 @@ export class MetaBuilding {
|
||||
|
||||
/**
|
||||
* Returns whether the building has the direction lock switch available
|
||||
* @param {string} variant
|
||||
*/
|
||||
getHasDirectionLockAvailable() {
|
||||
getHasDirectionLockAvailable(variant) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -88,8 +89,10 @@ export class MetaBuilding {
|
||||
|
||||
/**
|
||||
* Returns whether this building can get replaced
|
||||
* @param {string} variant
|
||||
* @param {number} rotationVariant
|
||||
*/
|
||||
getIsReplaceable() {
|
||||
getIsReplaceable(variant, rotationVariant) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -278,6 +281,7 @@ export class MetaBuilding {
|
||||
* Should setup the entity components
|
||||
* @param {Entity} entity
|
||||
* @param {GameRoot} root
|
||||
* @abstract
|
||||
*/
|
||||
setupEntityComponents(entity, root) {
|
||||
abstract;
|
||||
|
@ -22,6 +22,7 @@ import { MetaTransistorBuilding } from "../buildings/transistor";
|
||||
import { HUDPuzzleEditorControls } from "../hud/parts/puzzle_editor_controls";
|
||||
import { HUDPuzzleEditorReview } from "../hud/parts/puzzle_editor_review";
|
||||
import { HUDPuzzleEditorSettings } from "../hud/parts/puzzle_editor_settings";
|
||||
import { HUDConstantSignalEdit } from "../hud/parts/constant_signal_edit";
|
||||
|
||||
export class PuzzleEditGameMode extends PuzzleGameMode {
|
||||
static getId() {
|
||||
@ -58,6 +59,7 @@ export class PuzzleEditGameMode extends PuzzleGameMode {
|
||||
this.additionalHudParts.puzzleEditorControls = HUDPuzzleEditorControls;
|
||||
this.additionalHudParts.puzzleEditorReview = HUDPuzzleEditorReview;
|
||||
this.additionalHudParts.puzzleEditorSettings = HUDPuzzleEditorSettings;
|
||||
this.additionalHudParts.constantSignalEdit = HUDConstantSignalEdit;
|
||||
}
|
||||
|
||||
getIsEditor() {
|
||||
|
@ -594,18 +594,13 @@ export class RegularGameMode extends GameMode {
|
||||
this.additionalHudParts.interactiveTutorial = HUDInteractiveTutorial;
|
||||
}
|
||||
|
||||
// @ts-ignore
|
||||
if (queryParamOptions.sandboxMode || window.sandboxMode || G_IS_DEV) {
|
||||
this.additionalHudParts.sandboxController = HUDSandboxController;
|
||||
}
|
||||
|
||||
/** @type {(typeof MetaBuilding)[]} */
|
||||
this.hiddenBuildings = [MetaConstantProducerBuilding, MetaGoalAcceptorBuilding, MetaBlockBuilding];
|
||||
|
||||
// @ts-ignore
|
||||
if (!(G_IS_DEV || window.sandboxMode || queryParamOptions.sandboxMode)) {
|
||||
this.hiddenBuildings.push(MetaItemProducerBuilding);
|
||||
}
|
||||
this.hiddenBuildings = [
|
||||
MetaConstantProducerBuilding,
|
||||
MetaGoalAcceptorBuilding,
|
||||
MetaBlockBuilding,
|
||||
MetaItemProducerBuilding,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -39,6 +39,11 @@ import { ShapeItem } from "../items/shape_item";
|
||||
*/
|
||||
export const MOD_ITEM_PROCESSOR_HANDLERS = {};
|
||||
|
||||
/**
|
||||
* @type {Object<string, ({entity: Entity}) => boolean>}
|
||||
*/
|
||||
export const MODS_CAN_PROCESS = {};
|
||||
|
||||
export class ItemProcessorSystem extends GameSystemWithFilter {
|
||||
constructor(root) {
|
||||
super(root, [ItemProcessorComponent]);
|
||||
@ -168,6 +173,12 @@ export class ItemProcessorSystem extends GameSystemWithFilter {
|
||||
const acceptorComp = entity.components.ItemAcceptor;
|
||||
const processorComp = entity.components.ItemProcessor;
|
||||
|
||||
if (MODS_CAN_PROCESS[processorComp.processingRequirement]) {
|
||||
return MODS_CAN_PROCESS[processorComp.processingRequirement].bind(this)({
|
||||
entity,
|
||||
});
|
||||
}
|
||||
|
||||
switch (processorComp.processingRequirement) {
|
||||
// DEFAULT
|
||||
// By default, we can start processing once all inputs are there
|
||||
|
@ -59,7 +59,11 @@ export class WiredPinsSystem extends GameSystemWithFilter {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (staticComp.getMetaBuilding().getIsReplaceable()) {
|
||||
if (
|
||||
staticComp
|
||||
.getMetaBuilding()
|
||||
.getIsReplaceable(staticComp.getVariant(), staticComp.getRotationVariant())
|
||||
) {
|
||||
// Don't mind here, even if there would be a collision we
|
||||
// could replace it
|
||||
continue;
|
||||
@ -113,7 +117,12 @@ export class WiredPinsSystem extends GameSystemWithFilter {
|
||||
|
||||
// If there's an entity, and it can't get removed -> That's a collision
|
||||
if (collidingEntity) {
|
||||
if (!collidingEntity.components.StaticMapEntity.getMetaBuilding().getIsReplaceable()) {
|
||||
const staticComp = collidingEntity.components.StaticMapEntity;
|
||||
if (
|
||||
!staticComp
|
||||
.getMetaBuilding()
|
||||
.getIsReplaceable(staticComp.getVariant(), staticComp.getRotationVariant())
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -138,8 +147,11 @@ export class WiredPinsSystem extends GameSystemWithFilter {
|
||||
const worldPos = entity.components.StaticMapEntity.localTileToWorld(slot.pos);
|
||||
const collidingEntity = this.root.map.getLayerContentXY(worldPos.x, worldPos.y, "wires");
|
||||
if (collidingEntity) {
|
||||
const staticComp = collidingEntity.components.StaticMapEntity;
|
||||
assertAlways(
|
||||
collidingEntity.components.StaticMapEntity.getMetaBuilding().getIsReplaceable(),
|
||||
staticComp
|
||||
.getMetaBuilding()
|
||||
.getIsReplaceable(staticComp.getVariant(), staticComp.getRotationVariant()),
|
||||
"Tried to replace non-repleaceable entity for pins"
|
||||
);
|
||||
if (!this.root.logic.tryDeleteBuilding(collidingEntity)) {
|
||||
|
@ -92,6 +92,7 @@ export class AchievementProviderInterface {
|
||||
/**
|
||||
* Initializes the achievement provider.
|
||||
* @returns {Promise<void>}
|
||||
* @abstract
|
||||
*/
|
||||
initialize() {
|
||||
abstract;
|
||||
@ -102,6 +103,7 @@ export class AchievementProviderInterface {
|
||||
* Opportunity to do additional initialization work with the GameRoot.
|
||||
* @param {GameRoot} root
|
||||
* @returns {Promise<void>}
|
||||
* @abstract
|
||||
*/
|
||||
onLoad(root) {
|
||||
abstract;
|
||||
@ -118,6 +120,7 @@ export class AchievementProviderInterface {
|
||||
* Call to activate an achievement with the provider
|
||||
* @param {string} key - Maps to an Achievement
|
||||
* @returns {Promise<void>}
|
||||
* @abstract
|
||||
*/
|
||||
activate(key) {
|
||||
abstract;
|
||||
@ -127,6 +130,7 @@ export class AchievementProviderInterface {
|
||||
/**
|
||||
* Checks if achievements are supported in the current build
|
||||
* @returns {boolean}
|
||||
* @abstract
|
||||
*/
|
||||
hasAchievements() {
|
||||
abstract;
|
||||
|
@ -19,6 +19,7 @@ export class AdProviderInterface {
|
||||
/**
|
||||
* Returns if this provider serves ads at all
|
||||
* @returns {boolean}
|
||||
* @abstract
|
||||
*/
|
||||
getHasAds() {
|
||||
abstract;
|
||||
@ -29,6 +30,7 @@ export class AdProviderInterface {
|
||||
* Returns if it would be possible to show a video ad *now*. This can be false if for
|
||||
* example the last video ad is
|
||||
* @returns {boolean}
|
||||
* @abstract
|
||||
*/
|
||||
getCanShowVideoAd() {
|
||||
abstract;
|
||||
|
@ -11,6 +11,7 @@ export class AnalyticsInterface {
|
||||
/**
|
||||
* Initializes the analytics
|
||||
* @returns {Promise<void>}
|
||||
* @abstract
|
||||
*/
|
||||
initialize() {
|
||||
abstract;
|
||||
|
@ -1,6 +1,5 @@
|
||||
import { globalConfig } from "../../core/config";
|
||||
import { createLogger } from "../../core/logging";
|
||||
import { queryParamOptions } from "../../core/query_parameters";
|
||||
import { BeltComponent } from "../../game/components/belt";
|
||||
import { StaticMapEntityComponent } from "../../game/components/static_map_entity";
|
||||
import { RegularGameMode } from "../../game/modes/regular";
|
||||
@ -24,9 +23,6 @@ export class ShapezGameAnalytics extends GameAnalyticsInterface {
|
||||
}
|
||||
|
||||
if (G_IS_STANDALONE) {
|
||||
if (queryParamOptions.sandboxMode) {
|
||||
return "steam-sandbox";
|
||||
}
|
||||
return "steam";
|
||||
}
|
||||
|
||||
@ -35,14 +31,8 @@ export class ShapezGameAnalytics extends GameAnalyticsInterface {
|
||||
}
|
||||
|
||||
if (window.location.host.indexOf("alpha") >= 0) {
|
||||
if (queryParamOptions.sandboxMode) {
|
||||
return "alpha-sandbox";
|
||||
}
|
||||
return "alpha";
|
||||
} else {
|
||||
if (queryParamOptions.sandboxMode) {
|
||||
return "beta-sandbox";
|
||||
}
|
||||
return "beta";
|
||||
}
|
||||
}
|
||||
|
@ -11,6 +11,7 @@ export class GameAnalyticsInterface {
|
||||
/**
|
||||
* Initializes the analytics
|
||||
* @returns {Promise<void>}
|
||||
* @abstract
|
||||
*/
|
||||
initialize() {
|
||||
abstract;
|
||||
@ -43,6 +44,7 @@ export class GameAnalyticsInterface {
|
||||
/**
|
||||
* Activates a DLC
|
||||
* @param {string} dlc
|
||||
* @abstract
|
||||
*/
|
||||
activateDlc(dlc) {
|
||||
abstract;
|
||||
|
@ -13,6 +13,7 @@ export class StorageInterface {
|
||||
/**
|
||||
* Initializes the storage
|
||||
* @returns {Promise<void>}
|
||||
* @abstract
|
||||
*/
|
||||
initialize() {
|
||||
abstract;
|
||||
@ -24,6 +25,7 @@ export class StorageInterface {
|
||||
* @param {string} filename
|
||||
* @param {string} contents
|
||||
* @returns {Promise<void>}
|
||||
* @abstract
|
||||
*/
|
||||
writeFileAsync(filename, contents) {
|
||||
abstract;
|
||||
@ -34,6 +36,7 @@ export class StorageInterface {
|
||||
* Reads a string asynchronously. Returns Promise<FILE_NOT_FOUND> if file was not found.
|
||||
* @param {string} filename
|
||||
* @returns {Promise<string>}
|
||||
* @abstract
|
||||
*/
|
||||
readFileAsync(filename) {
|
||||
abstract;
|
||||
|
@ -81,6 +81,7 @@ export class PlatformWrapperInterface {
|
||||
* Attempt to open an external url
|
||||
* @param {string} url
|
||||
* @param {boolean=} force Whether to always open the url even if not allowed
|
||||
* @abstract
|
||||
*/
|
||||
openExternalLink(url, force = false) {
|
||||
abstract;
|
||||
@ -88,6 +89,7 @@ export class PlatformWrapperInterface {
|
||||
|
||||
/**
|
||||
* Attempt to restart the app
|
||||
* @abstract
|
||||
*/
|
||||
performRestart() {
|
||||
abstract;
|
||||
@ -103,6 +105,7 @@ export class PlatformWrapperInterface {
|
||||
/**
|
||||
* Should set the apps fullscreen state to the desired state
|
||||
* @param {boolean} flag
|
||||
* @abstract
|
||||
*/
|
||||
setFullscreen(flag) {
|
||||
abstract;
|
||||
@ -117,6 +120,7 @@ export class PlatformWrapperInterface {
|
||||
|
||||
/**
|
||||
* Attempts to quit the app
|
||||
* @abstract
|
||||
*/
|
||||
exitApp() {
|
||||
abstract;
|
||||
|
@ -64,6 +64,7 @@ export class BaseSetting {
|
||||
/**
|
||||
* Returns the HTML for this setting
|
||||
* @param {Application} app
|
||||
* @abstract
|
||||
*/
|
||||
getHtml(app) {
|
||||
abstract;
|
||||
@ -84,6 +85,7 @@ export class BaseSetting {
|
||||
|
||||
/**
|
||||
* Attempts to modify the setting
|
||||
* @abstract
|
||||
*/
|
||||
modify() {
|
||||
abstract;
|
||||
@ -107,6 +109,7 @@ export class BaseSetting {
|
||||
* Validates the set value
|
||||
* @param {any} value
|
||||
* @returns {boolean}
|
||||
* @abstract
|
||||
*/
|
||||
validate(value) {
|
||||
abstract;
|
||||
|
@ -48,6 +48,7 @@ export class BaseDataType {
|
||||
/**
|
||||
* Serializes a given raw value
|
||||
* @param {any} value
|
||||
* @abstract
|
||||
*/
|
||||
serialize(value) {
|
||||
abstract;
|
||||
@ -68,6 +69,7 @@ export class BaseDataType {
|
||||
* @param {object} targetObject
|
||||
* @param {string|number} targetKey
|
||||
* @returns {string|void} String error code or null on success
|
||||
* @abstract
|
||||
*/
|
||||
deserialize(value, targetObject, targetKey, root) {
|
||||
abstract;
|
||||
@ -92,6 +94,7 @@ export class BaseDataType {
|
||||
|
||||
/**
|
||||
* INTERNAL Should return the json schema representation
|
||||
* @abstract
|
||||
*/
|
||||
getAsJsonSchemaUncached() {
|
||||
abstract;
|
||||
@ -131,6 +134,7 @@ export class BaseDataType {
|
||||
|
||||
/**
|
||||
* Should return a cacheable key
|
||||
* @abstract
|
||||
*/
|
||||
getCacheKey() {
|
||||
abstract;
|
||||
|
@ -1013,10 +1013,8 @@ tips:
|
||||
- <b>SHIFT</b>を押したままにするとベルトプランナーが有効になり、長距離のベルトを簡単に配置できます。
|
||||
- 切断機は配置された向きを考慮せず、常に垂直に切断します。
|
||||
- ストレージは左側の出力を優先します。
|
||||
- 増築可能なデザインを作るために時間を使ってください。それだけの価値があります!
|
||||
- Invest time to build repeatable designs - it's worth it!
|
||||
- 増築可能なデザインを目指してみましょう。それだけの価値があります!
|
||||
- <b>ALT</b>を押しながらベルトを設置すると、向きを逆転できます。
|
||||
- You can hold <b>ALT</b> to invert the direction of placed belts.
|
||||
- ハブから遠くに離れるほど、形状資源はより複雑な形になります。
|
||||
- 機械の速度には上限があるので、最大効率を得るためには入力を分割してください。
|
||||
- 効率を最大化するために分配機/合流機を使用できます。
|
||||
@ -1032,8 +1030,7 @@ tips:
|
||||
- モジュールがあれば、空間はただの認識に過ぎなくなる――生ある人間に対する気遣いだ。
|
||||
- 設計図としての工場を別に作っておくと、工場のモジュール化において重要な役割を果たします。
|
||||
- 混色機をよく見ると、色の混ぜ方が解ります。
|
||||
- Have a closer look at the color mixer, and your questions will be answered.
|
||||
- Use <b>CTRL</b> + Click to select an area.
|
||||
- <b>CTRL</b>を押したままクリックすると、領域を選択できます。
|
||||
- アップグレードリストの各形状の横にあるピンのアイコンは、その形状を画面左に固定表示します。
|
||||
- 三原色全てを混ぜ合わせると白になります!
|
||||
- マップは無限の広さがあります。臆せずに拡張してください。
|
||||
@ -1046,8 +1043,7 @@ tips:
|
||||
- ベルトの中身をクリアするには、範囲選択して同じ場所に貼り付けをします。
|
||||
- F4を押すことで、FPSとTickレートを表示できます。
|
||||
- F4を2回押すと、マウスとカメラの座標を表示できます。
|
||||
- 左のピン留めされた図形をクリックすると、固定を解除できます。
|
||||
- You can click a pinned shape on the left side to unpin it.
|
||||
- 左のピン留めされた図形をクリックすると、ピン留めを解除できます。
|
||||
puzzleMenu:
|
||||
play: Play
|
||||
edit: Edit
|
||||
|
@ -50,7 +50,7 @@ global:
|
||||
escape: ESC
|
||||
shift: SHIFT
|
||||
space: ПРОБЕЛ
|
||||
loggingIn: Logging in
|
||||
loggingIn: Вход
|
||||
demoBanners:
|
||||
title: Демоверсия
|
||||
intro: Приобретите полную версию, чтобы разблокировать все возможности!
|
||||
@ -74,14 +74,14 @@ mainMenu:
|
||||
puzzleMode: Головоломка
|
||||
back: Назад
|
||||
puzzleDlcText: Нравится оптимизировать фабрики и делать их меньше? Купите
|
||||
обновление "Головоломка" в Steam сейчас и получите еще больше
|
||||
обновление «Головоломка» в Steam сейчас и получите еще больше
|
||||
удовольствия!
|
||||
puzzleDlcWishlist: Добавь в список желаемого!
|
||||
puzzleDlcViewNow: Посмотреть
|
||||
mods:
|
||||
title: Active Mods
|
||||
warningPuzzleDLC: Playing the Puzzle DLC is not possible with mods. Please
|
||||
disable all mods to play the DLC.
|
||||
title: Активные моды
|
||||
warningPuzzleDLC: Обновление «Головоломка» невозможна с модами. Пожалуйста,
|
||||
отключите все моды, чтобы играть в DLC.
|
||||
dialogs:
|
||||
buttons:
|
||||
ok: OK
|
||||
@ -230,8 +230,8 @@ dialogs:
|
||||
desc: "Не удалось отправить вашу головоломку:"
|
||||
puzzleSubmitOk:
|
||||
title: Головоломка опубликована
|
||||
desc: Поздравляю! Ваша головоломка была опубликована, и теперь в нее могут
|
||||
играть остальные. Теперь вы можете найти ее в разделе "Мои
|
||||
desc: Поздравляю! Ваша головоломка была опубликована, и теперь в неё могут
|
||||
играть остальные. Теперь вы можете найти её в разделе "Мои
|
||||
головоломки".
|
||||
puzzleCreateOffline:
|
||||
title: Оффлайн режим
|
||||
@ -265,12 +265,13 @@ dialogs:
|
||||
title: Удалить головоломку?
|
||||
desc: Вы уверены, что хотите удалить '<title>'? Это действие нельзя отменить!
|
||||
modsDifference:
|
||||
title: Mod Warning
|
||||
desc: The currently installed mods differ from the mods the savegame was created
|
||||
with. This might cause the savegame to break or not load at all. Are
|
||||
you sure you want to continue?
|
||||
missingMods: Missing Mods
|
||||
newMods: Newly installed Mods
|
||||
title: Предупреждение Мода
|
||||
desc: Установленные в данный момент моды отличаются от модов, с которыми была
|
||||
создана игра сохранения с ним. Это может привести к тому, что сохранение
|
||||
не загрузится или вообще ничего не загрузится. Вы вы уверены, что хотите
|
||||
продолжить?
|
||||
missingMods: Отсутствуют Моды
|
||||
newMods: Недавно установленные Моды
|
||||
ingame:
|
||||
keybindingsOverlay:
|
||||
moveMap: Передвижение
|
||||
@ -1312,19 +1313,19 @@ backendErrors:
|
||||
все еще хотите удалить ее, обратитесь в support@shapez.io!
|
||||
no-permission: У вас нет прав на выполнение этого действия.
|
||||
mods:
|
||||
title: Mods
|
||||
author: Author
|
||||
version: Version
|
||||
modWebsite: Website
|
||||
openFolder: Open Mods Folder
|
||||
folderOnlyStandalone: Opening the mod folder is only possible when running the standalone.
|
||||
browseMods: Browse Mods
|
||||
modsInfo: To install and manage mods, copy them to the mods folder within the
|
||||
game directory. You can also use the 'Open Mods Folder' button on the
|
||||
top right.
|
||||
noModSupport: You need the standalone version on Steam to install mods.
|
||||
title: Моды
|
||||
author: Автор
|
||||
version: Версия
|
||||
modWebsite: Веб-сайт
|
||||
openFolder: Открыть папку с Модами
|
||||
folderOnlyStandalone: Открытие папки Модов возможно только при запуске автономного режима.
|
||||
browseMods: Просмотреть Моды
|
||||
modsInfo: Чтобы установить и управлять модами, скопируйте их в папку модов в
|
||||
директории игры. Вы также можете воспользоваться кнопкой "Открыть папку модов" в
|
||||
справа вверху.
|
||||
noModSupport: Для установки модов вам нужна автономная версия в Steam.
|
||||
togglingComingSoon:
|
||||
title: Coming Soon
|
||||
description: Enabling or disabling mods is currently only possible by copying
|
||||
the mod file from or to the mods/ folder. However, being able to
|
||||
toggle them here is planned for a future update!
|
||||
title: Совсем скоро
|
||||
description: Включение или отключение модов в настоящее время возможно только
|
||||
путем копирования файла мода из/в папку mods/. Однако, возможность
|
||||
управлять ими здесь планируется в будущем обновлении!
|
||||
|
@ -52,7 +52,7 @@ global:
|
||||
escape: ESC
|
||||
shift: SKIFT
|
||||
space: MELLANSLAG
|
||||
loggingIn: Logging in
|
||||
loggingIn: Loggar in
|
||||
demoBanners:
|
||||
title: Demo-version
|
||||
intro: Skaffa den fristående versionen för att låsa upp alla funktioner!
|
||||
|
Loading…
Reference in New Issue
Block a user