|
|
1.1 ! root 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 [email protected]. ! 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: ! 73: ! 74: MapCmdconfigure(VIEW_ARGS) ! 75: { ! 76: int result = TCL_OK; ! 77: ! 78: if (argc == 2) { ! 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); ! 84: } else { ! 85: result = ConfigureTileView(interp, view, argc-2, argv+2, ! 86: TK_CONFIG_ARGV_ONLY); ! 87: } ! 88: return result; ! 89: } ! 90: ! 91: MapCmdposition(VIEW_ARGS) ! 92: { ! 93: if ((argc != 2) && (argc != 4)) { ! 94: return TCL_ERROR; ! 95: } ! 96: if (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)) { ! 99: return TCL_ERROR; ! 100: } ! 101: } ! 102: sprintf(interp->result, "%d %d", view->w_x, view->w_y); ! 103: return TCL_OK; ! 104: } ! 105: ! 106: MapCmdsize(VIEW_ARGS) ! 107: { ! 108: if ((argc != 2) && (argc != 4)) { ! 109: return TCL_ERROR; ! 110: } ! 111: if (argc == 4) { ! 112: int w, h; ! 113: ! 114: if (Tcl_GetInt(interp, argv[2], &w) != TCL_OK) { ! 115: return TCL_ERROR; ! 116: } ! 117: if (Tcl_GetInt(interp, argv[3], &h) != TCL_OK) { ! 118: return TCL_ERROR; ! 119: } ! 120: view->w_width = w; ! 121: view->w_height = h; ! 122: } ! 123: sprintf(interp->result, "%d %d", view->w_width, view->w_height); ! 124: return TCL_OK; ! 125: } ! 126: ! 127: MapCmdMapState(VIEW_ARGS) ! 128: { ! 129: int state; ! 130: ! 131: if ((argc != 2) && (argc != 3)) { ! 132: return TCL_ERROR; ! 133: } ! 134: ! 135: if (argc == 3) { ! 136: if ((Tcl_GetInt(interp, argv[2], &state) != TCL_OK) || ! 137: (state < 0) || (state >= NMAPS)) { ! 138: return TCL_ERROR; ! 139: } ! 140: ! 141: DoSetMapState(view, state); Kick(); ! 142: } ! 143: ! 144: sprintf(interp->result, "%d", view->map_state); ! 145: return TCL_OK; ! 146: } ! 147: ! 148: MapCmdShowEditors(VIEW_ARGS) ! 149: { ! 150: int val; ! 151: ! 152: if ((argc != 2) && (argc != 3)) { ! 153: return TCL_ERROR; ! 154: } ! 155: ! 156: if (argc == 3) { ! 157: if (Tcl_GetInt(interp, argv[2], &val) != TCL_OK) { ! 158: return TCL_ERROR; ! 159: } ! 160: ! 161: view->show_editors = val; ! 162: } ! 163: ! 164: sprintf(interp->result, "%d", view->show_editors); ! 165: return TCL_OK; ! 166: } ! 167: ! 168: MapCmdPanStart(VIEW_ARGS) ! 169: { ! 170: int x, y, left, right, top, bottom, width, height; ! 171: SimView *ed; ! 172: ! 173: if (argc != 4) { ! 174: return TCL_ERROR; ! 175: } ! 176: ! 177: if ((Tcl_GetInt(interp, argv[2], &x) != TCL_OK) || ! 178: (Tcl_GetInt(interp, argv[3], &y) != TCL_OK)) { ! 179: return TCL_ERROR; ! 180: } ! 181: ! 182: for (ed = sim->editor; ed != NULL; ed = ed->next) { ! 183: if ((ed->x != view->x) || (ed->show_me == 0)) ! 184: continue; ! 185: ! 186: width = ed->w_width; ! 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; ! 192: ! 193: left = left * 3 / 16 - 4; ! 194: top = top * 3 / 16 - 4; ! 195: right = right * 3 / 16 + 4; ! 196: bottom = bottom * 3 / 16 + 4; ! 197: ! 198: if ((x >= left) && (x <= right) && ! 199: (y >= top) && (y <= bottom)) { ! 200: goto gotit; ! 201: } ! 202: } ! 203: ! 204: gotit: ! 205: view->last_x = x; ! 206: view->last_y = y; ! 207: view->track_info = (char *)ed; ! 208: return TCL_OK; ! 209: } ! 210: ! 211: MapCmdPanTo(VIEW_ARGS) ! 212: { ! 213: int x, y, dx, dy; ! 214: SimView *ed; ! 215: ! 216: if (argc != 4) { ! 217: return TCL_ERROR; ! 218: } ! 219: ! 220: if ((Tcl_GetInt(interp, argv[2], &x) != TCL_OK) || ! 221: (Tcl_GetInt(interp, argv[3], &y) != TCL_OK)) { ! 222: return TCL_ERROR; ! 223: } ! 224: ! 225: if ((ed = (SimView *)view->track_info) != NULL) { ! 226: dx = x - view->last_x; ! 227: dy = y - view->last_y; ! 228: if (dx || dy) { ! 229: view->last_x = x; ! 230: view->last_y = y; ! 231: dx = dx * 16 / 3; ! 232: dy = dy * 16 / 3; ! 233: ! 234: ed->skip = 0; ! 235: DoPanBy(ed, dx, dy); Kick(); ! 236: } ! 237: } ! 238: return TCL_OK; ! 239: } ! 240: ! 241: MapCmdVisible(VIEW_ARGS) ! 242: { ! 243: int visible; ! 244: ! 245: if ((argc != 2) && (argc != 3)) { ! 246: return TCL_ERROR; ! 247: } ! 248: ! 249: if (argc == 3) { ! 250: if ((Tcl_GetInt(interp, argv[2], &visible) != TCL_OK) || ! 251: (visible < 0) || (visible > 1)) { ! 252: return TCL_ERROR; ! 253: } ! 254: ! 255: visible = visible && Tk_IsMapped(view->tkwin); ! 256: view->visible = visible; ! 257: } ! 258: ! 259: sprintf(interp->result, "%d", view->visible); ! 260: return TCL_OK; ! 261: } ! 262: ! 263: MapCmdViewAt(VIEW_ARGS) ! 264: { ! 265: int x, y; ! 266: ! 267: if (argc != 4) { ! 268: return TCL_ERROR; ! 269: } ! 270: ! 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)) { ! 275: return TCL_ERROR; ! 276: } ! 277: ! 278: sprintf(interp->result, "Sorry Not Implemented Yet"); /* XXX */ ! 279: return TCL_OK; ! 280: } ! 281: ! 282: ! 283: map_command_init() ! 284: { ! 285: int new; ! 286: extern int TileViewCmd(CLIENT_ARGS); ! 287: ! 288: Tcl_CreateCommand(tk_mainInterp, "mapview", TileViewCmd, ! 289: (ClientData)MainWindow, (void (*)()) NULL); ! 290: ! 291: Tcl_InitHashTable(&MapCmds, TCL_STRING_KEYS); ! 292: ! 293: #define MAP_CMD(name) HASHED_CMD(Map, name) ! 294: ! 295: MAP_CMD(configure); ! 296: MAP_CMD(position); ! 297: MAP_CMD(size); ! 298: MAP_CMD(MapState); ! 299: MAP_CMD(ShowEditors); ! 300: MAP_CMD(PanStart); ! 301: MAP_CMD(PanTo); ! 302: MAP_CMD(Visible); ! 303: MAP_CMD(ViewAt); ! 304: } ! 305: ! 306: ! 307: int ! 308: DoMapCmd(CLIENT_ARGS) ! 309: { ! 310: SimView *view = (SimView *) clientData; ! 311: Tcl_HashEntry *ent; ! 312: int result = TCL_OK; ! 313: int (*cmd)(); ! 314: ! 315: if (argc < 2) { ! 316: return TCL_ERROR; ! 317: } ! 318: ! 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); ! 324: } else { ! 325: Tcl_AppendResult(interp, "unknown command name: \"", ! 326: argv[0], " ", argv[1], "\".", (char *) NULL); ! 327: result = TCL_ERROR; ! 328: } ! 329: return result; ! 330: } ! 331: ! 332: ! 333: /*************************************************************************/ ! 334: ! 335: DoNewMap(SimView *view) ! 336: { ! 337: sim->maps++; view->next = sim->map; sim->map = view; ! 338: /* NewMap = 1; */ ! 339: view->invalid = 1; ! 340: } ! 341: ! 342: ! 343: int DoUpdateMap(SimView *view) ! 344: { ! 345: int dx, dy, i; ! 346: ! 347: view->updates++; ! 348: ! 349: // fprintf(stderr, "UpdateMaps sim_skips %d skips %d skip %d visible %d\n", sim_skips, view->skips, view->skip, view->visible); ! 350: ! 351: if (!view->visible) { ! 352: return 0; ! 353: } ! 354: ! 355: if ((!ShakeNow) && ! 356: (!view->update) && ! 357: (sim_skips || ! 358: view->skips)) { ! 359: if (sim_skips) { ! 360: if (sim_skip > 0) { ! 361: return 0; ! 362: } ! 363: } else { ! 364: if (view->skip > 0) { ! 365: --view->skip; ! 366: return 0; ! 367: } else { ! 368: view->skip = view->skips; ! 369: } ! 370: } ! 371: } ! 372: ! 373: view->update = 0; ! 374: view->skip = 0; ! 375: ! 376: // view->invalid = 1; ! 377: ! 378: if (view->invalid || NewMap || ShakeNow) { ! 379: ! 380: view->invalid = 0; ! 381: ! 382: switch (view->type) { ! 383: ! 384: case X_Mem_View: ! 385: MemDrawMap(view); ! 386: break; ! 387: ! 388: case X_Wire_View: ! 389: WireDrawMap(view); ! 390: break; ! 391: } ! 392: ! 393: } ! 394: ! 395: /* XXX: don't do this stuff if just redrawing overlay */ ! 396: ! 397: for (dx = dy = i = 0; i < ShakeNow; i++) { ! 398: dx += Rand(16) - 8; ! 399: dy += Rand(16) - 8; ! 400: } ! 401: ! 402: XCopyArea(view->x->dpy, view->pixmap, view->pixmap2, view->x->gc, ! 403: dx, dy, view->w_width, view->w_height, 0, 0); ! 404: DrawMapInk(view); ! 405: ! 406: /* XXX: do this if just redrawing overlay */ ! 407: ! 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); ! 411: ! 412: if (view->show_editors) { ! 413: DrawMapEditorViews(view); ! 414: } ! 415: ! 416: return 1; ! 417: } ! 418: ! 419: ! 420: DrawMapEditorViews(SimView *view) ! 421: { ! 422: Pixmap pm = Tk_WindowId(view->tkwin); ! 423: struct SimView *ed; ! 424: int left, right, top, bottom, width, height; ! 425: int mine; ! 426: ! 427: XSetLineAttributes(view->x->dpy, view->x->gc, 1, ! 428: LineSolid, CapButt, JoinBevel); ! 429: ! 430: for (ed = sim->editor; ed != NULL; ed = ed->next) { ! 431: if ((ed->x != view->x) || (ed->show_me == 0)) ! 432: continue; ! 433: ! 434: width = ed->w_width; ! 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; ! 440: ! 441: left = left * 3 / 16; ! 442: top = top * 3 / 16; ! 443: right = right * 3 / 16; ! 444: bottom = bottom * 3 / 16; ! 445: width = right - left; ! 446: height = bottom - top; ! 447: ! 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); ! 452: ! 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); ! 457: ! 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); ! 462: } ! 463: } ! 464: ! 465: ! 466: /* ! 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. ! 471: */ ! 472: ! 473: #define MAX_PIX 256 ! 474: int max_pix = MAX_PIX; ! 475: ! 476: struct Pix { ! 477: long color; ! 478: short x, y; ! 479: }; ! 480: ! 481: struct Pix pix[MAX_PIX]; ! 482: ! 483: ! 484: CompareColor(struct Pix *p1, struct Pix *p2) ! 485: { ! 486: register char c1 = p1->color, c2 = p2->color; ! 487: ! 488: if (c1 == c2) ! 489: return (0); ! 490: return ((c1 < c2) ? -1 : 1); ! 491: } ! 492: ! 493: ! 494: WireDrawMap(SimView *view) ! 495: { ! 496: int different, x, y, i, last, pts; ! 497: unsigned char *old, *new; ! 498: XPoint *points; ! 499: ! 500: if (!view->x->color) { ! 501: MemDrawMap(view); ! 502: return; ! 503: } ! 504: ! 505: memcpy(view->other_data, view->data, view->line_bytes * view->m_height); /* XXX: handle depth */ ! 506: MemDrawMap(view); ! 507: ! 508: old = view->other_data; new = view->data; /* XXX: handle depth */ ! 509: different = 0; ! 510: ! 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); ! 520: return; ! 521: } ! 522: pix[different].color = new[x]; ! 523: pix[different].x = x; ! 524: pix[different].y = y; ! 525: different++; ! 526: } ! 527: } ! 528: old += view->line_bytes; new += view->line_bytes; /* XXX: handle depth */ ! 529: } ! 530: ! 531: /* Whew, the images are identical! */ ! 532: if (different == 0) ! 533: return; ! 534: ! 535: #if 1 ! 536: ! 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); ! 540: ! 541: #else ! 542: ! 543: /* TODO: Fix this. I disabled this incremental drawing code for now since it seems to be buggy. */ ! 544: ! 545: /* Sort the changed pixels by their color */ ! 546: qsort(pix, different, sizeof (struct Pix), (int (*)())CompareColor); ! 547: ! 548: /* Draw the points of each color that have changed */ ! 549: points = (XPoint *)malloc(sizeof (XPoint) * different); ! 550: last = 0; pts = 0; ! 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); ! 557: if (i == different) ! 558: break; ! 559: pts = 0; ! 560: last = i; ! 561: } ! 562: points[pts].x = pix[i].x; ! 563: points[pts].y = pix[i].y; ! 564: pts++; ! 565: } ! 566: free(points); ! 567: ! 568: #endif ! 569: ! 570: } ! 571: ! 572: ! 573: DrawMapInk(SimView *view) ! 574: { ! 575: Pixmap pm = view->pixmap2; ! 576: SimView *v; ! 577: Ink *ink, *ink2 = NewInk(); ! 578: int i, X, Y, x, y; ! 579: ! 580: XSetLineAttributes(view->x->dpy, view->x->gc, 0, ! 581: LineSolid, CapButt, JoinBevel); ! 582: ! 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; ! 586: ! 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); ! 592: } else { ! 593: StartInk(ink2, x, y); ! 594: ! 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; ! 598: AddInk(ink2, x, y); ! 599: } ! 600: ! 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); ! 605: } ! 606: } ! 607: ! 608: FreeInk(ink2); ! 609: } ! 610: ! 611:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.