]>
git.zerfleddert.de Git - micropolis/blob - src/sim/sim.c
79a7817903ecc907a10208e5ecf3e015edbf99ca
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.
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.
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/>.
21 * ADDITIONAL TERMS per GNU GPL Section 7
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.
29 * Any propagation or conveyance of this program must include this
30 * copyright notice and these terms.
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.
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.
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
67 char *MicropolisVersion
= "4.0";
74 int sim_paused_speed
= 3;
83 struct timeval start_time
, now_time
, beat_time
, last_now_time
;
84 char *CityFileName
= NULL
;
86 int StartupGameLevel
= 0;
87 char *StartupName
= NULL
;
89 int MultiPlayerMode
= 0;
91 int TilesAnimated
= 0;
95 char *Displays
= NULL
;
96 char *FirstDisplay
= NULL
;
107 sim_really_exit(int val
)
115 #define COPY(FROM, TO) \
116 TO = ckalloc(strlen(FROM) + 1); \
120 #define TESTDIR(DIR, NAME) \
121 if ((stat(DIR, &statbuf) == -1) || \
122 !(S_ISDIR(statbuf.st_mode))) { \
124 "Can't find the directory \"%s\"!\n", DIR); \
126 "The environment variable \"%s\" should name a directory.\n", \
140 if ((s
= getenv("SIMHOME")) == NULL
) {
144 TESTDIR(HomeDir
, "$SIMHOME");
146 sprintf(dir
, "%s/res/", HomeDir
);
147 COPY(dir
, ResourceDir
);
148 TESTDIR(ResourceDir
, "$SIMHOME/res");
150 { extern char *TCL_Library
, *TK_Library
;
151 TCL_Library
= TK_Library
= ResourceDir
;
156 "Please check the environment or reinstall Micropolis and try again! Sorry!\n");
157 sim_exit(1); // Just sets tkMustExit and ExitReturn
161 gettimeofday(&now_time
, NULL
);
162 last_now_time
= now_time
;
169 gettimeofday(&start_time
, NULL
);
170 gettimeofday(&beat_time
, NULL
);
175 MustUpdateOptions
= 1;
180 sim_skips
= sim_skip
= 0;
216 SetGameLevelFunds(StartupGameLevel
);
222 int triedToBailOnce
= 0;
227 if (triedToBailOnce
) {
231 fprintf(stderr
, "\nMicropolis has been terminated by a signal.\n");
232 fprintf(stderr
, "Pick a window -- you're leaving!\n\n");
241 signal(SIGHUP
, (void (*)())SignalExitHandler
);
242 signal(SIGINT
, (void (*)())SignalExitHandler
);
243 signal(SIGQUIT
, (void (*)())SignalExitHandler
);
244 signal(SIGTERM
, (void (*)())SignalExitHandler
);
251 gettimeofday(&now_time
, NULL
);
253 flagBlink
= (now_time
.tv_usec
< 500000) ? 1 : -1;
255 if (SimSpeed
&& !heat_steps
) {
259 sim_update_editors();
263 sim_update_budgets();
264 sim_update_evaluations();
270 sim_update_editors(void)
274 for (view
= sim
->editor
; view
!= NULL
; view
= view
->next
) {
276 CancelRedrawView(view
);
278 DoUpdateEditor(view
);
280 EventuallyRedrawView(view
);
288 sim_update_maps(void)
293 for (view
= sim
->map
; view
!= NULL
; view
= view
->next
) {
295 NewMapFlags
[view
->map_state
] || NewMap
|| ShakeNow
;
302 //fprintf(stderr, "sim_update_maps mustUpdateMap\n");
305 if (DoUpdateMap(view
)) {
306 // CancelRedrawView(view);
307 // view->invalid = 1;
310 EventuallyRedrawView(view
);
316 for (i
= 0; i
< NMAPS
; i
++) {
322 sim_update_graphs(void)
328 sim_update_budgets(void)
330 if ((sim_skips
!= 0) &&
335 UpdateBudgetWindow();
339 sim_update_evaluations(void)
341 if ((sim_skips
!= 0) &&
352 sim_update_cams(void)
356 if ((sim_skips
!= 0) &&
361 for (scam
= sim
->scam
; scam
!= NULL
; scam
= scam
->next
) {
362 CancelRedrawView(scam
);
371 short *CellSrc
= NULL
;
372 short *CellDst
= NULL
;
374 #define SRCCOL (WORLD_Y + 2)
375 #define DSTCOL WORLD_Y
377 #define CLIPPER_LOOP_BODY(CODE) \
378 src = CellSrc; dst = CellDst; \
379 for (x = 0; x < WORLD_X;) { \
380 short nw, n, ne, w, c, e, sw, s, se; \
382 src = CellSrc + (x * SRCCOL); dst = CellDst + (x * DSTCOL); \
383 w = src[0]; c = src[SRCCOL]; e = src[2 * SRCCOL]; \
384 sw = src[1]; s = src[SRCCOL + 1]; se = src[(2 * SRCCOL) + 1]; \
386 for (y = 0; y < WORLD_Y; y++) { \
387 nw = w; w = sw; sw = src[2]; \
388 n = c; c = s; s = src[SRCCOL + 2]; \
389 ne = e; e = se; se = src[(2 * SRCCOL) + 2]; \
393 x++; /* src += SRCCOL - 3; dst += DSTCOL - 1; */ \
394 src = CellSrc + ((x + 1) * SRCCOL) - 3; dst = CellDst + ((x + 1) * DSTCOL) - 1; \
396 nw = src[1]; n = src[SRCCOL + 1]; ne = src[(2 * SRCCOL) + 1]; \
397 w = src[2]; c = src[SRCCOL + 2]; e = src[(2 * SRCCOL) + 2]; \
399 for (y = WORLD_Y - 1; y >= 0; y--) { \
400 sw = w; w = nw; nw = src[0]; \
401 s = c; c = n; n = src[SRCCOL]; \
402 se = e; e = ne; ne = src[2 * SRCCOL]; \
406 x++; /* src += SRCCOL + 3; dst += DSTCOL + 1; */ \
412 int x
, y
, l
, r
, u
, d
;
415 register int fl
= heat_flow
;
417 if (CellSrc
== NULL
) {
418 CellSrc
= (short *)ckalloc((WORLD_X
+ 2) * (WORLD_Y
+ 2) * sizeof (short));
419 CellDst
= &Map
[0][0];
422 src
= CellSrc
+ SRCCOL
+ 1;
426 * Copy wrapping edges:
428 * 0 ff f0 f1 ... fe ff f0
430 * 1 0f 00 01 ... 0e 0f 00
431 * 2 1f 10 11 ... 1e 1f 10
433 * ef e0 e1 ... ee ef e0
434 * h ff f0 f1 ... fe ff f0
436 * h+1 0f 00 01 ... 0e 0f 00
438 * wrap value: effect:
440 * 1 copy future=>past, no wrap
441 * 2 no copy, wrap edges
442 * 3 copy future=>past, wrap edges
443 * 4 copy future=>past, same edges
450 for (x
= 0; x
< WORLD_X
; x
++) {
451 memcpy(src
, dst
, WORLD_Y
* sizeof (short));
457 for (x
= 0; x
< WORLD_X
; x
++) {
458 src
[-1] = src
[WORLD_Y
- 1];
459 src
[WORLD_Y
] = src
[0];
463 memcpy(CellSrc
,CellSrc
+ (SRCCOL
* WORLD_X
),
464 SRCCOL
* sizeof (short));
465 memcpy(CellSrc
+ SRCCOL
* (WORLD_X
+ 1), CellSrc
+ SRCCOL
,
466 SRCCOL
* sizeof (short));
469 for (x
= 0; x
< WORLD_X
; x
++) {
470 memcpy(src
, dst
, WORLD_Y
* sizeof (short));
471 src
[-1] = src
[WORLD_Y
- 1];
472 src
[WORLD_Y
] = src
[0];
476 memcpy(CellSrc
, CellSrc
+ (SRCCOL
* WORLD_X
),
477 SRCCOL
* sizeof (short));
478 memcpy(CellSrc
+ SRCCOL
* (WORLD_X
+ 1), CellSrc
+ SRCCOL
,
479 SRCCOL
* sizeof (short));
483 src
[1 + WORLD_Y
] = dst
[WORLD_Y
- 1];
484 src
[(1 + WORLD_X
) * SRCCOL
] = dst
[(WORLD_X
- 1) * DSTCOL
];
485 src
[((2 + WORLD_X
) * SRCCOL
) - 1] = dst
[(WORLD_X
* WORLD_Y
) - 1];
486 for (x
= 0; x
< WORLD_X
; x
++) {
487 memcpy(src
, dst
, WORLD_Y
* sizeof (short));
489 src
[WORLD_Y
] = src
[WORLD_Y
- 1];
493 memcpy(CellSrc
+ (SRCCOL
* (WORLD_X
+ 1)), CellSrc
+ (SRCCOL
* WORLD_X
),
494 SRCCOL
* sizeof (short));
495 memcpy(CellSrc
, CellSrc
+ SRCCOL
,
496 SRCCOL
* sizeof (short));
505 a += nw + n + ne + w + e + sw + s + se + fl; \
506 dst[0] = ((a >> 3) & LOMASK) | \
507 (ANIMBIT | BURNBIT | BULLBIT); \
510 CLIPPER_LOOP_BODY(HEAT
);
514 #define ECOMASK 0x3fc
516 c -= fl; n -= fl; s -= fl; e -= fl; w -= fl; \
517 ne -= fl; nw -= fl; se -= fl; sw -= fl; \
520 { int sum = (c&1) + (n&1) + (s&1) + (e&1) + (w&1) + \
521 (ne&1) + (nw&1) + (se&1) + (sw&1), cell; \
522 if (((sum > 5) || (sum == 4))) { \
523 /* brian's brain */ \
524 cell = ((c <<1) & (0x3fc)) | \
525 (((((c >>1)&3) == 0) && \
526 (((n&2) + (s&2) + (e&2) + (w&2) + \
527 (ne&2) + (nw&2) + (se&2) + (sw&2)) == (2 <<1)) \
532 sum = ((n&2) + (s&2) + (e&2) + (w&2) + \
533 (ne&2) + (nw&2) + (se&2) + (sw&2)) >>1; \
534 cell = (((c ^ 2) <<1) & ECOMASK) | \
535 ((c&2) ? ((sum != 5) ? 2 : 0) \
536 : (((sum != 5) && (sum != 6)) ? 2 : 0)); \
538 dst[0] = ((fl + cell) & LOMASK) | \
539 (ANIMBIT | BURNBIT | BULLBIT); \
541 c += fl; n += fl; s += fl; e += fl; w += fl; \
542 ne += fl; nw += fl; se += fl; sw += fl;
544 CLIPPER_LOOP_BODY(ECO
);
551 sim_timeout_loop(short doSim
)
568 for (j
= 0; j
< heat_steps
; j
++) {
597 MatchArg(char *arg
, char *pat
)
599 while (*pat
&& *arg
) {
600 if (tolower(*arg
) != tolower(*pat
)) {
609 return (*arg
== '\0');
614 main(int argc
, char *argv
[])
619 printf("Welcome to X11 Multi Player Micropolis version %s by Will Wright, Don Hopkins.\n",
621 printf("Copyright (C) 2002 by Electronic Arts, Maxis. All rights reserved.\n");
625 (c
= getopt(argc
, argv
, "tcwmSR:gs:l:")) != -1) {
628 case 't': /* TTY mode */
632 case 'c': /* Create Own Colormap */
633 { extern int TK_CreateColormap
;
634 TK_CreateColormap
= 1;
638 case 'w': /* Wire Mode (don't use shared memory) */
642 case 'm': /* Multi Player Mode */
646 case 'S': /* Sugar Mode */
650 case 'R': /* Root Window ID */
659 case 'g': /* Generate New Terrain */
667 case 'l': /* Level */
670 if (MatchArg(optarg
, "easy")) {
672 } else if (MatchArg(optarg
, "medium")) {
674 } else if (MatchArg(optarg
, "hard")) {
678 if ((c
< 1) || (c
> 3)) {
681 StartupGameLevel
= c
- 1;
685 case 's': /* Scenario <name> */
691 if (MatchArg(optarg
, "Dullsville")) {
693 } else if (MatchArg(optarg
, "San_Francisco")) {
695 } else if (MatchArg(optarg
, "Hamburg")) {
697 } else if (MatchArg(optarg
, "Bern")) {
699 } else if (MatchArg(optarg
, "Tokyo")) {
701 } else if (MatchArg(optarg
, "Detroit")) {
703 } else if (MatchArg(optarg
, "Boston")) {
705 } else if (MatchArg(optarg
, "Rio_de_Janeiro")) {
709 if ((c
< 1) || (c
> 8)) {
717 case 'd': /* Display <name> */
718 { char *d
= Displays
;
721 Displays
= malloc(strlen(optarg
) + 3);
722 sprintf(Displays
, "{%s}", optarg
);
724 if (strchr(optarg
, ':') != NULL
) {
725 FirstDisplay
= malloc(strlen(optarg
) + 1);
726 strcpy(FirstDisplay
, optarg
);
728 FirstDisplay
= malloc(strlen(optarg
) + 3);
729 sprintf(FirstDisplay
, "%s:0", optarg
);
732 /* Implicitly set multi player mode if multiple displays given. */
734 Displays
= malloc(strlen(Displays
) + strlen(optarg
) + 4);
735 sprintf(Displays
, "%s {%s}", d
, optarg
);
749 if ((Startup
== -1) ||
751 /* Generate New City */
752 if ((optind
!= argc
) && (optind
!= argc
- 1)) {
755 if (optind
== argc
- 1)
756 StartupName
= argv
[optind
];
758 } else if (Startup
> 0) {
760 } else if (optind
== argc
- 1) {
763 StartupName
= argv
[optind
];
764 } else if (optind
== argc
) {
773 "usage: %s\n", argv
[0]);
775 " [-s(cenario) number|name]\n");
777 " [-g(enerate random map and start playing)\n");
779 " [-l(evel) number|name]\n");
781 " [-w(ire mode: use X11 networking without shared memory)]\n");
783 " [-t(ty mode: interactive TCL session on stdin/stdout)]\n");
785 " [-c(olormap mode: create own X11 colormap on 8 bit screens)]\n");
787 " [-S(ugar mode: enable OLPC Sugar user interface integration)]\n");
789 " [-m(ulti player mode: enable adding multiple players via X11)]\n");
793 " [SavedFileName.city]\n");
795 "The game level and NewCityName argument are optional, and only apply when\n");
797 "starting a new city or generating new terrain.\n");
799 "Game levels include: 1: Easy, 2: Medium, 3: Hard\n");
801 "Scenarios include: 1: Dullsville, 2: San_Francisco, 3: Hamburg, 4: Bern,\n");
803 " 5: Tokyo, 6: Detroit, 7: Boston, 8: Rio_de_Janeiro\n");
805 sim_exit(0); // Just sets tkMustExit and ExitReturn
809 (Displays
== NULL
)) {
810 char *d
= getenv("DISPLAY");
812 if (d
== NULL
) d
= ":0";
814 Displays
= malloc(strlen(d
) + 3);
815 sprintf(Displays
, "{%s}", d
);
816 if (strchr(d
, ':') != NULL
) {
817 FirstDisplay
= malloc(strlen(d
) + 1);
818 strcpy(FirstDisplay
, d
);
820 FirstDisplay
= malloc(strlen(d
) + 3);
821 sprintf(FirstDisplay
, "%s:0", d
);