1 /*
2  * Copyright (c) 2017-2018 sel-project
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a copy
5  * of this software and associated documentation files (the "Software"), to deal
6  * in the Software without restriction, including without limitation the rights
7  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8  * copies of the Software, and to permit persons to whom the Software is
9  * furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included in all
12  * copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20  * SOFTWARE.
21  *
22  */
23 /**
24  * Copyright: 2017-2018 sel-project
25  * License: MIT
26  * Authors: Kripth
27  * Source: $(HTTP github.com/sel-project/selery/source/selery/world/generator.d, selery/world/generator.d)
28  */
29 module selery.world.generator;
30 
31 import std.algorithm : min;
32 import std.conv : to;
33 import std.random : uniform, uniform01;
34 
35 import selery.block.block : Block;
36 import selery.block.blocks : Blocks;
37 import selery.math.vector : ChunkPosition, BlockPosition, distance;
38 import selery.world.chunk : Chunk;
39 import selery.world.world : World;
40 
41 abstract class Generator {
42 
43 	protected World world;
44 	private uint m_seed;
45 
46 	public @safe @nogc this(World world) {
47 		this.world = world;
48 	}
49 
50 	public abstract @property @safe BlockPosition spawn();
51 
52 	public abstract Chunk generate(ChunkPosition position);
53 
54 	public pure nothrow @property @safe @nogc uint seed() {
55 		return this.m_seed;
56 	}
57 
58 	public pure nothrow @property @safe @nogc uint seed(uint seed) {
59 		return this.m_seed = seed;
60 	}
61 
62 	public abstract pure nothrow @property @safe string type();
63 
64 }
65 
66 class Empty : Generator {
67 
68 	public @safe @nogc this(World world) {
69 		super(world);
70 	}
71 
72 	public override @property @safe BlockPosition spawn() {
73 		return BlockPosition(0, 0, 0);
74 	}
75 
76 	public override @safe Chunk generate(ChunkPosition position) {
77 		return new Chunk(this.world, position);
78 	}
79 
80 	public override pure nothrow @property @safe string type() {
81 		return "flat";
82 	}
83 
84 }
85 
86 class Flat : Generator {
87 
88 	private ushort[] layers;
89 	protected bool trees;
90 
91 	public @safe this(World world, ushort[] layers=[Blocks.bedrock, Blocks.dirt, Blocks.dirt, Blocks.dirt, Blocks.grass], bool trees=true) {
92 		super(world);
93 		this.layers = layers;
94 		this.trees = trees;
95 	}
96 
97 	public override @property @safe BlockPosition spawn() {
98 		return BlockPosition(0, this.layers.length.to!int, 0);
99 	}
100 
101 	public override Chunk generate(ChunkPosition position) {
102 		Chunk chunk = new Chunk(this.world, position);
103 		foreach(ubyte xx ; 0..16) {
104 			foreach(ubyte zz ; 0..16) {
105 				foreach(uint y ; 0..this.layers.length.to!uint) {
106 					chunk[xx, y, zz] = this.layers[y];
107 				}
108 			}
109 		}
110 		if(this.trees && uniform01!float(this.world.random) >= .75) {
111 			//test a tree
112 			ubyte tree = uniform(ubyte(0), ubyte(6), this.world.random);
113 			ubyte height = uniform(ubyte(4), ubyte(24), this.world.random);
114 			ubyte foliage = uniform(ubyte(3), min(height, ubyte(7)), this.world.random);
115 			//logs
116 			foreach(y ; this.layers.length..this.layers.length+height) {
117 				chunk[7, cast(uint)y, 7] = Blocks.woodUpDown[tree];
118 			}
119 			//leaves
120 			BlockPosition center = BlockPosition(7, this.layers.length.to!int + height, 7);
121 			foreach(ubyte xx ; to!ubyte(7 - foliage)..to!ubyte(7 + foliage + 1)) {
122 				foreach(ubyte zz ; to!ubyte(7 - foliage)..to!ubyte(7 + foliage + 1)) {
123 					foreach(uint yy ; (center.y - foliage)..(center.y + foliage + 1)) {
124 						BlockPosition pos = BlockPosition(xx, yy, zz);
125 						if(pos.distance(center) <= foliage) {
126 							auto current = chunk[xx, yy, zz];
127 							if(current is null || *current is null) {
128 								chunk[xx, yy, zz] = Blocks.leavesDecay[tree];
129 							}
130 						}
131 					}
132 				}
133 			}
134 		}
135 		return chunk;
136 	}
137 
138 	public override pure nothrow @property @safe string type() {
139 		return "flat";
140 	}
141 
142 }