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