1
0
mirror of https://github.com/tobspr/shapez.io.git synced 2025-12-14 02:31:51 +00:00

Direction lock now indicates when there is a building inbetween

This commit is contained in:
tobspr 2022-01-18 20:38:20 +01:00
parent f3a939b071
commit 4a76135d57
7 changed files with 119 additions and 51 deletions

View File

@ -65,10 +65,10 @@ class Mod extends shapez.Mod {
// Only allow placing an entity when there is enough currency // Only allow placing an entity when there is enough currency
this.modInterface.replaceMethod(shapez.GameLogic, "checkCanPlaceEntity", function ( this.modInterface.replaceMethod(shapez.GameLogic, "checkCanPlaceEntity", function (
$original, $original,
[entity, offset] [entity, options]
) { ) {
const storedCurrency = this.root.hubGoals.storedShapes[CURRENCY] || 0; const storedCurrency = this.root.hubGoals.storedShapes[CURRENCY] || 0;
return storedCurrency > 0 && $original(entity, offset); return storedCurrency > 0 && $original(entity, options);
}); });
// Take shapes when placing a building // Take shapes when placing a building

View File

@ -40,6 +40,10 @@ const RESOURCES = {
color: "rgb(74, 237, 134)", color: "rgb(74, 237, 134)",
background: "rgba(74, 237, 134, 0.2)", background: "rgba(74, 237, 134, 0.2)",
}, },
error: {
color: "rgb(255, 137, 137)",
background: "rgba(255, 137, 137, 0.2)",
},
}, },
colorBlindPickerTile: "rgba(50, 50, 50, 0.4)", colorBlindPickerTile: "rgba(50, 50, 50, 0.4)",

View File

@ -82,7 +82,7 @@ export class Blueprint {
const rect = staticComp.getTileSpaceBounds(); const rect = staticComp.getTileSpaceBounds();
rect.moveBy(tile.x, tile.y); rect.moveBy(tile.x, tile.y);
if (!parameters.root.logic.checkCanPlaceEntity(entity, tile)) { if (!parameters.root.logic.checkCanPlaceEntity(entity, { offset: tile })) {
parameters.context.globalAlpha = 0.3; parameters.context.globalAlpha = 0.3;
} else { } else {
parameters.context.globalAlpha = 1; parameters.context.globalAlpha = 1;
@ -131,7 +131,7 @@ export class Blueprint {
for (let i = 0; i < this.entities.length; ++i) { for (let i = 0; i < this.entities.length; ++i) {
const entity = this.entities[i]; const entity = this.entities[i];
if (root.logic.checkCanPlaceEntity(entity, tile)) { if (root.logic.checkCanPlaceEntity(entity, { offset: tile })) {
anyPlaceable = true; anyPlaceable = true;
} }
} }
@ -160,7 +160,7 @@ export class Blueprint {
let count = 0; let count = 0;
for (let i = 0; i < this.entities.length; ++i) { for (let i = 0; i < this.entities.length; ++i) {
const entity = this.entities[i]; const entity = this.entities[i];
if (!root.logic.checkCanPlaceEntity(entity, tile)) { if (!root.logic.checkCanPlaceEntity(entity, { offset: tile })) {
continue; continue;
} }

View File

@ -61,7 +61,7 @@ export class HUDBuildingPlacer extends HUDBuildingPlacerLogic {
this.currentInterpolatedCornerTile = new Vector(); this.currentInterpolatedCornerTile = new Vector();
this.lockIndicatorSprites = {}; this.lockIndicatorSprites = {};
layers.forEach(layer => { [...layers, "error"].forEach(layer => {
this.lockIndicatorSprites[layer] = this.makeLockIndicatorSprite(layer); this.lockIndicatorSprites[layer] = this.makeLockIndicatorSprite(layer);
}); });
@ -76,7 +76,7 @@ export class HUDBuildingPlacer extends HUDBuildingPlacerLogic {
/** /**
* Makes the lock indicator sprite for the given layer * Makes the lock indicator sprite for the given layer
* @param {Layer} layer * @param {string} layer
*/ */
makeLockIndicatorSprite(layer) { makeLockIndicatorSprite(layer) {
const dims = 48; const dims = 48;
@ -358,7 +358,7 @@ export class HUDBuildingPlacer extends HUDBuildingPlacerLogic {
rotationVariant rotationVariant
); );
const canBuild = this.root.logic.checkCanPlaceEntity(this.fakeEntity); const canBuild = this.root.logic.checkCanPlaceEntity(this.fakeEntity, {});
// Fade in / out // Fade in / out
parameters.context.lineWidth = 1; parameters.context.lineWidth = 1;
@ -397,6 +397,42 @@ export class HUDBuildingPlacer extends HUDBuildingPlacerLogic {
} }
} }
/**
* Checks if there are any entities in the way, returns true if there are
* @param {Vector} from
* @param {Vector} to
* @returns
*/
checkForObstales(from, to) {
assert(from.x === to.x || from.y === to.y, "Must be a straight line");
const prop = from.x === to.x ? "y" : "x";
const current = from.copy();
const metaBuilding = this.currentMetaBuilding.get();
this.fakeEntity.layer = metaBuilding.getLayer();
const staticComp = this.fakeEntity.components.StaticMapEntity;
staticComp.origin = current;
staticComp.rotation = 0;
metaBuilding.updateVariants(this.fakeEntity, 0, this.currentVariant.get());
staticComp.code = getCodeFromBuildingData(
this.currentMetaBuilding.get(),
this.currentVariant.get(),
0
);
const start = Math.min(from[prop], to[prop]);
const end = Math.max(from[prop], to[prop]);
for (let i = start; i <= end; i++) {
current[prop] = i;
if (!this.root.logic.checkCanPlaceEntity(this.fakeEntity, { allowReplaceBuildings: false })) {
return true;
}
}
return false;
}
/** /**
* @param {DrawParameters} parameters * @param {DrawParameters} parameters
*/ */
@ -407,55 +443,73 @@ export class HUDBuildingPlacer extends HUDBuildingPlacerLogic {
return; return;
} }
const applyStyles = look => {
parameters.context.fillStyle = THEME.map.directionLock[look].color;
parameters.context.strokeStyle = THEME.map.directionLock[look].background;
parameters.context.lineWidth = 10;
};
if (!this.lastDragTile) {
// Not dragging yet
applyStyles(this.root.currentLayer);
const mouseWorld = this.root.camera.screenToWorld(mousePosition);
parameters.context.beginCircle(mouseWorld.x, mouseWorld.y, 4);
parameters.context.fill();
return;
}
const mouseWorld = this.root.camera.screenToWorld(mousePosition); const mouseWorld = this.root.camera.screenToWorld(mousePosition);
const mouseTile = mouseWorld.toTileSpace(); const mouseTile = mouseWorld.toTileSpace();
parameters.context.fillStyle = THEME.map.directionLock[this.root.currentLayer].color; const startLine = this.lastDragTile.toWorldSpaceCenterOfTile();
parameters.context.strokeStyle = THEME.map.directionLock[this.root.currentLayer].background; const endLine = mouseTile.toWorldSpaceCenterOfTile();
parameters.context.lineWidth = 10; const midLine = this.currentDirectionLockCorner.toWorldSpaceCenterOfTile();
const anyObstacle =
this.checkForObstales(this.lastDragTile, this.currentDirectionLockCorner) ||
this.checkForObstales(this.currentDirectionLockCorner, mouseTile);
if (anyObstacle) {
applyStyles("error");
} else {
applyStyles(this.root.currentLayer);
}
parameters.context.beginCircle(mouseWorld.x, mouseWorld.y, 4); parameters.context.beginCircle(mouseWorld.x, mouseWorld.y, 4);
parameters.context.fill(); parameters.context.fill();
if (this.lastDragTile) { parameters.context.beginCircle(startLine.x, startLine.y, 8);
const startLine = this.lastDragTile.toWorldSpaceCenterOfTile(); parameters.context.fill();
const endLine = mouseTile.toWorldSpaceCenterOfTile();
const midLine = this.currentDirectionLockCorner.toWorldSpaceCenterOfTile();
parameters.context.beginCircle(startLine.x, startLine.y, 8); parameters.context.beginPath();
parameters.context.fill(); parameters.context.moveTo(startLine.x, startLine.y);
parameters.context.lineTo(midLine.x, midLine.y);
parameters.context.lineTo(endLine.x, endLine.y);
parameters.context.stroke();
parameters.context.beginPath(); parameters.context.beginCircle(endLine.x, endLine.y, 5);
parameters.context.moveTo(startLine.x, startLine.y); parameters.context.fill();
parameters.context.lineTo(midLine.x, midLine.y);
parameters.context.lineTo(endLine.x, endLine.y);
parameters.context.stroke();
parameters.context.beginCircle(endLine.x, endLine.y, 5); // Draw arrow
parameters.context.fill(); const arrowSprite = this.lockIndicatorSprites[anyObstacle ? "error" : this.root.currentLayer];
const path = this.computeDirectionLockPath();
for (let i = 0; i < path.length - 1; i += 1) {
const { rotation, tile } = path[i];
const worldPos = tile.toWorldSpaceCenterOfTile();
const angle = Math.radians(rotation);
// Draw arrow parameters.context.translate(worldPos.x, worldPos.y);
const arrowSprite = this.lockIndicatorSprites[this.root.currentLayer]; parameters.context.rotate(angle);
const path = this.computeDirectionLockPath(); parameters.context.drawImage(
for (let i = 0; i < path.length - 1; i += 1) { arrowSprite,
const { rotation, tile } = path[i]; -6,
const worldPos = tile.toWorldSpaceCenterOfTile(); -globalConfig.halfTileSize -
const angle = Math.radians(rotation); clamp((this.root.time.realtimeNow() * 1.5) % 1.0, 0, 1) * 1 * globalConfig.tileSize +
globalConfig.halfTileSize -
parameters.context.translate(worldPos.x, worldPos.y); 6,
parameters.context.rotate(angle); 12,
parameters.context.drawImage( 12
arrowSprite, );
-6, parameters.context.rotate(-angle);
-globalConfig.halfTileSize - parameters.context.translate(-worldPos.x, -worldPos.y);
clamp((this.root.time.realtimeNow() * 1.5) % 1.0, 0, 1) * 1 * globalConfig.tileSize +
globalConfig.halfTileSize -
6,
12,
12
);
parameters.context.rotate(-angle);
parameters.context.translate(-worldPos.x, -worldPos.y);
}
} }
} }

View File

@ -53,10 +53,12 @@ export class GameLogic {
/** /**
* Checks if the given entity can be placed * Checks if the given entity can be placed
* @param {Entity} entity * @param {Entity} entity
* @param {Vector=} offset Optional, move the entity by the given offset first * @param {Object} param0
* @param {boolean=} param0.allowReplaceBuildings
* @param {Vector=} param0.offset Optional, move the entity by the given offset first
* @returns {boolean} true if the entity could be placed there * @returns {boolean} true if the entity could be placed there
*/ */
checkCanPlaceEntity(entity, offset = null) { checkCanPlaceEntity(entity, { allowReplaceBuildings = false, offset = null }) {
// Compute area of the building // Compute area of the building
const rect = entity.components.StaticMapEntity.getTileSpaceBounds(); const rect = entity.components.StaticMapEntity.getTileSpaceBounds();
if (offset) { if (offset) {
@ -71,7 +73,7 @@ export class GameLogic {
const otherEntity = this.root.map.getLayerContentXY(x, y, entity.layer); const otherEntity = this.root.map.getLayerContentXY(x, y, entity.layer);
if (otherEntity) { if (otherEntity) {
const metaClass = otherEntity.components.StaticMapEntity.getMetaBuilding(); const metaClass = otherEntity.components.StaticMapEntity.getMetaBuilding();
if (!metaClass.getIsReplaceable()) { if (!allowReplaceBuildings || !metaClass.getIsReplaceable()) {
// This one is a direct blocker // This one is a direct blocker
return false; return false;
} }
@ -116,7 +118,7 @@ export class GameLogic {
rotationVariant, rotationVariant,
variant, variant,
}); });
if (this.checkCanPlaceEntity(entity)) { if (this.checkCanPlaceEntity(entity, {})) {
this.freeEntityAreaBeforeBuild(entity); this.freeEntityAreaBeforeBuild(entity);
this.root.map.placeStaticEntity(entity); this.root.map.placeStaticEntity(entity);
this.root.entityMgr.registerEntity(entity); this.root.entityMgr.registerEntity(entity);

View File

@ -18,6 +18,10 @@
"wires": { "wires": {
"color": "rgb(74, 237, 134)", "color": "rgb(74, 237, 134)",
"background": "rgba(74, 237, 134, 0.2)" "background": "rgba(74, 237, 134, 0.2)"
},
"error": {
"color": "rgb(255, 137, 137)",
"background": "rgba(255, 137, 137, 0.2)"
} }
}, },

View File

@ -18,6 +18,10 @@
"wires": { "wires": {
"color": "rgb(74, 237, 134)", "color": "rgb(74, 237, 134)",
"background": "rgba(74, 237, 134, 0.2)" "background": "rgba(74, 237, 134, 0.2)"
},
"error": {
"color": "rgb(255, 137, 137)",
"background": "rgba(255, 137, 137, 0.2)"
} }
}, },