1 
2 #include "../stdai.h"
3 #include "weed.fdh"
4 
INITFUNC(AIRoutines)5 INITFUNC(AIRoutines)
6 {
7 	ONTICK(OBJ_CRITTER_FLYING, ai_critter);
8 	ONTICK(OBJ_POWER_CRITTER, ai_critter);
9 
10 	ONTICK(OBJ_BAT_HANG, ai_bat_hang);
11 	ONTICK(OBJ_BAT_CIRCLE, ai_bat_circle);
12 
13 	ONTICK(OBJ_JELLY, ai_jelly);
14 	ONTICK(OBJ_GIANT_JELLY, ai_giant_jelly);
15 
16 	ONTICK(OBJ_MANNAN, ai_mannan);
17 	ONTICK(OBJ_MANNAN_SHOT, ai_mannan_shot);
18 
19 	ONTICK(OBJ_FROG, ai_frog);
20 	ONTICK(OBJ_MINIFROG, ai_frog);
21 
22 	ONTICK(OBJ_SANTAS_KEY, ai_animate2);
23 
24 	ONTICK(OBJ_HEY_SPAWNER, ai_hey_spawner);
25 	ONTICK(OBJ_MOTORBIKE, ai_motorbike);
26 
27 	ONTICK(OBJ_POWERCOMP, ai_animate3);
28 	ONTICK(OBJ_POWERSINE, ai_animate1);
29 	ONTICK(OBJ_MALCO, ai_malco);
30 	ONTICK(OBJ_MALCO_BROKEN, ai_malco_broken);
31 }
32 
33 /*
34 void c------------------------------() {}
35 */
36 
ai_critter(Object * o)37 void ai_critter(Object *o)
38 {
39 	switch(o->state)
40 	{
41 		case 0:
42 		{
43 			if (o->type == OBJ_POWER_CRITTER)
44 			{	// altered physics for Power Critter
45 				o->critter.jumpheight = 0x2800;
46 				o->critter.jumpgrav = 0x1C;
47 				o->critter.falldmg = 12;
48 			}
49 			else
50 			{
51 				o->critter.jumpheight = 0;
52 				o->critter.jumpgrav = 0x40;
53 				o->critter.falldmg = 3;
54 
55 				if (o->type == OBJ_CRITTER_HOPPING_BLUE || 			// first cave
56 					o->type == OBJ_CRITTER_HOPPING_GREEN || 		// egg 1
57 					o->type == OBJ_CRITTER_HOPPING_AQUA ||			// egg 2
58 					o->type == OBJ_CRITTER_HOPPING_RED)				// last cave
59 				{
60 					o->critter.canfly = false;
61 
62 					// critters in egg1 only 2 dmg
63 					if (o->type == OBJ_CRITTER_HOPPING_GREEN)
64 						o->critter.falldmg = 2;
65 
66 					// critters in First Cave don't jump as high
67 					if (o->type != OBJ_CRITTER_HOPPING_BLUE)
68 					{
69 						o->critter.jumpgrav = 0x2C;
70 					}
71 				}
72 				else
73 				{
74 					// critters are purple in Maze
75 					o->sprite = SPR_CRITTER_FLYING_CYAN;
76 
77 					o->critter.canfly = true;
78 				}
79 			}
80 
81 			o->state = 1;
82 		} //fall thru
83 		case 1:
84 		{
85 			o->frame = 0;
86 
87 			if (o->timer >= 8)
88 			{
89 				int attack_dist = (o->critter.canfly) ? (96 << CSF) : (64 << CSF);
90 
91 				// close enough to attack?
92 				if (pdistlx(attack_dist) && pdistly2(96<<CSF, 48<<CSF))
93 				{
94 					o->state = 2;
95 					o->frame = 0;
96 					o->timer = 0;
97 				}
98 				else if (pdistlx(attack_dist + (32<<CSF)) && pdistly2(128<<CSF, 48<<CSF))
99 				{	// no, but close enough to look up at "attention" and watch player
100 					FACEPLAYER;
101 					o->frame = 1;
102 					o->timer = 8;	// reset timer to stop watching
103 				}
104 				else
105 				{
106 					// once a little time has passed stop watching him if he turns his back
107 					if ((o->x > player->x && player->dir==LEFT) || \
108 						(o->x < player->x && player->dir==RIGHT))
109 					{
110 						if (++o->timer >= 150)
111 						{
112 							o->frame = 0;
113 							o->timer = 8;
114 						}
115 					}
116 					else o->timer = 8;
117 				}
118 			}
119 			else
120 			{
121 				o->timer++;
122 			}
123 
124 			if (o->shaketime)
125 			{	// attack if shot
126 				o->state = 2;
127 				o->frame = 0;
128 				o->timer = 0;
129 			}
130 		}
131 		break;
132 
133 		case 2:		// start jump
134 		{
135 			if (++o->timer > 8)
136 			{
137 				o->state = 3;
138 				o->frame = 2;
139 				o->yinertia = -1228;
140 				sound(SND_ENEMY_JUMP);
141 
142 				FACEPLAYER;
143 				XMOVE(0x100);
144 			}
145 		}
146 		break;
147 
148 		case 3:		// jumping
149 		{
150 			// enter flying phase as we start to come down or
151 			// if we hit the ceiling.
152 			if (o->yinertia > 0x100 || o->blocku)
153 			{
154 				// during flight we will sine-wave oscilliate around this position
155 				o->ymark = (o->y - o->critter.jumpheight);
156 
157 				o->state = 4;
158 				o->frame = 2;
159 				o->timer = 0;
160 			}
161 			else
162 			{
163 				if (o->blockd && o->yinertia >= 0)
164 				{	// jumped onto a platform before we got to fly--land immediately
165 					goto landed;
166 				}
167 				break;
168 			}
169 		}	// fall-thru
170 		case 4:		// flying
171 		{
172 			FACEPLAYER;
173 
174 			// time to come down yet?
175 			// (come down immediately if we are not one of the flying critters)
176 			if (!o->critter.canfly || \
177 				o->blockl || o->blockr || o->blocku || \
178 				++o->timer > 100)
179 			{
180 				o->damage = o->critter.falldmg;			// increased damage if falls on player
181 				o->state = 5;
182 				o->frame = 2;
183 				o->yinertia /= 2;
184 			}
185 			else
186 			{
187 				// run the propeller
188 				ANIMATE(0, 3, 5);
189 				if ((o->timer & 3)==1) sound(SND_CRITTER_FLY);
190 
191 				if (o->blockd) o->yinertia = -0x200;
192 			}
193 		}
194 		break;
195 
196 		case 5:		// coming down from flight
197 		{
198 			if (o->blockd)
199 			{	// landed
200 landed: ;
201 				o->damage = 2;			// reset to normal damage
202 				o->state = 1;
203 
204 				o->frame = 0;
205 				o->timer = 0;
206 				o->xinertia = 0;
207 
208 				sound(SND_THUD);
209 			}
210 		}
211 		break;
212 	}
213 
214 	if (o->state == 4)		// flying
215 	{
216 		// fly towards player
217 		o->xinertia += (o->x > player->x) ? -0x20 : 0x20;
218 		// sine-wave oscillate
219 		o->yinertia += (o->y > o->ymark) ? -0x10 : 0x10;
220 
221 		LIMITX(0x200);
222 		LIMITY(0x200);
223 	}
224 	else if (o->state == 3 && o->yinertia < 0)	// jumping up
225 	{
226 		o->yinertia += o->critter.jumpgrav;
227 	}
228 	else
229 	{
230 		o->yinertia += 0x40;
231 	}
232 
233 	LIMITY(0x5ff);
234 }
235 
236 /*
237 void c------------------------------() {}
238 */
239 
ai_bat_hang(Object * o)240 void ai_bat_hang(Object *o)
241 {
242 	switch(o->state)
243 	{
244 		case 0:
245 			o->state = 1;
246 		case 1:		// hanging and waiting
247 			if (!random(0, 100))
248 			{
249 				o->state = 2;
250 				o->timer = 0;
251 				o->frame = 1;
252 			}
253 
254 			if (pdistlx(0x1000) && pdistly2(0x1000, 0x9000))
255 			{
256 				o->frame = 0;
257 				o->state = 3;
258 			}
259 		break;
260 
261 		case 2:		// blinking
262 			if (++o->timer > 8)
263 			{
264 				o->state = 1;
265 				o->frame = 0;
266 			}
267 		break;
268 
269 		case 3:		// at attention
270 			o->frame = 0;
271 			if (o->shaketime || pdistlx(0x2800))
272 			{
273 				o->frame = 1;
274 				o->animtimer = 0;
275 				o->state = 4;
276 				o->timer = 0;
277 			}
278 		break;
279 
280 		case 4:		// falling
281 			o->yinertia += 0x20;
282 			LIMITY(0x5ff);
283 
284 			o->timer++;
285 			if (o->timer > 20 || o->blockd)
286 			{
287 				if (o->blockd || ((player->y - 0x2000) < o->y))
288 				{	// start flying
289 					o->animtimer = 0;
290 					o->frame = 2;
291 					o->state = 5;
292 					o->ymark = o->y;
293 					if (o->blockd) o->yinertia = -0x200;
294 				}
295 			}
296 		break;
297 
298 		case 5:		// flying
299 			ANIMATE(1, 2, 4);
300 			FACEPLAYER;
301 
302 			o->xinertia += (o->x > player->x) ? -0x20 : 0x20;
303 			o->yinertia += (o->y > o->ymark) ? -0x10 : 0x10;
304 
305 			LIMITX(0x200);
306 			LIMITY(0x200);
307 
308 			if (o->blockd) o->yinertia = -0x200;
309 			if (o->blockr) o->yinertia = 0x200;
310 		break;
311 	}
312 }
313 
ai_bat_circle(Object * o)314 void ai_bat_circle(Object *o)
315 {
316 	switch(o->state)
317 	{
318 		case 0:
319 		{
320 			uint8_t angle;
321 			o->state = 1;
322 
323 			// set up initial direction and target x,y
324 			angle = random(0, 255);
325 			o->xinertia = sin_table[angle];
326 
327 			angle += 64;
328 			o->xmark = (o->x + (sin_table[angle] * 8));
329 
330 			angle = random(0, 255);
331 			o->yinertia = sin_table[angle];
332 
333 			angle += 64;
334 			o->ymark = (o->y + (sin_table[angle] * 8));
335 		}
336 		case 1:
337 			// circle around our target point
338 			ANIMATE(1, 2, 4);
339 			FACEPLAYER;
340 			o->xinertia += (o->x > o->xmark) ? -0x10 : 0x10;
341 			o->yinertia += (o->y > o->ymark) ? -0x10 : 0x10;
342 			LIMITX(0x200);
343 			LIMITY(0x200);
344 
345 			if (!o->timer2)
346 			{
347 				if (pdistlx(0x1000) && (player->y > o->y) && pdistly(0xC000))
348 				{	// dive attack
349 					o->xinertia /= 2;
350 					o->yinertia = 0;
351 					o->state = 2;
352 					o->frame = 5;		// mouth showing teeth
353 				}
354 			}
355 			else o->timer2--;
356 		break;
357 
358 		case 2:	// dive attack
359 			o->yinertia += 0x40;
360 			LIMITY(0x5ff);
361 
362 			if (o->blockd)
363 			{
364 				o->yinertia = 0;
365 				o->xinertia *= 2;
366 				o->timer2 = 120;		// delay before can dive again
367 				o->state = 1;
368 			}
369 		break;
370 	}
371 }
372 
373 /*
374 void c------------------------------() {}
375 */
376 
ai_jelly(Object * o)377 void ai_jelly(Object *o)
378 {
379 	switch(o->state)
380 	{
381 		case 0:
382 		{
383 			o->nxflags |= NXFLAG_SLOW_WHEN_HURT;
384 			o->timer = random(0, 20);
385 			o->xmark = o->x;
386 			o->ymark = o->y;
387 
388 			o->xinertia = (o->dir == LEFT) ? 0x200 : -0x200;
389 			o->state = 1;
390 		}
391 		case 1:
392 		{
393 			if (--o->timer <= 0)
394 			{
395 				o->state = 10;
396 			}
397 			else break;
398 		}
399 		case 10:
400 		{
401 			if (++o->timer > 10)
402 			{
403 				o->timer = o->frame = 0;
404 				o->state = 11;
405 			}
406 		}
407 		break;
408 
409 		case 11:
410 		{
411 			if (++o->animtimer > 5)
412 			{
413 				o->animtimer = 0;
414 				o->frame++;
415 			}
416 
417 			if (o->frame == 2)
418 			{
419 				o->xinertia += (o->dir == LEFT) ? -0x100 : +0x100;
420 				o->yinertia -= 0x200;
421 			}
422 			else if (o->frame > 2)
423 			{
424 				o->state = 12;
425 				o->frame = 3;
426 			}
427 		}
428 		break;
429 
430 		case 12:
431 		{
432 			o->timer++;
433 			if (o->y > o->ymark && o->timer > 10)
434 			{
435 				o->timer = 0;
436 				o->state = 10;
437 				o->frame = 0;
438 			}
439 		}
440 		break;
441 	}
442 
443 	o->dir = (o->x > o->xmark) ? LEFT : RIGHT;
444 
445 	if (o->blockl) o->dir = RIGHT;
446 	if (o->blockr) o->dir = LEFT;
447 	if (o->blockd) o->yinertia = -0x200;
448 
449 	o->yinertia += 0x20;
450 
451 	LIMITX(0x100);
452 	LIMITY(0x200);
453 }
454 
455 // Kulala
ai_giant_jelly(Object * o)456 void ai_giant_jelly(Object *o)
457 {
458 	switch(o->state)
459 	{
460 		case 0:		// frozen/in stasis. waiting for player to shoot.
461 			o->frame = 4;
462 			if (o->shaketime)
463 			{
464 				quake(30);
465 				o->state = 10;
466 				o->frame = 0;
467 				o->timer = 0;
468 			}
469 		break;
470 
471 		case 10:	// falling
472 		{
473 			o->flags |= FLAG_SHOOTABLE;
474 			o->flags &= ~FLAG_INVULNERABLE;
475 
476 			if (++o->timer > 40)
477 			{
478 				o->timer = 0;
479 				o->animtimer = 0;
480 				o->state = 11;
481 			}
482 		}
483 		break;
484 
485 		case 11:	// animate thrust
486 		{
487 			ANIMATE_FWD(5);
488 			if (o->frame >= 3)
489 			{
490 				o->frame = 3;
491 				o->state = 12;
492 			}
493 		}
494 		break;
495 
496 		case 12:	// thrusting upwards
497 		{
498 			o->yinertia = -0x155;
499 			if (++o->timer > 20)
500 			{
501 				o->state = 10;
502 				o->frame = 0;
503 				o->timer = 0;
504 			}
505 		}
506 		break;
507 
508 		case 20:	// shot/freeze over/go invulnerable
509 		{
510 			o->frame = 4;
511 			o->xinertia >>= 1;
512 			o->yinertia += 0x20;
513 
514 			if (!o->shaketime)
515 			{
516 				o->state = 10;
517 				o->frame = 0;
518 				o->timer = 30;
519 			}
520 		}
521 		break;
522 	}
523 
524 	if (o->shaketime)
525 	{
526 		if (++o->timer3 > 12)
527 		{
528 			o->state = 20;
529 			o->frame = 4;
530 			o->flags &= ~FLAG_SHOOTABLE;
531 			o->flags |= FLAG_INVULNERABLE;
532 		}
533 	}
534 	else
535 	{
536 		o->timer3 = 0;
537 	}
538 
539 	if (o->state >= 10)
540 	{
541 		if (o->blockl) { o->timer2 = 50; o->dir = RIGHT; }
542 		if (o->blockr) { o->timer2 = 50; o->dir = LEFT; }
543 
544 		if (o->timer2 > 0)
545 		{
546 			o->timer2--;
547 			XACCEL(0x80);
548 		}
549 		else
550 		{
551 			o->timer2 = 50;
552 			FACEPLAYER;
553 		}
554 
555 		o->yinertia += 0x10;
556 		if (o->blockd) o->yinertia = -0x300;
557 	}
558 
559 	LIMITX(0x100);
560 	LIMITY(0x300);
561 }
562 
563 
564 /*
565 void c------------------------------() {}
566 */
567 
ai_mannan(Object * o)568 void ai_mannan(Object *o)
569 {
570 	// check if we were "killed"
571 	if (o->state < 3 && o->hp < 90)
572 	{
573 		sound(SND_LITTLE_CRASH);
574 		SmokeClouds(o, 8, 12, 12);
575 		o->SpawnXP(objprop[o->type].xponkill);
576 		o->flags &= ~FLAG_SHOOTABLE;
577 		o->state = 3;
578 		o->timer = 0;
579 		o->frame = 2;
580 		o->damage = 0;
581 	}
582 
583 	switch(o->state)
584 	{
585 		case 0:
586 			if (o->shaketime)
587 			{
588 				SpawnObjectAtActionPoint(o, OBJ_MANNAN_SHOT);
589 				o->frame = 1;
590 				o->state = 2;
591 				o->timer = 0;
592 			}
593 		break;
594 
595 		case 2:		// firing
596 			if (++o->timer > 20)
597 			{
598 				o->timer = o->state = o->frame = 0;
599 			}
600 		break;
601 
602 		case 3:		// dead/blinking
603 			switch(++o->timer)
604 			{
605 				case 50: case 60: o->frame = 3; break;
606 				case 53: case 63: o->frame = 2; break;
607 				case 100: o->state = 4; break;
608 			}
609 		break;
610 	}
611 }
612 
ai_mannan_shot(Object * o)613 void ai_mannan_shot(Object *o)
614 {
615 	XACCEL(0x20);
616 	ANIMATE(0, 1, 2);
617 
618 	if ((o->timer & 3) == 1)
619 		sound(SND_IRONH_SHOT_FLY);
620 
621 	if (++o->timer > 100)
622 		o->Delete();
623 }
624 
625 /*
626 void c------------------------------() {}
627 */
628 
629 // there is an apparent bug on the sprite sheet for this monster:
630 //	right-facing frame 1 is a duplicate of frame 0,
631 //	so the mouth-twitch animation does not work when
632 //	the frog is facing right.
ai_frog(Object * o)633 void ai_frog(Object *o)
634 {
635 	switch(o->state)
636 	{
637 		case 0:
638 		{
639 			o->timer = 0;
640 			o->xinertia = 0;
641 			o->yinertia = 0;
642 
643 			// non-normal dirs are used to indicate that this frog was
644 			// spawned by balfrog: we are falling out of ceiling during fight
645 			if (o->dir != LEFT && o->dir != RIGHT)
646 			{
647 				o->dir = random(0, 1) ? LEFT : RIGHT;
648 				o->flags |= FLAG_IGNORE_SOLID;
649 
650 				o->state = 3;
651 				o->frame = 2;
652 			}
653 			else
654 			{
655 				o->flags &= ~FLAG_IGNORE_SOLID;
656 				o->state = 1;
657 			}
658 		}
659 		case 1:		// standing
660 		{
661 			o->timer++;
662 
663 			if (!random(0, 50))
664 			{	// mouth-flitter animation
665 				o->state = 2;
666 				o->frame = 0;
667 				o->timer = 0;
668 				o->animtimer = 0;
669 			}
670 		}
671 		break;
672 
673 		case 2:		// mouth flitter
674 		{
675 			ANIMATE(2, 0, 1);
676 
677 			if (++o->timer > 18)
678 				o->state = 1;
679 		}
680 		break;
681 
682 		case 3:		// falling out of ceiling during balfrog fight
683 		{
684 			if (++o->timer > 40)
685 			{
686 				o->flags &= ~FLAG_IGNORE_SOLID;
687 
688 				if (o->blockd)
689 				{
690 					o->state = 0;
691 					o->frame = 0;
692 					o->timer = 0;
693 				}
694 			}
695 		}
696 		break;
697 
698 		case 10:	// jumping
699 		case 11:
700 		{
701 			if (o->blockl && o->xinertia < 0)
702 			{
703 				o->dir = RIGHT;
704 				o->xinertia = -o->xinertia;
705 			}
706 
707 			if (o->blockr && o->xinertia > 0)
708 			{
709 				o->dir = LEFT;
710 				o->xinertia = -o->xinertia;
711 			}
712 
713 			if (o->blockd)
714 			{
715 				o->state = 0;
716 				o->frame = 0;
717 				o->timer = 0;
718 			}
719 		}
720 		break;
721 	}
722 
723 	// random jumping, and jump when shot
724 	if (o->state < 3 && o->timer > 10)
725 	{
726 		bool dojump = false;
727 
728 		if (o->shaketime)
729 		{
730 			dojump = true;
731 		}
732 		else if (pdistlx(0x14000) && pdistly(0x8000))
733 		{
734 			if (!random(0, 50))
735 			{
736 				dojump = true;
737 			}
738 		}
739 
740 		if (dojump)
741 		{
742 			FACEPLAYER;
743 			o->state = 10;
744 			o->frame = 2;
745 			o->yinertia = -0x5ff;
746 
747 			// no jumping sound in cutscenes at ending
748 			if (!player->inputs_locked && !player->disabled)
749 				sound(SND_ENEMY_JUMP);
750 
751 			XMOVE(0x200);
752 		}
753 	}
754 
755 	o->yinertia += 0x80;
756 	LIMITY(0x5ff);
757 }
758 
759 /*
760 void c------------------------------() {}
761 */
762 
ai_hey_spawner(Object * o)763 void ai_hey_spawner(Object *o)
764 {
765 	if (!o->state)
766 	{
767 		effect(o->x, o->y - (8<<CSF), EFFECT_HEY);
768 		o->state = 1;
769 	}
770 }
771 
ai_motorbike(Object * o)772 void ai_motorbike(Object *o)
773 {
774 
775 	switch(o->state)
776 	{
777 		case 0:		// parked
778 		break;
779 
780 		case 10:	// kazuma and booster mounted
781 			o->y -= (sprites[SPR_MOTORBIKE_MOUNTED].h - sprites[SPR_MOTORBIKE].h) << CSF;
782 			o->sprite = SPR_MOTORBIKE_MOUNTED;
783 			o->state++;
784 		break;
785 
786 		case 20:	// kazuma and booster start the engine
787 		{
788 			o->state = 21;
789 			o->timer = 1;
790 
791 			o->xmark = o->x;
792 			o->ymark = o->y;
793 		}
794 		case 21:
795 		{
796 			o->x = o->xmark + (random(-1, 1) << CSF);
797 			o->y = o->ymark + (random(-1, 1) << CSF);
798 
799 			if (++o->timer > 30)
800 				o->state = 30;
801 		}
802 		break;
803 
804 		case 30:	// kazuma and booster take off
805 		{
806 			o->state = 31;
807 			o->timer = 1;
808 
809 			o->xinertia = -0x800;
810 			o->ymark = o->y;
811 
812 			sound(SND_MISSILE_HIT);
813 		}
814 		case 31:
815 		{
816 			o->xinertia += 0x20;
817 			o->timer++;
818 
819 			o->y = o->ymark + (random(-1, 1) << CSF);
820 
821 			if (o->timer > 10)  o->dir = RIGHT;
822 			if (o->timer > 200) o->state = 40;
823 		}
824 		break;
825 
826 		case 40:		// flying away (fast out-of-control)
827 		{
828 			o->state = 41;
829 			o->timer = 2;
830 			o->dir = LEFT;
831 			o->y -= (48 << CSF);		// move up...
832 			o->xinertia = -0x1000;		// ...and fly fast
833 		}
834 		case 41:
835 		{
836 			o->timer += 2;	// makes exhaust sound go faster
837 			if (o->timer > 1200)
838 				o->Delete();
839 		}
840 		break;
841 	}
842 
843 	if (o->state >= 20 && (o->timer & 3) == 0)
844 	{
845 		sound(SND_FIREBALL);
846 
847 		// make exhaust puffs, and make them go out horizontal
848 		// instead of straight up as this effect usually does
849 		Caret *puff = effect(o->ActionPointX(), o->ActionPointY(), EFFECT_SMOKETRAIL_SLOW);
850 		puff->yinertia = 0;
851 		puff->xinertia = (o->dir == LEFT) ? 0x280 : -0x280;
852 	}
853 }
854 
855 /*
856 void c------------------------------() {}
857 */
858 
ai_malco(Object * o)859 void ai_malco(Object *o)
860 {
861 
862 	switch(o->state)
863 	{
864 		case 0:
865 			o->state = 1;
866 			o->frame = 0;
867 
868 			// smushed into ground, used on re-entry to room
869 			// if player does not choose to pull him out
870 			// after Balrog fight
871 			if (o->dir == RIGHT)
872 				o->frame = 5;
873 		break;
874 
875 		case 10:
876 			o->state = 11;
877 			o->timer = 0;
878 			o->timer = 0;
879 			SmokeClouds(o, 4, 16, 16);
880 		case 11:	// beeping and eyes flickering
881 			if (++o->timer < 100)
882 			{
883 				if ((o->timer & 1)==0)
884 				{
885 					sound(SND_COMPUTER_BEEP);
886 					o->frame ^= 1;
887 				}
888 			}
889 			else if (o->timer > 150)
890 			{
891 				o->timer = 0;
892 				o->state = 15;
893 			}
894 		break;
895 
896 		case 15:		// shaking
897 			if (o->timer & 2)
898 			{
899 				o->x += (1<<CSF);
900 				sound(SND_DOOR);
901 			}
902 			else
903 			{
904 				o->x -= (1<<CSF);
905 			}
906 			if (++o->timer > 50) o->state = 16;
907 		break;
908 
909 		case 16:		// stand up
910 			o->state = 17;
911 			o->frame = 2;
912 			o->timer = 0;
913 			sound(SND_BLOCK_DESTROY);
914 			SmokeClouds(o, 4, 16, 16);
915 		case 17:
916 			if (++o->timer > 150)
917 			{
918 				o->state = 18;
919 			}
920 		break;
921 
922 		case 18:		// gawking/bobbing up and down
923 			o->state = 19;
924 			o->timer = 0;
925 			// go into gawk frame first time
926 			o->animtimer = 999; o->frame = 9;
927 		case 19:
928 			if (++o->animtimer > 3)
929 			{
930 				o->animtimer = 0;
931 				if (++o->frame > 4) o->frame = 3;
932 				if (o->frame==3) sound(SND_DOOR);
933 			}
934 			if (++o->timer > 100)
935 			{
936 				o->state = 20;
937 				sound(SND_DOOR);
938 				SmokeClouds(o, 4, 16, 16);
939 			}
940 		break;
941 
942 		case 20: o->frame = 4; break;
943 
944 		case 21:	// got smushed!
945 			o->state = 22;
946 			o->frame = 5;
947 			sound(SND_ENEMY_HURT);
948 		break;
949 
950 		case 22:
951 		break;
952 
953 		case 100:	// "baby" malcos waking up during credits
954 		{
955 			o->state = 101;
956 			o->frame = 3;
957 			o->animtimer = 0;
958 		}
959 		case 101:
960 		{
961 			ANIMATE(4, 3, 4);
962 		}
963 		break;
964 		case 110:	// the one that blows up
965 		{
966 			SmokeClouds(o, 16, 4, 4);
967 			o->Delete();
968 		}
969 		break;
970 	}
971 }
972 
ai_malco_broken(Object * o)973 void ai_malco_broken(Object *o)
974 {
975 	switch(o->state)
976 	{
977 		case 10:	// set when pulled out of ground
978 			sound(SND_BLOCK_DESTROY);
979 			SmokeClouds(o, 4, 16, 16);
980 			o->state = 0;
981 		break;
982 
983 		case 0:
984 		{
985 			o->frame = 0;
986 			randblink(o, 1, 8, 50);
987 
988 			if (game.mode != GM_CREDITS)
989 				FACEPLAYER;
990 		}
991 		break;
992 	}
993 }
994 
995 
996 
997 
998 
999 
1000