]> git.zerfleddert.de Git - micropolis/blame - src/sim/s_gen.c
XINCLUDE: use /usr/X11R6/include everywhere
[micropolis] / src / sim / s_gen.c
CommitLineData
6a5fa4e0
MG
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
74short XStart, YStart, MapX, MapY;
75short Dir, LastDir;
76int TreeLevel = -1; /* level for tree creation */
77int LakeLevel = -1; /* level for lake creation */
78int CurveLevel = -1; /* level for river curviness */
79int CreateIsland = -1; /* -1 => 10%, 0 => never, 1 => always */
80
6f214ac0
MG
81void DoBRiv(void);
82void DoSRiv(void);
83void BRivPlop(void);
84void SRivPlop(void);
85void DoRivers(void);
86void DoTrees(void);
87void GetRandStart(void);
88void MakeLakes(void);
89void MakeIsland(void);
90void MakeNakedIsland(void);
91void GenerateMap(int r);
92
93
94void
6a5fa4e0
MG
95GenerateNewCity(void)
96{
97 GenerateSomeCity(Rand16());
98}
99
100
6f214ac0 101void
6a5fa4e0
MG
102GenerateSomeCity(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
6f214ac0 129int
6a5fa4e0
MG
130ERand(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
6f214ac0 142void
6a5fa4e0
MG
143GenerateMap(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
6f214ac0 173void
6a5fa4e0
MG
174ClearMap(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
6f214ac0 184void
6a5fa4e0
MG
185ClearUnnatural(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
6f214ac0
MG
201void
202MakeNakedIsland(void)
6a5fa4e0
MG
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
6f214ac0 237void
6a5fa4e0
MG
238MakeIsland(void)
239{
240 MakeNakedIsland();
241 SmoothRiver();
242 DoTrees();
243}
244
245
6f214ac0 246void
6a5fa4e0
MG
247MakeLakes(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
6f214ac0 273void
6a5fa4e0
MG
274GetRandStart(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
6f214ac0 283void
6a5fa4e0
MG
284MoveMap(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
6f214ac0 294void
6a5fa4e0
MG
295TreeSplash(short xloc, short yloc)
296{
297 short dis, dir;
6f214ac0 298 register short z;
6a5fa4e0
MG
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
6f214ac0 318void
6a5fa4e0
MG
319DoTrees(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
6f214ac0 338void
6a5fa4e0
MG
339SmoothRiver(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
6f214ac0 375int
6a5fa4e0
MG
376IsTree(int cell)
377{
378 if (((cell & LOMASK) >= WOODS_LOW) &&
379 ((cell & LOMASK) <= WOODS_HIGH))
380 return TRUE;
381 return FALSE;
382}
383
384
6f214ac0 385void
6a5fa4e0
MG
386SmoothTrees(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
6f214ac0 424void
6a5fa4e0
MG
425DoRivers(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
6f214ac0 443void
6a5fa4e0
MG
444DoBRiv(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
6f214ac0 469void
6a5fa4e0
MG
470DoSRiv(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
6f214ac0 495void
6a5fa4e0
MG
496PutOnMap(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;
6f214ac0 506 if ((temp = Map[Xloc][Yloc])) {
6a5fa4e0
MG
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
6f214ac0 518void
6a5fa4e0
MG
519BRivPlop(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
6f214ac0 539void
6a5fa4e0
MG
540SRivPlop(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
6f214ac0
MG
557void
558SmoothWater(void)
6a5fa4e0
MG
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