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
68 Tk_ConfigSpec SimCamConfigSpecs
[] = {
69 {TK_CONFIG_PIXELS
, "-width", "width", "Width",
70 0, Tk_Offset(SimCam
, w_width
), 0},
71 {TK_CONFIG_PIXELS
, "-height", "height", "Height",
72 0, Tk_Offset(SimCam
, w_height
), 0},
73 {TK_CONFIG_END
, (char *) NULL
, (char *) NULL
, (char *) NULL
,
78 Tk_ConfigSpec CamConfigSpecs
[] = {
79 {TK_CONFIG_PIXELS
, "-wrap", "wrap", "Wrap",
80 0, Tk_Offset(Cam
, wrap
), 0},
81 {TK_CONFIG_PIXELS
, "-steps", "steps", "Steps",
82 0, Tk_Offset(Cam
, steps
), 0},
83 {TK_CONFIG_PIXELS
, "-frob", "frob", "Frob",
84 0, Tk_Offset(Cam
, frob
), 0},
85 {TK_CONFIG_PIXELS
, "-x", "x", "X",
86 0, Tk_Offset(Cam
, x
), 0},
87 {TK_CONFIG_PIXELS
, "-y", "y", "Y",
88 0, Tk_Offset(Cam
, y
), 0},
89 {TK_CONFIG_PIXELS
, "-width", "width", "Width",
90 0, Tk_Offset(Cam
, width
), 0},
91 {TK_CONFIG_PIXELS
, "-height", "height", "Height",
92 0, Tk_Offset(Cam
, height
), 0},
93 {TK_CONFIG_PIXELS
, "-dx", "dx", "Dx",
94 0, Tk_Offset(Cam
, dx
), 0},
95 {TK_CONFIG_PIXELS
, "-dy", "dy", "Dy",
96 0, Tk_Offset(Cam
, dy
), 0},
97 {TK_CONFIG_PIXELS
, "-gx", "gx", "Gx",
98 0, Tk_Offset(Cam
, gx
), 0},
99 {TK_CONFIG_PIXELS
, "-gy", "gy", "Gy",
100 0, Tk_Offset(Cam
, gy
), 0},
101 {TK_CONFIG_PIXELS
, "-dragging", "dragging", "Dragging",
102 0, Tk_Offset(Cam
, dragging
), 0},
103 {TK_CONFIG_PIXELS
, "-setx", "setx", "SetX",
104 "-1", Tk_Offset(Cam
, set_x
), 0},
105 {TK_CONFIG_PIXELS
, "-sety", "sety", "SetY",
106 "-1", Tk_Offset(Cam
, set_y
), 0},
107 {TK_CONFIG_PIXELS
, "-setwidth", "setwidth", "SetWidth",
108 "-1", Tk_Offset(Cam
, set_width
), 0},
109 {TK_CONFIG_PIXELS
, "-setheight", "setheight", "SetHeight",
110 "-1", Tk_Offset(Cam
, set_height
), 0},
111 {TK_CONFIG_PIXELS
, "-setx0", "setx0", "SetX0",
112 "-1", Tk_Offset(Cam
, set_x0
), 0},
113 {TK_CONFIG_PIXELS
, "-sety0", "sety0", "SetY0",
114 "-1", Tk_Offset(Cam
, set_y0
), 0},
115 {TK_CONFIG_PIXELS
, "-setx1", "setx1", "SetX1",
116 "-1", Tk_Offset(Cam
, set_x1
), 0},
117 {TK_CONFIG_PIXELS
, "-sety1", "sety1", "SetY1",
118 "-1", Tk_Offset(Cam
, set_y1
), 0},
119 {TK_CONFIG_END
, (char *) NULL
, (char *) NULL
, (char *) NULL
,
124 Tcl_HashTable CamCmds
;
130 DisplaySimCam(ClientData clientData
)
132 SimCam
*scam
= (SimCam
*) clientData
;
133 Tk_Window tkwin
= scam
->tkwin
;
137 scam
->flags
&= ~VIEW_REDRAW_PENDING
;
138 if (scam
->visible
&& (tkwin
!= NULL
) && Tk_IsMapped(tkwin
)) {
145 DestroyCam(SimCam
*scam
, Cam
*cam
)
149 for (cp
= &scam
->cam_list
;
151 cp
= &((*cp
)->next
)) {
155 if (cam
->front
!= NULL
) {
158 if (cam
->back
!= NULL
) {
159 if (cam
->back
->mem
!= NULL
) {
160 ckfree(cam
->back
->mem
);
164 if (cam
->rule
!= NULL
) {
167 if (cam
->name
!= NULL
) {
178 DestroyScam(ClientData cdata
)
180 SimCam
*scam
= (SimCam
*)cdata
;
183 CancelRedrawView(scam
);
185 while (scam
->cam_list
) {
186 DestroyCam(scam
, scam
->cam_list
);
189 for (cp
= &sim
->scam
;
191 cp
= &((*cp
)->next
)) {
199 if (scam
->shminfo
!= NULL
) {
200 XShmDetach(scam
->x
->dpy
, scam
->shminfo
);
201 shmdt(scam
->shminfo
->shmaddr
);
202 shmctl(scam
->shminfo
->shmid
, IPC_RMID
, 0);
203 ckfree(scam
->shminfo
);
204 scam
->shminfo
= NULL
;
206 scam
->image
->data
= NULL
;
208 XDestroyImage(scam
->image
);
213 if (scam
->image
->data
) {
214 ckfree(scam
->image
->data
);
215 scam
->image
->data
= NULL
;
218 XDestroyImage(scam
->image
);
223 DecRefDisplay(scam
->x
);
225 ckfree((char *) scam
);
230 CamEventProc(ClientData clientData
, XEvent
*eventPtr
)
232 SimCam
*scam
= (SimCam
*) clientData
;
234 if ((eventPtr
->type
== Expose
) && (eventPtr
->xexpose
.count
== 0)) {
236 EventuallyRedrawCam(scam
);
237 } else if (eventPtr
->type
== MapNotify
) {
239 } else if (eventPtr
->type
== UnmapNotify
) {
241 } else if (eventPtr
->type
== VisibilityNotify
) {
242 if (eventPtr
->xvisibility
.state
== VisibilityFullyObscured
)
246 } else if (eventPtr
->type
== ConfigureNotify
) {
248 eventPtr
->xconfigure
.width
,
249 eventPtr
->xconfigure
.height
);
250 EventuallyRedrawCam(scam
);
251 } else if (eventPtr
->type
== DestroyNotify
) {
252 Tcl_DeleteCommand(scam
->interp
, Tk_PathName(scam
->tkwin
));
254 if (scam
->flags
& VIEW_REDRAW_PENDING
) {
255 Tk_CancelIdleCall(DisplaySimCam
, (ClientData
) scam
);
257 Tk_EventuallyFree((ClientData
) scam
, DestroyScam
);
263 DoCamCmd(CLIENT_ARGS
)
265 SimCam
*scam
= (SimCam
*) clientData
;
274 if (ent
= Tcl_FindHashEntry(&CamCmds
, argv
[1])) {
275 cmd
= (int (*)())ent
->clientData
;
276 Tk_Preserve((ClientData
) scam
);
277 result
= cmd(scam
, interp
, argc
, argv
);
278 Tk_Release((ClientData
) scam
);
280 Tcl_AppendResult(interp
, "unknown command name: \"",
281 argv
[0], " ", argv
[1], "\".", (char *) NULL
);
291 Tk_Window tkwin
= (Tk_Window
) clientData
;
295 Tcl_AppendResult(interp
, "wrong # args: should be \"",
296 argv
[0], " pathName ?options?\"", (char *) NULL
);
300 tkwin
= Tk_CreateWindowFromPath(interp
, tkwin
,
301 argv
[1], (char *) NULL
);
306 scam
= (SimCam
*)ckalloc(sizeof (SimCam
));
317 scam
->interp
= interp
;
321 scam
->shminfo
= NULL
;
322 scam
->line_bytes
= 0;
325 scam
->cam_list
= NULL
;
327 Tk_SetClass(scam
->tkwin
, "Cam");
329 Tk_CreateEventHandler(scam
->tkwin
,
330 VisibilityChangeMask
|
332 StructureNotifyMask
|
336 CamEventProc
, (ClientData
) scam
);
337 Tcl_CreateCommand(interp
, Tk_PathName(scam
->tkwin
),
338 DoCamCmd
, (ClientData
) scam
, (void (*)()) NULL
);
340 Tk_MakeWindowExist(scam
->tkwin
);
342 if (getenv("XSYNCHRONIZE") != NULL
) {
343 XSynchronize(Tk_Display(tkwin
), 1);
349 if (ConfigureCam(interp
, scam
, argc
-2, argv
+2, 0) != TCL_OK
) {
350 /* XXX: destroy scam */
351 Tk_DestroyWindow(scam
->tkwin
);
357 interp
->result
= Tk_PathName(scam
->tkwin
);
363 ConfigureCam(Tcl_Interp
*interp
, SimCam
*scam
,
364 int argc
, char **argv
, int flags
)
366 if (Tk_ConfigureWidget(interp
, scam
->tkwin
, SimCamConfigSpecs
,
367 argc
, argv
, (char *) scam
, flags
) != TCL_OK
) {
371 if (scam
->w_width
|| scam
->w_height
) {
372 Tk_GeometryRequest(scam
->tkwin
, scam
->w_width
, scam
->w_height
);
375 EventuallyRedrawCam(scam
);
381 EventuallyRedrawCam(SimCam
*scam
)
383 if (!(scam
->flags
& VIEW_REDRAW_PENDING
)) {
384 Tk_DoWhenIdle(DisplaySimCam
, (ClientData
) scam
);
385 scam
->flags
|= VIEW_REDRAW_PENDING
;
390 CamCmdconfigure(CAM_ARGS
)
395 result
= Tk_ConfigureInfo(interp
, scam
->tkwin
, SimCamConfigSpecs
,
396 (char *) scam
, (char *) NULL
, 0);
397 } else if (argc
== 3) {
398 result
= Tk_ConfigureInfo(interp
, scam
->tkwin
, SimCamConfigSpecs
,
399 (char *) scam
, argv
[2], 0);
401 result
= ConfigureCam(interp
, scam
, argc
-2, argv
+2,
402 TK_CONFIG_ARGV_ONLY
);
408 CamCmdposition(CAM_ARGS
)
410 if ((argc
!= 2) && (argc
!= 4)) {
416 if ((Tcl_GetInt(interp
, argv
[2], &x
) != TCL_OK
)
417 || (Tcl_GetInt(interp
, argv
[3], &y
) != TCL_OK
)) {
423 sprintf(interp
->result
, "%d %d", scam
->w_x
, scam
->w_y
);
430 if ((argc
!= 2) && (argc
!= 4)) {
436 if (Tcl_GetInt(interp
, argv
[2], &w
) != TCL_OK
) {
439 if (Tcl_GetInt(interp
, argv
[3], &h
) != TCL_OK
) {
445 sprintf(interp
->result
, "%d %d", scam
->w_width
, scam
->w_height
);
450 CamCmdVisible(CAM_ARGS
)
454 if ((argc
!= 2) && (argc
!= 3)) {
459 if ((Tcl_GetInt(interp
, argv
[2], &visible
) != TCL_OK
) ||
460 (visible
< 0) || (visible
> 1)) {
464 visible
= visible
&& Tk_IsMapped(scam
->tkwin
);
465 scam
->visible
= visible
;
468 sprintf(interp
->result
, "%d", scam
->visible
);
473 CamCmdStoreColor(CAM_ARGS
)
475 int index
, r
, g
, b
, err
;
482 if ((Tcl_GetInt(interp
, argv
[2], &index
) != TCL_OK
) ||
483 (Tcl_GetInt(interp
, argv
[2], &r
) != TCL_OK
) ||
484 (Tcl_GetInt(interp
, argv
[2], &g
) != TCL_OK
) ||
485 (Tcl_GetInt(interp
, argv
[2], &b
) != TCL_OK
)) {
493 color
.flags
= DoRed
| DoGreen
| DoBlue
;
494 err
= XStoreColor(scam
->x
->dpy
, scam
->x
->colormap
, &color
);
496 sprintf(interp
->result
, "%d", err
);
501 CamCmdNewCam(CAM_ARGS
)
505 char *rule_name
= NULL
;
515 if ((Tcl_GetInt(interp
, argv
[3], &rule_number
) != TCL_OK
) ||
516 (rule_number
== 0)) {
520 if ((Tcl_GetInt(interp
, argv
[4], &x
) != TCL_OK
) ||
521 (Tcl_GetInt(interp
, argv
[5], &y
) != TCL_OK
) ||
522 (Tcl_GetInt(interp
, argv
[6], &w
) != TCL_OK
) ||
523 (Tcl_GetInt(interp
, argv
[7], &h
) != TCL_OK
)) {
527 cam
= (Cam
*)find_cam_by_name(scam
, name
);
530 DestroyCam(scam
, cam
);
533 cam
= (Cam
*)new_cam(scam
, x
, y
, w
, h
, 0, 0, NULL
);
534 cam
->name
= (char *)malloc(strlen(name
) + 1);
535 strcpy(cam
->name
, name
);
537 if (rule_name
!= NULL
) {
538 cam_load_rule(cam
, rule_name
);
540 cam_set_neighborhood(cam
, rule_number
);
543 return Tk_ConfigureWidget(interp
, scam
->tkwin
, CamConfigSpecs
,
544 argc
- 8, argv
+ 8, (char *) cam
, 0);
548 CamCmdDeleteCam(CAM_ARGS
)
559 cam
= (Cam
*)find_cam_by_name(scam
, name
);
562 DestroyCam(scam
, cam
);
569 CamCmdRandomizeCam(CAM_ARGS
)
580 cam
= (Cam
*)find_cam_by_name(scam
, name
);
590 CamCmdConfigCam(CAM_ARGS
)
599 cam
= (Cam
*)find_cam_by_name(scam
, argv
[2]);
606 result
= Tk_ConfigureInfo(interp
, scam
->tkwin
, CamConfigSpecs
,
607 (char *) cam
, (char *) NULL
, 0);
608 } else if (argc
== 4) {
609 result
= Tk_ConfigureInfo(interp
, scam
->tkwin
, CamConfigSpecs
,
610 (char *) cam
, argv
[3], 0);
612 result
= Tk_ConfigureWidget(interp
, scam
->tkwin
, CamConfigSpecs
,
613 argc
- 3, argv
+ 3, (char *) cam
, 0);
620 CamCmdFindCam(CAM_ARGS
)
629 if ((Tcl_GetInt(interp
, argv
[2], &x
) != TCL_OK
) ||
630 (Tcl_GetInt(interp
, argv
[3], &y
) != TCL_OK
)) {
634 cam
= (Cam
*)find_cam(scam
, x
, y
);
635 sprintf(interp
->result
, "%s", (cam
== NULL
) ? "" : cam
->name
);
641 CamCmdFindSomeCam(CAM_ARGS
)
650 if ((Tcl_GetInt(interp
, argv
[2], &x
) != TCL_OK
) ||
651 (Tcl_GetInt(interp
, argv
[3], &y
) != TCL_OK
)) {
655 cam
= (Cam
*)find_cam(scam
, x
, y
);
657 cam
= scam
->cam_list
;
660 sprintf(interp
->result
, "%s", (cam
== NULL
) ? "" : cam
->name
);
665 /*************************************************************************/
667 InitNewCam(SimCam
*scam
)
669 scam
->x
= (XDisplay
*)FindXDisplay(scam
->tkwin
);
670 IncRefDisplay(scam
->x
);
672 DoResizeCam(scam
, 512, 512);
678 DoResizeCam(SimCam
*scam
, int w
, int h
)
682 for (cam
= scam
->cam_list
; cam
!= NULL
; cam
= cam
->next
) {
683 if (cam
->front
->width
> w
) w
= cam
->front
->width
;
684 if (cam
->front
->height
> h
) h
= cam
->front
->height
;
690 if (scam
->shminfo
!= NULL
) {
691 XShmDetach(scam
->x
->dpy
, scam
->shminfo
);
692 shmdt(scam
->shminfo
->shmaddr
);
693 shmctl(scam
->shminfo
->shmid
, IPC_RMID
, 0);
694 ckfree(scam
->shminfo
);
695 scam
->shminfo
= NULL
;
697 scam
->image
->data
= NULL
;
699 XDestroyImage(scam
->image
);
704 if (scam
->image
->data
) {
705 ckfree(scam
->image
->data
);
706 scam
->image
->data
= NULL
;
709 XDestroyImage(scam
->image
);
714 if (scam
->x
->shared
) {
715 scam
->shminfo
= (XShmSegmentInfo
*)ckalloc(sizeof (XShmSegmentInfo
));
718 XShmCreateImage(scam
->x
->dpy
, scam
->x
->visual
, scam
->x
->depth
,
719 scam
->x
->color
? ZPixmap
: XYBitmap
,
721 scam
->w_width
, scam
->w_height
);
723 scam
->line_bytes
= scam
->image
->bytes_per_line
;
724 scam
->shminfo
->readOnly
= False
;
725 scam
->shminfo
->shmid
= shmget(IPC_PRIVATE
,
729 if (scam
->shminfo
->shmid
< 0) {
732 "Drat, Micropolis can't share memory with X display \"%s\".\n",
737 scam
->data
= (unsigned char *)shmat(scam
->shminfo
->shmid
, 0, 0);
738 scam
->image
->data
= (char *)scam
->data
;
739 if ((int)scam
->data
== -1) {
742 "Drat, Micropolis can't find any memory to share with display \"%s\".\n",
747 scam
->shminfo
->shmaddr
= (char *)scam
->data
;
748 scam
->shminfo
->readOnly
= False
;
755 old
= XSetErrorHandler(CatchXError
);
757 if (XShmAttach(scam
->x
->dpy
, scam
->shminfo
) == 0) {
759 "Drat, the X display \"%s\" can't access Micropolis's shared memory.\n",
764 XSync(scam
->x
->dpy
, False
);
766 XSetErrorHandler(old
);
776 "Falling back to the X network protocol on display \"%s\"...\n",
781 if (scam
->shminfo
->shmid
>= 0) {
782 if (scam
->shminfo
->shmaddr
) {
783 shmdt(scam
->shminfo
->shmaddr
);
785 shmctl(scam
->shminfo
->shmid
, IPC_RMID
, 0);
787 ckfree((char *)scam
->shminfo
);
788 scam
->shminfo
= NULL
;
791 scam
->image
->data
= NULL
;
792 XDestroyImage(scam
->image
);
796 scam
->line_bytes
= scam
->w_width
;
797 scam
->data
= (Byte
*)ckalloc(scam
->line_bytes
* scam
->w_height
);
799 XCreateImage(scam
->x
->dpy
, scam
->x
->visual
,
801 scam
->x
->color
? ZPixmap
: XYBitmap
,
802 0, (char *)scam
->data
,
803 scam
->w_width
, scam
->w_height
,
804 8, scam
->line_bytes
); /* XXX: handle other depths */
807 for (cam
= scam
->cam_list
; cam
!= NULL
; cam
= cam
->next
) {
808 if (cam
->x
+ cam
->front
->width
> scam
->w_width
) {
809 cam
->x
= scam
->w_width
- cam
->front
->width
;
811 if (cam
->y
+ cam
->front
->height
> scam
->w_height
) {
812 cam
->y
= scam
->w_height
- cam
->front
->height
;
814 cam
->front
->line_bytes
= scam
->line_bytes
;
815 cam
->front
->mem
= /* XXX: handle other depths */
816 (Byte
*)scam
->data
+ cam
->x
+ (scam
->line_bytes
* cam
->y
);
821 DoNewCam(SimCam
*scam
)
823 sim
->scams
++; scam
->next
= sim
->scam
; sim
->scam
= scam
;
828 DoUpdateCam(SimCam
*scam
)
830 if (!scam
->visible
) {
838 if (scam
->x
->shared
) {
839 XShmPutImage(scam
->x
->dpy
, Tk_WindowId(scam
->tkwin
), scam
->x
->gc
,
841 0, 0, scam
->w_width
, scam
->w_height
,
844 XPutImage(scam
->x
->dpy
, Tk_WindowId(scam
->tkwin
), scam
->x
->gc
,
846 0, 0, scam
->w_width
, scam
->w_height
);
854 extern int TileCamCmd(CLIENT_ARGS
);
856 Tcl_CreateCommand(tk_mainInterp
, "camview", CamCmd
,
857 (ClientData
)MainWindow
, (void (*)()) NULL
);
859 Tcl_InitHashTable(&CamCmds
, TCL_STRING_KEYS
);
861 #define CAM_CMD(name) HASHED_CMD(Cam, name)
870 CAM_CMD(RandomizeCam
);
873 CAM_CMD(FindSomeCam
);