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