void ai_gaudi_egg(Object *o) { if (!o->state) { if (o->dir==LEFT) { // on floor // align properly with ground o->y -= (4<<CSF); o->x -= (4<<CSF); } else { // on ceiling // for the egg @ entrance point that is on a ceiling slope if (!o->blocku) { o->y -= (14 << CSF); } } o->state = 1; } else if (o->state == 1) { if (o->hp < 90) { o->frame = 1; o->damage = 0; o->flags &= ~FLAG_SHOOTABLE; SmokeSide(o, 6, (o->dir==LEFT)?DOWN:UP); o->SpawnPowerups(); sound(objprop[o->type].death_sound); o->state = 2; } } }
void ai_proximity_press_vert(Object *o) { switch(o->state) { case 0: { if (pdistlx(8<<CSF) && pdistly2(8<<CSF, 128<<CSF) && \ !o->blockd) { o->state = 10; o->animtimer = 0; o->frame = 1; } } break; case 10: { if (o->frame < 2) ANIMATE_FWD(2); if (o->blockd) { if (o->frame >= 2) // make sure eye fully open { SmokeSide(o, 4, DOWN); quake(10); } o->flags |= FLAG_SOLID_BRICK; o->damage = 0; o->state = 11; o->frame = 0; } else { if (player->Top() > o->CenterY()) { o->flags &= ~FLAG_SOLID_BRICK; o->damage = 127; } else { o->flags |= FLAG_SOLID_BRICK; o->damage = 0; } } } break; } if (o->state >= 5) { o->yinertia += 0x80; LIMITY(0x5ff); } }
void ai_block_movev(Object *o) { int py = player->CenterY(); int objy = o->CenterY(); switch(o->state) { case 0: NX_LOG("ai_block_movev - state 0.\n"); o->flags |= FLAG_SOLID_BRICK; o->smushdamage = 100; o->dir = (o->dir == LEFT) ? UP : DOWN; o->state = (o->dir == DOWN) ? 10 : 20; break; case 10: // at top edge, ready to travel down NX_LOG("ai_block_movev - state 10.\n"); if (((py > objy) && (py - objy) < 0x32000) || \ ((py < objy) && (objy - py) < 0x3200)) { if (pdistlx(0x3200)) { o->state = 30; o->timer = 0; } } break; case 20: // at bottom edge, ready to travel up NX_LOG("ai_block_movev - state 20.\n"); if (((py > objy) && (py - objy) < 0x3200) || \ ((py < objy) && (objy - py) < 0x32000)) { if (pdistlx(0x3200)) { o->state = 30; o->timer = 0; } } break; case 30: // traveling NX_LOG("ai_block_movev - state 30.\n"); { YACCEL(0x20); LIMITY(0x200); // hit edge if ((o->dir == DOWN && o->blockd) || (o->dir == UP && o->blocku)) { SmokeSide(o, 4, o->dir); quake(10); o->yinertia = 0; o->dir ^= 1; o->state = (o->dir==DOWN) ? 10 : 20; } if ((++o->timer % 10) == 6) sound(SND_BLOCK_MOVE); } break; } }
void ai_block_moveh(Object *o) { int px = player->CenterX(); int objx = o->CenterX(); switch(o->state) { case 0: NX_LOG("ai_block_moveh - state 0.\n"); o->flags |= FLAG_SOLID_BRICK; o->smushdamage = 100; o->state = (o->dir == LEFT) ? 10:20; break; case 10: // at right edge, ready to travel left NX_LOG("ai_block_moveh - state 10.\n"); if (((px > objx) && (px - objx) < 0x3200) || \ ((px < objx) && (objx - px) < 0x32000)) { if (pdistly(0x3200)) { o->state = 30; o->timer = 0; } } break; case 20: // at left edge, ready to travel right NX_LOG("ai_block_moveh - state 20.\n"); if (((px > objx) && (px - objx) < 0x32000) || \ ((px < objx) && (objx - px) < 0x3200)) { if (pdistly(0x3200)) { o->state = 30; o->timer = 0; } } break; case 30: // traveling { NX_LOG("ai_block_moveh - state 30.\n"); XACCEL(0x20); LIMITX(0x200); // hit edge if ((o->dir == RIGHT && o->blockr) || (o->dir == LEFT && o->blockl)) { SmokeSide(o, 4, o->dir); quake(10); o->xinertia = 0; o->dir ^= 1; o->state = (o->dir==LEFT) ? 10 : 20; } if ((++o->timer % 10) == 6) sound(SND_BLOCK_MOVE); } break; } }
// boss-fight igor void ai_boss_igor(Object *o) { enum { STATE_INIT = 0, STATE_STAND, STATE_BEGIN_ATTACK, STATE_WALK, STATE_JUMPING, STATE_LANDED, STATE_PUNCH, STATE_PUNCH_2, STATE_PUNCH_3, STATE_MOUTH_BLAST, STATE_MOUTH_BLAST_2 }; switch(o->state) { case STATE_INIT: { o->damage = 0; o->xinertia = 0; o->state = STATE_STAND; o->frame = 0; o->animtimer = 0; } case STATE_STAND: { ANIMATE(5, 0, 1); if (++o->timer > 50) { o->state = STATE_BEGIN_ATTACK; } } break; case STATE_BEGIN_ATTACK: { o->state = STATE_WALK; o->frame = 2; o->animtimer = 0; o->timer = 0; FACEPLAYER; o->igor.fireattack = false; // when health is less than halfway, then use // the mouth blast attack every third time. if (++o->timer2 >= 3 && \ o->hp <= (objprop[o->type].initial_hp / 2)) { o->timer2 = 0; o->igor.fireattack = true; o->dir ^= 1; // walk away from player } } // fall thru case STATE_WALK: { ANIMATE(3, 2, 5); XMOVE(0x200); if (o->igor.fireattack) { // begin mouth-blast attack if (++o->timer > 16) { o->state = STATE_MOUTH_BLAST; o->xinertia = 0; o->frame = 10; } } else { if (o->dir == LEFT) { if (o->x <= player->x + player->Width()) o->state = STATE_PUNCH; } else { if (o->x + o->Width() >= player->x) o->state = STATE_PUNCH; } // if we don't reach him after a while, do a jump if (++o->timer > 50) { o->frame = 10; o->yinertia = -0x400; o->state = STATE_JUMPING; o->timer = 0; o->xinertia *= 2; o->xinertia /= 3; o->damage = 2; } } } break; case STATE_PUNCH: { o->xinertia = 0; o->state = STATE_PUNCH_2; o->frame = 6; o->timer = 0; } case STATE_PUNCH_2: { if (++o->timer > 12) { sound(SND_EXPL_SMALL); // sprite appears identical, but has a wider bounding box. o->sprite = SPR_IGOR_PUNCHING; o->damage = 5; o->state = STATE_PUNCH_3; o->frame = 7; o->timer = 0; } } break; case STATE_PUNCH_3: { if (++o->timer > 10) { o->state = STATE_INIT; o->frame = 0; o->damage = 0; // return to normal-size bounding box o->sprite = SPR_IGOR; } } break; case STATE_JUMPING: { if (o->blockd) { sound(SND_QUAKE); SmokeSide(o, 4, DOWN); o->state = STATE_LANDED; o->frame = 11; o->timer = 0; } } break; case STATE_LANDED: { o->xinertia = 0; if (++o->timer > 10) { o->state = STATE_INIT; o->frame = 0; o->damage = 0; } } break; case STATE_MOUTH_BLAST: { FACEPLAYER; o->timer = 0; o->state++; } case STATE_MOUTH_BLAST_2: { o->timer++; // flash mouth o->frame = 8; if (o->timer > 50 && (o->timer & 2)) o->frame = 9; // fire shots if (o->timer > 100) { if ((o->timer % 6) == 1) { sound(SND_BLOCK_DESTROY); Object *shot = SpawnObjectAtActionPoint(o, OBJ_IGOR_SHOT); int angle = (o->dir == LEFT) ? 136 : 248; angle += random(-16, 16); ThrowObjectAtAngle(shot, angle, 0x580); } if (o->timer > 132) // fires 6 shots { o->state = STATE_INIT; o->timer = 0; } } } break; } o->yinertia += 0x40; LIMITY(0x5ff); }