bool is_hearing (struct anim *k0, struct anim *k1) { struct pos p0, p1; survey (_m, pos, &k0->f, NULL, &p0, NULL); survey ((k0->f.dir == LEFT) ? _mr : _ml, pos, &k1->f, NULL, &p1, NULL); pos2room (&p1, p0.room, &p1); return p1.room == p0.room && (is_kid_run (&k1->f) || is_kid_stop_run (&k1->f) || is_kid_jump_landing (&k1->f) || is_kid_run_jump_running (&k1->f) || is_kid_run_jump_landing (&k1->f) || (is_kid_couch (&k1->f) && k1->fall) || k1->action == kid_take_sword); }
void compute_spikes_floors (void) { size_t i, j; struct pos pm; for (i = 0; i < spikes_floor_nmemb; i++) { struct spikes_floor *s = &spikes_floor[i]; if (s->inactive) continue; int state = s->state; switch (s->i) { case 0: if (should_spikes_raise (&s->p) || s->activate) { alert_guards (&s->p); play_sample (spikes_sample, &s->p, -1); s->i++; s->wait = 12; s->state = 1; } else if (s->state != 0) s->state = 0; break; case 1: s->i++; s->state = 2; break; case 2: s->i++; s->state = 3; break; case 3: s->i++; s->state = 4; break; case 4: if (! should_spikes_raise (&s->p)) { if (s->wait-- == 0) { s->i++; s->state = 3; } else s->state = 5; } else { s->state = 5; } break; case 5: s->i++; s->state = 2; break; case 6: s->i = 0; s->state = 1; s->activate = false; break; } if (state != s->state) register_changed_pos (&s->p, CHPOS_SPIKES); /* spike kid */ for (j = 0; j < anima_nmemb; j++) { struct anim *a = &anima[j]; if (is_kid_dead (&a->f) || a->immortal || a->spikes_immune) continue; survey (_m, pos, &a->f, NULL, &pm, NULL); if (peq (&pm, &s->p) && (((s->state >= 2 && s->state <= 4) && (is_kid_start_run (&a->f) || is_kid_run (&a->f) || is_kid_run_jump_running (&a->f))) || (is_kid_couch (&a->f) && a->fall && a->i < 3 && ! a->float_timer) || (is_kid_jump_landing (&a->f) && a->i <= 13) || is_kid_run_jump_landing (&a->f))) { a->p = s->p; anim_die_spiked (a); } } } }
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; } }