|
|
1.1 ! root 1: /* w_sprite.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 SpriteCmds; ! 66: short CrashX, CrashY; ! 67: int absDist; ! 68: short Cycle; ! 69: ! 70: SimSprite *GlobalSprites[OBJN]; ! 71: ! 72: SimSprite *NewSprite(char *name, int type, int x, int y); ! 73: ! 74: ! 75: #define TRA_GROOVE_X -39 ! 76: #define TRA_GROOVE_Y 6 ! 77: #define BUS_GROOVE_X -39 ! 78: #define BUS_GROOVE_Y 6 ! 79: ! 80: #define SPRITECMD_ACCESS_INT(var) \ ! 81: int SpriteCmd##var(SPRITE_ARGS) { \ ! 82: int val; \ ! 83: if ((argc != 2) && (argc != 3)) return (TCL_ERROR); \ ! 84: if (argc == 3) { \ ! 85: if (Tcl_GetInt(interp, argv[2], &val) != TCL_OK) return (TCL_ERROR); \ ! 86: sprite->var = val; \ ! 87: } \ ! 88: sprintf(interp->result, "%d", sprite->var); \ ! 89: return (TCL_OK); \ ! 90: } ! 91: ! 92: ! 93: #define SPRITECMD_GET_STR(var) \ ! 94: int SpriteCmd##var(SPRITE_ARGS) { \ ! 95: sprintf(interp->result, "%s", sprite->var); \ ! 96: return (TCL_OK); \ ! 97: } ! 98: ! 99: ! 100: int ! 101: DoSpriteCmd(CLIENT_ARGS) ! 102: { ! 103: SimSprite *sprite = (SimSprite *) clientData; ! 104: Tcl_HashEntry *ent; ! 105: int result = TCL_OK; ! 106: int (*cmd)(); ! 107: ! 108: if (argc < 2) { ! 109: return TCL_ERROR; ! 110: } ! 111: ! 112: if (ent = Tcl_FindHashEntry(&SpriteCmds, argv[1])) { ! 113: cmd = (int (*)())ent->clientData; ! 114: Tk_Preserve((ClientData) sprite); ! 115: result = cmd(sprite, interp, argc, argv); ! 116: Tk_Release((ClientData) sprite); ! 117: } else { ! 118: Tcl_AppendResult(interp, "unknown command name: \"", ! 119: argv[0], " ", argv[1], "\".", (char *) NULL); ! 120: result = TCL_ERROR; ! 121: } ! 122: return result; ! 123: } ! 124: ! 125: ! 126: int ! 127: SpriteCmd(CLIENT_ARGS) ! 128: { ! 129: SimSprite *sprite; ! 130: int type; ! 131: ! 132: if ((argc != 3) || ! 133: (Tcl_GetInt(interp, argv[2], &type) != TCL_OK) || ! 134: (type < 1) || (type >= OBJN)) { ! 135: return TCL_ERROR; ! 136: } ! 137: ! 138: sprite = NewSprite(argv[1], type, 0, 0); ! 139: sprite->frame = 0; ! 140: ! 141: Tcl_CreateCommand(interp, sprite->name, ! 142: DoSpriteCmd, (ClientData) sprite, (void (*)()) NULL); ! 143: ! 144: interp->result = sprite->name; ! 145: return TCL_OK; ! 146: } ! 147: ! 148: ! 149: SPRITECMD_GET_STR(name) ! 150: SPRITECMD_ACCESS_INT(type) ! 151: SPRITECMD_ACCESS_INT(frame) ! 152: SPRITECMD_ACCESS_INT(x) ! 153: SPRITECMD_ACCESS_INT(y) ! 154: SPRITECMD_ACCESS_INT(width) ! 155: SPRITECMD_ACCESS_INT(height) ! 156: SPRITECMD_ACCESS_INT(x_offset) ! 157: SPRITECMD_ACCESS_INT(y_offset) ! 158: SPRITECMD_ACCESS_INT(x_hot) ! 159: SPRITECMD_ACCESS_INT(y_hot) ! 160: SPRITECMD_ACCESS_INT(orig_x) ! 161: SPRITECMD_ACCESS_INT(orig_y) ! 162: SPRITECMD_ACCESS_INT(dest_x) ! 163: SPRITECMD_ACCESS_INT(dest_y) ! 164: SPRITECMD_ACCESS_INT(count) ! 165: SPRITECMD_ACCESS_INT(sound_count) ! 166: SPRITECMD_ACCESS_INT(dir) ! 167: SPRITECMD_ACCESS_INT(new_dir) ! 168: SPRITECMD_ACCESS_INT(step) ! 169: SPRITECMD_ACCESS_INT(flag) ! 170: SPRITECMD_ACCESS_INT(control) ! 171: SPRITECMD_ACCESS_INT(turn) ! 172: SPRITECMD_ACCESS_INT(accel) ! 173: SPRITECMD_ACCESS_INT(speed) ! 174: ! 175: ! 176: int SpriteCmdExplode(SPRITE_ARGS) ! 177: { ! 178: ExplodeSprite(sprite); ! 179: return TCL_OK; ! 180: } ! 181: ! 182: ! 183: int SpriteCmdInit(SPRITE_ARGS) ! 184: { ! 185: int x, y; ! 186: ! 187: if (argc != 4) { ! 188: return (TCL_ERROR); ! 189: } ! 190: if ((Tcl_GetInt(interp, argv[2], &x) != TCL_OK) || ! 191: (x < 0) || (x >= (WORLD_X <<4)) || ! 192: (Tcl_GetInt(interp, argv[3], &y) != TCL_OK) || ! 193: (y < 0) || (y >= (WORLD_Y <<4))) { ! 194: return (TCL_ERROR); ! 195: } ! 196: InitSprite(sprite, x, y); ! 197: return TCL_OK; ! 198: } ! 199: ! 200: ! 201: sprite_command_init() ! 202: { ! 203: int i; ! 204: ! 205: Tcl_CreateCommand(tk_mainInterp, "sprite", SpriteCmd, ! 206: (ClientData)NULL, (void (*)()) NULL); ! 207: ! 208: Tcl_InitHashTable(&SpriteCmds, TCL_STRING_KEYS); ! 209: ! 210: #define SPRITE_CMD(cmd) HASHED_CMD(Sprite, cmd) ! 211: ! 212: SPRITE_CMD(name); ! 213: SPRITE_CMD(type); ! 214: SPRITE_CMD(frame); ! 215: SPRITE_CMD(x); ! 216: SPRITE_CMD(y); ! 217: SPRITE_CMD(width); ! 218: SPRITE_CMD(height); ! 219: SPRITE_CMD(x_offset); ! 220: SPRITE_CMD(y_offset); ! 221: SPRITE_CMD(x_hot); ! 222: SPRITE_CMD(y_hot); ! 223: SPRITE_CMD(orig_x); ! 224: SPRITE_CMD(orig_y); ! 225: SPRITE_CMD(dest_x); ! 226: SPRITE_CMD(dest_y); ! 227: SPRITE_CMD(count); ! 228: SPRITE_CMD(sound_count); ! 229: SPRITE_CMD(dir); ! 230: SPRITE_CMD(new_dir); ! 231: SPRITE_CMD(step); ! 232: SPRITE_CMD(flag); ! 233: SPRITE_CMD(control); ! 234: SPRITE_CMD(turn); ! 235: SPRITE_CMD(accel); ! 236: SPRITE_CMD(speed); ! 237: SPRITE_CMD(Explode); ! 238: SPRITE_CMD(Init); ! 239: ! 240: for (i = 0; i < OBJN; i++) { ! 241: GlobalSprites[i] = NULL; ! 242: } ! 243: } ! 244: ! 245: ! 246: SimSprite *FreeSprites = NULL; ! 247: ! 248: SimSprite * ! 249: NewSprite(char *name, int type, int x, int y) ! 250: { ! 251: SimSprite *sprite; ! 252: ! 253: if (FreeSprites) { ! 254: sprite = FreeSprites; ! 255: FreeSprites = sprite->next; ! 256: } else { ! 257: sprite = (SimSprite *)ckalloc(sizeof (SimSprite)); ! 258: } ! 259: ! 260: sprite->name = (char *)ckalloc(strlen(name) + 1); ! 261: strcpy(sprite->name, name); ! 262: sprite->type = type; ! 263: ! 264: InitSprite(sprite, x, y); ! 265: ! 266: sim->sprites++; sprite->next = sim->sprite; sim->sprite = sprite; ! 267: ! 268: return sprite; ! 269: } ! 270: ! 271: ! 272: InitSprite(SimSprite *sprite, int x, int y) ! 273: { ! 274: sprite->x = x; sprite->y = y; ! 275: sprite->frame = 0; ! 276: sprite->orig_x = sprite->orig_y = 0; ! 277: sprite->dest_x = sprite->dest_y = 0; ! 278: sprite->count = sprite->sound_count = 0; ! 279: sprite->dir = sprite->new_dir = 0; ! 280: sprite->step = sprite->flag = 0; ! 281: sprite->control = -1; ! 282: sprite->turn = 0; ! 283: sprite->accel = 0; ! 284: sprite->speed = 100; ! 285: ! 286: if (GlobalSprites[sprite->type] == NULL) { ! 287: GlobalSprites[sprite->type] = sprite; ! 288: } ! 289: ! 290: switch (sprite->type) { ! 291: ! 292: case TRA: ! 293: sprite->width = sprite->height = 32; ! 294: sprite->x_offset = 32; sprite->y_offset = -16; ! 295: sprite->x_hot = 40; sprite->y_hot = -8; ! 296: sprite->frame = 1; ! 297: sprite->dir = 4; ! 298: break; ! 299: ! 300: case SHI: ! 301: sprite->width = sprite->height = 48; ! 302: sprite->x_offset = 32; sprite->y_offset = -16; ! 303: sprite->x_hot = 48; sprite->y_hot = 0; ! 304: if (x < (4 <<4)) sprite->frame = 3; ! 305: else if (x >= ((WORLD_X - 4) <<4)) sprite->frame = 7; ! 306: else if (y < (4 <<4)) sprite->frame = 5; ! 307: else if (y >= ((WORLD_Y - 4) <<4)) sprite->frame = 1; ! 308: else sprite->frame = 3; ! 309: sprite->new_dir = sprite->frame; ! 310: sprite->dir = 10; ! 311: sprite->count = 1; ! 312: break; ! 313: ! 314: case GOD: ! 315: sprite->width = sprite->height = 48; ! 316: sprite->x_offset = 24; sprite->y_offset = 0; ! 317: sprite->x_hot = 40; sprite->y_hot = 16; ! 318: if (x > ((WORLD_X <<4) / 2)) { ! 319: if (y > ((WORLD_Y <<4) / 2)) sprite->frame = 10; ! 320: else sprite->frame = 7; ! 321: } else if (y > ((WORLD_Y <<4) / 2)) sprite->frame = 1; ! 322: else sprite->frame = 4; ! 323: sprite->count = 1000; ! 324: sprite->dest_x = PolMaxX <<4; ! 325: sprite->dest_y = PolMaxY <<4; ! 326: sprite->orig_x = sprite->x; ! 327: sprite->orig_y = sprite->y; ! 328: break; ! 329: ! 330: case COP: ! 331: sprite->width = sprite->height = 32; ! 332: sprite->x_offset = 32; sprite->y_offset = -16; ! 333: sprite->x_hot = 40; sprite->y_hot = -8; ! 334: sprite->frame = 5; ! 335: sprite->count = 1500; ! 336: sprite->dest_x = Rand((WORLD_X <<4) - 1); ! 337: sprite->dest_y = Rand((WORLD_Y <<4) - 1); ! 338: sprite->orig_x = x - 30; ! 339: sprite->orig_y = y; ! 340: break; ! 341: ! 342: case AIR: ! 343: sprite->width = sprite->height = 48; ! 344: sprite->x_offset = 24; sprite->y_offset = 0; ! 345: sprite->x_hot = 48; sprite->y_hot = 16; ! 346: if (x > ((WORLD_X - 20) <<4)) { ! 347: sprite->x -= 100 + 48; ! 348: sprite->dest_x = sprite->x - 200; ! 349: sprite->frame = 7; ! 350: } else { ! 351: sprite->dest_x = sprite->x + 200; ! 352: sprite->frame = 11; ! 353: } ! 354: sprite->dest_y = sprite->y; ! 355: break; ! 356: ! 357: case TOR: ! 358: sprite->width = sprite->height = 48; ! 359: sprite->x_offset = 24; sprite->y_offset = 0; ! 360: sprite->x_hot = 40; sprite->y_hot = 36; ! 361: sprite->frame = 1; ! 362: sprite->count = 200; ! 363: break; ! 364: ! 365: case EXP: ! 366: sprite->width = sprite->height = 48; ! 367: sprite->x_offset = 24; sprite->y_offset = 0; ! 368: sprite->x_hot = 40; sprite->y_hot = 16; ! 369: sprite->frame = 1; ! 370: break; ! 371: ! 372: case BUS: ! 373: sprite->width = sprite->height = 32; ! 374: sprite->x_offset = 30; sprite->y_offset = -18; ! 375: sprite->x_hot = 40; sprite->y_hot = -8; ! 376: sprite->frame = 1; ! 377: sprite->dir = 1; ! 378: break; ! 379: ! 380: } ! 381: } ! 382: ! 383: ! 384: DestroyAllSprites() ! 385: { ! 386: SimSprite *sprite; ! 387: ! 388: for (sprite = sim->sprite; sprite != NULL; sprite = sprite->next) { ! 389: sprite->frame = 0; ! 390: } ! 391: } ! 392: ! 393: ! 394: DestroySprite(SimSprite *sprite) ! 395: { ! 396: SimView *view; ! 397: SimSprite **sp; ! 398: ! 399: for (view = sim->editor; view != NULL; view = view->next) ! 400: if (view->follow == sprite) ! 401: view->follow = NULL; ! 402: ! 403: if (GlobalSprites[sprite->type] == sprite) { ! 404: GlobalSprites[sprite->type] = (SimSprite *)NULL; ! 405: } ! 406: ! 407: if (sprite->name != NULL) { ! 408: ckfree(sprite->name); ! 409: sprite->name = NULL; ! 410: } ! 411: ! 412: for (sp = &sim->sprite; *sp != NULL; sp = &((*sp)->next)) { ! 413: if (sprite == (*sp)) { ! 414: *sp = sprite->next; ! 415: break; ! 416: } ! 417: } ! 418: ! 419: sprite->next = FreeSprites; ! 420: FreeSprites = sprite; ! 421: } ! 422: ! 423: ! 424: SimSprite * ! 425: GetSprite(int type) ! 426: { ! 427: SimSprite *sprite; ! 428: ! 429: if (((sprite = GlobalSprites[type]) == NULL) || ! 430: (sprite->frame == 0)) ! 431: return (SimSprite *)NULL; ! 432: else ! 433: return sprite; ! 434: } ! 435: ! 436: ! 437: SimSprite * ! 438: MakeSprite(int type, int x, int y) ! 439: { ! 440: SimSprite *sprite; ! 441: ! 442: if ((sprite = GlobalSprites[type]) == NULL) { ! 443: sprite = NewSprite("", type, x, y); ! 444: } else { ! 445: InitSprite(sprite, x, y); ! 446: } ! 447: return sprite; ! 448: } ! 449: ! 450: ! 451: SimSprite * ! 452: MakeNewSprite(int type, int x, int y) ! 453: { ! 454: SimSprite *sprite; ! 455: ! 456: sprite = NewSprite("", type, x, y); ! 457: return sprite; ! 458: } ! 459: ! 460: ! 461: DrawObjects(SimView *view) ! 462: { ! 463: SimSprite *sprite; ! 464: ! 465: /* XXX: sort these by layer */ ! 466: /* ! 467: if (z = Oframe[TRA]) DrawTrain(view, z); ! 468: if (z = Oframe[SHI]) DrawBoat(view, z); ! 469: if (z = Oframe[GOD]) DrawMonster(view, z); ! 470: if (z = Oframe[COP]) DrawCopter(view, z); ! 471: if (z = Oframe[AIR]) DrawPlane(view, z); ! 472: if (z = Oframe[TOR]) DrawTor(view, z); ! 473: if (z = Oframe[EXP]) DrawExp(view, z); ! 474: */ ! 475: ! 476: for (sprite = sim->sprite; sprite != NULL; sprite = sprite->next) { ! 477: DrawSprite(view, sprite); ! 478: } ! 479: } ! 480: ! 481: ! 482: DrawSprite(SimView *view, SimSprite *sprite) ! 483: { ! 484: Pixmap pict, mask; ! 485: int x, y, i; ! 486: ! 487: if (sprite->frame == 0) ! 488: return; ! 489: ! 490: i = (sprite->frame - 1) * 2; ! 491: pict = view->x->objects[sprite->type][i]; ! 492: mask = view->x->objects[sprite->type][i + 1]; ! 493: ! 494: x = sprite->x ! 495: - ((view->tile_x <<4) - view->screen_x) ! 496: + sprite->x_offset; ! 497: y = sprite->y ! 498: - ((view->tile_y <<4) - view->screen_y) ! 499: + sprite->y_offset; ! 500: ! 501: XSetClipMask(view->x->dpy, view->x->gc, mask); ! 502: XSetClipOrigin(view->x->dpy, view->x->gc, x, y); ! 503: XCopyArea(view->x->dpy, pict, view->pixmap2, view->x->gc, ! 504: 0, 0, sprite->width, sprite->height, x, y); ! 505: XSetClipMask(view->x->dpy, view->x->gc, None); ! 506: XSetClipOrigin(view->x->dpy, view->x->gc, 0, 0); ! 507: } ! 508: ! 509: ! 510: short GetChar(int x, int y) ! 511: { ! 512: x >>= 4; ! 513: y >>= 4; ! 514: if (!TestBounds(x, y)) ! 515: return(-1); ! 516: else ! 517: return(Map[x][y] & LOMASK); ! 518: } ! 519: ! 520: ! 521: short TurnTo(int p, int d) ! 522: { ! 523: if (p == d) return(p); ! 524: if (p < d) ! 525: if ((d - p) < 4) p++; ! 526: else p--; ! 527: else ! 528: if ((p - d) < 4) p--; ! 529: else p++; ! 530: if (p > 8) p = 1; ! 531: if (p < 1) p = 8; ! 532: return(p); ! 533: } ! 534: ! 535: ! 536: TryOther(int Tpoo, int Told, int Tnew) ! 537: { ! 538: register short z; ! 539: ! 540: z = Told + 4; ! 541: if (z > 8) z -= 8; ! 542: if (Tnew != z) return(0); ! 543: if ((Tpoo == POWERBASE) || (Tpoo == POWERBASE + 1) || ! 544: (Tpoo == RAILBASE) || (Tpoo == RAILBASE + 1)) ! 545: return(1); ! 546: return(0); ! 547: } ! 548: ! 549: ! 550: short SpriteNotInBounds(SimSprite *sprite) ! 551: { ! 552: int x = sprite->x + sprite->x_hot; ! 553: int y = sprite->y + sprite->y_hot; ! 554: ! 555: if ((x < 0) || (y < 0) || ! 556: (x >= (WORLD_X <<4)) || ! 557: (y >= (WORLD_Y <<4))) { ! 558: return (1); ! 559: } ! 560: return (0); ! 561: } ! 562: ! 563: ! 564: short GetDir(int orgX, int orgY, int desX, int desY) ! 565: { ! 566: static short Gdtab[13] = { 0, 3, 2, 1, 3, 4, 5, 7, 6, 5, 7, 8, 1 }; ! 567: int dispX, dispY, z; ! 568: ! 569: dispX = desX - orgX; ! 570: dispY = desY - orgY; ! 571: if (dispX < 0) ! 572: if (dispY < 0) z = 11; ! 573: else z = 8; ! 574: else ! 575: if (dispY < 0) z = 2; ! 576: else z = 5; ! 577: if (dispX < 0) dispX = -dispX; ! 578: if (dispY < 0) dispY = -dispY; ! 579: ! 580: absDist = dispX + dispY; ! 581: ! 582: if ((dispX <<1) < dispY) z++; ! 583: else if ((dispY <<1) < dispY) z--; ! 584: ! 585: if ((z < 0) || (z > 12)) z = 0; ! 586: ! 587: return (Gdtab[z]); ! 588: } ! 589: ! 590: ! 591: GetDis(int x1, int y1, int x2, int y2) ! 592: { ! 593: register short dispX, dispY; ! 594: ! 595: if (x1 > x2) dispX = x1 - x2; ! 596: else dispX = x2 - x1; ! 597: if (y1 > y2) dispY = y1 - y2; ! 598: else dispY = y2 - y1; ! 599: ! 600: return (dispX + dispY); ! 601: } ! 602: ! 603: ! 604: int CheckSpriteCollision(SimSprite *s1, SimSprite *s2) ! 605: { ! 606: if ((s1->frame != 0) && (s2->frame != 0) && ! 607: GetDis(s1->x + s1->x_hot, s1->y + s1->y_hot, ! 608: s2->x + s2->x_hot, s2->y + s2->y_hot) < 30) ! 609: return(1); ! 610: return(0); ! 611: } ! 612: ! 613: ! 614: MoveObjects() ! 615: { ! 616: SimSprite *sprite; ! 617: ! 618: if (!SimSpeed) return; ! 619: Cycle++; ! 620: ! 621: for (sprite = sim->sprite; sprite != NULL;) { ! 622: if (sprite->frame) { ! 623: switch (sprite->type) { ! 624: case TRA: ! 625: DoTrainSprite(sprite); ! 626: break; ! 627: case COP: ! 628: DoCopterSprite(sprite); ! 629: break; ! 630: case AIR: ! 631: DoAirplaneSprite(sprite); ! 632: break; ! 633: case SHI: ! 634: DoShipSprite(sprite); ! 635: break; ! 636: case GOD: ! 637: DoMonsterSprite(sprite); ! 638: break; ! 639: case TOR: ! 640: DoTornadoSprite(sprite); ! 641: break; ! 642: case EXP: ! 643: DoExplosionSprite(sprite); ! 644: break; ! 645: case BUS: ! 646: DoBusSprite(sprite); ! 647: break; ! 648: } ! 649: sprite = sprite->next; ! 650: } else { ! 651: if (sprite->name[0] == '\0') { ! 652: SimSprite *s = sprite; ! 653: sprite = sprite->next; ! 654: DestroySprite(s); ! 655: } else { ! 656: sprite = sprite->next; ! 657: } ! 658: } ! 659: } ! 660: } ! 661: ! 662: ! 663: DoTrainSprite(SimSprite *sprite) ! 664: { ! 665: static short Cx[4] = { 0, 16, 0, -16 }; ! 666: static short Cy[4] = { -16, 0, 16, 0 }; ! 667: static short Dx[5] = { 0, 4, 0, -4, 0 }; ! 668: static short Dy[5] = { -4, 0, 4, 0, 0 }; ! 669: static short TrainPic2[5] = { 1, 2, 1, 2, 5 }; ! 670: register short z, dir, dir2; ! 671: short c; ! 672: ! 673: if ((sprite->frame == 3) || (sprite->frame == 4)) ! 674: sprite->frame = TrainPic2[sprite->dir]; ! 675: sprite->x += Dx[sprite->dir]; ! 676: sprite->y += Dy[sprite->dir]; ! 677: if (!(Cycle & 3)) { ! 678: dir = Rand16() & 3; ! 679: for (z = dir; z < (dir + 4); z++) { ! 680: dir2 = z & 3; ! 681: if (sprite->dir != 4) { ! 682: if (dir2 == ((sprite->dir + 2) & 3)) continue; ! 683: } ! 684: c = GetChar(sprite->x + Cx[dir2] + 48, ! 685: sprite->y + Cy[dir2]); ! 686: if (((c >= RAILBASE) && (c <= LASTRAIL)) || /* track? */ ! 687: (c == RAILVPOWERH) || ! 688: (c == RAILHPOWERV)) { ! 689: if ((sprite->dir != dir2) && ! 690: (sprite->dir != 4)) { ! 691: if ((sprite->dir + dir2) == 3) ! 692: sprite->frame = 3; ! 693: else ! 694: sprite->frame = 4; ! 695: } else ! 696: sprite->frame = TrainPic2[dir2]; ! 697: ! 698: if ((c == RAILBASE) || (c == (RAILBASE + 1))) ! 699: sprite->frame = 5; ! 700: sprite->dir = dir2; ! 701: return; ! 702: } ! 703: } ! 704: if (sprite->dir == 4) { ! 705: sprite->frame = 0; ! 706: return; ! 707: } ! 708: sprite->dir = 4; ! 709: } ! 710: } ! 711: ! 712: ! 713: DoCopterSprite(SimSprite *sprite) ! 714: { ! 715: static short CDx[9] = { 0, 0, 3, 5, 3, 0, -3, -5, -3 }; ! 716: static short CDy[9] = { 0, -5, -3, 0, 3, 5, 3, 0, -3 }; ! 717: register short z, d, x, y; ! 718: ! 719: if (sprite->sound_count > 0) sprite->sound_count--; ! 720: ! 721: if (sprite->control < 0) { ! 722: ! 723: if (sprite->count > 0) sprite->count--; ! 724: ! 725: if (!sprite->count) { ! 726: /* Attract copter to monster and tornado so it blows up more often */ ! 727: SimSprite *s = GetSprite(GOD); ! 728: if (s != NULL) { ! 729: sprite->dest_x = s->x; ! 730: sprite->dest_y = s->y; ! 731: } else { ! 732: s = GetSprite(TOR); ! 733: if (s != NULL) { ! 734: sprite->dest_x = s->x; ! 735: sprite->dest_y = s->y; ! 736: } else { ! 737: sprite->dest_x = sprite->orig_x; ! 738: sprite->dest_y = sprite->orig_y; ! 739: } ! 740: } ! 741: } ! 742: if (!sprite->count) { /* land */ ! 743: GetDir(sprite->x, sprite->y, sprite->orig_x, sprite->orig_y); ! 744: if (absDist < 30) { ! 745: sprite->frame = 0; ! 746: return; ! 747: } ! 748: } ! 749: } else { ! 750: GetDir(sprite->x, sprite->y, sprite->dest_x, sprite->dest_y); ! 751: if (absDist < 16) { ! 752: sprite->dest_x = sprite->orig_x; ! 753: sprite->dest_y = sprite->orig_y; ! 754: sprite->control = -1; ! 755: } ! 756: } ! 757: ! 758: if (!sprite->sound_count) { /* send report */ ! 759: x = (sprite->x + 48) >>5; ! 760: y = sprite->y >>5; ! 761: if ((x >= 0) && ! 762: (x < (WORLD_X >>1)) && ! 763: (y >= 0) && ! 764: (y < (WORLD_Y >>1))) { ! 765: /* Don changed from 160 to 170 to shut the #$%#$% thing up! */ ! 766: if ((TrfDensity[x][y] > 170) && ((Rand16() & 7) == 0)) { ! 767: SendMesAt(-41, (x <<1) + 1, (y <<1) + 1); ! 768: MakeSound("city", "HeavyTraffic"); /* chopper */ ! 769: sprite->sound_count = 200; ! 770: } ! 771: } ! 772: } ! 773: z = sprite->frame; ! 774: if (!(Cycle & 3)) { ! 775: d = GetDir(sprite->x, sprite->y, sprite->dest_x, sprite->dest_y); ! 776: z = TurnTo(z, d); ! 777: sprite->frame = z; ! 778: } ! 779: ! 780: sprite->x += CDx[z]; ! 781: sprite->y += CDy[z]; ! 782: } ! 783: ! 784: ! 785: DoAirplaneSprite(SimSprite *sprite) ! 786: { ! 787: static short CDx[12] = { 0, 0, 6, 8, 6, 0, -6, -8, -6, 8, 8, 8 }; ! 788: static short CDy[12] = { 0, -8, -6, 0, 6, 8, 6, 0, -6, 0, 0, 0 }; ! 789: ! 790: register short z, d; ! 791: ! 792: z = sprite->frame; ! 793: ! 794: if (!(Cycle % 5)) { ! 795: if (z > 8) { /* TakeOff */ ! 796: z--; ! 797: if (z < 9) z = 3; ! 798: sprite->frame = z; ! 799: } else { /* goto destination */ ! 800: d = GetDir(sprite->x, sprite->y, sprite->dest_x, sprite->dest_y); ! 801: z = TurnTo(z, d); ! 802: sprite->frame = z; ! 803: } ! 804: } ! 805: ! 806: if (absDist < 50) { /* at destination */ ! 807: sprite->dest_x = Rand((WORLD_X * 16) + 100) - 50; ! 808: sprite->dest_y = Rand((WORLD_Y * 16) + 100) - 50; ! 809: } ! 810: ! 811: /* deh added test for !Disasters */ ! 812: if (!NoDisasters) { ! 813: SimSprite *s; ! 814: int explode = 0; ! 815: ! 816: for (s = sim->sprite; s != NULL; s = s->next) { ! 817: if ((s->frame != 0) && ! 818: ((s->type == COP) || ! 819: ((sprite != s) && ! 820: (s->type == AIR))) && ! 821: CheckSpriteCollision(sprite, s)) { ! 822: ExplodeSprite(s); ! 823: explode = 1; ! 824: } ! 825: } ! 826: if (explode) ! 827: ExplodeSprite(sprite); ! 828: } ! 829: ! 830: sprite->x += CDx[z]; ! 831: sprite->y += CDy[z]; ! 832: if (SpriteNotInBounds(sprite)) sprite->frame = 0; ! 833: } ! 834: ! 835: ! 836: DoShipSprite(SimSprite *sprite) ! 837: { ! 838: static short BDx[9] = { 0, 0, 1, 1, 1, 0, -1, -1, -1 }; ! 839: static short BDy[9] = { 0, -1, -1, 0, 1, 1, 1, 0, -1 }; ! 840: static short BPx[9] = { 0, 0, 2, 2, 2, 0, -2, -2, -2 }; ! 841: static short BPy[9] = { 0, -2, -2, 0, 2, 2, 2, 0, -2 }; ! 842: static short BtClrTab[8] = { RIVER, CHANNEL, POWERBASE, POWERBASE + 1, ! 843: RAILBASE, RAILBASE + 1, BRWH, BRWV }; ! 844: register short x, y, z, t = RIVER; ! 845: short tem, pem; ! 846: ! 847: if (sprite->sound_count > 0) sprite->sound_count--; ! 848: if (!sprite->sound_count) { ! 849: if ((Rand16() & 3) == 1) { ! 850: if ((ScenarioID == 2) && /* San Francisco */ ! 851: (Rand(10) < 5)) { ! 852: MakeSound("city", "HonkHonk-Low -speed 80"); ! 853: } else { ! 854: MakeSound("city", "HonkHonk-Low"); ! 855: } ! 856: } ! 857: sprite->sound_count = 200; ! 858: } ! 859: ! 860: if (sprite->count > 0) sprite->count--; ! 861: if (!sprite->count) { ! 862: sprite->count = 9; ! 863: if (sprite->frame != sprite->new_dir) { ! 864: sprite->frame = TurnTo(sprite->frame, sprite->new_dir); ! 865: return; ! 866: } ! 867: tem = Rand16() & 7; ! 868: for (pem = tem; pem < (tem + 8); pem++) { ! 869: z = (pem & 7) + 1; ! 870: ! 871: if (z == sprite->dir) continue; ! 872: x = ((sprite->x + (48 - 1)) >>4) + BDx[z]; ! 873: y = (sprite->y >>4) + BDy[z]; ! 874: if (TestBounds(x, y)) { ! 875: t = Map[x][y] & LOMASK; ! 876: if ((t == CHANNEL) || (t == BRWH) || (t == BRWV) || ! 877: TryOther(t, sprite->dir, z)) { ! 878: sprite->new_dir = z; ! 879: sprite->frame = TurnTo(sprite->frame, sprite->new_dir); ! 880: sprite->dir = z + 4; ! 881: if (sprite->dir > 8) sprite->dir -= 8; ! 882: break; ! 883: } ! 884: } ! 885: } ! 886: if (pem == (tem + 8)) { ! 887: sprite->dir = 10; ! 888: sprite->new_dir = (Rand16() & 7) + 1; ! 889: } ! 890: } else { ! 891: z = sprite->frame; ! 892: if (z == sprite->new_dir) { ! 893: sprite->x += BPx[z]; ! 894: sprite->y += BPy[z]; ! 895: } ! 896: } ! 897: if (SpriteNotInBounds(sprite)) { ! 898: sprite->frame = 0; ! 899: return; ! 900: } ! 901: for (z = 0; z < 8; z++) { ! 902: if (t == BtClrTab[z]) break; ! 903: if (z == 7) { ! 904: ExplodeSprite(sprite); ! 905: Destroy(sprite->x + 48, sprite->y); ! 906: } ! 907: } ! 908: } ! 909: ! 910: ! 911: DoMonsterSprite(SimSprite *sprite) ! 912: { ! 913: static short Gx[5] = { 2, 2, -2, -2, 0 }; ! 914: static short Gy[5] = { -2, 2, 2, -2, 0 }; ! 915: static short ND1[4] = { 0, 1, 2, 3 }; ! 916: static short ND2[4] = { 1, 2, 3, 0 }; ! 917: static short nn1[4] = { 2, 5, 8, 11 }; ! 918: static short nn2[4] = { 11, 2, 5, 8 }; ! 919: register short d, z, c; ! 920: ! 921: if (sprite->sound_count > 0) sprite->sound_count--; ! 922: ! 923: if (sprite->control < 0) { ! 924: /* business as usual */ ! 925: ! 926: if (sprite->control == -2) { ! 927: d = (sprite->frame - 1) / 3; ! 928: z = (sprite->frame - 1) % 3; ! 929: if (z == 2) sprite->step = 0; ! 930: if (z == 0) sprite->step = 1; ! 931: if (sprite->step) z++; ! 932: else z--; ! 933: c = GetDir(sprite->x, sprite->y, sprite->dest_x, sprite->dest_y); ! 934: if (absDist < 18) { ! 935: sprite->control = -1; ! 936: sprite->count = 1000; ! 937: sprite->flag = 1; ! 938: sprite->dest_x = sprite->orig_x; ! 939: sprite->dest_y = sprite->orig_y; ! 940: } else { ! 941: c = (c - 1) / 2; ! 942: if (((c != d) && (!Rand(5))) || ! 943: (!Rand(20))) { ! 944: int diff = (c - d) & 3; ! 945: if ((diff == 1) || (diff == 3)) { ! 946: d = c; ! 947: } else { ! 948: if (Rand16() & 1) d++; else d--; ! 949: d &= 3; ! 950: } ! 951: } else { ! 952: if (!Rand(20)) { ! 953: if (Rand16() & 1) d++; else d--; ! 954: d &= 3; ! 955: } ! 956: } ! 957: } ! 958: } else { ! 959: ! 960: d = (sprite->frame - 1) / 3; ! 961: ! 962: if (d < 4) { /* turn n s e w */ ! 963: z = (sprite->frame - 1) % 3; ! 964: if (z == 2) sprite->step = 0; ! 965: if (z == 0) sprite->step = 1; ! 966: if (sprite->step) z++; ! 967: else z--; ! 968: GetDir(sprite->x, sprite->y, sprite->dest_x, sprite->dest_y); ! 969: if (absDist < 60) { ! 970: if (sprite->flag == 0) { ! 971: sprite->flag = 1; ! 972: sprite->dest_x = sprite->orig_x; ! 973: sprite->dest_y = sprite->orig_y; ! 974: } else { ! 975: sprite->frame = 0; ! 976: return; ! 977: } ! 978: } ! 979: c = GetDir(sprite->x, sprite->y, sprite->dest_x, sprite->dest_y); ! 980: c = (c - 1) / 2; ! 981: if ((c != d) && (!Rand(10))) { ! 982: if (Rand16() & 1) z = ND1[d]; ! 983: else z = ND2[d]; ! 984: d = 4; ! 985: if (!sprite->sound_count) { ! 986: MakeSound("city", "Monster -speed [MonsterSpeed]"); /* monster */ ! 987: sprite->sound_count = 50 + Rand(100); ! 988: } ! 989: } ! 990: } else { ! 991: d = 4; ! 992: c = sprite->frame; ! 993: z = (c - 13) & 3; ! 994: if (!(Rand16() & 3)) { ! 995: if (Rand16() & 1) z = nn1[z]; ! 996: else z = nn2[z]; ! 997: d = (z - 1) / 3; ! 998: z = (z - 1) % 3; ! 999: } ! 1000: } ! 1001: } ! 1002: } else { ! 1003: /* somebody's taken control of the monster */ ! 1004: ! 1005: d = sprite->control; ! 1006: z = (sprite->frame - 1) % 3; ! 1007: ! 1008: if (z == 2) sprite->step = 0; ! 1009: if (z == 0) sprite->step = 1; ! 1010: if (sprite->step) z++; ! 1011: else z--; ! 1012: } ! 1013: ! 1014: z = (((d * 3) + z) + 1); ! 1015: if (z > 16) z = 16; ! 1016: sprite->frame = z; ! 1017: ! 1018: sprite->x += Gx[d]; ! 1019: sprite->y += Gy[d]; ! 1020: ! 1021: if (sprite->count > 0) sprite->count--; ! 1022: c = GetChar(sprite->x + sprite->x_hot, sprite->y + sprite->y_hot); ! 1023: if ((c == -1) || ! 1024: ((c == RIVER) && ! 1025: (sprite->count != 0) && ! 1026: (sprite->control == -1))) { ! 1027: sprite->frame = 0; /* kill zilla */ ! 1028: } ! 1029: ! 1030: { SimSprite *s; ! 1031: for (s = sim->sprite; s != NULL; s = s->next) { ! 1032: if ((s->frame != 0) && ! 1033: ((s->type == AIR) || ! 1034: (s->type == COP) || ! 1035: (s->type == SHI) || ! 1036: (s->type == TRA)) && ! 1037: CheckSpriteCollision(sprite, s)) { ! 1038: ExplodeSprite(s); ! 1039: } ! 1040: } ! 1041: } ! 1042: ! 1043: Destroy(sprite->x + 48, sprite->y + 16); ! 1044: } ! 1045: ! 1046: ! 1047: DoTornadoSprite(SimSprite *sprite) ! 1048: { ! 1049: static short CDx[9] = { 2, 3, 2, 0, -2, -3 }; ! 1050: static short CDy[9] = { -2, 0, 2, 3, 2, 0 }; ! 1051: register short z; ! 1052: ! 1053: z = sprite->frame; ! 1054: ! 1055: if (z == 2) /* cycle animation... post Rel */ ! 1056: if (sprite->flag) ! 1057: z = 3; ! 1058: else ! 1059: z = 1; ! 1060: else { ! 1061: if (z == 1) ! 1062: sprite->flag = 1; ! 1063: else ! 1064: sprite->flag = 0; ! 1065: z = 2; ! 1066: } ! 1067: ! 1068: if (sprite->count > 0) sprite->count--; ! 1069: ! 1070: sprite->frame = z; ! 1071: ! 1072: { SimSprite *s; ! 1073: for (s = sim->sprite; s != NULL; s = s->next) { ! 1074: if ((s->frame != 0) && ! 1075: ((s->type == AIR) || ! 1076: (s->type == COP) || ! 1077: (s->type == SHI) || ! 1078: (s->type == TRA)) && ! 1079: CheckSpriteCollision(sprite, s)) { ! 1080: ExplodeSprite(s); ! 1081: } ! 1082: } ! 1083: } ! 1084: ! 1085: z = Rand(5); ! 1086: sprite->x += CDx[z]; ! 1087: sprite->y += CDy[z]; ! 1088: if (SpriteNotInBounds(sprite)) sprite->frame = 0; ! 1089: ! 1090: if ((sprite->count != 0) && ! 1091: (!Rand(500))) ! 1092: sprite->frame = 0; ! 1093: ! 1094: Destroy(sprite->x + 48, sprite->y + 40); ! 1095: } ! 1096: ! 1097: ! 1098: DoExplosionSprite(SimSprite *sprite) ! 1099: { ! 1100: short x, y; ! 1101: ! 1102: if (!(Cycle & 1)) { ! 1103: if (sprite->frame == 1) { ! 1104: MakeSound("city", "Explosion-High"); /* explosion */ ! 1105: x = (sprite->x >>4) + 3; ! 1106: y = (sprite->y >>4); ! 1107: SendMesAt(32, x, y); ! 1108: } ! 1109: sprite->frame++; ! 1110: } ! 1111: ! 1112: if (sprite->frame > 6) { ! 1113: sprite->frame = 0; ! 1114: ! 1115: StartFire(sprite->x + 48 - 8, sprite->y + 16); ! 1116: StartFire(sprite->x + 48 - 24, sprite->y); ! 1117: StartFire(sprite->x + 48 + 8, sprite->y); ! 1118: StartFire(sprite->x + 48 - 24, sprite->y + 32); ! 1119: StartFire(sprite->x + 48 + 8, sprite->y + 32); ! 1120: return; ! 1121: } ! 1122: } ! 1123: ! 1124: ! 1125: DoBusSprite(SimSprite *sprite) ! 1126: { ! 1127: static short Dx[5] = { 0, 1, 0, -1, 0 }; ! 1128: static short Dy[5] = { -1, 0, 1, 0, 0 }; ! 1129: static short Dir2Frame[4] = { 1, 2, 1, 2 }; ! 1130: register int dir, dir2; ! 1131: int c, dx, dy, crossed, tx, ty, otx, oty; ! 1132: int turned = 0; ! 1133: int speed, z; ! 1134: ! 1135: #ifdef DEBUGBUS ! 1136: printf("Bus dir %d turn %d frame %d\n", ! 1137: sprite->dir, sprite->turn, sprite->frame); ! 1138: #endif ! 1139: ! 1140: if (sprite->turn) { ! 1141: if (sprite->turn < 0) { /* ccw */ ! 1142: if (sprite->dir & 1) { /* up or down */ ! 1143: sprite->frame = 4; ! 1144: } else { /* left or right */ ! 1145: sprite->frame = 3; ! 1146: } ! 1147: sprite->turn++; ! 1148: sprite->dir = (sprite->dir - 1) & 3; ! 1149: } else { /* cw */ ! 1150: if (sprite->dir & 1) { /* up or down */ ! 1151: sprite->frame = 3; ! 1152: } else { /* left or right */ ! 1153: sprite->frame = 4; ! 1154: } ! 1155: sprite->turn--; ! 1156: sprite->dir = (sprite->dir + 1) & 3; ! 1157: } ! 1158: turned = 1; ! 1159: } else { ! 1160: /* finish turn */ ! 1161: if ((sprite->frame == 3) || (sprite->frame == 4)) { ! 1162: turned = 1; ! 1163: sprite->frame = Dir2Frame[sprite->dir]; ! 1164: } ! 1165: } ! 1166: ! 1167: if (sprite->speed == 0) { ! 1168: /* brake */ ! 1169: dx = 0; dy = 0; ! 1170: } else { /* cruise at traffic speed */ ! 1171: ! 1172: tx = (sprite->x + sprite->x_hot) >>5; ! 1173: ty = (sprite->y + sprite->y_hot) >>5; ! 1174: if ((tx >= 0) && ! 1175: (tx < (WORLD_X >>1)) && ! 1176: (ty >= 0) && ! 1177: (ty < (WORLD_Y >>1))) { ! 1178: z = TrfDensity[tx][ty] >>6; ! 1179: if (z > 1) z--; ! 1180: } else z = 0; ! 1181: ! 1182: switch (z) { ! 1183: case 0: ! 1184: speed = 8; ! 1185: break; ! 1186: case 1: ! 1187: speed = 4; ! 1188: break; ! 1189: case 2: ! 1190: speed = 1; ! 1191: break; ! 1192: } ! 1193: ! 1194: /* govern speed */ ! 1195: if (speed > sprite->speed) ! 1196: speed = sprite->speed; ! 1197: ! 1198: if (turned) { ! 1199: #ifdef DEBUGBUS ! 1200: printf("turned\n"); ! 1201: #endif ! 1202: if (speed > 1) speed = 1; ! 1203: dx = Dx[sprite->dir] * speed; ! 1204: dy = Dy[sprite->dir] * speed; ! 1205: } else { ! 1206: dx = Dx[sprite->dir] * speed; ! 1207: dy = Dy[sprite->dir] * speed; ! 1208: ! 1209: tx = (sprite->x + sprite->x_hot) >>4; ! 1210: ty = (sprite->y + sprite->y_hot) >>4; ! 1211: ! 1212: /* drift into the right lane */ ! 1213: switch (sprite->dir) { ! 1214: case 0: /* up */ ! 1215: z = ((tx <<4) + 4) - (sprite->x + sprite->x_hot); ! 1216: if (z < 0) dx = -1; ! 1217: else if (z > 0) dx = 1; ! 1218: #ifdef DEBUGBUS ! 1219: printf("moving up x %x z %d dx %d\n", sprite->x + sprite->x_hot, z, dx); ! 1220: #endif ! 1221: break; ! 1222: case 1: /* right */ ! 1223: z = ((ty <<4) + 4) - (sprite->y + sprite->y_hot); ! 1224: if (z < 0) dy = -1; ! 1225: else if (z > 0) dy = 1; ! 1226: #ifdef DEBUGBUS ! 1227: printf("moving right y %x z %d dy %d\n", sprite->y + sprite->y_hot, z, dy); ! 1228: #endif ! 1229: break; ! 1230: case 2: /* down */ ! 1231: z = ((tx <<4)) - (sprite->x + sprite->x_hot); ! 1232: if (z < 0) dx = -1; ! 1233: else if (z > 0) dx = 1; ! 1234: #ifdef DEBUGBUS ! 1235: printf("moving down x %x z %d dx %d\n", sprite->x + sprite->x_hot, z, dx); ! 1236: #endif ! 1237: break; ! 1238: case 3: /* left */ ! 1239: z = ((ty <<4)) - (sprite->y + sprite->y_hot); ! 1240: if (z < 0) dy = -1; ! 1241: else if (z > 0) dy = 1; ! 1242: #ifdef DEBUGBUS ! 1243: printf("moving left y %x z %d dy %d\n", sprite->y + sprite->y_hot, z, dy); ! 1244: #endif ! 1245: break; ! 1246: } ! 1247: } ! 1248: } ! 1249: #ifdef DEBUGBUS ! 1250: printf("speed dx %d dy %d\n", dx, dy); ! 1251: #endif ! 1252: ! 1253: #define AHEAD 8 ! 1254: ! 1255: otx = (sprite->x + sprite->x_hot + (Dx[sprite->dir] * AHEAD)) >>4; ! 1256: oty = (sprite->y + sprite->y_hot + (Dy[sprite->dir] * AHEAD)) >>4; ! 1257: if (otx < 0) otx = 0; else if (otx >= WORLD_X) otx = WORLD_X - 1; ! 1258: if (oty < 0) oty = 0; else if (oty >= WORLD_Y) oty = WORLD_Y - 1; ! 1259: ! 1260: tx = (sprite->x + sprite->x_hot + dx + (Dx[sprite->dir] * AHEAD)) >>4; ! 1261: ty = (sprite->y + sprite->y_hot + dy + (Dy[sprite->dir] * AHEAD)) >>4; ! 1262: if (tx < 0) tx = 0; else if (tx >= WORLD_X) tx = WORLD_X - 1; ! 1263: if (ty < 0) ty = 0; else if (ty >= WORLD_Y) ty = WORLD_Y - 1; ! 1264: ! 1265: if ((tx != otx) || (ty != oty)) { ! 1266: #ifdef DEBUGBUS ! 1267: printf("drive from tile %d %d to %d %d\n", ! 1268: otx, oty, tx, ty); ! 1269: #endif ! 1270: z = CanDriveOn(tx, ty); ! 1271: if (z == 0) { ! 1272: /* can't drive forward into a new tile */ ! 1273: if (speed == 8) { ! 1274: bulldozer_tool(NULL, tx, ty); ! 1275: } else { ! 1276: } ! 1277: } else { ! 1278: /* drive forward into a new tile */ ! 1279: if (z > 0) { ! 1280: /* smooth */ ! 1281: } else { ! 1282: /* bumpy */ ! 1283: dx /= 2; ! 1284: dy /= 2; ! 1285: } ! 1286: } ! 1287: } ! 1288: ! 1289: tx = (sprite->x + sprite->x_hot + dx) >>4; ! 1290: ty = (sprite->y + sprite->y_hot + dy) >>4; ! 1291: z = CanDriveOn(tx, ty); ! 1292: if (z > 0) { ! 1293: /* cool, cruise along */ ! 1294: } else { ! 1295: if (z < 0) { ! 1296: /* bumpy */ ! 1297: } else { ! 1298: /* something in the way */ ! 1299: } ! 1300: } ! 1301: ! 1302: sprite->x += dx; ! 1303: sprite->y += dy; ! 1304: ! 1305: if (!NoDisasters) { ! 1306: SimSprite *s; ! 1307: int explode = 0; ! 1308: ! 1309: for (s = sim->sprite; s != NULL; s = s->next) { ! 1310: if ((sprite != s) && ! 1311: (s->frame != 0) && ! 1312: ((s->type == BUS) || ! 1313: ((s->type == TRA) && ! 1314: (s->frame != 5))) && ! 1315: CheckSpriteCollision(sprite, s)) { ! 1316: ExplodeSprite(s); ! 1317: explode = 1; ! 1318: } ! 1319: } ! 1320: if (explode) ! 1321: ExplodeSprite(sprite); ! 1322: } ! 1323: } ! 1324: ! 1325: ! 1326: int ! 1327: CanDriveOn(int x, int y) ! 1328: { ! 1329: int tile; ! 1330: ! 1331: if (!TestBounds(x, y)) ! 1332: return 0; ! 1333: ! 1334: tile = Map[x][y] & LOMASK; ! 1335: ! 1336: if (((tile >= ROADBASE) && ! 1337: (tile <= LASTROAD) && ! 1338: (tile != BRWH) && ! 1339: (tile != BRWV)) || ! 1340: (tile == HRAILROAD) || ! 1341: (tile == VRAILROAD)) ! 1342: return 1; ! 1343: ! 1344: if ((tile == DIRT) || tally(tile)) ! 1345: return -1; ! 1346: ! 1347: return 0; ! 1348: } ! 1349: ! 1350: ! 1351: ExplodeSprite(SimSprite *sprite) ! 1352: { ! 1353: int x, y; ! 1354: ! 1355: sprite->frame = 0; ! 1356: ! 1357: x = sprite->x + sprite->x_hot; ! 1358: y = sprite->y + sprite->y_hot; ! 1359: MakeExplosionAt(x, y); ! 1360: ! 1361: x = (x >>4); ! 1362: y = (y >>4); ! 1363: ! 1364: switch (sprite->type) { ! 1365: case AIR: ! 1366: CrashX = x; ! 1367: CrashY = y; ! 1368: SendMesAt(-24, x, y); ! 1369: break; ! 1370: case SHI: ! 1371: CrashX = x; ! 1372: CrashY = y; ! 1373: SendMesAt(-25, x, y); ! 1374: break; ! 1375: case TRA: ! 1376: CrashX = x; ! 1377: CrashY = y; ! 1378: SendMesAt(-26, x, y); ! 1379: break; ! 1380: case COP: ! 1381: CrashX = x; ! 1382: CrashY = y; ! 1383: SendMesAt(-27, x, y); ! 1384: break; ! 1385: case BUS: ! 1386: CrashX = x; ! 1387: CrashY = y; ! 1388: SendMesAt(-26, x, y); /* XXX for now */ ! 1389: break; ! 1390: } ! 1391: MakeSound("city", "Explosion-High"); /* explosion */ ! 1392: return; ! 1393: } ! 1394: ! 1395: ! 1396: int checkWet(int x) ! 1397: { ! 1398: if ((x == POWERBASE) || (x == POWERBASE + 1) || ! 1399: (x == RAILBASE) || (x == RAILBASE + 1) || ! 1400: (x == BRWH) || (x == BRWV)) ! 1401: return(1); ! 1402: else ! 1403: return(0); ! 1404: } ! 1405: ! 1406: ! 1407: Destroy(int ox, int oy) ! 1408: { ! 1409: short t, z, x, y; ! 1410: ! 1411: x = ox >>4; ! 1412: y = oy >>4; ! 1413: if (!TestBounds(x, y)) ! 1414: return; ! 1415: z = Map[x][y]; ! 1416: t = z & LOMASK; ! 1417: if (t >= TREEBASE) { ! 1418: /* TILE_IS_BRIDGE(t) */ ! 1419: if (!(z & BURNBIT)) { ! 1420: if ((t >= ROADBASE) && (t <= LASTROAD)) ! 1421: Map[x][y] = RIVER; ! 1422: return; ! 1423: } ! 1424: if (z & ZONEBIT) { ! 1425: OFireZone(x, y, z); ! 1426: if (t > RZB) { ! 1427: MakeExplosionAt(ox, oy); ! 1428: } ! 1429: } ! 1430: if (checkWet(t)) ! 1431: Map[x][y] = RIVER; ! 1432: else ! 1433: Map[x][y] = (DoAnimation ! 1434: ? TINYEXP ! 1435: : (LASTTINYEXP - 3)) | BULLBIT | ANIMBIT; ! 1436: } ! 1437: } ! 1438: ! 1439: ! 1440: OFireZone(int Xloc, int Yloc, int ch) ! 1441: { ! 1442: register short Xtem, Ytem; ! 1443: short x, y, XYmax; ! 1444: ! 1445: RateOGMem[Xloc >>3][Yloc >>3] -= 20; ! 1446: ! 1447: ch &= LOMASK; ! 1448: if (ch < PORTBASE) ! 1449: XYmax = 2; ! 1450: else ! 1451: if (ch == AIRPORT) XYmax = 5; ! 1452: else XYmax = 4; ! 1453: ! 1454: for (x = -1; x < XYmax; x++) ! 1455: for (y = -1; y < XYmax; y++) { ! 1456: Xtem = Xloc + x; ! 1457: Ytem = Yloc + y; ! 1458: if ((Map[Xtem][Ytem] & LOMASK) >= ROADBASE) ! 1459: Map[Xtem][Ytem] |= BULLBIT; ! 1460: } ! 1461: } ! 1462: ! 1463: ! 1464: StartFire(int x, int y) ! 1465: { ! 1466: register t, z; ! 1467: ! 1468: x >>= 4; ! 1469: y >>= 4; ! 1470: if ((x >= WORLD_X) || ! 1471: (y >= WORLD_Y) || ! 1472: (x < 0) || (y < 0)) ! 1473: return; ! 1474: z = Map[x][y]; ! 1475: t = z & LOMASK; ! 1476: if ((!(z & BURNBIT)) && (t != 0)) return; ! 1477: if (z & ZONEBIT) return; ! 1478: Map[x][y] = FIRE + (Rand16() & 3) + ANIMBIT; ! 1479: } ! 1480: ! 1481: ! 1482: GenerateTrain(int x, int y) ! 1483: { ! 1484: if ((TotalPop > 20) && ! 1485: (GetSprite(TRA) == NULL) && ! 1486: (!Rand(25))) { ! 1487: MakeSprite(TRA, (x <<4) + TRA_GROOVE_X, (y <<4) + TRA_GROOVE_Y); ! 1488: } ! 1489: } ! 1490: ! 1491: ! 1492: GenerateBus(int x, int y) ! 1493: { ! 1494: if ((GetSprite(BUS) == NULL) && ! 1495: (!Rand(25))) { ! 1496: MakeSprite(BUS, (x <<4) + BUS_GROOVE_X, (y <<4) + BUS_GROOVE_Y); ! 1497: } ! 1498: } ! 1499: ! 1500: ! 1501: GenerateShip(void) ! 1502: { ! 1503: register short x, y; ! 1504: ! 1505: if (!(Rand16() & 3)) ! 1506: for (x = 4; x < WORLD_X - 2; x++) ! 1507: if (Map[x][0] == CHANNEL) { ! 1508: MakeShipHere(x, 0); ! 1509: return; ! 1510: } ! 1511: if (!(Rand16() & 3)) ! 1512: for (y = 1; y < WORLD_Y - 2; y++) ! 1513: if (Map[0][y] == CHANNEL) { ! 1514: MakeShipHere(0, y); ! 1515: return; ! 1516: } ! 1517: if (!(Rand16() & 3)) ! 1518: for (x = 4; x < WORLD_X - 2; x++) ! 1519: if (Map[x][WORLD_Y - 1] == CHANNEL) { ! 1520: MakeShipHere(x, WORLD_Y - 1); ! 1521: return; ! 1522: } ! 1523: if (!(Rand16() & 3)) ! 1524: for (y = 1; y < WORLD_Y - 2; y++) ! 1525: if (Map[WORLD_X - 1][y] == CHANNEL) { ! 1526: MakeShipHere(WORLD_X - 1, y); ! 1527: return; ! 1528: } ! 1529: } ! 1530: ! 1531: ! 1532: MakeShipHere(int x, int y, int z) ! 1533: { ! 1534: MakeSprite(SHI, (x <<4) - (48 - 1), (y <<4)); ! 1535: } ! 1536: ! 1537: ! 1538: MakeMonster(void) ! 1539: { ! 1540: register x, y, z, done = 0; ! 1541: SimSprite *sprite; ! 1542: ! 1543: if ((sprite = GetSprite(GOD)) != NULL) { ! 1544: sprite->sound_count = 1; ! 1545: sprite->count = 1000; ! 1546: sprite->dest_x = PolMaxX <<4; ! 1547: sprite->dest_y = PolMaxY <<4; ! 1548: return; ! 1549: } ! 1550: ! 1551: for (z = 0; z < 300; z++) { ! 1552: x = Rand(WORLD_X - 20) + 10; ! 1553: y = Rand(WORLD_Y - 10) + 5; ! 1554: if ((Map[x][y] == RIVER) || (Map[x][y] == RIVER + BULLBIT)) { ! 1555: MonsterHere(x, y); ! 1556: done = 1; ! 1557: break; ! 1558: } ! 1559: } ! 1560: if (!done == 0) ! 1561: MonsterHere(60, 50); ! 1562: } ! 1563: ! 1564: ! 1565: MonsterHere(int x, int y) ! 1566: { ! 1567: short z; ! 1568: ! 1569: MakeSprite(GOD, (x <<4) + 48, (y <<4)); ! 1570: ClearMes(); ! 1571: SendMesAt(-21, x + 5, y); ! 1572: } ! 1573: ! 1574: ! 1575: GenerateCopter(int x, int y) ! 1576: { ! 1577: if (GetSprite(COP) != NULL) return; ! 1578: ! 1579: MakeSprite(COP, (x <<4), (y <<4) + 30); ! 1580: } ! 1581: ! 1582: ! 1583: GeneratePlane(int x, int y) ! 1584: { ! 1585: if (GetSprite(AIR) != NULL) return; ! 1586: ! 1587: MakeSprite(AIR, (x <<4) + 48, (y <<4) + 12); ! 1588: } ! 1589: ! 1590: ! 1591: MakeTornado(void) ! 1592: { ! 1593: short x, y; ! 1594: SimSprite *sprite; ! 1595: ! 1596: if ((sprite = GetSprite(TOR)) != NULL) { ! 1597: sprite->count = 200; ! 1598: return; ! 1599: } ! 1600: ! 1601: x = Rand((WORLD_X <<4) - 800) + 400; ! 1602: y = Rand((WORLD_Y <<4) - 200) + 100; ! 1603: MakeSprite(TOR, x, y); ! 1604: ClearMes(); ! 1605: SendMesAt(-22, (x >>4) + 3, (y >>4) + 2); ! 1606: } ! 1607: ! 1608: ! 1609: MakeExplosion(int x, int y) ! 1610: { ! 1611: if ((x >= 0) && (x < WORLD_X) && ! 1612: (y >= 0) && (y < WORLD_Y)) { ! 1613: MakeExplosionAt((x << 4) + 8, (y << 4) + 8); ! 1614: } ! 1615: } ! 1616: ! 1617: ! 1618: MakeExplosionAt(int x, int y) ! 1619: { ! 1620: MakeNewSprite(EXP, x - 40, y - 16); ! 1621: } ! 1622:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.