-
Notifications
You must be signed in to change notification settings - Fork 1
/
worldgen.py
188 lines (165 loc) · 6.14 KB
/
worldgen.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
"""The worldgen module contains random world generation functions.
It exports the generate_world() function for the Game class __init__()
method. In the future it will be used by some other module that will
allow the user to tweak the worldgen settings from within the game.
"""
import json
import random
from dataclasses import dataclass
from math import sqrt, floor
import cubic
import data
# from playergen import Player
layout = cubic.Layout(cubic.layout_pointy, cubic.Point(50, 50), cubic.Point(800, 550))
CITY_DENSITY = 0.1
@dataclass
class Locality:
name: str = ''
category: str = ''
starting_owner: object = None
@dataclass
class Tile:
"""Represents the data held by a game tile
Attributes
----------
owner : Player | None
The tile owner.
category : str
Tile type - i.e. water/land.
locality: Locality | None
Can be a City or a Capital.
army : Army | None
Armies can move between tiles.
"""
owner: object = None
category: str = 'farmland'
locality: object = None
army: object = None
def __str__(self):
if self.locality:
string = str(self.locality.name)
else:
string = str(self.category)
return string
def align_hex_top_left(radius):
# R = Layout.size
# r = cos30 R = sqrt(3)/2 R
factor = sqrt(3)/2
r = cubic.Point(layout.size.x * factor, layout.size.y * factor)
R = cubic.Point(layout.size.x, layout.size.y)
if layout.orientation == cubic.layout_pointy:
x = (2 * r.x * radius) - r.x
# every 4 tiles skip one R
y = (2 * R.y * radius) - (2 * R.y * radius/4) + R.y
else:
y = (2 * r.y * radius)
# every 4 tiles skip one R
x = (2 * R.x * radius) - (2 * R.x * radius/4) -R.x/2
layout.origin = cubic.Point(x,y)
def shape_classic():
"""Generates a cube:tile dict to be used as the game world map,
identical to the original hex empire 1 world map. Returns the dict.
"""
layout.orientation = cubic.layout_flat
layout.origin = cubic.Point(-10, 10)
MAP_WIDTH = 20
MAP_HEIGHT = 11
world_map = dict()
q = 0
while (q < MAP_WIDTH):
q += 1
q_offset = floor((q+1)/2) # or q>>1
r = -q_offset
while (r < MAP_HEIGHT - q_offset):
r += 1
world_map[(cubic.Cube(q, r, -q-r))] = Tile()
return world_map
def shape_hexagon(map_radius):
"""Generates a cube:tile dictionary with a hexagonal shape.
Returns the dictionary."""
align_hex_top_left(map_radius)
world_map = dict()
q = -map_radius
while q <= map_radius:
r1 = max(-map_radius, -q - map_radius)
r2 = min(map_radius, -q + map_radius)
r = r1
q += 1
while r <= r2:
world_map[(cubic.Cube(q, r, -q-r))] = Tile()
r += 1
return world_map
def choose_shape(shape, radius):
"""Shape interface"""
if shape == 'classic': res = shape_classic()
elif shape == 'hexagon': res = shape_hexagon(radius)
return res
def get_city_names():
"""Returns a list of european city names under 12 characters in length."""
with open("resources/cities.json", "r") as read_file:
raw = json.load(read_file)
cities = raw['data']
city_names = [city['asciiname'] for city in cities if len(city['asciiname']) < 12]
random.shuffle(city_names)
return city_names
def get_random_locality_name():
all_cities = get_city_names()
for city in all_cities:
yield city
locality_name_generator = get_random_locality_name()
def localgen_random(empty_world):
world_size = len(empty_world)
random_tiles = random.sample(world_size.values())
for tile in random_tiles:
name = next(locality_name_generator)
tile.locality = Locality(name, "City")
def localgen_random_ots(empty_world):
"""Same as localgen_random(), but ensures there is one tile of space between every locality."""
for cube, tile in empty_world.items():
flag = True
if empty_world.get(cube).locality:
flag = False
for neighbour in cubic.get_nearest_neighbours(cube):
if neighbour in empty_world and empty_world.get(neighbour).locality:
flag = False
if flag and random.random() > 1 - CITY_DENSITY:
name = next(locality_name_generator)
tile.locality = Locality(name, "City")
def choose_localgen_algorithm(empty_world, algorithm):
if algorithm == 'random':
localgen_random(empty_world)
elif algorithm == 'random_ots':
localgen_random_ots(empty_world)
def playerspawn_classic(filled_world, players):
"""Spawn positions hardcoded to correspond to the original hex empire 1 spawn positions."""
starting_positions = (
cubic.Cube(2, 1, -3),
cubic.Cube(2, 9, -11),
cubic.Cube(19, -8, -11),
cubic.Cube(19, 0, -19))
for player, pos in zip(players, starting_positions):
tile = filled_world[pos]
tile.owner = player
locality_name = next(locality_name_generator)
tile.locality = Locality(locality_name, "Capital", player)
player.starting_cube = pos
for neighbour in cubic.get_nearest_neighbours(pos):
tile = filled_world.get(neighbour)
tile.owner = player
def playerspawn_random(filled_world, players):
for player in players:
starting_cube = random.choice(list(filled_world.keys()))
starting_tile = filled_world.get(starting_cube)
starting_tile.owner = player
locality_name = next(locality_name_generator)
starting_tile.locality = Locality(locality_name, "Capital", player)
player.starting_cube = starting_cube
def choose_playerspawn(filled_world, players, spawntype):
if spawntype == 'classic': playerspawn_classic(filled_world, players)
#elif spawntype == 'maxdist': playerspawn_maxdist(filled_world, players)
elif spawntype == 'random': playerspawn_random(filled_world, players)
def generate_world(shape, radius, algorithm, spawntype, players):
game_world = choose_shape(shape, radius)
choose_playerspawn(game_world, players, spawntype)
choose_localgen_algorithm(game_world, algorithm)
return game_world