diff --git a/gulp/gulpfile.js b/gulp/gulpfile.js
index 72d5b699..a4b63dec 100644
--- a/gulp/gulpfile.js
+++ b/gulp/gulpfile.js
@@ -1,5 +1,11 @@
/* eslint-disable */
+const nodeVersion = process.versions.node.split(".")[0];
+if (nodeVersion !== "10") {
+ console.error("This cli requires exactly Node 10. You are using node " + nodeVersion);
+ process.exit(1);
+}
+
require("colors");
const gulp = require("gulp");
diff --git a/res_raw/atlas.tps b/res_raw/atlas.tps
index 9d94a757..36f93c3d 100644
--- a/res_raw/atlas.tps
+++ b/res_raw/atlas.tps
@@ -304,6 +304,24 @@
scale9FromFile
+ sprites/blueprints/cutter-quad.png
+ sprites/blueprints/painter-quad.png
+ sprites/buildings/cutter-quad.png
+ sprites/buildings/painter-quad.png
+
+ pivotPoint
+ 0.5,0.5
+ spriteScale
+ 1
+ scale9Enabled
+
+ scale9Borders
+ 192,48,384,96
+ scale9Paddings
+ 192,48,384,96
+ scale9FromFile
+
+
sprites/blueprints/cutter.png
sprites/blueprints/mixer.png
sprites/blueprints/painter.png
@@ -323,12 +341,22 @@
scale9FromFile
+ sprites/blueprints/miner-chainable.png
sprites/blueprints/miner.png
+ sprites/blueprints/rotater-ccw.png
sprites/blueprints/rotater.png
+ sprites/blueprints/splitter-compact.png
sprites/blueprints/trash.png
+ sprites/blueprints/underground_belt_entry-tier2.png
sprites/blueprints/underground_belt_entry.png
+ sprites/blueprints/underground_belt_exit-tier2.png
sprites/blueprints/underground_belt_exit.png
+ sprites/buildings/miner-chainable.png
+ sprites/buildings/rotater-ccw.png
+ sprites/buildings/splitter-compact.png
+ sprites/buildings/underground_belt_entry-tier2.png
sprites/buildings/underground_belt_entry.png
+ sprites/buildings/underground_belt_exit-tier2.png
sprites/buildings/underground_belt_exit.png
pivotPoint
@@ -344,6 +372,22 @@
scale9FromFile
+ sprites/blueprints/painter-double.png
+ sprites/buildings/painter-double.png
+
+ pivotPoint
+ 0.5,0.5
+ spriteScale
+ 1
+ scale9Enabled
+
+ scale9Borders
+ 96,96,192,192
+ scale9Paddings
+ 96,96,192,192
+ scale9FromFile
+
+
sprites/buildings/cutter.png
sprites/buildings/mixer.png
sprites/buildings/painter.png
diff --git a/src/css/ingame_hud/mass_selector.scss b/src/css/ingame_hud/mass_selector.scss
index 0e8bdcb2..99027735 100644
--- a/src/css/ingame_hud/mass_selector.scss
+++ b/src/css/ingame_hud/mass_selector.scss
@@ -3,20 +3,21 @@
@include S(top, 50px);
left: 50%;
transform: translateX(-50%);
- background: rgba(#f77, 0.8);
- @include S(border-radius, 4px);
- @include S(padding, 9px);
- @include PlainText;
+ background: rgba(lighten(#f77, 5), 0.95);
+ @include S(border-radius, 2px);
+ @include S(padding, 6px, 10px);
+ @include SuperSmallText;
color: #fff;
- display: flex;
- align-items: center;
+ // color: #f77;
.keybinding {
+ vertical-align: middle;
@include S(margin, 0, 4px);
position: relative;
top: unset;
left: unset;
right: unset;
bottom: unset;
+ @include S(margin-top, -2px);
}
}
diff --git a/src/css/main.scss b/src/css/main.scss
index a974e2e0..1bb07d65 100644
--- a/src/css/main.scss
+++ b/src/css/main.scss
@@ -54,8 +54,8 @@ ingame_HUD_PinnedShapes,
ingame_HUD_buildings_toolbar,
ingame_HUD_GameMenu,
ingame_HUD_KeybindingOverlay,
-ingame_HUD_MassSelector,
ingame_HUD_Notifications,
+ingame_HUD_MassSelector,
// Overlays
ingame_HUD_BetaOverlay,
diff --git a/src/js/core/config.js b/src/js/core/config.js
index 05cad1c8..36821b58 100644
--- a/src/js/core/config.js
+++ b/src/js/core/config.js
@@ -38,7 +38,7 @@ export const globalConfig = {
// Belt speeds
// NOTICE: Update webpack.production.config too!
- beltSpeedItemsPerSecond: 5,
+ beltSpeedItemsPerSecond: 1,
itemSpacingOnBelts: 0.63,
minerSpeedItemsPerSecond: 0, // COMPUTED
diff --git a/src/js/game/buildings/belt_base.js b/src/js/game/buildings/belt_base.js
index 8a0f5490..cfd1f299 100644
--- a/src/js/game/buildings/belt_base.js
+++ b/src/js/game/buildings/belt_base.js
@@ -93,6 +93,7 @@ export class MetaBeltBaseBuilding extends MetaBuilding {
directions: [enumDirection.bottom],
},
],
+ animated: false,
})
);
diff --git a/src/js/game/buildings/hub.js b/src/js/game/buildings/hub.js
index 6186597e..218144ee 100644
--- a/src/js/game/buildings/hub.js
+++ b/src/js/game/buildings/hub.js
@@ -44,6 +44,10 @@ export class MetaHubBuilding extends MetaBuilding {
processorType: enumItemProcessorTypes.hub,
})
);
+
+ // We render the sprite ourself
+ entity.components.StaticMapEntity.spriteKey = null;
+
entity.addComponent(new UnremovableComponent());
entity.addComponent(
new ItemAcceptorComponent({
diff --git a/src/js/game/buildings/splitter.js b/src/js/game/buildings/splitter.js
index 77d35604..d83375f5 100644
--- a/src/js/game/buildings/splitter.js
+++ b/src/js/game/buildings/splitter.js
@@ -112,7 +112,7 @@ export class MetaSplitterBuilding extends MetaBuilding {
{ pos: new Vector(1, 0), direction: enumDirection.top },
]);
- entity.components.ItemProcessor.beltUnderlays = [
+ entity.components.ItemAcceptor.beltUnderlays = [
{ pos: new Vector(0, 0), direction: enumDirection.top },
{ pos: new Vector(1, 0), direction: enumDirection.top },
];
@@ -135,7 +135,7 @@ export class MetaSplitterBuilding extends MetaBuilding {
{ pos: new Vector(0, 0), direction: enumDirection.top },
]);
- entity.components.ItemProcessor.beltUnderlays = [
+ entity.components.ItemAcceptor.beltUnderlays = [
{ pos: new Vector(0, 0), direction: enumDirection.top },
];
diff --git a/src/js/game/camera.js b/src/js/game/camera.js
index 9c0559e8..1fd235e5 100644
--- a/src/js/game/camera.js
+++ b/src/js/game/camera.js
@@ -29,6 +29,15 @@ const velocityFade = 0.98;
const velocityStrength = 0.4;
const velocityMax = 20;
+/**
+ * @enum {string}
+ */
+export const enumMouseButton = {
+ left: "left",
+ middle: "middle",
+ right: "right",
+};
+
export class Camera extends BasicSerializableObject {
constructor(root) {
super();
@@ -81,10 +90,10 @@ export class Camera extends BasicSerializableObject {
this.touchPostMoveVelocity = new Vector(0, 0);
// Handlers
- this.downPreHandler = new Signal(/* pos */);
- this.movePreHandler = new Signal(/* pos */);
- this.pinchPreHandler = new Signal(/* pos */);
- this.upPostHandler = new Signal(/* pos */);
+ this.downPreHandler = /** @type {TypedSignal<[Vector, enumMouseButton]>} */ (new Signal());
+ this.movePreHandler = /** @type {TypedSignal<[Vector]>} */ (new Signal());
+ // this.pinchPreHandler = /** @type {TypedSignal<[Vector]>} */ (new Signal());
+ this.upPostHandler = /** @type {TypedSignal<[Vector]>} */ (new Signal());
this.internalInitEvents();
this.clampZoomLevel();
@@ -411,6 +420,10 @@ export class Camera extends BasicSerializableObject {
this.touchPostMoveVelocity = new Vector(0, 0);
if (event.which === 1) {
this.combinedSingleTouchStartHandler(event.clientX, event.clientY);
+ } else if (event.which === 2) {
+ this.downPreHandler.dispatch(new Vector(event.clientX, event.clientY), enumMouseButton.middle);
+ } else if (event.which === 3) {
+ this.downPreHandler.dispatch(new Vector(event.clientX, event.clientY), enumMouseButton.right);
}
return false;
}
@@ -496,10 +509,10 @@ export class Camera extends BasicSerializableObject {
const touch = event.touches[0];
this.combinedSingleTouchStartHandler(touch.clientX, touch.clientY);
} else if (event.touches.length === 2) {
- if (this.pinchPreHandler.dispatch() === STOP_PROPAGATION) {
- // Something prevented pinching
- return false;
- }
+ // if (this.pinchPreHandler.dispatch() === STOP_PROPAGATION) {
+ // // Something prevented pinching
+ // return false;
+ // }
const touch1 = event.touches[0];
const touch2 = event.touches[1];
@@ -620,7 +633,7 @@ export class Camera extends BasicSerializableObject {
*/
combinedSingleTouchStartHandler(x, y) {
const pos = new Vector(x, y);
- if (this.downPreHandler.dispatch(pos) === STOP_PROPAGATION) {
+ if (this.downPreHandler.dispatch(pos, enumMouseButton.left) === STOP_PROPAGATION) {
// Somebody else captured it
return;
}
diff --git a/src/js/game/colors.js b/src/js/game/colors.js
index 8926dd23..6d483771 100644
--- a/src/js/game/colors.js
+++ b/src/js/game/colors.js
@@ -45,7 +45,7 @@ export const enumColorsToHexCode = {
[enumColors.purple]: "#dd66ff",
// blue + green
- [enumColors.cyan]: "#87fff5",
+ [enumColors.cyan]: "#00fcff",
// blue + green + red
[enumColors.white]: "#ffffff",
diff --git a/src/js/game/components/belt.js b/src/js/game/components/belt.js
index 339610a1..3f890b9b 100644
--- a/src/js/game/components/belt.js
+++ b/src/js/game/components/belt.js
@@ -59,9 +59,8 @@ export class BeltComponent extends Component {
/**
* Returns if the belt can currently accept an item from the given direction
- * @param {enumDirection} direction
*/
- canAcceptNewItem(direction) {
+ canAcceptNewItem() {
const firstItem = this.sortedItems[0];
if (!firstItem) {
return true;
@@ -73,9 +72,8 @@ export class BeltComponent extends Component {
/**
* Pushes a new item to the belt
* @param {BaseItem} item
- * @param {enumDirection} direction
*/
- takeNewItem(item, direction) {
+ takeNewItem(item) {
this.sortedItems.unshift([0, item]);
}
diff --git a/src/js/game/components/item_acceptor.js b/src/js/game/components/item_acceptor.js
index f696c0e4..d5546d4b 100644
--- a/src/js/game/components/item_acceptor.js
+++ b/src/js/game/components/item_acceptor.js
@@ -1,5 +1,5 @@
import { Component } from "../component";
-import { Vector, enumDirection, enumDirectionToAngle, enumInvertedDirections } from "../../core/vector";
+import { Vector, enumDirection, enumInvertedDirections } from "../../core/vector";
import { BaseItem } from "../base_item";
import { ShapeItem } from "../items/shape_item";
import { ColorItem } from "../items/color_item";
@@ -34,6 +34,23 @@ export class ItemAcceptorComponent extends Component {
filter: types.nullable(types.enum(enumItemAcceptorItemFilter)),
})
),
+ animated: types.bool,
+ beltUnderlays: types.array(
+ types.structured({
+ pos: types.vector,
+ direction: types.enum(enumDirection),
+ })
+ ),
+
+ // We don't actually need to store the animations
+ // itemConsumptionAnimations: types.array(
+ // types.structured({
+ // item: types.obj(gItemRegistry),
+ // slotIndex: types.uint,
+ // animProgress: types.float,
+ // direction: types.enum(enumDirection),
+ // })
+ // ),
};
}
@@ -41,10 +58,23 @@ export class ItemAcceptorComponent extends Component {
*
* @param {object} param0
* @param {Array<{pos: Vector, directions: enumDirection[], filter?: enumItemAcceptorItemFilter}>} param0.slots The slots from which we accept items
+ * @param {boolean=} param0.animated Whether to animate item consumption
+ * @param {Array<{pos: Vector, direction: enumDirection}>=} param0.beltUnderlays Where to render belt underlays
*/
- constructor({ slots = [] }) {
+ constructor({ slots = [], beltUnderlays = [], animated = true }) {
super();
+ this.animated = animated;
+
+ /**
+ * Fixes belt animations
+ * @type {Array<{ item: BaseItem, slotIndex: number, animProgress: number, direction: enumDirection}>}
+ */
+ this.itemConsumptionAnimations = [];
+
+ /* Which belt underlays to render */
+ this.beltUnderlays = beltUnderlays;
+
this.setSlots(slots);
}
@@ -86,6 +116,23 @@ export class ItemAcceptorComponent extends Component {
}
}
+ /**
+ * Called when an item has been accepted so that
+ * @param {number} slotIndex
+ * @param {enumDirection} direction
+ * @param {BaseItem} item
+ */
+ onItemAccepted(slotIndex, direction, item) {
+ if (this.animated) {
+ this.itemConsumptionAnimations.push({
+ item,
+ slotIndex,
+ direction,
+ animProgress: 0.0,
+ });
+ }
+ }
+
/**
* Tries to find a slot which accepts the current item
* @param {Vector} targetLocalTile
@@ -106,12 +153,6 @@ export class ItemAcceptorComponent extends Component {
for (let slotIndex = 0; slotIndex < this.slots.length; ++slotIndex) {
const slot = this.slots[slotIndex];
- // const acceptorLocalPosition = targetStaticComp.applyRotationToVector(
- // slot.pos
- // );
-
- // const acceptorGlobalPosition = acceptorLocalPosition.add(targetStaticComp.origin);
-
// Make sure the acceptor slot is on the right position
if (!slot.pos.equals(targetLocalTile)) {
continue;
@@ -130,7 +171,6 @@ export class ItemAcceptorComponent extends Component {
}
}
- // && this.canAcceptItem(slotIndex, ejectingItem)
return null;
}
}
diff --git a/src/js/game/components/item_processor.js b/src/js/game/components/item_processor.js
index 6eaaa755..0c4e90c6 100644
--- a/src/js/game/components/item_processor.js
+++ b/src/js/game/components/item_processor.js
@@ -30,12 +30,7 @@ export class ItemProcessorComponent extends Component {
nextOutputSlot: types.uint,
type: types.enum(enumItemProcessorTypes),
inputsPerCharge: types.uint,
- beltUnderlays: types.array(
- types.structured({
- pos: types.vector,
- direction: types.enum(enumDirection),
- })
- ),
+
inputSlots: types.array(
types.structured({
item: types.obj(gItemRegistry),
@@ -50,14 +45,6 @@ export class ItemProcessorComponent extends Component {
})
),
secondsUntilEject: types.float,
- itemConsumptionAnimations: types.array(
- types.structured({
- item: types.obj(gItemRegistry),
- slotIndex: types.uint,
- animProgress: types.float,
- direction: types.enum(enumDirection),
- })
- ),
};
}
@@ -66,14 +53,9 @@ export class ItemProcessorComponent extends Component {
* @param {object} param0
* @param {enumItemProcessorTypes=} param0.processorType Which type of processor this is
* @param {number=} param0.inputsPerCharge How many items this machine needs until it can start working
- * @param {Array<{pos: Vector, direction: enumDirection}>=} param0.beltUnderlays Where to render belt underlays
*
*/
- constructor({
- processorType = enumItemProcessorTypes.splitter,
- inputsPerCharge = 1,
- beltUnderlays = [],
- }) {
+ constructor({ processorType = enumItemProcessorTypes.splitter, inputsPerCharge = 1 }) {
super();
// Which slot to emit next, this is only a preference and if it can't emit
@@ -87,9 +69,6 @@ export class ItemProcessorComponent extends Component {
// How many inputs we need for one charge
this.inputsPerCharge = inputsPerCharge;
- // Which belt underlays to render
- this.beltUnderlays = beltUnderlays;
-
/**
* Our current inputs
* @type {Array<{ item: BaseItem, sourceSlot: number }>}
@@ -108,19 +87,14 @@ export class ItemProcessorComponent extends Component {
* How long it takes until we are done with the current items
*/
this.secondsUntilEject = 0;
-
- /**
- * Fixes belt animations
- * @type {Array<{ item: BaseItem, slotIndex: number, animProgress: number, direction: enumDirection}>}
- */
- this.itemConsumptionAnimations = [];
}
/**
* Tries to take the item
* @param {BaseItem} item
+ * @param {number} sourceSlot
*/
- tryTakeItem(item, sourceSlot, sourceDirection) {
+ tryTakeItem(item, sourceSlot) {
// Check that we only take one item per slot
for (let i = 0; i < this.inputSlots.length; ++i) {
const slot = this.inputSlots[i];
@@ -130,12 +104,6 @@ export class ItemProcessorComponent extends Component {
}
this.inputSlots.push({ item, sourceSlot });
- this.itemConsumptionAnimations.push({
- item,
- slotIndex: sourceSlot,
- direction: sourceDirection,
- animProgress: 0.0,
- });
return true;
}
}
diff --git a/src/js/game/components/underground_belt.js b/src/js/game/components/underground_belt.js
index 7093e4b3..92d15203 100644
--- a/src/js/game/components/underground_belt.js
+++ b/src/js/game/components/underground_belt.js
@@ -34,6 +34,9 @@ export class UndergroundBeltComponent extends Component {
this.mode = mode;
this.tier = tier;
+ /** @type {Array<{ item: BaseItem, progress: number }>} */
+ this.consumptionAnimations = [];
+
/**
* Used on both receiver and sender.
* Reciever: Used to store the next item to transfer, and to block input while doing this
diff --git a/src/js/game/core.js b/src/js/game/core.js
index db577110..b69d8227 100644
--- a/src/js/game/core.js
+++ b/src/js/game/core.js
@@ -398,10 +398,10 @@ export class GameCore {
// systems.mapResources.draw(params);
if (!this.root.camera.getIsMapOverlayActive()) {
- systems.itemProcessor.drawUnderlays(params);
+ systems.itemAcceptor.drawUnderlays(params);
systems.belt.draw(params);
systems.itemEjector.draw(params);
- systems.itemProcessor.draw(params);
+ systems.itemAcceptor.draw(params);
}
root.map.drawForeground(params);
diff --git a/src/js/game/game_system_manager.js b/src/js/game/game_system_manager.js
index 810ddec0..7cde296e 100644
--- a/src/js/game/game_system_manager.js
+++ b/src/js/game/game_system_manager.js
@@ -11,6 +11,7 @@ import { ItemProcessorSystem } from "./systems/item_processor";
import { UndergroundBeltSystem } from "./systems/underground_belt";
import { HubSystem } from "./systems/hub";
import { StaticMapEntitySystem } from "./systems/static_map_entity";
+import { ItemAcceptorSystem } from "./systems/item_acceptor";
const logger = createLogger("game_system_manager");
@@ -48,6 +49,9 @@ export class GameSystemManager {
/** @type {StaticMapEntitySystem} */
staticMapEntities: null,
+ /** @type {ItemAcceptorSystem} */
+ itemAcceptor: null,
+
/* typehints:end */
};
this.systemUpdateOrder = [];
@@ -82,6 +86,8 @@ export class GameSystemManager {
add("staticMapEntities", StaticMapEntitySystem);
+ add("itemAcceptor", ItemAcceptorSystem);
+
logger.log("📦 There are", this.systemUpdateOrder.length, "game systems");
}
diff --git a/src/js/game/hud/parts/building_placer.js b/src/js/game/hud/parts/building_placer.js
index 2fc3ba5e..d33cf559 100644
--- a/src/js/game/hud/parts/building_placer.js
+++ b/src/js/game/hud/parts/building_placer.js
@@ -17,6 +17,7 @@ import { Math_abs, Math_radians, Math_degrees } from "../../../core/builtins";
import { Loader } from "../../../core/loader";
import { drawRotatedSprite } from "../../../core/draw_utils";
import { Entity } from "../../entity";
+import { enumMouseButton } from "../../camera";
export class HUDBuildingPlacer extends BaseHUDPart {
initialize() {
@@ -45,6 +46,11 @@ export class HUDBuildingPlacer extends BaseHUDPart {
this.variantsAttach = new DynamicDomAttach(this.root, this.variantsElement, {});
+ /**
+ * Whether we are currently drag-deleting
+ */
+ this.currentlyDeleting = false;
+
/**
* Stores which variants for each building we prefer, this is based on what
* the user last selected
@@ -87,14 +93,17 @@ export class HUDBuildingPlacer extends BaseHUDPart {
/**
* mouse down pre handler
* @param {Vector} pos
+ * @param {enumMouseButton} button
*/
- onMouseDown(pos) {
+ onMouseDown(pos, button) {
if (this.root.camera.getIsMapOverlayActive()) {
return;
}
- if (this.currentMetaBuilding.get()) {
+ // Placement
+ if (button === enumMouseButton.left && this.currentMetaBuilding.get()) {
this.currentlyDragging = true;
+ this.currentlyDeleting = false;
this.lastDragTile = this.root.camera.screenToWorld(pos).toTileSpace();
// Place initial building
@@ -102,6 +111,15 @@ export class HUDBuildingPlacer extends BaseHUDPart {
return STOP_PROPAGATION;
}
+
+ // Deletion
+ if (button === enumMouseButton.right && !this.currentMetaBuilding.get()) {
+ this.currentlyDragging = true;
+ this.currentlyDeleting = true;
+ this.lastDragTile = this.root.camera.screenToWorld(pos).toTileSpace();
+ this.currentMetaBuilding.set(null);
+ return STOP_PROPAGATION;
+ }
}
/**
@@ -114,7 +132,7 @@ export class HUDBuildingPlacer extends BaseHUDPart {
}
const metaBuilding = this.currentMetaBuilding.get();
- if (metaBuilding && this.lastDragTile) {
+ if ((metaBuilding || this.currentlyDeleting) && this.lastDragTile) {
const oldPos = this.lastDragTile;
const newPos = this.root.camera.screenToWorld(pos).toTileSpace();
@@ -126,6 +144,7 @@ export class HUDBuildingPlacer extends BaseHUDPart {
if (!oldPos.equals(newPos)) {
if (
+ metaBuilding &&
metaBuilding.getRotateAutomaticallyWhilePlacing(this.currentVariant.get()) &&
!this.root.app.inputMgr.ctrlIsDown
) {
@@ -152,8 +171,15 @@ export class HUDBuildingPlacer extends BaseHUDPart {
var sy = y0 < y1 ? 1 : -1;
var err = dx - dy;
- while (this.currentMetaBuilding.get()) {
- this.tryPlaceCurrentBuildingAt(new Vector(x0, y0));
+ while (this.currentlyDeleting || this.currentMetaBuilding.get()) {
+ if (this.currentlyDeleting) {
+ const contents = this.root.map.getTileContentXY(x0, y0);
+ if (contents && !contents.queuedForDestroy && !contents.destroyed) {
+ this.root.logic.tryDeleteBuilding(contents);
+ }
+ } else {
+ this.tryPlaceCurrentBuildingAt(new Vector(x0, y0));
+ }
if (x0 === x1 && y0 === y1) break;
var e2 = 2 * err;
if (e2 > -dy) {
@@ -186,6 +212,7 @@ export class HUDBuildingPlacer extends BaseHUDPart {
*/
abortDragging() {
this.currentlyDragging = true;
+ this.currentlyDeleting = false;
this.lastDragTile = null;
}
@@ -201,6 +228,7 @@ export class HUDBuildingPlacer extends BaseHUDPart {
* @param {MetaBuilding} metaBuilding
*/
onSelectedMetaBuildingChanged(metaBuilding) {
+ this.abortDragging();
this.root.hud.signals.selectedPlacementBuildingChanged.dispatch(metaBuilding);
if (metaBuilding) {
this.buildingInfoElements.label.innerHTML = metaBuilding.getName();
@@ -215,7 +243,8 @@ export class HUDBuildingPlacer extends BaseHUDPart {
this.currentVariant.set(variant);
this.fakeEntity = new Entity(null);
- metaBuilding.setupEntityComponents(this.fakeEntity, null, variant);
+ metaBuilding.setupEntityComponents(this.fakeEntity, null);
+
this.fakeEntity.addComponent(
new StaticMapEntityComponent({
origin: new Vector(0, 0),
@@ -223,13 +252,13 @@ export class HUDBuildingPlacer extends BaseHUDPart {
tileSize: metaBuilding.getDimensions(this.currentVariant.get()).copy(),
})
);
+ metaBuilding.updateVariants(this.fakeEntity, 0, this.currentVariant.get());
this.buildingInfoElements.tutorialImage.setAttribute(
"data-icon",
"building_tutorials/" + metaBuilding.getId() + ".png"
);
} else {
- this.currentlyDragging = false;
this.fakeEntity = null;
}
diff --git a/src/js/game/hud/parts/buildings_toolbar.js b/src/js/game/hud/parts/buildings_toolbar.js
index 4965a0da..6c2aec81 100644
--- a/src/js/game/hud/parts/buildings_toolbar.js
+++ b/src/js/game/hud/parts/buildings_toolbar.js
@@ -33,7 +33,13 @@ export class HUDBuildingsToolbar extends BaseHUDPart {
constructor(root) {
super(root);
- /** @type {Object.} */
+ /** @type {Object.} */
this.buildingHandles = {};
this.sigBuildingSelected = new Signal();
@@ -76,6 +82,7 @@ export class HUDBuildingsToolbar extends BaseHUDPart {
element: itemContainer,
unlocked: false,
selected: false,
+ index: i,
};
}
@@ -83,6 +90,9 @@ export class HUDBuildingsToolbar extends BaseHUDPart {
this.onSelectedPlacementBuildingChanged,
this
);
+
+ this.lastSelectedIndex = 0;
+ actionMapper.getBinding("cycle_buildings").add(this.cycleBuildings, this);
}
update() {
@@ -98,6 +108,13 @@ export class HUDBuildingsToolbar extends BaseHUDPart {
}
}
+ cycleBuildings() {
+ const newIndex = (this.lastSelectedIndex + 1) % toolbarBuildings.length;
+ const metaBuildingClass = toolbarBuildings[newIndex];
+ const metaBuilding = gMetaBuildingRegistry.findByClass(metaBuildingClass);
+ this.selectBuildingForPlacement(metaBuilding);
+ }
+
/**
* @param {MetaBuilding} metaBuilding
*/
@@ -109,6 +126,9 @@ export class HUDBuildingsToolbar extends BaseHUDPart {
handle.selected = newStatus;
handle.element.classList.toggle("selected", newStatus);
}
+ if (handle.selected) {
+ this.lastSelectedIndex = handle.index;
+ }
}
this.element.classList.toggle("buildingSelected", !!metaBuilding);
diff --git a/src/js/game/hud/parts/mass_selector.js b/src/js/game/hud/parts/mass_selector.js
index 25e37306..33ade806 100644
--- a/src/js/game/hud/parts/mass_selector.js
+++ b/src/js/game/hud/parts/mass_selector.js
@@ -8,6 +8,7 @@ import { globalConfig } from "../../../core/config";
import { makeDiv } from "../../../core/utils";
import { DynamicDomAttach } from "../dynamic_dom_attach";
import { createLogger } from "../../../core/logging";
+import { enumMouseButton } from "../../camera";
const logger = createLogger("hud/mass_selector");
@@ -82,12 +83,17 @@ export class HUDMassSelector extends BaseHUDPart {
/**
* mouse down pre handler
* @param {Vector} pos
+ * @param {enumMouseButton} mouseButton
*/
- onMouseDown(pos) {
+ onMouseDown(pos, mouseButton) {
if (!this.root.app.inputMgr.ctrlIsDown) {
return;
}
+ if (mouseButton !== enumMouseButton.left) {
+ return;
+ }
+
if (!this.root.app.inputMgr.shiftIsDown) {
// Start new selection
this.entityUidsMarkedForDeletion = new Set();
diff --git a/src/js/game/key_action_mapper.js b/src/js/game/key_action_mapper.js
index d5972820..19bc5b2a 100644
--- a/src/js/game/key_action_mapper.js
+++ b/src/js/game/key_action_mapper.js
@@ -50,6 +50,8 @@ export const defaultKeybindings = {
rotate_while_placing: { keyCode: key("R") },
cycle_variants: { keyCode: key("T") },
+
+ cycle_buildings: { keyCode: 9 },
},
};
diff --git a/src/js/game/systems/hub.js b/src/js/game/systems/hub.js
index 55ce3544..ee26b71b 100644
--- a/src/js/game/systems/hub.js
+++ b/src/js/game/systems/hub.js
@@ -4,10 +4,13 @@ import { DrawParameters } from "../../core/draw_parameters";
import { Entity } from "../entity";
import { formatBigNumber } from "../../core/utils";
import { enumHubGoalRewardToString } from "../tutorial_goals";
+import { Loader } from "../../core/loader";
export class HubSystem extends GameSystemWithFilter {
constructor(root) {
super(root, [HubComponent]);
+
+ this.hubSprite = Loader.getSprite("sprites/buildings/hub.png");
}
draw(parameters) {
@@ -40,6 +43,9 @@ export class HubSystem extends GameSystemWithFilter {
const pos = staticComp.getTileSpaceBounds().getCenter().toWorldSpace();
+ // Background
+ staticComp.drawSpriteOnFullEntityBounds(parameters, this.hubSprite, 2.2);
+
const definition = this.root.hubGoals.currentGoal.definition;
definition.draw(pos.x - 25, pos.y - 10, parameters, 40);
diff --git a/src/js/game/systems/item_acceptor.js b/src/js/game/systems/item_acceptor.js
new file mode 100644
index 00000000..961b7203
--- /dev/null
+++ b/src/js/game/systems/item_acceptor.js
@@ -0,0 +1,114 @@
+import { GameSystemWithFilter } from "../game_system_with_filter";
+import { globalConfig } from "../../core/config";
+import { DrawParameters } from "../../core/draw_parameters";
+import { Entity } from "../entity";
+import { enumDirectionToVector, enumDirectionToAngle } from "../../core/vector";
+import { ItemAcceptorComponent } from "../components/item_acceptor";
+import { Loader } from "../../core/loader";
+import { drawRotatedSprite } from "../../core/draw_utils";
+import { Math_radians } from "../../core/builtins";
+
+export class ItemAcceptorSystem extends GameSystemWithFilter {
+ constructor(root) {
+ super(root, [ItemAcceptorComponent]);
+
+ this.underlayBeltSprites = [
+ Loader.getSprite("sprites/belt/forward_0.png"),
+ Loader.getSprite("sprites/belt/forward_1.png"),
+ Loader.getSprite("sprites/belt/forward_2.png"),
+ Loader.getSprite("sprites/belt/forward_3.png"),
+ Loader.getSprite("sprites/belt/forward_4.png"),
+ Loader.getSprite("sprites/belt/forward_5.png"),
+ ];
+ }
+
+ update() {
+ for (let i = 0; i < this.allEntities.length; ++i) {
+ const entity = this.allEntities[i];
+ const aceptorComp = entity.components.ItemAcceptor;
+
+ // Process item consumption animations to avoid items popping from the belts
+ for (let animIndex = 0; animIndex < aceptorComp.itemConsumptionAnimations.length; ++animIndex) {
+ const anim = aceptorComp.itemConsumptionAnimations[animIndex];
+ anim.animProgress +=
+ globalConfig.physicsDeltaSeconds * this.root.hubGoals.getBeltBaseSpeed() * 2;
+ if (anim.animProgress > 1) {
+ aceptorComp.itemConsumptionAnimations.splice(animIndex, 1);
+ animIndex -= 1;
+ }
+ }
+ }
+ }
+
+ draw(parameters) {
+ this.forEachMatchingEntityOnScreen(parameters, this.drawEntity.bind(this));
+ }
+
+ drawUnderlays(parameters) {
+ this.forEachMatchingEntityOnScreen(parameters, this.drawEntityUnderlays.bind(this));
+ }
+
+ /**
+ * @param {DrawParameters} parameters
+ * @param {Entity} entity
+ */
+ drawEntity(parameters, entity) {
+ const staticComp = entity.components.StaticMapEntity;
+ const acceptorComp = entity.components.ItemAcceptor;
+
+ for (let animIndex = 0; animIndex < acceptorComp.itemConsumptionAnimations.length; ++animIndex) {
+ const { item, slotIndex, animProgress, direction } = acceptorComp.itemConsumptionAnimations[
+ animIndex
+ ];
+
+ const slotData = acceptorComp.slots[slotIndex];
+ const slotWorldPos = staticComp.applyRotationToVector(slotData.pos).add(staticComp.origin);
+
+ const fadeOutDirection = enumDirectionToVector[staticComp.localDirectionToWorld(direction)];
+ const finalTile = slotWorldPos.subScalars(
+ fadeOutDirection.x * (animProgress / 2 - 0.5),
+ fadeOutDirection.y * (animProgress / 2 - 0.5)
+ );
+ item.draw(
+ (finalTile.x + 0.5) * globalConfig.tileSize,
+ (finalTile.y + 0.5) * globalConfig.tileSize,
+ parameters
+ );
+ }
+ }
+
+ /**
+ * @param {DrawParameters} parameters
+ * @param {Entity} entity
+ */
+ drawEntityUnderlays(parameters, entity) {
+ const staticComp = entity.components.StaticMapEntity;
+ const acceptorComp = entity.components.ItemAcceptor;
+
+ const underlays = acceptorComp.beltUnderlays;
+ for (let i = 0; i < underlays.length; ++i) {
+ const { pos, direction } = underlays[i];
+
+ const transformedPos = staticComp.localTileToWorld(pos);
+ const angle = enumDirectionToAngle[staticComp.localDirectionToWorld(direction)];
+
+ // SYNC with systems/belt.js:drawSingleEntity!
+ const animationIndex = Math.floor(
+ (this.root.time.now() *
+ this.root.hubGoals.getBeltBaseSpeed() *
+ this.underlayBeltSprites.length *
+ 126) /
+ 42
+ );
+
+ drawRotatedSprite({
+ parameters,
+ sprite: this.underlayBeltSprites[animationIndex % this.underlayBeltSprites.length],
+ x: (transformedPos.x + 0.5) * globalConfig.tileSize,
+ y: (transformedPos.y + 0.5) * globalConfig.tileSize,
+ angle: Math_radians(angle),
+ size: globalConfig.tileSize,
+ });
+ }
+ }
+}
diff --git a/src/js/game/systems/item_ejector.js b/src/js/game/systems/item_ejector.js
index cc5cb82d..dec116d7 100644
--- a/src/js/game/systems/item_ejector.js
+++ b/src/js/game/systems/item_ejector.js
@@ -72,14 +72,12 @@ export class ItemEjectorSystem extends GameSystemWithFilter {
continue;
}
- if (
- this.tryPassOverItem(
- ejectingItem,
- targetEntity,
+ if (this.tryPassOverItem(ejectingItem, targetEntity, matchingSlot.index)) {
+ targetAcceptorComp.onItemAccepted(
matchingSlot.index,
- matchingSlot.acceptedDirection
- )
- ) {
+ matchingSlot.acceptedDirection,
+ ejectingItem
+ );
ejectorSlot.item = null;
continue;
}
@@ -92,9 +90,8 @@ export class ItemEjectorSystem extends GameSystemWithFilter {
* @param {BaseItem} item
* @param {Entity} receiver
* @param {number} slotIndex
- * @param {string} localDirection
*/
- tryPassOverItem(item, receiver, slotIndex, localDirection) {
+ tryPassOverItem(item, receiver, slotIndex) {
// Try figuring out how what to do with the item
// TODO: Kinda hacky. How to solve this properly? Don't want to go through inheritance hell.
// Also its just a few cases (hope it stays like this .. :x).
@@ -102,8 +99,8 @@ export class ItemEjectorSystem extends GameSystemWithFilter {
const beltComp = receiver.components.Belt;
if (beltComp) {
// Ayy, its a belt!
- if (beltComp.canAcceptNewItem(localDirection)) {
- beltComp.takeNewItem(item, localDirection);
+ if (beltComp.canAcceptNewItem()) {
+ beltComp.takeNewItem(item);
return true;
}
}
@@ -111,7 +108,7 @@ export class ItemEjectorSystem extends GameSystemWithFilter {
const itemProcessorComp = receiver.components.ItemProcessor;
if (itemProcessorComp) {
// Its an item processor ..
- if (itemProcessorComp.tryTakeItem(item, slotIndex, localDirection)) {
+ if (itemProcessorComp.tryTakeItem(item, slotIndex)) {
return true;
}
}
diff --git a/src/js/game/systems/item_processor.js b/src/js/game/systems/item_processor.js
index 5a8d01d8..d8757294 100644
--- a/src/js/game/systems/item_processor.js
+++ b/src/js/game/systems/item_processor.js
@@ -1,37 +1,16 @@
+import { Math_max } from "../../core/builtins";
import { globalConfig } from "../../core/config";
-import { DrawParameters } from "../../core/draw_parameters";
-import { Loader } from "../../core/loader";
+import { BaseItem } from "../base_item";
+import { enumColorMixingResults } from "../colors";
+import { enumItemProcessorTypes, ItemProcessorComponent } from "../components/item_processor";
import { Entity } from "../entity";
import { GameSystemWithFilter } from "../game_system_with_filter";
-import { ItemProcessorComponent, enumItemProcessorTypes } from "../components/item_processor";
-import { Math_max, Math_radians } from "../../core/builtins";
-import { BaseItem } from "../base_item";
-import { ShapeItem } from "../items/shape_item";
-import { enumDirectionToVector, enumDirection, enumDirectionToAngle } from "../../core/vector";
import { ColorItem } from "../items/color_item";
-import { enumColorMixingResults } from "../colors";
-import { drawRotatedSprite } from "../../core/draw_utils";
+import { ShapeItem } from "../items/shape_item";
export class ItemProcessorSystem extends GameSystemWithFilter {
constructor(root) {
super(root, [ItemProcessorComponent]);
-
- this.underlayBeltSprites = [
- Loader.getSprite("sprites/belt/forward_0.png"),
- Loader.getSprite("sprites/belt/forward_1.png"),
- Loader.getSprite("sprites/belt/forward_2.png"),
- Loader.getSprite("sprites/belt/forward_3.png"),
- Loader.getSprite("sprites/belt/forward_4.png"),
- Loader.getSprite("sprites/belt/forward_5.png"),
- ];
- }
-
- draw(parameters) {
- this.forEachMatchingEntityOnScreen(parameters, this.drawEntity.bind(this));
- }
-
- drawUnderlays(parameters) {
- this.forEachMatchingEntityOnScreen(parameters, this.drawEntityUnderlays.bind(this));
}
update() {
@@ -47,17 +26,6 @@ export class ItemProcessorSystem extends GameSystemWithFilter {
processorComp.secondsUntilEject - globalConfig.physicsDeltaSeconds
);
- // Also, process item consumption animations to avoid items popping from the belts
- for (let animIndex = 0; animIndex < processorComp.itemConsumptionAnimations.length; ++animIndex) {
- const anim = processorComp.itemConsumptionAnimations[animIndex];
- anim.animProgress +=
- globalConfig.physicsDeltaSeconds * this.root.hubGoals.getBeltBaseSpeed() * 2;
- if (anim.animProgress > 1) {
- processorComp.itemConsumptionAnimations.splice(animIndex, 1);
- animIndex -= 1;
- }
- }
-
// Check if we have any finished items we can eject
if (
processorComp.secondsUntilEject === 0 && // it was processed in time
@@ -363,68 +331,4 @@ export class ItemProcessorSystem extends GameSystemWithFilter {
processorComp.itemsToEject = outItems;
}
-
- /**
- * @param {DrawParameters} parameters
- * @param {Entity} entity
- */
- drawEntity(parameters, entity) {
- const staticComp = entity.components.StaticMapEntity;
- const processorComp = entity.components.ItemProcessor;
- const acceptorComp = entity.components.ItemAcceptor;
-
- for (let animIndex = 0; animIndex < processorComp.itemConsumptionAnimations.length; ++animIndex) {
- const { item, slotIndex, animProgress, direction } = processorComp.itemConsumptionAnimations[
- animIndex
- ];
-
- const slotData = acceptorComp.slots[slotIndex];
- const slotWorldPos = staticComp.applyRotationToVector(slotData.pos).add(staticComp.origin);
-
- const fadeOutDirection = enumDirectionToVector[staticComp.localDirectionToWorld(direction)];
- const finalTile = slotWorldPos.subScalars(
- fadeOutDirection.x * (animProgress / 2 - 0.5),
- fadeOutDirection.y * (animProgress / 2 - 0.5)
- );
- item.draw(
- (finalTile.x + 0.5) * globalConfig.tileSize,
- (finalTile.y + 0.5) * globalConfig.tileSize,
- parameters
- );
- }
- }
- /**
- * @param {DrawParameters} parameters
- * @param {Entity} entity
- */
- drawEntityUnderlays(parameters, entity) {
- const staticComp = entity.components.StaticMapEntity;
- const processorComp = entity.components.ItemProcessor;
-
- const underlays = processorComp.beltUnderlays;
- for (let i = 0; i < underlays.length; ++i) {
- const { pos, direction } = underlays[i];
-
- const transformedPos = staticComp.localTileToWorld(pos);
- const angle = enumDirectionToAngle[staticComp.localDirectionToWorld(direction)];
-
- // SYNC with systems/belt.js:drawSingleEntity!
- const animationIndex = Math.floor(
- (this.root.time.now() *
- this.root.hubGoals.getBeltBaseSpeed() *
- this.underlayBeltSprites.length *
- 126) /
- 42
- );
-
- drawRotatedSprite({
- parameters,
- sprite: this.underlayBeltSprites[animationIndex % this.underlayBeltSprites.length],
- x: (transformedPos.x + 0.5) * globalConfig.tileSize,
- y: (transformedPos.y + 0.5) * globalConfig.tileSize,
- angle: Math_radians(angle),
- size: globalConfig.tileSize,
- });
- }
- }
}
diff --git a/src/js/game/systems/static_map_entity.js b/src/js/game/systems/static_map_entity.js
index 751315e6..d50b134d 100644
--- a/src/js/game/systems/static_map_entity.js
+++ b/src/js/game/systems/static_map_entity.js
@@ -26,7 +26,6 @@ export class StaticMapEntitySystem extends GameSystem {
return;
}
- const drawEntitiesOutside = parameters.zoomLevel < globalConfig.mapChunkPrerenderMinZoom;
const drawOutlinesOnly = parameters.zoomLevel < globalConfig.mapChunkOverviewMinZoom;
const contents = chunk.contents;
@@ -54,17 +53,8 @@ export class StaticMapEntitySystem extends GameSystem {
} else {
const spriteKey = staticComp.spriteKey;
if (spriteKey) {
- // Check if origin is contained to avoid drawing entities multiple times
- if (
- drawEntitiesOutside ||
- (staticComp.origin.x >= chunk.tileX &&
- staticComp.origin.x < chunk.tileX + globalConfig.mapChunkSize &&
- staticComp.origin.y >= chunk.tileY &&
- staticComp.origin.y < chunk.tileY + globalConfig.mapChunkSize)
- ) {
- const sprite = Loader.getSprite(spriteKey);
- staticComp.drawSpriteOnFullEntityBounds(parameters, sprite, 2, false);
- }
+ const sprite = Loader.getSprite(spriteKey);
+ staticComp.drawSpriteOnFullEntityBounds(parameters, sprite, 2, false);
}
}
}
diff --git a/src/js/globals.d.ts b/src/js/globals.d.ts
index 71e2db5c..7e84d86a 100644
--- a/src/js/globals.d.ts
+++ b/src/js/globals.d.ts
@@ -199,10 +199,10 @@ declare class TypedTrackedState {
declare const STOP_PROPAGATION = "stop_propagation";
declare interface TypedSignal> {
- add(receiver: (...args: T) => typeof STOP_PROPAGATION | void, scope?: object);
- remove(receiver: (...args: T) => typeof STOP_PROPAGATION | void);
+ add(receiver: (...args: T) => /* STOP_PROPAGATION */ string | void, scope?: object);
+ remove(receiver: (...args: T) => /* STOP_PROPAGATION */ string | void);
- dispatch(...args: T): typeof STOP_PROPAGATION | void;
+ dispatch(...args: T): /* STOP_PROPAGATION */ string | void;
removeAll();
}