]> git.zerfleddert.de Git - micropolis/blame_incremental - src/sim/terrain/terragen.c
Linux pkg-config needs double dashes.
[micropolis] / src / sim / terrain / terragen.c
... / ...
CommitLineData
1/* terragen.c: Terrain generator
2 *
3 * Micropolis, Unix Version. This game was released for the Unix platform
4 * in or about 1990 and has been modified for inclusion in the One Laptop
5 * Per Child program. Copyright (C) 1989 - 2007 Electronic Arts Inc. If
6 * you need assistance with this program, you may contact:
7 * http://wiki.laptop.org/go/Micropolis or email micropolis@laptop.org.
8 *
9 * This program is free software: you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation, either version 3 of the License, or (at
12 * your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * General Public License for more details. You should have received a
18 * copy of the GNU General Public License along with this program. If
19 * not, see <http://www.gnu.org/licenses/>.
20 *
21 * ADDITIONAL TERMS per GNU GPL Section 7
22 *
23 * No trademark or publicity rights are granted. This license does NOT
24 * give you any right, title or interest in the trademark SimCity or any
25 * other Electronic Arts trademark. You may not distribute any
26 * modification of this program using the trademark SimCity or claim any
27 * affliation or association with Electronic Arts Inc. or its employees.
28 *
29 * Any propagation or conveyance of this program must include this
30 * copyright notice and these terms.
31 *
32 * If you convey this program (or any modifications of it) and assume
33 * contractual liability for the program to recipients of it, you agree
34 * to indemnify Electronic Arts for any liability that those contractual
35 * assumptions impose on Electronic Arts.
36 *
37 * You may not misrepresent the origins of this program; modified
38 * versions of the program must be marked as such and not identified as
39 * the original program.
40 *
41 * This disclaimer supplements the one included in the General Public
42 * License. TO THE FULLEST EXTENT PERMISSIBLE UNDER APPLICABLE LAW, THIS
43 * PROGRAM IS PROVIDED TO YOU "AS IS," WITH ALL FAULTS, WITHOUT WARRANTY
44 * OF ANY KIND, AND YOUR USE IS AT YOUR SOLE RISK. THE ENTIRE RISK OF
45 * SATISFACTORY QUALITY AND PERFORMANCE RESIDES WITH YOU. ELECTRONIC ARTS
46 * DISCLAIMS ANY AND ALL EXPRESS, IMPLIED OR STATUTORY WARRANTIES,
47 * INCLUDING IMPLIED WARRANTIES OF MERCHANTABILITY, SATISFACTORY QUALITY,
48 * FITNESS FOR A PARTICULAR PURPOSE, NONINFRINGEMENT OF THIRD PARTY
49 * RIGHTS, AND WARRANTIES (IF ANY) ARISING FROM A COURSE OF DEALING,
50 * USAGE, OR TRADE PRACTICE. ELECTRONIC ARTS DOES NOT WARRANT AGAINST
51 * INTERFERENCE WITH YOUR ENJOYMENT OF THE PROGRAM; THAT THE PROGRAM WILL
52 * MEET YOUR REQUIREMENTS; THAT OPERATION OF THE PROGRAM WILL BE
53 * UNINTERRUPTED OR ERROR-FREE, OR THAT THE PROGRAM WILL BE COMPATIBLE
54 * WITH THIRD PARTY SOFTWARE OR THAT ANY ERRORS IN THE PROGRAM WILL BE
55 * CORRECTED. NO ORAL OR WRITTEN ADVICE PROVIDED BY ELECTRONIC ARTS OR
56 * ANY AUTHORIZED REPRESENTATIVE SHALL CREATE A WARRANTY. SOME
57 * JURISDICTIONS DO NOT ALLOW THE EXCLUSION OF OR LIMITATIONS ON IMPLIED
58 * WARRANTIES OR THE LIMITATIONS ON THE APPLICABLE STATUTORY RIGHTS OF A
59 * CONSUMER, SO SOME OR ALL OF THE ABOVE EXCLUSIONS AND LIMITATIONS MAY
60 * NOT APPLY TO YOU.
61 */
62
63/* Micropolis simulator code. Copyright 1988, 1989 Maxis, Will Wright */
64/* modified by Paul Schmidt 10-89 to implement terrain editor quickly... - rax */
65
66#include "..\sim\sim.h"
67
68#define TRUE 1
69#define FALSE 0
70#define WORLD_X 120
71#define WORLD_Y 100
72#define RIVER 2
73#define REDGE 3
74#define CHANNEL 4
75#define WOODS 37
76#define BL 4096
77#define BN 8192
78#define BLN BL+BN
79
80#define WATER_LOW 2 /* range for water */
81#define WATER_HIGH 20
82#define WOODS_LOW 21 /* range for woods */
83#define WOODS_HIGH 39
84
85static int XStart, YStart;
86static int Dir, LastDir;
87
88 /* trash values for GRand() */
89static int GRanArray[5] = { 1018,4521,202,419,3 };
90
91extern int treeLevel; /* level for tree creation (terra.c) */
92extern int lakeLevel; /* level for lake creation (terra.c) */
93extern int curvLevel; /* level for river curviness (terra.c) */
94
95rax_ClearMap()
96{
97register int x, y;
98
99 for (x=0; x<WORLD_X; x++)
100 for (y=0; y<WORLD_Y; y++)
101 Map[x][y] = 0;
102}
103
104rax_WaterEdges() /* set water edges */
105{
106 register int x,y; /* temporary counters */
107
108 for(x=0;x < WORLD_X;x++) {
109 for(y=0;y < WORLD_Y;y++) {
110 if((Map[x][y]&LOMASK) >= WATER_LOW && (Map[x][y]&LOMASK) <= WATER_HIGH) { /* if water */
111 if(x > 0) {
112 if((Map[x-1][y]&LOMASK) < WATER_LOW || (Map[x-1][y]&LOMASK) > WATER_HIGH) { /* if nearest object is not water */
113 goto edge;
114 }
115 }
116 if(x < WORLD_X-1) {
117 if((Map[x+1][y]&LOMASK) < WATER_LOW || (Map[x+1][y]&LOMASK) > WATER_HIGH) { /* if nearest object is not water */
118 goto edge;
119 }
120 }
121 if(y > 0) {
122 if((Map[x][y-1]&LOMASK) < WATER_LOW || (Map[x][y-1]&LOMASK) > WATER_HIGH) { /* if nearest object is not water */
123 goto edge;
124 }
125 }
126 if(y < WORLD_Y-1) {
127 if((Map[x][y+1]&LOMASK) < WATER_LOW || (Map[x][y+1]&LOMASK) > WATER_HIGH) { /* if nearest object is not water */
128edge:
129 Map[x][y]=REDGE; /* set river edge */
130 continue;
131 }
132 }
133 }
134 }
135 }
136 for(x=0;x < WORLD_X;x++) {
137 for(y=0;y < WORLD_Y;y++) {
138 if((Map[x][y]&LOMASK) != CHANNEL && (Map[x][y]&LOMASK) >= WATER_LOW && (Map[x][y]&LOMASK) <= WATER_HIGH) { /* if water which is not a channel */
139 if(x > 0) {
140 if((Map[x-1][y]&LOMASK) < WATER_LOW || (Map[x-1][y]&LOMASK) > WATER_HIGH) { /* if nearest object is not water */
141 continue;
142 }
143 }
144 if(x < WORLD_X-1) {
145 if((Map[x+1][y]&LOMASK) < WATER_LOW || (Map[x+1][y]&LOMASK) > WATER_HIGH) { /* if nearest object is not water */
146 continue;
147 }
148 }
149 if(y > 0) {
150 if((Map[x][y-1]&LOMASK) < WATER_LOW || (Map[x][y-1]&LOMASK) > WATER_HIGH) { /* if nearest object is not water */
151 continue;
152 }
153 }
154 if(y < WORLD_Y-1) {
155 if((Map[x][y+1]&LOMASK) < WATER_LOW || (Map[x][y+1]&LOMASK) > WATER_HIGH) { /* if nearest object is not water */
156 continue;
157 }
158 }
159 Map[x][y]=RIVER; /* make it a river */
160 }
161 }
162 }
163 for(x=0;x < WORLD_X;x++) {
164 for(y=0;y < WORLD_Y;y++) {
165 if((Map[x][y]&LOMASK) >= WOODS_LOW && (Map[x][y]&LOMASK) <= WOODS_HIGH) { /* if woods */
166 if(x > 0) {
167 if(Map[x-1][y] == RIVER || Map[x-1][y] == CHANNEL) { /* if nearest object is water */
168 Map[x][y]=REDGE; /* make it water's edge */
169 continue;
170 }
171 }
172 if(x < WORLD_X-1) {
173 if(Map[x+1][y] == RIVER || Map[x+1][y] == CHANNEL) { /* if nearest object is water */
174 Map[x][y]=REDGE; /* make it water's edge */
175 continue;
176 }
177 }
178 if(y > 0) {
179 if(Map[x][y-1] == RIVER || Map[x][y-1] == CHANNEL) { /* if nearest object is water */
180 Map[x][y]=REDGE; /* make it water's edge */
181 continue;
182 }
183 }
184 if(y < WORLD_Y-1) {
185 if(Map[x][y+1] == RIVER || Map[x][y+1] == CHANNEL) { /* if nearest object is water */
186 Map[x][y]=REDGE; /* make it water's edge */
187 continue;
188 }
189 }
190 }
191 }
192 }
193}
194
195#define RADIUS 18
196
197rax_MakeIsland()
198{
199 register int x,y,z;
200
201 for (x=0; x<WORLD_X; x++)
202 for (y=0; y<WORLD_Y; y++)
203 Map[x][y] = RIVER;
204 for (x=5; x<WORLD_X-5; x++)
205 for (y=5; y<WORLD_Y-5; y++)
206 Map[x][y] = 0;
207 for (x=0; x<WORLD_X-5; x+=2) {
208 MapX= x ;
209 MapY= rax_EGRand(RADIUS);
210 rax_BRivPlop();
211 MapY= 90-rax_EGRand(RADIUS);
212 rax_BRivPlop();
213 MapY= 0;
214 rax_SRivPlop();
215 MapY= 94;
216 rax_SRivPlop();
217 }
218 for (y=0; y<WORLD_Y-5; y+=2) {
219 MapY= y ;
220 MapX= rax_EGRand(RADIUS);
221 rax_BRivPlop();
222 MapX= 110-rax_EGRand(RADIUS);
223 rax_BRivPlop();
224 MapX= 0;
225 rax_SRivPlop();
226 MapX= 114;
227 rax_SRivPlop();
228 }
229}
230
231rax_MakeLakes()
232{
233 int Lim1, Lim2, t, z;
234 register int x, y;
235
236/* Lim1 = rax_GRand(10); /**/
237 Lim1=lakeLevel/2;
238 for (t = 0; t < Lim1; t++) {
239 x = rax_GRand(99) + 10;
240 y = rax_GRand(80) + 10;
241 Lim2 = rax_GRand(12)+2;
242 for (z = 0; z < Lim2; z++) {
243 MapX = x - 6 + rax_GRand(12);
244 MapY = y - 6 + rax_GRand(12);
245 if (rax_GRand(4)) rax_SRivPlop();
246 else rax_BRivPlop();
247 }
248 }
249}
250
251rax_GetRandStart()
252{
253 XStart = 40 + rax_GRand(40);
254 YStart = 33 + rax_GRand(33);
255 MapX = XStart;
256 MapY = YStart;
257}
258
259rax_DoTrees()
260{
261 int x,xloc,yloc;
262
263 for(x=0;x < (treeLevel*3);x++) {
264 xloc=rax_GRand(119);
265 yloc=rax_GRand(99);
266 rax_TreeSplash(xloc,yloc);
267 }
268 rax_SmoothTrees();
269 rax_SmoothTrees();
270}
271
272rax_TreeSplash(xloc,yloc)
273int xloc,yloc;
274{
275 int Dis, Dir;
276 register int xoff, yoff,z;
277
278 Dis = rax_GRand(100+(treeLevel*2))+50;
279 MapX = xloc;
280 MapY = yloc;
281 for (z=0; z<Dis; z++) {
282 Dir = rax_GRand(7);
283 rax_MoveMap(Dir);
284 if (!(rax_TestBounds(MapX,MapY))) return;
285 if (Map[MapX][MapY] == 0) Map[MapX][MapY] = WOODS+ BLN;
286 }
287}
288
289rax_SmoothRiver()
290{
291 static int DX[4] = {-1, 0, 1, 0};
292 static int DY[4] = { 0, 1, 0,-1};
293 static int REdTab[16] = { 13+BL,13+BL,17+BL,15+BL,5+BL,2,19+BL,
294 17+BL,9+BL,11+BL,2,13+BL,7+BL,9+BL,5+BL,2};
295 int bitindex, z,Xtem,Ytem;
296 register int temp,MapX,MapY;
297
298 for (MapX = 0; MapX < WORLD_X; MapX++)
299 for (MapY = 0; MapY < WORLD_Y; MapY++)
300 if (Map[MapX][MapY] == REDGE) {
301 bitindex = 0;
302 for (z=0; z<4; z++) {
303 bitindex = bitindex << 1;
304 Xtem = MapX + DX[z];
305 Ytem = MapY + DY[z];
306 if (rax_TestBounds(Xtem, Ytem))
307/* if(Map[Xtem][Ytem]) bitindex++; /* original code */
308 if((Map[Xtem][Ytem]&LOMASK) && ((Map[Xtem][Ytem]&LOMASK) < WOODS_LOW || (Map[Xtem][Ytem]&LOMASK) > WOODS_HIGH)) bitindex++; /* new code - rax */
309 }
310 temp = REdTab[bitindex & 15];
311 if ((temp != 2) && (rax_GRand(1))) temp++;
312 Map[MapX][MapY] = temp;
313 }
314 }
315
316IsTree(cell) /* return TRUE or FALSE if cell value is a tree cell */
317register int cell;
318{
319 if((cell&LOMASK) >= WOODS_LOW && (cell&LOMASK) <= WOODS_HIGH) return TRUE; else return FALSE;
320}
321
322rax_SmoothTrees()
323{
324 static int DX[4] = {-1, 0, 1, 0};
325 static int DY[4] = { 0, 1, 0,-1};
326 static int TEdTab[16] = {0,0,0,34,0,0,36,35,0,32,0,33,30,31,29,37};
327 int bitindex, z,Xtem,Ytem;
328 register int temp,MapX,MapY;
329
330 for (MapX = 0; MapX < WORLD_X; MapX++)
331 for (MapY = 0; MapY < WORLD_Y; MapY++)
332 if (IsTree(Map[MapX][MapY])) {
333 bitindex = 0;
334 for (z=0; z<4; z++) {
335 bitindex = bitindex << 1;
336 Xtem = MapX + DX[z];
337 Ytem = MapY + DY[z];
338 if (rax_TestBounds(Xtem, Ytem))
339 if(IsTree(Map[Xtem][Ytem])) bitindex++;
340
341 }
342 temp = TEdTab[bitindex & 15];
343 if (temp) {
344 if (temp != 37)
345 if ((MapX+MapY) & 1)
346 temp = temp-8;
347 Map[MapX][MapY] = temp+BLN;
348 }
349 else Map[MapX][MapY] = temp;
350 }
351 }
352
353rax_DoRivers()
354{
355 LastDir = rax_GRand(3);
356 Dir = LastDir;
357 rax_DoBRiv();
358 MapX = XStart;
359 MapY = YStart;
360 LastDir = LastDir ^ 4;
361 Dir = LastDir;
362 rax_DoBRiv();
363 MapX = XStart;
364 MapY = YStart;
365 LastDir = rax_GRand(3);
366 rax_DoSRiv();
367}
368
369rax_DoBRiv()
370{
371 while(rax_TestBounds (MapX+4, MapY+4)) {
372 rax_BRivPlop();
373 if(rax_GRand(curvLevel+10) < 10) {
374 Dir=LastDir;
375 } else {
376 if(rax_GRand(curvLevel+100) > 90) {
377 Dir++;
378 }
379 if(rax_GRand(curvLevel+100) > 90) {
380 Dir--;
381 }
382 }
383 rax_MoveMap(Dir);
384 }
385}
386
387rax_DoSRiv()
388{
389 while(rax_TestBounds (MapX+3, MapY+3)) {
390 rax_SRivPlop();
391 if(rax_GRand(curvLevel+10) < 10) {
392 Dir=LastDir;
393 } else {
394 if(rax_GRand(curvLevel+100) > 90) {
395 Dir++;
396 }
397 if(rax_GRand(curvLevel+100) > 90) {
398 Dir--;
399 }
400 }
401 rax_MoveMap(Dir);
402 }
403}
404
405rax_MoveMap (dir)
406int dir;
407{
408static int DirTab[2][8] ={ { 0, 1, 1, 1, 0, -1, -1, -1},
409 {-1,-1, 0, 1, 1, 1, 0, -1} };
410 dir = dir & 7;
411 MapX += DirTab[0][dir];
412 MapY += DirTab[1][dir];
413}
414
415
416
417
418rax_BRivPlop()
419{
420static int BRMatrix[9][9] ={
421 {0,0,0,3,3,3,0,0,0},
422 {0,0,3,2,2,2,3,0,0},
423 {0,3,2,2,2,2,2,3,0},
424 {3,2,2,2,2,2,2,2,3},
425 {3,2,2,2,4,2,2,2,3},
426 {3,2,2,2,2,2,2,2,3},
427 {0,3,2,2,2,2,2,3,0},
428 {0,0,3,2,2,2,3,0,0},
429 {0,0,0,3,3,3,0,0,0} };
430int x, y;
431
432 for (x=0; x<9; x++)
433 for (y=0; y<9; y++)
434 rax_PutOnMap (BRMatrix[y][x], x, y);
435}
436
437rax_SRivPlop()
438{
439static int SRMatrix[6][6] ={
440 {0,0,3,3,0,0},
441 {0,3,2,2,3,0},
442 {3,2,2,2,2,3},
443 {3,2,2,2,2,3},
444 {0,3,2,2,3,0},
445 {0,0,3,3,0,0} };
446int x, y;
447
448 for (x=0; x<6; x++)
449 for (y=0; y<6; y++)
450 rax_PutOnMap (SRMatrix[y][x], x, y);
451}
452
453rax_PutOnMap (Mchar, Xoff, Yoff)
454int Mchar, Xoff, Yoff;
455{
456register int Xloc, Yloc, temp;
457
458 if (Mchar == 0) return;
459 Xloc = MapX + Xoff;
460 Yloc = MapY + Yoff;
461 if (rax_TestBounds (Xloc, Yloc) == FALSE) return (FALSE);
462 if (temp = Map [Xloc][Yloc]) {
463 temp = temp & 1023;
464 if (temp == RIVER)
465 if (Mchar != CHANNEL)
466 return (FALSE);
467 if (temp == CHANNEL) return (FALSE);
468 }
469 Map [Xloc][Yloc] = Mchar;
470}
471
472rax_TestBounds(x, y)
473register int x, y;
474{
475 if ((( x >= 0) && (x < WORLD_X)) && (( y >= 0) && (y < WORLD_Y)))
476 return (TRUE);
477 return (FALSE);
478}
479
480
481
482rax_EGRand(limit)
483int limit;
484{
485 int x,z;
486
487 z= rax_GRand(limit);
488 x= rax_GRand(limit);
489 if (z < x) return(z);
490 return(x);
491}
492
493#define RANMASK 32767
494
495rax_GRand(range) /* stupid but works */
496int range;
497{
498 register x, newv, divisor;
499
500 divisor = RANMASK/ (range+1);
501 newv = 0;
502 for (x=4; x!=0; x--)
503 newv += (GRanArray[x] = GRanArray[x-1]);
504 GRanArray[0] = newv;
505 x = (newv & RANMASK) / divisor;
506 if (x > range) return(range);
507 return(x);
508}
Impressum, Datenschutz