void aftermove_blade_l12_shot(Object *o) { int level = (o->shot.btype - B_BLADE_L1); ANIMATE(1, 0, 3); if (--o->shot.ttl < 0) { shot_dissipate(o); return; } // only start damaging enemies after we've passed the player // as it starts slightly behind him if (++o->timer >= 4) { Object *enemy; if ((enemy = damage_enemies(o))) { // on level 2 we can deal damage up to 3 times (18 max) if (level == 0 || \ ++o->timer2 >= 3 || (enemy->flags & FLAG_INVULNERABLE)) { o->Delete(); return; } } else if (IsBlockedInShotDir(o)) { if (!shot_destroy_blocks(o)) sound(SND_SHOT_HIT); shot_dissipate(o, EFFECT_STARSOLID); return; } } switch(level) { case 0: if ((o->timer % 5) == 1) sound(SND_FIREBALL); break; case 1: if ((o->timer % 7) == 1) sound(SND_SLASH); break; } }
void ai_missile_shot(Object *o) { int index = o->shot.level + ((o->type == OBJ_SUPERMISSILE_SHOT) ? 3 : 0); MissileSettings *settings = &missile_settings[index]; if (o->state == 0) { o->shot.damage = settings->damage; if (o->shot.level == 2) { // initilize wavey effect if (o->shot.dir == LEFT || o->shot.dir == RIGHT) o->ymark = -0x20; else o->xmark = -0x20; // don't let it explode until the "recoil" effect is over. o->state = STATE_WAIT_RECOIL_OVER; // record position we were fired at (we won't explode until we pass it) o->xmark2 = player->x; o->ymark2 = player->y; } else { o->state = STATE_MISSILE_CAN_EXPLODE; } } // accelerate according to current type and level of missile // don't use LIMITX here as it can mess up recoil of level 3 super missiles switch(o->shot.dir) { case RIGHT: o->xinertia += settings->accel; if (o->xinertia > settings->maxspeed) o->xinertia = settings->maxspeed; break; case LEFT: o->xinertia -= settings->accel; if (o->xinertia < -settings->maxspeed) o->xinertia = -settings->maxspeed; break; case UP: o->yinertia -= settings->accel; if (o->yinertia < -settings->maxspeed) o->yinertia = -settings->maxspeed; break; case DOWN: o->yinertia += settings->accel; if (o->yinertia > settings->maxspeed) o->yinertia = settings->maxspeed; break; } // wavey effect for level 3 // (markx/y is used as a "speed" value here) if (o->shot.level == 2) { if (o->shot.dir == LEFT || o->shot.dir == RIGHT) { o->yinertia += o->ymark; if (o->ymark > 0 && o->yinertia > 0x100) o->ymark = -o->ymark; if (o->ymark < 0 && o->yinertia < -0x100) o->ymark = -o->ymark; } else { o->xinertia += o->xmark; if (o->xmark > 0 && o->xinertia > 0x100) o->xmark = -o->xmark; if (o->xmark < 0 && o->xinertia < -0x100) o->xmark = -o->xmark; } } // check if we hit an enemy // level 3 missiles can not blow up while they are "recoiling" // what we do is first wait until they're traveling in the direction // they're pointing, then wait till they pass the player's original position. switch(o->state) { case STATE_WAIT_RECOIL_OVER: switch(o->shot.dir) { case LEFT: if (o->xinertia <= 0) o->state = STATE_RECOIL_OVER; break; case RIGHT: if (o->xinertia >= 0) o->state = STATE_RECOIL_OVER; break; case UP: if (o->yinertia <= 0) o->state = STATE_RECOIL_OVER; break; case DOWN: if (o->yinertia >= 0) o->state = STATE_RECOIL_OVER; break; } if (o->state != STATE_RECOIL_OVER) break; case STATE_RECOIL_OVER: switch(o->shot.dir) { case LEFT: if (o->x <= o->xmark2-(2<<CSF)) o->state = STATE_MISSILE_CAN_EXPLODE; break; case RIGHT: if (o->x >= o->xmark2+(2<<CSF)) o->state = STATE_MISSILE_CAN_EXPLODE; break; case UP: if (o->y <= o->ymark2-(2<<CSF)) o->state = STATE_MISSILE_CAN_EXPLODE; break; case DOWN: if (o->y >= o->ymark2+(2<<CSF)) o->state = STATE_MISSILE_CAN_EXPLODE; break; } if (o->state != STATE_MISSILE_CAN_EXPLODE) break; case STATE_MISSILE_CAN_EXPLODE: { bool blow_up = false; if (damage_enemies(o)) { blow_up = true; } else { // check if we hit a wall if (o->shot.dir==LEFT && o->blockl) blow_up = true; else if (o->shot.dir==RIGHT && o->blockr) blow_up = true; else if (o->shot.dir==UP && o->blocku) blow_up = true; else if (o->shot.dir==DOWN && o->blockd) blow_up = true; } if (blow_up) { sound(SND_MISSILE_HIT); // create the boom-spawner object for the flashes, smoke, and AoE damage Object *sp = CreateObject(o->CenterX(), o->CenterY(), OBJ_MISSILE_BOOM_SPAWNER); sp->shot.boomspawner.range = settings->boomrange; sp->shot.boomspawner.booms_left = settings->num_booms; sp->shot.damage = settings->boomdamage; o->Delete(); return; } } break; } if (--o->shot.ttl < 0) shot_dissipate(o, EFFECT_STARPOOF); // smoke trails if (++o->timer > 2) { o->timer = 0; Caret *trail = effect(o->CenterX() - o->xinertia, \ o->CenterY() - o->yinertia, EFFECT_SMOKETRAIL); const int trailspd = 0x400; switch(o->shot.dir) { case LEFT: trail->xinertia = trailspd; trail->y -= (2<<CSF); break; case RIGHT: trail->xinertia = -trailspd; trail->y -= (2<<CSF); break; case UP: trail->yinertia = trailspd; trail->x -= (1<<CSF); break; case DOWN: trail->yinertia = -trailspd; trail->x -= (1<<CSF); break; } } }
void ai_blade_l3_shot(Object *o) { switch(o->state) { case STATE_FLYING: { if ((++o->timer % 4) == 1) { Object *slash = CreateObject(o->x, o->y - (12 << CSF), OBJ_BLADE_SLASH); if (++o->timer2 & 1) { slash->dir = LEFT; slash->x += (10 << CSF); } else { slash->dir = RIGHT; slash->x -= (10 << CSF); } sound(SND_SLASH); } if (++o->timer2 > o->shot.ttl) { shot_dissipate(o); return; } // damage enemies and hit walls if (o->timer2 >= 5) { Object *enemy; if ((enemy = damage_enemies(o))) { if (enemy->flags & FLAG_INVULNERABLE) { shot_spawn_effect(o, EFFECT_STARSOLID); sound(SND_SHOT_HIT); o->Delete(); } else { o->x += o->xinertia; o->y += o->yinertia; o->xinertia = 0; o->yinertia = 0; o->state = STATE_AOE; o->frame = 1; o->timer = 0; } } else if (IsBlockedInShotDir(o)) { if (!shot_destroy_blocks(o)) sound(SND_SHOT_HIT); shot_spawn_effect(o, EFFECT_STARSOLID); o->Delete(); } } } break; case STATE_AOE: { if (!random(0, 2)) { Object *slash = CreateObject(o->x + random(-BLADE_AOE, BLADE_AOE), o->y + random(-BLADE_AOE, BLADE_AOE), OBJ_BLADE_SLASH); slash->dir = random(0, 1) ? LEFT : RIGHT; sound(SND_SLASH); } if (++o->timer > 50) o->Delete(); } break; } o->invisible = (o->timer & 1); }