1 /*
2  *  This file is part of Dune Legacy.
3  *
4  *  Dune Legacy is free software: you can redistribute it and/or modify
5  *  it under the terms of the GNU General Public License as published by
6  *  the Free Software Foundation, either version 2 of the License, or
7  *  (at your option) any later version.
8  *
9  *  Dune Legacy is distributed in the hope that it will be useful,
10  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  *  GNU General Public License for more details.
13  *
14  *  You should have received a copy of the GNU General Public License
15  *  along with Dune Legacy.  If not, see <http://www.gnu.org/licenses/>.
16  */
17 
18 
19 
20 #include <string.h>
21 #include <stdlib.h>
22 #include <SDL.h>
23 
24 #include "MapSeed.h"
25 
26 // global seed value
27 static Uint32 Seed;
28 
29 // a point that has 2 coordinates
30 typedef struct  {
31     Uint16 x;
32     Uint16 y;
33 } Point;
34 
35 // some values
36 const Uint8 BoolArray[] = {0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,0,0,1,0,0};
37 
38 // some offsets
39 const Sint8 OffsetArray1[]={
40     0,-1,1,-16,16,
41     -17,17,-15,15,
42     -2, 2,-32,32,
43     -4, 4,-64,64,
44     -30,30,-34,34
45 };
46 
47 // some more offsets
48 const Uint8 OffsetArray2[]={
49     0,0,4,0,4,0,4,4,0,0,0,4,0,4,4,4,0,0,0,2,0,
50     2,0,4,0,0,2,0,2,0,4,0,4,0,4,2,4,2,4,4,0,4,
51     2,4,2,4,4,4,0,0,4,4,2,0,2,2,0,0,2,2,4,0,2,
52     2,0,2,2,2,2,2,4,2,2,2,0,4,2,2,4,4,2,2,2,4,
53     0,0,4,0,4,0,4,4,0,0,0,4,0,4,4,4,0,0,0,2,0,
54     2,0,4,0,0,2,0,2,0,4,0,4,0,4,2,4,2,4,4,0,4,
55     2,4,2,4,4,4,4,0,0,4,2,0,2,2,0,0,2,2,4,0,2,
56     2,0,2,2,2,2,2,4,2,2,2,0,4,2,2,4,4,2,2,2,4
57 };
58 
59 // TileTypes
60 const Sint16 TileTypes[] = {
61     220, 221, 222, 229, 230, 231, 213, 214, 215, 223, 224, 225, 232, 233, 234, 216,
62     217, 218, 226, 227, 228, 235, 236, 237, 219, 217, 218, 226, 227, 228, 235, 236,
63     237, 238, 239, 244, 245, 125, 240, 246, 247, 241, 242, 248, 249, 241, 243, 248,
64     249, 241, 242, 248, 250, 241, 243, 248, 250, 251, 252, 253, 258, 259, 260, 223,
65     224, 225, 232, 233, 234, 254, 255, 256, 261, 262, 263, 257, 255, 256, 261, 262,
66     263, 254, 255, 256, 261, 264, 265, 257, 255, 256, 261, 264, 265, 254, 255, 256,
67     261, 266, 267, 257, 255, 256, 261, 266, 267, 210, 268, 269, 273, 274, 275, 223,
68     224, 225, 232, 233, 234, 270, 271, 272, 276, 277, 278, 270, 271, 272, 279, 277,
69     278, 270, 271, 272, 276, 277, 278, 270, 271, 272, 279, 277, 278, 270, 271, 272,
70     276, 277, 278, 270, 271, 272, 279, 277, 278, 238, 239, 244, 245, 125, 240, 246,
71     247, 280, 281, 282, 283, 280, 281, 282, 284, 238, 239, 244, 245, 125, 240, 246,
72     247, 285, 286, 288, 289, 287, 286, 290, 289, 143, 291, 295, 296, 125, 240, 246,
73     247, 292, 293, 297, 298, 294, 293, 297, 298, 238, 239, 244, 245, 125, 240, 246,
74     247, 299, 300, 301, 302, 299, 300, 301, 303, 238, 239, 244, 245, 125, 240, 246,
75     247, 304, 305, 306, 307, 304, 305, 306, 308, 210, 211, 212, 220, 221, 222, 229,
76     230, 231, 213, 214, 215, 223, 313, 225, 232, 233, 234, 309, 310, 311, 314, 315,
77     316, 319, 320, 321, 312, 310, 311, 314, 315, 316, 319, 320, 321, 309, 310, 311
78 };
79 
80 // sinus[index] = 127 * sin(pi * index/128)
81 static const Sint8 sinus[256] = {
82     0, 3, 6, 9, 12, 15, 18, 21, 24, 27, 30, 33, 36, 39, 42, 45,
83     48, 51, 54, 57, 59, 62, 65, 67, 70, 73, 75, 78, 80, 82, 85, 87,
84     89, 91, 94, 96, 98, 100, 101, 103, 105, 107, 108, 110, 111, 113, 114, 116,
85     117, 118, 119, 120, 121, 122, 123, 123, 124, 125, 125, 126, 126, 126, 126, 126,
86     127, 126, 126, 126, 126, 126, 125, 125, 124, 123, 123, 122, 121, 120, 119, 118,
87     117, 116, 114, 113, 112, 110, 108, 107, 105, 103, 102, 100, 98, 96, 94, 91,
88     89, 87, 85, 82, 80, 78, 75, 73, 70, 67, 65, 62, 59, 57, 54, 51,
89     48, 45, 42, 39, 36, 33, 30, 27, 24, 21, 18, 15, 12, 9, 6, 3,
90     0, -3, -6, -9, -12, -15, -18, -21, -24, -27, -30, -33, -36, -39, -42, -45,
91     -48, -51, -54, -57, -59, -62, -65, -67, -70, -73, -75, -78, -80, -82, -85, -87,
92     -89, -91, -94, -96, -98, -100, -102, -103, -105, -107, -108, -110, -111, -113, -114, -116,
93     -117, -118, -119, -120, -121, -122, -123, -123, -124, -125, -125, -126, -126, -126, -126, -126,
94     -126, -126, -126, -126, -126, -126, -125, -125, -124, -123, -123, -122, -121, -120, -119, -118,
95     -117, -116, -114, -113, -112, -110, -108, -107, -105, -103, -102, -100, -98, -96, -94, -91,
96     -89, -87, -85, -82, -80, -78, -75, -73, -70, -67, -65, -62, -59, -57, -54, -51,
97     -48, -45, -42, -39, -36, -33, -30, -27, -24, -21, -18, -15, -12, -9, -6, -3
98 };
99 
100 /**
101     Converts a 2d coordinate to a 1d.
102     \param Xcoord   The coordinate in x-direction
103     \param Ycoord   The coordinate in y-direction
104     \return The 1-dimensional coordinate
105 */
MapArray2DToMapArray1D(Sint16 Xcoord,Sint16 Ycoord)106 static Sint16 MapArray2DToMapArray1D(Sint16 Xcoord,Sint16 Ycoord) {
107     return Xcoord | (Ycoord << 6);
108 }
109 
110 /**
111     Converts a 2d coordinate to a 1d. This function is basically the same
112     as MapArray2DToMapArray1D() but limits the Xcoord to (0-63).
113     \param Xcoord   The coordinate in x-direction
114     \param Ycoord   The coordinate in y-direction
115     \return The 1-dimensional coordinate
116 */
MapArray2DToMapArray1D_OOB(Sint16 Xcoord,Sint16 Ycoord)117 static Sint16 MapArray2DToMapArray1D_OOB(Sint16 Xcoord,Sint16 Ycoord) {
118     return MapArray2DToMapArray1D(Xcoord & 0x3F,Ycoord);
119 }
120 
121 
122 /**
123     This function smooth the map in the local neighbourhood of index.
124     \param  index       The position which should be smoothed
125     \param  pMapArray   Pointer to the map that should be smoothed
126     \return none
127 */
SmoothNeighbourhood(Sint16 index,Uint32 * pMapArray)128 static void SmoothNeighbourhood(Sint16 index, Uint32* pMapArray) {
129     Sint16 TileType;
130     Sint16 Xcoord;
131     Sint16 Ycoord;
132     Sint16 Pos;
133 
134     TileType = (Sint16) pMapArray[index];
135 
136     if(TileType == 8) {
137         pMapArray[index] = 9;
138         SmoothNeighbourhood(index,pMapArray);
139     } else if (TileType == 9) {
140         for(Ycoord = -1; Ycoord <= 1; Ycoord++) {
141             for(Xcoord = -1; Xcoord <= 1; Xcoord++) {
142                 Pos = MapArray2DToMapArray1D( (index & 0x3F)+Xcoord,((index >> 6) & 0x3F)+Ycoord);
143                 if(Pos < 0)
144                     continue;
145                 if(Pos >= 64*64)
146                     continue;
147 
148                 if(BoolArray[pMapArray[Pos]] == 1) {
149                     pMapArray[index] = 8;
150                     continue;
151                 } else {
152                     if(pMapArray[Pos] == 9)
153                         continue;
154 
155                     pMapArray[Pos]=8;
156                 }
157             }
158         }
159     } else {
160         if(BoolArray[TileType] == 0) {
161             pMapArray[index] = 8;
162         }
163     }
164 }
165 
166 /**
167     Creates new random value.
168     \return The new random value
169 */
SeedRand()170 static Uint16 SeedRand() {
171     Uint8 a;
172     Uint8 carry;
173     Uint8 old_carry;
174 
175     // little endian is more useful for this algorithm
176     Seed = SDL_SwapLE32(Seed);
177     Uint8* pSeed = (Uint8*) &Seed;
178 
179     // shift right
180     a = pSeed[0];
181     a = a >> 1;
182 
183     // shift right in carry
184     carry = a & 0x01;
185     a = a >> 1;
186 
187     // rotate left through carry
188     old_carry = carry;
189     carry = (pSeed[2] & 0x80) >> 7;
190     pSeed[2] = pSeed[2] << 1;
191     pSeed[2] = pSeed[2] | old_carry;
192 
193     // rotate left through carry
194     old_carry = carry;
195     carry = (pSeed[1] & 0x80) >> 7;
196     pSeed[1] = pSeed[1] << 1;
197     pSeed[1] = pSeed[1] | old_carry;
198 
199     // invert carry
200     carry = (carry == 1 ? 0 : 1);
201 
202     // subtract with carry
203     a = ((Uint16) a) - (((Uint16) pSeed[0]) + ((Uint16) carry));
204 
205     // shift right
206     carry = a & 0x01;
207     // a = a >> 1;  //< Not needed anymore
208 
209     // rotate right through carry
210     pSeed[0] = (pSeed[0] >> 1) | (carry << 7);
211 
212     // xor
213     a = pSeed[0] ^ pSeed[1];
214 
215     // convert back to native endianess
216     Seed = SDL_SwapLE32(Seed);
217 
218     return ((Uint16) a);
219 
220 }
221 
222 /**
223     Creates a random map.
224     \param Para_Seed    Seed of the map
225     \param pResultMap   Should be Uint16[64*64]
226 */
createMapWithSeed(Uint32 Para_Seed,Uint16 * pResultMap)227 void createMapWithSeed(Uint32 Para_Seed,Uint16 *pResultMap)
228 {
229     Uint8 Array4x4TerrainGrid[16*16+16+1];
230     Uint32 MapArray[65*65];
231     Point point;
232     Uint16 randNum;
233     Uint16 randNum2;
234     Uint16 randNum3;
235     Sint16 index;
236     Sint16 i,j;
237     Sint16 Xcoord;
238     Sint16 Ycoord;
239     Uint16 max;
240     Sint16 Point1;
241     Sint16 Point2;
242     Uint16 pos;
243 
244     Uint16 curMapRow[0x80];
245     Uint16 oldMapRow[0x80];
246     Uint32 Area[3][3];
247 
248     Seed = Para_Seed;
249 
250     // clear map
251     memset(MapArray,0,sizeof(MapArray));
252 
253     for(i = 0; i < 16*16+16 ; i++) {
254         Array4x4TerrainGrid[i] = SeedRand() & 0x0F;
255         if(Array4x4TerrainGrid[i] <= 0x0A)
256             continue;
257 
258         Array4x4TerrainGrid[i] = 0x0A;
259     }
260 
261     for(i = SeedRand() & 0x0F;i >= 0 ;i--) {
262         randNum = SeedRand() & 0xFF;
263         for(j = 0; j < 21; j++) {
264             index = randNum + OffsetArray1[j];
265             index = index >= 0 ? index : 0;
266             index = index <= (16*16+16) ? index : (16*16+16);
267             Array4x4TerrainGrid[index] = ((Uint16) Array4x4TerrainGrid[index] + (SeedRand() & 0x0F)) & 0x0F;
268         }
269     }
270 
271     for(i = SeedRand() & 0x03; i >= 0; i--) {
272         randNum = SeedRand() & 0xFF;
273         for(j = 0; j < 21; j++) {
274             index = randNum + OffsetArray1[j];
275             index = index >= 0 ? index : 0;
276             index = index <= (16*16+16) ? index : (16*16+16);
277             Array4x4TerrainGrid[index] = SeedRand() & 0x03;
278         }
279     }
280 
281     for(Ycoord = 0; Ycoord < 64; Ycoord+=4) {
282         for(Xcoord = 0; Xcoord < 64; Xcoord+=4) {
283             MapArray[MapArray2DToMapArray1D(Xcoord,Ycoord)] = Array4x4TerrainGrid[Ycoord*4+Xcoord/4];
284         }
285     }
286 
287     for(Ycoord = 0; Ycoord < 64; Ycoord+=4) {
288         for(Xcoord = 0; Xcoord < 64; Xcoord+=4) {
289             for(i = (Xcoord % 8 == 0 ? 21 : 0) ; (Xcoord % 8 == 0 ? 21 : 0) + 21 > i; i++) {
290                 Point1 =  MapArray2DToMapArray1D(Xcoord + OffsetArray2[4*i],Ycoord + OffsetArray2[4*i+1]);
291                 Point2 =  MapArray2DToMapArray1D(Xcoord + OffsetArray2[4*i+2],Ycoord + OffsetArray2[4*i+3]);
292                 pos = (Point1 + Point2) / 2;
293 
294                 if(pos >= 64*64)
295                     continue;
296 
297                 Point1 =  MapArray2DToMapArray1D_OOB(Xcoord + OffsetArray2[4*i],Ycoord + OffsetArray2[4*i+1]);
298                 Point2 =  MapArray2DToMapArray1D_OOB(Xcoord + OffsetArray2[4*i+2],Ycoord + OffsetArray2[4*i+3]);
299 
300                 MapArray[pos] = (MapArray[Point1] + MapArray[Point2] + 1) / 2;
301             }
302 
303         }
304     }
305 
306     memset(curMapRow,0,sizeof(curMapRow));
307 
308     // apply box-filter to the map
309     for(Ycoord = 0; Ycoord < 64; Ycoord++) {
310 
311         // save the old row
312         memcpy(oldMapRow,curMapRow,sizeof(curMapRow));
313         for(i = 0;i < 64; i++) {
314             curMapRow[i] = (Uint16) MapArray[Ycoord*64+i];
315         }
316 
317         for(Xcoord = 0; Xcoord < 64; Xcoord++) {
318 
319             Area[0][0] = ((Xcoord > 0) && (Ycoord > 0)) ? oldMapRow[Xcoord-1] : curMapRow[Xcoord];
320             Area[1][0] = (Ycoord > 0) ? oldMapRow[Xcoord] : curMapRow[Xcoord];
321             Area[2][0] = ((Xcoord < 63) && (Ycoord > 0)) ? oldMapRow[Xcoord+1] : curMapRow[Xcoord];
322 
323             Area[0][1] = (Xcoord > 0) ? curMapRow[Xcoord-1] : curMapRow[Xcoord];
324             Area[1][1] = curMapRow[Xcoord];
325             Area[2][1] = (Xcoord < 63) ? curMapRow[Xcoord+1] : curMapRow[Xcoord];
326 
327             Area[0][2] = ((Xcoord > 0) && (Ycoord < 63)) ? MapArray[(Ycoord+1)*64 + Xcoord-1] : curMapRow[Xcoord];
328             Area[1][2] = (Ycoord < 63) ? MapArray[(Ycoord+1)*64 + Xcoord] : curMapRow[Xcoord];
329             Area[2][2] = ((Xcoord < 63) && (Ycoord < 63)) ? MapArray[(Ycoord+1)*64 + Xcoord+1] : curMapRow[Xcoord];
330 
331             MapArray[Ycoord*64 + Xcoord]    =   (   Area[0][0] + Area[1][0] + Area[2][0]
332                                                 +   Area[0][1] + Area[1][1] + Area[1][2]
333                                                 +   Area[0][2] + Area[2][1] + Area[2][2] )/9;
334         }
335     }
336 
337     randNum = SeedRand() & 0x0F;
338     randNum = (randNum < 8 ? 8 : randNum);
339     randNum = (randNum > 0x0C ? 0x0C : randNum);
340     point.y = (SeedRand() & 0x03) - 1;
341     point.y = ( (randNum-3) < point.y ? randNum-3 : point.y);
342 
343     for(i = 0; i < 64*64; i++) {
344         point.x = (Uint16) MapArray[i];
345 
346         if( (randNum+4) < point.x) {
347             MapArray[i] = 0x06;
348         } else if(point.x >= randNum) {
349             MapArray[i] = 0x04;
350         } else if(point.x <= point.y) {
351             MapArray[i] = 0x02;
352         } else {
353             MapArray[i] = 0x00;
354         }
355     }
356 
357     for(i = SeedRand() & 0x2F; i != 0; i--) {
358         point.y = SeedRand() & 0x3F;
359         point.x = SeedRand() & 0x3F;
360         index = MapArray2DToMapArray1D(point.x,point.y);
361 
362         if(BoolArray[MapArray[index]] == 1) {
363             i++;
364             continue;
365         }
366 
367 
368         randNum = SeedRand() & 0x1F;
369         for(j=0; j < randNum; j++) {
370             max = SeedRand() & 0x3F;
371 
372             if(max == 0) {
373                 pos = index;
374             } else {
375                 point.y = ((index << 2) & 0xFF00) | 0x80;
376                 point.x = ((index & 0x3F) << 8) | 0x80;
377 
378                 randNum2 = SeedRand() & 0xFF;
379 
380                 while(randNum2 > max)
381                     randNum2 = randNum2 >> 1;
382 
383                 randNum3 = SeedRand() & 0xFF;
384 
385                 point.x = point.x + (((sinus[randNum3] * randNum2) >> 7) << 4);
386                 point.y = point.y + ((((-1) * sinus[(randNum3+64) % 256] * randNum2) >> 7) << 4);
387 
388 
389                 if(/*(point.x < 0) || */(point.x > 0x4000) || /*(point.y < 0) ||*/ (point.y > 0x4000)) {
390                     pos =  index;
391                 } else {
392                     pos = ((point.y & 0xFF00) >> 2) | (point.x >> 8);
393                 }
394             }
395 
396             if(pos >= 64*64) {
397                 j--;
398                 continue;
399             }
400 
401             /*
402             if(pos < 0) {
403                 j--;
404                 continue;
405             }*/
406 
407             SmoothNeighbourhood(pos,MapArray);
408         }
409     }
410 
411 
412     //smoothing
413     for(i = 0; i < 64; i++) {
414         curMapRow[i] = (Uint16) MapArray[i];
415     }
416 
417     for(Ycoord = 0; Ycoord < 64; Ycoord++) {
418         memcpy(oldMapRow,curMapRow,sizeof(curMapRow));
419 
420         for(i = 0; i < 64; i++) {
421             curMapRow[i] = (Uint16) MapArray[Ycoord*64+i];
422         }
423 
424         for(Xcoord = 0; Xcoord < 64; Xcoord++) {
425 
426             Area[1][0] = (Ycoord > 0) ? oldMapRow[Xcoord] : MapArray[Ycoord*64+Xcoord];
427             Area[0][1] = (Xcoord > 0) ? curMapRow[Xcoord-1] : MapArray[Ycoord*64+Xcoord];
428             Area[1][1] = MapArray[Ycoord*64+Xcoord];
429             Area[2][1] = (Xcoord < 63) ? curMapRow[Xcoord+1] : MapArray[Ycoord*64+Xcoord];
430             Area[1][2] = (Ycoord < 63) ? MapArray[(Ycoord+1)*64+Xcoord] : MapArray[Ycoord*64+Xcoord];
431 
432             MapArray[Ycoord*64+Xcoord] = 0;
433 
434             switch(Area[1][1]) {
435 
436             case 4:
437                 if( (Area[1][0] == 4) || (Area[1][0] == 6) )
438                     MapArray[Ycoord*64+Xcoord] |= 0x01;
439 
440                 if( (Area[2][1] == 4) || (Area[2][1] == 6) )
441                     MapArray[Ycoord*64+Xcoord] |= 0x02;
442 
443                 if( (Area[1][2] == 4) || (Area[1][2] == 6) )
444                     MapArray[Ycoord*64+Xcoord] |= 0x04;
445 
446                 if( (Area[0][1] == 4) || (Area[0][1] == 6) )
447                     MapArray[Ycoord*64+Xcoord] |= 0x08;
448 
449                 break;
450 
451             case 8:
452                 if( (Area[1][0] == 8) || (Area[1][0] == 9) )
453                     MapArray[Ycoord*64+Xcoord] |= 0x01;
454 
455                 if( (Area[2][1] == 8) || (Area[2][1] == 9) )
456                     MapArray[Ycoord*64+Xcoord] |= 0x02;
457 
458                 if( (Area[1][2] == 8) || (Area[1][2] == 9) )
459                     MapArray[Ycoord*64+Xcoord] |= 0x04;
460 
461                 if( (Area[0][1] == 8) || (Area[0][1] == 9) )
462                     MapArray[Ycoord*64+Xcoord] |= 0x08;
463 
464                 break;
465 
466             default:
467                 if(Area[1][0] == Area[1][1])
468                     MapArray[Ycoord*64+Xcoord] |= 0x01;
469 
470                 if(Area[2][1] == Area[1][1])
471                     MapArray[Ycoord*64+Xcoord] |= 0x02;
472 
473                 if(Area[1][2] == Area[1][1])
474                     MapArray[Ycoord*64+Xcoord] |= 0x04;
475 
476                 if(Area[0][1] == Area[1][1])
477                     MapArray[Ycoord*64+Xcoord] |= 0x08;
478 
479                 break;
480             }
481 
482             if(Area[1][1] == 0)
483                 MapArray[Ycoord*64+Xcoord] = 0;
484 
485             if(Area[1][1] == 4)
486                 MapArray[Ycoord*64+Xcoord]++;
487 
488             if(Area[1][1] == 2)
489                 MapArray[Ycoord*64+Xcoord] += 0x11;
490 
491             if(Area[1][1] == 6)
492                 MapArray[Ycoord*64+Xcoord] += 0x21;
493 
494             if(Area[1][1] == 8)
495                 MapArray[Ycoord*64+Xcoord] += 0x31;
496 
497             if(Area[1][1] == 9)
498                 MapArray[Ycoord*64+Xcoord] += 0x41;
499         }
500     }
501 
502     //create resulting array
503     for(i = 0; i < 64*64; i++) {
504         MapArray[i] = (MapArray[i] & 0xFE00) | ((MapArray[i] <= 85) ? (MapArray[i]+127) : TileTypes[MapArray[i]-85]) | 0xF800;
505         pResultMap[i] = MapArray[i] & 0x1FF;
506     }
507 }
508 
createMapWithSeed(Uint32 Para_Seed,int mapscale)509 MapData createMapWithSeed(Uint32 Para_Seed, int mapscale) {
510     Uint16 SeedMap[64*64];
511     createMapWithSeed(Para_Seed,SeedMap);
512 
513     int sizeX = 0;
514     int sizeY = 0;
515     int logicalOffsetX = 0;
516     int logicalOffsetY = 0;
517 
518     switch(mapscale) {
519         case 0: {
520             sizeX = 62;
521             sizeY = 62;
522             logicalOffsetX = 1;
523             logicalOffsetY = 1;
524         } break;
525 
526         case 1: {
527             sizeX = 32;
528             sizeY = 32;
529             logicalOffsetX = 16;
530             logicalOffsetY = 16;
531         } break;
532 
533         case 2:
534         default: {
535             sizeX = 21;
536             sizeY = 21;
537             logicalOffsetX = 11;
538             logicalOffsetY = 11;
539         } break;
540     }
541 
542     MapData mapData(sizeX, sizeY);
543 
544     for(int y = 0; y < sizeY; y++) {
545         for(int x = 0; x < sizeX; x++) {
546 
547             TERRAINTYPE terrainType = Terrain_Sand;
548 
549             unsigned char seedmaptype = SeedMap[(y+logicalOffsetY)*64+x+logicalOffsetX] >> 4;
550             switch(seedmaptype) {
551                 case 0x7: {
552                     // Normal sand
553                     terrainType = Terrain_Sand;
554                 } break;
555 
556                 case 0x2:
557                 case 0x8: {
558                     // Rock or building
559                     terrainType = Terrain_Rock;
560                 } break;
561 
562                 case 0x9: {
563                     // Sand dunes
564                     terrainType = Terrain_Dunes;
565                 } break;
566 
567                 case 0xa: {
568                     // Mountain
569                     terrainType = Terrain_Mountain;
570                 } break;
571 
572                 case 0xb: {
573                     // Spice
574                     terrainType = Terrain_Spice;
575                 } break;
576 
577                 case 0xc: {
578                     // Thick spice
579                     terrainType = Terrain_ThickSpice;
580                 } break;
581             }
582 
583             mapData(x,y) = terrainType;
584         }
585     }
586 
587     return mapData;
588 }
589