ruby-perlin-2D-map-generator 0.0.4 → 0.0.6

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1bd8731cdd9870723cfcb6b977f7d111cc160591f727598ae05be919d6dd231f
4
- data.tar.gz: d13ec13f781e96e6251bf37ee54d998c065698063e59d99b8143735c48e7e28a
3
+ metadata.gz: 8bef2e8554e39c0e315b940f4a98a8927348ae576a7f12168c86c74f969c241b
4
+ data.tar.gz: b3debfe8269979c1f1f0be2a8def6a86de9fcd2a8ad6f548295113068ec04566
5
5
  SHA512:
6
- metadata.gz: 766f4c73584e9e5152bf6842790bb3f330ca7d7fd9b46ab7427754f4c7869c0529e870827f181b0523f341d9134e8c5fdce18eecc2ef8a9ad2d22f17112cb040
7
- data.tar.gz: ed3f8b411ccced1c278e0038abd92ccb6f856f67b683f13ab5298b51f762e71683efecf69e87ab53b56ecacf24859a8541336330fb65dcb15da2a8ae1e3b2740
6
+ metadata.gz: c91f9810eda61b360e26b31944820b2587ff9e6a10776cdc84347475470573b381853e63b629781fbc0f18eb9fc33299fad31e2a436ef7f7a66d67db8dbb2ea2
7
+ data.tar.gz: 8c12388e0e7965165557bc5680f030d6d2da9a42e35cc066fbff2390de0e6076c2318e7d62000d17026fa91206adb1ff631eff0ff6af5d670ef81e3d206e45a0
data/README.md CHANGED
@@ -3,16 +3,18 @@
3
3
  [![Gem Version](https://badge.fury.io/rb/ruby-perlin-2D-map-generator.svg)](https://badge.fury.io/rb/ruby-perlin-2D-map-generator)
4
4
  ![CI Status](https://github.com/matthewstyler/ruby-perlin-2D-map-generator/actions/workflows/main.yml/badge.svg)
5
5
  ![CodeQL](https://github.com/matthewstyler/ruby-perlin-2D-map-generator/workflows/CodeQL/badge.svg)
6
+ <a href="https://codeclimate.com/github/matthewstyler/ruby-perlin-2D-map-generator/test_coverage"><img src="https://api.codeclimate.com/v1/badges/b99aae29d02b7a8a4cc6/test_coverage" /></a>
7
+ <a href="https://codeclimate.com/github/matthewstyler/ruby-perlin-2D-map-generator/maintainability"><img src="https://api.codeclimate.com/v1/badges/b99aae29d02b7a8a4cc6/maintainability" /></a>
6
8
  [![Downloads](https://img.shields.io/gem/dt/ruby-perlin-2D-map-generator.svg?style=flat)](https://rubygems.org/gems/ruby-perlin-2D-map-generator)
7
9
 
8
- A gem that procedurally generates seeded and customizable 2D map using perlin noise.
10
+ A gem that procedurally generates seeded and customizable 2D map with optional roads and towns using perlin noise.
9
11
 
10
12
  Include the gem in your project, or use the executable from the command line.
11
13
 
12
14
  Map can be rendered in console using ansi colors or returned as 2D array of hashes describing each tile and binome. Completely customizable, use the --help option for full usage details.
13
15
 
14
16
 
15
- ![2D-maps](https://github.com/matthewstyler/ruby-perlin-2D-map-generator/assets/4560901/4fa5883f-839a-40c9-86a1-d5f9e2c37b9a)
17
+ ![2D-maps](https://github.com/matthewstyler/ruby-perlin-2D-map-generator/assets/4560901/6234ebc1-f3bd-48b5-9b78-4d286d2c8d6e)
16
18
 
17
19
 
18
20
  # Installation
@@ -34,6 +36,7 @@ gem install ruby-perlin-2D-map-generator
34
36
  See Command line Usage for full customization, below are some examples. Alter the temperature, moisture or elevation seeds to alter these maps:
35
37
 
36
38
  - Plains with random terrain evens: `ruby-perlin-2D-map-generator render`
39
+ - Plains with random terrain events and two roads: `ruby-perlin-2D-map-generator render --roads=2`
37
40
  - Desert (increase temperature, decrease moisture): `ruby-perlin-2D-map-generator render --temp=100 --moisture=-100`
38
41
  - Mountainous with lakes (increase elevation, increase moisture) `ruby-perlin-2D-map-generator render --elevation=25 --moisture=25`
39
42
  - Islands (decreaes elevation, increase moisture): `ruby-perlin-2D-map-generator render --elevation=-40 --moisture=25`
@@ -44,21 +47,42 @@ See Command line Usage for full customization, below are some examples. Alter th
44
47
  --width=int The width of the generated map (default 128)
45
48
  --height=int The height of the generated map (default 128)
46
49
 
50
+ --roads=int Add this many roads through the map,
51
+ starting and ending at edges
52
+ (default 0)
53
+ --towns=int Add this randomly sized towns
54
+ (default 0)
47
55
  --hs=int The seed for a terrains height perlin generation
48
56
  (default 10)
49
57
  --ms=int The seed for a terrains moist perlin generation
50
58
  (default 300)
51
59
  --ts=int The seed for a terrains temperature perlin generation
52
60
  (default 3000)
61
+ --rs=int The seed for generating roads
62
+ (default 100)
53
63
 
54
- --elevation=float Adjust each generated elevation by this percent (0 -
64
+ --elevation=float Adjust each generated elevation by this percent (-100 -
55
65
  100) (default 0.0)
56
- --moisture=float Adjust each generated moisture by this percent (0 -
66
+ --moisture=float Adjust each generated moisture by this percent (-100 -
57
67
  100) (default 0.0)
58
- --temp=float Adjust each generated temperature by this percent (0
68
+ --temp=float Adjust each generated temperature by this percent (-100
59
69
  - 100) (default 0.0)
60
70
  ```
61
71
 
72
+ ## Roads and the heuristic
73
+ Roads can be generated by providing a positive integer to the `roads=` argument. Roads are randomly seeded to begin
74
+ and start at an axis (but not the same axis).
75
+
76
+ A* pathfinding with a priority queue is used to generate the roads. The heuristic uses manhattan distance, and favours existing roads and similar elevations in adjacent tiles.
77
+
78
+ Roads can be configured to include/exclude generating paths thorugh water, mountains and flora.
79
+
80
+ Tiles containing roads are of type `road`, those without are of type `terrain`.
81
+
82
+ The `--roads_to_make` option allows you to specify multiple pairs of coordinates to attempt to build paths, subject to the heuristic and other option constraints. Expects a a single list, but must be sets of 4, example of two roads: `--roads_to_make=0,0,50,50,0,0,75,75`
83
+
84
+ ## Towns
85
+ With Poisson Disk Sampling, towns can be generated randomly or with a provided x,y coordinate used as a centroid with radius. The result will be tiles that contain `Building` `items`. Buildings in a town are connected by roads, and additionally towns are connected to other towns by roads.
62
86
  # Generate without rendering
63
87
 
64
88
  ```irb
@@ -112,7 +136,7 @@ $ ruby-perlin-2D-map-generator --help
112
136
  ```bash
113
137
  Usage: ruby-perlin-2D-map-generator [OPTIONS] (DESCRIBE | RENDER)
114
138
 
115
- Generate a seeded customizable procedurally generated 2D map.
139
+ Generate a seeded customizable procedurally generated 2D map with optional roads.
116
140
  Rendered in the console using ansi colours, or described as a 2D array of
117
141
  hashes with each tiles information.
118
142
 
@@ -128,40 +152,74 @@ Keywords:
128
152
  coordinate tile details
129
153
 
130
154
  Options:
131
- --elevation=float Adjust each generated elevation by this percent (0 -
132
- 100) (default 0.0)
133
- --fhx=float The frequency for height generation across the x-axis
134
- (default 2.5)
135
- --fhy=float The frequency for height generation across the y-axis
136
- (default 2.5)
137
- --fmx=float The frequency for moist generation across the x-axis
138
- (default 2.5)
139
- --fmy=float The frequency for moist generation across the y-axis
140
- (default 2.5)
141
- --ftx=float The frequency for temp generation across the x-axis
142
- (default 2.5)
143
- --fty=float The frequency for temp generation across the y-axis
144
- (default 2.5)
145
- --gf=bool Generate flora, significantly affects performance
146
- --height=int The height of the generated map (default 128)
147
- -h, --help Print usage
148
- --hs=int The seed for a terrains height perlin generation
149
- (default 10)
150
- --moisture=float Adjust each generated moisture by this percent (0 -
151
- 100) (default 0.0)
152
- --ms=int The seed for a terrains moist perlin generation
153
- (default 300)
154
- --oh=int Octaves for height generation (default 3)
155
- --om=int Octaves for moist generation (default 3)
156
- --ot=int Octaves for temp generation (default 3)
157
- --ph=float Persistance for height generation (default 1.0)
158
- --pm=float Persistance for moist generation (default 1.0)
159
- --pt=float Persistance for temp generation (default 1.0)
160
- --temp=float Adjust each generated temperature by this percent (0
161
- - 100) (default 0.0)
162
- --ts=int The seed for a terrains temperature perlin generation
163
- (default 3000)
164
- --width=int The width of the generated map (default 128)
155
+ --elevation=float Adjust each generated elevation by
156
+ this percent (-100 - 100) (default 0.0)
157
+ --fhx=float The frequency for height generation
158
+ across the x-axis (default 2.5)
159
+ --fhy=float The frequency for height generation
160
+ across the y-axis (default 2.5)
161
+ --fmx=float The frequency for moist generation
162
+ across the x-axis (default 2.5)
163
+ --fmy=float The frequency for moist generation
164
+ across the y-axis (default 2.5)
165
+ --ftx=float The frequency for temp generation
166
+ across the x-axis (default 2.5)
167
+ --fty=float The frequency for temp generation
168
+ across the y-axis (default 2.5)
169
+ --gf=bool Generate flora, significantly affects
170
+ performance
171
+ --height=int The height of the generated map
172
+ (default 128)
173
+ -h, --help Print usage
174
+ --hs=int The seed for a terrains height perlin
175
+ generation (default 10)
176
+ --moisture=float Adjust each generated moisture by
177
+ this percent (-100 - 100) (default 0.0)
178
+ --ms=int The seed for a terrains moist perlin
179
+ generation (default 300)
180
+ --oh=int Octaves for height generation
181
+ (default 3)
182
+ --om=int Octaves for moist generation (default
183
+ 3)
184
+ --ot=int Octaves for temp generation (default
185
+ 3)
186
+ --ph=float Persistance for height generation
187
+ (default 1.0)
188
+ --pm=float Persistance for moist generation
189
+ (default 1.0)
190
+ --pt=float Persistance for temp generation
191
+ (default 1.0)
192
+ --road_exclude_flora_path=bool Controls if roads will run tiles
193
+ containing flora
194
+ --road_exclude_mountain_path=bool Controls if roads will run through
195
+ high mountains
196
+ --road_exclude_water_path=bool Controls if roads will run through
197
+ water
198
+ --roads=int Add this many roads through the map,
199
+ starting and ending at edges (default
200
+ 0)
201
+ --roads_to_make ints Attempt to create a road from a start
202
+ and end point (4 integers), can be
203
+ supplied multiple paths
204
+ (default [])
205
+ --rs=int The seed for generating roads
206
+ (default 100)
207
+ --temp=float Adjust each generated temperature by
208
+ this percent (-100 - 100) (default 0.0)
209
+ --town_seed=int The seed for generating towns
210
+ (default 500)
211
+ --towns=int Add this many randomly sized towns
212
+ throughout the map
213
+ (default 0)
214
+ --towns_to_make ints Attempt to create a town at given x,y
215
+ coordinate, with z points and v radius
216
+ (4 integers). Can be supplied multiple
217
+ towns.
218
+ (default [])
219
+ --ts=int The seed for a terrains temperature
220
+ perlin generation (default 3000)
221
+ --width=int The width of the generated map
222
+ (default 128)
165
223
 
166
224
  Examples:
167
225
  Render with defaults
@@ -169,6 +227,12 @@ Examples:
169
227
 
170
228
  Render with options
171
229
  $ ruby-perlin-2D-map-generator render --elevation=-40 --moisture=25 --hs=1
230
+
231
+ Render with roads
232
+ $ ruby-perlin-2D-map-generator render --roads=2
233
+
234
+ Render with 5 roads, 1 provided road, 10 random towns and 1 provided town
235
+ $ ruby-perlin-2D-map-generator render --roads=5 --roads_to_make=0,0,50,50 --towns=10 --towns_to_make=5,5,10,3
172
236
 
173
237
  Describe tile [1, 1]
174
238
  $ ruby-perlin-2D-map-generator describe coordinates=1,1
data/lib/CLI/command.rb CHANGED
@@ -12,7 +12,7 @@ module CLI
12
12
 
13
13
  no_command
14
14
 
15
- desc 'Generate a seeded customizable procedurally generated 2D map. Rendered in the console ' \
15
+ desc 'Generate a seeded customizable procedurally generated 2D map with optional roads. Rendered in the console ' \
16
16
  ' using ansi colours, or described as a 2D array of hashes with each tiles information.'
17
17
 
18
18
  example 'Render with defaults',
@@ -21,6 +21,9 @@ module CLI
21
21
  example 'Render with options',
22
22
  ' $ ruby-perlin-2D-map-generator render --elevation=-40 --moisture=25 --hs=1'
23
23
 
24
+ example 'Render with roads',
25
+ ' $ ruby-perlin-2D-map-generator render --roads=2'
26
+
24
27
  example 'Describe tile [1, 1]',
25
28
  ' $ ruby-perlin-2D-map-generator describe coordinates=1,1'
26
29
  end
@@ -41,6 +44,24 @@ module CLI
41
44
  desc 'Used with the describe command, only returns the given coordinate tile details'
42
45
  end
43
46
 
47
+ option :roads_to_make do
48
+ arity one
49
+ long '--roads_to_make ints'
50
+ convert :int_list
51
+ validate ->(v) { v >= 0 }
52
+ desc 'Attempt to create a road from a start and end point (4 integers), can be supplied multiple paths'
53
+ default MapConfig::DEFAULT_ROADS_TO_MAKE
54
+ end
55
+
56
+ option :towns_to_make do
57
+ arity one
58
+ long '--towns_to_make ints'
59
+ convert :int_list
60
+ validate ->(v) { v >= 0 }
61
+ desc 'Attempt to create a town at given x,y coordinate, with z points and v radius (4 integers). Can be supplied multiple towns.'
62
+ default MapConfig::DEFAULT_TOWNS_TO_MAKE
63
+ end
64
+
44
65
  option :height_seed do
45
66
  long '--hs int'
46
67
  # or
@@ -210,7 +231,7 @@ module CLI
210
231
  long '--temp float'
211
232
  long '--temp=float'
212
233
 
213
- desc 'Adjust each generated temperature by this percent (0 - 100)'
234
+ desc 'Adjust each generated temperature by this percent (-100 - 100)'
214
235
  convert ->(val) { val.to_f / 100.0 }
215
236
  validate ->(val) { val >= -1.0 && val <= 1.0 }
216
237
  default MapConfig::DEFAULT_TEMP_ADJUSTMENT
@@ -220,7 +241,7 @@ module CLI
220
241
  long '--elevation float'
221
242
  long '--elevation=float'
222
243
 
223
- desc 'Adjust each generated elevation by this percent (0 - 100)'
244
+ desc 'Adjust each generated elevation by this percent (-100 - 100)'
224
245
  convert ->(val) { val.to_f / 100.0 }
225
246
  validate ->(val) { val >= -1.0 && val <= 1.0 }
226
247
  default MapConfig::DEFAULT_HEIGHT_ADJUSTMENT
@@ -230,12 +251,83 @@ module CLI
230
251
  long '--moisture float'
231
252
  long '--moisture=float'
232
253
 
233
- desc 'Adjust each generated moisture by this percent (0 - 100)'
254
+ desc 'Adjust each generated moisture by this percent (-100 - 100)'
234
255
  convert ->(val) { val.to_f / 100.0 }
235
256
  validate ->(val) { val >= -1.0 && val <= 1.0 }
236
257
  default MapConfig::DEFAULT_MOIST_ADJUSTMENT
237
258
  end
238
259
 
260
+ option :roads do
261
+ long '--roads int'
262
+ long '--roads=int'
263
+
264
+ desc 'Add this many roads through the map, starting and ending at edges'
265
+ convert Integer
266
+ validate ->(val) { val >= 0 }
267
+ default MapConfig::DEFAULT_NUM_OF_ROADS
268
+ end
269
+
270
+ option :road_seed do
271
+ long '--rs int'
272
+ long '--rs=int'
273
+
274
+ desc 'The seed for generating roads'
275
+ convert Integer
276
+ default MapConfig::DEFAULT_ROAD_SEED
277
+ end
278
+
279
+ option :road_exclude_water_path do
280
+ long '--road_exclude_water_path bool'
281
+ long '--road_exclude_water_path=bool'
282
+
283
+ desc 'Controls if roads will run through water'
284
+ convert :bool
285
+ default MapConfig::DEFAULT_ROAD_EXCLUDE_WATER_PATH
286
+ end
287
+
288
+ option :road_exclude_mountain_path do
289
+ long '--road_exclude_mountain_path bool'
290
+ long '--road_exclude_mountain_path=bool'
291
+
292
+ desc 'Controls if roads will run through high mountains'
293
+ convert :bool
294
+ default MapConfig::DEFAULT_ROAD_EXCLUDE_MOUNTAIN_PATH
295
+ end
296
+
297
+ option :road_exclude_flora_path do
298
+ long '--road_exclude_flora_path bool'
299
+ long '--road_exclude_flora_path=bool'
300
+
301
+ desc 'Controls if roads will run tiles containing flora'
302
+ convert :bool
303
+ default MapConfig::DEFAULT_ROAD_EXCLUDE_FLORA_PATH
304
+ end
305
+
306
+ option :town_seed do
307
+ long '--town_seed int'
308
+ long '--town_seed=int'
309
+
310
+ desc 'The seed for generating towns'
311
+ convert Integer
312
+ default MapConfig::DEFAULT_TOWN_SEED
313
+ end
314
+
315
+ option :towns do
316
+ long '--towns int'
317
+ long '--towns=int'
318
+
319
+ desc 'Add this many randomly sized towns throughout the map'
320
+ convert Integer
321
+ validate ->(val) { val >= 0 }
322
+ default MapConfig::DEFAULT_NUM_OF_TOWNS
323
+ end
324
+
325
+ option :verbose do
326
+ arity one
327
+ long '--verbose'
328
+ desc 'Used with the render command, outputs loading information'
329
+ end
330
+
239
331
  flag :help do
240
332
  short '-h'
241
333
  long '--help'
@@ -259,10 +351,11 @@ module CLI
259
351
  map = Map.new(map_config: MapConfig.new(
260
352
  width: params[:width],
261
353
  height: params[:height],
262
- perlin_height_config: perlin_height_config,
263
- perlin_moist_config: perlin_moist_config,
264
- perlin_temp_config: perlin_temp_config,
265
- generate_flora: params[:generate_flora]
354
+ all_perlin_configs: MapConfig::AllPerlinConfigs.new(perlin_height_config, perlin_moist_config, perlin_temp_config),
355
+ generate_flora: params[:generate_flora],
356
+ road_config: MapConfig::RoadConfig.new(*params.to_h.slice(:road_seed, :roads, :road_exclude_water_path, :road_exclude_mountain_path, :road_exclude_flora_path, :roads_to_make).values),
357
+ town_config: MapConfig::TownConfig.new(*params.to_h.slice(:town_seed, :towns, :towns_to_make).values),
358
+ verbose: params[:verbose]
266
359
  ))
267
360
  case params[:command]
268
361
  when 'render' then map.render
data/lib/ansi_colours.rb CHANGED
@@ -26,6 +26,9 @@ module AnsiColours
26
26
  TAIGA_HIGHLAND = "\e[48;5;65m"
27
27
  TAIGA_COAST = "\e[48;5;17m"
28
28
  ICE = "\e[48;5;159m"
29
+ LOW_ROAD_BLACK = "\e[48;5;241m"
30
+ ROAD_BLACK = "\e[48;5;239m"
31
+ HIGH_ROAD_BLACK = "\e[48;5;236m"
29
32
  ANSI_RESET = "\033[0m"
30
33
  end
31
34
  end
data/lib/biome.rb CHANGED
@@ -32,6 +32,10 @@ class Biome
32
32
  TAIGA_TERRAIN.include?(self)
33
33
  end
34
34
 
35
+ def high_mountain?
36
+ HIGH_MOUNTAIN.include?(self)
37
+ end
38
+
35
39
  def flora_available
36
40
  !flora_range.nil?
37
41
  end
@@ -132,6 +136,12 @@ class Biome
132
136
  TAIGA_COAST
133
137
  ].freeze
134
138
 
139
+ HIGH_MOUNTAIN = [
140
+ SNOW,
141
+ ROCKS,
142
+ MOUNTAIN
143
+ ].freeze
144
+
135
145
  LAND_TERRAIN = (ALL_TERRAIN - WATER_TERRAIN).freeze
136
146
 
137
147
  class << self
@@ -141,21 +151,21 @@ class Biome
141
151
  case elevation
142
152
  when 0.95..1
143
153
  SNOW
144
- when 0.9..0.95
154
+ when 0.9...0.95
145
155
  ROCKS
146
- when 0.8..0.9
156
+ when 0.8...0.9
147
157
  if moist < 0.9
148
158
  MOUNTAIN
149
159
  else
150
160
  SHOAL
151
161
  end
152
- when 0.7..0.8
162
+ when 0.7...0.8
153
163
  if moist < 0.9
154
164
  MOUNTAIN_FOOT
155
165
  else
156
166
  SHOAL
157
167
  end
158
- when 0.6..0.7
168
+ when 0.6...0.7
159
169
  if moist < 0.8
160
170
  if desert_condition?(moist, temp)
161
171
  STEPPE_DESERT
@@ -169,7 +179,7 @@ class Biome
169
179
  else
170
180
  SHOAL
171
181
  end
172
- when 0.3..0.6
182
+ when 0.3...0.6
173
183
  if desert_condition?(moist, temp)
174
184
  DESERT
175
185
  elsif taiga_condition?(moist, temp)
@@ -177,7 +187,7 @@ class Biome
177
187
  else
178
188
  VALLEY
179
189
  end
180
- when 0.2..0.3
190
+ when 0.2...0.3
181
191
  if desert_condition?(moist, temp)
182
192
  DEEP_DESERT
183
193
  elsif taiga_condition?(moist, temp)
@@ -185,25 +195,25 @@ class Biome
185
195
  else
186
196
  DEEP_VALLEY
187
197
  end
188
- when 0.15..0.2
198
+ when 0.15...0.2
189
199
  if taiga_condition?(moist, temp)
190
200
  TAIGA_COAST
191
201
  else
192
202
  COASTLINE
193
203
  end
194
- when 0.05..0.15
204
+ when 0.05...0.15
195
205
  if taiga_condition?(moist, temp)
196
206
  ICE
197
207
  else
198
208
  SHOAL
199
209
  end
200
- when 0.025..0.05
210
+ when 0.025...0.05
201
211
  if taiga_condition?(moist, temp)
202
212
  ICE
203
213
  else
204
214
  OCEAN
205
215
  end
206
- when 0.0..0.025
216
+ when 0.0...0.025
207
217
  if taiga_condition?(moist, temp)
208
218
  ICE
209
219
  else
data/lib/building.rb ADDED
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'tile_item'
4
+
5
+ #
6
+ # Represents a building item on a tile
7
+ #
8
+ class Building < TileItem
9
+ TOWN_RENDER_PRIORITY = DEFAULT_RENDER_PRIORITY + 1
10
+
11
+ HOUSE = "\u{1F3E0}"
12
+
13
+ def initialize(render_symbol)
14
+ super self, render_symbol: render_symbol, render_priority: TOWN_RENDER_PRIORITY
15
+ end
16
+
17
+ def self.random_town_building(_seed)
18
+ Building.new(HOUSE)
19
+ end
20
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ #
4
+ # Generates flora for the given tiles
5
+ #
6
+ class FloraGenerator
7
+ attr_reader :tiles
8
+
9
+ def initialize(tiles)
10
+ @tiles = tiles
11
+ end
12
+
13
+ def generate(config)
14
+ return unless config.generate_flora
15
+
16
+ puts 'generating flora...' if config.verbose
17
+ tiles.each do |row|
18
+ row.each do |tile|
19
+ next unless tile.biome.flora_available
20
+
21
+ range_max_value = tiles[(tile.y - tile.biome.flora_range)...(tile.y + tile.biome.flora_range)]&.map do |r|
22
+ r[(tile.x - tile.biome.flora_range)...(tile.x + tile.biome.flora_range)]
23
+ end&.flatten&.map(&:height)&.max
24
+ tile.add_flora if range_max_value == tile.height
25
+ end
26
+ end
27
+ end
28
+ end
data/lib/map.rb CHANGED
@@ -2,6 +2,9 @@
2
2
 
3
3
  require 'map_tile_generator'
4
4
  require 'map_config'
5
+ require 'road_generator'
6
+ require 'town_generator'
7
+ require 'flora_generator'
5
8
 
6
9
  class Map
7
10
  attr_reader :config
@@ -30,6 +33,35 @@ class Map
30
33
  # rubocop:enable Naming/MethodParameterName:
31
34
 
32
35
  def tiles
33
- @tiles ||= MapTileGenerator.new(map: self).generate
36
+ return @tiles if @tiles
37
+
38
+ generate_tiles
39
+ generate_flora
40
+ generate_roads
41
+ generate_towns
42
+
43
+ @tiles
44
+ end
45
+
46
+ private
47
+
48
+ def generate_tiles
49
+ @tiles = MapTileGenerator.new(map: self).generate
50
+ end
51
+
52
+ def generate_flora
53
+ FloraGenerator.new(@tiles).generate(config)
54
+ end
55
+
56
+ def generate_roads
57
+ road_generator = RoadGenerator.new(@tiles)
58
+ road_generator.generate_num_of_random_roads(config.road_config)
59
+ road_generator.generate_roads_from_coordinate_list(config.road_config.roads_to_make, config.verbose)
60
+ end
61
+
62
+ def generate_towns
63
+ town_generator = TownGenerator.new(@tiles, seed: config.town_config.town_seed)
64
+ town_generator.generate_random_towns(config.town_config)
65
+ town_generator.generate_towns_from_coordinate_list(config.town_config)
34
66
  end
35
67
  end
data/lib/map_config.rb CHANGED
@@ -25,25 +25,57 @@ class MapConfig
25
25
  DEFAULT_TEMP_X_FREQUENCY = 2.5
26
26
  DEFAULT_TEMP_ADJUSTMENT = 0.0
27
27
 
28
+ DEFAULT_ROAD_SEED = 100
29
+ DEFAULT_NUM_OF_ROADS = 0
30
+ DEFAULT_ROAD_EXCLUDE_WATER_PATH = true
31
+ DEFAULT_ROAD_EXCLUDE_MOUNTAIN_PATH = true
32
+ DEFAULT_ROAD_EXCLUDE_FLORA_PATH = true
33
+ DEFAULT_ROADS_TO_MAKE = [].freeze
34
+
35
+ DEFAULT_TOWN_SEED = 500
36
+ DEFAULT_NUM_OF_TOWNS = 0
37
+ DEFAULT_TOWNS_TO_MAKE = [].freeze
38
+
39
+ DEFAULT_VERBOSE = false
40
+
28
41
  PERLIN_CONFIG_OPTIONS = %i[width height noise_seed octaves x_frequency y_frequency persistance adjustment].freeze
29
- PerlinConfig = Struct.new(*PERLIN_CONFIG_OPTIONS)
42
+ ALL_PERLIN_CONFIGS = %i[perlin_height_config perlin_moist_config perlin_temp_config].freeze
43
+ ROAD_CONFIG_OPTIONS = %i[road_seed roads road_exclude_water_path road_exclude_mountain_path road_exclude_flora_path roads_to_make verbose].freeze
44
+ TOWN_CONFIG_OPTIONS = %i[town_seed towns towns_to_make verbose].freeze
30
45
 
31
- attr_reader :generate_flora, :perlin_height_config, :perlin_moist_config, :perlin_temp_config, :width, :height
46
+ PerlinConfig = Struct.new(*PERLIN_CONFIG_OPTIONS)
47
+ AllPerlinConfigs = Struct.new(*ALL_PERLIN_CONFIGS)
48
+ RoadConfig = Struct.new(*ROAD_CONFIG_OPTIONS)
49
+ TownConfig = Struct.new(*TOWN_CONFIG_OPTIONS)
32
50
 
33
- def initialize(perlin_height_config: default_perlin_height_config, perlin_moist_config: default_perlin_moist_config, perlin_temp_config: default_perlin_temp_config, width: DEFAULT_TILE_COUNT,
34
- height: DEFAULT_TILE_COUNT, generate_flora: DEFAULT_GENERATE_FLORA)
35
- raise ArgumentError unless perlin_height_config.is_a?(PerlinConfig) && perlin_moist_config.is_a?(PerlinConfig)
51
+ attr_reader :generate_flora, :perlin_height_config, :perlin_moist_config, :perlin_temp_config, :width, :height, :road_config, :town_config, :verbose
36
52
 
53
+ # rubocop:disable Metrics/ParameterLists:
54
+ def initialize(all_perlin_configs: default_perlin_configs, width: DEFAULT_TILE_COUNT,
55
+ height: DEFAULT_TILE_COUNT, generate_flora: DEFAULT_GENERATE_FLORA, road_config: default_road_config, town_config: default_town_config, verbose: DEFAULT_VERBOSE)
56
+ validate(all_perlin_configs)
37
57
  @generate_flora = generate_flora
38
- @perlin_height_config = perlin_height_config
39
- @perlin_moist_config = perlin_moist_config
40
- @perlin_temp_config = perlin_temp_config
58
+ @perlin_height_config = all_perlin_configs.perlin_height_config
59
+ @perlin_moist_config = all_perlin_configs.perlin_moist_config
60
+ @perlin_temp_config = all_perlin_configs.perlin_temp_config
41
61
  @width = width
42
62
  @height = height
63
+ @road_config = road_config
64
+ @town_config = town_config
65
+ @verbose = verbose
66
+ town_config.verbose = verbose
67
+ road_config.verbose = verbose
43
68
  end
69
+ # rubocop:enable Metrics/ParameterLists:
44
70
 
45
71
  private
46
72
 
73
+ def validate(all_perlin_configs)
74
+ unless all_perlin_configs.perlin_height_config.is_a?(PerlinConfig) && all_perlin_configs.perlin_moist_config.is_a?(PerlinConfig) && all_perlin_configs.perlin_temp_config.is_a?(PerlinConfig)
75
+ raise ArgumentError
76
+ end
77
+ end
78
+
47
79
  def default_perlin_height_config
48
80
  PerlinConfig.new(DEFAULT_TILE_COUNT, DEFAULT_TILE_COUNT, DEFAULT_HEIGHT_SEED, DEFAULT_HEIGHT_OCTAVES,
49
81
  DEFAULT_HEIGHT_X_FREQUENCY, DEFAULT_HEIGHT_Y_FREQUENCY, DEFAULT_HEIGHT_PERSISTANCE, DEFAULT_HEIGHT_ADJUSTMENT)
@@ -58,4 +90,17 @@ class MapConfig
58
90
  PerlinConfig.new(DEFAULT_TILE_COUNT, DEFAULT_TILE_COUNT, DEFAULT_TEMP_SEED, DEFAULT_TEMP_OCTAVES,
59
91
  DEFAULT_TEMP_X_FREQUENCY, DEFAULT_TEMP_Y_FREQUENCY, DEFAULT_TEMP_PERSISTANCE, DEFAULT_TEMP_ADJUSTMENT)
60
92
  end
93
+
94
+ def default_road_config
95
+ RoadConfig.new(DEFAULT_ROAD_SEED, DEFAULT_NUM_OF_ROADS, DEFAULT_ROAD_EXCLUDE_WATER_PATH, DEFAULT_ROAD_EXCLUDE_MOUNTAIN_PATH, DEFAULT_ROAD_EXCLUDE_FLORA_PATH, DEFAULT_ROADS_TO_MAKE,
96
+ DEFAULT_VERBOSE)
97
+ end
98
+
99
+ def default_town_config
100
+ TownConfig.new(DEFAULT_TOWN_SEED, DEFAULT_NUM_OF_TOWNS, DEFAULT_TOWNS_TO_MAKE, DEFAULT_VERBOSE)
101
+ end
102
+
103
+ def default_perlin_configs
104
+ AllPerlinConfigs.new(default_perlin_height_config, default_perlin_moist_config, default_perlin_temp_config)
105
+ end
61
106
  end