home *** CD-ROM | disk | FTP | other *** search
/ Amiga Times / AmigaTimes.iso / spiele / FreeCiv / src / freeciv-1.7.0 / server / mapgen.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-10-06  |  29.4 KB  |  1,058 lines

  1. /********************************************************************** 
  2.  Freeciv - Copyright (C) 1996 - A Kjeldberg, L Gregersen, P Unold
  3.    This program is free software; you can redistribute it and/or modify
  4.    it under the terms of the GNU General Public License as published by
  5.    the Free Software Foundation; either version 2, or (at your option)
  6.    any later version.
  7.  
  8.    This program is distributed in the hope that it will be useful,
  9.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  10.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  11.    GNU General Public License for more details.
  12. ***********************************************************************/
  13. #include <math.h>
  14. #include <stdio.h>
  15. #include <stdlib.h>
  16. #include <time.h>
  17. #include <sys/time.h>
  18.  
  19. #include <map.h>
  20. #include <game.h>
  21. #include <shared.h>
  22.  
  23. #include <aitools.h>
  24. void make_huts(int number);
  25. void mapgenerator1(void);
  26. void mapgenerator2(void);
  27. void spread(int spr);
  28. void smooth_map();
  29. void add_height(int x,int y, int radius);
  30. void adjust_map(int minval);
  31. void init_workmap(void);
  32. int *height_map;
  33.  
  34. int maxval=0;
  35. int forests=0;
  36.  
  37. /**************************************************************************
  38.  Just a wrapper function off the height_map, returns the height at x,y
  39. **************************************************************************/
  40.  
  41. int full_map(int x, int y)
  42. {
  43.   return height_map[y*map.xsize+x];
  44. }
  45.  
  46. /**************************************************************************
  47.  is this y coordinate in the arctic zone?
  48. **************************************************************************/
  49. int arctic_y(int y)
  50. {
  51.   return (y < map.ysize*0.1 || y > map.ysize*0.9);
  52. }
  53.  
  54. /**************************************************************************
  55.  Is this y coordinate in the desert zone?
  56. **************************************************************************/
  57. int desert_y(int y)
  58. {
  59.   return (y > map.ysize*0.4  &&  y < map.ysize*0.6);
  60. }
  61.  
  62. /**************************************************************************
  63.   make_mountains will convert all squares that is heigher than thill to
  64.   mountains and hills, notice that thill will be adjusted according to
  65.   the map.mountains value, so increase map.mountains and you'll get more 
  66.   hills and mountains, and vice versa  
  67. **************************************************************************/
  68.  
  69. void make_mountains(int thill)
  70. {
  71.   int x,y;
  72.   int mount;
  73.   int j;
  74.   for (j=0;j<10;j++) {
  75.     mount=0;
  76.     for (y=0;y<map.ysize;y++) 
  77.       for (x=0;x<map.xsize;x++) 
  78.     if (full_map(x, y)>thill) 
  79.         mount++;
  80.     if (mount<((map.xsize*map.ysize)*map.mountains)/1000) 
  81.       thill*=0.95;
  82.     else 
  83.       thill*=1.05;
  84.   }
  85.   
  86.   for (y=0;y<map.ysize;y++) 
  87.     for (x=0;x<map.xsize;x++) 
  88.       if (full_map(x, y)>thill &&map_get_terrain(x,y)!=T_OCEAN) { 
  89.     if (myrand(100)>75) 
  90.       map_set_terrain(x, y, T_MOUNTAINS);
  91.     else if (myrand(100)>25) 
  92.       map_set_terrain(x, y, T_HILLS);
  93.       }
  94. }
  95.  
  96. /**************************************************************************
  97.  add arctic and tundra squares in the arctic zone. 
  98.  (that is the top 10%, and low 10% of the map)
  99. **************************************************************************/
  100. void make_polar()
  101. {
  102.   int y,x;
  103.  
  104.   for (y=0;y<map.ysize*0.1;y++) {
  105.     for (x=0;x<map.xsize;x++) {
  106.       if ((full_map(x, y)+(map.ysize*0.1-y*25)>myrand(maxval) && map_get_terrain(x,y)==T_GRASSLAND) || y==0) { 
  107.     if (y<2)
  108.       map_set_terrain(x, y, T_ARCTIC);
  109.     else
  110.       map_set_terrain(x, y, T_TUNDRA);
  111.       
  112.       } 
  113.     }
  114.   }
  115.   for (y=map.ysize*0.9;y<map.ysize;y++) {
  116.     for (x=0;x<map.xsize;x++) {
  117.       if ((full_map(x, y)+(map.ysize*0.1-(map.ysize-y)*25)>myrand(maxval) && map_get_terrain(x, y)==T_GRASSLAND) || y==map.ysize-1) {
  118.     if (y>map.ysize-3)
  119.       map_set_terrain(x, y, T_ARCTIC);
  120.     else
  121.       map_set_terrain(x, y, T_TUNDRA);
  122.       }
  123.     }
  124.   }
  125. }
  126.  
  127. /**************************************************************************
  128.   recursively generate deserts, i use the heights of the map, to make the
  129.   desert unregulary shaped, diff is the recursion stopper, and will be reduced
  130.   more if desert wants to grow in the y direction, so we end up with 
  131.   "wide" deserts. 
  132. **************************************************************************/
  133. void make_desert(int x, int y, int height, int diff) 
  134. {
  135.   if (abs(full_map(x, y)-height)<diff && map_get_terrain(x, y)==T_GRASSLAND) {
  136.     map_set_terrain(x, y, T_DESERT);
  137.     make_desert(x-1,y, height, diff-1);
  138.     make_desert(x,y-1, height, diff-3);
  139.     make_desert(x+1,y, height, diff-1);
  140.     make_desert(x,y+1, height, diff-3);
  141.   }
  142. }
  143.  
  144. /**************************************************************************
  145.   a recursive function that adds forest to the current location and try
  146.   to spread out to the neighbours, it's called from make_forests until
  147.   enough forest has been planted. diff is again the block function.
  148.   if we're close to equator it will with 50% chance generate jungle instead
  149. **************************************************************************/
  150. void make_forest(int x, int y, int height, int diff)
  151. {
  152.   if (x==0 || x==map.xsize-1 ||y==0 || y==map.ysize-1)
  153.     return;
  154.  
  155.   if (map_get_terrain(x, y)==T_GRASSLAND) {
  156.     if (y>map.ysize*0.42 && y<map.ysize*0.58 && myrand(100)>50)
  157.       map_set_terrain(x, y, T_JUNGLE);
  158.     else 
  159.       map_set_terrain(x, y, T_FOREST);
  160.       if (abs(full_map(x, y)-height)<diff) {
  161.     if (myrand(10)>5) make_forest(x-1,y, height, diff-5);
  162.     if (myrand(10)>5) make_forest(x,y-1, height, diff-5);
  163.     if (myrand(10)>5) make_forest(x+1,y, height, diff-5);
  164.     if (myrand(10)>5) make_forest(x,y+1, height, diff-5);
  165.       }
  166.     forests++;
  167.   }
  168. }
  169.  
  170. /**************************************************************************
  171.   makeforest calls make_forest with random grassland locations until there
  172.   has been made enough forests. (the map.forestsize value controls this) 
  173. **************************************************************************/
  174. void make_forests()
  175. {
  176.   int x,y;
  177.   int forestsize=25;
  178.   forestsize=(map.xsize*map.ysize*map.forestsize)/1000;
  179.    do {
  180.     x=myrand(map.xsize);
  181.     y=myrand(map.ysize);
  182.     if (map_get_terrain(x, y)==T_GRASSLAND) {
  183.       make_forest(x,y, full_map(x, y), 25);
  184.     }
  185.     if (myrand(100)>75) {
  186.       y=(myrand((int)(map.ysize*0.2)))+map.ysize*0.4;
  187.       x=myrand(map.xsize);
  188.       if (map_get_terrain(x, y)==T_GRASSLAND) {
  189.     make_forest(x,y, full_map(x, y), 25);
  190.       }
  191.     }
  192.   } while (forests<forestsize);
  193. }
  194.  
  195. /**************************************************************************
  196.   swamps, is placed on low lying locations, that will typically be close to
  197.   the shoreline. They're put at random (where there is grassland)
  198.   and with 50% chance each of it's neighbour squares will be converted to
  199.   swamp aswell
  200. **************************************************************************/
  201. void make_swamps()
  202. {
  203.   int x,y,i;
  204.   int forever=0;
  205.   for (i=0;i<map.swampsize;) {
  206.     forever++;
  207.     if (forever>1000) return;
  208.     y=myrand(map.ysize);
  209.     x=myrand(map.xsize);
  210.     if (map_get_terrain(x, y)==T_GRASSLAND && full_map(x, y)<(maxval*60)/100) {
  211.       map_set_terrain(x, y, T_SWAMP);
  212.       if (myrand(10)>5 && map_get_terrain(x-1, y)!=T_OCEAN) 
  213.     map_set_terrain(x-1,y, T_SWAMP);
  214.       if (myrand(10)>5 && map_get_terrain(x+1, y)!=T_OCEAN) 
  215.     map_set_terrain(x+1,y, T_SWAMP);
  216.       if (myrand(10)>5 && map_get_terrain(x, y-1)!=T_OCEAN) 
  217.     map_set_terrain(x,y-1, T_SWAMP);
  218.       if (myrand(10)>5 && map_get_terrain(x, y+1)!=T_OCEAN) 
  219.     map_set_terrain(x, y+1, T_SWAMP);
  220.       i++;
  221.     }
  222.   }
  223. }
  224.  
  225. /*************************************************************************
  226.   make_deserts calls make_desert until we have enough deserts actually
  227.   there is no map setting for how many we want, what happends is that
  228.   we choose a random coordinate in the equator zone and if it's a grassland
  229.   square we call make_desert with this coordinate, we try this 1000 times
  230. **************************************************************************/
  231. void make_deserts()
  232. {
  233.   int x,y,i,j;
  234.   i=map.deserts;
  235.   j=0;
  236.   while (i && j<1000) {
  237.     j++;
  238.     y=myrand((int)(map.ysize*0.1))+map.ysize*0.45;
  239.     x=myrand(map.xsize);
  240.     if (map_get_terrain(x, y)==T_GRASSLAND) {
  241.       make_desert(x,y, full_map(x, y), 50);
  242.       i--;
  243.     }
  244.   }
  245. }
  246. /*************************************************************************
  247.  this recursive function try to make some decent rivers, that run towards
  248.  the ocean, it does this by following a descending path on the map spiced
  249.  with a bit of chance, if it fails to reach the ocean it rolls back.
  250. **************************************************************************/
  251.  
  252. int make_river(int x,int y) 
  253. {
  254.   int mini=10000;
  255.   int mp;
  256.   int res=0;
  257.   mp=-1;
  258.   if (x==0 || x==map.xsize-1 ||y==0 || y==map.ysize-1)
  259.     return 0;
  260.   if (map_get_terrain(x, y)==T_OCEAN)
  261.     return 1;
  262.   if (is_at_coast(x, y)) {
  263.     map_set_terrain(x, y, T_RIVER);
  264.     return 1;
  265.   }
  266.  
  267.   if (map_get_terrain(x, y)==T_RIVER )
  268.     return 0;
  269.   map_set_terrain(x, y, map_get_terrain(x,y)+16);
  270.   if (full_map(x, y-1)<mini+myrand(10) && map_get_terrain(x, y)<16) {
  271.     mini=full_map(x, y-1);
  272.     mp=0;
  273.   }
  274.   
  275.   if (full_map(x, y+1)<mini+myrand(11) && map_get_terrain(x, y+1)<16) {
  276.     mini=full_map(x, y+1);
  277.     mp=1;
  278.   }
  279.   if (full_map(x+1, y)<mini+myrand(12) && map_get_terrain(x+1, y)<16) {
  280.     mini=full_map(x+1, y);
  281.     mp=2;
  282.   }
  283.   if (full_map(x-1, y)<mini+myrand(13) && map_get_terrain(x-1, y)<16) {
  284.     mp=3;
  285.   }
  286.   if (mp==-1) {
  287.     map_set_terrain(x, y, map_get_terrain(x, y)-16);
  288.     return 0;
  289.   }
  290.   switch(mp) {
  291.    case 0:
  292.     res=make_river(x,y-1);
  293.     break;
  294.    case 1:
  295.     res=make_river(x,y+1);
  296.     break;
  297.    case 2:
  298.     res=make_river(x+1,y);
  299.     break;
  300.    case 3:
  301.     res=make_river(x-1,y);
  302.     break;
  303.   }
  304.   
  305.   if (res) {
  306.     map_set_terrain(x, y, T_RIVER);
  307.   }
  308.   else
  309.     map_set_terrain(x, y, map_get_terrain(x ,y) - 16);
  310.   return res;
  311. }
  312.  
  313. /**************************************************************************
  314.   calls make_river until we have enough river tiles (map.riverlength), 
  315.   to stop this potentially never ending loop a miss counts as a river of 
  316.   length one 
  317. **************************************************************************/
  318. void make_rivers()
  319. {
  320.   int x,y,i;
  321.   i=0;
  322.  
  323.   while (i<map.riverlength) {
  324.     y=myrand(map.ysize);
  325.     x=myrand(map.xsize);
  326.     if (map_get_terrain(x, y)==T_OCEAN ||map_get_terrain(x, y)==T_RIVER)
  327.       continue;
  328.     i+=make_river(x,y);
  329.     i+=1;
  330.   }
  331. }
  332.  
  333. /**************************************************************************
  334.   make_plains converts 50% of the remaining grassland to plains, this should
  335.   maybe be lowered to 30% or done in batches, like the swamps?
  336. **************************************************************************/
  337. void make_plains()
  338. {
  339.   int x,y;
  340.   for (y=0;y<map.ysize;y++)
  341.     for (x=0;x<map.xsize;x++)
  342.       if (map_get_terrain(x, y)==T_GRASSLAND && myrand(100)>50)
  343.     map_set_terrain(x, y, T_PLAINS);
  344. }
  345.  
  346. /**************************************************************************
  347.   we want the map to be sailable east-west at least at north and south pole 
  348.   and make it a bit jagged at the edge as well.
  349.   So this procedure converts the second line and the second last line to
  350.   ocean, and 50% of the 3rd and 3rd last line to ocean. 
  351. **************************************************************************/
  352. void make_passable()
  353. {
  354.   int x;
  355.   
  356.   for (x=0;x<map.xsize;x++) {
  357.     map_set_terrain(x, 2, T_OCEAN);
  358.     if (myrand(100)>50) map_set_terrain(x,1,T_OCEAN);
  359.     if (myrand(100)>50) map_set_terrain(x,3,T_OCEAN);
  360.     map_set_terrain(x, map.ysize-3, T_OCEAN);
  361.     if (myrand(100)>50) map_set_terrain(x,map.ysize-2,T_OCEAN);
  362.     if (myrand(100)>50) map_set_terrain(x,map.ysize-4,T_OCEAN);
  363.   } 
  364.   
  365. }
  366.  
  367. /**************************************************************************
  368.   we don't want huge areas of grass/plains, 
  369.  so we put in a hill here and there, where it gets too 'clean' 
  370. **************************************************************************/
  371.  
  372. void make_fair()
  373. {
  374.   int x,y;
  375.   for (y=2;y<map.ysize-3;y++) 
  376.     for (x=0;x<map.xsize;x++) {
  377.       if (terrain_is_clean(x,y)) {
  378.     map_set_terrain(x,y, T_HILLS);
  379.     if (myrand(100)>66 && map_get_terrain(x-1, y)!=T_OCEAN)
  380.       map_set_terrain(x-1,y, T_HILLS);
  381.     if (myrand(100)>66 && map_get_terrain(x+1, y)!=T_OCEAN)
  382.       map_set_terrain(x+1,y, T_HILLS);
  383.     if (myrand(100)>66 && map_get_terrain(x, y-1)!=T_OCEAN) 
  384.       map_set_terrain(x,y-1, T_HILLS);
  385.     if (myrand(100)>66 && map_get_terrain(x, y+1)!=T_OCEAN) 
  386.       map_set_terrain(x,y+1, T_HILLS);
  387.       }
  388.     }
  389. }
  390.  
  391. /**************************************************************************
  392.   make land simply does it all based on a generated heightmap
  393.   1) with map.landpercent it generates a ocean/grassland map 
  394.   2) it then calls the above functions to generate the different terrains
  395. **************************************************************************/
  396. void make_land()
  397. {
  398.   int x, y;
  399.   int tres=(maxval*map.landpercent)/100;
  400.   int count=0;
  401.   int total=(map.xsize*map.ysize*map.landpercent)/100;
  402.   int forever=0;
  403.   do {
  404.     forever++;
  405.     if (forever>50) break; /* loop elimination */
  406.     count=0;
  407.     for (y=0;y<map.ysize;y++)
  408.       for (x=0;x<map.xsize;x++) {
  409.     if (full_map(x, y)<tres)
  410.       map_set_terrain(x, y, T_OCEAN);
  411.     else {
  412.       map_set_terrain(x, y, T_GRASSLAND);
  413.       count++;
  414.     }
  415.       }
  416.     if (count>total)
  417.       tres=tres*1.1;
  418.     else
  419.       tres=tres*0.9;
  420.   } while (abs(total-count)> maxval/40);
  421.   make_passable();
  422.   make_mountains(maxval*0.8);
  423.   make_forests();
  424.   make_swamps();
  425.   make_deserts();
  426.   make_rivers(); 
  427.   make_plains();
  428.   make_polar();
  429.   make_fair();
  430. }
  431.  
  432. /**************************************************************************
  433.  returns if this is a 1x1 island (which we remove)
  434. **************************************************************************/
  435. int tiny_island(int x, int y) 
  436. {
  437.   if (map_get_terrain(x,y)==T_OCEAN) return 0;
  438.   if (map_get_terrain(x-1,y)!=T_OCEAN) return 0;
  439.   if (map_get_terrain(x+1,y)!=T_OCEAN) return 0;
  440.   if (map_get_terrain(x,y-1)!=T_OCEAN) return 0;
  441.   if (map_get_terrain(x,y+1)!=T_OCEAN) return 0;
  442.   return 1;
  443. }
  444.  
  445. /**************************************************************************
  446.   removes all 1x1 islands
  447. **************************************************************************/
  448. void filter_land()
  449. {
  450.   int x,y;
  451.   
  452.   for (y=0;y<map.ysize;y++)
  453.     for (x=0;x<map.xsize;x++) {
  454.       /* Remove Islands that is only 1x1 */
  455.       if (tiny_island(x,y)) {
  456.     map_set_terrain(x,y, T_OCEAN);
  457.       }
  458.     }
  459. }
  460.  
  461. /**************************************************************************
  462.  a basic floodfill used to give every square a continent number, so we later
  463.  on can ask which continent a given square belongs to.
  464. **************************************************************************/
  465. void flood_fill(int x, int y, int nr)
  466. {
  467.   if (x==-1) x=map.xsize-1;
  468.   if (x==map.xsize) x=0;
  469.   if (y==-1) return;
  470.   if (y==map.ysize) return;
  471.   if (map_get_continent(x, y)) 
  472.     return;
  473.  
  474.   if (map_get_terrain(x, y)==T_OCEAN) return;
  475.   islands[nr].goodies+=is_good_tile(x, y);
  476.   map_set_continent(x, y, nr);
  477.   flood_fill(x-1,y,nr);
  478.   flood_fill(x-1,y+1,nr);
  479.   flood_fill(x-1,y-1,nr);
  480.   flood_fill(x,y-1,nr);
  481.   flood_fill(x,y+1,nr);
  482.   flood_fill(x+1,y-1,nr);
  483.   flood_fill(x+1,y,nr);
  484.   flood_fill(x+1,y+1,nr);
  485. }
  486.  
  487. /**************************************************************************
  488.  find start points for continents and call flood_fill for all of them 
  489. **************************************************************************/
  490. void flood_it(int loaded)
  491. {
  492.   int x,y;
  493.   int good;
  494.   int isles=3;
  495.  
  496.   for (y=0;y<map.ysize;y++)
  497.     for (x=0;x<map.xsize;x++)
  498.       map_set_continent(x, y, 0);
  499.   flood_fill(0,0,1);                   /* want to know where the rim is */
  500.   flood_fill(0,map.ysize-1,2);         /* ... */
  501.   for (y=0;y<map.ysize;y++)
  502.     for (x=0;x<map.xsize;x++) 
  503.       if (!map_get_continent(x, y) && map_get_terrain(x, y)!=T_OCEAN) {
  504.     islands[isles].goodies=0;
  505.     flood_fill(x,y,isles);
  506.     islands[isles].starters=0;
  507.     islands[isles].x=x;
  508.     islands[isles].y=y;
  509.     isles++;
  510.       }
  511.  
  512. /* fnord -- Syela */
  513.  
  514.   if (loaded)                 /* only make the continents if loaded game*/
  515.     return;
  516.  
  517.   good=0;
  518.   for (x=0;x<isles;x++) {
  519.     if (islands[x].goodies>(60-game.nplayers*3)) 
  520.       good+=islands[x].goodies;
  521.   }
  522.   for (x=0;x<isles;x++) {
  523.     if (islands[x].goodies>(60-game.nplayers*3)) {
  524.       islands[x].starters=1+islands[x].goodies/(good/game.nplayers);
  525.     } 
  526.   }
  527. }
  528. /**************************************************************************
  529.   where do the different races start on the map? well this function tries
  530.   to spread them out on the different islands.
  531. **************************************************************************/
  532.  
  533. void choose_start_positions(void)
  534. {
  535.   int nr=0;
  536.   int dist=40;
  537.   int x, y, j=0;
  538.  
  539.   while (nr<game.nplayers) {
  540.     x=myrand(map.xsize);
  541.     y=myrand(map.ysize);
  542.     if (islands[(int)map_get_continent(x, y)].starters) {
  543.       j++;
  544.       if (!is_starter_close(x, y, nr, dist)) {
  545.     islands[(int)map_get_continent(x, y)].starters--;
  546.     map.start_positions[nr].x=x;
  547.     map.start_positions[nr].y=y;
  548.     nr++;
  549.       }
  550.       if (j>500) {
  551.       dist--;
  552.     j=0;
  553.       } 
  554.     }
  555.   } 
  556. }
  557.  
  558. /**************************************************************************
  559.   we have 2 ways of generation a map, 
  560.   1) generates normal maps like in civ
  561.   2) generates 7 equally sized and with equally number of specials islands
  562. **************************************************************************/
  563. void map_fractal_generate(void)
  564. {
  565.   if (map.seed==0)
  566.     mysrand(time(NULL));
  567.   else 
  568.     mysrand(map.seed);
  569.   
  570.   init_workmap();
  571.  
  572.   if (map.generator == 1 || (map.xsize < 80 || map.ysize < 50)) {
  573.     mapgenerator1();
  574.   } else {
  575.     mapgenerator2();
  576.   }
  577.  
  578.  
  579.   filter_land();
  580.   add_specials(map.riches); /* hvor mange promiller specials oensker vi*/
  581.   
  582.   /* print_map(); */
  583.   make_huts(map.huts);
  584. }
  585.  
  586. /**************************************************************************
  587.   this next block is only for debug purposes and could be removed
  588. **************************************************************************/
  589. char terrai_chars[] = {'a','D', 'F', 'g', 'h', 'j', 'M', '*', 'p', 'R', '%','T', 'U' };
  590.  
  591. void print_map(void)
  592. {
  593.   int x,y;
  594.   for (y=0;y<map.ysize;y++) {
  595.     for (x=0;x<map.xsize;x++) {
  596.       putchar(terrai_chars[map_get_terrain(x, y)]);
  597.     }
  598.     puts("");
  599.   }
  600. }
  601.  
  602. void print_hmap(void)
  603. {
  604.   int x,y;
  605.   for (y=0;y<20;y++) {
  606.     for (x=0;x<20;x++) {
  607.       putchar(terrai_chars[height_map[y*20+x]]);
  608.     }
  609.     puts("");
  610.   }
  611. }
  612.  
  613. /**************************************************************************
  614.   since the generated map will always have a positive number as minimum height
  615.   i reduce the height so the lowest height is zero, this makes calculations
  616.   easier
  617. **************************************************************************/
  618. void adjust_map(int minval)
  619. {
  620.   int x,y;
  621.   for (y=0;y<map.ysize;y++) {
  622.     for (x=0;x<map.xsize;x++) {
  623.       height_map[y*map.xsize+x]-=minval;
  624.     }
  625.   }
  626. }
  627.  
  628. /**************************************************************************
  629.   this function will create a map.
  630. **************************************************************************/
  631. void init_workmap(void)
  632. {
  633.   int x,y;
  634.   if(!(map.tiles=(struct tile*)malloc(map.xsize*map.ysize*
  635.                       sizeof(struct tile)))) {
  636.     fprintf(stderr, "malloc failed in mapgen\n");
  637.     exit(1);
  638.   }
  639.   for(y=0;y<map.ysize;y++)
  640.      for(x=0;x<map.xsize;x++)
  641.        tile_init(map_get_tile(x, y));
  642. }
  643.  
  644. /*****************************************************************************
  645.   The rest of this file is only used in  mapgenerator 2, and should not be 
  646.   confused with the previous stuff.
  647. *****************************************************************************/
  648. int ymax = 20;
  649. int xmax = 20;
  650. int size = 100;
  651. int xs; 
  652. int ys;
  653. int dx;
  654. int dy;
  655.  
  656. /**************************************************************************
  657.   a wrapper
  658. **************************************************************************/
  659. int mini_map(int x, int y)
  660. {
  661.   return height_map[y*xmax + x];
  662. }
  663.  
  664. /**************************************************************************
  665.   fill an island with different types of terrain,
  666. **************************************************************************/
  667. void fillisland(int xp, int yp)
  668. {
  669.   int mountains = 3;
  670.   int hills = 7;
  671.   int forest = 10;
  672.   int mixed;
  673.   int x,y;
  674.   int dir;
  675.   mixed = 5 + size;
  676.   if (mixed < 0) 
  677.     mixed = 0;
  678.   x = xp + xmax / 2;
  679.   y = yp + ymax / 2;
  680.  
  681.   dir = myrand(4);
  682.   map_set_terrain(x,y, T_RIVER);
  683.   while (!is_terrain_near_tile(x, y, T_OCEAN)) {
  684.     switch (dir) {
  685.     case 0:
  686.       x--;
  687.       break;
  688.     case 1:
  689.       y--;
  690.       break;
  691.     case 2:
  692.       x++;
  693.       break;
  694.     case 3:
  695.       y++;
  696.       break;
  697.     }
  698.       
  699.     map_set_terrain(x,y, T_RIVER);
  700.     if (is_terrain_near_tile(x, y, T_OCEAN)) 
  701.       break;
  702.  
  703.     switch ((dir + myrand(3) - 1 + 4)%4) {
  704.     case 0:
  705.       x--;
  706.       break;
  707.     case 1:
  708.       y--;
  709.       break;
  710.     case 2:
  711.       x++;
  712.       break;
  713.     case 3:
  714.       y++;
  715.     }
  716.     
  717.     map_set_terrain(x,y, T_RIVER);
  718.   }
  719.  
  720.  
  721.   while (mountains) {
  722.     x = myrand(xmax) + xp;
  723.     y = myrand(ymax) + yp;
  724.     if (map_get_terrain(x,y) == T_GRASSLAND && !is_terrain_near_tile(x, y, T_OCEAN)) {
  725.       map_set_terrain(x, y, T_MOUNTAINS);
  726.       mountains--;
  727.     }    
  728.   }
  729.   while (hills) {
  730.     x = myrand(xmax) + xp;
  731.     y = myrand(ymax) + yp;
  732.     if (map_get_terrain(x,y) == T_GRASSLAND && !is_terrain_near_tile(x, y, T_OCEAN)) {
  733.       map_set_terrain(x, y, T_HILLS);
  734.       hills--;
  735.     }    
  736.   }
  737.   while (forest >0) {
  738.     x = myrand(xmax-1) + xp;
  739.     y = myrand(ymax-1) + yp;
  740.     if (map_get_terrain(x,y) == T_GRASSLAND) {
  741.       map_set_terrain(x, y, T_FOREST);
  742.       forest--;
  743.       if (map_get_terrain(x+1,y) == T_GRASSLAND && myrand(3)) {
  744.     map_set_terrain(x+1, y, T_FOREST);
  745.     forest--;
  746.       }
  747.       if (map_get_terrain(x,y+1) == T_GRASSLAND && myrand(3)) {
  748.     map_set_terrain(x, y+1, T_FOREST);
  749.     forest--;
  750.       }
  751.       if (map_get_terrain(x+1,y+1) == T_GRASSLAND && myrand(3)) {
  752.     map_set_terrain(x+1, y+1, T_FOREST);
  753.     forest--;
  754.       }
  755.     }    
  756.   }
  757.   while (mixed > 0) {
  758.     x = myrand(xmax) + xp;
  759.     y = myrand(ymax) + yp;
  760.     if (map_get_terrain(x,y) == T_GRASSLAND) {
  761.       if (arctic_y(y)) {
  762.     map_set_terrain(x, y, T_TUNDRA);
  763.     mixed--;
  764.       } else if (desert_y(y) && is_terrain_near_tile(x, y, T_OCEAN)) {
  765.     map_set_terrain(x, y, T_DESERT);
  766.     mixed--;
  767.     if (map_get_terrain(x+1,y) == T_GRASSLAND && myrand(3)) {
  768.       map_set_terrain(x, y, T_DESERT);
  769.       mixed--;
  770.     }
  771.     if (map_get_terrain(x,y+1) == T_GRASSLAND && myrand(3)) {
  772.       map_set_terrain(x, y, T_DESERT);
  773.       mixed--;
  774.     }
  775.     if (map_get_terrain(x+1,y+1) == T_GRASSLAND && myrand(3)) {
  776.       map_set_terrain(x, y, T_DESERT);
  777.       mixed--;
  778.     }
  779.       } else {
  780.     if (desert_y(y))
  781.       map_set_terrain(x, y, T_JUNGLE);
  782.     else 
  783.       map_set_terrain(x, y, T_SWAMP);
  784.     mixed--;
  785.       }
  786.     }
  787.   }
  788.   for (y = 0; y < ymax; y++)
  789.     for (x = 0; x < ymax; x++) {
  790.       if (map_get_terrain(xp +x, yp+y) == T_GRASSLAND && !myrand(3)) {
  791.     map_set_terrain(xp+x, y+yp, T_PLAINS);
  792.       }
  793.     }
  794. }
  795.  
  796. /**************************************************************************
  797.   copy the newly created island to the real map, notice that T_OCEAN is
  798.   used as mask so other island won't get destroyed.
  799. **************************************************************************/
  800. void placeisland(int xp, int yp)
  801. {
  802.   int x,y;
  803.   for (y = 0 ; y < dy ; y++) 
  804.     for (x = 0 ; x < dx ; x++) {
  805.       if (mini_map(xs+x, y+ys) != T_OCEAN) 
  806.     map_set_terrain(xp + x, yp + y, mini_map(xs+x, ys+y));
  807.     }
  808. }
  809.  
  810. /**************************************************************************
  811.   is there a neighbour square in the 4 basic directions?
  812. **************************************************************************/
  813. int neighbour(int x, int y)
  814. {
  815.   if ( x == 0 || x == xmax - 1 || y==0 || y == ymax -1) return 0;
  816.   return (mini_map(x+1, y) + mini_map(x-1, y) + mini_map(x, y+1) + mini_map(x, y-1));
  817. }
  818.  
  819. /**************************************************************************
  820.   is there a neighbour square in any of the 8 directions?
  821. **************************************************************************/
  822. int neighbour8(int x, int y)
  823. {
  824.   if ( x == 0 || x == xmax - 1 || y==0 || y == ymax -1) return 0;
  825.   return(neighbour(x,y) + mini_map(x+1, y-1) + mini_map(x-1, y-1) + mini_map(x+1, y+1) + mini_map(x-1, y+1));
  826. }
  827.  
  828. /**************************************************************************
  829.   we need this to convert tbe 0 based ocean representation to 2 
  830. **************************************************************************/
  831. void floodocean(int x, int y)
  832. {
  833.   if (x < 0 || x == xmax) return;
  834.   if (y < 0 || y == ymax) return;
  835.   if (mini_map(x,y) == 0) {
  836.     height_map[y*xmax + x] = 2;
  837.     floodocean(x - 1, y);
  838.     floodocean(x + 1, y);
  839.     floodocean(x , y - 1);
  840.     floodocean(x , y + 1);
  841.   }
  842. }
  843.  
  844. /**************************************************************************
  845.   this procedure will generate 1 island
  846. **************************************************************************/
  847. void makeisland(void)
  848. {
  849.   int x,y;
  850.   
  851.   xs = xmax/2 -1;
  852.   ys = ymax/2 -1;
  853.   dx = 3;
  854.   dy = 3;
  855.   for (y = 0 ; y < ymax ; y++) {
  856.     for (x = 0 ; x < xmax ; x++) {
  857.       height_map[y * xmax + x]=0;
  858.     }
  859.   }
  860.   height_map[(ymax/2)*xmax + xmax/2] = 1;
  861.   while (size > 0) {
  862.     x = myrand(dx) + xs;
  863.     y = myrand(dy) + ys;
  864.     if (mini_map(x, y) == 0 && neighbour(x,y)) {
  865.       height_map[y*xmax + x] = 1;
  866.       size--;
  867.       if (x <= xs) {
  868.     xs--;
  869.     dx++;
  870.       }
  871.       if (x == xs+dx - 1) dx++;
  872.       if (y <= ys) {
  873.     ys--;
  874.     dy++;
  875.       }
  876.       if (y == ys+dy - 1) dy++;
  877.     }
  878.   }
  879.   for (y = 0 ; y < ymax - 1; y++) 
  880.     for (x = 0; x < xmax - 1; x++) {
  881.       if (neighbour8(x, y) == 1 && mini_map(x, y) == 1) {
  882.     height_map[y*xmax + x] = 0;
  883.     size--;
  884.       }
  885.     }
  886.   floodocean(0,0);
  887.   for (y = 0 ; y < ymax; y++) 
  888.     for (x = 0; x < xmax; x++) {
  889.       if (mini_map(x, y) == 0) {
  890.     height_map[y*xmax + x] = 1;
  891.     size++;
  892.       }
  893.       if (mini_map(x, y) == 1) 
  894.     height_map[y*xmax + x] = T_GRASSLAND;
  895.       else 
  896.     height_map[y*xmax + x] = T_OCEAN;
  897.     }
  898. }
  899.  
  900. /**************************************************************************
  901.   this procedure finds a place to drop the current island
  902. **************************************************************************/
  903. void findislandspot(int *xplace, int *yplace)
  904. {
  905.   int x, y;
  906.   int rx, ry;
  907.   int taken;
  908.   while (1) {
  909.     rx = myrand(map.xsize);
  910.     ry = myrand(map.ysize-dy-6) + 3;
  911.     taken = 0;
  912.     for (y = 0; y < dy && !taken; y++)
  913.       for (x = 0; x < dx && !taken; x++) {
  914.       if (map_get_terrain(rx + x, ry + y) != T_OCEAN) {
  915.         taken = 1;
  916.       }
  917.     }
  918.     if (!taken) {
  919.       *xplace = rx;
  920.       *yplace = ry;
  921.       return;
  922.     }
  923.   }
  924. }
  925.  
  926. /**************************************************************************
  927.   this is mapgenerators2. The highlevel routine that ties the knots together
  928. **************************************************************************/
  929.  
  930. void mapgenerator2(void)
  931. {
  932.   int i;
  933.   int xp,yp;
  934.   int x,y;
  935.   height_map =(int *) malloc (sizeof(int)*xmax*ymax);
  936.   for (y = 0 ; y < map.ysize ; y++) 
  937.     for (x = 0 ; x < map.xsize ; x++) {
  938.       map_set_terrain(x,y, T_OCEAN);
  939.     }
  940.   for (x = 0 ; x < map.xsize; x++) {
  941.     map_set_terrain(x,0, T_ARCTIC);
  942.     if (myrand(100)>50) 
  943.       map_set_terrain(x,1, T_ARCTIC);
  944.     map_set_terrain(x, map.ysize-1, T_ARCTIC);
  945.     if (myrand(100)>50) 
  946.       map_set_terrain(x,map.ysize-2, T_ARCTIC);
  947.   }
  948.     for (i=0;i<7;i++) {
  949.       size = 100;
  950.       makeisland();
  951.       findislandspot(&xp, &yp);
  952.       placeisland(xp, yp);
  953.       fillisland(xp, yp);
  954.     }
  955.  
  956.   
  957.     /*  print_map();*/
  958.   free(height_map);
  959. }
  960.  
  961. /**************************************************************************
  962.   mapgenerator1, highlevel function, that calls all the previous functions
  963. **************************************************************************/
  964. void mapgenerator1(void)
  965. {
  966.   int x,y, i;
  967.   int minval=5000000;
  968.   height_map=(int *) malloc (sizeof(int)*map.xsize*map.ysize);
  969.  
  970.   
  971.   for (y=0;y<map.ysize;y++) {
  972.     for (x=0;x<map.xsize;x++) {
  973.       height_map[y*map.xsize+x]=myrand(40)+((500-abs(map.ysize/2)-y)/10);
  974.     }
  975.   }
  976.   for (i=0;i<1500;i++) {
  977.     height_map[myrand(map.ysize*map.xsize)]+=myrand(5000);
  978.     if (!(i%100)) {
  979.       smooth_map(); 
  980.     }
  981.   }
  982.  
  983.   smooth_map(); 
  984.   smooth_map(); 
  985.   smooth_map(); 
  986.  
  987.   for (y=0;y<map.ysize;y++)
  988.     for (x=0;x<map.xsize;x++) {
  989.       if (full_map(x, y)>maxval) 
  990.     maxval=full_map(x, y);
  991.       if (full_map(x, y)<minval)
  992.     minval=full_map(x, y);
  993.     }
  994.   maxval-=minval;
  995.   adjust_map(minval);
  996.  
  997.   make_land();
  998.   free(height_map);
  999. }
  1000.  
  1001. /**************************************************************************
  1002.   smooth_map should be viewed  as a  corrosion function on the map, it levels
  1003.   out the differences in the heightmap.
  1004. **************************************************************************/
  1005.  
  1006. void smooth_map()
  1007. {
  1008.   int x,y;
  1009.   int mx,my,px,py;
  1010.   int a;
  1011.   
  1012.   for (y=0;y<map.ysize;y++) {
  1013.     my=map_adjust_y(y-1);
  1014.     py=map_adjust_y(y+1);
  1015.     for (x=0;x<map.xsize;x++) {
  1016.       mx=map_adjust_x(x-1);
  1017.       px=map_adjust_x(x+1);
  1018.       a=full_map(x, y)*2;
  1019.       
  1020.       a+=full_map(px, my);
  1021.       a+=full_map(mx, my);
  1022.       a+=full_map(mx, py);
  1023.       a+=full_map(px, py);
  1024.  
  1025.       a+=full_map(x, my);
  1026.       a+=full_map(mx, y);
  1027.       
  1028.       a+=full_map(x, py);
  1029.       a+=full_map(px, y);
  1030.  
  1031.       a+=myrand(60);
  1032.       a-=30;
  1033.       if (a<0) a=0;
  1034.       height_map[y*map.xsize +x]=a/10;
  1035.     }
  1036.   }
  1037. }
  1038.  
  1039. /**************************************************************************
  1040.   this function spreads out huts on the map, a position can be used for a
  1041.   hut if there isn't another hut close and if it's not on the ocean.
  1042. **************************************************************************/
  1043. void make_huts(int number)
  1044. {
  1045.   int x,y;
  1046.   int count=0;
  1047.   while ((number*map.xsize*map.ysize)/2000 && count++<map.xsize*map.ysize*2) {
  1048.     x=myrand(map.xsize);
  1049.     y=myrand(map.ysize);
  1050.     if (map_get_terrain(x, y)!=T_OCEAN) {
  1051.       if (!is_hut_close(x,y)) {
  1052.     number--;
  1053.     map_get_tile(x,y)->special|=S_HUT;
  1054.       }
  1055.     }
  1056.   }
  1057. }
  1058.