]> git.zerfleddert.de Git - micropolis/blob - src/sim/w_map.c
Makefile: Micropolis build fixes for recent macOS
[micropolis] / src / sim / w_map.c
1 /* w_map.c
2 *
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.
8 *
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.
13 *
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/>.
20 *
21 * ADDITIONAL TERMS per GNU GPL Section 7
22 *
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.
28 *
29 * Any propagation or conveyance of this program must include this
30 * copyright notice and these terms.
31 *
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.
36 *
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.
40 *
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
60 * NOT APPLY TO YOU.
61 */
62 #include "sim.h"
63
64
65 Tcl_HashTable MapCmds;
66
67
68 extern Tk_ConfigSpec TileViewConfigSpecs[];
69
70
71 Ink *NewInk();
72 void DrawMapInk(SimView *view);
73 void WireDrawMap(SimView *view);
74 void DrawMapEditorViews(SimView *view);
75
76
77 int
78 MapCmdconfigure(VIEW_ARGS)
79 {
80 int result = TCL_OK;
81
82 if (argc == 2) {
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);
88 } else {
89 result = ConfigureTileView(interp, view, argc-2, argv+2,
90 TK_CONFIG_ARGV_ONLY);
91 }
92 return result;
93 }
94
95 int
96 MapCmdposition(VIEW_ARGS)
97 {
98 if ((argc != 2) && (argc != 4)) {
99 return TCL_ERROR;
100 }
101 if (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)) {
104 return TCL_ERROR;
105 }
106 }
107 sprintf(interp->result, "%d %d", view->w_x, view->w_y);
108 return TCL_OK;
109 }
110
111 int
112 MapCmdsize(VIEW_ARGS)
113 {
114 if ((argc != 2) && (argc != 4)) {
115 return TCL_ERROR;
116 }
117 if (argc == 4) {
118 int w, h;
119
120 if (Tcl_GetInt(interp, argv[2], &w) != TCL_OK) {
121 return TCL_ERROR;
122 }
123 if (Tcl_GetInt(interp, argv[3], &h) != TCL_OK) {
124 return TCL_ERROR;
125 }
126 view->w_width = w;
127 view->w_height = h;
128 }
129 sprintf(interp->result, "%d %d", view->w_width, view->w_height);
130 return TCL_OK;
131 }
132
133 int
134 MapCmdMapState(VIEW_ARGS)
135 {
136 int state;
137
138 if ((argc != 2) && (argc != 3)) {
139 return TCL_ERROR;
140 }
141
142 if (argc == 3) {
143 if ((Tcl_GetInt(interp, argv[2], &state) != TCL_OK) ||
144 (state < 0) || (state >= NMAPS)) {
145 return TCL_ERROR;
146 }
147
148 DoSetMapState(view, state); Kick();
149 }
150
151 sprintf(interp->result, "%d", view->map_state);
152 return TCL_OK;
153 }
154
155 int
156 MapCmdShowEditors(VIEW_ARGS)
157 {
158 int val;
159
160 if ((argc != 2) && (argc != 3)) {
161 return TCL_ERROR;
162 }
163
164 if (argc == 3) {
165 if (Tcl_GetInt(interp, argv[2], &val) != TCL_OK) {
166 return TCL_ERROR;
167 }
168
169 view->show_editors = val;
170 }
171
172 sprintf(interp->result, "%d", view->show_editors);
173 return TCL_OK;
174 }
175
176 int
177 MapCmdPanStart(VIEW_ARGS)
178 {
179 int x, y, left, right, top, bottom, width, height;
180 SimView *ed;
181
182 if (argc != 4) {
183 return TCL_ERROR;
184 }
185
186 if ((Tcl_GetInt(interp, argv[2], &x) != TCL_OK) ||
187 (Tcl_GetInt(interp, argv[3], &y) != TCL_OK)) {
188 return TCL_ERROR;
189 }
190
191 for (ed = sim->editor; ed != NULL; ed = ed->next) {
192 if ((ed->x != view->x) || (ed->show_me == 0))
193 continue;
194
195 width = ed->w_width;
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;
201
202 left = left * 3 / 16 - 4;
203 top = top * 3 / 16 - 4;
204 right = right * 3 / 16 + 4;
205 bottom = bottom * 3 / 16 + 4;
206
207 if ((x >= left) && (x <= right) &&
208 (y >= top) && (y <= bottom)) {
209 goto gotit;
210 }
211 }
212
213 gotit:
214 view->last_x = x;
215 view->last_y = y;
216 view->track_info = (char *)ed;
217 return TCL_OK;
218 }
219
220 int
221 MapCmdPanTo(VIEW_ARGS)
222 {
223 int x, y, dx, dy;
224 SimView *ed;
225
226 if (argc != 4) {
227 return TCL_ERROR;
228 }
229
230 if ((Tcl_GetInt(interp, argv[2], &x) != TCL_OK) ||
231 (Tcl_GetInt(interp, argv[3], &y) != TCL_OK)) {
232 return TCL_ERROR;
233 }
234
235 if ((ed = (SimView *)view->track_info) != NULL) {
236 dx = x - view->last_x;
237 dy = y - view->last_y;
238 if (dx || dy) {
239 view->last_x = x;
240 view->last_y = y;
241 dx = dx * 16 / 3;
242 dy = dy * 16 / 3;
243
244 ed->skip = 0;
245 DoPanBy(ed, dx, dy); Kick();
246 }
247 }
248 return TCL_OK;
249 }
250
251 int
252 MapCmdVisible(VIEW_ARGS)
253 {
254 int visible;
255
256 if ((argc != 2) && (argc != 3)) {
257 return TCL_ERROR;
258 }
259
260 if (argc == 3) {
261 if ((Tcl_GetInt(interp, argv[2], &visible) != TCL_OK) ||
262 (visible < 0) || (visible > 1)) {
263 return TCL_ERROR;
264 }
265
266 visible = visible && Tk_IsMapped(view->tkwin);
267 view->visible = visible;
268 }
269
270 sprintf(interp->result, "%d", view->visible);
271 return TCL_OK;
272 }
273
274 int
275 MapCmdViewAt(VIEW_ARGS)
276 {
277 int x, y;
278
279 if (argc != 4) {
280 return TCL_ERROR;
281 }
282
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)) {
287 return TCL_ERROR;
288 }
289
290 sprintf(interp->result, "Sorry Not Implemented Yet"); /* XXX */
291 return TCL_OK;
292 }
293
294
295 void
296 map_command_init(void)
297 {
298 extern int TileViewCmd(CLIENT_ARGS);
299
300 Tcl_CreateCommand(tk_mainInterp, "mapview", TileViewCmd,
301 (ClientData)MainWindow, (void (*)()) NULL);
302
303 Tcl_InitHashTable(&MapCmds, TCL_STRING_KEYS);
304
305 #define MAP_CMD(name) HASHED_CMD(Map, name)
306
307 MAP_CMD(configure);
308 MAP_CMD(position);
309 MAP_CMD(size);
310 MAP_CMD(MapState);
311 MAP_CMD(ShowEditors);
312 MAP_CMD(PanStart);
313 MAP_CMD(PanTo);
314 MAP_CMD(Visible);
315 MAP_CMD(ViewAt);
316 }
317
318
319 int
320 DoMapCmd(CLIENT_ARGS)
321 {
322 SimView *view = (SimView *) clientData;
323 Tcl_HashEntry *ent;
324 int result = TCL_OK;
325 int (*cmd)();
326
327 if (argc < 2) {
328 return TCL_ERROR;
329 }
330
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);
336 } else {
337 Tcl_AppendResult(interp, "unknown command name: \"",
338 argv[0], " ", argv[1], "\".", (char *) NULL);
339 result = TCL_ERROR;
340 }
341 return result;
342 }
343
344
345 /*************************************************************************/
346
347 void
348 DoNewMap(SimView *view)
349 {
350 sim->maps++; view->next = sim->map; sim->map = view;
351 /* NewMap = 1; */
352 view->invalid = 1;
353 }
354
355
356 int DoUpdateMap(SimView *view)
357 {
358 int dx, dy, i;
359
360 view->updates++;
361
362 // fprintf(stderr, "UpdateMaps sim_skips %d skips %d skip %d visible %d\n", sim_skips, view->skips, view->skip, view->visible);
363
364 if (!view->visible) {
365 return 0;
366 }
367
368 if ((!ShakeNow) &&
369 (!view->update) &&
370 (sim_skips ||
371 view->skips)) {
372 if (sim_skips) {
373 if (sim_skip > 0) {
374 return 0;
375 }
376 } else {
377 if (view->skip > 0) {
378 --view->skip;
379 return 0;
380 } else {
381 view->skip = view->skips;
382 }
383 }
384 }
385
386 view->update = 0;
387 view->skip = 0;
388
389 // view->invalid = 1;
390
391 if (view->invalid || NewMap || ShakeNow) {
392
393 view->invalid = 0;
394
395 switch (view->type) {
396
397 case X_Mem_View:
398 MemDrawMap(view);
399 break;
400
401 case X_Wire_View:
402 WireDrawMap(view);
403 break;
404 }
405
406 }
407
408 /* XXX: don't do this stuff if just redrawing overlay */
409
410 for (dx = dy = i = 0; i < ShakeNow; i++) {
411 dx += Rand(16) - 8;
412 dy += Rand(16) - 8;
413 }
414
415 XCopyArea(view->x->dpy, view->pixmap, view->pixmap2, view->x->gc,
416 dx, dy, view->w_width, view->w_height, 0, 0);
417 DrawMapInk(view);
418
419 /* XXX: do this if just redrawing overlay */
420
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);
424
425 if (view->show_editors) {
426 DrawMapEditorViews(view);
427 }
428
429 return 1;
430 }
431
432
433 void
434 DrawMapEditorViews(SimView *view)
435 {
436 Pixmap pm = Tk_WindowId(view->tkwin);
437 struct SimView *ed;
438 int left, right, top, bottom, width, height;
439
440 XSetLineAttributes(view->x->dpy, view->x->gc, 1,
441 LineSolid, CapButt, JoinBevel);
442
443 for (ed = sim->editor; ed != NULL; ed = ed->next) {
444 if ((ed->x != view->x) || (ed->show_me == 0))
445 continue;
446
447 width = ed->w_width;
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;
453
454 left = left * 3 / 16;
455 top = top * 3 / 16;
456 right = right * 3 / 16;
457 bottom = bottom * 3 / 16;
458 width = right - left;
459 height = bottom - top;
460
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);
465
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);
470
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);
475 }
476 }
477
478
479 /*
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.
484 */
485
486 #define MAX_PIX 256
487 int max_pix = MAX_PIX;
488
489 struct Pix {
490 long color;
491 short x, y;
492 };
493
494 struct Pix pix[MAX_PIX];
495
496
497 int
498 CompareColor(struct Pix *p1, struct Pix *p2)
499 {
500 register char c1 = p1->color, c2 = p2->color;
501
502 if (c1 == c2)
503 return (0);
504 return ((c1 < c2) ? -1 : 1);
505 }
506
507
508 void
509 WireDrawMap(SimView *view)
510 {
511 int different, x, y;
512 unsigned char *old, *new;
513 #if 0
514 XPoint *points;
515 int i, last, pts;
516 #endif
517
518 if (!view->x->color) {
519 MemDrawMap(view);
520 return;
521 }
522
523 memcpy(view->other_data, view->data, view->line_bytes * view->m_height); /* XXX: handle depth */
524 MemDrawMap(view);
525
526 old = view->other_data; new = view->data; /* XXX: handle depth */
527 different = 0;
528
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);
538 return;
539 }
540 pix[different].color = new[x];
541 pix[different].x = x;
542 pix[different].y = y;
543 different++;
544 }
545 }
546 old += view->line_bytes; new += view->line_bytes; /* XXX: handle depth */
547 }
548
549 /* Whew, the images are identical! */
550 if (different == 0)
551 return;
552
553 #if 1
554
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);
558
559 #else
560
561 /* TODO: Fix this. I disabled this incremental drawing code for now since it seems to be buggy. */
562
563 /* Sort the changed pixels by their color */
564 qsort(pix, different, sizeof (struct Pix), (int (*)())CompareColor);
565
566 /* Draw the points of each color that have changed */
567 points = (XPoint *)malloc(sizeof (XPoint) * different);
568 last = 0; pts = 0;
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);
575 if (i == different)
576 break;
577 pts = 0;
578 last = i;
579 }
580 points[pts].x = pix[i].x;
581 points[pts].y = pix[i].y;
582 pts++;
583 }
584 free(points);
585
586 #endif
587
588 }
589
590
591 void
592 DrawMapInk(SimView *view)
593 {
594 Pixmap pm = view->pixmap2;
595 Ink *ink, *ink2 = NewInk();
596 int i, X, Y, x, y;
597
598 XSetLineAttributes(view->x->dpy, view->x->gc, 0,
599 LineSolid, CapButt, JoinBevel);
600
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;
604
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);
610 } else {
611 StartInk(ink2, x, y);
612
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;
616 AddInk(ink2, x, y);
617 }
618
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);
623 }
624 }
625
626 FreeInk(ink2);
627 }
628
629
Impressum, Datenschutz