]>
cvs.zerfleddert.de Git - micropolis/blob - src/sim/w_sprite.c
c7258bb1c2197592722409d220a384aa4a998b48
   3  * Micropolis, Unix Version.  This game was released for the Unix platform 
   4  * in or about 1990 and has been modified for inclusion in the One Laptop 
   5  * Per Child program.  Copyright (C) 1989 - 2007 Electronic Arts Inc.  If 
   6  * you need assistance with this program, you may contact: 
   7  *   http://wiki.laptop.org/go/Micropolis  or email  micropolis@laptop.org. 
   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. 
  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/>. 
  21  *             ADDITIONAL TERMS per GNU GPL Section 7 
  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. 
  29  * Any propagation or conveyance of this program must include this 
  30  * copyright notice and these terms. 
  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. 
  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. 
  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 
  65 Tcl_HashTable SpriteCmds
; 
  70 SimSprite 
*GlobalSprites
[OBJN
]; 
  72 SimSprite 
*NewSprite(char *name
, int type
, int x
, int y
); 
  73 void MonsterHere(int x
, int y
); 
  74 void MakeShipHere(int x
, int y
); 
  75 void StartFire(int x
, int y
); 
  76 void OFireZone(int Xloc
, int Yloc
, int ch
); 
  77 void Destroy(int ox
, int oy
); 
  78 void ExplodeSprite(SimSprite 
*sprite
); 
  79 int CanDriveOn(int x
, int y
); 
  80 void DoBusSprite(SimSprite 
*sprite
); 
  81 void DoExplosionSprite(SimSprite 
*sprite
); 
  82 void DoTornadoSprite(SimSprite 
*sprite
); 
  83 void DoMonsterSprite(SimSprite 
*sprite
); 
  84 void DoShipSprite(SimSprite 
*sprite
); 
  85 void DoAirplaneSprite(SimSprite 
*sprite
); 
  86 void DoCopterSprite(SimSprite 
*sprite
); 
  87 void DoTrainSprite(SimSprite 
*sprite
); 
  88 void DrawSprite(SimView 
*view
, SimSprite 
*sprite
); 
  89 void InitSprite(SimSprite 
*sprite
, int x
, int y
); 
  92 #define TRA_GROOVE_X -39 
  93 #define TRA_GROOVE_Y 6 
  94 #define BUS_GROOVE_X -39 
  95 #define BUS_GROOVE_Y 6 
  97 #define SPRITECMD_ACCESS_INT(var) \ 
  98   int SpriteCmd##var(SPRITE_ARGS) { \ 
 100     if ((argc != 2) && (argc != 3)) return (TCL_ERROR); \ 
 102       if (Tcl_GetInt(interp, argv[2], &val) != TCL_OK) return (TCL_ERROR); \ 
 105     sprintf(interp->result, "%d", sprite->var); \ 
 110 #define SPRITECMD_GET_STR(var) \ 
 111   int SpriteCmd##var(SPRITE_ARGS) { \ 
 112     sprintf(interp->result, "%s", sprite->var); \ 
 118 DoSpriteCmd(CLIENT_ARGS
) 
 120   SimSprite 
*sprite 
= (SimSprite 
*) clientData
; 
 129   if ((ent 
= Tcl_FindHashEntry(&SpriteCmds
, argv
[1]))) { 
 130     cmd 
= (int (*)())ent
->clientData
; 
 131     Tk_Preserve((ClientData
) sprite
); 
 132     result 
= cmd(sprite
, interp
, argc
, argv
); 
 133     Tk_Release((ClientData
) sprite
); 
 135     Tcl_AppendResult(interp
, "unknown command name: \"", 
 136                      argv
[0], " ", argv
[1], "\".", (char *) NULL
); 
 144 SpriteCmd(CLIENT_ARGS
) 
 150       (Tcl_GetInt(interp
, argv
[2], &type
) != TCL_OK
) || 
 151       (type 
< 1) || (type 
>= OBJN
)) { 
 155   sprite 
= NewSprite(argv
[1], type
, 0, 0); 
 158   Tcl_CreateCommand(interp
, sprite
->name
, 
 159                     DoSpriteCmd
, (ClientData
) sprite
, (void (*)()) NULL
); 
 161   interp
->result 
= sprite
->name
; 
 166 SPRITECMD_GET_STR(name
) 
 167 SPRITECMD_ACCESS_INT(type
) 
 168 SPRITECMD_ACCESS_INT(frame
) 
 169 SPRITECMD_ACCESS_INT(x
) 
 170 SPRITECMD_ACCESS_INT(y
) 
 171 SPRITECMD_ACCESS_INT(width
) 
 172 SPRITECMD_ACCESS_INT(height
) 
 173 SPRITECMD_ACCESS_INT(x_offset
) 
 174 SPRITECMD_ACCESS_INT(y_offset
) 
 175 SPRITECMD_ACCESS_INT(x_hot
) 
 176 SPRITECMD_ACCESS_INT(y_hot
) 
 177 SPRITECMD_ACCESS_INT(orig_x
) 
 178 SPRITECMD_ACCESS_INT(orig_y
) 
 179 SPRITECMD_ACCESS_INT(dest_x
) 
 180 SPRITECMD_ACCESS_INT(dest_y
) 
 181 SPRITECMD_ACCESS_INT(count
) 
 182 SPRITECMD_ACCESS_INT(sound_count
) 
 183 SPRITECMD_ACCESS_INT(dir
) 
 184 SPRITECMD_ACCESS_INT(new_dir
) 
 185 SPRITECMD_ACCESS_INT(step
) 
 186 SPRITECMD_ACCESS_INT(flag
) 
 187 SPRITECMD_ACCESS_INT(control
) 
 188 SPRITECMD_ACCESS_INT(turn
) 
 189 SPRITECMD_ACCESS_INT(accel
) 
 190 SPRITECMD_ACCESS_INT(speed
) 
 193 int SpriteCmdExplode(SPRITE_ARGS
) 
 195   ExplodeSprite(sprite
); 
 200 int SpriteCmdInit(SPRITE_ARGS
) 
 207   if ((Tcl_GetInt(interp
, argv
[2], &x
) != TCL_OK
) || 
 208       (x 
< 0) || (x 
>= (WORLD_X 
<<4)) || 
 209       (Tcl_GetInt(interp
, argv
[3], &y
) != TCL_OK
) || 
 210       (y 
< 0) || (y 
>= (WORLD_Y 
<<4))) { 
 213   InitSprite(sprite
, x
, y
); 
 219 sprite_command_init(void) 
 223   Tcl_CreateCommand(tk_mainInterp
, "sprite", SpriteCmd
, 
 224                     (ClientData
)NULL
, (void (*)()) NULL
); 
 226   Tcl_InitHashTable(&SpriteCmds
, TCL_STRING_KEYS
); 
 228 #define SPRITE_CMD(cmd) HASHED_CMD(Sprite, cmd) 
 237   SPRITE_CMD(x_offset
); 
 238   SPRITE_CMD(y_offset
); 
 246   SPRITE_CMD(sound_count
); 
 258   for (i 
= 0; i 
< OBJN
; i
++) { 
 259     GlobalSprites
[i
] = NULL
; 
 264 SimSprite 
*FreeSprites 
= NULL
; 
 267 NewSprite(char *name
, int type
, int x
, int y
) 
 272     sprite 
= FreeSprites
; 
 273     FreeSprites 
= sprite
->next
; 
 275     sprite 
= (SimSprite 
*)ckalloc(sizeof (SimSprite
)); 
 278   sprite
->name 
= (char *)ckalloc(strlen(name
) + 1); 
 279   strcpy(sprite
->name
, name
); 
 282   InitSprite(sprite
, x
, y
); 
 284   sim
->sprites
++; sprite
->next 
= sim
->sprite
; sim
->sprite 
= sprite
; 
 291 InitSprite(SimSprite 
*sprite
, int x
, int y
) 
 293   sprite
->x 
= x
; sprite
->y 
= y
; 
 295   sprite
->orig_x 
= sprite
->orig_y 
= 0; 
 296   sprite
->dest_x 
= sprite
->dest_y 
= 0; 
 297   sprite
->count 
= sprite
->sound_count 
= 0; 
 298   sprite
->dir 
= sprite
->new_dir 
= 0; 
 299   sprite
->step 
= sprite
->flag 
= 0; 
 300   sprite
->control 
= -1; 
 305   if (GlobalSprites
[sprite
->type
] == NULL
) { 
 306     GlobalSprites
[sprite
->type
] = sprite
; 
 309   switch (sprite
->type
) { 
 312     sprite
->width 
= sprite
->height 
= 32; 
 313     sprite
->x_offset 
= 32; sprite
->y_offset 
= -16; 
 314     sprite
->x_hot 
= 40; sprite
->y_hot 
= -8; 
 320     sprite
->width 
= sprite
->height 
= 48; 
 321     sprite
->x_offset 
= 32; sprite
->y_offset 
= -16; 
 322     sprite
->x_hot 
= 48; sprite
->y_hot 
= 0; 
 323     if (x 
< (4 <<4)) sprite
->frame 
= 3; 
 324     else if (x 
>= ((WORLD_X 
- 4) <<4)) sprite
->frame 
= 7; 
 325     else if (y 
< (4 <<4)) sprite
->frame 
= 5; 
 326     else if (y 
>= ((WORLD_Y 
- 4) <<4)) sprite
->frame 
= 1; 
 327     else sprite
->frame 
= 3; 
 328     sprite
->new_dir 
= sprite
->frame
; 
 334     sprite
->width 
= sprite
->height 
= 48; 
 335     sprite
->x_offset 
= 24; sprite
->y_offset 
= 0; 
 336     sprite
->x_hot 
= 40; sprite
->y_hot 
= 16; 
 337     if (x 
> ((WORLD_X 
<<4) / 2)) { 
 338       if (y 
> ((WORLD_Y 
<<4) / 2)) sprite
->frame 
= 10; 
 339       else sprite
->frame 
= 7; 
 340     } else if (y 
> ((WORLD_Y 
<<4) / 2)) sprite
->frame 
= 1; 
 341     else sprite
->frame 
= 4; 
 342     sprite
->count 
= 1000; 
 343     sprite
->dest_x 
= PolMaxX 
<<4; 
 344     sprite
->dest_y 
= PolMaxY 
<<4; 
 345     sprite
->orig_x 
= sprite
->x
; 
 346     sprite
->orig_y 
= sprite
->y
; 
 350     sprite
->width 
= sprite
->height 
= 32; 
 351     sprite
->x_offset 
= 32; sprite
->y_offset 
= -16; 
 352     sprite
->x_hot 
= 40; sprite
->y_hot 
= -8; 
 354     sprite
->count 
= 1500; 
 355     sprite
->dest_x 
= Rand((WORLD_X 
<<4) - 1); 
 356     sprite
->dest_y 
= Rand((WORLD_Y 
<<4) - 1); 
 357     sprite
->orig_x 
= x 
- 30; 
 362     sprite
->width 
= sprite
->height 
= 48; 
 363     sprite
->x_offset 
= 24; sprite
->y_offset 
= 0; 
 364     sprite
->x_hot 
= 48; sprite
->y_hot 
= 16; 
 365     if (x 
> ((WORLD_X 
- 20) <<4)) { 
 366       sprite
->x 
-= 100 + 48; 
 367       sprite
->dest_x 
= sprite
->x 
- 200; 
 370       sprite
->dest_x 
= sprite
->x 
+ 200; 
 373     sprite
->dest_y 
= sprite
->y
; 
 377     sprite
->width 
= sprite
->height 
= 48; 
 378     sprite
->x_offset 
= 24; sprite
->y_offset 
= 0; 
 379     sprite
->x_hot 
= 40; sprite
->y_hot 
= 36; 
 385     sprite
->width 
= sprite
->height 
= 48; 
 386     sprite
->x_offset 
= 24; sprite
->y_offset 
= 0; 
 387     sprite
->x_hot 
= 40; sprite
->y_hot 
= 16; 
 392     sprite
->width 
= sprite
->height 
= 32; 
 393     sprite
->x_offset 
= 30; sprite
->y_offset 
= -18; 
 394     sprite
->x_hot 
= 40; sprite
->y_hot 
= -8; 
 404 DestroyAllSprites(void) 
 408   for (sprite 
= sim
->sprite
; sprite 
!= NULL
; sprite 
= sprite
->next
) { 
 415 DestroySprite(SimSprite 
*sprite
) 
 420   for (view 
= sim
->editor
; view 
!= NULL
; view 
= view
->next
) 
 421     if (view
->follow 
== sprite
) 
 424   if (GlobalSprites
[sprite
->type
] == sprite
) { 
 425     GlobalSprites
[sprite
->type
] = (SimSprite 
*)NULL
; 
 428   if (sprite
->name 
!= NULL
) { 
 429     ckfree(sprite
->name
); 
 433   for (sp 
= &sim
->sprite
; *sp 
!= NULL
; sp 
= &((*sp
)->next
)) { 
 434     if (sprite 
== (*sp
)) { 
 440   sprite
->next 
= FreeSprites
; 
 441   FreeSprites 
= sprite
; 
 450   if (((sprite 
= GlobalSprites
[type
]) == NULL
) || 
 451       (sprite
->frame 
== 0)) 
 452     return (SimSprite 
*)NULL
; 
 459 MakeSprite(int type
, int x
, int y
) 
 463   if ((sprite 
= GlobalSprites
[type
]) == NULL
) { 
 464     sprite 
= NewSprite("", type
, x
, y
); 
 466     InitSprite(sprite
, x
, y
); 
 473 MakeNewSprite(int type
, int x
, int y
) 
 477   sprite 
= NewSprite("", type
, x
, y
); 
 483 DrawObjects(SimView 
*view
) 
 487   /* XXX: sort these by layer */ 
 489   if (z = Oframe[TRA]) DrawTrain(view, z); 
 490   if (z = Oframe[SHI]) DrawBoat(view, z); 
 491   if (z = Oframe[GOD]) DrawMonster(view, z); 
 492   if (z = Oframe[COP]) DrawCopter(view, z); 
 493   if (z = Oframe[AIR]) DrawPlane(view, z); 
 494   if (z = Oframe[TOR]) DrawTor(view, z); 
 495   if (z = Oframe[EXP]) DrawExp(view, z); 
 498   for (sprite 
= sim
->sprite
; sprite 
!= NULL
; sprite 
= sprite
->next
) { 
 499     DrawSprite(view
, sprite
); 
 505 DrawSprite(SimView 
*view
, SimSprite 
*sprite
) 
 510   if (sprite
->frame 
== 0) 
 513   i 
= (sprite
->frame 
- 1) * 2; 
 514   pict 
= view
->x
->objects
[sprite
->type
][i
]; 
 515   mask 
= view
->x
->objects
[sprite
->type
][i 
+ 1]; 
 518         - ((view
->tile_x 
<<4) - view
->screen_x
) 
 521         - ((view
->tile_y 
<<4) - view
->screen_y
) 
 524   XSetClipMask(view
->x
->dpy
, view
->x
->gc
, mask
); 
 525   XSetClipOrigin(view
->x
->dpy
, view
->x
->gc
, x
, y
); 
 526   XCopyArea(view
->x
->dpy
, pict
, view
->pixmap2
, view
->x
->gc
,  
 527             0, 0, sprite
->width
, sprite
->height
, x
, y
); 
 528   XSetClipMask(view
->x
->dpy
, view
->x
->gc
, None
); 
 529   XSetClipOrigin(view
->x
->dpy
, view
->x
->gc
, 0, 0); 
 533 short GetChar(int x
, int y
) 
 537   if (!TestBounds(x
, y
)) 
 540     return(Map
[x
][y
] & LOMASK
); 
 544 short TurnTo(int p
, int d
) 
 546   if (p 
== d
) return(p
); 
 548     if ((d 
- p
) < 4) p
++; 
 551     if ((p 
- d
) < 4) p
--; 
 560 TryOther(int Tpoo
, int Told
, int Tnew
) 
 566   if (Tnew 
!= z
) return(0); 
 567   if ((Tpoo 
== POWERBASE
) || (Tpoo 
== POWERBASE 
+ 1) || 
 568       (Tpoo 
== RAILBASE
) || (Tpoo 
== RAILBASE 
+ 1)) 
 574 short SpriteNotInBounds(SimSprite 
*sprite
) 
 576   int x 
= sprite
->x 
+ sprite
->x_hot
; 
 577   int y 
= sprite
->y 
+ sprite
->y_hot
; 
 579   if ((x 
< 0) || (y 
< 0) || 
 580       (x 
>= (WORLD_X 
<<4)) || 
 581       (y 
>= (WORLD_Y 
<<4))) { 
 588 short GetDir(int orgX
, int orgY
, int desX
, int desY
) 
 590   static short Gdtab
[13] = { 0, 3, 2, 1, 3, 4, 5, 7, 6, 5, 7, 8, 1 }; 
 596     if (dispY 
< 0) z 
= 11; 
 599     if (dispY 
< 0) z 
= 2; 
 601   if (dispX 
< 0) dispX 
= -dispX
; 
 602   if (dispY 
< 0) dispY 
= -dispY
; 
 604   absDist 
= dispX 
+ dispY
; 
 606   if ((dispX 
<<1) < dispY
) z
++; 
 607   else if ((dispY 
<<1) < dispY
) z
--; 
 609   if ((z 
< 0) || (z 
> 12)) z 
= 0; 
 616 GetDis(int x1
, int y1
, int x2
, int y2
) 
 618   register short dispX
, dispY
; 
 620   if (x1 
> x2
) dispX 
= x1 
- x2
; 
 621   else dispX 
= x2 
- x1
; 
 622   if (y1 
> y2
) dispY 
= y1 
- y2
; 
 623   else dispY 
= y2 
- y1
; 
 625   return (dispX 
+ dispY
); 
 629 int CheckSpriteCollision(SimSprite 
*s1
, SimSprite 
*s2
) 
 631   if ((s1
->frame 
!= 0) && (s2
->frame 
!= 0) && 
 632       GetDis(s1
->x 
+ s1
->x_hot
, s1
->y 
+ s1
->y_hot
, 
 633              s2
->x 
+ s2
->x_hot
, s2
->y 
+ s2
->y_hot
) < 30) 
 639 void MoveObjects(void) 
 643   if (!SimSpeed
) return; 
 646   for (sprite 
= sim
->sprite
; sprite 
!= NULL
;) { 
 648       switch (sprite
->type
) { 
 650         DoTrainSprite(sprite
); 
 653         DoCopterSprite(sprite
); 
 656         DoAirplaneSprite(sprite
); 
 659         DoShipSprite(sprite
); 
 662         DoMonsterSprite(sprite
); 
 665         DoTornadoSprite(sprite
); 
 668         DoExplosionSprite(sprite
); 
 674       sprite 
= sprite
->next
; 
 676       if (sprite
->name
[0] == '\0') { 
 677         SimSprite 
*s 
= sprite
; 
 678         sprite 
= sprite
->next
; 
 681         sprite 
= sprite
->next
; 
 689 DoTrainSprite(SimSprite 
*sprite
) 
 691   static short Cx
[4] = {   0,  16,   0, -16 }; 
 692   static short Cy
[4] = { -16,   0,  16,   0 }; 
 693   static short Dx
[5] = {   0,   4,   0,  -4,   0 }; 
 694   static short Dy
[5] = {  -4,   0,   4,   0,   0 }; 
 695   static short TrainPic2
[5] = { 1, 2, 1, 2, 5 }; 
 696   register short z
, dir
, dir2
; 
 699   if ((sprite
->frame 
== 3) || (sprite
->frame 
== 4)) 
 700     sprite
->frame 
= TrainPic2
[sprite
->dir
]; 
 701   sprite
->x 
+= Dx
[sprite
->dir
]; 
 702   sprite
->y 
+= Dy
[sprite
->dir
]; 
 705     for (z 
= dir
; z 
< (dir 
+ 4); z
++) { 
 707       if (sprite
->dir 
!= 4) { 
 708         if (dir2 
== ((sprite
->dir 
+ 2) & 3)) continue; 
 710       c 
= GetChar(sprite
->x 
+ Cx
[dir2
] + 48, 
 711                   sprite
->y 
+ Cy
[dir2
]); 
 712       if (((c 
>= RAILBASE
) && (c 
<= LASTRAIL
)) || /* track? */ 
 713           (c 
== RAILVPOWERH
) || 
 714           (c 
== RAILHPOWERV
)) { 
 715         if ((sprite
->dir 
!= dir2
) && 
 716             (sprite
->dir 
!= 4)) { 
 717           if ((sprite
->dir 
+ dir2
) == 3) 
 722           sprite
->frame 
= TrainPic2
[dir2
]; 
 724         if ((c 
== RAILBASE
) || (c 
== (RAILBASE 
+ 1))) 
 730     if (sprite
->dir 
== 4) { 
 740 DoCopterSprite(SimSprite 
*sprite
) 
 742   static short CDx
[9] = { 0,  0,  3,  5,  3,  0, -3, -5, -3 }; 
 743   static short CDy
[9] = { 0, -5, -3,  0,  3,  5,  3,  0, -3 }; 
 744   register short z
, d
, x
, y
; 
 746   if (sprite
->sound_count 
> 0) sprite
->sound_count
--; 
 748   if (sprite
->control 
< 0) { 
 750     if (sprite
->count 
> 0) sprite
->count
--; 
 752     if (!sprite
->count
) { 
 753       /* Attract copter to monster and tornado so it blows up more often */ 
 754       SimSprite 
*s 
= GetSprite(GOD
); 
 756         sprite
->dest_x 
= s
->x
; 
 757         sprite
->dest_y 
= s
->y
; 
 761           sprite
->dest_x 
= s
->x
; 
 762           sprite
->dest_y 
= s
->y
; 
 764           sprite
->dest_x 
= sprite
->orig_x
; 
 765           sprite
->dest_y 
= sprite
->orig_y
; 
 769     if (!sprite
->count
) { /* land */ 
 770       GetDir(sprite
->x
, sprite
->y
, sprite
->orig_x
, sprite
->orig_y
); 
 777     GetDir(sprite
->x
, sprite
->y
, sprite
->dest_x
, sprite
->dest_y
); 
 779       sprite
->dest_x 
= sprite
->orig_x
; 
 780       sprite
->dest_y 
= sprite
->orig_y
; 
 781       sprite
->control 
= -1; 
 785   if (!sprite
->sound_count
) { /* send report  */ 
 786     x 
= (sprite
->x 
+ 48) >>5; 
 789         (x 
< (WORLD_X 
>>1)) && 
 791         (y 
< (WORLD_Y 
>>1))) { 
 792       /* Don changed from 160 to 170 to shut the #$%#$% thing up! */ 
 793       if ((TrfDensity
[x
][y
] > 170) && ((Rand16() & 7) == 0)) { 
 794         SendMesAt(-41, (x 
<<1) + 1, (y 
<<1) + 1); 
 795         MakeSound("city", "HeavyTraffic"); /* chopper */ 
 796         sprite
->sound_count 
= 200; 
 802     d 
= GetDir(sprite
->x
, sprite
->y
, sprite
->dest_x
, sprite
->dest_y
); 
 813 DoAirplaneSprite(SimSprite 
*sprite
) 
 815   static short CDx
[12] = { 0,  0,  6,  8,  6,  0, -6, -8, -6,  8,  8,  8 }; 
 816   static short CDy
[12] = { 0, -8, -6,  0,  6,  8,  6,  0, -6,  0,  0,  0 }; 
 823     if (z 
> 8) { /* TakeOff  */ 
 827     } else { /* goto destination */ 
 828       d 
= GetDir(sprite
->x
, sprite
->y
, sprite
->dest_x
, sprite
->dest_y
); 
 834   if (absDist 
< 50) { /* at destination  */ 
 835     sprite
->dest_x 
= Rand((WORLD_X 
* 16) + 100) - 50; 
 836     sprite
->dest_y 
= Rand((WORLD_Y 
* 16) + 100) - 50; 
 839   /* deh added test for !Disasters */ 
 844     for (s 
= sim
->sprite
; s 
!= NULL
; s 
= s
->next
) { 
 845       if ((s
->frame 
!= 0) && 
 848             (s
->type 
== AIR
))) && 
 849           CheckSpriteCollision(sprite
, s
)) { 
 855       ExplodeSprite(sprite
); 
 860   if (SpriteNotInBounds(sprite
)) sprite
->frame 
= 0; 
 865 DoShipSprite(SimSprite 
*sprite
) 
 867   static short BDx
[9] = { 0,  0,  1,  1,  1,  0, -1, -1, -1 }; 
 868   static short BDy
[9] = { 0, -1, -1,  0,  1,  1,  1,  0, -1 }; 
 869   static short BPx
[9] = { 0,  0,  2,  2,  2,  0, -2, -2, -2 }; 
 870   static short BPy
[9] = { 0, -2, -2,  0,  2,  2,  2,  0, -2 }; 
 871   static short BtClrTab
[8] = { RIVER
, CHANNEL
, POWERBASE
, POWERBASE 
+ 1, 
 872                                RAILBASE
, RAILBASE 
+ 1, BRWH
, BRWV 
}; 
 873   register short x
, y
, z
, t 
= RIVER
; 
 876   if (sprite
->sound_count 
> 0) sprite
->sound_count
--; 
 877   if (!sprite
->sound_count
) { 
 878     if ((Rand16() & 3) == 1) { 
 879       if ((ScenarioID 
== 2) && /* San Francisco */ 
 881         MakeSound("city", "HonkHonk-Low"); 
 883         MakeSound("city", "HonkHonk-Low"); 
 886     sprite
->sound_count 
= 200; 
 889   if (sprite
->count 
> 0) sprite
->count
--; 
 890   if (!sprite
->count
) { 
 892     if (sprite
->frame 
!= sprite
->new_dir
) { 
 893       sprite
->frame 
= TurnTo(sprite
->frame
, sprite
->new_dir
); 
 897     for (pem 
= tem
; pem 
< (tem 
+ 8); pem
++) { 
 900       if (z 
== sprite
->dir
) continue; 
 901       x 
= ((sprite
->x 
+ (48 - 1)) >>4) + BDx
[z
]; 
 902       y 
= (sprite
->y 
>>4) + BDy
[z
]; 
 903       if (TestBounds(x
, y
)) { 
 904         t 
= Map
[x
][y
] & LOMASK
; 
 905         if ((t 
== CHANNEL
) || (t 
== BRWH
) || (t 
== BRWV
) || 
 906             TryOther(t
, sprite
->dir
, z
)) { 
 908           sprite
->frame 
= TurnTo(sprite
->frame
, sprite
->new_dir
); 
 910           if (sprite
->dir 
> 8) sprite
->dir 
-= 8; 
 915     if (pem 
== (tem 
+ 8)) { 
 917       sprite
->new_dir 
= (Rand16() & 7) + 1; 
 921     if (z 
== sprite
->new_dir
)  { 
 926   if (SpriteNotInBounds(sprite
)) { 
 931     for (z 
= 0; z 
< 8; z
++) { 
 932       if (t 
== BtClrTab
[z
]) break; 
 934         ExplodeSprite(sprite
); 
 935         Destroy(sprite
->x 
+ 48, sprite
->y
); 
 943 DoMonsterSprite(SimSprite 
*sprite
) 
 945   static short Gx
[5] = {  2,  2, -2, -2,  0 }; 
 946   static short Gy
[5] = { -2,  2,  2, -2,  0 }; 
 947   static short ND1
[4] = {  0,  1,  2,  3 }; 
 948   static short ND2
[4] = {  1,  2,  3,  0 }; 
 949   static short nn1
[4] = {  2,  5,  8, 11 }; 
 950   static short nn2
[4] = { 11,  2,  5,  8 }; 
 951   register short d
, z
, c
; 
 953   if (sprite
->sound_count 
> 0) sprite
->sound_count
--; 
 955   if (sprite
->control 
< 0) { 
 956     /* business as usual */ 
 958     if (sprite
->control 
== -2) { 
 959       d 
= (sprite
->frame 
- 1) / 3; 
 960       z 
= (sprite
->frame 
- 1) % 3; 
 961       if (z 
== 2) sprite
->step 
= 0; 
 962       if (z 
== 0) sprite
->step 
= 1; 
 963       if (sprite
->step
) z
++; 
 965       c 
= GetDir(sprite
->x
, sprite
->y
, sprite
->dest_x
, sprite
->dest_y
); 
 967         sprite
->control 
= -1; 
 968         sprite
->count 
= 1000; 
 970         sprite
->dest_x 
= sprite
->orig_x
; 
 971         sprite
->dest_y 
= sprite
->orig_y
; 
 974         if (((c 
!= d
) && (!Rand(5))) || 
 976           int diff 
= (c 
- d
) & 3; 
 977           if ((diff 
== 1) || (diff 
== 3)) { 
 980             if (Rand16() & 1) d
++; else d
--; 
 985             if (Rand16() & 1) d
++; else d
--; 
 992       d 
= (sprite
->frame 
- 1) / 3; 
 994       if (d 
< 4) { /* turn n s e w */ 
 995         z 
= (sprite
->frame 
- 1) % 3; 
 996         if (z 
== 2) sprite
->step 
= 0; 
 997         if (z 
== 0) sprite
->step 
= 1; 
 998         if (sprite
->step
) z
++; 
1000         GetDir(sprite
->x
, sprite
->y
, sprite
->dest_x
, sprite
->dest_y
); 
1002           if (sprite
->flag 
== 0) { 
1004             sprite
->dest_x 
= sprite
->orig_x
; 
1005             sprite
->dest_y 
= sprite
->orig_y
; 
1011         c 
= GetDir(sprite
->x
, sprite
->y
, sprite
->dest_x
, sprite
->dest_y
); 
1013         if ((c 
!= d
) && (!Rand(10))) { 
1014           if (Rand16() & 1) z 
= ND1
[d
]; 
1017           if (!sprite
->sound_count
) { 
1018             MakeSound("city", "Monster"); /* monster */ 
1019             sprite
->sound_count 
= 50 + Rand(100); 
1026         if (!(Rand16() & 3)) { 
1027           if (Rand16() & 1) z 
= nn1
[z
]; 
1035     /* somebody's taken control of the monster */ 
1037     d 
= sprite
->control
; 
1038     z 
= (sprite
->frame 
- 1) % 3; 
1040     if (z 
== 2) sprite
->step 
= 0; 
1041     if (z 
== 0) sprite
->step 
= 1; 
1042     if (sprite
->step
) z
++; 
1046   z 
= (((d 
* 3) + z
) + 1); 
1053   if (sprite
->count 
> 0) sprite
->count
--; 
1054   c 
= GetChar(sprite
->x 
+ sprite
->x_hot
, sprite
->y 
+ sprite
->y_hot
); 
1056     sprite
->frame 
= 0; /* kill zilla */ 
1060     for (s 
= sim
->sprite
; s 
!= NULL
; s 
= s
->next
) { 
1061       if ((s
->frame 
!= 0) && 
1062           ((s
->type 
== AIR
) || 
1065            (s
->type 
== TRA
)) && 
1066           CheckSpriteCollision(sprite
, s
)) { 
1072   Destroy(sprite
->x 
+ 48, sprite
->y 
+ 16); 
1077 DoTornadoSprite(SimSprite 
*sprite
) 
1079   static short CDx
[9] = {  2,  3,  2,  0, -2, -3 }; 
1080   static short CDy
[9] = { -2,  0,  2,  3,  2,  0 }; 
1085   if (z 
== 2) /* cycle animation... post Rel */ 
1098   if (sprite
->count 
> 0) sprite
->count
--; 
1103     for (s 
= sim
->sprite
; s 
!= NULL
; s 
= s
->next
) { 
1104       if ((s
->frame 
!= 0) && 
1105           ((s
->type 
== AIR
) || 
1108            (s
->type 
== TRA
)) && 
1109           CheckSpriteCollision(sprite
, s
)) { 
1116   sprite
->x 
+= CDx
[z
]; 
1117   sprite
->y 
+= CDy
[z
]; 
1118   if (SpriteNotInBounds(sprite
)) sprite
->frame 
= 0; 
1120   if ((sprite
->count 
!= 0) && 
1124   Destroy(sprite
->x 
+ 48, sprite
->y 
+ 40); 
1129 DoExplosionSprite(SimSprite 
*sprite
) 
1134     if (sprite
->frame 
== 1) { 
1135       MakeSound("city", "Explosion-High"); /* explosion */ 
1136       x 
= (sprite
->x 
>>4) + 3; 
1137       y 
= (sprite
->y 
>>4); 
1138       SendMesAt(32, x
, y
); 
1143   if (sprite
->frame 
> 6) { 
1146     StartFire(sprite
->x 
+ 48 - 8, sprite
->y 
+ 16); 
1147     StartFire(sprite
->x 
+ 48 - 24, sprite
->y
); 
1148     StartFire(sprite
->x 
+ 48 + 8, sprite
->y
); 
1149     StartFire(sprite
->x 
+ 48 - 24, sprite
->y 
+ 32); 
1150     StartFire(sprite
->x 
+ 48 + 8, sprite
->y 
+ 32); 
1157 DoBusSprite(SimSprite 
*sprite
) 
1159   static short Dx
[5] = {   0,   1,   0,  -1,   0 }; 
1160   static short Dy
[5] = {  -1,   0,   1,   0,   0 }; 
1161   static short Dir2Frame
[4] = { 1, 2, 1, 2 }; 
1162   int dx
, dy
, tx
, ty
, otx
, oty
; 
1167 printf("Bus dir %d turn %d frame %d\n", 
1168        sprite
->dir
, sprite
->turn
, sprite
->frame
); 
1172     if (sprite
->turn 
< 0) { /* ccw */ 
1173       if (sprite
->dir 
& 1) { /* up or down */ 
1175       } else { /* left or right */ 
1179       sprite
->dir 
= (sprite
->dir 
- 1) & 3; 
1181       if (sprite
->dir 
& 1) { /* up or down */ 
1183       } else { /* left or right */ 
1187       sprite
->dir 
= (sprite
->dir 
+ 1) & 3; 
1192     if ((sprite
->frame 
== 3) || (sprite
->frame 
== 4)) { 
1194       sprite
->frame 
= Dir2Frame
[sprite
->dir
]; 
1198   if (sprite
->speed 
== 0) { 
1201   } else { /* cruise at traffic speed */ 
1203     tx 
= (sprite
->x 
+ sprite
->x_hot
) >>5; 
1204     ty 
= (sprite
->y 
+ sprite
->y_hot
) >>5; 
1206         (tx 
< (WORLD_X 
>>1)) && 
1208         (ty 
< (WORLD_Y 
>>1))) { 
1209       z 
= TrfDensity
[tx
][ty
] >>6; 
1226     if (speed 
> sprite
->speed
) 
1227       speed 
= sprite
->speed
; 
1233       if (speed 
> 1) speed 
= 1; 
1234       dx 
= Dx
[sprite
->dir
] * speed
; 
1235       dy 
= Dy
[sprite
->dir
] * speed
; 
1237       dx 
= Dx
[sprite
->dir
] * speed
; 
1238       dy 
= Dy
[sprite
->dir
] * speed
; 
1240       tx 
= (sprite
->x 
+ sprite
->x_hot
) >>4; 
1241       ty 
= (sprite
->y 
+ sprite
->y_hot
) >>4; 
1243       /* drift into the right lane */ 
1244       switch (sprite
->dir
) { 
1246         z 
= ((tx 
<<4) + 4) - (sprite
->x 
+ sprite
->x_hot
); 
1248         else if (z 
> 0) dx 
= 1; 
1250 printf("moving up x %x z %d dx %d\n", sprite
->x 
+ sprite
->x_hot
, z
, dx
); 
1254         z 
= ((ty 
<<4) + 4) - (sprite
->y 
+ sprite
->y_hot
); 
1256         else if (z 
> 0) dy 
= 1; 
1258 printf("moving right y %x z %d dy %d\n", sprite
->y 
+ sprite
->y_hot
, z
, dy
); 
1262         z 
= ((tx 
<<4)) - (sprite
->x 
+ sprite
->x_hot
); 
1264         else if (z 
> 0) dx 
= 1; 
1266 printf("moving down x %x z %d dx %d\n", sprite
->x 
+ sprite
->x_hot
, z
, dx
); 
1270         z 
= ((ty 
<<4)) - (sprite
->y 
+ sprite
->y_hot
); 
1272         else if (z 
> 0) dy 
= 1; 
1274 printf("moving left y %x z %d dy %d\n", sprite
->y 
+ sprite
->y_hot
, z
, dy
); 
1281 printf("speed dx %d dy %d\n", dx
, dy
); 
1286   otx 
= (sprite
->x 
+ sprite
->x_hot 
+ (Dx
[sprite
->dir
] * AHEAD
)) >>4; 
1287   oty 
= (sprite
->y 
+ sprite
->y_hot 
+ (Dy
[sprite
->dir
] * AHEAD
)) >>4; 
1288   if (otx 
< 0) otx 
= 0; else if (otx 
>= WORLD_X
) otx 
= WORLD_X 
- 1; 
1289   if (oty 
< 0) oty 
= 0; else if (oty 
>= WORLD_Y
) oty 
= WORLD_Y 
- 1; 
1291   tx 
= (sprite
->x 
+ sprite
->x_hot 
+ dx 
+ (Dx
[sprite
->dir
] * AHEAD
)) >>4; 
1292   ty 
= (sprite
->y 
+ sprite
->y_hot 
+ dy 
+ (Dy
[sprite
->dir
] * AHEAD
)) >>4; 
1293   if (tx 
< 0) tx 
= 0; else if (tx 
>= WORLD_X
) tx 
= WORLD_X 
- 1; 
1294   if (ty 
< 0) ty 
= 0; else if (ty 
>= WORLD_Y
) ty 
= WORLD_Y 
- 1; 
1296   if ((tx 
!= otx
) || (ty 
!= oty
)) { 
1298 printf("drive from tile %d %d to %d %d\n", 
1301     z 
= CanDriveOn(tx
, ty
); 
1303       /* can't drive forward into a new tile */ 
1305         bulldozer_tool(NULL
, tx
, ty
); 
1309       /* drive forward into a new tile */ 
1320   tx 
= (sprite
->x 
+ sprite
->x_hot 
+ dx
) >>4; 
1321   ty 
= (sprite
->y 
+ sprite
->y_hot 
+ dy
) >>4; 
1322   z 
= CanDriveOn(tx
, ty
); 
1324     /* cool, cruise along */ 
1329       /* something in the way */ 
1340     for (s 
= sim
->sprite
; s 
!= NULL
; s 
= s
->next
) { 
1341       if ((sprite 
!= s
) && 
1343           ((s
->type 
== BUS
) || 
1344            ((s
->type 
== TRA
) && 
1345             (s
->frame 
!= 5))) && 
1346           CheckSpriteCollision(sprite
, s
)) { 
1352       ExplodeSprite(sprite
); 
1358 CanDriveOn(int x
, int y
) 
1362   if (!TestBounds(x
, y
)) 
1365   tile 
= Map
[x
][y
] & LOMASK
; 
1367   if (((tile 
>= ROADBASE
) && 
1368        (tile 
<= LASTROAD
) && 
1371       (tile 
== HRAILROAD
) || 
1372       (tile 
== VRAILROAD
)) 
1375   if ((tile 
== DIRT
) || tally(tile
)) 
1383 ExplodeSprite(SimSprite 
*sprite
) 
1389   x 
= sprite
->x 
+ sprite
->x_hot
; 
1390   y 
= sprite
->y 
+ sprite
->y_hot
; 
1391   MakeExplosionAt(x
, y
); 
1396   switch (sprite
->type
) { 
1400     SendMesAt(-24, x
, y
); 
1405     SendMesAt(-25, x
, y
); 
1410     SendMesAt(-26, x
, y
); 
1415     SendMesAt(-27, x
, y
); 
1420     SendMesAt(-26, x
, y
); /* XXX for now */ 
1423   MakeSound("city", "Explosion-High"); /* explosion */ 
1430   if ((x 
== POWERBASE
) || (x 
== POWERBASE 
+ 1) || 
1431       (x 
== RAILBASE
) || (x 
== RAILBASE 
+ 1) || 
1432       (x 
== BRWH
) || (x 
== BRWV
)) 
1440 Destroy(int ox
, int oy
) 
1446   if (!TestBounds(x
, y
)) 
1450   if (t 
>= TREEBASE
) { 
1451     /* TILE_IS_BRIDGE(t) */ 
1452     if (!(z 
& BURNBIT
)) {                
1453       if ((t 
>= ROADBASE
) && (t 
<= LASTROAD
)) 
1460         MakeExplosionAt(ox
, oy
); 
1466       Map
[x
][y
] = (DoAnimation
 
1468                    : (LASTTINYEXP 
- 3)) | BULLBIT 
| ANIMBIT
; 
1474 OFireZone(int Xloc
, int Yloc
, int ch
) 
1476   register short Xtem
, Ytem
; 
1479   RateOGMem
[Xloc 
>>3][Yloc 
>>3] -= 20; 
1485     if (ch 
== AIRPORT
) XYmax 
= 5; 
1488   for (x 
= -1; x 
< XYmax
; x
++) 
1489     for (y 
= -1; y 
< XYmax
; y
++) { 
1492       if ((Map
[Xtem
][Ytem
] & LOMASK
) >= ROADBASE
) 
1493         Map
[Xtem
][Ytem
] |= BULLBIT
; 
1499 StartFire(int x
, int y
) 
1505   if ((x 
>= WORLD_X
) || 
1511   if ((!(z 
& BURNBIT
)) && (t 
!= 0)) return; 
1512   if (z 
& ZONEBIT
) return; 
1513   Map
[x
][y
] = FIRE 
+ (Rand16() & 3) + ANIMBIT
; 
1518 GenerateTrain(int x
, int y
) 
1520   if ((TotalPop 
> 20) && 
1521       (GetSprite(TRA
) == NULL
) && 
1523     MakeSprite(TRA
, (x 
<<4) + TRA_GROOVE_X
, (y 
<<4) + TRA_GROOVE_Y
); 
1529 GenerateBus(int x
, int y
) 
1531   if ((GetSprite(BUS
) == NULL
) && 
1533     MakeSprite(BUS
, (x 
<<4) + BUS_GROOVE_X
, (y 
<<4) + BUS_GROOVE_Y
); 
1541   register short x
, y
; 
1543   if (!(Rand16() & 3)) 
1544     for (x 
= 4; x 
< WORLD_X 
- 2; x
++) 
1545       if (Map
[x
][0] == CHANNEL
)  { 
1549   if (!(Rand16() & 3)) 
1550     for (y 
= 1; y 
< WORLD_Y 
- 2; y
++) 
1551       if (Map
[0][y
] == CHANNEL
)  { 
1555   if (!(Rand16() & 3)) 
1556     for (x 
= 4; x 
< WORLD_X 
- 2; x
++)                    
1557       if (Map
[x
][WORLD_Y 
- 1] == CHANNEL
)  { 
1558         MakeShipHere(x
, WORLD_Y 
- 1); 
1561   if (!(Rand16() & 3)) 
1562     for (y 
= 1; y 
< WORLD_Y 
- 2; y
++) 
1563       if (Map
[WORLD_X 
- 1][y
] == CHANNEL
)  { 
1564         MakeShipHere(WORLD_X 
- 1, y
); 
1571 MakeShipHere(int x
, int y
) 
1573   MakeSprite(SHI
, (x 
<<4) - (48 - 1), (y 
<<4)); 
1580   register int x
, y
, z
, done 
= 0; 
1583   if ((sprite 
= GetSprite(GOD
)) != NULL
) { 
1584     sprite
->sound_count 
= 1; 
1585     sprite
->count 
= 1000; 
1586     sprite
->dest_x 
= PolMaxX 
<<4; 
1587     sprite
->dest_y 
= PolMaxY 
<<4; 
1591   for (z 
= 0; z 
< 300; z
++)  { 
1592     x 
= Rand(WORLD_X 
- 20) + 10; 
1593     y 
= Rand(WORLD_Y 
- 10) + 5; 
1594     if ((Map
[x
][y
] == RIVER
) || (Map
[x
][y
] == RIVER 
+ BULLBIT
)) { 
1601     MonsterHere(60, 50); 
1606 MonsterHere(int x
, int y
) 
1608   MakeSprite(GOD
, (x 
<<4) + 48, (y 
<<4)); 
1610   SendMesAt(-21, x 
+ 5, y
); 
1615 GenerateCopter(int x
, int y
) 
1617   if (GetSprite(COP
) != NULL
) return; 
1619   MakeSprite(COP
, (x 
<<4), (y 
<<4) + 30); 
1624 GeneratePlane(int x
, int y
) 
1626   if (GetSprite(AIR
) != NULL
) return; 
1628   MakeSprite(AIR
, (x 
<<4) + 48, (y 
<<4) + 12); 
1636   if (GetSprite(AIR
) == NULL
) { 
1639     x 
= Rand(WORLD_X 
- 20) + 10; 
1640     y 
= Rand(WORLD_Y 
- 10) + 5; 
1642     GeneratePlane(x
, y
); 
1645   ExplodeSprite(GetSprite(AIR
)); 
1656   if ((sprite 
= GetSprite(TOR
)) != NULL
) { 
1657     sprite
->count 
= 200; 
1661   x 
= Rand((WORLD_X 
<<4) - 800) + 400; 
1662   y 
= Rand((WORLD_Y 
<<4) - 200) + 100; 
1663   MakeSprite(TOR
, x
, y
); 
1665   SendMesAt(-22, (x 
>>4) + 3, (y 
>>4) + 2); 
1670 MakeExplosion(int x
, int y
) 
1672   if ((x 
>= 0) && (x 
< WORLD_X
) && 
1673       (y 
>= 0) && (y 
< WORLD_Y
)) { 
1674     MakeExplosionAt((x 
<< 4) + 8, (y 
<< 4) + 8); 
1680 MakeExplosionAt(int x
, int y
) 
1682   MakeNewSprite(EXP
, x 
- 40, y 
- 16);