Add potato mode
Before Width: | Height: | Size: 1.3 MiB After Width: | Height: | Size: 1.3 MiB |
Before Width: | Height: | Size: 281 KiB After Width: | Height: | Size: 278 KiB |
Before Width: | Height: | Size: 661 KiB After Width: | Height: | Size: 690 KiB |
BIN
res_raw/sprites/belt/potato_mode/forward.png
Normal file
After Width: | Height: | Size: 2.0 KiB |
BIN
res_raw/sprites/belt/potato_mode/left.png
Normal file
After Width: | Height: | Size: 5.3 KiB |
BIN
res_raw/sprites/belt/potato_mode/right.png
Normal file
After Width: | Height: | Size: 5.0 KiB |
@ -5,6 +5,8 @@ import { round3Digits } from "./utils";
|
|||||||
export const ORIGINAL_SPRITE_SCALE = "0.75";
|
export const ORIGINAL_SPRITE_SCALE = "0.75";
|
||||||
export const FULL_CLIP_RECT = new Rectangle(0, 0, 1, 1);
|
export const FULL_CLIP_RECT = new Rectangle(0, 0, 1, 1);
|
||||||
|
|
||||||
|
const EXTRUDE = 0.1;
|
||||||
|
|
||||||
export class BaseSprite {
|
export class BaseSprite {
|
||||||
/**
|
/**
|
||||||
* Returns the raw handle
|
* Returns the raw handle
|
||||||
@ -211,10 +213,10 @@ export class AtlasSprite extends BaseSprite {
|
|||||||
srcH,
|
srcH,
|
||||||
|
|
||||||
// dest pos and size
|
// dest pos and size
|
||||||
destX,
|
destX - EXTRUDE,
|
||||||
destY,
|
destY - EXTRUDE,
|
||||||
destW,
|
destW + 2 * EXTRUDE,
|
||||||
destH
|
destH + 2 * EXTRUDE
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -267,10 +269,10 @@ export class AtlasSprite extends BaseSprite {
|
|||||||
srcH,
|
srcH,
|
||||||
|
|
||||||
// dest pos and size
|
// dest pos and size
|
||||||
destX,
|
destX - EXTRUDE,
|
||||||
destY,
|
destY - EXTRUDE,
|
||||||
destW,
|
destW + 2 * EXTRUDE,
|
||||||
destH
|
destH + 2 * EXTRUDE
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@ import { globalConfig } from "../core/config";
|
|||||||
import { DrawParameters } from "../core/draw_parameters";
|
import { DrawParameters } from "../core/draw_parameters";
|
||||||
import { createLogger } from "../core/logging";
|
import { createLogger } from "../core/logging";
|
||||||
import { Rectangle } from "../core/rectangle";
|
import { Rectangle } from "../core/rectangle";
|
||||||
import { epsilonCompare, round4Digits, clamp } from "../core/utils";
|
import { clamp, epsilonCompare, round4Digits } from "../core/utils";
|
||||||
import { enumDirection, enumDirectionToVector, enumInvertedDirections, Vector } from "../core/vector";
|
import { enumDirection, enumDirectionToVector, enumInvertedDirections, Vector } from "../core/vector";
|
||||||
import { BasicSerializableObject, types } from "../savegame/serialization";
|
import { BasicSerializableObject, types } from "../savegame/serialization";
|
||||||
import { BaseItem } from "./base_item";
|
import { BaseItem } from "./base_item";
|
||||||
@ -1069,12 +1069,14 @@ export class BeltPath extends BasicSerializableObject {
|
|||||||
// Trigger animation on the acceptor comp
|
// Trigger animation on the acceptor comp
|
||||||
const targetAcceptorComp = this.acceptorTarget.entity.components.ItemAcceptor;
|
const targetAcceptorComp = this.acceptorTarget.entity.components.ItemAcceptor;
|
||||||
if (targetAcceptorComp) {
|
if (targetAcceptorComp) {
|
||||||
targetAcceptorComp.onItemAccepted(
|
if (!this.root.app.settings.getAllSettings().simplifiedBelts) {
|
||||||
this.acceptorTarget.slot,
|
targetAcceptorComp.onItemAccepted(
|
||||||
this.acceptorTarget.direction,
|
this.acceptorTarget.slot,
|
||||||
item,
|
this.acceptorTarget.direction,
|
||||||
remainingProgress
|
item,
|
||||||
);
|
remainingProgress
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -1179,6 +1181,35 @@ export class BeltPath extends BasicSerializableObject {
|
|||||||
parameters.context.fillRect(firstItemIndicator.x - 3, firstItemIndicator.y - 1, 6, 2);
|
parameters.context.fillRect(firstItemIndicator.x - 3, firstItemIndicator.y - 1, 6, 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if this belt path should render simplified
|
||||||
|
*/
|
||||||
|
checkIsPotatoMode() {
|
||||||
|
// POTATO Mode: Only show items when belt is hovered
|
||||||
|
if (!this.root.app.settings.getAllSettings().simplifiedBelts) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const mousePos = this.root.app.mousePosition;
|
||||||
|
if (!mousePos) {
|
||||||
|
// Mouse not registered
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const tile = this.root.camera.screenToWorld(mousePos).toTileSpace();
|
||||||
|
const contents = this.root.map.getLayerContentXY(tile.x, tile.y, "regular");
|
||||||
|
if (!contents || !contents.components.Belt) {
|
||||||
|
// Nothing below
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (contents.components.Belt.assignedPath !== this) {
|
||||||
|
// Not this path
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Draws the path
|
* Draws the path
|
||||||
* @param {DrawParameters} parameters
|
* @param {DrawParameters} parameters
|
||||||
@ -1193,6 +1224,29 @@ export class BeltPath extends BasicSerializableObject {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this.checkIsPotatoMode()) {
|
||||||
|
const firstItem = this.items[0];
|
||||||
|
if (this.entityPath.length > 1 && firstItem) {
|
||||||
|
const medianBeltIndex = clamp(
|
||||||
|
Math.round(this.entityPath.length / 2 - 1),
|
||||||
|
0,
|
||||||
|
this.entityPath.length - 1
|
||||||
|
);
|
||||||
|
const medianBelt = this.entityPath[medianBeltIndex];
|
||||||
|
const staticComp = medianBelt.components.StaticMapEntity;
|
||||||
|
const centerPosLocal = medianBelt.components.Belt.transformBeltToLocalSpace(
|
||||||
|
this.entityPath.length % 2 === 0 ? 1 : 0.5
|
||||||
|
);
|
||||||
|
const centerPos = staticComp.localTileToWorld(centerPosLocal).toWorldSpaceCenterOfTile();
|
||||||
|
|
||||||
|
parameters.context.globalAlpha = 0.5;
|
||||||
|
firstItem[_item].drawItemCenteredClipped(centerPos.x, centerPos.y, parameters);
|
||||||
|
parameters.context.globalAlpha = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
let currentItemPos = this.spacingToFirstItem;
|
let currentItemPos = this.spacingToFirstItem;
|
||||||
let currentItemIndex = 0;
|
let currentItemIndex = 0;
|
||||||
|
|
||||||
|
@ -88,16 +88,17 @@ export class MapChunkView extends MapChunk {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const dims = globalConfig.mapChunkWorldSize;
|
const dims = globalConfig.mapChunkWorldSize;
|
||||||
|
const extrude = 0.05;
|
||||||
|
|
||||||
// Draw chunk "pixel" art
|
// Draw chunk "pixel" art
|
||||||
parameters.context.imageSmoothingEnabled = false;
|
parameters.context.imageSmoothingEnabled = false;
|
||||||
drawSpriteClipped({
|
drawSpriteClipped({
|
||||||
parameters,
|
parameters,
|
||||||
sprite,
|
sprite,
|
||||||
x: this.x * dims,
|
x: this.x * dims - extrude,
|
||||||
y: this.y * dims,
|
y: this.y * dims - extrude,
|
||||||
w: dims,
|
w: dims + 2 * extrude,
|
||||||
h: dims,
|
h: dims + 2 * extrude,
|
||||||
originalW: overlaySize,
|
originalW: overlaySize,
|
||||||
originalH: overlaySize,
|
originalH: overlaySize,
|
||||||
});
|
});
|
||||||
|
@ -7,13 +7,13 @@ import { AtlasSprite } from "../../core/sprites";
|
|||||||
import { fastArrayDeleteValue } from "../../core/utils";
|
import { fastArrayDeleteValue } from "../../core/utils";
|
||||||
import { enumDirection, enumDirectionToVector, enumInvertedDirections, Vector } from "../../core/vector";
|
import { enumDirection, enumDirectionToVector, enumInvertedDirections, Vector } from "../../core/vector";
|
||||||
import { BeltPath } from "../belt_path";
|
import { BeltPath } from "../belt_path";
|
||||||
|
import { arrayBeltVariantToRotation, MetaBeltBuilding } from "../buildings/belt";
|
||||||
|
import { getCodeFromBuildingData } from "../building_codes";
|
||||||
import { BeltComponent } from "../components/belt";
|
import { BeltComponent } from "../components/belt";
|
||||||
import { Entity } from "../entity";
|
import { Entity } from "../entity";
|
||||||
import { GameSystemWithFilter } from "../game_system_with_filter";
|
import { GameSystemWithFilter } from "../game_system_with_filter";
|
||||||
import { MapChunkView } from "../map_chunk_view";
|
import { MapChunkView } from "../map_chunk_view";
|
||||||
import { defaultBuildingVariant } from "../meta_building";
|
import { defaultBuildingVariant } from "../meta_building";
|
||||||
import { getCodeFromBuildingData } from "../building_codes";
|
|
||||||
import { arrayBeltVariantToRotation, MetaBeltBuilding } from "../buildings/belt";
|
|
||||||
|
|
||||||
export const BELT_ANIM_COUNT = 14;
|
export const BELT_ANIM_COUNT = 14;
|
||||||
|
|
||||||
@ -43,6 +43,16 @@ export class BeltSystem extends GameSystemWithFilter {
|
|||||||
[enumDirection.right]: [],
|
[enumDirection.right]: [],
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stores simplified sprites of a belt
|
||||||
|
* @type {Object<enumDirection, AtlasSprite>}
|
||||||
|
*/
|
||||||
|
this.potatoBeltSprites = {
|
||||||
|
[enumDirection.top]: Loader.getSprite("sprites/belt/potato_mode/forward.png"),
|
||||||
|
[enumDirection.right]: Loader.getSprite("sprites/belt/potato_mode/right.png"),
|
||||||
|
[enumDirection.left]: Loader.getSprite("sprites/belt/potato_mode/left.png"),
|
||||||
|
};
|
||||||
|
|
||||||
for (let i = 0; i < BELT_ANIM_COUNT; ++i) {
|
for (let i = 0; i < BELT_ANIM_COUNT; ++i) {
|
||||||
this.beltAnimations[enumDirection.top].push(
|
this.beltAnimations[enumDirection.top].push(
|
||||||
Loader.getSprite("sprites/belt/built/forward_" + i + ".png")
|
Loader.getSprite("sprites/belt/built/forward_" + i + ".png")
|
||||||
@ -496,14 +506,43 @@ export class BeltSystem extends GameSystemWithFilter {
|
|||||||
globalConfig.itemSpacingOnBelts
|
globalConfig.itemSpacingOnBelts
|
||||||
);
|
);
|
||||||
const contents = chunk.containedEntitiesByLayer.regular;
|
const contents = chunk.containedEntitiesByLayer.regular;
|
||||||
for (let i = 0; i < contents.length; ++i) {
|
|
||||||
const entity = contents[i];
|
|
||||||
if (entity.components.Belt) {
|
|
||||||
const direction = entity.components.Belt.direction;
|
|
||||||
const sprite = this.beltAnimations[direction][animationIndex % BELT_ANIM_COUNT];
|
|
||||||
|
|
||||||
// Culling happens within the static map entity component
|
if (this.root.app.settings.getAllSettings().simplifiedBelts) {
|
||||||
entity.components.StaticMapEntity.drawSpriteOnBoundsClipped(parameters, sprite, 0);
|
// POTATO Mode: Only show items when belt is hovered
|
||||||
|
let hoveredBeltPath = null;
|
||||||
|
const mousePos = this.root.app.mousePosition;
|
||||||
|
if (mousePos) {
|
||||||
|
const tile = this.root.camera.screenToWorld(mousePos).toTileSpace();
|
||||||
|
const contents = this.root.map.getLayerContentXY(tile.x, tile.y, "regular");
|
||||||
|
if (contents && contents.components.Belt) {
|
||||||
|
hoveredBeltPath = contents.components.Belt.assignedPath;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let i = 0; i < contents.length; ++i) {
|
||||||
|
const entity = contents[i];
|
||||||
|
if (entity.components.Belt) {
|
||||||
|
const direction = entity.components.Belt.direction;
|
||||||
|
let sprite = this.potatoBeltSprites[direction];
|
||||||
|
|
||||||
|
if (entity.components.Belt.assignedPath === hoveredBeltPath) {
|
||||||
|
sprite = this.beltAnimations[direction][animationIndex % BELT_ANIM_COUNT];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Culling happens within the static map entity component
|
||||||
|
entity.components.StaticMapEntity.drawSpriteOnBoundsClipped(parameters, sprite, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (let i = 0; i < contents.length; ++i) {
|
||||||
|
const entity = contents[i];
|
||||||
|
if (entity.components.Belt) {
|
||||||
|
const direction = entity.components.Belt.direction;
|
||||||
|
const sprite = this.beltAnimations[direction][animationIndex % BELT_ANIM_COUNT];
|
||||||
|
|
||||||
|
// Culling happens within the static map entity component
|
||||||
|
entity.components.StaticMapEntity.drawSpriteOnBoundsClipped(parameters, sprite, 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,6 +15,11 @@ export class ItemAcceptorSystem extends GameSystemWithFilter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
update() {
|
update() {
|
||||||
|
if (this.root.app.settings.getAllSettings().simplifiedBelts) {
|
||||||
|
// Disabled in potato mode
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// This system doesn't render anything while in map overview,
|
// This system doesn't render anything while in map overview,
|
||||||
// so simply accumulate ticks
|
// so simply accumulate ticks
|
||||||
if (this.root.camera.getIsMapOverlayActive()) {
|
if (this.root.camera.getIsMapOverlayActive()) {
|
||||||
@ -56,6 +61,11 @@ export class ItemAcceptorSystem extends GameSystemWithFilter {
|
|||||||
* @param {MapChunkView} chunk
|
* @param {MapChunkView} chunk
|
||||||
*/
|
*/
|
||||||
drawChunk(parameters, chunk) {
|
drawChunk(parameters, chunk) {
|
||||||
|
if (this.root.app.settings.getAllSettings().simplifiedBelts) {
|
||||||
|
// Disabled in potato mode
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const contents = chunk.containedEntitiesByLayer.regular;
|
const contents = chunk.containedEntitiesByLayer.regular;
|
||||||
for (let i = 0; i < contents.length; ++i) {
|
for (let i = 0; i < contents.length; ++i) {
|
||||||
const entity = contents[i];
|
const entity = contents[i];
|
||||||
|
@ -202,7 +202,13 @@ export class ItemEjectorSystem extends GameSystemWithFilter {
|
|||||||
// Try to hand over the item
|
// Try to hand over the item
|
||||||
if (this.tryPassOverItem(item, destEntity, destSlot.index)) {
|
if (this.tryPassOverItem(item, destEntity, destSlot.index)) {
|
||||||
// Handover successful, clear slot
|
// Handover successful, clear slot
|
||||||
targetAcceptorComp.onItemAccepted(destSlot.index, destSlot.acceptedDirection, item);
|
if (!this.root.app.settings.getAllSettings().simplifiedBelts) {
|
||||||
|
targetAcceptorComp.onItemAccepted(
|
||||||
|
destSlot.index,
|
||||||
|
destSlot.acceptedDirection,
|
||||||
|
item
|
||||||
|
);
|
||||||
|
}
|
||||||
sourceSlot.item = null;
|
sourceSlot.item = null;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -284,6 +290,11 @@ export class ItemEjectorSystem extends GameSystemWithFilter {
|
|||||||
* @param {MapChunkView} chunk
|
* @param {MapChunkView} chunk
|
||||||
*/
|
*/
|
||||||
drawChunk(parameters, chunk) {
|
drawChunk(parameters, chunk) {
|
||||||
|
if (this.root.app.settings.getAllSettings().simplifiedBelts) {
|
||||||
|
// Disabled in potato mode
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const contents = chunk.containedEntitiesByLayer.regular;
|
const contents = chunk.containedEntitiesByLayer.regular;
|
||||||
|
|
||||||
for (let i = 0; i < contents.length; ++i) {
|
for (let i = 0; i < contents.length; ++i) {
|
||||||
|
@ -276,6 +276,7 @@ export const allApplicationSettings = [
|
|||||||
new BoolSetting("lowQualityMapResources", enumCategories.performance, (app, value) => {}),
|
new BoolSetting("lowQualityMapResources", enumCategories.performance, (app, value) => {}),
|
||||||
new BoolSetting("disableTileGrid", enumCategories.performance, (app, value) => {}),
|
new BoolSetting("disableTileGrid", enumCategories.performance, (app, value) => {}),
|
||||||
new BoolSetting("lowQualityTextures", enumCategories.performance, (app, value) => {}),
|
new BoolSetting("lowQualityTextures", enumCategories.performance, (app, value) => {}),
|
||||||
|
new BoolSetting("simplifiedBelts", enumCategories.performance, (app, value) => {}),
|
||||||
];
|
];
|
||||||
|
|
||||||
export function getApplicationSettingById(id) {
|
export function getApplicationSettingById(id) {
|
||||||
@ -313,6 +314,7 @@ class SettingsStorage {
|
|||||||
this.lowQualityMapResources = false;
|
this.lowQualityMapResources = false;
|
||||||
this.disableTileGrid = false;
|
this.disableTileGrid = false;
|
||||||
this.lowQualityTextures = false;
|
this.lowQualityTextures = false;
|
||||||
|
this.simplifiedBelts = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @type {Object.<string, number>}
|
* @type {Object.<string, number>}
|
||||||
@ -523,7 +525,7 @@ export class ApplicationSettings extends ReadWriteProxy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getCurrentVersion() {
|
getCurrentVersion() {
|
||||||
return 26;
|
return 27;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @param {{settings: SettingsStorage, version: number}} data */
|
/** @param {{settings: SettingsStorage, version: number}} data */
|
||||||
@ -646,6 +648,11 @@ export class ApplicationSettings extends ReadWriteProxy {
|
|||||||
data.version = 26;
|
data.version = 26;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (data.version < 27) {
|
||||||
|
data.settings.simplifiedBelts = false;
|
||||||
|
data.version = 27;
|
||||||
|
}
|
||||||
|
|
||||||
return ExplainedResult.good();
|
return ExplainedResult.good();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -898,6 +898,11 @@ settings:
|
|||||||
description: >-
|
description: >-
|
||||||
Enabled by default, selects the miner if you use the pipette when hovering a resource patch.
|
Enabled by default, selects the miner if you use the pipette when hovering a resource patch.
|
||||||
|
|
||||||
|
simplifiedBelts:
|
||||||
|
title: Simplified Belts (Ugly)
|
||||||
|
description: >-
|
||||||
|
Does not render belt items except when hovering the belt, to save performance.
|
||||||
|
|
||||||
keybindings:
|
keybindings:
|
||||||
title: Keybindings
|
title: Keybindings
|
||||||
hint: >-
|
hint: >-
|
||||||
@ -1004,3 +1009,53 @@ demo:
|
|||||||
exportingBase: Exporting whole Base as Image
|
exportingBase: Exporting whole Base as Image
|
||||||
|
|
||||||
settingNotAvailable: Not available in the demo.
|
settingNotAvailable: Not available in the demo.
|
||||||
|
|
||||||
|
tips:
|
||||||
|
- The hub accepts input of any kind, not just the current shape!
|
||||||
|
- Make sure your factories are stackable - it will pay out!
|
||||||
|
- Don't build too close to the hub, or it will be a huge chaos!
|
||||||
|
- If stacking does not work, try switching the inputs.
|
||||||
|
- You can toggle the belt planner direction by pressing <b>R</b>.
|
||||||
|
- Holding <b>CTRL</b> allows dragging of belts without auto-orientation.
|
||||||
|
- Ratios stay the same, as long as all upgrades are on the same Tier.
|
||||||
|
- Serial execution is more efficient than parallel.
|
||||||
|
- You will unlock more variants of buildings later in the game!
|
||||||
|
- You can use <b>T</b> to switch between different variants.
|
||||||
|
- Symmetry is key!
|
||||||
|
- You can weave different tiers of tunnels.
|
||||||
|
- Try to build compact factories - it will pay out!
|
||||||
|
- The painter has a mirrored variant which you can select with <b>T</b>
|
||||||
|
- Having the right building ratios will maximize efficiency.
|
||||||
|
- At maximum level, 5 extractors will fill a single belt.
|
||||||
|
- Don't forget about tunnels!
|
||||||
|
- You don't need to divide up items evenly for full efficiency.
|
||||||
|
- Holding <b>SHIFT</b> will activate the belt planner, letting you place long lines of belts easily.
|
||||||
|
- Cutters always cut vertically, regardless of their orientation.
|
||||||
|
- To get white mix all three colors.
|
||||||
|
- The storage buffer priorities the first output.
|
||||||
|
- Invest time to build repeatable designs - it's worth it!
|
||||||
|
- Holding <b>CTRL</b> allows to place multiple buildings.
|
||||||
|
- You can hold <b>ALT</b> to invert the direction of placed belts.
|
||||||
|
- Efficiency is key!
|
||||||
|
- Shape patches that are further away from the hub are more complex.
|
||||||
|
- Machines have a limited speed, divide them up for maximum efficiency.
|
||||||
|
- Use balancers to maximize your efficiency.
|
||||||
|
- Organization is important. Try not to cross conveyors too much.
|
||||||
|
- Plan in advance, or it will be a huge chaos!
|
||||||
|
- Don't remove your old factories! You'll need them to unlock upgrades.
|
||||||
|
- Try beating level 18 on your own before seeking for help!
|
||||||
|
- Don't complicate things, try to stay simple and you'll go far.
|
||||||
|
- You may need to re-use factories later in the game. Plan your factories to be re-usable.
|
||||||
|
- Sometimes, you can find a needed shape in the map without creating it with stackers.
|
||||||
|
- Full windmills / pinwheels can never spawn naturally.
|
||||||
|
- Color your shapes before cutting for maximum efficiency.
|
||||||
|
- With modules, space is merely a perception; a concern for mortal men.
|
||||||
|
- Make a separate blueprint factory. They're important for modules.
|
||||||
|
- Have a closer look on the color mixer, and your questions will be answered.
|
||||||
|
- Use <b>CTRL</b> + Click to select an area.
|
||||||
|
- Building too close to the hub can get in the way of later projects.
|
||||||
|
- The pin icon next to each shape in the upgrade list pins it to the screen.
|
||||||
|
- Mix all primary colours together to make white!
|
||||||
|
- You have an infinite map, don't cramp your factory, expand!
|
||||||
|
- Also try Factorio! It's my favourite game.
|
||||||
|
- The quad cutter cuts counter-clockwise starting from the top right!
|
||||||
|