1 
2 #include "../stdai.h"
3 #include "../plantation/plantation.fdh"	// ai_droll_shot
4 #include "../sym/sym.fdh"				// ai_press
5 #include "last_cave.fdh"
6 
INITFUNC(AIRoutines)7 INITFUNC(AIRoutines)
8 {
9 	ONTICK(OBJ_CRITTER_HOPPING_RED, ai_critter_hopping_red);
10 
11 	ONTICK(OBJ_LAVA_DRIP_SPAWNER, ai_lava_drip_spawner);
12 	ONTICK(OBJ_LAVA_DRIP, ai_lava_drip);
13 
14 	ONTICK(OBJ_RED_BAT_SPAWNER, ai_red_bat_spawner);
15 	ONTICK(OBJ_RED_BAT, ai_red_bat);
16 
17 	ONTICK(OBJ_RED_DEMON, ai_red_demon);
18 	ONTICK(OBJ_RED_DEMON_SHOT, ai_droll_shot);
19 
20 	ONTICK(OBJ_PROXIMITY_PRESS_VERT, ai_proximity_press_vert);
21 }
22 
23 /*
24 void c------------------------------() {}
25 */
26 
ai_proximity_press_vert(Object * o)27 void ai_proximity_press_vert(Object *o)
28 {
29 	switch(o->state)
30 	{
31 		case 0:
32 		{
33 			if (pdistlx(8<<CSF) && pdistly2(8<<CSF, 128<<CSF) && \
34 				!o->blockd)
35 			{
36 				o->state = 10;
37 				o->animtimer = 0;
38 				o->frame = 1;
39 			}
40 		}
41 		break;
42 
43 		case 10:
44 		{
45 			if (o->frame < 2)
46 				ANIMATE_FWD(2);
47 
48 			if (o->blockd)
49 			{
50 				if (o->frame >= 2)	// make sure eye fully open
51 				{
52 					SmokeSide(o, 4, DOWN);
53 					quake(10);
54 				}
55 
56 				o->flags |= FLAG_SOLID_BRICK;
57 				o->damage = 0;
58 
59 				o->state = 11;
60 				o->frame = 0;
61 			}
62 			else
63 			{
64 				if (player->Top() > o->CenterY())
65 				{
66 					o->flags &= ~FLAG_SOLID_BRICK;
67 					o->damage = 127;
68 				}
69 				else
70 				{
71 					o->flags |= FLAG_SOLID_BRICK;
72 					o->damage = 0;
73 				}
74 			}
75 		}
76 		break;
77 	}
78 
79 	if (o->state >= 5)
80 	{
81 		o->yinertia += 0x80;
82 		LIMITY(0x5ff);
83 	}
84 }
85 
86 /*
87 void c------------------------------() {}
88 */
89 
ai_critter_hopping_red(Object * o)90 void ai_critter_hopping_red(Object *o)
91 {
92 	switch(o->state)
93 	{
94 		case 0:
95 		{
96 			FACEPLAYER;
97 			o->frame = 0;
98 
99 			if (o->shaketime)
100 			{
101 				o->state = 2;
102 				o->timer = 0;
103 			}
104 			else if (++o->timer >= 8)
105 			{
106 				if (pdistly((5 * TILE_H) << CSF))
107 				{
108 					if (pdistlx((6 * TILE_W) << CSF))
109 					{
110 						o->state = 1;
111 						o->timer = 0;
112 					}
113 					else if (pdistlx((9 * TILE_W) << CSF))
114 					{
115 						o->frame = 1;
116 					}
117 				}
118 			}
119 		}
120 		break;
121 
122 		case 1:		// prepare to jump
123 		{
124 			if (++o->timer > 8)
125 			{
126 				o->state = 2;
127 				o->frame = 2;
128 				sound(SND_ENEMY_JUMP);
129 
130 				o->yinertia = -0x5ff;
131 				o->xinertia = (o->dir == RIGHT) ? 0x200 : -0x200;
132 			}
133 		}
134 		break;
135 
136 		case 2:		// in air
137 		{
138 			if (o->blockd && o->yinertia > 0)
139 			{
140 				sound(SND_THUD);
141 				o->xinertia = 0;
142 
143 				o->state = 0;
144 				o->timer = 0;
145 				o->frame = 1;
146 			}
147 		}
148 		break;
149 	}
150 
151 	o->yinertia += 0x55;
152 	LIMITY(0x5ff);
153 }
154 
155 /*
156 void c------------------------------() {}
157 */
158 
159 // lava drip spawner in Last Cave (hidden) and used extensively in Final Cave.
160 // the id1 tag sets the frequency of the drip, the id2 tag sets an amount to
161 // delay the first drip in order to desync a group of drips.
ai_lava_drip_spawner(Object * o)162 void ai_lava_drip_spawner(Object *o)
163 {
164 	switch(o->state)
165 	{
166 		case 0:
167 		{
168 			o->sprite = SPR_LAVA_DRIP;
169 			o->x += (4 << CSF);
170 			o->timer = (o->id2 - o->id1);
171 			o->state = 1;
172 		}
173 		case 1:
174 		{
175 			if (--o->timer < 0)
176 			{
177 				o->state = 2;
178 				o->animtimer = 0;
179 				o->timer2 = 0;
180 			}
181 		}
182 		break;
183 
184 		case 2:
185 		{
186 			o->display_xoff = (++o->timer2 & 2) ? 0 : 1;
187 
188 			ANIMATE_FWD(10);
189 			if (o->frame > 3)
190 			{
191 				o->frame = 0;
192 				o->state = 1;
193 				o->timer = o->id1;
194 
195 				ai_lava_drip(CreateObject(o->x, o->y, OBJ_LAVA_DRIP));
196 			}
197 		}
198 		break;
199 	}
200 }
201 
ai_lava_drip(Object * o)202 void ai_lava_drip(Object *o)
203 {
204 	o->frame = 4;
205 	o->yinertia += 0x40;
206 	LIMITY(0x5ff);
207 
208 	if (o->blockd || \
209 		(++o->timer > 10 && o->CheckAttribute(&sprites[o->sprite].block_u, TA_WATER)))
210 	{
211 		for(int i=0;i<3;i++)
212 		{
213 			Caret *c = effect(o->CenterX(), o->Bottom(), EFFECT_LAVA_SPLASH);
214 			c->xinertia = random(-0x400, 0x400);
215 			c->yinertia = random(-0x400, 0);
216 		}
217 
218 		if (o->onscreen)
219 			sound(SND_BUBBLE);
220 
221 		o->Delete();
222 	}
223 }
224 
225 /*
226 void c------------------------------() {}
227 */
228 
ai_red_bat_spawner(Object * o)229 void ai_red_bat_spawner(Object *o)
230 {
231 	switch(o->state)
232 	{
233 		case 0:
234 		{
235 			o->state = 1;
236 			o->timer = random(0, 500);
237 		}
238 		case 1:
239 		{
240 			if (--o->timer < 0)
241 			{
242 				Object *bat = CreateObject(o->CenterX(), \
243 										   o->CenterY() + random(-32<<CSF, 32<<CSF), \
244 										   OBJ_RED_BAT);
245 				bat->x -= (bat->Width() / 2);
246 				bat->y -= (bat->Height() / 2);
247 				bat->dir = o->dir;
248 				o->state = 0;
249 			}
250 		}
251 	}
252 }
253 
ai_red_bat(Object * o)254 void ai_red_bat(Object *o)
255 {
256 	ANIMATE(1, 0, 2);
257 
258 	switch(o->state)
259 	{
260 		case 0:
261 		{
262 			o->state = 1;
263 			o->ymark = o->y;
264 			o->timer = random(0, 50);
265 		}
266 		case 1:
267 		{
268 			if (--o->timer < 0)
269 			{
270 				o->state = 2;
271 				o->yinertia = 0x400;
272 			}
273 			else break;
274 		}
275 		case 2:
276 		{
277 			o->yinertia += (o->y < o->ymark) ? 0x10 : -0x10;
278 			LIMITY(0x300);
279 			XMOVE(0x100);
280 		}
281 		break;
282 	}
283 
284 	if (o->x < 0 || o->x > (map.xsize * TILE_W) << CSF)
285 	{
286 		effect(o->CenterX(), o->CenterY(), EFFECT_BOOMFLASH);
287 		o->Delete();
288 	}
289 }
290 
291 /*
292 void c------------------------------() {}
293 */
294 
ai_red_demon(Object * o)295 void ai_red_demon(Object *o)
296 {
297 	switch(o->state)
298 	{
299 		case 0:
300 		{
301 			o->xmark = o->x;
302 			o->xinertia = 0;
303 			o->frame = 0;
304 			o->state = 1;
305 		}
306 		case 1:
307 		{
308 			ANIMATE(20, 0, 1);
309 			FACEPLAYER;
310 		}
311 		break;
312 
313 		case 10:	// prepare to jump
314 		{
315 			o->flags |= FLAG_SHOOTABLE;
316 			o->state = 11;
317 			o->frame = 3;
318 			o->timer = 0;
319 		}
320 		case 11:
321 		{
322 			switch(++o->timer)
323 			{
324 				case 30:
325 				case 40:
326 				case 50:
327 				{
328 					o->frame = 4;
329 					EmFireAngledShot(o, OBJ_RED_DEMON_SHOT, 0, 0x800);
330 					sound(SND_EM_FIRE);
331 				}
332 				break;
333 
334 				case 34:
335 				case 44:
336 				case 54:
337 				{
338 					o->frame = 3;
339 				}
340 				break;
341 
342 				case 61:
343 				{
344 					o->state = 20;
345 					o->timer = 0;
346 					o->frame = 2;
347 				}
348 				break;
349 			}
350 		}
351 		break;
352 
353 		case 20:	// pause before jump
354 		{
355 			if (++o->timer > 20)
356 			{
357 				o->state = 21;
358 				o->timer = 0;
359 				o->frame = 5;
360 
361 				o->yinertia = -0x5ff;
362 				o->xinertia = (o->CenterX() < player->CenterX()) ? 0x100 : -0x100;
363 			}
364 		}
365 		break;
366 
367 		case 21:	// in air
368 		{
369 			switch(++o->timer)
370 			{
371 				case 30:
372 				case 40:
373 				case 50:
374 				{
375 					o->frame = 6;
376 					EmFireAngledShot(o, OBJ_RED_DEMON_SHOT, 0, 0x800);
377 					sound(SND_EM_FIRE);
378 				}
379 				break;
380 
381 				case 34:
382 				case 44:
383 				{
384 					o->frame = 5;
385 				}
386 				break;
387 
388 				case 54:
389 				{
390 					o->frame = 7;
391 				}
392 				break;
393 			}
394 
395 			if (o->blockd && o->yinertia >= 0)
396 			{
397 				quake(10);
398 				o->state = 22;
399 				o->timer = 0;
400 				o->frame = 2;
401 			}
402 		}
403 		break;
404 
405 		case 22:	// landed
406 		{
407 			o->xinertia /= 2;
408 
409 			if (++o->timer > 22)
410 			{
411 				o->state = 10;
412 			}
413 		}
414 		break;
415 
416 		// defeated/turned to stone (set by script)
417 		case 50:
418 		{
419 			o->flags &= ~FLAG_SHOOTABLE;
420 			o->damage = 0;
421 
422 			if (o->blockd)
423 			{
424 				o->state = 51;
425 				o->frame = 2;
426 
427 				game.quaketime = 10;
428 				SmokeClouds(o, 12, 4, 4);
429 				o->SpawnXP(19);
430 
431 				sound(SND_BIG_CRASH);
432 
433 				// needed to prevent status bars from not disappearing
434 				game.bossbar.object = NULL;
435 			}
436 		}
437 		break;
438 
439 		case 51:
440 		{
441 			o->xinertia *= 7;
442 			o->xinertia /= 8;
443 
444 			o->frame = 8;
445 		}
446 		break;
447 	}
448 
449 	if (o->state < 50)
450 	{
451 		FACEPLAYER;
452 	}
453 
454 	o->yinertia += 0x20;
455 	LIMITY(0x5ff);
456 }
457 
458 /*
459 void c------------------------------() {}
460 */
461 
ai_press_vert(Object * o)462 void ai_press_vert(Object *o)
463 {
464 	switch(o->state)
465 	{
466 		case 0:
467 		{
468 			o->state = 1;
469 			o->y -= (4 << CSF);
470 
471 			if (pdistlx((8<<CSF)) && pdistly2((8<<CSF), (128<<CSF)))
472 			{
473 				o->state = 5;
474 			}
475 		}
476 		break;
477 
478 		case 5:
479 		{
480 			if (o->blockd)
481 			{
482 				o->state = 10;
483 				o->animtimer = 0;
484 				o->frame = 1;
485 			}
486 		}
487 		break;
488 
489 		case 10:
490 		{
491 			ANIMATE_FWD(2);
492 			if (o->frame > 2)
493 				o->frame = 2;
494 
495 			if (player->y > o->y)
496 				o->flags |= FLAG_SOLID_BRICK;
497 		}
498 		break;
499 	}
500 }
501 
502 
503 
504 
505 
506