1
2 #include "../stdai.h"
3 #include "ironhead.h"
4 #include "ironhead.fdh"
5
6 #define ARENA_TOP 2
7 #define ARENA_BOTTOM 13
8
9 #define IRONH_SPAWN_FISHIES 100
10 #define IRONH_SWIM 250
11 #define IRONH_DEFEATED 1000
12
INITFUNC(AIRoutines)13 INITFUNC(AIRoutines)
14 {
15 ONDEATH(OBJ_IRONH, ondeath_ironhead);
16
17 ONTICK(OBJ_IRONH_FISHY, ai_ironh_fishy);
18 ONTICK(OBJ_IRONH_SHOT, ai_ironh_shot);
19
20 ONTICK(OBJ_BRICK_SPAWNER, ai_brick_spawner);
21 ONTICK(OBJ_IRONH_BRICK, ai_ironh_brick);
22
23 ONTICK(OBJ_IKACHAN_SPAWNER, ai_ikachan_spawner);
24 ONTICK(OBJ_IKACHAN, ai_ikachan);
25
26 ONTICK(OBJ_MOTION_WALL, ai_motion_wall);
27
28 objprop[OBJ_IRONH].hurt_sound = SND_ENEMY_HURT_COOL;
29 }
30
31 /*
32 void c------------------------------() {}
33 */
34
OnMapEntry()35 void IronheadBoss::OnMapEntry()
36 {
37 o = CreateObject(0, 0, OBJ_IRONH);
38 o->damage = 10;
39 o->hp = 400;
40 o->state = IRONH_SPAWN_FISHIES;
41
42 game.stageboss.object = o;
43 this->hittimer = 0;
44 }
45
OnMapExit()46 void IronheadBoss::OnMapExit()
47 {
48 o = NULL;
49 game.stageboss.object = NULL;
50 }
51
52 /*
53 void c------------------------------() {}
54 */
55
Run(void)56 void IronheadBoss::Run(void)
57 {
58 if (!o) return;
59
60 switch(o->state)
61 {
62 case IRONH_SPAWN_FISHIES:
63 {
64 o->timer = 0;
65 o->state++;
66 }
67 case IRONH_SPAWN_FISHIES+1: // wave of fishies comes in
68 {
69 if (++o->timer > 50)
70 {
71 o->timer = 0;
72 o->state = IRONH_SWIM;
73 }
74
75 if ((o->timer & 3)==0)
76 {
77 CreateObject((random(15, 18) * TILE_W) << CSF, \
78 (random(ARENA_TOP, ARENA_BOTTOM) * TILE_H) << CSF, \
79 OBJ_IRONH_FISHY);
80 }
81 }
82 break;
83
84 case IRONH_SWIM: // swimming attack
85 {
86 o->state++;
87
88 if (o->dir==RIGHT)
89 { // coming up on player from left
90 o->x = 0x1e000;
91 o->y = player->y;
92 }
93 else
94 { // returning from right side of screen
95 o->x = 0x5a000;
96 o->y = (random(ARENA_TOP, ARENA_BOTTOM) * TILE_H) << CSF;
97 }
98
99 o->xmark = o->x;
100 o->ymark = o->y;
101
102 o->yinertia = random(-0x200, 0x200);
103 o->xinertia = random(-0x200, 0x200);
104
105 o->flags |= FLAG_SHOOTABLE;
106 }
107 case IRONH_SWIM+1:
108 {
109 ANIMATE(2, 0, 7);
110
111 if (o->dir==RIGHT)
112 {
113 o->xmark += 0x400;
114 }
115 else
116 {
117 o->xmark -= 0x200;
118 o->ymark += (o->ymark < player->y) ? 0x200: -0x200;
119 }
120
121 //debugXline(o->xmark, 255,0,0);
122 //debugYline(o->ymark, 0,255,0);
123 o->xinertia += (o->x > o->xmark) ? -8 : 8;
124 o->yinertia += (o->y > o->ymark) ? -8 : 8;
125
126 LIMITY(0x200);
127
128 if (o->dir==RIGHT)
129 {
130 if (o->x > 0x5a000)
131 {
132 o->dir = LEFT;
133 o->state = IRONH_SPAWN_FISHIES;
134 }
135 }
136 else
137 {
138 if (o->x < 0x22000)
139 {
140 o->dir = RIGHT;
141 o->state = IRONH_SPAWN_FISHIES;
142 }
143 }
144
145 if (o->dir==LEFT)
146 {
147 // fire bullets at player when retreating
148 switch(++o->timer)
149 {
150 case 300:
151 case 310:
152 case 320:
153 {
154 Object *shot = SpawnObjectAtActionPoint(o, OBJ_IRONH_SHOT);
155 shot->xinertia = (random(-3, 0) << CSF);
156 shot->yinertia = (random(-3, 3) << CSF);
157 sound(SND_EM_FIRE);
158 }
159 break;
160 }
161 }
162 }
163 break;
164
165 case IRONH_DEFEATED:
166 {
167 sound(SND_EXPL_SMALL);
168 o->state = IRONH_DEFEATED+1;
169 o->flags &= ~FLAG_SHOOTABLE;
170 o->frame = 8;
171 o->damage = 0;
172 o->xmark = o->x;
173 o->ymark = o->y;
174 o->xinertia = o->yinertia = 0;
175 o->timer = 0;
176 KillObjectsOfType(OBJ_IRONH_FISHY);
177 KillObjectsOfType(OBJ_IRONH_BRICK);
178 KillObjectsOfType(OBJ_BRICK_SPAWNER);
179 game.quaketime = 20;
180
181 for(int i=0;i<32;i++)
182 ironh_smokecloud(o);
183 }
184 case IRONH_DEFEATED+1: // retreat back to left...
185 {
186 o->xmark -= (1<<CSF);
187
188 o->x = o->xmark + (random(-1, 1) << CSF);
189 o->y = o->ymark + (random(-1, 1) << CSF);
190
191 o->timer++;
192 if ((o->timer & 3)==0) ironh_smokecloud(o);
193 }
194 break;
195 }
196
197 // show pink "hit" frame when he's taking damage
198 o->sprite = SPR_IRONH;
199 if (o->shaketime)
200 {
201 this->hittimer++;
202 if (this->hittimer & 2)
203 {
204 o->sprite = SPR_IRONH_HURT;
205 }
206 }
207 else
208 {
209 this->hittimer = 0;
210 }
211 }
212
ironh_smokecloud(Object * o)213 static void ironh_smokecloud(Object *o)
214 {
215 Object *smoke;
216
217 smoke = CreateObject(o->CenterX() + (random(-128, 128)<<CSF), \
218 o->CenterY() + (random(-64, 64)<<CSF),
219 OBJ_SMOKE_CLOUD);
220
221 smoke->xinertia = random(-128, 128);
222 smoke->yinertia = random(-128, 128);
223 }
224
ondeath_ironhead(Object * o)225 void ondeath_ironhead(Object *o)
226 {
227 StartScript(1000);
228 }
229
230 /*
231 void c------------------------------() {}
232 */
233
ai_ironh_fishy(Object * o)234 void ai_ironh_fishy(Object *o)
235 {
236 switch(o->state)
237 {
238 case 0:
239 {
240 o->state = 10;
241 o->animtimer = 0;
242 o->yinertia = random(-0x200, 0x200);
243 o->xinertia = 0x800;
244 }
245 case 10: // harmless fishy
246 {
247 ANIMATE(2, 0, 1);
248 if (o->xinertia < 0)
249 {
250 o->damage = 3;
251 o->state = 20;
252 }
253 }
254 break;
255
256 case 20: // puffer fish
257 {
258 ANIMATE(2, 2, 3);
259
260 if (o->x < (48<<CSF))
261 o->Delete();
262 }
263 break;
264 }
265
266 if (o->blocku) o->yinertia = 0x200;
267 if (o->blockd) o->yinertia = -0x200;
268 o->xinertia -= 0x0c;
269 }
270
ai_ironh_shot(Object * o)271 void ai_ironh_shot(Object *o)
272 {
273 if (!o->state)
274 {
275 if (++o->timer > 20)
276 {
277 o->state = 1;
278 o->xinertia = o->yinertia = 0;
279 o->timer2 = 0;
280 }
281 }
282 else
283 {
284 o->xinertia += 0x20;
285 }
286
287 ANIMATE(0, 0, 2);
288
289 if (++o->timer2 > 100 && !o->onscreen)
290 {
291 o->Delete();
292 }
293
294 if ((o->timer2 & 3)==1) sound(SND_IRONH_SHOT_FLY);
295 }
296
297
ai_brick_spawner(Object * o)298 void ai_brick_spawner(Object *o)
299 {
300 Object *brick;
301
302 if (!o->state)
303 {
304 o->state = 1;
305 o->timer = random(0, 200);
306 }
307
308 if (!o->timer)
309 { // time to spawn a block
310 o->state = 0;
311 brick = CreateObject(o->x, o->y + (random(-20, 20) << CSF), OBJ_IRONH_BRICK);
312 brick->dir = o->dir;
313 }
314 else o->timer--;
315 }
316
ai_ironh_brick(Object * o)317 void ai_ironh_brick(Object *o)
318 {
319 if (!o->state)
320 {
321 int r = random(0, 9);
322 if (r == 9)
323 {
324 o->sprite = SPR_IRONH_BIGBRICK;
325 }
326 else
327 {
328 o->sprite = SPR_IRONH_BRICK;
329 o->frame = r;
330 }
331
332 o->xinertia = random(0x100, 0x200);
333 o->xinertia *= (o->dir == LEFT) ? -2 : 2;
334
335 o->yinertia = random(-0x200, 0x200);
336 o->state = 1;
337 }
338
339 // bounce off the walls
340 if (o->yinertia < 0 && o->y <= (16<<CSF))
341 {
342 effect(o->CenterX(), o->y, EFFECT_BONKPLUS);
343 o->yinertia = -o->yinertia;
344 }
345
346 if (o->yinertia > 0 && (o->Bottom() >= (239<<CSF)))
347 {
348 effect(o->CenterX(), o->Bottom(), EFFECT_BONKPLUS);
349 o->yinertia = -o->yinertia;
350 }
351
352
353 if ((o->xinertia < 0 && (o->x < -0x2000)) ||\
354 (o->x > (map.xsize * TILE_W) << CSF))
355 {
356 o->Delete();
357 }
358 }
359
360 /*
361 void c------------------------------() {}
362 */
363
ai_ikachan_spawner(Object * o)364 void ai_ikachan_spawner(Object *o)
365 {
366 switch(o->state)
367 {
368 case 0:
369 {
370 // oops player got hurt--no ikachans for you!
371 // the deletion of the object causes the flag matching it's id2 to be set,
372 // which is how the scripts know not to give the alien medal.
373 if (player->hurt_time != 0)
374 o->Delete();
375 }
376 break;
377
378 case 10: // yay spawn ikachans!
379 {
380 o->timer++;
381 if ((o->timer & 3) == 1)
382 {
383 CreateObject(o->x, o->y + ((random(0, 13) * TILE_H) << CSF), OBJ_IKACHAN);
384 }
385 }
386 break;
387 }
388 }
389
ai_ikachan(Object * o)390 void ai_ikachan(Object *o)
391 {
392 switch(o->state)
393 {
394 case 0:
395 {
396 o->state = 1;
397 o->timer = random(3, 20);
398 }
399 case 1: // he pushes ahead
400 {
401 if (--o->timer <= 0)
402 {
403 o->state = 2;
404 o->timer = random(10, 50);
405 o->frame = 1;
406 o->xinertia = 0x600;
407 }
408 }
409 break;
410
411 case 2: // after a short time his tentacles look less whooshed-back
412 {
413 if (--o->timer <= 0)
414 {
415 o->state = 3;
416 o->timer = random(40, 50);
417 o->frame = 2;
418 o->yinertia = random(-0x100, 0x100);
419 }
420 }
421 break;
422
423 case 3: // gliding
424 {
425 if (--o->timer <= 0)
426 {
427 o->state = 1;
428 o->timer = 0;
429 o->frame = 0;
430 }
431
432 o->xinertia -= 0x10;
433 }
434 break;
435 }
436
437 if (o->x > 720<<CSF) o->Delete();
438 }
439
ai_motion_wall(Object * o)440 void ai_motion_wall(Object *o) // the walls at the top and bottom of the arena
441 {
442 o->x -= (6 << CSF);
443
444 if (o->x < (((19 * TILE_W) - 8) << CSF))
445 o->x += (SCREEN_WIDTH + 32) << CSF;
446 }
447
448