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
[];
74 MapCmdconfigure(VIEW_ARGS
)
79 result
= Tk_ConfigureInfo(interp
, view
->tkwin
, TileViewConfigSpecs
,
80 (char *) view
, (char *) NULL
, 0);
81 } else if (argc
== 3) {
82 result
= Tk_ConfigureInfo(interp
, view
->tkwin
, TileViewConfigSpecs
,
83 (char *) view
, argv
[2], 0);
85 result
= ConfigureTileView(interp
, view
, argc
-2, argv
+2,
91 MapCmdposition(VIEW_ARGS
)
93 if ((argc
!= 2) && (argc
!= 4)) {
97 if ((Tcl_GetInt(interp
, argv
[2], &view
->w_x
) != TCL_OK
)
98 || (Tcl_GetInt(interp
, argv
[3], &view
->w_y
) != TCL_OK
)) {
102 sprintf(interp
->result
, "%d %d", view
->w_x
, view
->w_y
);
106 MapCmdsize(VIEW_ARGS
)
108 if ((argc
!= 2) && (argc
!= 4)) {
114 if (Tcl_GetInt(interp
, argv
[2], &w
) != TCL_OK
) {
117 if (Tcl_GetInt(interp
, argv
[3], &h
) != TCL_OK
) {
123 sprintf(interp
->result
, "%d %d", view
->w_width
, view
->w_height
);
127 MapCmdMapState(VIEW_ARGS
)
131 if ((argc
!= 2) && (argc
!= 3)) {
136 if ((Tcl_GetInt(interp
, argv
[2], &state
) != TCL_OK
) ||
137 (state
< 0) || (state
>= NMAPS
)) {
141 DoSetMapState(view
, state
); Kick();
144 sprintf(interp
->result
, "%d", view
->map_state
);
148 MapCmdShowEditors(VIEW_ARGS
)
152 if ((argc
!= 2) && (argc
!= 3)) {
157 if (Tcl_GetInt(interp
, argv
[2], &val
) != TCL_OK
) {
161 view
->show_editors
= val
;
164 sprintf(interp
->result
, "%d", view
->show_editors
);
168 MapCmdPanStart(VIEW_ARGS
)
170 int x
, y
, left
, right
, top
, bottom
, width
, height
;
177 if ((Tcl_GetInt(interp
, argv
[2], &x
) != TCL_OK
) ||
178 (Tcl_GetInt(interp
, argv
[3], &y
) != TCL_OK
)) {
182 for (ed
= sim
->editor
; ed
!= NULL
; ed
= ed
->next
) {
183 if ((ed
->x
!= view
->x
) || (ed
->show_me
== 0))
187 height
= ed
->w_height
;
188 left
= ed
->pan_x
- (width
/ 2);
189 top
= ed
->pan_y
- (height
/ 2);
190 right
= left
+ width
;
191 bottom
= top
+ height
;
193 left
= left
* 3 / 16 - 4;
194 top
= top
* 3 / 16 - 4;
195 right
= right
* 3 / 16 + 4;
196 bottom
= bottom
* 3 / 16 + 4;
198 if ((x
>= left
) && (x
<= right
) &&
199 (y
>= top
) && (y
<= bottom
)) {
207 view
->track_info
= (char *)ed
;
211 MapCmdPanTo(VIEW_ARGS
)
220 if ((Tcl_GetInt(interp
, argv
[2], &x
) != TCL_OK
) ||
221 (Tcl_GetInt(interp
, argv
[3], &y
) != TCL_OK
)) {
225 if ((ed
= (SimView
*)view
->track_info
) != NULL
) {
226 dx
= x
- view
->last_x
;
227 dy
= y
- view
->last_y
;
235 DoPanBy(ed
, dx
, dy
); Kick();
241 MapCmdVisible(VIEW_ARGS
)
245 if ((argc
!= 2) && (argc
!= 3)) {
250 if ((Tcl_GetInt(interp
, argv
[2], &visible
) != TCL_OK
) ||
251 (visible
< 0) || (visible
> 1)) {
255 visible
= visible
&& Tk_IsMapped(view
->tkwin
);
256 view
->visible
= visible
;
259 sprintf(interp
->result
, "%d", view
->visible
);
263 MapCmdViewAt(VIEW_ARGS
)
271 if ((Tcl_GetInt(interp
, argv
[2], &x
) != TCL_OK
) ||
272 (x
< 0) || (x
>= WORLD_X
) ||
273 (Tcl_GetInt(interp
, argv
[3], &y
) != TCL_OK
) ||
274 (y
< 0) || (y
>= WORLD_Y
)) {
278 sprintf(interp
->result
, "Sorry Not Implemented Yet"); /* XXX */
286 extern int TileViewCmd(CLIENT_ARGS
);
288 Tcl_CreateCommand(tk_mainInterp
, "mapview", TileViewCmd
,
289 (ClientData
)MainWindow
, (void (*)()) NULL
);
291 Tcl_InitHashTable(&MapCmds
, TCL_STRING_KEYS
);
293 #define MAP_CMD(name) HASHED_CMD(Map, name)
299 MAP_CMD(ShowEditors
);
308 DoMapCmd(CLIENT_ARGS
)
310 SimView
*view
= (SimView
*) clientData
;
319 if (ent
= Tcl_FindHashEntry(&MapCmds
, argv
[1])) {
320 cmd
= (int (*)())ent
->clientData
;
321 Tk_Preserve((ClientData
) view
);
322 result
= cmd(view
, interp
, argc
, argv
);
323 Tk_Release((ClientData
) view
);
325 Tcl_AppendResult(interp
, "unknown command name: \"",
326 argv
[0], " ", argv
[1], "\".", (char *) NULL
);
333 /*************************************************************************/
335 DoNewMap(SimView
*view
)
337 sim
->maps
++; view
->next
= sim
->map
; sim
->map
= view
;
343 int DoUpdateMap(SimView
*view
)
349 // fprintf(stderr, "UpdateMaps sim_skips %d skips %d skip %d visible %d\n", sim_skips, view->skips, view->skip, view->visible);
351 if (!view
->visible
) {
364 if (view
->skip
> 0) {
368 view
->skip
= view
->skips
;
376 // view->invalid = 1;
378 if (view
->invalid
|| NewMap
|| ShakeNow
) {
382 switch (view
->type
) {
395 /* XXX: don't do this stuff if just redrawing overlay */
397 for (dx
= dy
= i
= 0; i
< ShakeNow
; i
++) {
402 XCopyArea(view
->x
->dpy
, view
->pixmap
, view
->pixmap2
, view
->x
->gc
,
403 dx
, dy
, view
->w_width
, view
->w_height
, 0, 0);
406 /* XXX: do this if just redrawing overlay */
408 XCopyArea(view
->x
->dpy
, view
->pixmap2
,
409 Tk_WindowId(view
->tkwin
), view
->x
->gc
,
410 0, 0, view
->w_width
, view
->w_height
, 0, 0);
412 if (view
->show_editors
) {
413 DrawMapEditorViews(view
);
420 DrawMapEditorViews(SimView
*view
)
422 Pixmap pm
= Tk_WindowId(view
->tkwin
);
424 int left
, right
, top
, bottom
, width
, height
;
427 XSetLineAttributes(view
->x
->dpy
, view
->x
->gc
, 1,
428 LineSolid
, CapButt
, JoinBevel
);
430 for (ed
= sim
->editor
; ed
!= NULL
; ed
= ed
->next
) {
431 if ((ed
->x
!= view
->x
) || (ed
->show_me
== 0))
435 height
= ed
->w_height
;
436 left
= ed
->pan_x
- (width
/ 2);
437 top
= ed
->pan_y
- (height
/ 2);
438 right
= left
+ width
;
439 bottom
= top
+ height
;
441 left
= left
* 3 / 16;
443 right
= right
* 3 / 16;
444 bottom
= bottom
* 3 / 16;
445 width
= right
- left
;
446 height
= bottom
- top
;
448 XSetForeground(view
->x
->dpy
, view
->x
->gc
,
449 view
->pixels
[COLOR_WHITE
]);
450 XDrawRectangle(view
->x
->dpy
, pm
, view
->x
->gc
,
451 left
- 3, top
- 3, width
+ 3, height
+ 3);
453 XSetForeground(view
->x
->dpy
, view
->x
->gc
,
454 view
->pixels
[COLOR_BLACK
]);
455 XDrawRectangle(view
->x
->dpy
, pm
, view
->x
->gc
,
456 left
- 1, top
- 1, width
+ 3, height
+ 3);
458 XSetForeground(view
->x
->dpy
, view
->x
->gc
,
459 view
->pixels
[COLOR_YELLOW
]);
460 XDrawRectangle(view
->x
->dpy
, pm
, view
->x
->gc
,
461 left
- 2, top
- 2, width
+ 3, height
+ 3);
467 * Sending the whole image is 108108 bytes.
468 * Sending points is 4.4 bytes per point.
469 * One image is as big as 24570 points.
470 * But we have to sort these dang things.
474 int max_pix
= MAX_PIX
;
481 struct Pix pix
[MAX_PIX
];
484 CompareColor(struct Pix
*p1
, struct Pix
*p2
)
486 register char c1
= p1
->color
, c2
= p2
->color
;
490 return ((c1
< c2
) ? -1 : 1);
494 WireDrawMap(SimView
*view
)
496 int different
, x
, y
, i
, last
, pts
;
497 unsigned char *old
, *new;
500 if (!view
->x
->color
) {
505 memcpy(view
->other_data
, view
->data
, view
->line_bytes
* view
->m_height
); /* XXX: handle depth */
508 old
= view
->other_data
; new = view
->data
; /* XXX: handle depth */
511 /* Scan the pixels that have changed */
512 for (y
= 0; y
< view
->m_height
; y
++) {
513 for (x
= 0; x
< view
->m_width
; x
++) {
514 if (old
[x
] != new[x
]) {
515 if (different
>= max_pix
) {
516 /* Wow, lots of the pixels have changed.
517 Maybe we ought to just do it the hard way. */
518 XPutImage(view
->x
->dpy
, view
->pixmap
, view
->x
->gc
, view
->image
,
519 0, 0, 0, 0, view
->m_width
, view
->m_height
);
522 pix
[different
].color
= new[x
];
523 pix
[different
].x
= x
;
524 pix
[different
].y
= y
;
528 old
+= view
->line_bytes
; new += view
->line_bytes
; /* XXX: handle depth */
531 /* Whew, the images are identical! */
537 /* Always draw the whole pixmap, for now. */
538 XPutImage(view
->x
->dpy
, view
->pixmap
, view
->x
->gc
, view
->image
,
539 0, 0, 0, 0, view
->m_width
, view
->m_height
);
543 /* TODO: Fix this. I disabled this incremental drawing code for now since it seems to be buggy. */
545 /* Sort the changed pixels by their color */
546 qsort(pix
, different
, sizeof (struct Pix
), (int (*)())CompareColor
);
548 /* Draw the points of each color that have changed */
549 points
= (XPoint
*)malloc(sizeof (XPoint
) * different
);
551 for (i
= 0; i
<= different
; i
++) {
552 if ((i
== different
) ||
553 (pix
[i
].color
!= pix
[last
].color
)) {
554 XSetForeground(view
->x
->dpy
, view
->x
->gc
, pix
[last
].color
);
555 XDrawPoints(view
->x
->dpy
, view
->pixmap
, view
->x
->gc
,
556 points
, pts
, CoordModeOrigin
);
562 points
[pts
].x
= pix
[i
].x
;
563 points
[pts
].y
= pix
[i
].y
;
573 DrawMapInk(SimView
*view
)
575 Pixmap pm
= view
->pixmap2
;
577 Ink
*ink
, *ink2
= NewInk();
580 XSetLineAttributes(view
->x
->dpy
, view
->x
->gc
, 0,
581 LineSolid
, CapButt
, JoinBevel
);
583 for (ink
= sim
->overlay
; ink
!= NULL
; ink
= ink
->next
) {
584 X
= ink
->x
; x
= (X
* 3) >>4;
585 Y
= ink
->y
; y
= (Y
* 3) >>4;
587 if (ink
->length
<= 1) {
588 XSetForeground(view
->x
->dpy
, view
->x
->gc
,
589 view
->pixels
[ink
->color
]);
590 XFillArc(view
->x
->dpy
, pm
, view
->x
->gc
,
591 ink
->x
- 1, ink
->y
- 1, 1, 1, 0, 360 * 64);
593 StartInk(ink2
, x
, y
);
595 for (i
= 1; i
< ink
->length
; i
++) {
596 X
+= ink
->points
[i
].x
; x
= (X
* 3) >>4;
597 Y
+= ink
->points
[i
].y
; y
= (Y
* 3) >>4;
601 XSetForeground(view
->x
->dpy
, view
->x
->gc
,
602 view
->pixels
[ink
->color
]);
603 XDrawLines(view
->x
->dpy
, pm
, view
->x
->gc
,
604 ink2
->points
, ink2
->length
, CoordModePrevious
);