void compute_loose_floor_fall (struct loose_floor *l) { int speed = 3 * ++l->i; if (speed > 29) speed = 29; struct frame nf; struct frame_offset fo; fo.b = l->f.b; fo.dx = 0; fo.dy = speed; next_frame (&l->f, &nf, &fo); struct coord mbo_f, mbo_nf; struct pos fpmbo_f, nfpmbo_f, fpmbo_nf, nfpmbo_nf; enum confg fcmbo_f; fcmbo_f = survey (_mbo, posf, &l->f, &mbo_f, &fpmbo_f, &nfpmbo_f)->fg; survey (_mbo, posf, &nf, &mbo_nf, &fpmbo_nf, &nfpmbo_nf); struct pos p; /* hit kid */ int i; for (i = 0; i < anima_nmemb; i++) { struct coord kmt, ambo_f, ambo_nf; struct pos np, kpmt; struct anim *a = &anima[i]; if (is_anim_dead (&a->f) || a->immortal || a->loose_floor_immune) continue; survey (_mt, pos, &a->f, &kmt, &kpmt, &np); coord2room (&mbo_f, kpmt.room, &ambo_f); coord2room (&mbo_nf, kpmt.room, &ambo_nf); if (peq (&nfpmbo_f, &kpmt) && ambo_f.y <= kmt.y && ambo_nf.y >= kmt.y && ! a->hit_by_loose_floor && ! is_kid_hang_or_climb (&a->f) && ! is_kid_fall (&a->f)) { a->hit_by_loose_floor = true; a->splash = true; a->current_lives--; a->uncouch_slowly = true; /* ensure kid doesn't couch in thin air (might occur when hit while jumping, for example) */ place_on_the_ground (&a->f, &a->f.c); play_sample (hit_wall_sample, kpmt.room); alert_guards (&kpmt); if (a->id == current_kid_id) { video_effect.color = get_flicker_blood_color (); start_video_effect (VIDEO_FLICKERING, SECS_TO_VCYCLES (0.1)); } if (a->current_lives <= 0) { a->p = kpmt; anim_die_suddenly (a); a->death_reason = LOOSE_FLOOR_DEATH; } else if (a->type == KID) kid_couch (a); } } /* fall */ if (is_strictly_traversable (&fpmbo_f) || peq (&fpmbo_f, &fpmbo_nf)) { /* the floor hit a rigid structure */ if (is_rigid_con (&fpmbo_nf)) prel (&fpmbo_nf, &p, -1, 0); /* the floor continue to fall */ else { l->f = nf; if (is_strictly_traversable (&fpmbo_nf)) l->p = fpmbo_nf; must_sort = true; return; } /* the floor hit the ground */ } else { struct loose_floor *m; p = fpmbo_f; switch (fcmbo_f) { case LOOSE_FLOOR: /* loose floor isn't ground */ m = loose_floor_at_pos (&fpmbo_f); if (m) m->p.room = -1; must_remove = true; l->f = nf; l->f.b = get_correct_falling_loose_floor_bitmap (dv_broken_floor); l->p = fpmbo_f; l->i = 0; con (&fpmbo_f)->fg = NO_FLOOR; must_sort = true; play_sample (broken_floor_sample, p.room); alert_guards (&p); return; case OPENER_FLOOR: break_opener_floor (&fpmbo_f); break; case CLOSER_FLOOR: break_closer_floor (&fpmbo_f); break; case SPIKES_FLOOR: break_spikes_floor (&fpmbo_f); break; case LEVEL_DOOR: break_level_door (&fpmbo_f); break; default: break; } } /* reach here only if the floor hit a rigid structure or the ground */ if (con (&p)->fg != LEVEL_DOOR) con (&p)->fg = BROKEN_FLOOR; shake_loose_floor_row (&p); l->p.room = -1; must_remove = true; must_sort = true; play_sample (broken_floor_sample, p.room); alert_guards (&p); }
void fight_ai (struct anim *k) { /* non-fightable characters don't fight */ if (! is_fightable_anim (k)) return; /* controllables and non-fighters doesn't need AI to fight */ if (k->controllable || ! k->fight) return; /* if forgetting about an enemy, no need to fight */ if (k->enemy_refraction > 0) return; /* without an enemy or awareness, no need to fight */ if (k->enemy_id == -1) { if (is_in_fight_mode (k)) leave_fight_mode (k); return; } /* first thing, enter in fight mode */ if (! is_in_fight_mode (k)) { enter_fight_mode (k); return; } /* who's the enemy? */ struct anim *ke = get_anim_by_id (k->enemy_id); /* what's the facing opposite direction? */ enum dir odir = (k->f.dir == LEFT) ? RIGHT : LEFT; /* get positions */ struct pos p, pe; survey (_m, pos, &k->f, NULL, &p, NULL); survey ((k->f.dir != ke->f.dir) ? _m : _mba, pos, &ke->f, NULL, &pe, NULL); pos2room (&pe, p.room, &pe); /* remember the place the enemy was last seen */ if (pe.room == p.room && pe.floor == p.floor) k->enemy_pos = pe; else if (pe.floor > p.floor && is_valid_pos (&k->enemy_pos) && ! is_strictly_traversable (&k->enemy_pos)) k->enemy_pos.place = pe.place; if (is_valid_pos (&k->enemy_pos) && is_strictly_traversable (&k->enemy_pos)) { struct pos pp; int d = (p.place < k->enemy_pos.place) ? -1 : +1; while (is_strictly_traversable (prel (&k->enemy_pos, &pp, +0, d))) k->enemy_pos = pp; } /* prevent enemy from passing through */ if (ke->type == KID && is_in_range (k, ke, ATTACK_RANGE) && ! is_in_fight_mode (ke) && ! ke->immortal && ! (is_kid_climb (&ke->f) && ke->i <= 7) && ke->f.dir != k->f.dir && ke->current_lives > 0 && ke->has_sword && ! is_kid_fall (&ke->f) && ! is_kid_hang (&ke->f) && ! is_kid_jump_air (&ke->f) && ! is_kid_run_jump_air (&ke->f) && is_safe_to_attack (ke)) { place_on_the_ground (&ke->f, &ke->f.c); kid_take_sword (ke); ke->auto_taken_sword = true; } /* prevent enemy from hiding near */ if (ke->type == KID && is_in_range (k, ke, INVERSION_RANGE) && ! is_in_fight_mode (ke) && ke->current_lives > 0) { if (is_safe_to_walkb (k)) fight_walkb (k); else if (is_safe_to_turn (k)) fight_turn (k); return; } /* if the enemy is on the back, turn */ if (is_on_back (k, ke) && is_anim_seeing (k, ke, odir) && p.floor == pe.floor && ! is_in_range (k, ke, INVERSION_RANGE)) { if (is_safe_to_turn (k)) fight_turn (k); else if (is_safe_to_walkb (k)) fight_walkb (k); return; } /* if too near to a wall, back off to have room for an attack */ if (fight_crel (k, +0, +1) == WALL && is_safe_to_walkb (k)) { fight_walkb (k); return; } /* /\* if the enemy can be followed in the opposite direction, turn *\/ */ /* if (! is_safe_to_follow (k, ke, k->f.dir) */ /* && is_safe_to_follow (k, ke, odir)) { */ /* fight_turn (k); */ /* return; */ /* } */ /* if the enemy is trying to bypass, attack him */ if (! is_in_fight_mode (ke) && ! ke->has_sword && ! is_kid_stairs (&ke->f) && ke->f.dir != k->f.dir && ke->current_lives > 0 && ! is_on_back (k, ke) && ((is_kid_run (&ke->f) && is_in_range (k, ke, 3 * PLACE_WIDTH - 4)) || (is_kid_run_jump (&ke->f) && is_in_range (k, ke, 4 * PLACE_WIDTH - 4)) || (is_kid_jump_air (&ke->f) && ke->i < 9 && is_in_range (k, ke, 4 * PLACE_WIDTH)))) { if (is_safe_to_attack (k)) fight_attack (k); else if (is_safe_to_walkb (k)) fight_walkb (k); return; } /* stays at least in the fight range. Advance, unless the enemy is not running towards you */ if (! is_in_range (k, ke, FIGHT_RANGE + 10) && ! is_kid_stairs (&ke->f) && (ke->f.dir == k->f.dir || p.room != pe.room || p.floor != pe.floor || ! (is_kid_run (&ke->f) || is_kid_run_jump (&ke->f) || is_kid_jump (&ke->f))) && is_safe_to_follow (k, ke, k->f.dir)) { fight_walkf (k); return; } /* if the enemy is not targeting you, do nothing more */ if (ke->enemy_id != -1 && ke->enemy_id != k->id) return; /* in fight range, if the enemy is not attacking, go towards attack range (with probability, unless the enemy is not in fight mode, then go immediately) */ if (is_in_range (k, ke, FIGHT_RANGE + 10) && ! is_in_range (k, ke, ATTACK_RANGE) && ! is_kid_stairs (&ke->f) && is_safe_to_follow (k, ke, k->f.dir) && (prandom (99) <= k->skill.advance_prob || ! is_in_fight_mode (ke)) && ! is_attacking (ke) && (! is_in_fight_mode (ke) || is_walking (ke) || ke->i >= 6 + prandom (24))) { fight_walkf (k); return; } /* in attack range, if being attacked, defend yourself (with probability) and counter attack (with probability handled elsewhere) */ if (is_in_range (k, ke, ATTACK_RANGE + 16) && ! is_on_back (k, ke) && (is_attacking (ke) && ke->i == 0) && (prandom (99) <= k->skill.defense_prob || k->refraction > 0) && ke->current_lives > 0) { fight_defense (k); fight_attack (k); return; } /* if attacking, counter defend (with probability handled elsewhere) */ if (is_in_range (k, ke, ATTACK_RANGE + 16) && is_attacking (k)) { fight_defense (k); fight_attack (k); return; } /* in attack range, if not being attacked, attack (with probability, unless the enemy is not in fight mode, then attack immediately) */ if (is_in_range (k, ke, ATTACK_RANGE) && ! is_attacking (ke) && ! is_on_back (k, ke) && ! is_kid_stairs (&ke->f) && ! ((is_kid_climb (&ke->f) || is_kid_successfully_climbing (&ke->f)) && ke->i >= 1) && ke->current_lives > 0 && (prandom (99) <= k->skill.attack_prob || ! is_in_fight_mode (ke))) { if (is_safe_to_attack (k)) fight_attack (k); else if (is_safe_to_walkb (k)) fight_walkb (k); return; } /* in hit range, back off (with probability) */ if (is_in_range (k, ke, HIT_RANGE - 10) && is_safe_to_walkb (k) && ! k->refraction && ! is_walkingb (ke) && prandom (99) <= k->skill.return_prob) { fight_walkb (k); return; } }