import { HashSet } from "../lib/util/data_structures/hash"; import { enumKeys } from "../lib/util/misc"; import { ChunkGenConstants, PointNodeRef, WorldGenState } from "../data/GameState"; import { Vector2 } from "../lib/util/geometry/vector2"; enum Direction { NORTH = 'NORTH', SOUTH = 'SOUTH', EAST = 'EAST', WEST = 'WEST', UP = 'UP', DOWN = 'DOWN', } type NeighborsMap = { [k in Direction]?: PointNodeRef | undefined } export function getNeighbors(selfPointNodeRef: PointNodeRef, worldGen: WorldGenState): PointNodeRef[] { let neighborsMap = getNeighborsMap(selfPointNodeRef, worldGen); let neighbors : PointNodeRef[] = [] for (let direction of enumKeys(Direction)) { let it = neighborsMap[direction]; if (it) { neighbors.push(it); } } return neighbors; } // TODO(bowei): support vertical neighbors export function getNeighborsMap(selfPointNodeRef: PointNodeRef, worldGen: WorldGenState): NeighborsMap { let neighbors: NeighborsMap = {} let zLevel = worldGen.zLevels[selfPointNodeRef.z]! let myChunk = zLevel.chunks.get(selfPointNodeRef.chunkCoord)!; // first, the right neighbor: if (selfPointNodeRef.pointNodeCoord.x === ChunkGenConstants.CHUNK_HALF_DIM) { let chunkCoord = selfPointNodeRef.chunkCoord.addX(1) let chunk = zLevel.chunks.get(chunkCoord); if (chunk) { let pointNodeCoord = selfPointNodeRef.pointNodeCoord.withX(-ChunkGenConstants.CHUNK_HALF_DIM) let nbor = chunk.pointNodes.get(pointNodeCoord); if (nbor) { neighbors.EAST = new PointNodeRef({ z: selfPointNodeRef.z, chunkCoord, pointNodeCoord, pointNodeId: nbor.id }) } } } else { let pointNodeCoord = selfPointNodeRef.pointNodeCoord.addX(1); let nbor = myChunk.pointNodes.get(pointNodeCoord); if (nbor) { neighbors.EAST = new PointNodeRef({ z: selfPointNodeRef.z, chunkCoord: selfPointNodeRef.chunkCoord, pointNodeCoord, pointNodeId: nbor.id }) } } // left neighbor if (selfPointNodeRef.pointNodeCoord.x === -ChunkGenConstants.CHUNK_HALF_DIM) { let chunkCoord = selfPointNodeRef.chunkCoord.addX(-1) let chunk = zLevel.chunks.get(chunkCoord); if (chunk) { let pointNodeCoord = selfPointNodeRef.pointNodeCoord.withX(ChunkGenConstants.CHUNK_HALF_DIM) let nbor = chunk.pointNodes.get(pointNodeCoord); if (nbor) { neighbors.WEST = new PointNodeRef({ z: selfPointNodeRef.z, chunkCoord, pointNodeCoord, pointNodeId: nbor.id }) } } } else { let pointNodeCoord = selfPointNodeRef.pointNodeCoord.addX(-1); let nbor = myChunk.pointNodes.get(pointNodeCoord); if (nbor) { neighbors.WEST = new PointNodeRef({ z: selfPointNodeRef.z, chunkCoord: selfPointNodeRef.chunkCoord, pointNodeCoord, pointNodeId: nbor.id }) } } // +y is down if (selfPointNodeRef.pointNodeCoord.y === ChunkGenConstants.CHUNK_HALF_DIM) { let chunkCoord = selfPointNodeRef.chunkCoord.addY(1) let chunk = zLevel.chunks.get(chunkCoord); if (chunk) { let pointNodeCoord = selfPointNodeRef.pointNodeCoord.withY(-ChunkGenConstants.CHUNK_HALF_DIM) let nbor = chunk.pointNodes.get(pointNodeCoord); if (nbor) { neighbors.SOUTH = new PointNodeRef({ z: selfPointNodeRef.z, chunkCoord, pointNodeCoord, pointNodeId: nbor.id }) } } } else { let pointNodeCoord = selfPointNodeRef.pointNodeCoord.addY(1); let nbor = myChunk.pointNodes.get(pointNodeCoord); if (nbor) { neighbors.SOUTH = new PointNodeRef({ z: selfPointNodeRef.z, chunkCoord: selfPointNodeRef.chunkCoord, pointNodeCoord, pointNodeId: nbor.id }) } } // -y is up if (selfPointNodeRef.pointNodeCoord.y === -ChunkGenConstants.CHUNK_HALF_DIM) { let chunkCoord = selfPointNodeRef.chunkCoord.addY(-1) let chunk = zLevel.chunks.get(chunkCoord); if (chunk) { let pointNodeCoord = selfPointNodeRef.pointNodeCoord.withY(ChunkGenConstants.CHUNK_HALF_DIM) let nbor = chunk.pointNodes.get(pointNodeCoord); if (nbor) { neighbors.NORTH = new PointNodeRef({ z: selfPointNodeRef.z, chunkCoord, pointNodeCoord, pointNodeId: nbor.id }) } } } else { let pointNodeCoord = selfPointNodeRef.pointNodeCoord.addY(-1); let nbor = myChunk.pointNodes.get(pointNodeCoord); if (nbor) { neighbors.NORTH = new PointNodeRef({ z: selfPointNodeRef.z, chunkCoord: selfPointNodeRef.chunkCoord, pointNodeCoord, pointNodeId: nbor.id }) } } // progress zlevels // up is only available if we are the center of our chunk if (selfPointNodeRef.pointNodeCoord.equals(Vector2.Zero)) { let upZLevel = worldGen.zLevels[selfPointNodeRef.z + 1]; if (upZLevel) { // use our chunkcoord and divide by CHUNK_DIM let chunkCoord = selfPointNodeRef.chunkCoord; let upChunkCoordX = Math.round(chunkCoord.x / ChunkGenConstants.CHUNK_DIM) let upNodeX = chunkCoord.x - ChunkGenConstants.CHUNK_DIM * upChunkCoordX // should be between - CHUNK_HALF_DIM and CHUNK_HALF_DIM let upChunkCoordY = Math.round(chunkCoord.y / ChunkGenConstants.CHUNK_DIM) let upNodeY = chunkCoord.y - ChunkGenConstants.CHUNK_DIM * upChunkCoordX // should be between - CHUNK_HALF_DIM and CHUNK_HALF_DIM let upChunkCoord = new Vector2(upChunkCoordX, upChunkCoordY); let upChunk = upZLevel.chunks.get(upChunkCoord); if (upChunk) { let upNode = new Vector2(upNodeX, upNodeY); let nbor = upChunk.pointNodes.get(upNode) if (nbor) { neighbors.UP = new PointNodeRef({ z: selfPointNodeRef.z + 1, chunkCoord: upChunkCoord, pointNodeCoord: upNode, pointNodeId: nbor.id }); } } } } // down let downZLevel = worldGen.zLevels[selfPointNodeRef.z - 1]; if (downZLevel) { let chunkCoord = selfPointNodeRef.chunkCoord.multiply(9).add(selfPointNodeRef.pointNodeCoord); let downChunk = downZLevel.chunks.get(chunkCoord); if (downChunk) { let nbor = downChunk.pointNodes.get(Vector2.Zero); if (nbor) { neighbors.DOWN = new PointNodeRef({ z: selfPointNodeRef.z - 1, chunkCoord, pointNodeCoord: Vector2.Zero, pointNodeId: nbor.id }); } } } return neighbors; } export function canAllocate( selfPointNodeRef: PointNodeRef, worldGen: WorldGenState, allocatedPointNodeSet: HashSet<PointNodeRef>, hasActiveQuest: boolean, ): "yes" | "already allocated" | "no active quest" | "not connected" { if (allocatedPointNodeSet.contains(selfPointNodeRef)) { return "already allocated"; } if (hasActiveQuest === false) { return "no active quest" } // check if any of our neighbors are allocated const neighbors = getNeighbors(selfPointNodeRef, worldGen); for (let nbor of neighbors) { if (allocatedPointNodeSet.contains(nbor)) { return "yes"; } } return "not connected"; }