1
0
mirror of https://github.com/tobspr/shapez.io.git synced 2025-12-13 18:21: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
this.modInterface.replaceMethod(shapez.GameLogic, "checkCanPlaceEntity", function (
$original,
[entity, offset]
[entity, options]
) {
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

View File

@ -40,6 +40,10 @@ const RESOURCES = {
color: "rgb(74, 237, 134)",
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)",

View File

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

View File

@ -61,7 +61,7 @@ export class HUDBuildingPlacer extends HUDBuildingPlacerLogic {
this.currentInterpolatedCornerTile = new Vector();
this.lockIndicatorSprites = {};
layers.forEach(layer => {
[...layers, "error"].forEach(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
* @param {Layer} layer
* @param {string} layer
*/
makeLockIndicatorSprite(layer) {
const dims = 48;
@ -358,7 +358,7 @@ export class HUDBuildingPlacer extends HUDBuildingPlacerLogic {
rotationVariant
);
const canBuild = this.root.logic.checkCanPlaceEntity(this.fakeEntity);
const canBuild = this.root.logic.checkCanPlaceEntity(this.fakeEntity, {});
// Fade in / out
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
*/
@ -407,55 +443,73 @@ export class HUDBuildingPlacer extends HUDBuildingPlacerLogic {
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 mouseTile = mouseWorld.toTileSpace();
parameters.context.fillStyle = THEME.map.directionLock[this.root.currentLayer].color;
parameters.context.strokeStyle = THEME.map.directionLock[this.root.currentLayer].background;
parameters.context.lineWidth = 10;
const startLine = this.lastDragTile.toWorldSpaceCenterOfTile();
const endLine = mouseTile.toWorldSpaceCenterOfTile();
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.fill();
if (this.lastDragTile) {
const startLine = this.lastDragTile.toWorldSpaceCenterOfTile();
const endLine = mouseTile.toWorldSpaceCenterOfTile();
const midLine = this.currentDirectionLockCorner.toWorldSpaceCenterOfTile();
parameters.context.beginCircle(startLine.x, startLine.y, 8);
parameters.context.fill();
parameters.context.beginCircle(startLine.x, startLine.y, 8);
parameters.context.fill();
parameters.context.beginPath();
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.moveTo(startLine.x, startLine.y);
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);
parameters.context.fill();
parameters.context.beginCircle(endLine.x, endLine.y, 5);
parameters.context.fill();
// Draw arrow
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
const arrowSprite = this.lockIndicatorSprites[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);
parameters.context.translate(worldPos.x, worldPos.y);
parameters.context.rotate(angle);
parameters.context.drawImage(
arrowSprite,
-6,
-globalConfig.halfTileSize -
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);
}
parameters.context.translate(worldPos.x, worldPos.y);
parameters.context.rotate(angle);
parameters.context.drawImage(
arrowSprite,
-6,
-globalConfig.halfTileSize -
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
* @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
*/
checkCanPlaceEntity(entity, offset = null) {
checkCanPlaceEntity(entity, { allowReplaceBuildings = false, offset = null }) {
// Compute area of the building
const rect = entity.components.StaticMapEntity.getTileSpaceBounds();
if (offset) {
@ -71,7 +73,7 @@ export class GameLogic {
const otherEntity = this.root.map.getLayerContentXY(x, y, entity.layer);
if (otherEntity) {
const metaClass = otherEntity.components.StaticMapEntity.getMetaBuilding();
if (!metaClass.getIsReplaceable()) {
if (!allowReplaceBuildings || !metaClass.getIsReplaceable()) {
// This one is a direct blocker
return false;
}
@ -116,7 +118,7 @@ export class GameLogic {
rotationVariant,
variant,
});
if (this.checkCanPlaceEntity(entity)) {
if (this.checkCanPlaceEntity(entity, {})) {
this.freeEntityAreaBeforeBuild(entity);
this.root.map.placeStaticEntity(entity);
this.root.entityMgr.registerEntity(entity);

View File

@ -18,6 +18,10 @@
"wires": {
"color": "rgb(74, 237, 134)",
"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": {
"color": "rgb(74, 237, 134)",
"background": "rgba(74, 237, 134, 0.2)"
},
"error": {
"color": "rgb(255, 137, 137)",
"background": "rgba(255, 137, 137, 0.2)"
}
},