Annotation of micropolis/src/sim/w_sprite.c, revision 1.1.1.1

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: 

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.