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 Tcl_HashTable MapCmds
;
68 extern Tk_ConfigSpec TileViewConfigSpecs
[];
72 void DrawMapInk(SimView
*view
);
73 void WireDrawMap(SimView
*view
);
74 void DrawMapEditorViews(SimView
*view
);
78 MapCmdconfigure(VIEW_ARGS
)
83 result
= Tk_ConfigureInfo(interp
, view
->tkwin
, TileViewConfigSpecs
,
84 (char *) view
, (char *) NULL
, 0);
85 } else if (argc
== 3) {
86 result
= Tk_ConfigureInfo(interp
, view
->tkwin
, TileViewConfigSpecs
,
87 (char *) view
, argv
[2], 0);
89 result
= ConfigureTileView(interp
, view
, argc
-2, argv
+2,
96 MapCmdposition(VIEW_ARGS
)
98 if ((argc
!= 2) && (argc
!= 4)) {
102 if ((Tcl_GetInt(interp
, argv
[2], &view
->w_x
) != TCL_OK
)
103 || (Tcl_GetInt(interp
, argv
[3], &view
->w_y
) != TCL_OK
)) {
107 sprintf(interp
->result
, "%d %d", view
->w_x
, view
->w_y
);
112 MapCmdsize(VIEW_ARGS
)
114 if ((argc
!= 2) && (argc
!= 4)) {
120 if (Tcl_GetInt(interp
, argv
[2], &w
) != TCL_OK
) {
123 if (Tcl_GetInt(interp
, argv
[3], &h
) != TCL_OK
) {
129 sprintf(interp
->result
, "%d %d", view
->w_width
, view
->w_height
);
134 MapCmdMapState(VIEW_ARGS
)
138 if ((argc
!= 2) && (argc
!= 3)) {
143 if ((Tcl_GetInt(interp
, argv
[2], &state
) != TCL_OK
) ||
144 (state
< 0) || (state
>= NMAPS
)) {
148 DoSetMapState(view
, state
); Kick();
151 sprintf(interp
->result
, "%d", view
->map_state
);
156 MapCmdShowEditors(VIEW_ARGS
)
160 if ((argc
!= 2) && (argc
!= 3)) {
165 if (Tcl_GetInt(interp
, argv
[2], &val
) != TCL_OK
) {
169 view
->show_editors
= val
;
172 sprintf(interp
->result
, "%d", view
->show_editors
);
177 MapCmdPanStart(VIEW_ARGS
)
179 int x
, y
, left
, right
, top
, bottom
, width
, height
;
186 if ((Tcl_GetInt(interp
, argv
[2], &x
) != TCL_OK
) ||
187 (Tcl_GetInt(interp
, argv
[3], &y
) != TCL_OK
)) {
191 for (ed
= sim
->editor
; ed
!= NULL
; ed
= ed
->next
) {
192 if ((ed
->x
!= view
->x
) || (ed
->show_me
== 0))
196 height
= ed
->w_height
;
197 left
= ed
->pan_x
- (width
/ 2);
198 top
= ed
->pan_y
- (height
/ 2);
199 right
= left
+ width
;
200 bottom
= top
+ height
;
202 left
= left
* 3 / 16 - 4;
203 top
= top
* 3 / 16 - 4;
204 right
= right
* 3 / 16 + 4;
205 bottom
= bottom
* 3 / 16 + 4;
207 if ((x
>= left
) && (x
<= right
) &&
208 (y
>= top
) && (y
<= bottom
)) {
216 view
->track_info
= (char *)ed
;
221 MapCmdPanTo(VIEW_ARGS
)
230 if ((Tcl_GetInt(interp
, argv
[2], &x
) != TCL_OK
) ||
231 (Tcl_GetInt(interp
, argv
[3], &y
) != TCL_OK
)) {
235 if ((ed
= (SimView
*)view
->track_info
) != NULL
) {
236 dx
= x
- view
->last_x
;
237 dy
= y
- view
->last_y
;
245 DoPanBy(ed
, dx
, dy
); Kick();
252 MapCmdVisible(VIEW_ARGS
)
256 if ((argc
!= 2) && (argc
!= 3)) {
261 if ((Tcl_GetInt(interp
, argv
[2], &visible
) != TCL_OK
) ||
262 (visible
< 0) || (visible
> 1)) {
266 visible
= visible
&& Tk_IsMapped(view
->tkwin
);
267 view
->visible
= visible
;
270 sprintf(interp
->result
, "%d", view
->visible
);
275 MapCmdViewAt(VIEW_ARGS
)
283 if ((Tcl_GetInt(interp
, argv
[2], &x
) != TCL_OK
) ||
284 (x
< 0) || (x
>= WORLD_X
) ||
285 (Tcl_GetInt(interp
, argv
[3], &y
) != TCL_OK
) ||
286 (y
< 0) || (y
>= WORLD_Y
)) {
290 sprintf(interp
->result
, "Sorry Not Implemented Yet"); /* XXX */
296 map_command_init(void)
298 extern int TileViewCmd(CLIENT_ARGS
);
300 Tcl_CreateCommand(tk_mainInterp
, "mapview", TileViewCmd
,
301 (ClientData
)MainWindow
, (void (*)()) NULL
);
303 Tcl_InitHashTable(&MapCmds
, TCL_STRING_KEYS
);
305 #define MAP_CMD(name) HASHED_CMD(Map, name)
311 MAP_CMD(ShowEditors
);
320 DoMapCmd(CLIENT_ARGS
)
322 SimView
*view
= (SimView
*) clientData
;
331 if ((ent
= Tcl_FindHashEntry(&MapCmds
, argv
[1]))) {
332 cmd
= (int (*)())ent
->clientData
;
333 Tk_Preserve((ClientData
) view
);
334 result
= cmd(view
, interp
, argc
, argv
);
335 Tk_Release((ClientData
) view
);
337 Tcl_AppendResult(interp
, "unknown command name: \"",
338 argv
[0], " ", argv
[1], "\".", (char *) NULL
);
345 /*************************************************************************/
348 DoNewMap(SimView
*view
)
350 sim
->maps
++; view
->next
= sim
->map
; sim
->map
= view
;
356 int DoUpdateMap(SimView
*view
)
362 // fprintf(stderr, "UpdateMaps sim_skips %d skips %d skip %d visible %d\n", sim_skips, view->skips, view->skip, view->visible);
364 if (!view
->visible
) {
377 if (view
->skip
> 0) {
381 view
->skip
= view
->skips
;
389 // view->invalid = 1;
391 if (view
->invalid
|| NewMap
|| ShakeNow
) {
395 switch (view
->type
) {
408 /* XXX: don't do this stuff if just redrawing overlay */
410 for (dx
= dy
= i
= 0; i
< ShakeNow
; i
++) {
415 XCopyArea(view
->x
->dpy
, view
->pixmap
, view
->pixmap2
, view
->x
->gc
,
416 dx
, dy
, view
->w_width
, view
->w_height
, 0, 0);
419 /* XXX: do this if just redrawing overlay */
421 XCopyArea(view
->x
->dpy
, view
->pixmap2
,
422 Tk_WindowId(view
->tkwin
), view
->x
->gc
,
423 0, 0, view
->w_width
, view
->w_height
, 0, 0);
425 if (view
->show_editors
) {
426 DrawMapEditorViews(view
);
434 DrawMapEditorViews(SimView
*view
)
436 Pixmap pm
= Tk_WindowId(view
->tkwin
);
438 int left
, right
, top
, bottom
, width
, height
;
440 XSetLineAttributes(view
->x
->dpy
, view
->x
->gc
, 1,
441 LineSolid
, CapButt
, JoinBevel
);
443 for (ed
= sim
->editor
; ed
!= NULL
; ed
= ed
->next
) {
444 if ((ed
->x
!= view
->x
) || (ed
->show_me
== 0))
448 height
= ed
->w_height
;
449 left
= ed
->pan_x
- (width
/ 2);
450 top
= ed
->pan_y
- (height
/ 2);
451 right
= left
+ width
;
452 bottom
= top
+ height
;
454 left
= left
* 3 / 16;
456 right
= right
* 3 / 16;
457 bottom
= bottom
* 3 / 16;
458 width
= right
- left
;
459 height
= bottom
- top
;
461 XSetForeground(view
->x
->dpy
, view
->x
->gc
,
462 view
->pixels
[COLOR_WHITE
]);
463 XDrawRectangle(view
->x
->dpy
, pm
, view
->x
->gc
,
464 left
- 3, top
- 3, width
+ 3, height
+ 3);
466 XSetForeground(view
->x
->dpy
, view
->x
->gc
,
467 view
->pixels
[COLOR_BLACK
]);
468 XDrawRectangle(view
->x
->dpy
, pm
, view
->x
->gc
,
469 left
- 1, top
- 1, width
+ 3, height
+ 3);
471 XSetForeground(view
->x
->dpy
, view
->x
->gc
,
472 view
->pixels
[COLOR_YELLOW
]);
473 XDrawRectangle(view
->x
->dpy
, pm
, view
->x
->gc
,
474 left
- 2, top
- 2, width
+ 3, height
+ 3);
480 * Sending the whole image is 108108 bytes.
481 * Sending points is 4.4 bytes per point.
482 * One image is as big as 24570 points.
483 * But we have to sort these dang things.
487 int max_pix
= MAX_PIX
;
494 struct Pix pix
[MAX_PIX
];
498 CompareColor(struct Pix
*p1
, struct Pix
*p2
)
500 register char c1
= p1
->color
, c2
= p2
->color
;
504 return ((c1
< c2
) ? -1 : 1);
509 WireDrawMap(SimView
*view
)
512 unsigned char *old
, *new;
518 if (!view
->x
->color
) {
523 memcpy(view
->other_data
, view
->data
, view
->line_bytes
* view
->m_height
); /* XXX: handle depth */
526 old
= view
->other_data
; new = view
->data
; /* XXX: handle depth */
529 /* Scan the pixels that have changed */
530 for (y
= 0; y
< view
->m_height
; y
++) {
531 for (x
= 0; x
< view
->m_width
; x
++) {
532 if (old
[x
] != new[x
]) {
533 if (different
>= max_pix
) {
534 /* Wow, lots of the pixels have changed.
535 Maybe we ought to just do it the hard way. */
536 XPutImage(view
->x
->dpy
, view
->pixmap
, view
->x
->gc
, view
->image
,
537 0, 0, 0, 0, view
->m_width
, view
->m_height
);
540 pix
[different
].color
= new[x
];
541 pix
[different
].x
= x
;
542 pix
[different
].y
= y
;
546 old
+= view
->line_bytes
; new += view
->line_bytes
; /* XXX: handle depth */
549 /* Whew, the images are identical! */
555 /* Always draw the whole pixmap, for now. */
556 XPutImage(view
->x
->dpy
, view
->pixmap
, view
->x
->gc
, view
->image
,
557 0, 0, 0, 0, view
->m_width
, view
->m_height
);
561 /* TODO: Fix this. I disabled this incremental drawing code for now since it seems to be buggy. */
563 /* Sort the changed pixels by their color */
564 qsort(pix
, different
, sizeof (struct Pix
), (int (*)())CompareColor
);
566 /* Draw the points of each color that have changed */
567 points
= (XPoint
*)malloc(sizeof (XPoint
) * different
);
569 for (i
= 0; i
<= different
; i
++) {
570 if ((i
== different
) ||
571 (pix
[i
].color
!= pix
[last
].color
)) {
572 XSetForeground(view
->x
->dpy
, view
->x
->gc
, pix
[last
].color
);
573 XDrawPoints(view
->x
->dpy
, view
->pixmap
, view
->x
->gc
,
574 points
, pts
, CoordModeOrigin
);
580 points
[pts
].x
= pix
[i
].x
;
581 points
[pts
].y
= pix
[i
].y
;
592 DrawMapInk(SimView
*view
)
594 Pixmap pm
= view
->pixmap2
;
595 Ink
*ink
, *ink2
= NewInk();
598 XSetLineAttributes(view
->x
->dpy
, view
->x
->gc
, 0,
599 LineSolid
, CapButt
, JoinBevel
);
601 for (ink
= sim
->overlay
; ink
!= NULL
; ink
= ink
->next
) {
602 X
= ink
->x
; x
= (X
* 3) >>4;
603 Y
= ink
->y
; y
= (Y
* 3) >>4;
605 if (ink
->length
<= 1) {
606 XSetForeground(view
->x
->dpy
, view
->x
->gc
,
607 view
->pixels
[ink
->color
]);
608 XFillArc(view
->x
->dpy
, pm
, view
->x
->gc
,
609 ink
->x
- 1, ink
->y
- 1, 1, 1, 0, 360 * 64);
611 StartInk(ink2
, x
, y
);
613 for (i
= 1; i
< ink
->length
; i
++) {
614 X
+= ink
->points
[i
].x
; x
= (X
* 3) >>4;
615 Y
+= ink
->points
[i
].y
; y
= (Y
* 3) >>4;
619 XSetForeground(view
->x
->dpy
, view
->x
->gc
,
620 view
->pixels
[ink
->color
]);
621 XDrawLines(view
->x
->dpy
, pm
, view
->x
->gc
,
622 ink2
->points
, ink2
->length
, CoordModePrevious
);