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