Annotation of micropolis/src/sim/w_sprite.c, revision 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.