]>
cvs.zerfleddert.de Git - micropolis/blob - src/sim/sim.c
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
65 void sim_update_evaluations(void);
66 void sim_update_editors(void);
67 void sim_update_budgets(void);
68 void sim_update_graphs(void);
69 void sim_update_maps(void);
73 char *MicropolisVersion
= "4.0";
80 int sim_paused_speed
= 3;
89 struct timeval start_time
, now_time
, beat_time
, last_now_time
;
90 char *CityFileName
= NULL
;
92 int StartupGameLevel
= 0;
93 char *StartupName
= NULL
;
95 int MultiPlayerMode
= 0;
98 int TilesAnimated
= 0;
102 char *Displays
= NULL
;
103 char *FirstDisplay
= NULL
;
115 void sim_really_exit(int val
)
123 #define COPY(FROM, TO) \
124 TO = ckalloc(strlen(FROM) + 1); \
128 #define TESTDIR(DIR, NAME) \
129 if ((stat(DIR, &statbuf) == -1) || \
130 !(S_ISDIR(statbuf.st_mode))) { \
132 "Can't find the directory \"%s\"!\n", DIR); \
134 "The environment variable \"%s\" should name a directory.\n", \
148 if ((s
= getenv("SIMHOME")) == NULL
) {
152 TESTDIR(HomeDir
, "$SIMHOME");
154 sprintf(dir
, "%s/res/", HomeDir
);
155 COPY(dir
, ResourceDir
);
156 TESTDIR(ResourceDir
, "$SIMHOME/res");
158 { extern char *TCL_Library
, *TK_Library
;
159 TCL_Library
= TK_Library
= ResourceDir
;
164 "Please check the environment or reinstall Micropolis and try again! Sorry!\n");
165 sim_exit(1); // Just sets tkMustExit and ExitReturn
169 gettimeofday(&now_time
, NULL
);
170 last_now_time
= now_time
;
177 gettimeofday(&start_time
, NULL
);
178 gettimeofday(&beat_time
, NULL
);
183 MustUpdateOptions
= 1;
188 sim_skips
= sim_skip
= 0;
224 SetGameLevelFunds(StartupGameLevel
);
230 int triedToBailOnce
= 0;
233 SignalExitHandler(int sig
)
235 if (triedToBailOnce
) {
239 fprintf(stderr
, "\nMicropolis has been terminated by a signal.\n");
240 fprintf(stderr
, "Pick a window -- you're leaving!\n\n");
250 signal(SIGHUP
, (void (*)(int))SignalExitHandler
);
251 signal(SIGINT
, (void (*)(int))SignalExitHandler
);
252 signal(SIGQUIT
, (void (*)(int))SignalExitHandler
);
253 signal(SIGTERM
, (void (*)(int))SignalExitHandler
);
260 gettimeofday(&now_time
, NULL
);
262 flagBlink
= (now_time
.tv_usec
< 500000) ? 1 : -1;
264 if (SimSpeed
&& !heat_steps
) {
268 sim_update_editors();
272 sim_update_budgets();
273 sim_update_evaluations();
280 sim_update_editors(void)
284 for (view
= sim
->editor
; view
!= NULL
; view
= view
->next
) {
286 CancelRedrawView(view
);
288 DoUpdateEditor(view
);
290 EventuallyRedrawView(view
);
299 sim_update_maps(void)
304 for (view
= sim
->map
; view
!= NULL
; view
= view
->next
) {
306 NewMapFlags
[view
->map_state
] || NewMap
|| ShakeNow
;
313 //fprintf(stderr, "sim_update_maps mustUpdateMap\n");
316 if (DoUpdateMap(view
)) {
317 // CancelRedrawView(view);
318 // view->invalid = 1;
321 EventuallyRedrawView(view
);
327 for (i
= 0; i
< NMAPS
; i
++) {
334 sim_update_graphs(void)
341 sim_update_budgets(void)
343 if ((sim_skips
!= 0) &&
348 UpdateBudgetWindow();
353 sim_update_evaluations(void)
355 if ((sim_skips
!= 0) &&
366 sim_update_cams(void)
370 if ((sim_skips
!= 0) &&
375 for (scam
= sim
->scam
; scam
!= NULL
; scam
= scam
->next
) {
376 CancelRedrawView(scam
);
385 short *CellSrc
= NULL
;
386 short *CellDst
= NULL
;
388 #define SRCCOL (WORLD_Y + 2)
389 #define DSTCOL WORLD_Y
391 #define CLIPPER_LOOP_BODY(CODE) \
392 src = CellSrc; dst = CellDst; \
393 for (x = 0; x < WORLD_X;) { \
394 short nw, n, ne, w, c, e, sw, s, se; \
396 src = CellSrc + (x * SRCCOL); dst = CellDst + (x * DSTCOL); \
397 w = src[0]; c = src[SRCCOL]; e = src[2 * SRCCOL]; \
398 sw = src[1]; s = src[SRCCOL + 1]; se = src[(2 * SRCCOL) + 1]; \
400 for (y = 0; y < WORLD_Y; y++) { \
401 nw = w; w = sw; sw = src[2]; \
402 n = c; c = s; s = src[SRCCOL + 2]; \
403 ne = e; e = se; se = src[(2 * SRCCOL) + 2]; \
407 x++; /* src += SRCCOL - 3; dst += DSTCOL - 1; */ \
408 src = CellSrc + ((x + 1) * SRCCOL) - 3; dst = CellDst + ((x + 1) * DSTCOL) - 1; \
410 nw = src[1]; n = src[SRCCOL + 1]; ne = src[(2 * SRCCOL) + 1]; \
411 w = src[2]; c = src[SRCCOL + 2]; e = src[(2 * SRCCOL) + 2]; \
413 for (y = WORLD_Y - 1; y >= 0; y--) { \
414 sw = w; w = nw; nw = src[0]; \
415 s = c; c = n; n = src[SRCCOL]; \
416 se = e; e = ne; ne = src[2 * SRCCOL]; \
420 x++; /* src += SRCCOL + 3; dst += DSTCOL + 1; */ \
429 register int fl
= heat_flow
;
431 if (CellSrc
== NULL
) {
432 CellSrc
= (short *)ckalloc((WORLD_X
+ 2) * (WORLD_Y
+ 2) * sizeof (short));
433 CellDst
= &Map
[0][0];
436 src
= CellSrc
+ SRCCOL
+ 1;
440 * Copy wrapping edges:
442 * 0 ff f0 f1 ... fe ff f0
444 * 1 0f 00 01 ... 0e 0f 00
445 * 2 1f 10 11 ... 1e 1f 10
447 * ef e0 e1 ... ee ef e0
448 * h ff f0 f1 ... fe ff f0
450 * h+1 0f 00 01 ... 0e 0f 00
452 * wrap value: effect:
454 * 1 copy future=>past, no wrap
455 * 2 no copy, wrap edges
456 * 3 copy future=>past, wrap edges
457 * 4 copy future=>past, same edges
464 for (x
= 0; x
< WORLD_X
; x
++) {
465 memcpy(src
, dst
, WORLD_Y
* sizeof (short));
471 for (x
= 0; x
< WORLD_X
; x
++) {
472 src
[-1] = src
[WORLD_Y
- 1];
473 src
[WORLD_Y
] = src
[0];
477 memcpy(CellSrc
,CellSrc
+ (SRCCOL
* WORLD_X
),
478 SRCCOL
* sizeof (short));
479 memcpy(CellSrc
+ SRCCOL
* (WORLD_X
+ 1), CellSrc
+ SRCCOL
,
480 SRCCOL
* sizeof (short));
483 for (x
= 0; x
< WORLD_X
; x
++) {
484 memcpy(src
, dst
, WORLD_Y
* sizeof (short));
485 src
[-1] = src
[WORLD_Y
- 1];
486 src
[WORLD_Y
] = src
[0];
490 memcpy(CellSrc
, CellSrc
+ (SRCCOL
* WORLD_X
),
491 SRCCOL
* sizeof (short));
492 memcpy(CellSrc
+ SRCCOL
* (WORLD_X
+ 1), CellSrc
+ SRCCOL
,
493 SRCCOL
* sizeof (short));
497 src
[1 + WORLD_Y
] = dst
[WORLD_Y
- 1];
498 src
[(1 + WORLD_X
) * SRCCOL
] = dst
[(WORLD_X
- 1) * DSTCOL
];
499 src
[((2 + WORLD_X
) * SRCCOL
) - 1] = dst
[(WORLD_X
* WORLD_Y
) - 1];
500 for (x
= 0; x
< WORLD_X
; x
++) {
501 memcpy(src
, dst
, WORLD_Y
* sizeof (short));
503 src
[WORLD_Y
] = src
[WORLD_Y
- 1];
507 memcpy(CellSrc
+ (SRCCOL
* (WORLD_X
+ 1)), CellSrc
+ (SRCCOL
* WORLD_X
),
508 SRCCOL
* sizeof (short));
509 memcpy(CellSrc
, CellSrc
+ SRCCOL
,
510 SRCCOL
* sizeof (short));
519 a += nw + n + ne + w + e + sw + s + se + fl; \
520 dst[0] = ((a >> 3) & LOMASK) | \
521 (ANIMBIT | BURNBIT | BULLBIT); \
524 CLIPPER_LOOP_BODY(HEAT
);
528 #define ECOMASK 0x3fc
530 c -= fl; n -= fl; s -= fl; e -= fl; w -= fl; \
531 ne -= fl; nw -= fl; se -= fl; sw -= fl; \
534 { int sum = (c&1) + (n&1) + (s&1) + (e&1) + (w&1) + \
535 (ne&1) + (nw&1) + (se&1) + (sw&1), cell; \
536 if (((sum > 5) || (sum == 4))) { \
537 /* brian's brain */ \
538 cell = ((c <<1) & (0x3fc)) | \
539 (((((c >>1)&3) == 0) && \
540 (((n&2) + (s&2) + (e&2) + (w&2) + \
541 (ne&2) + (nw&2) + (se&2) + (sw&2)) == (2 <<1)) \
546 sum = ((n&2) + (s&2) + (e&2) + (w&2) + \
547 (ne&2) + (nw&2) + (se&2) + (sw&2)) >>1; \
548 cell = (((c ^ 2) <<1) & ECOMASK) | \
549 ((c&2) ? ((sum != 5) ? 2 : 0) \
550 : (((sum != 5) && (sum != 6)) ? 2 : 0)); \
552 dst[0] = ((fl + cell) & LOMASK) | \
553 (ANIMBIT | BURNBIT | BULLBIT); \
555 c += fl; n += fl; s += fl; e += fl; w += fl; \
556 ne += fl; nw += fl; se += fl; sw += fl;
558 CLIPPER_LOOP_BODY(ECO
);
564 sim_timeout_loop(short doSim
)
582 for (j
= 0; j
< heat_steps
; j
++) {
611 MatchArg(char *arg
, char *pat
)
613 while (*pat
&& *arg
) {
614 if (tolower(*arg
) != tolower(*pat
)) {
623 return (*arg
== '\0');
628 main(int argc
, char *argv
[])
631 extern int isatty(int);
633 printf("Welcome to X11 Multi Player Micropolis version %s by Will Wright, Don Hopkins.\n",
635 printf("Copyright (C) 2002 by Electronic Arts, Maxis. All rights reserved.\n");
636 printf("Support for newer Unix systems and new bugs added by Michael Gernoth.\n");
640 (c
= getopt(argc
, argv
, "tcwmSR:gs:l:")) != -1) {
643 case 't': /* TTY mode */
647 case 'c': /* Create Own Colormap */
648 { extern int TK_CreateColormap
;
649 TK_CreateColormap
= 1;
653 case 'w': /* Wire Mode (don't use shared memory) */
657 case 'm': /* Multi Player Mode */
661 case 'S': /* Sugar Mode */
665 case 'R': /* Root Window ID */
674 case 'g': /* Generate New Terrain */
682 case 'l': /* Level */
685 if (MatchArg(optarg
, "easy")) {
687 } else if (MatchArg(optarg
, "medium")) {
689 } else if (MatchArg(optarg
, "hard")) {
693 if ((c
< 1) || (c
> 3)) {
696 StartupGameLevel
= c
- 1;
700 case 's': /* Scenario <name> */
706 if (MatchArg(optarg
, "Dullsville")) {
708 } else if (MatchArg(optarg
, "San_Francisco")) {
710 } else if (MatchArg(optarg
, "Hamburg")) {
712 } else if (MatchArg(optarg
, "Bern")) {
714 } else if (MatchArg(optarg
, "Tokyo")) {
716 } else if (MatchArg(optarg
, "Detroit")) {
718 } else if (MatchArg(optarg
, "Boston")) {
720 } else if (MatchArg(optarg
, "Rio_de_Janeiro")) {
724 if ((c
< 1) || (c
> 8)) {
732 case 'd': /* Display <name> */
733 { char *d
= Displays
;
736 Displays
= malloc(strlen(optarg
) + 3);
737 sprintf(Displays
, "{%s}", optarg
);
739 if (strchr(optarg
, ':') != NULL
) {
740 FirstDisplay
= malloc(strlen(optarg
) + 1);
741 strcpy(FirstDisplay
, optarg
);
743 FirstDisplay
= malloc(strlen(optarg
) + 3);
744 sprintf(FirstDisplay
, "%s:0", optarg
);
747 /* Implicitly set multi player mode if multiple displays given. */
749 Displays
= malloc(strlen(Displays
) + strlen(optarg
) + 4);
750 sprintf(Displays
, "%s {%s}", d
, optarg
);
764 if ((Startup
== -1) ||
766 /* Generate New City */
767 if ((optind
!= argc
) && (optind
!= argc
- 1)) {
770 if (optind
== argc
- 1)
771 StartupName
= argv
[optind
];
773 } else if (Startup
> 0) {
775 } else if (optind
== argc
- 1) {
778 StartupName
= argv
[optind
];
779 } else if (optind
== argc
) {
788 "usage: %s\n", argv
[0]);
790 " [-s(cenario) number|name]\n");
792 " [-g(enerate random map and start playing)\n");
794 " [-l(evel) number|name]\n");
796 " [-w(ire mode: use X11 networking without shared memory)]\n");
798 " [-t(ty mode: interactive TCL session on stdin/stdout)]\n");
800 " [-c(olormap mode: create own X11 colormap on 8 bit screens)]\n");
802 " [-S(ugar mode: enable OLPC Sugar user interface integration)]\n");
804 " [-m(ulti player mode: enable adding multiple players via X11)]\n");
808 " [SavedFileName.city]\n");
810 "The game level and NewCityName argument are optional, and only apply when\n");
812 "starting a new city or generating new terrain.\n");
814 "Game levels include: 1: Easy, 2: Medium, 3: Hard\n");
816 "Scenarios include: 1: Dullsville, 2: San_Francisco, 3: Hamburg, 4: Bern,\n");
818 " 5: Tokyo, 6: Detroit, 7: Boston, 8: Rio_de_Janeiro\n");
820 sim_exit(0); // Just sets tkMustExit and ExitReturn
824 (Displays
== NULL
)) {
825 char *d
= getenv("DISPLAY");
827 if (d
== NULL
) d
= ":0";
829 Displays
= malloc(strlen(d
) + 3);
830 sprintf(Displays
, "{%s}", d
);
831 if (strchr(d
, ':') != NULL
) {
832 FirstDisplay
= malloc(strlen(d
) + 1);
833 strcpy(FirstDisplay
, d
);
835 FirstDisplay
= malloc(strlen(d
) + 3);
836 sprintf(FirstDisplay
, "%s:0", d
);