]>
git.zerfleddert.de Git - micropolis/blob - src/sim/sim.c
4b2748c0a75563f92b8cbfe915cba660d3d92651
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;
97 int TilesAnimated
= 0;
101 char *Displays
= NULL
;
102 char *FirstDisplay
= NULL
;
114 void sim_really_exit(int val
)
122 #define COPY(FROM, TO) \
123 TO = ckalloc(strlen(FROM) + 1); \
127 #define TESTDIR(DIR, NAME) \
128 if ((stat(DIR, &statbuf) == -1) || \
129 !(S_ISDIR(statbuf.st_mode))) { \
131 "Can't find the directory \"%s\"!\n", DIR); \
133 "The environment variable \"%s\" should name a directory.\n", \
147 if ((s
= getenv("SIMHOME")) == NULL
) {
151 TESTDIR(HomeDir
, "$SIMHOME");
153 sprintf(dir
, "%s/res/", HomeDir
);
154 COPY(dir
, ResourceDir
);
155 TESTDIR(ResourceDir
, "$SIMHOME/res");
157 { extern char *TCL_Library
, *TK_Library
;
158 TCL_Library
= TK_Library
= ResourceDir
;
163 "Please check the environment or reinstall Micropolis and try again! Sorry!\n");
164 sim_exit(1); // Just sets tkMustExit and ExitReturn
168 gettimeofday(&now_time
, NULL
);
169 last_now_time
= now_time
;
176 gettimeofday(&start_time
, NULL
);
177 gettimeofday(&beat_time
, NULL
);
182 MustUpdateOptions
= 1;
187 sim_skips
= sim_skip
= 0;
223 SetGameLevelFunds(StartupGameLevel
);
229 int triedToBailOnce
= 0;
234 if (triedToBailOnce
) {
238 fprintf(stderr
, "\nMicropolis has been terminated by a signal.\n");
239 fprintf(stderr
, "Pick a window -- you're leaving!\n\n");
249 signal(SIGHUP
, (void (*)())SignalExitHandler
);
250 signal(SIGINT
, (void (*)())SignalExitHandler
);
251 signal(SIGQUIT
, (void (*)())SignalExitHandler
);
252 signal(SIGTERM
, (void (*)())SignalExitHandler
);
259 gettimeofday(&now_time
, NULL
);
261 flagBlink
= (now_time
.tv_usec
< 500000) ? 1 : -1;
263 if (SimSpeed
&& !heat_steps
) {
267 sim_update_editors();
271 sim_update_budgets();
272 sim_update_evaluations();
279 sim_update_editors(void)
283 for (view
= sim
->editor
; view
!= NULL
; view
= view
->next
) {
285 CancelRedrawView(view
);
287 DoUpdateEditor(view
);
289 EventuallyRedrawView(view
);
298 sim_update_maps(void)
303 for (view
= sim
->map
; view
!= NULL
; view
= view
->next
) {
305 NewMapFlags
[view
->map_state
] || NewMap
|| ShakeNow
;
312 //fprintf(stderr, "sim_update_maps mustUpdateMap\n");
315 if (DoUpdateMap(view
)) {
316 // CancelRedrawView(view);
317 // view->invalid = 1;
320 EventuallyRedrawView(view
);
326 for (i
= 0; i
< NMAPS
; i
++) {
333 sim_update_graphs(void)
340 sim_update_budgets(void)
342 if ((sim_skips
!= 0) &&
347 UpdateBudgetWindow();
352 sim_update_evaluations(void)
354 if ((sim_skips
!= 0) &&
365 sim_update_cams(void)
369 if ((sim_skips
!= 0) &&
374 for (scam
= sim
->scam
; scam
!= NULL
; scam
= scam
->next
) {
375 CancelRedrawView(scam
);
384 short *CellSrc
= NULL
;
385 short *CellDst
= NULL
;
387 #define SRCCOL (WORLD_Y + 2)
388 #define DSTCOL WORLD_Y
390 #define CLIPPER_LOOP_BODY(CODE) \
391 src = CellSrc; dst = CellDst; \
392 for (x = 0; x < WORLD_X;) { \
393 short nw, n, ne, w, c, e, sw, s, se; \
395 src = CellSrc + (x * SRCCOL); dst = CellDst + (x * DSTCOL); \
396 w = src[0]; c = src[SRCCOL]; e = src[2 * SRCCOL]; \
397 sw = src[1]; s = src[SRCCOL + 1]; se = src[(2 * SRCCOL) + 1]; \
399 for (y = 0; y < WORLD_Y; y++) { \
400 nw = w; w = sw; sw = src[2]; \
401 n = c; c = s; s = src[SRCCOL + 2]; \
402 ne = e; e = se; se = src[(2 * SRCCOL) + 2]; \
406 x++; /* src += SRCCOL - 3; dst += DSTCOL - 1; */ \
407 src = CellSrc + ((x + 1) * SRCCOL) - 3; dst = CellDst + ((x + 1) * DSTCOL) - 1; \
409 nw = src[1]; n = src[SRCCOL + 1]; ne = src[(2 * SRCCOL) + 1]; \
410 w = src[2]; c = src[SRCCOL + 2]; e = src[(2 * SRCCOL) + 2]; \
412 for (y = WORLD_Y - 1; y >= 0; y--) { \
413 sw = w; w = nw; nw = src[0]; \
414 s = c; c = n; n = src[SRCCOL]; \
415 se = e; e = ne; ne = src[2 * SRCCOL]; \
419 x++; /* src += SRCCOL + 3; dst += DSTCOL + 1; */ \
428 register int fl
= heat_flow
;
430 if (CellSrc
== NULL
) {
431 CellSrc
= (short *)ckalloc((WORLD_X
+ 2) * (WORLD_Y
+ 2) * sizeof (short));
432 CellDst
= &Map
[0][0];
435 src
= CellSrc
+ SRCCOL
+ 1;
439 * Copy wrapping edges:
441 * 0 ff f0 f1 ... fe ff f0
443 * 1 0f 00 01 ... 0e 0f 00
444 * 2 1f 10 11 ... 1e 1f 10
446 * ef e0 e1 ... ee ef e0
447 * h ff f0 f1 ... fe ff f0
449 * h+1 0f 00 01 ... 0e 0f 00
451 * wrap value: effect:
453 * 1 copy future=>past, no wrap
454 * 2 no copy, wrap edges
455 * 3 copy future=>past, wrap edges
456 * 4 copy future=>past, same edges
463 for (x
= 0; x
< WORLD_X
; x
++) {
464 memcpy(src
, dst
, WORLD_Y
* sizeof (short));
470 for (x
= 0; x
< WORLD_X
; x
++) {
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));
482 for (x
= 0; x
< WORLD_X
; x
++) {
483 memcpy(src
, dst
, WORLD_Y
* sizeof (short));
484 src
[-1] = src
[WORLD_Y
- 1];
485 src
[WORLD_Y
] = src
[0];
489 memcpy(CellSrc
, CellSrc
+ (SRCCOL
* WORLD_X
),
490 SRCCOL
* sizeof (short));
491 memcpy(CellSrc
+ SRCCOL
* (WORLD_X
+ 1), CellSrc
+ SRCCOL
,
492 SRCCOL
* sizeof (short));
496 src
[1 + WORLD_Y
] = dst
[WORLD_Y
- 1];
497 src
[(1 + WORLD_X
) * SRCCOL
] = dst
[(WORLD_X
- 1) * DSTCOL
];
498 src
[((2 + WORLD_X
) * SRCCOL
) - 1] = dst
[(WORLD_X
* WORLD_Y
) - 1];
499 for (x
= 0; x
< WORLD_X
; x
++) {
500 memcpy(src
, dst
, WORLD_Y
* sizeof (short));
502 src
[WORLD_Y
] = src
[WORLD_Y
- 1];
506 memcpy(CellSrc
+ (SRCCOL
* (WORLD_X
+ 1)), CellSrc
+ (SRCCOL
* WORLD_X
),
507 SRCCOL
* sizeof (short));
508 memcpy(CellSrc
, CellSrc
+ SRCCOL
,
509 SRCCOL
* sizeof (short));
518 a += nw + n + ne + w + e + sw + s + se + fl; \
519 dst[0] = ((a >> 3) & LOMASK) | \
520 (ANIMBIT | BURNBIT | BULLBIT); \
523 CLIPPER_LOOP_BODY(HEAT
);
527 #define ECOMASK 0x3fc
529 c -= fl; n -= fl; s -= fl; e -= fl; w -= fl; \
530 ne -= fl; nw -= fl; se -= fl; sw -= fl; \
533 { int sum = (c&1) + (n&1) + (s&1) + (e&1) + (w&1) + \
534 (ne&1) + (nw&1) + (se&1) + (sw&1), cell; \
535 if (((sum > 5) || (sum == 4))) { \
536 /* brian's brain */ \
537 cell = ((c <<1) & (0x3fc)) | \
538 (((((c >>1)&3) == 0) && \
539 (((n&2) + (s&2) + (e&2) + (w&2) + \
540 (ne&2) + (nw&2) + (se&2) + (sw&2)) == (2 <<1)) \
545 sum = ((n&2) + (s&2) + (e&2) + (w&2) + \
546 (ne&2) + (nw&2) + (se&2) + (sw&2)) >>1; \
547 cell = (((c ^ 2) <<1) & ECOMASK) | \
548 ((c&2) ? ((sum != 5) ? 2 : 0) \
549 : (((sum != 5) && (sum != 6)) ? 2 : 0)); \
551 dst[0] = ((fl + cell) & LOMASK) | \
552 (ANIMBIT | BURNBIT | BULLBIT); \
554 c += fl; n += fl; s += fl; e += fl; w += fl; \
555 ne += fl; nw += fl; se += fl; sw += fl;
557 CLIPPER_LOOP_BODY(ECO
);
563 sim_timeout_loop(short doSim
)
581 for (j
= 0; j
< heat_steps
; j
++) {
610 MatchArg(char *arg
, char *pat
)
612 while (*pat
&& *arg
) {
613 if (tolower(*arg
) != tolower(*pat
)) {
622 return (*arg
== '\0');
627 main(int argc
, char *argv
[])
632 printf("Welcome to X11 Multi Player Micropolis version %s by Will Wright, Don Hopkins.\n",
634 printf("Copyright (C) 2002 by Electronic Arts, Maxis. All rights reserved.\n");
638 (c
= getopt(argc
, argv
, "tcwmSR:gs:l:")) != -1) {
641 case 't': /* TTY mode */
645 case 'c': /* Create Own Colormap */
646 { extern int TK_CreateColormap
;
647 TK_CreateColormap
= 1;
651 case 'w': /* Wire Mode (don't use shared memory) */
655 case 'm': /* Multi Player Mode */
659 case 'S': /* Sugar Mode */
663 case 'R': /* Root Window ID */
672 case 'g': /* Generate New Terrain */
680 case 'l': /* Level */
683 if (MatchArg(optarg
, "easy")) {
685 } else if (MatchArg(optarg
, "medium")) {
687 } else if (MatchArg(optarg
, "hard")) {
691 if ((c
< 1) || (c
> 3)) {
694 StartupGameLevel
= c
- 1;
698 case 's': /* Scenario <name> */
704 if (MatchArg(optarg
, "Dullsville")) {
706 } else if (MatchArg(optarg
, "San_Francisco")) {
708 } else if (MatchArg(optarg
, "Hamburg")) {
710 } else if (MatchArg(optarg
, "Bern")) {
712 } else if (MatchArg(optarg
, "Tokyo")) {
714 } else if (MatchArg(optarg
, "Detroit")) {
716 } else if (MatchArg(optarg
, "Boston")) {
718 } else if (MatchArg(optarg
, "Rio_de_Janeiro")) {
722 if ((c
< 1) || (c
> 8)) {
730 case 'd': /* Display <name> */
731 { char *d
= Displays
;
734 Displays
= malloc(strlen(optarg
) + 3);
735 sprintf(Displays
, "{%s}", optarg
);
737 if (strchr(optarg
, ':') != NULL
) {
738 FirstDisplay
= malloc(strlen(optarg
) + 1);
739 strcpy(FirstDisplay
, optarg
);
741 FirstDisplay
= malloc(strlen(optarg
) + 3);
742 sprintf(FirstDisplay
, "%s:0", optarg
);
745 /* Implicitly set multi player mode if multiple displays given. */
747 Displays
= malloc(strlen(Displays
) + strlen(optarg
) + 4);
748 sprintf(Displays
, "%s {%s}", d
, optarg
);
762 if ((Startup
== -1) ||
764 /* Generate New City */
765 if ((optind
!= argc
) && (optind
!= argc
- 1)) {
768 if (optind
== argc
- 1)
769 StartupName
= argv
[optind
];
771 } else if (Startup
> 0) {
773 } else if (optind
== argc
- 1) {
776 StartupName
= argv
[optind
];
777 } else if (optind
== argc
) {
786 "usage: %s\n", argv
[0]);
788 " [-s(cenario) number|name]\n");
790 " [-g(enerate random map and start playing)\n");
792 " [-l(evel) number|name]\n");
794 " [-w(ire mode: use X11 networking without shared memory)]\n");
796 " [-t(ty mode: interactive TCL session on stdin/stdout)]\n");
798 " [-c(olormap mode: create own X11 colormap on 8 bit screens)]\n");
800 " [-S(ugar mode: enable OLPC Sugar user interface integration)]\n");
802 " [-m(ulti player mode: enable adding multiple players via X11)]\n");
806 " [SavedFileName.city]\n");
808 "The game level and NewCityName argument are optional, and only apply when\n");
810 "starting a new city or generating new terrain.\n");
812 "Game levels include: 1: Easy, 2: Medium, 3: Hard\n");
814 "Scenarios include: 1: Dullsville, 2: San_Francisco, 3: Hamburg, 4: Bern,\n");
816 " 5: Tokyo, 6: Detroit, 7: Boston, 8: Rio_de_Janeiro\n");
818 sim_exit(0); // Just sets tkMustExit and ExitReturn
822 (Displays
== NULL
)) {
823 char *d
= getenv("DISPLAY");
825 if (d
== NULL
) d
= ":0";
827 Displays
= malloc(strlen(d
) + 3);
828 sprintf(Displays
, "{%s}", d
);
829 if (strchr(d
, ':') != NULL
) {
830 FirstDisplay
= malloc(strlen(d
) + 1);
831 strcpy(FirstDisplay
, d
);
833 FirstDisplay
= malloc(strlen(d
) + 3);
834 sprintf(FirstDisplay
, "%s:0", d
);