int sp_frighten(struct castorder * co) { fighter * fi = co->magician.fig; int level = co->level; double power = co->force; const spell * sp = co->sp; battle *b = fi->side->battle; unit *mage = fi->unit; int at_malus = 0; int df_malus = 0; int force = 0; int enemies = 0; int targets = 0; message *m; at_malus = level - 4; if (at_malus < 1) at_malus = 1; df_malus = 2; force = (int)get_force(power, 2); enemies = count_enemies(b, fi, FIGHT_ROW, BEHIND_ROW - 1, SELECT_ADVANCE); if (!enemies) { m = msg_message("spell_out_of_range", "mage spell", fi->unit, sp); message_all(b, m); msg_release(m); return 0; } while (force && enemies) { troop dt = select_enemy(fi, FIGHT_ROW, BEHIND_ROW - 1, SELECT_ADVANCE); fighter *df = dt.fighter; --enemies; if (!df) break; assert(!helping(fi->side, df->side)); if (df->person[dt.index].flags & FL_COURAGE) { df->person[dt.index].flags &= ~(FL_COURAGE); } if (!is_magic_resistant(mage, df->unit, 0)) { df->person[dt.index].attack -= at_malus; df->person[dt.index].defense -= df_malus; targets++; } --force; } m = msg_message("cast_frighten_effect", "mage spell amount", fi->unit, sp, targets); message_all(b, m); msg_release(m); return level; }
/* Panik (Praekampfzauber) */ int flee_spell(struct castorder * co, int strength) { fighter * fi = co->magician.fig; int level = co->level; const spell * sp = co->sp; battle *b = fi->side->battle; unit *mage = fi->unit; selist *fgs, *ql; int n, qi, panik = 0; message *msg; double power = co->force; int force; force = (int)get_force(power, strength); if (force<=0 || !count_enemies(b, fi, FIGHT_ROW, AVOID_ROW, SELECT_ADVANCE | SELECT_FIND)) { msg = msg_message("sp_flee_effect_0", "mage spell", mage, sp); message_all(b, msg); msg_release(msg); return 0; } fgs = select_fighters(b, fi->side, FS_ENEMY, select_afraid, NULL); scramble_fighters(fgs); for (qi = 0, ql = fgs; force > 0 && ql; selist_advance(&ql, &qi, 1)) { fighter *df = (fighter *)selist_get(ql, qi); for (n = 0; force > 0 && n != df->alive; ++n) { if (df->person[n].flags & FL_PANICED) { /* bei SPL_SONG_OF_FEAR moeglich */ df->person[n].attack -= 1; --force; ++panik; } else if (!(df->person[n].flags & FL_COURAGE) || !(u_race(df->unit)->flags & RCF_UNDEAD)) { if (!is_magic_resistant(mage, df->unit, 0)) { df->person[n].flags |= FL_PANICED; ++panik; } --force; } } } selist_free(fgs); msg = msg_message("sp_flee_effect_1", "mage spell amount", mage, sp, panik); message_all(b, msg); msg_release(msg); return level; }
/* Benommenheit: eine Runde kein Angriff */ int sp_stun(struct castorder * co) { fighter * fi = co->magician.fig; int level = co->level; double power = co->force; const spell * sp = co->sp; battle *b = fi->side->battle; unit *mage = fi->unit; message *m; /* Aus beiden Reihen nehmen */ int force = 0, enemies; int stunned; if (power <= 0) return 0; switch (sp->id) { case SPL_SHOCKWAVE: force = lovar(get_force(power, 1)); break; default: assert(0); } enemies = count_enemies(b, fi, FIGHT_ROW, BEHIND_ROW, SELECT_ADVANCE); if (!enemies) { message *m = msg_message("battle::out_of_range", "mage spell", fi->unit, sp); message_all(b, m); msg_release(m); return 0; } stunned = 0; while (force && stunned < enemies) { troop dt = select_enemy(fi, FIGHT_ROW, BEHIND_ROW, SELECT_ADVANCE); fighter *df = dt.fighter; unit *du = df->unit; --force; if (!is_magic_resistant(mage, du, 0)) { df->person[dt.index].flags |= FL_STUNNED; ++stunned; } } m = msg_message("cast_stun_effect", "mage spell amount", fi->unit, sp, stunned); message_all(b, m); msg_release(m); return level; }
int sp_tiredsoldiers(struct castorder * co) { fighter * fi = co->magician.fig; int level = co->level; double power = co->force; const spell * sp = co->sp; battle *b = fi->side->battle; unit *mage = fi->unit; int n = 0; int force = (int)(power * power * 4); message *m; if (!count_enemies(b, fi, FIGHT_ROW, BEHIND_ROW, SELECT_ADVANCE | SELECT_FIND)) { message *m = msg_message("battle::out_of_range", "mage spell", fi->unit, sp); message_all(b, m); msg_release(m); return 0; } while (force) { troop t = select_enemy(fi, FIGHT_ROW, BEHIND_ROW, SELECT_ADVANCE); fighter *df = t.fighter; if (!df) break; assert(!helping(fi->side, df->side)); if (!(df->person[t.index].flags & FL_TIRED)) { if (!is_magic_resistant(mage, df->unit, 0)) { df->person[t.index].flags = df->person[t.index].flags | FL_TIRED; df->person[t.index].defence -= 2; ++n; } } --force; } m = msg_message("cast_tired_effect", "mage spell amount", fi->unit, sp, n); message_all(b, m); msg_release(m); return level; }
/* Versteinern */ int sp_petrify(struct castorder * co) { fighter * fi = co->magician.fig; int level = co->level; double power = co->force; const spell * sp = co->sp; battle *b = fi->side->battle; unit *mage = fi->unit; /* Wirkt auf erste und zweite Reihe */ int force, enemies; int stoned = 0; message *m; force = lovar(get_force(power, 0)); enemies = count_enemies(b, fi, FIGHT_ROW, BEHIND_ROW, SELECT_ADVANCE); if (!enemies) { message *m = msg_message("battle::out_of_range", "mage spell", fi->unit, sp); message_all(b, m); msg_release(m); return 0; } while (force && stoned < enemies) { troop dt = select_enemy(fi, FIGHT_ROW, BEHIND_ROW, SELECT_ADVANCE); unit *du = dt.fighter->unit; if (!is_magic_resistant(mage, du, 0)) { /* person ans ende hinter die lebenden schieben */ remove_troop(dt); ++stoned; } --force; } m = msg_message("cast_petrify_effect", "mage spell amount", fi->unit, sp, stoned); message_all(b, m); msg_release(m); return level; }
int sp_sleep(struct castorder * co) { fighter * fi = co->magician.fig; int level = co->level; const spell * sp = co->sp; battle *b = fi->side->battle; unit *mage = fi->unit; unit *du; troop dt; int force, enemies; int k = 0; message *m; /* Immer aus der ersten Reihe nehmen */ force = lovar(co->force * 25); enemies = count_enemies(b, fi, FIGHT_ROW, BEHIND_ROW, SELECT_ADVANCE); if (!enemies) { m = msg_message("battle::out_of_range", "mage spell", fi->unit, sp); message_all(b, m); msg_release(m); return 0; } while (force && enemies) { dt = select_enemy(fi, FIGHT_ROW, BEHIND_ROW, SELECT_ADVANCE); assert(dt.fighter); du = dt.fighter->unit; if (!is_magic_resistant(mage, du, 0)) { dt.fighter->person[dt.index].flags |= FL_SLEEPING; ++k; --enemies; } --force; } m = msg_message("cast_sleep_effect", "mage spell amount", fi->unit, sp, k); message_all(b, m); msg_release(m); return level; }
/** Spells: chaosrow / song of confusion. * German Title: 'Gesang der Verwirrung' */ int sp_chaosrow(struct castorder * co) { fighter * fi = co->magician.fig; int level = co->level; double power = co->force; const spell * sp = co->sp; battle *b = fi->side->battle; unit *mage = fi->unit; selist *fgs, *ql; message *m; const char *mtype; int qi, k = 0; bool chaosrow = strcmp(sp->sname, "chaosrow") == 0; if (!count_enemies(b, fi, FIGHT_ROW, NUMROWS, SELECT_ADVANCE | SELECT_FIND)) { m = msg_message("spell_out_of_range", "mage spell", fi->unit, sp); message_all(b, m); msg_release(m); return 0; } power = chaosrow ? (power * 40) : get_force(power, 5); fgs = select_fighters(b, fi->side, FS_ENEMY, select_alive, NULL); scramble_fighters(fgs); for (qi = 0, ql = fgs; ql; selist_advance(&ql, &qi, 1)) { fighter *df = (fighter *)selist_get(ql, qi); int n = df->unit->number; if (df->alive == 0) continue; if (power <= 0.0) break; if (is_magic_resistant(mage, df->unit, 0)) continue; if (chance(power / n)) { int row = statusrow(df->status); df->side->size[row] -= df->alive; if (u_race(df->unit)->battle_flags & BF_NOBLOCK) { df->side->nonblockers[row] -= df->alive; } row = FIRST_ROW + (rng_int() % (NUMROWS - FIRST_ROW)); switch (row) { case FIGHT_ROW: df->status = ST_FIGHT; break; case BEHIND_ROW: df->status = ST_CHICKEN; break; case AVOID_ROW: df->status = ST_AVOID; break; case FLEE_ROW: df->status = ST_FLEE; break; default: assert(!"unknown combatrow"); } assert(statusrow(df->status) == row); df->side->size[row] += df->alive; if (u_race(df->unit)->battle_flags & BF_NOBLOCK) { df->side->nonblockers[row] += df->alive; } k += df->alive; } power = fmax(0, power - n); } selist_free(fgs); if (chaosrow) { mtype = (k > 0) ? "sp_chaosrow_effect_1" : "sp_chaosrow_effect_0"; } else { mtype = (k > 0) ? "sp_confusion_effect_1" : "sp_confusion_effect_0"; } m = msg_message(mtype, "mage", mage); message_all(b, m); msg_release(m); return level; }
/** The mind blast spell for regular folks. * This spell temporarily reduces the skill of the victims */ int sp_mindblast(struct castorder * co) { fighter * fi = co->magician.fig; int level = co->level; double power = co->force; const spell * sp = co->sp; battle *b = fi->side->battle; unit *mage = fi->unit; int k = 0, reset = 0, maxloss = (level + 2) / 3; message *m; int force = lovar(power * 25); int enemies = count_enemies(b, fi, FIGHT_ROW, BEHIND_ROW, SELECT_ADVANCE); if (!enemies) { m = msg_message("spell_out_of_range", "mage spell", fi->unit, sp); message_all(b, m); msg_release(m); return 0; } while (force > 0 && enemies > 0) { unit *du; troop dt = select_enemy(fi, FIGHT_ROW, BEHIND_ROW, SELECT_ADVANCE); assert(dt.fighter); du = dt.fighter->unit; if (du->flags & UFL_MARK) { /* not this one again */ continue; } if (humanoidrace(u_race(du)) && force >= du->number) { if (!is_magic_resistant(mage, du, 0)) { skill_t sk = random_skill(du, true); if (sk != NOSKILL) { int n = 1 + rng_int() % maxloss; attrib *a = make_skillmod(sk, NULL, 0.0, n); /* neat: you can add a whole lot of these to a unit, they stack */ a_add(&du->attribs, a); } k += du->number; } force -= du->number; } du->flags |= UFL_MARK; reset = 1; enemies -= du->number; } if (reset) { unit *u; for (u = b->region->units; u; u = u->next) { u->flags &= ~UFL_MARK; } } m = msg_message("sp_mindblast_temp_effect", "mage spell amount", mage, sp, k); message_all(b, m); msg_release(m); return level; }
/** A mind blast spell for monsters. * This spell PERMANENTLY reduces the skill of the victims or kills them * when they have no skills left. Not currently in use. */ int sp_mindblast(struct castorder * co) { fighter * fi = co->magician.fig; int level = co->level; double power = co->force; const spell * sp = co->sp; battle *b = fi->side->battle; unit *mage = fi->unit; int killed = 0, k = 0, reset = 0; message *m; int force = lovar(power * 25); int enemies = count_enemies(b, fi, FIGHT_ROW, BEHIND_ROW, SELECT_ADVANCE); if (!enemies) { m = msg_message("battle::out_of_range", "mage spell", fi->unit, sp); message_all(b, m); msg_release(m); return 0; } while (enemies > 0 && force > 0) { unit *du; troop dt = select_enemy(fi, FIGHT_ROW, BEHIND_ROW, SELECT_ADVANCE); assert(dt.fighter); du = dt.fighter->unit; if (du->flags & UFL_MARK) { /* not this one again */ continue; } if (humanoidrace(u_race(du)) && force >= du->number) { if (!is_magic_resistant(mage, du, 0)) { skill_t sk = random_skill(du, false); if (sk != NOSKILL) { skill *sv = unit_skill(du, sk); if (sv) { int n = 1 + rng_int() % 3; reduce_skill(du, sv, n); k += du->number; } } else { /* unit has no skill. kill it. */ kill_troop(dt); ++killed; } } force -= du->number; } else { /* only works against humanoids, don't try others. but do remove them * from 'force' once or we may never terminate. */ du->flags |= UFL_MARK; reset = 1; } enemies -= du->number; } if (reset) { unit *u; for (u = b->region->units; u; u = u->next) { u->flags &= ~UFL_MARK; } } m = msg_message("sp_mindblast_effect", "mage spell amount dead", mage, sp, k, killed); message_all(b, m); msg_release(m); return level; }
int sp_flee(struct castorder * co) { fighter * fi = co->magician.fig; int level = co->level; double power = co->force; const spell * sp = co->sp; battle *b = fi->side->battle; unit *mage = fi->unit; quicklist *fgs, *ql; int force, n, qi; int panik = 0; message *msg; switch (sp->id) { case SPL_FLEE: force = (int)get_force(power, 4); break; case SPL_SONG_OF_FEAR: force = (int)get_force(power, 3); break; case SPL_AURA_OF_FEAR: force = (int)get_force(power, 5); break; default: force = (int)get_force(power, 10); } if (!count_enemies(b, fi, FIGHT_ROW, AVOID_ROW, SELECT_ADVANCE | SELECT_FIND)) { msg = msg_message("sp_flee_effect_0", "mage spell", mage, sp); message_all(b, msg); msg_release(msg); return 0; } fgs = fighters(b, fi->side, FIGHT_ROW, AVOID_ROW, FS_ENEMY); scramble_fighters(fgs); for (qi = 0, ql = fgs; ql; ql_advance(&ql, &qi, 1)) { fighter *df = (fighter *)ql_get(ql, qi); for (n = 0; n != df->alive; ++n) { if (force < 0) break; if (df->person[n].flags & FL_PANICED) { /* bei SPL_SONG_OF_FEAR m�glich */ df->person[n].attack -= 1; --force; ++panik; } else if (!(df->person[n].flags & FL_COURAGE) || !(u_race(df->unit)->flags & RCF_UNDEAD)) { if (!is_magic_resistant(mage, df->unit, 0)) { df->person[n].flags |= FL_PANICED; ++panik; } --force; } } } ql_free(fgs); msg = msg_message("sp_flee_effect_1", "mage spell amount", mage, sp, panik); message_all(b, msg); msg_release(msg); return level; }