]> git.zerfleddert.de Git - micropolis/blob - src/sim/s_gen.c
Makefile: Micropolis build fixes for recent macOS
[micropolis] / src / sim / s_gen.c
1 /* s_gen.c
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 #include "sim.h"
63
64
65 /* Generate Map */
66
67
68 #define WATER_LOW RIVER /* 2 */
69 #define WATER_HIGH LASTRIVEDGE /* 20 */
70 #define WOODS_LOW TREEBASE /* 21 */
71 #define WOODS_HIGH UNUSED_TRASH2 /* 39 */
72
73
74 short XStart, YStart, MapX, MapY;
75 short Dir, LastDir;
76 int TreeLevel = -1; /* level for tree creation */
77 int LakeLevel = -1; /* level for lake creation */
78 int CurveLevel = -1; /* level for river curviness */
79 int CreateIsland = -1; /* -1 => 10%, 0 => never, 1 => always */
80
81 void DoBRiv(void);
82 void DoSRiv(void);
83 void BRivPlop(void);
84 void SRivPlop(void);
85 void DoRivers(void);
86 void DoTrees(void);
87 void GetRandStart(void);
88 void MakeLakes(void);
89 void MakeIsland(void);
90 void MakeNakedIsland(void);
91 void GenerateMap(int r);
92
93
94 void
95 GenerateNewCity(void)
96 {
97 GenerateSomeCity(Rand16());
98 }
99
100
101 void
102 GenerateSomeCity(int r)
103 {
104 if (CityFileName != NULL) {
105 ckfree(CityFileName);
106 CityFileName = NULL;
107 }
108
109 gettimeofday(&start_time, NULL);
110
111 GenerateMap(r);
112 ScenarioID = 0;
113 CityTime = 0;
114 InitSimLoad = 2;
115 DoInitialEval = 0;
116
117 InitWillStuff();
118 ResetMapState();
119 ResetEditorState();
120 InvalidateEditors();
121 InvalidateMaps();
122 UpdateFunds();
123 DoSimInit();
124 Eval("UIDidGenerateNewCity");
125 Kick();
126 }
127
128
129 int
130 ERand(short limit)
131 {
132 short x, z;
133
134 z = Rand(limit);
135 x = Rand(limit);
136 if (z < x)
137 return (z);
138 return (x);
139 }
140
141
142 void
143 GenerateMap(int r)
144 {
145 SeedRand(r);
146
147 if (CreateIsland < 0) {
148 if (Rand(100) < 10) { /* chance that island is generated */
149 MakeIsland();
150 return;
151 }
152 }
153 if (CreateIsland == 1) {
154 MakeNakedIsland();
155 } else {
156 ClearMap();
157 }
158 GetRandStart();
159 if (CurveLevel != 0) {
160 DoRivers();
161 }
162 if (LakeLevel != 0) {
163 MakeLakes();
164 }
165 SmoothRiver();
166 if (TreeLevel != 0) {
167 DoTrees();
168 }
169 RandomlySeedRand();
170 }
171
172
173 void
174 ClearMap(void)
175 {
176 register short x, y;
177
178 for (x = 0; x < WORLD_X; x++)
179 for (y = 0; y < WORLD_Y; y++)
180 Map[x][y] = DIRT;
181 }
182
183
184 void
185 ClearUnnatural(void)
186 {
187 register short x, y;
188
189 for (x = 0; x < WORLD_X; x++) {
190 for (y = 0; y < WORLD_Y; y++) {
191 if (Map[x][y] > WOODS) {
192 Map[x][y] = DIRT;
193 }
194 }
195 }
196 }
197
198
199 #define RADIUS 18
200
201 void
202 MakeNakedIsland(void)
203 {
204 register int x, y;
205
206 for (x = 0; x < WORLD_X; x++)
207 for (y = 0; y < WORLD_Y; y++)
208 Map[x][y] = RIVER;
209 for (x = 5; x < WORLD_X - 5; x++)
210 for (y = 5; y < WORLD_Y - 5; y++)
211 Map[x][y] = DIRT;
212 for (x = 0; x < WORLD_X - 5; x += 2) {
213 MapX = x ;
214 MapY = ERand(RADIUS);
215 BRivPlop();
216 MapY = (WORLD_Y - 10) - ERand(RADIUS);
217 BRivPlop();
218 MapY = 0;
219 SRivPlop();
220 MapY = (WORLD_Y - 6);
221 SRivPlop();
222 }
223 for (y = 0; y < WORLD_Y - 5; y += 2) {
224 MapY = y ;
225 MapX = ERand(RADIUS);
226 BRivPlop();
227 MapX = (WORLD_X - 10) - ERand(RADIUS);
228 BRivPlop();
229 MapX = 0;
230 SRivPlop();
231 MapX = (WORLD_X - 6);
232 SRivPlop();
233 }
234 }
235
236
237 void
238 MakeIsland(void)
239 {
240 MakeNakedIsland();
241 SmoothRiver();
242 DoTrees();
243 }
244
245
246 void
247 MakeLakes(void)
248 {
249 short Lim1, Lim2, t, z;
250 register short x, y;
251
252 if (LakeLevel < 0) {
253 Lim1 = Rand(10);
254 } else {
255 Lim1 = LakeLevel / 2;
256 }
257 for (t = 0; t < Lim1; t++) {
258 x = Rand(WORLD_X - 21) + 10;
259 y = Rand(WORLD_Y - 20) + 10;
260 Lim2 = Rand(12) + 2;
261 for (z = 0; z < Lim2; z++) {
262 MapX = x - 6 + Rand(12);
263 MapY = y - 6 + Rand(12);
264 if (Rand(4))
265 SRivPlop();
266 else
267 BRivPlop();
268 }
269 }
270 }
271
272
273 void
274 GetRandStart(void)
275 {
276 XStart = 40 + Rand(WORLD_X - 80);
277 YStart = 33 + Rand(WORLD_Y - 67);
278 MapX = XStart;
279 MapY = YStart;
280 }
281
282
283 void
284 MoveMap(short dir)
285 {
286 static short DirTab[2][8] = { { 0, 1, 1, 1, 0, -1, -1, -1},
287 {-1,-1, 0, 1, 1, 1, 0, -1} };
288 dir = dir & 7;
289 MapX += DirTab[0][dir];
290 MapY += DirTab[1][dir];
291 }
292
293
294 void
295 TreeSplash(short xloc, short yloc)
296 {
297 short dis, dir;
298 register short z;
299
300 if (TreeLevel < 0) {
301 dis = Rand(150) + 50;
302 } else {
303 dis = Rand(100 + (TreeLevel * 2)) + 50;
304 }
305 MapX = xloc;
306 MapY = yloc;
307 for (z = 0; z < dis; z++) {
308 dir = Rand(7);
309 MoveMap(dir);
310 if (!(TestBounds(MapX, MapY)))
311 return;
312 if ((Map[MapX][MapY] & LOMASK) == DIRT)
313 Map[MapX][MapY] = WOODS + BLBNBIT;
314 }
315 }
316
317
318 void
319 DoTrees(void)
320 {
321 short Amount, x, xloc, yloc;
322
323 if (TreeLevel < 0) {
324 Amount = Rand(100) + 50;
325 } else {
326 Amount = TreeLevel + 3;
327 }
328 for(x = 0; x < Amount; x++) {
329 xloc = Rand(WORLD_X - 1);
330 yloc = Rand(WORLD_Y - 1);
331 TreeSplash(xloc, yloc);
332 }
333 SmoothTrees();
334 SmoothTrees();
335 }
336
337
338 void
339 SmoothRiver(void)
340 {
341 static short DX[4] = {-1, 0, 1, 0};
342 static short DY[4] = { 0, 1, 0,-1};
343 static short REdTab[16] = {
344 13+BULLBIT, 13+BULLBIT, 17+BULLBIT, 15+BULLBIT,
345 5+BULLBIT, 2, 19+BULLBIT, 17+BULLBIT,
346 9+BULLBIT, 11+BULLBIT, 2, 13+BULLBIT,
347 7+BULLBIT, 9+BULLBIT, 5+BULLBIT, 2 };
348 short bitindex, z, Xtem, Ytem;
349 register short temp, MapX, MapY;
350
351 for (MapX = 0; MapX < WORLD_X; MapX++) {
352 for (MapY = 0; MapY < WORLD_Y; MapY++) {
353 if (Map[MapX][MapY] == REDGE) {
354 bitindex = 0;
355 for (z = 0; z < 4; z++) {
356 bitindex = bitindex << 1;
357 Xtem = MapX + DX[z];
358 Ytem = MapY + DY[z];
359 if (TestBounds(Xtem, Ytem) &&
360 ((Map[Xtem][Ytem] & LOMASK) != DIRT) &&
361 (((Map[Xtem][Ytem]&LOMASK) < WOODS_LOW) ||
362 ((Map[Xtem][Ytem]&LOMASK) > WOODS_HIGH)))
363 bitindex++;
364 }
365 temp = REdTab[bitindex & 15];
366 if ((temp != RIVER) && (Rand(1)))
367 temp++;
368 Map[MapX][MapY] = temp;
369 }
370 }
371 }
372 }
373
374
375 int
376 IsTree(int cell)
377 {
378 if (((cell & LOMASK) >= WOODS_LOW) &&
379 ((cell & LOMASK) <= WOODS_HIGH))
380 return TRUE;
381 return FALSE;
382 }
383
384
385 void
386 SmoothTrees(void)
387 {
388 static short DX[4] = {-1, 0, 1, 0};
389 static short DY[4] = { 0, 1, 0,-1};
390 static short TEdTab[16] = { 0, 0, 0, 34,
391 0, 0, 36, 35,
392 0, 32, 0, 33,
393 30, 31, 29, 37 };
394 short bitindex, z, Xtem, Ytem;
395 register short temp, MapX, MapY;
396
397 for (MapX = 0; MapX < WORLD_X; MapX++) {
398 for (MapY = 0; MapY < WORLD_Y; MapY++) {
399 if (IsTree(Map[MapX][MapY])) {
400 bitindex = 0;
401 for (z = 0; z < 4; z++) {
402 bitindex = bitindex << 1;
403 Xtem = MapX + DX[z];
404 Ytem = MapY + DY[z];
405 if (TestBounds(Xtem, Ytem) &&
406 IsTree(Map[Xtem][Ytem])) {
407 bitindex++;
408 }
409 }
410 temp = TEdTab[bitindex & 15];
411 if (temp) {
412 if (temp != WOODS)
413 if ((MapX + MapY) & 1)
414 temp = temp - 8;
415 Map[MapX][MapY] = temp + BLBNBIT;
416 }
417 else Map[MapX][MapY] = temp;
418 }
419 }
420 }
421 }
422
423
424 void
425 DoRivers(void)
426 {
427
428 LastDir = Rand(3);
429 Dir = LastDir;
430 DoBRiv();
431 MapX = XStart;
432 MapY = YStart;
433 LastDir = LastDir ^ 4;
434 Dir = LastDir;
435 DoBRiv();
436 MapX = XStart;
437 MapY = YStart;
438 LastDir = Rand(3);
439 DoSRiv();
440 }
441
442
443 void
444 DoBRiv(void)
445 {
446 int r1, r2;
447
448 if (CurveLevel < 0) {
449 r1 = 100;
450 r2 = 200;
451 } else {
452 r1 = CurveLevel + 10;
453 r2 = CurveLevel + 100;
454 }
455
456 while (TestBounds (MapX + 4, MapY + 4)) {
457 BRivPlop();
458 if (Rand(r1) < 10) {
459 Dir = LastDir;
460 } else {
461 if (Rand(r2) > 90) Dir++;
462 if (Rand(r2) > 90) Dir--;
463 }
464 MoveMap(Dir);
465 }
466 }
467
468
469 void
470 DoSRiv(void)
471 {
472 int r1, r2;
473
474 if (CurveLevel < 0) {
475 r1 = 100;
476 r2 = 200;
477 } else {
478 r1 = CurveLevel + 10;
479 r2 = CurveLevel + 100;
480 }
481
482 while (TestBounds (MapX + 3, MapY + 3)) {
483 SRivPlop();
484 if (Rand(r1) < 10) {
485 Dir = LastDir;
486 } else {
487 if (Rand(r2) > 90) Dir++;
488 if (Rand(r2) > 90) Dir--;
489 }
490 MoveMap(Dir);
491 }
492 }
493
494
495 void
496 PutOnMap(short Mchar, short Xoff, short Yoff)
497 {
498 register short Xloc, Yloc, temp;
499
500 if (Mchar == 0)
501 return;
502 Xloc = MapX + Xoff;
503 Yloc = MapY + Yoff;
504 if (TestBounds(Xloc, Yloc) == FALSE)
505 return;
506 if ((temp = Map[Xloc][Yloc])) {
507 temp = temp & LOMASK;
508 if (temp == RIVER)
509 if (Mchar != CHANNEL)
510 return;
511 if (temp == CHANNEL)
512 return;
513 }
514 Map[Xloc][Yloc] = Mchar;
515 }
516
517
518 void
519 BRivPlop(void)
520 {
521 static short BRMatrix[9][9] = {
522 { 0, 0, 0, 3, 3, 3, 0, 0, 0 },
523 { 0, 0, 3, 2, 2, 2, 3, 0, 0 },
524 { 0, 3, 2, 2, 2, 2, 2, 3, 0 },
525 { 3, 2, 2, 2, 2, 2, 2, 2, 3 },
526 { 3, 2, 2, 2, 4, 2, 2, 2, 3 },
527 { 3, 2, 2, 2, 2, 2, 2, 2, 3 },
528 { 0, 3, 2, 2, 2, 2, 2, 3, 0 },
529 { 0, 0, 3, 2, 2, 2, 3, 0, 0 },
530 { 0, 0, 0, 3, 3, 3, 0, 0, 0 } };
531 short x, y;
532
533 for (x = 0; x < 9; x++)
534 for (y = 0; y < 9; y++)
535 PutOnMap(BRMatrix[y][x], x, y);
536 }
537
538
539 void
540 SRivPlop(void)
541 {
542 static short SRMatrix[6][6] = {
543 { 0, 0, 3, 3, 0, 0 },
544 { 0, 3, 2, 2, 3, 0 },
545 { 3, 2, 2, 2, 2, 3 },
546 { 3, 2, 2, 2, 2, 3 },
547 { 0, 3, 2, 2, 3, 0 },
548 { 0, 0, 3, 3, 0, 0 } };
549 short x, y;
550
551 for (x = 0; x < 6; x++)
552 for (y = 0; y < 6; y++)
553 PutOnMap(SRMatrix[y][x], x, y);
554 }
555
556
557 void
558 SmoothWater(void)
559 {
560 int x, y;
561
562 for(x = 0; x < WORLD_X; x++) {
563 for(y = 0; y < WORLD_Y; y++) {
564 /* If water: */
565 if (((Map[x][y] & LOMASK) >= WATER_LOW) &&
566 ((Map[x][y] & LOMASK) <= WATER_HIGH)) {
567 if (x > 0) {
568 /* If nearest object is not water: */
569 if (((Map[x - 1][y] & LOMASK) < WATER_LOW) ||
570 ((Map[x - 1][y] & LOMASK) > WATER_HIGH)) {
571 goto edge;
572 }
573 }
574 if (x < (WORLD_X - 1)) {
575 /* If nearest object is not water: */
576 if (((Map[x+1][y]&LOMASK) < WATER_LOW) ||
577 ((Map[x+1][y]&LOMASK) > WATER_HIGH)) {
578 goto edge;
579 }
580 }
581 if (y > 0) {
582 /* If nearest object is not water: */
583 if (((Map[x][y - 1] & LOMASK) < WATER_LOW) ||
584 ((Map[x][y-1]&LOMASK) > WATER_HIGH)) {
585 goto edge;
586 }
587 }
588 if (y < (WORLD_Y - 1)) {
589 /* If nearest object is not water: */
590 if (((Map[x][y + 1] & LOMASK) < WATER_LOW) ||
591 ((Map[x][y + 1] & LOMASK) > WATER_HIGH)) {
592 edge:
593 Map[x][y]=REDGE; /* set river edge */
594 continue;
595 }
596 }
597 }
598 }
599 }
600 for (x = 0; x < WORLD_X; x++) {
601 for (y = 0; y < WORLD_Y; y++) {
602 /* If water which is not a channel: */
603 if (((Map[x][y] & LOMASK) != CHANNEL) &&
604 ((Map[x][y] & LOMASK) >= WATER_LOW) &&
605 ((Map[x][y] & LOMASK) <= WATER_HIGH)) {
606 if (x > 0) {
607 /* If nearest object is not water; */
608 if (((Map[x - 1][y] & LOMASK) < WATER_LOW) ||
609 ((Map[x - 1][y] & LOMASK) > WATER_HIGH)) {
610 continue;
611 }
612 }
613 if (x < (WORLD_X - 1)) {
614 /* If nearest object is not water: */
615 if (((Map[x + 1][y] & LOMASK) < WATER_LOW) ||
616 ((Map[x + 1][y] & LOMASK) > WATER_HIGH)) {
617 continue;
618 }
619 }
620 if (y > 0) {
621 /* If nearest object is not water: */
622 if (((Map[x][y - 1] & LOMASK) < WATER_LOW) ||
623 ((Map[x][y - 1] & LOMASK) > WATER_HIGH)) {
624 continue;
625 }
626 }
627 if (y < (WORLD_Y - 1)) {
628 /* If nearest object is not water: */
629 if (((Map[x][y + 1] & LOMASK) < WATER_LOW) ||
630 ((Map[x][y + 1] & LOMASK) > WATER_HIGH)) {
631 continue;
632 }
633 }
634 Map[x][y] = RIVER; /* make it a river */
635 }
636 }
637 }
638 for (x = 0; x < WORLD_X; x++) {
639 for (y = 0; y < WORLD_Y; y++) {
640 /* If woods: */
641 if (((Map[x][y] & LOMASK) >= WOODS_LOW) &&
642 ((Map[x][y] & LOMASK) <= WOODS_HIGH)) {
643 if (x > 0) {
644 /* If nearest object is water: */
645 if ((Map[x - 1][y] == RIVER) ||
646 (Map[x - 1][y] == CHANNEL)) {
647 Map[x][y] = REDGE; /* make it water's edge */
648 continue;
649 }
650 }
651 if (x < (WORLD_X - 1)) {
652 /* If nearest object is water: */
653 if ((Map[x + 1][y] == RIVER) ||
654 (Map[x + 1][y] == CHANNEL)) {
655 Map[x][y] = REDGE; /* make it water's edge */
656 continue;
657 }
658 }
659 if (y > 0) {
660 /* If nearest object is water: */
661 if ((Map[x][y - 1] == RIVER) ||
662 (Map[x][y - 1] == CHANNEL)) {
663 Map[x][y] = REDGE; /* make it water's edge */
664 continue;
665 }
666 }
667 if (y < (WORLD_Y - 1)) {
668 /* If nearest object is water; */
669 if ((Map[x][y + 1] == RIVER) ||
670 (Map[x][y + 1] == CHANNEL)) {
671 Map[x][y] = REDGE; /* make it water's edge */
672 continue;
673 }
674 }
675 }
676 }
677 }
678 }
Impressum, Datenschutz