]>
git.zerfleddert.de Git - micropolis/blob - src/sim/w_sprite.c
1268e3d824999ed05610cae8fad2815db57a55c3
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
);
1057 (sprite
->count
!= 0) &&
1058 (sprite
->control
== -1))) {
1059 sprite
->frame
= 0; /* kill zilla */
1063 for (s
= sim
->sprite
; s
!= NULL
; s
= s
->next
) {
1064 if ((s
->frame
!= 0) &&
1065 ((s
->type
== AIR
) ||
1068 (s
->type
== TRA
)) &&
1069 CheckSpriteCollision(sprite
, s
)) {
1075 Destroy(sprite
->x
+ 48, sprite
->y
+ 16);
1080 DoTornadoSprite(SimSprite
*sprite
)
1082 static short CDx
[9] = { 2, 3, 2, 0, -2, -3 };
1083 static short CDy
[9] = { -2, 0, 2, 3, 2, 0 };
1088 if (z
== 2) /* cycle animation... post Rel */
1101 if (sprite
->count
> 0) sprite
->count
--;
1106 for (s
= sim
->sprite
; s
!= NULL
; s
= s
->next
) {
1107 if ((s
->frame
!= 0) &&
1108 ((s
->type
== AIR
) ||
1111 (s
->type
== TRA
)) &&
1112 CheckSpriteCollision(sprite
, s
)) {
1119 sprite
->x
+= CDx
[z
];
1120 sprite
->y
+= CDy
[z
];
1121 if (SpriteNotInBounds(sprite
)) sprite
->frame
= 0;
1123 if ((sprite
->count
!= 0) &&
1127 Destroy(sprite
->x
+ 48, sprite
->y
+ 40);
1132 DoExplosionSprite(SimSprite
*sprite
)
1137 if (sprite
->frame
== 1) {
1138 MakeSound("city", "Explosion-High"); /* explosion */
1139 x
= (sprite
->x
>>4) + 3;
1140 y
= (sprite
->y
>>4);
1141 SendMesAt(32, x
, y
);
1146 if (sprite
->frame
> 6) {
1149 StartFire(sprite
->x
+ 48 - 8, sprite
->y
+ 16);
1150 StartFire(sprite
->x
+ 48 - 24, sprite
->y
);
1151 StartFire(sprite
->x
+ 48 + 8, sprite
->y
);
1152 StartFire(sprite
->x
+ 48 - 24, sprite
->y
+ 32);
1153 StartFire(sprite
->x
+ 48 + 8, sprite
->y
+ 32);
1160 DoBusSprite(SimSprite
*sprite
)
1162 static short Dx
[5] = { 0, 1, 0, -1, 0 };
1163 static short Dy
[5] = { -1, 0, 1, 0, 0 };
1164 static short Dir2Frame
[4] = { 1, 2, 1, 2 };
1165 int dx
, dy
, tx
, ty
, otx
, oty
;
1170 printf("Bus dir %d turn %d frame %d\n",
1171 sprite
->dir
, sprite
->turn
, sprite
->frame
);
1175 if (sprite
->turn
< 0) { /* ccw */
1176 if (sprite
->dir
& 1) { /* up or down */
1178 } else { /* left or right */
1182 sprite
->dir
= (sprite
->dir
- 1) & 3;
1184 if (sprite
->dir
& 1) { /* up or down */
1186 } else { /* left or right */
1190 sprite
->dir
= (sprite
->dir
+ 1) & 3;
1195 if ((sprite
->frame
== 3) || (sprite
->frame
== 4)) {
1197 sprite
->frame
= Dir2Frame
[sprite
->dir
];
1201 if (sprite
->speed
== 0) {
1204 } else { /* cruise at traffic speed */
1206 tx
= (sprite
->x
+ sprite
->x_hot
) >>5;
1207 ty
= (sprite
->y
+ sprite
->y_hot
) >>5;
1209 (tx
< (WORLD_X
>>1)) &&
1211 (ty
< (WORLD_Y
>>1))) {
1212 z
= TrfDensity
[tx
][ty
] >>6;
1229 if (speed
> sprite
->speed
)
1230 speed
= sprite
->speed
;
1236 if (speed
> 1) speed
= 1;
1237 dx
= Dx
[sprite
->dir
] * speed
;
1238 dy
= Dy
[sprite
->dir
] * speed
;
1240 dx
= Dx
[sprite
->dir
] * speed
;
1241 dy
= Dy
[sprite
->dir
] * speed
;
1243 tx
= (sprite
->x
+ sprite
->x_hot
) >>4;
1244 ty
= (sprite
->y
+ sprite
->y_hot
) >>4;
1246 /* drift into the right lane */
1247 switch (sprite
->dir
) {
1249 z
= ((tx
<<4) + 4) - (sprite
->x
+ sprite
->x_hot
);
1251 else if (z
> 0) dx
= 1;
1253 printf("moving up x %x z %d dx %d\n", sprite
->x
+ sprite
->x_hot
, z
, dx
);
1257 z
= ((ty
<<4) + 4) - (sprite
->y
+ sprite
->y_hot
);
1259 else if (z
> 0) dy
= 1;
1261 printf("moving right y %x z %d dy %d\n", sprite
->y
+ sprite
->y_hot
, z
, dy
);
1265 z
= ((tx
<<4)) - (sprite
->x
+ sprite
->x_hot
);
1267 else if (z
> 0) dx
= 1;
1269 printf("moving down x %x z %d dx %d\n", sprite
->x
+ sprite
->x_hot
, z
, dx
);
1273 z
= ((ty
<<4)) - (sprite
->y
+ sprite
->y_hot
);
1275 else if (z
> 0) dy
= 1;
1277 printf("moving left y %x z %d dy %d\n", sprite
->y
+ sprite
->y_hot
, z
, dy
);
1284 printf("speed dx %d dy %d\n", dx
, dy
);
1289 otx
= (sprite
->x
+ sprite
->x_hot
+ (Dx
[sprite
->dir
] * AHEAD
)) >>4;
1290 oty
= (sprite
->y
+ sprite
->y_hot
+ (Dy
[sprite
->dir
] * AHEAD
)) >>4;
1291 if (otx
< 0) otx
= 0; else if (otx
>= WORLD_X
) otx
= WORLD_X
- 1;
1292 if (oty
< 0) oty
= 0; else if (oty
>= WORLD_Y
) oty
= WORLD_Y
- 1;
1294 tx
= (sprite
->x
+ sprite
->x_hot
+ dx
+ (Dx
[sprite
->dir
] * AHEAD
)) >>4;
1295 ty
= (sprite
->y
+ sprite
->y_hot
+ dy
+ (Dy
[sprite
->dir
] * AHEAD
)) >>4;
1296 if (tx
< 0) tx
= 0; else if (tx
>= WORLD_X
) tx
= WORLD_X
- 1;
1297 if (ty
< 0) ty
= 0; else if (ty
>= WORLD_Y
) ty
= WORLD_Y
- 1;
1299 if ((tx
!= otx
) || (ty
!= oty
)) {
1301 printf("drive from tile %d %d to %d %d\n",
1304 z
= CanDriveOn(tx
, ty
);
1306 /* can't drive forward into a new tile */
1308 bulldozer_tool(NULL
, tx
, ty
);
1312 /* drive forward into a new tile */
1323 tx
= (sprite
->x
+ sprite
->x_hot
+ dx
) >>4;
1324 ty
= (sprite
->y
+ sprite
->y_hot
+ dy
) >>4;
1325 z
= CanDriveOn(tx
, ty
);
1327 /* cool, cruise along */
1332 /* something in the way */
1343 for (s
= sim
->sprite
; s
!= NULL
; s
= s
->next
) {
1344 if ((sprite
!= s
) &&
1346 ((s
->type
== BUS
) ||
1347 ((s
->type
== TRA
) &&
1348 (s
->frame
!= 5))) &&
1349 CheckSpriteCollision(sprite
, s
)) {
1355 ExplodeSprite(sprite
);
1361 CanDriveOn(int x
, int y
)
1365 if (!TestBounds(x
, y
))
1368 tile
= Map
[x
][y
] & LOMASK
;
1370 if (((tile
>= ROADBASE
) &&
1371 (tile
<= LASTROAD
) &&
1374 (tile
== HRAILROAD
) ||
1375 (tile
== VRAILROAD
))
1378 if ((tile
== DIRT
) || tally(tile
))
1386 ExplodeSprite(SimSprite
*sprite
)
1392 x
= sprite
->x
+ sprite
->x_hot
;
1393 y
= sprite
->y
+ sprite
->y_hot
;
1394 MakeExplosionAt(x
, y
);
1399 switch (sprite
->type
) {
1403 SendMesAt(-24, x
, y
);
1408 SendMesAt(-25, x
, y
);
1413 SendMesAt(-26, x
, y
);
1418 SendMesAt(-27, x
, y
);
1423 SendMesAt(-26, x
, y
); /* XXX for now */
1426 MakeSound("city", "Explosion-High"); /* explosion */
1433 if ((x
== POWERBASE
) || (x
== POWERBASE
+ 1) ||
1434 (x
== RAILBASE
) || (x
== RAILBASE
+ 1) ||
1435 (x
== BRWH
) || (x
== BRWV
))
1443 Destroy(int ox
, int oy
)
1449 if (!TestBounds(x
, y
))
1453 if (t
>= TREEBASE
) {
1454 /* TILE_IS_BRIDGE(t) */
1455 if (!(z
& BURNBIT
)) {
1456 if ((t
>= ROADBASE
) && (t
<= LASTROAD
))
1463 MakeExplosionAt(ox
, oy
);
1469 Map
[x
][y
] = (DoAnimation
1471 : (LASTTINYEXP
- 3)) | BULLBIT
| ANIMBIT
;
1477 OFireZone(int Xloc
, int Yloc
, int ch
)
1479 register short Xtem
, Ytem
;
1482 RateOGMem
[Xloc
>>3][Yloc
>>3] -= 20;
1488 if (ch
== AIRPORT
) XYmax
= 5;
1491 for (x
= -1; x
< XYmax
; x
++)
1492 for (y
= -1; y
< XYmax
; y
++) {
1495 if ((Map
[Xtem
][Ytem
] & LOMASK
) >= ROADBASE
)
1496 Map
[Xtem
][Ytem
] |= BULLBIT
;
1502 StartFire(int x
, int y
)
1508 if ((x
>= WORLD_X
) ||
1514 if ((!(z
& BURNBIT
)) && (t
!= 0)) return;
1515 if (z
& ZONEBIT
) return;
1516 Map
[x
][y
] = FIRE
+ (Rand16() & 3) + ANIMBIT
;
1521 GenerateTrain(int x
, int y
)
1523 if ((TotalPop
> 20) &&
1524 (GetSprite(TRA
) == NULL
) &&
1526 MakeSprite(TRA
, (x
<<4) + TRA_GROOVE_X
, (y
<<4) + TRA_GROOVE_Y
);
1532 GenerateBus(int x
, int y
)
1534 if ((GetSprite(BUS
) == NULL
) &&
1536 MakeSprite(BUS
, (x
<<4) + BUS_GROOVE_X
, (y
<<4) + BUS_GROOVE_Y
);
1544 register short x
, y
;
1546 if (!(Rand16() & 3))
1547 for (x
= 4; x
< WORLD_X
- 2; x
++)
1548 if (Map
[x
][0] == CHANNEL
) {
1552 if (!(Rand16() & 3))
1553 for (y
= 1; y
< WORLD_Y
- 2; y
++)
1554 if (Map
[0][y
] == CHANNEL
) {
1558 if (!(Rand16() & 3))
1559 for (x
= 4; x
< WORLD_X
- 2; x
++)
1560 if (Map
[x
][WORLD_Y
- 1] == CHANNEL
) {
1561 MakeShipHere(x
, WORLD_Y
- 1);
1564 if (!(Rand16() & 3))
1565 for (y
= 1; y
< WORLD_Y
- 2; y
++)
1566 if (Map
[WORLD_X
- 1][y
] == CHANNEL
) {
1567 MakeShipHere(WORLD_X
- 1, y
);
1574 MakeShipHere(int x
, int y
)
1576 MakeSprite(SHI
, (x
<<4) - (48 - 1), (y
<<4));
1583 register int x
, y
, z
, done
= 0;
1586 if ((sprite
= GetSprite(GOD
)) != NULL
) {
1587 sprite
->sound_count
= 1;
1588 sprite
->count
= 1000;
1589 sprite
->dest_x
= PolMaxX
<<4;
1590 sprite
->dest_y
= PolMaxY
<<4;
1594 for (z
= 0; z
< 300; z
++) {
1595 x
= Rand(WORLD_X
- 20) + 10;
1596 y
= Rand(WORLD_Y
- 10) + 5;
1597 if ((Map
[x
][y
] == RIVER
) || (Map
[x
][y
] == RIVER
+ BULLBIT
)) {
1604 MonsterHere(60, 50);
1609 MonsterHere(int x
, int y
)
1611 MakeSprite(GOD
, (x
<<4) + 48, (y
<<4));
1613 SendMesAt(-21, x
+ 5, y
);
1618 GenerateCopter(int x
, int y
)
1620 if (GetSprite(COP
) != NULL
) return;
1622 MakeSprite(COP
, (x
<<4), (y
<<4) + 30);
1627 GeneratePlane(int x
, int y
)
1629 if (GetSprite(AIR
) != NULL
) return;
1631 MakeSprite(AIR
, (x
<<4) + 48, (y
<<4) + 12);
1639 if (GetSprite(AIR
) == NULL
) {
1642 x
= Rand(WORLD_X
- 20) + 10;
1643 y
= Rand(WORLD_Y
- 10) + 5;
1645 GeneratePlane(x
, y
);
1648 ExplodeSprite(GetSprite(AIR
));
1659 if ((sprite
= GetSprite(TOR
)) != NULL
) {
1660 sprite
->count
= 200;
1664 x
= Rand((WORLD_X
<<4) - 800) + 400;
1665 y
= Rand((WORLD_Y
<<4) - 200) + 100;
1666 MakeSprite(TOR
, x
, y
);
1668 SendMesAt(-22, (x
>>4) + 3, (y
>>4) + 2);
1673 MakeExplosion(int x
, int y
)
1675 if ((x
>= 0) && (x
< WORLD_X
) &&
1676 (y
>= 0) && (y
< WORLD_Y
)) {
1677 MakeExplosionAt((x
<< 4) + 8, (y
<< 4) + 8);
1683 MakeExplosionAt(int x
, int y
)
1685 MakeNewSprite(EXP
, x
- 40, y
- 16);