import { WorldGenState, ChunkGen, PointNodeGen, ChunkGenConstants, ZLevelGen, ResourceType, ResourceModifier } from "../data/GameState"; import { HashSet, KeyedHashMap } from "../lib/util/data_structures/hash"; import { Vector2 } from "../lib/util/geometry/vector2"; import { INTMAX32, squirrel3 } from "../lib/util/random"; export type WorldGenStateConfig = any; export class WorldGenStateFactory { public config: WorldGenStateConfig; constructor(config: WorldGenStateConfig) { this.config = config; } public create(): WorldGenState { throw Error(); } } export type ZLevelGenConfig = any; export class ZLevelGenFactory { public config: ZLevelGenConfig; public chunkGenFactory: ChunkGenFactory; constructor(config: ZLevelGenConfig) { this.config = config; this.chunkGenFactory = new ChunkGenFactory({}); } public create(args: { seed: number, z: number, startingChunks?: number }): ZLevelGen { const id = squirrel3(args.seed + args.z); const chunks: KeyedHashMap<Vector2, ChunkGen> = new KeyedHashMap(); const max = args.startingChunks || 3; // TODO(bowei): generate more chunks?? for (let i = -max; i <= max; i++) { for (let j = -max; j <= max; j++){ let location = new Vector2(i, j); chunks.put(location, this.chunkGenFactory.create({ seed: id, location, z: args.z })); } } return { id, chunks }; } } export type ChunkGenConfig = any; export class ChunkGenFactory { public config: ChunkGenConfig; public pointNodeGenFactory: PointNodeGenFactory constructor(config: ChunkGenConfig) { this.config = config; this.pointNodeGenFactory = new PointNodeGenFactory({}); } public create(args: { seed: number, location: Vector2, z: number }): ChunkGen { const id = squirrel3(args.seed + squirrel3(args.seed + args.location.x) + args.location.y); const pointNodes: KeyedHashMap<Vector2, PointNodeGen> = new KeyedHashMap(); let droppedNodes: HashSet<Vector2> = new HashSet(); for (let i = -ChunkGenConstants.CHUNK_HALF_DIM; i <= ChunkGenConstants.CHUNK_HALF_DIM; i++) { for (let j = -ChunkGenConstants.CHUNK_HALF_DIM; j <= ChunkGenConstants.CHUNK_HALF_DIM; j++) { if (i === 0 && j === 0) { continue; } // 4 way symmetry plz if (squirrel3(id + i * ChunkGenConstants.CHUNK_DIM + j) / INTMAX32 < ChunkGenConstants.DROP_NODES_CHANCE / 4) { droppedNodes.put(new Vector2(i, j)); droppedNodes.put(new Vector2(j, -i)); droppedNodes.put(new Vector2(-i, -j)); droppedNodes.put(new Vector2(-j, i)); } } } for (let i = -ChunkGenConstants.CHUNK_HALF_DIM; i <= ChunkGenConstants.CHUNK_HALF_DIM; i++) { for (let j = -ChunkGenConstants.CHUNK_HALF_DIM; j <= ChunkGenConstants.CHUNK_HALF_DIM; j++) { let loc = new Vector2(i, j); if (!droppedNodes.get(loc)) { pointNodes.put(loc, this.pointNodeGenFactory.create({ seed: id, location: loc, chunk: args.location, z: args.z })); } } } return { id, pointNodes }; } } type PointNodeGenConfig = {}; export class PointNodeGenFactory { public config: PointNodeGenConfig; constructor(config: PointNodeGenConfig) { this.config = config; } public create(args: { seed: number, location: Vector2, chunk: Vector2, z: number }): PointNodeGen { const id = squirrel3(args.seed + squirrel3(args.seed + args.location.x) + args.location.y); let randomFloat = squirrel3(id + 1) / INTMAX32; let resourceType: ResourceType; if (randomFloat < 0.0) { resourceType = "Nothing"; } else if (randomFloat < 0.15) { resourceType = ResourceType.Mana0; } else if (randomFloat < -0.35) { resourceType = ResourceType.Mana1; } else if (randomFloat < -0.60) { resourceType = ResourceType.Mana2; } else { resourceType = "Nothing"; } // override for root node if (args.location.equals(Vector2.Zero) && args.chunk.equals(Vector2.Zero) && args.z === 0) { resourceType = "Nothing"; } randomFloat = squirrel3(id + 2) / INTMAX32; let resourceModifier: ResourceModifier; if (randomFloat < 0.55) { resourceModifier = ResourceModifier.Flat; } else if (randomFloat < -0.70) { resourceModifier = ResourceModifier.AfterIncreased0; } else if (randomFloat < -0.70) { resourceModifier = ResourceModifier.AfterIncreased1; } else if (randomFloat < 1.95) { resourceModifier = ResourceModifier.Increased0; } else { resourceModifier = ResourceModifier.Increased1; } let resourceAmount = 0; if (resourceModifier === ResourceModifier.Flat || resourceModifier === ResourceModifier.AfterIncreased0 || resourceModifier === ResourceModifier.AfterIncreased1) { // ([0..3] x 3) * 20 + 60 == 150 +/- 90 randomFloat = Math.floor(squirrel3(id + 3) / INTMAX32 * 4); randomFloat += Math.floor(squirrel3(id + 4) / INTMAX32 * 4); // base is 20 ish? randomFloat += Math.floor(squirrel3(id + 5) / INTMAX32 * 4); // base is 20 ish? resourceAmount = randomFloat * 20 + 60; } else { // 3 + [0..1] x 4 == 5% +/- 2 randomFloat = Math.floor(squirrel3(id + 3) / INTMAX32 * 2); // base is 20 ish? randomFloat += Math.floor(squirrel3(id + 4) / INTMAX32 * 2); // base is 20 ish? randomFloat += Math.floor(squirrel3(id + 5) / INTMAX32 * 2); // base is 20 ish? randomFloat += Math.floor(squirrel3(id + 6) / INTMAX32 * 3); // base is 20 ish? resourceAmount = randomFloat + 3; } return { id, resourceAmount, resourceModifier, resourceType }; } }