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 FULL_CLIP_RECT = new Rectangle(0, 0, 1, 1);
|
||||
|
||||
const EXTRUDE = 0.1;
|
||||
|
||||
export class BaseSprite {
|
||||
/**
|
||||
* Returns the raw handle
|
||||
@ -211,10 +213,10 @@ export class AtlasSprite extends BaseSprite {
|
||||
srcH,
|
||||
|
||||
// dest pos and size
|
||||
destX,
|
||||
destY,
|
||||
destW,
|
||||
destH
|
||||
destX - EXTRUDE,
|
||||
destY - EXTRUDE,
|
||||
destW + 2 * EXTRUDE,
|
||||
destH + 2 * EXTRUDE
|
||||
);
|
||||
}
|
||||
|
||||
@ -267,10 +269,10 @@ export class AtlasSprite extends BaseSprite {
|
||||
srcH,
|
||||
|
||||
// dest pos and size
|
||||
destX,
|
||||
destY,
|
||||
destW,
|
||||
destH
|
||||
destX - EXTRUDE,
|
||||
destY - EXTRUDE,
|
||||
destW + 2 * EXTRUDE,
|
||||
destH + 2 * EXTRUDE
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -2,7 +2,7 @@ import { globalConfig } from "../core/config";
|
||||
import { DrawParameters } from "../core/draw_parameters";
|
||||
import { createLogger } from "../core/logging";
|
||||
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 { BasicSerializableObject, types } from "../savegame/serialization";
|
||||
import { BaseItem } from "./base_item";
|
||||
@ -1069,6 +1069,7 @@ export class BeltPath extends BasicSerializableObject {
|
||||
// Trigger animation on the acceptor comp
|
||||
const targetAcceptorComp = this.acceptorTarget.entity.components.ItemAcceptor;
|
||||
if (targetAcceptorComp) {
|
||||
if (!this.root.app.settings.getAllSettings().simplifiedBelts) {
|
||||
targetAcceptorComp.onItemAccepted(
|
||||
this.acceptorTarget.slot,
|
||||
this.acceptorTarget.direction,
|
||||
@ -1076,6 +1077,7 @@ export class BeltPath extends BasicSerializableObject {
|
||||
remainingProgress
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -1179,6 +1181,35 @@ export class BeltPath extends BasicSerializableObject {
|
||||
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
|
||||
* @param {DrawParameters} parameters
|
||||
@ -1193,6 +1224,29 @@ export class BeltPath extends BasicSerializableObject {
|
||||
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 currentItemIndex = 0;
|
||||
|
||||
|
@ -88,16 +88,17 @@ export class MapChunkView extends MapChunk {
|
||||
});
|
||||
|
||||
const dims = globalConfig.mapChunkWorldSize;
|
||||
const extrude = 0.05;
|
||||
|
||||
// Draw chunk "pixel" art
|
||||
parameters.context.imageSmoothingEnabled = false;
|
||||
drawSpriteClipped({
|
||||
parameters,
|
||||
sprite,
|
||||
x: this.x * dims,
|
||||
y: this.y * dims,
|
||||
w: dims,
|
||||
h: dims,
|
||||
x: this.x * dims - extrude,
|
||||
y: this.y * dims - extrude,
|
||||
w: dims + 2 * extrude,
|
||||
h: dims + 2 * extrude,
|
||||
originalW: overlaySize,
|
||||
originalH: overlaySize,
|
||||
});
|
||||
|
@ -7,13 +7,13 @@ import { AtlasSprite } from "../../core/sprites";
|
||||
import { fastArrayDeleteValue } from "../../core/utils";
|
||||
import { enumDirection, enumDirectionToVector, enumInvertedDirections, Vector } from "../../core/vector";
|
||||
import { BeltPath } from "../belt_path";
|
||||
import { arrayBeltVariantToRotation, MetaBeltBuilding } from "../buildings/belt";
|
||||
import { getCodeFromBuildingData } from "../building_codes";
|
||||
import { BeltComponent } from "../components/belt";
|
||||
import { Entity } from "../entity";
|
||||
import { GameSystemWithFilter } from "../game_system_with_filter";
|
||||
import { MapChunkView } from "../map_chunk_view";
|
||||
import { defaultBuildingVariant } from "../meta_building";
|
||||
import { getCodeFromBuildingData } from "../building_codes";
|
||||
import { arrayBeltVariantToRotation, MetaBeltBuilding } from "../buildings/belt";
|
||||
|
||||
export const BELT_ANIM_COUNT = 14;
|
||||
|
||||
@ -43,6 +43,16 @@ export class BeltSystem extends GameSystemWithFilter {
|
||||
[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) {
|
||||
this.beltAnimations[enumDirection.top].push(
|
||||
Loader.getSprite("sprites/belt/built/forward_" + i + ".png")
|
||||
@ -496,6 +506,34 @@ export class BeltSystem extends GameSystemWithFilter {
|
||||
globalConfig.itemSpacingOnBelts
|
||||
);
|
||||
const contents = chunk.containedEntitiesByLayer.regular;
|
||||
|
||||
if (this.root.app.settings.getAllSettings().simplifiedBelts) {
|
||||
// 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) {
|
||||
@ -507,6 +545,7 @@ export class BeltSystem extends GameSystemWithFilter {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Draws the belt path debug overlays
|
||||
|
@ -15,6 +15,11 @@ export class ItemAcceptorSystem extends GameSystemWithFilter {
|
||||
}
|
||||
|
||||
update() {
|
||||
if (this.root.app.settings.getAllSettings().simplifiedBelts) {
|
||||
// Disabled in potato mode
|
||||
return;
|
||||
}
|
||||
|
||||
// This system doesn't render anything while in map overview,
|
||||
// so simply accumulate ticks
|
||||
if (this.root.camera.getIsMapOverlayActive()) {
|
||||
@ -56,6 +61,11 @@ export class ItemAcceptorSystem extends GameSystemWithFilter {
|
||||
* @param {MapChunkView} chunk
|
||||
*/
|
||||
drawChunk(parameters, chunk) {
|
||||
if (this.root.app.settings.getAllSettings().simplifiedBelts) {
|
||||
// Disabled in potato mode
|
||||
return;
|
||||
}
|
||||
|
||||
const contents = chunk.containedEntitiesByLayer.regular;
|
||||
for (let i = 0; i < contents.length; ++i) {
|
||||
const entity = contents[i];
|
||||
|
@ -202,7 +202,13 @@ export class ItemEjectorSystem extends GameSystemWithFilter {
|
||||
// Try to hand over the item
|
||||
if (this.tryPassOverItem(item, destEntity, destSlot.index)) {
|
||||
// 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;
|
||||
continue;
|
||||
}
|
||||
@ -284,6 +290,11 @@ export class ItemEjectorSystem extends GameSystemWithFilter {
|
||||
* @param {MapChunkView} chunk
|
||||
*/
|
||||
drawChunk(parameters, chunk) {
|
||||
if (this.root.app.settings.getAllSettings().simplifiedBelts) {
|
||||
// Disabled in potato mode
|
||||
return;
|
||||
}
|
||||
|
||||
const contents = chunk.containedEntitiesByLayer.regular;
|
||||
|
||||
for (let i = 0; i < contents.length; ++i) {
|
||||
|
@ -276,6 +276,7 @@ export const allApplicationSettings = [
|
||||
new BoolSetting("lowQualityMapResources", enumCategories.performance, (app, value) => {}),
|
||||
new BoolSetting("disableTileGrid", enumCategories.performance, (app, value) => {}),
|
||||
new BoolSetting("lowQualityTextures", enumCategories.performance, (app, value) => {}),
|
||||
new BoolSetting("simplifiedBelts", enumCategories.performance, (app, value) => {}),
|
||||
];
|
||||
|
||||
export function getApplicationSettingById(id) {
|
||||
@ -313,6 +314,7 @@ class SettingsStorage {
|
||||
this.lowQualityMapResources = false;
|
||||
this.disableTileGrid = false;
|
||||
this.lowQualityTextures = false;
|
||||
this.simplifiedBelts = false;
|
||||
|
||||
/**
|
||||
* @type {Object.<string, number>}
|
||||
@ -523,7 +525,7 @@ export class ApplicationSettings extends ReadWriteProxy {
|
||||
}
|
||||
|
||||
getCurrentVersion() {
|
||||
return 26;
|
||||
return 27;
|
||||
}
|
||||
|
||||
/** @param {{settings: SettingsStorage, version: number}} data */
|
||||
@ -646,6 +648,11 @@ export class ApplicationSettings extends ReadWriteProxy {
|
||||
data.version = 26;
|
||||
}
|
||||
|
||||
if (data.version < 27) {
|
||||
data.settings.simplifiedBelts = false;
|
||||
data.version = 27;
|
||||
}
|
||||
|
||||
return ExplainedResult.good();
|
||||
}
|
||||
}
|
||||
|
@ -898,6 +898,11 @@ settings:
|
||||
description: >-
|
||||
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:
|
||||
title: Keybindings
|
||||
hint: >-
|
||||
@ -1004,3 +1009,53 @@ demo:
|
||||
exportingBase: Exporting whole Base as Image
|
||||
|
||||
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!
|
||||
|