1 /* ----------------------------------------------------------------------
2 * init_game.cpp
3 * This file is part of lincity-ng
4 * see COPYING for license, and CREDITS for authors
5 * ----------------------------------------------------------------------
6 */
7
8 // This was part of simulate.cpp.
9 // Moved in new file for clarification
10 //
11 // (re)initialise engine and UI data when
12 // - load a saved game (or a scenario)
13 // - start a random village (or a void map)
14 //
15
16 #include <math.h>
17 #include <cstdlib>
18 #include "init_game.h"
19 #include "fileutil.h"
20 #include "simulate.h"
21 #include "gui_interface/shared_globals.h"
22 #include "lctypes.h"
23 #include "lin-city.h"
24 #include "engglobs.h"
25 #include "gui_interface/screen_interface.h"
26 #include "power.h"
27 #include "stats.h"
28 #include "gui_interface/pbar_interface.h"
29 #include "modules/all_modules.h"
30 #include "transport.h"
31
32 #define IS_RIVER(x,y) (MP_INFO(x,y).flags & FLAG_IS_RIVER)
33
34 static const int di[8] = { -1, 0, 1, 0, 1, 1, -1, -1};
35 static const int dj[8] = { 0, -1, 0, 1, 1, -1, 1, -1};
36
37 /* Private functions prototypes */
38
39 static void init_mappoint_array(void);
40 static void initialize_tax_rates(void);
41 static void nullify_mappoint(int x, int y);
42 static void random_start(int *originx, int *originy);
43 static void coal_reserve_setup(void);
44 static void ore_reserve_setup(void);
45 static void setup_river(void);
46 static void setup_river2(int x, int y, int d, int alt, int mountain);
47 static void setup_ground(void);
48 static void new_setup_river_ground(void);
49 static void new_setup_river(void);
50 static void sort_by_altitude(int n, int *tabx, int *taby);
51 static void new_setup_one_river(int num_river, int c, int *colx, int *coly, int t, int *topx, int *topy, int l, int *lakx, int *laky);
52 static void set_river_tile( int i, int j);
53
54 /* ---------------------------------------------------------------------- *
55 * Public Functions
56 * ---------------------------------------------------------------------- */
clear_game(void)57 void clear_game(void)
58 {
59 int x, y, i, p;
60
61 init_mappoint_array ();
62 initialize_tax_rates ();
63 init_inventory();
64
65 // Clear engine and UI data.
66 for (y = 0; y < WORLD_SIDE_LEN; y++) {
67 for (x = 0; x < WORLD_SIDE_LEN; x++) {
68 nullify_mappoint(x, y);
69 }
70 }
71 total_time = 0;
72 coal_survey_done = 0;
73 numof_shanties = 0;
74 numof_communes = 0;
75 numof_substations = 0;
76 numof_health_centres = 0;
77 numof_markets = 0;
78 max_pop_ever = 0;
79 total_evacuated = 0;
80 total_births = 0;
81 total_money = 0;
82 tech_level = 0;
83 highest_tech_level = 0;
84 rockets_launched = 0;
85 rockets_launched_success = 0;
86 init_inventory();
87 update_avail_modules(0);
88
89 use_waterwell = true; // NG 1.91 : AL1
90 // unused now (it was used in branch waterwell)
91 // but useful to know how to add an optional module, so keep it for a while.
92 numof_waterwell = 0;
93 global_aridity = 0;
94 global_mountainity =0;
95
96 highest_tech_level = 0;
97 total_pollution_deaths = 0;
98 pollution_deaths_history = 0;
99 total_starve_deaths = 0;
100 starve_deaths_history = 0;
101 total_unemployed_years = 0;
102 unemployed_history = 0;
103 /* Al1. NG 1.1 is this enough ? Are all global variables reseted ? */
104
105 // UI stuff
106 /* TODO check reset screen, sustain info ... */
107 given_scene[0] = 0;
108 for( i = 0; i < monthgraph_size; i++ ){
109 monthgraph_pop[i] = 0;
110 monthgraph_starve[i] = 0;
111 monthgraph_nojobs[i] = 0;
112 monthgraph_ppool[i] = 0;
113 }
114 // reset PBARS
115 // FIXME AL1 NG 1.92.svn pbars are reseted only
116 // when we build something
117 // when some building already exist and modify one value
118 //
119 /* AL1 i don't understand why this does not work
120 init_pbars(); // AL1: Why is this not enough and why do we need additional stuff ?
121 */
122
123 /*
124 */
125 housed_population=0;
126 tech_level=0;
127 tfood_in_markets=0;
128 tjobs_in_markets=0;
129 tcoal_in_markets=0;
130 tgoods_in_markets=0;
131 tore_in_markets=0;
132 tsteel_in_markets=0;
133 total_money=0;
134
135 init_pbars();
136 for (p = 0; p < NUM_PBARS; p++)
137 pbars[p].data_size = PBAR_DATA_SIZE;
138
139 for (p = 0; p < NUM_PBARS; p++) {
140 pbars[p].oldtot = 0;
141 pbars[p].diff = 0;
142 }
143
144 for (x = 0; x < PBAR_DATA_SIZE; x++) {
145 update_pbar (PPOP, housed_population, 1);
146 update_pbar (PTECH, tech_level, 1);
147 update_pbar (PFOOD, tfood_in_markets , 1);
148 update_pbar (PJOBS, tjobs_in_markets , 1);
149 update_pbar (PCOAL, tcoal_in_markets , 1);
150 update_pbar (PGOODS, tgoods_in_markets , 1);
151 update_pbar (PORE, tore_in_markets , 1);
152 update_pbar (PSTEEL, tsteel_in_markets , 1);
153 update_pbar (PMONEY, total_money, 1);
154 }
155 data_last_month = 1;
156 update_pbars_monthly();
157 }
158
new_city(int * originx,int * originy,int random_village)159 void new_city(int *originx, int *originy, int random_village)
160 {
161 int old_setup_ground = true;
162 clear_game();
163 coal_reserve_setup();
164
165 global_mountainity= 100 + rand () % 300; // roughly water slope = 25m / 1km (=from N to S)
166 if (old_setup_ground) {
167 setup_river();
168 setup_ground();
169 } else {
170 new_setup_river_ground();
171 }
172 setup_land();
173 ore_reserve_setup();
174 init_pbars();
175
176 /* Initial population is 100 for empty board or 200
177 for random village (100 are housed). */
178 people_pool = 100;
179
180 if (random_village != 0) {
181 random_start(originx, originy);
182 update_pbar(PPOP, 200, 1); /* So pbars don't flash */
183 } else {
184 *originx = *originy = WORLD_SIDE_LEN / 2;
185 update_pbar(PPOP, 100, 1);
186 }
187 connect_transport(1, 1, WORLD_SIDE_LEN - 2, WORLD_SIDE_LEN - 2);
188 /* Fix desert frontier for old saved games and scenarios */
189 desert_frontier(0, 0, WORLD_SIDE_LEN, WORLD_SIDE_LEN);
190
191 refresh_pbars(); // AL1: does nothing in NG !
192 }
193
setup_land(void)194 void setup_land(void)
195 {
196 int x, y, xw, yw;
197 int aridity = rand() % 450 - 150;
198
199 global_aridity = aridity;
200
201
202 for (y = 0; y < WORLD_SIDE_LEN; y++) {
203 for (x = 0; x < WORLD_SIDE_LEN; x++) {
204 int d2w_min = 2 * WORLD_SIDE_LEN * WORLD_SIDE_LEN;
205 int r;
206 int arid = aridity;
207 int alt0 = 0;
208
209 /* test against IS_RIVER to prevent terrible recursion */
210 if (IS_RIVER(x, y) || !GROUP_IS_BARE(MP_GROUP(x, y)))
211 continue;
212
213 for (yw = 0; yw < WORLD_SIDE_LEN; yw++) {
214 for (xw = 0; xw < WORLD_SIDE_LEN; xw++) {
215 int d2w;
216 if (!IS_RIVER(xw, yw))
217 continue;
218 d2w = (xw - x) * (xw - x) + (yw - y) * (yw - y);
219 if (d2w < d2w_min) {
220 d2w_min = d2w;
221 alt0 = ALT(xw,yw); // altitude of the river
222 }
223 /* TODO ? Store square of distance to river for each tile */
224 }
225 }
226
227 /* near river lower aridity */
228 if (aridity > 0) {
229 if (d2w_min < 5)
230 arid = aridity / 3;
231 else if (d2w_min < 17)
232 arid = (aridity * 2) / 3;
233 }
234 /* Altitude has same effect as distance */
235 if( alt_step == 0 ){
236 alt_step = 400; // TODO: Why can alt_step be zero here? Quick hack to prevent crash WolfgangB 2008-09-13
237 }
238 r = rand() % (d2w_min / 3 + 1) + arid +
239 abs((ALT(x,y) - alt0) * 19 / alt_step) + 3 * (ALT(x,y) * ALT(x,y)) /1000000 ;
240 ground[x][y].ecotable=r;
241 /* needed to setup quasi randome land. The flag is set below */
242 MP_INFO(x, y).flags |= FLAG_HAS_UNDERGROUND_WATER;
243 do_rand_ecology(x,y);
244 MP_POL(x, y) = 0;
245
246 /* preserve rivers, so that we can connect port later */
247 if (MP_TYPE(x, y) == CST_WATER) {
248 int navigable = MP_INFO(x, y).flags & FLAG_IS_RIVER;
249 set_mappoint(x, y, CST_WATER);
250 MP_INFO(x, y).flags |= navigable;
251 MP_INFO(x, y).flags |= FLAG_HAS_UNDERGROUND_WATER;
252 }
253 /* set undergroung water according to first random land setup */
254 if (MP_TYPE(x, y) == CST_DESERT) {
255 MP_INFO(x, y).flags &= (0xffffffff - FLAG_HAS_UNDERGROUND_WATER);
256 }
257 }
258 }
259 for (y = 0; y < WORLD_SIDE_LEN; y++)
260 for (x = 0; x < WORLD_SIDE_LEN; x++)
261 if (MP_TYPE(x, y) == CST_WATER)
262 MP_INFO(x, y).flags |= FLAG_HAS_UNDERGROUND_WATER;
263
264 connect_rivers();
265 }
266
267 /* ---------------------------------------------------------------------- *
268 * Private Functions
269 * ---------------------------------------------------------------------- */
initialize_tax_rates(void)270 static void initialize_tax_rates(void)
271 {
272 income_tax_rate = INCOME_TAX_RATE;
273 coal_tax_rate = COAL_TAX_RATE;
274 goods_tax_rate = GOODS_TAX_RATE;
275 dole_rate = DOLE_RATE;
276 transport_cost_rate = TRANSPORT_COST_RATE;
277 import_cost_rate = IM_PORT_COST_RATE;
278 }
279
init_mappoint_array(void)280 static void init_mappoint_array(void)
281 {
282 int x;
283 for (x = 0; x < WORLD_SIDE_LEN; x++) {
284 mappoint_array_x[x] = x;
285 mappoint_array_y[x] = x;
286 }
287 }
288
coal_reserve_setup(void)289 static void coal_reserve_setup(void)
290 {
291 int i, j, x, y, xx, yy;
292 for (i = 0; i < NUMOF_COAL_RESERVES / 5; i++) {
293 x = (rand() % (WORLD_SIDE_LEN - 12)) + 6;
294 y = (rand() % (WORLD_SIDE_LEN - 10)) + 6;
295 do {
296 xx = (rand() % 3) - 1;
297 yy = (rand() % 3) - 1;
298 }
299 while (xx == 0 && yy == 0);
300 for (j = 0; j < 5; j++) {
301 MP_INFO(x, y).coal_reserve += rand() % COAL_RESERVE_SIZE;
302 x += xx;
303 y += yy;
304 }
305 }
306 }
307
ore_reserve_setup(void)308 static void ore_reserve_setup(void)
309 {
310 int x, y;
311 for (y = 0; y < WORLD_SIDE_LEN; y++)
312 for (x = 0; x < WORLD_SIDE_LEN; x++)
313 MP_INFO(x, y).ore_reserve = ORE_RESERVE;
314 }
315
new_setup_river_ground(void)316 static void new_setup_river_ground(void)
317 {
318 const int NLOOP = 7;
319 const int SZ=128; // must be = 2^NLOOP
320 const int SHIFT = (SZ - WORLD_SIDE_LEN) / 2; // center the visible map in the big one
321 const float sigma = 3.5; // gaussian smoothing
322 const float ods2 = 1. / (2. * sigma * sigma);
323 const int mask_size = 11; // useless to be larger than 3*sigma && Must be < SHIFT
324 const float fract = 0.9;
325
326 float mat[2 * mask_size + 1][2 * mask_size + 1];
327 float g[SZ][SZ];
328 float tmp[SZ][SZ];
329 float min = 10000000000000000000.;
330 float norm;
331 int i,j,k,l,m,n,size,h;
332
333 // build gaussian mask
334 norm = 0;
335 for ( i = 0; i < 2 * mask_size + 1; i++) {
336 for ( j = 0; j < 2 * mask_size + 1; j++) {
337 float r2 = (i - mask_size) * (i - mask_size) + (j - mask_size) * (j - mask_size);
338 mat[i][j] = exp(-r2 * ods2);
339 norm += mat[i][j];
340 }
341 }
342 norm = 1. / norm;
343
344 // intialisation
345 #ifdef DEBUG
346 fprintf(stderr," mountainity = %i \n", global_mountainity);
347 #endif
348 h = ( rand() % 10 + rand() % 10 ) * global_mountainity / 20;
349 for (i = 0; i < SZ; i++) {
350 for (j = 0; j < SZ; j++) {
351 g[i][j]=h;
352 tmp[i][j]=0;
353 }
354 }
355
356 /* fractal iteration for height */
357 n = 1;
358 for (k = 1; k <= NLOOP; k++) {
359 n *= 2;
360 size = SZ / n;
361 // n x n block of size
362 for ( l = 0; l < n; l++ ) {
363 for ( m = 0; m < n; m++ ) {
364 // one block
365 h = int ( double((rand() % 10 + rand() % 10) * global_mountainity) * pow(fract,k));
366 for (i = 0 ; i < size; i++)
367 for (j = 0 ; j < size; j++)
368 g[l * size + i][ m * size + j ] += h;
369 }
370 }
371 }
372
373 //smooth is iterated to propagate a little the lowering of borders
374 for (n = 0; n < 2 ; n++) {
375 // apply the mask
376 for (i = mask_size; i < SZ - mask_size; i++)
377 for (j = mask_size; j < SZ - mask_size; j++) {
378 tmp[i][j] = 0;
379 for ( k = -mask_size; k <= mask_size; k++ )
380 for ( l = -mask_size; l <= mask_size; l++ )
381 tmp[i][j] += g[i + k][j - l] * mat[mask_size + k][mask_size + l];
382 }
383
384 for (i = mask_size; i< SZ - mask_size; i++)
385 for (j = mask_size; j< SZ - mask_size; j++)
386 g[i][j] = tmp[i][j] * norm;
387
388 if (n == 0) {
389 // find the lowest borders
390 // switch the map to have lowest borders in SE an SW in ISO view
391 float Nmin = 0;
392 float Smin = 0;
393 float Emin = 0;
394 float Wmin = 0;
395 for ( i = 0; i < WORLD_SIDE_LEN ; i++) {
396 Nmin += g[SHIFT + i][SHIFT];
397 Smin += g[SHIFT + i][SHIFT + WORLD_SIDE_LEN];
398 Wmin += g[SHIFT][SHIFT + i];
399 Emin += g[SHIFT + WORLD_SIDE_LEN][SHIFT + i];
400 }
401 if (Nmin < Smin) {
402 for ( i = 0; i < SZ; i++)
403 for ( j = 0; j < SZ; j++)
404 tmp[i][j] = g[i][SZ - j -1];
405
406 for ( i = 0; i < SZ; i++)
407 for ( j = 0; j < SZ; j++)
408 g[i][j] = tmp[i][j];
409 }
410
411 if (Wmin < Emin) {
412 for ( i = 0; i < SZ; i++)
413 for ( j = 0; j < SZ; j++)
414 tmp[i][j] = g[SZ - i -1][j];
415
416 for ( i = 0; i < SZ; i++)
417 for ( j = 0; j < SZ; j++)
418 g[i][j] = tmp[i][j];
419 }
420 }
421
422 // put the south and east border of the "big" map at the minimum visible height
423 for ( i = 0; i < WORLD_SIDE_LEN ; i++)
424 for ( j = 0; j < WORLD_SIDE_LEN ; j++)
425 if (g[SHIFT + i][SHIFT + j] < min)
426 min = g[SHIFT + i][SHIFT + j];
427
428 for ( i = 0; i < SZ; i++)
429 for (j = 0; j < (SZ - SHIFT - WORLD_SIDE_LEN); j++) {
430 g[i][SZ - 1 - j] = min; // south
431 g[SZ - 1 - j][i] = min; // east
432 }
433 }
434
435 alt_min = int (min);
436 alt_max = 0;
437 // pick our map in the fractal one
438 for ( i = 0; i < WORLD_SIDE_LEN; i++)
439 for ( j = 0; j < WORLD_SIDE_LEN; j++) {
440 ALT(i,j) = int (g[SHIFT + i][SHIFT + j]) - alt_min + 1;
441 if ( ALT(i,j) > alt_max)
442 alt_max = ALT(i,j);
443 }
444
445 // take visible value for maximum color dynamic
446 alt_min = 0; // visible alt_min is 1, we will use 0 for gray border
447 alt_step = (alt_max - alt_min)/10;
448
449 #ifdef DEBUG
450 fprintf(stderr," alt min = %i; max = %i\n", alt_min, alt_max);
451 #endif
452 new_setup_river();
453
454 }
new_setup_river(void)455 void new_setup_river(void)
456 {
457
458
459 int colx[WORLD_SIDE_LEN * WORLD_SIDE_LEN], coly[WORLD_SIDE_LEN * WORLD_SIDE_LEN];
460 int topx[WORLD_SIDE_LEN * WORLD_SIDE_LEN], topy[WORLD_SIDE_LEN * WORLD_SIDE_LEN];
461 int lakx[WORLD_SIDE_LEN * WORLD_SIDE_LEN], laky[WORLD_SIDE_LEN * WORLD_SIDE_LEN];
462
463 int i, j, c, t, l;
464
465
466 // Put lakes/seas in the lowest part of the map
467 for ( i = 0; i < WORLD_SIDE_LEN; i++)
468 for ( j = 0; j < WORLD_SIDE_LEN; j++)
469 if (ALT(i,j) < 2 * alt_step)
470 set_river_tile(i,j);
471
472 // Put the gray border (not visible) at alt_min, for easier rivers handling.
473 for ( i = 0; i < WORLD_SIDE_LEN; i++) {
474 ALT(i, 0) = alt_min;
475 ALT(i, WORLD_SIDE_LEN - 1) = alt_min;
476 ALT(0, i) = alt_min;
477 ALT(WORLD_SIDE_LEN - 1, i) = alt_min;
478 }
479
480 // Hessian = second order derivatives in visible map
481 // => know curvature, local max, min, saddle points and find col (mountain pass)
482 c = 0;
483 l = 0;
484 t = 0;
485 for ( i = 1; i < WORLD_SIDE_LEN - 1 ; i++)
486 for ( j = 1; j < WORLD_SIDE_LEN - 1 ; j++) {
487 float e1, e2;
488 float dx2, dy2, dxy, dyx, delta;
489
490 dx2 = float (ALT(i + 1,j) + ALT(i - 1,j) - 2 * ALT(i,j));
491 dy2 = float (ALT(i,j + 1) + ALT(i,j - 1) - 2 * ALT(i,j));
492 dxy = float ( (ALT(i+1 , j+1) + ALT(i-1, j-1) - ALT(i+1,j-1) - ALT(i-1,j+1)) * 0.25);
493 dyx = dxy;
494 // e1 e2 are the eigenvalues of Hessian, ie solutions of:
495 // X^2 - (dx2 + dy2).X + dx2.dy2 - dxy.dyx = 0 (wrt X)
496 delta = (dx2 + dy2)*(dx2 + dy2) - 4 * (dx2 * dy2 - dxy * dyx);
497 e1 = (dx2 + dy2) + sqrt(delta);
498 e2 = (dx2 + dy2) - sqrt(delta);
499
500 if (e1 * e2 < 0) {
501 // saddle point = mountain pass _IF_ tangent plane is _nearly_ horizontal !
502
503 /* Tangent plane has equation alpha.(x-x0) + beta.(y-y0) - z = 0
504 * Least square method to find alpha and beta considering 8 neighbours
505 * (just partial derivatives along x and y are not enought)
506 * After some calculus, alpha = (Sax.Syy - Say.Sxy)/(2.*(Sxx.Syy-Sxy*Syx))
507 * beta is symetrical wrt x <-> y
508 */
509 // precomputed terms for least square, on 8 neighbours
510 // (for i = 0; i < 8; i++) Sxy += (xi -x0) * (yi - y0);
511 // => Sxy = Syx = 0 :-)
512 // => simple result for alpha and beta.
513
514 const float Sxx = 6.; // Syy = Sxx
515 float alpha, beta;
516 float Sax = 0.;
517 float Say = 0.;
518 for (int n = 0; n < 8; n++) {
519 Sax += float ((ALT(i + di[n], j + dj[n]) - ALT(i,j)) * di[n]);
520 Say += float ((ALT(i + di[n], j + dj[n]) - ALT(i,j)) * dj[n]);
521 }
522 alpha = Sax / Sxx;
523 beta = Say / Sxx; // because Syy = Sxx
524
525 // Normal vector is (alpha, beta, -1)
526 // so plane is nearly horizontal if alpha^2 + beta^2 is "small"
527 if ( (alpha * alpha + beta * beta) < float(global_mountainity / 2) ) {
528 // mountain pass = col
529 colx[c] = i;
530 coly[c] = j;
531 c++;
532 //#define DEBUG_LAND
533 #ifdef DEBUG_LAND
534 fprintf(stderr," x %i, y %i, norm %f\n", i, j, alpha * alpha + beta * beta);
535 if (GROUP_IS_BARE(MP_GROUP(i,j)))
536 set_mappoint(i,j, CST_ROAD_LR);
537 //XXX AL1: why is there a segfault if we use CST_POWERL_H_D ?
538 #endif
539 }
540 } else if (e1 * e2 != 0) {
541 if ( e1 < 0) {
542 // local top
543 if ( ALT(i + 1,j) < ALT(i,j) && ALT(i - 1,j) < ALT(i,j) &&
544 ALT(i,j + 1) < ALT(i,j) && ALT(i,j - 1) < ALT(i,j) ) {
545
546 topx[t] = i;
547 topy[t] = j;
548 t++;
549 #ifdef DEBUG_LAND
550 if (GROUP_IS_BARE(MP_GROUP(i,j)))
551 set_mappoint(i,j, CST_FIRE_1);
552 #endif
553 }
554 } else {
555 // local min = potential lake => has water.
556 if ( ALT(i + 1,j) > ALT(i,j) && ALT(i - 1,j) > ALT(i,j) &&
557 ALT(i,j + 1) > ALT(i,j) && ALT(i,j - 1) > ALT(i,j) ) {
558
559 lakx[l] = i;
560 laky[l] = j;
561 l++;
562 if (GROUP_IS_BARE(MP_GROUP(i,j))) {
563 set_mappoint(i,j, CST_PARKLAND_LAKE);
564 MP_INFO(i,j).flags |= (FLAG_HAS_UNDERGROUND_WATER + FLAG_IS_RIVER);
565 }
566 }
567 }
568 } else {
569 // parabolic point
570 #ifdef DEBUG_LAND
571 if (GROUP_IS_BARE(MP_GROUP(i,j)))
572 set_mappoint(i,j, CST_RAIL_LR);
573 #endif
574 }
575
576
577 }
578
579 #ifdef DEBUG_LAND
580 fprintf(stderr," pass c = %i, cx = %i, cy = %i\n", c, colx[c - 1], coly[c -1]);
581 fprintf(stderr," top t = %i, tx = %i, ty = %i\n", t, topx[t-1], topy[t-1]);
582 fprintf(stderr," lak l = %i, lx = %i, ly = %i\n", l, lakx[l-1], laky[l-1]);
583 #endif
584
585 // put one river from each top.
586 sort_by_altitude(t, topx, topy);
587 for (i = 0; i < t; i++)
588 new_setup_one_river(i, c, colx, coly, t, topx, topy, l, lakx, laky);
589 }
590
set_river_tile(int i,int j)591 static void set_river_tile( int i, int j)
592 {
593 MP_TYPE(i, j) = CST_WATER;
594 MP_GROUP(i, j) = GROUP_WATER;
595 MP_INFO(i, j).flags |= FLAG_IS_RIVER;
596 }
597
sort_by_altitude(int n,int * tabx,int * taby)598 static void sort_by_altitude(int n, int *tabx, int *taby)
599 {
600 int tmp_x, tmp_y;
601 bool sorted = false;
602
603 // bubble sort. n is near 10 so ...
604 for (int i = 0; i < n && !sorted ; i++) {
605 sorted = true;
606 for (int j=1; j < n - i; j++)
607 if (ALT(tabx[j],taby[j]) < ALT(tabx[j-1], taby[j-1])) {
608 tmp_x = tabx[j-1];
609 tmp_y = taby[j-1];
610 tabx[j-1] = tabx[j];
611 taby[j-1] = taby[j];
612 tabx[j] = tmp_x;
613 taby[j] = tmp_y;
614 sorted = false;
615 }
616 /*fprintf(stderr," sorted = %i, n - i -1 = %i, ALT() = %i\n",
617 * sorted, n - i -1, ALT(tabx[n-i-1], taby[n -i -1]));
618 */
619 }
620 }
621
new_setup_one_river(int num_river,int c,int * colx,int * coly,int t,int * topx,int * topy,int l,int * lakx,int * laky)622 static void new_setup_one_river(int num_river, int c, int *colx, int *coly, int t, int *topx, int *topy, int l, int *lakx, int *laky)
623 {
624 int x, y, xx, yy, alt, alt_max;
625
626 /* find a place in altitude near top */
627 xx = topx[t - num_river] + (1 + rand() % 2) * di[rand() % 8];
628 yy = topy[t - num_river] + (1 + rand() % 2) * dj[rand() % 8];
629 if ( xx < 0 || xx >= WORLD_SIDE_LEN)
630 xx = topx[t - num_river];
631
632 if ( yy < 0 || yy >= WORLD_SIDE_LEN)
633 yy = topy[t - num_river];
634
635 set_river_tile(xx,yy);
636 alt_max = ALT(xx, yy);
637
638 /* follow most important slope and go downward */
639 do {
640 int m = 0;
641 x = xx;
642 y = yy;
643 alt = ALT(x,y);
644 for (int n = 0; n < 8; n++) {
645 if (ALT(x + di[n], y + dj[n]) < alt) {
646 xx = x + di[n];
647 yy = y + dj[n];
648 alt = ALT(xx, yy);
649 m = n;
650 }
651 }
652 set_river_tile(xx,yy);
653 if (m>3) {
654 // we did diagonal move, so we need to connect river
655 if (ALT(x + di[m], y) > ALT(x, y + dj[m]))
656 set_river_tile(x, y + dj[m]);
657 else
658 set_river_tile(x + di[m], y);
659 }
660 } while ( (xx != x) || (yy != y) );
661 // We are in a local minimum
662
663 if ( x == 0 || x == WORLD_SIDE_LEN - 1 || y == 0 || y == WORLD_SIDE_LEN - 1) {
664 // borders of the map are strictly the lowest points
665 return;
666 }
667
668 // TODO connect lakes to outside of the map
669 // make a small lake
670 sort_by_altitude(c, colx, coly);
671 sort_by_altitude(l, lakx, laky);
672
673 }
674
setup_river(void)675 static void setup_river(void)
676 {
677 int x, y, i, j;
678 int alt = 1; //lowest altitude in the map = surface of the river at mouth.
679 x = (1 * WORLD_SIDE_LEN + rand() % WORLD_SIDE_LEN) / 3;
680 y = WORLD_SIDE_LEN - 1;
681 ground[x][y].water_alt = alt; // 1 unit = 1 cm ,
682 //for rivers .water_alt = .altitude = surface of the water
683 //for "earth tile" .water_alt = alt of underground water
684 // .altitude = alt of the ground
685 // so .water_alt <= .altitude
686
687 /* Mouth of the river, 3 tiles wide, 6 + %12 long */
688 i = (rand() % 12) + 6;
689 for (j = 0; j < i; j++) {
690 x += (rand() % 3) - 1;
691 MP_TYPE(x, y) = CST_WATER;
692 MP_GROUP(x, y) = GROUP_WATER;
693 MP_INFO(x, y).flags |= FLAG_IS_RIVER;
694 ground[x][y].altitude=alt;
695
696 MP_TYPE(x + 1, y) = CST_WATER;
697 MP_GROUP(x + 1, y) = GROUP_WATER;
698 MP_INFO(x + 1, y).flags |= FLAG_IS_RIVER;
699 ground[x + 1][y].altitude=alt;
700
701 MP_TYPE(x - 1, y) = CST_WATER;
702 MP_GROUP(x - 1, y) = GROUP_WATER;
703 MP_INFO(x - 1, y).flags |= FLAG_IS_RIVER;
704 ground[x -1][y].altitude=alt;
705
706 y--;
707 alt += 1; // wide river, so very small slope
708 }
709
710 MP_TYPE(x, y) = CST_WATER;
711 MP_GROUP(x, y) = GROUP_WATER;
712 MP_INFO(x, y).flags |= FLAG_IS_RIVER;
713 ground[x][y].altitude=alt;
714
715 MP_TYPE(x + 1, y) = CST_WATER;
716 MP_GROUP(x + 1, y) = GROUP_WATER;
717 MP_INFO(x + 1, y).flags |= FLAG_IS_RIVER;
718 ground[x + 1][y].altitude=alt;
719
720 MP_TYPE(x - 1, y) = CST_WATER;
721 MP_GROUP(x - 1, y) = GROUP_WATER;
722 MP_INFO(x - 1, y).flags |= FLAG_IS_RIVER;
723 ground[x -1][y].altitude=alt;
724
725 alt += 2;
726
727 #ifdef DEBUG
728 fprintf(stderr," x= %d, y=%d, altitude = %d, mountainity = %d\n", x, y, alt, global_mountainity);
729 #endif
730 setup_river2(x - 1, y, -1, alt, global_mountainity); /* left tributary */
731 setup_river2(x + 1, y, 1, alt, global_mountainity); /* right tributary */
732 }
733
setup_river2(int x,int y,int d,int alt,int mountain)734 static void setup_river2(int x, int y, int d, int alt, int mountain)
735 {
736 int i, j, r;
737 i = (rand() % 55) + 15;
738 for (j = 0; j < i; j++) {
739 r = (rand() % 3) - 1 + (d * (rand() % 3));
740 if (r < -1) {
741 alt += rand() % (mountain / 10);
742 r = -1;
743 } else if (r > 1) {
744 alt += rand() % (mountain / 10);
745 r = 1;
746 }
747 x += r;
748 if (!GROUP_IS_BARE(MP_GROUP(x + (d + d), y))
749 || !GROUP_IS_BARE(MP_GROUP(x + (d + d + d), y)))
750 return;
751 if (x > 5 && x < WORLD_SIDE_LEN - 5) {
752 MP_TYPE(x, y) = CST_WATER;
753 MP_GROUP(x, y) = GROUP_WATER;
754 MP_INFO(x, y).flags |= FLAG_IS_RIVER;
755 ground[x][y].altitude = alt;
756 alt += rand() % (mountain / 10);
757
758 MP_TYPE(x + d, y) = CST_WATER;
759 MP_GROUP(x + d, y) = GROUP_WATER;
760 MP_INFO(x + d, y).flags |= FLAG_IS_RIVER;
761 ground[x + d][y].altitude = alt;
762 alt += rand () % (mountain / 10);
763 }
764 if (--y < 10 || x < 5 || x > WORLD_SIDE_LEN - 5)
765 break;
766 }
767 #ifdef DEBUG
768 fprintf(stderr," x= %d, y=%d, altitude = %d\n", x, y, alt);
769 #endif
770
771 if (y > 20) {
772 if (x > 5 && x < WORLD_SIDE_LEN - 5) {
773 #ifdef DEBUG
774 fprintf(stderr," x= %d, y=%d, altitude = %d\n", x, y, alt);
775 #endif
776 setup_river2(x, y, -1, alt, (mountain * 3)/2 );
777 }
778 if (x > 5 && x < WORLD_SIDE_LEN - 5) {
779 #ifdef DEBUG
780 fprintf(stderr," x= %d, y=%d, altitude = %d\n", x, y, alt);
781 #endif
782 setup_river2(x, y, 1, alt, (mountain *3)/2 );
783 }
784 }
785 }
786
setup_ground(void)787 static void setup_ground(void)
788 {
789 int x,y;
790 int hmax =0;
791 int tmp[WORLD_SIDE_LEN][WORLD_SIDE_LEN];
792
793 /* fill the corrects fields: ground[x][y).stuff, global_aridity, global_mountainity */
794 /* currently only dummy things in order to compile */
795
796 #define TMP(x,y) tmp[x][y]
797
798 for (x = 1; x < WORLD_SIDE_LEN - 1; x++) {
799 for (y = 1; y < WORLD_SIDE_LEN - 1; y++) {
800 if ( !IS_RIVER(x,y) ) {
801 ALT(x,y) = 0;
802 TMP(x,y) = 0;
803 } else {
804 ground[x][y].water_alt = ALT(x,y);
805 //shore is higher than water
806 ALT(x,y) += 10 + rand() % (global_mountainity/7);
807 TMP(x,y) = ALT(x,y);
808 if (ALT(x,y) >= hmax)
809 hmax = ALT(x,y);
810 }
811 }
812 }
813 #ifdef DEBUG
814 fprintf(stderr,"\n river max = %d\n\n", hmax);
815 hmax=0;
816 #endif
817
818 for (int i =0; i < 90; i++ ) {
819 int tot_cnt = 0;
820 for (x = 1; x < WORLD_SIDE_LEN - 1; x++) {
821 for (y = 1; y < WORLD_SIDE_LEN - 1; y++) {
822 if ( ALT(x,y) != 0 )
823 continue;
824 int count = 0;
825 int lmax = 0;
826 tot_cnt ++;
827 for ( int k = -1; k <= 1; k++ )
828 for ( int l = -1; l <= 1; l++)
829 if ( ALT(x+k, y+l) != 0 ) {
830 count ++;
831 if ( ALT(x+k, y+l) >= lmax )
832 lmax = ALT(x+k, y+l);
833 }
834
835 if (count != 0)
836 TMP(x,y) = lmax + rand () % (global_mountainity/3);
837
838 if (TMP(x,y) >= hmax)
839 hmax = TMP(x,y);
840 }
841 }
842 for (x = 1; x < WORLD_SIDE_LEN - 1; x++)
843 for (y = 1; y < WORLD_SIDE_LEN - 1; y++)
844 ALT(x,y)=TMP(x,y);
845
846 #ifdef DEBUG
847 if ( (i%5) == 1 )
848 fprintf(stderr," i= %2d, alt max = %d, tot_cnt = %d\n", i, hmax, tot_cnt);
849 #endif
850 }
851 alt_min = 2000000000;
852 alt_max = -alt_min;
853 for (x = 1; x < WORLD_SIDE_LEN - 1; x++)
854 for (y = 1; y < WORLD_SIDE_LEN - 1; y++) {
855 if (alt_min > ALT(x,y))
856 alt_min = ALT(x,y);
857 if (alt_max < ALT(x,y))
858 alt_max = ALT(x,y);
859 }
860 alt_step = (alt_max - alt_min) /10;
861
862 }
863
864
nullify_mappoint(int x,int y)865 static void nullify_mappoint(int x, int y)
866 {
867 MP_TYPE(x, y) = CST_GREEN;
868 MP_GROUP(x, y) = GROUP_BARE;
869 MP_SIZE(x, y) = 1;
870 MP_POL(x, y) = 0;
871 MP_INFO(x, y).population = 0;
872 MP_INFO(x, y).flags = 0;
873 MP_INFO(x, y).coal_reserve = 0;
874 MP_INFO(x, y).ore_reserve = 0;
875 MP_INFO(x, y).int_1 = 0;
876 MP_INFO(x, y).int_2 = 0;
877 MP_INFO(x, y).int_3 = 0;
878 MP_INFO(x, y).int_4 = 0;
879 MP_INFO(x, y).int_5 = 0;
880 MP_INFO(x, y).int_6 = 0;
881 MP_INFO(x, y).int_7 = 0;
882
883 ground[x][y].altitude = 0;
884 ground[x][y].ecotable = 0;
885 ground[x][y].wastes = 0;
886 ground[x][y].pollution = 0;
887 ground[x][y].water_alt = 0;
888 ground[x][y].water_pol = 0;
889 ground[x][y].water_wast = 0;
890 ground[x][y].water_next = 0;
891 ground[x][y].int1 = 0;
892 ground[x][y].int2 = 0;
893 ground[x][y].int3 = 0;
894 ground[x][y].int4 = 0;
895
896 }
897
random_start(int * originx,int * originy)898 static void random_start(int *originx, int *originy)
899 {
900 int x, y, xx, yy, flag, watchdog;
901
902 /* first find a place that has some water. */
903 watchdog = 90; /* if too many tries, random placement. */
904 do {
905 do {
906 xx = rand() % (WORLD_SIDE_LEN - 25);
907 yy = rand() % (WORLD_SIDE_LEN - 25);
908 flag = 0;
909 for (y = yy + 2; y < yy + 23; y++)
910 for (x = xx + 2; x < xx + 23; x++)
911 if (IS_RIVER(x, y)) {
912 flag = 1;
913 x = xx + 23; /* break out of loop */
914 y = yy + 23; /* break out of loop */
915 }
916 } while (flag == 0 && (--watchdog) > 1);
917 for (y = yy + 4; y < yy + 22; y++)
918 for (x = xx + 4; x < xx + 22; x++)
919 /* Don't put the village on a river, but don't care of
920 * isolated random water tiles putted by setup_land
921 */
922 if (IS_RIVER(x, y)) {
923 flag = 0;
924 x = xx + 22; /* break out of loop */
925 y = yy + 22; /* break out of loop */
926 }
927 } while (flag == 0 && (--watchdog) > 1);
928 #ifdef DEBUG
929 fprintf(stderr, "random village watchdog = %i\n", watchdog);
930 #endif
931
932 /* These are going to be the main_screen_origin? vars */
933 *originx = xx;
934 *originy = yy;
935
936 /* Draw the start scene. */
937 set_mappoint(xx + 5, yy + 5, CST_FARM_O0);
938 /* The first two farms have more underground water */
939 for (int i = 0; i < MP_SIZE(xx + 5, yy + 5); i++)
940 for (int j = 0; j < MP_SIZE(xx + 5, yy + 5); j++)
941 if (!HAS_UGWATER(xx + 5 + i, yy + 5 + j) && (rand() % 2))
942 MP_INFO(xx + 5 + i, yy + 5 + j).flags |= FLAG_HAS_UNDERGROUND_WATER;
943
944 set_mappoint(xx + 9, yy + 6, CST_RESIDENCE_ML);
945 MP_INFO(xx + 9, yy + 6).population = 50;
946 MP_INFO(xx + 9, yy + 6).flags |= (FLAG_FED + FLAG_EMPLOYED + FLAG_WATERWELL_COVER);
947
948 set_mappoint(xx + 9, yy + 9, CST_POTTERY_0);
949
950 set_mappoint(xx + 16, yy + 9, CST_WATERWELL);
951 do_waterwell_cover(xx + 16, yy + 9);
952
953 set_mappoint(xx + 14, yy + 6, CST_RESIDENCE_ML);
954 MP_INFO(xx + 14, yy + 6).population = 50;
955 MP_INFO(xx + 14, yy + 6).flags |= (FLAG_FED + FLAG_EMPLOYED + FLAG_WATERWELL_COVER);
956
957 /* The first two farms have more underground water */
958 set_mappoint(xx + 17, yy + 5, CST_FARM_O0);
959 for (int i = 0; i < MP_SIZE(xx + 17, yy + 5); i++)
960 for (int j = 0; j < MP_SIZE(xx + 17, yy + 5); j++)
961 if (!HAS_UGWATER(xx + 17 + i, yy + 5 + j) && (rand() % 2))
962 MP_INFO(xx + 17 + i, yy + 5 + j).flags |= FLAG_HAS_UNDERGROUND_WATER;
963
964 set_mappoint(xx + 14, yy + 9, CST_MARKET_EMPTY);
965 marketx[numof_markets] = xx + 14;
966 markety[numof_markets] = yy + 9;
967 numof_markets++;
968 /* Bootstrap markets with some stuff. */
969 MP_INFO(xx + 14, yy + 9).int_1 = 2000;
970 MP_INFO(xx + 14, yy + 9).int_2 = 10000;
971 MP_INFO(xx + 14, yy + 9).int_3 = 100;
972 MP_INFO(xx + 14, yy + 9).int_5 = 10000;
973 MP_INFO(xx + 14, yy + 9).flags
974 |= (FLAG_MB_FOOD + FLAG_MS_FOOD + FLAG_MB_JOBS
975 + FLAG_MS_JOBS + FLAG_MB_COAL + FLAG_MS_COAL + FLAG_MB_ORE
976 + FLAG_MS_ORE + FLAG_MB_GOODS + FLAG_MS_GOODS + FLAG_MB_STEEL + FLAG_MS_STEEL);
977
978 /* build tracks */
979 for (x = 2; x < 23; x++) {
980 set_mappoint(xx + x, yy + 11, CST_TRACK_LR);
981 MP_INFO(xx + x, yy + 11).flags |= FLAG_IS_TRANSPORT;
982 }
983 for (y = 2; y < 11; y++) {
984 set_mappoint(xx + 13, yy + y, CST_TRACK_LR);
985 MP_INFO(xx + 13, yy + y).flags |= FLAG_IS_TRANSPORT;
986 }
987 for (y = 12; y < 23; y++) {
988 set_mappoint(xx + 15, yy + y, CST_TRACK_LR);
989 MP_INFO(xx + 15, yy + y).flags |= FLAG_IS_TRANSPORT;
990 }
991
992 /* build communes */
993 set_mappoint(xx + 6, yy + 12, CST_COMMUNE_1);
994 set_mappoint(xx + 6, yy + 17, CST_COMMUNE_1);
995 set_mappoint(xx + 11, yy + 12, CST_COMMUNE_1);
996 set_mappoint(xx + 11, yy + 17, CST_COMMUNE_1);
997 set_mappoint(xx + 16, yy + 12, CST_COMMUNE_1);
998 set_mappoint(xx + 16, yy + 17, CST_COMMUNE_1);
999 }
1000
1001
1002