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