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; }
int sp_windshield(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; int force, at_malus; int enemies; message *m; force = (int)get_force(power, 4); at_malus = level / 4; enemies = count_enemies(b, fi, BEHIND_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 && enemies) { troop dt = select_enemy(fi, BEHIND_ROW, BEHIND_ROW, SELECT_ADVANCE); fighter *df = dt.fighter; --enemies; if (!df) break; assert(!helping(fi->side, df->side)); if (df->person[dt.index].missile) { /* this suxx... affects your melee weapon as well. */ df->person[dt.index].attack -= at_malus; --force; } } m = msg_message("cast_storm_effect", "mage spell", fi->unit, sp); 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; }
/* Generischer Kampfzauber */ int damage_spell(struct castorder * co, int dmg, int strength) { fighter * fi = co->magician.fig; int level = co->level; const spell * sp = co->sp; double power = co->force; battle *b = fi->side->battle; troop at, dt; message *m; /* Immer aus der ersten Reihe nehmen */ int enemies, killed = 0; int force = lovar(get_force(power, strength)); const char *damage = spell_damage(dmg); at.fighter = fi; at.index = 0; enemies = count_enemies(b, fi, FIGHT_ROW, BEHIND_ROW - 1, SELECT_ADVANCE); if (enemies == 0) { m = msg_message("spell_out_of_range", "mage spell", fi->unit, sp); message_all(b, m); msg_release(m); return 0; } while (force > 0 && killed < enemies) { dt = select_enemy(fi, FIGHT_ROW, BEHIND_ROW - 1, SELECT_ADVANCE); assert(dt.fighter); --force; killed += terminate(dt, at, AT_COMBATSPELL, damage, false); } m = msg_message("cast_combatspell", "mage spell dead", fi->unit, sp, killed); message_all(b, m); msg_release(m); return level; }
/*! \brief Activate the special skill * * This function activates the special skill for a hero, * including targetting etc. if required. * * \param attack_fighter_index Hero to process * \returns 1 if the skill was used, otherwise 0 */ int skill_use(size_t attack_fighter_index) { int tgt, found_item, a, b, c, p, cts, tx, ty, next_target = 0, nn[NUM_FIGHTERS]; size_t enemy_index; size_t fighter_index; std::unique_ptr<Raster> temp; tempa = Magic.status_adjust(attack_fighter_index); switch (pidx[attack_fighter_index]) { case SENSAR: tgt = select_enemy(attack_fighter_index, TGT_ENEMY_ONE); if (tgt == -1) { return 0; } enemy_index = (unsigned int)tgt; temp = std::unique_ptr<Raster>(new Raster(320, 240)); blit(Combat.backart, temp.get(), 0, 0, 0, 0, 320, 240); Draw.color_scale(temp.get(), Combat.backart, 16, 31); b = fighter[attack_fighter_index].mhp / 20; strcpy(attack_string, _("Rage")); display_attack_string = 1; tempa.stats[eStat::Attack] = fighter[attack_fighter_index].stats[eStat::Attack]; tempa.stats[eStat::Hit] = fighter[attack_fighter_index].stats[eStat::Hit]; if (fighter[enemy_index].crit == 1) { tempa.stats[eStat::Attack] += b; tempa.stats[eStat::Hit] += b; } Combat.fight(attack_fighter_index, enemy_index, 1); if (fighter[enemy_index].IsDead()) { for (fighter_index = PSIZE; fighter_index < PSIZE + Combat.GetNumEnemies(); fighter_index++) { if (fighter[fighter_index].IsAlive()) { nn[next_target] = fighter_index; next_target++; } } if (next_target > 0) { enemy_index = nn[kqrandom->random_range_exclusive(0, next_target)]; Combat.fight(attack_fighter_index, enemy_index, 1); } } fighter[attack_fighter_index].hp -= (b * 2); Combat.AdjustHealth(attack_fighter_index, b * 2); display_attack_string = 0; blit(temp.get(), Combat.backart, 0, 0, 0, 0, 320, 240); Effects.display_amount(attack_fighter_index, FONT_DECIDE, 0); if (fighter[attack_fighter_index].IsAlive() && fighter[attack_fighter_index].hp <= 0) { Combat.fkill(attack_fighter_index); Effects.death_animation(attack_fighter_index, 0); } break; case SARINA: fighter[attack_fighter_index].ctmem = 1000; strcpy(attack_string, _("Sweep")); display_attack_string = 1; tempa.stats[eStat::Attack] = tempa.stats[eStat::Attack] * 75 / 100; fighter[attack_fighter_index].aframe = 6; Combat.UnsetDatafileImageCoords(); Combat.battle_render(0, 0, 0); Draw.blit2screen(0, 0); kq_wait(150); Combat.multi_fight(attack_fighter_index); display_attack_string = 0; break; case CORIN: strcpy(attack_string, _("Elemental Infusion")); display_attack_string = 1; fighter[attack_fighter_index].aux = 2; if (combat_spell_menu(attack_fighter_index) == 1) { Effects.draw_castersprite( attack_fighter_index, eff[magic[fighter[attack_fighter_index].csmem].eff].kolor); Combat.UnsetDatafileImageCoords(); play_effect(22, 128); Draw.convert_cframes( attack_fighter_index, eff[magic[fighter[attack_fighter_index].csmem].eff].kolor - 3, eff[magic[fighter[attack_fighter_index].csmem].eff].kolor + 3, 0); Combat.battle_render(0, 0, 0); fullblit(double_buffer, back); for (p = 0; p < 2; p++) { for (a = 0; a < 16; a++) { tx = fighter[attack_fighter_index].cx + (fighter[attack_fighter_index].cw / 2); ty = fighter[attack_fighter_index].cy + (fighter[attack_fighter_index].cl / 2); if (p == 0) { circlefill( double_buffer, tx, ty, a, eff[magic[fighter[attack_fighter_index].csmem].eff].kolor); } else { circlefill( double_buffer, tx, ty, 15 - a, eff[magic[fighter[attack_fighter_index].csmem].eff].kolor); Combat.draw_fighter(attack_fighter_index, 0); } Draw.blit2screen(0, 0); kq_wait(50); fullblit(back, double_buffer); } } Draw.revert_cframes(attack_fighter_index, 0); Combat.battle_render(0, 0, 0); Draw.blit2screen(0, 0); infusion(attack_fighter_index, fighter[attack_fighter_index].csmem); c = Magic.mp_needed(attack_fighter_index, fighter[attack_fighter_index].csmem); if (c < 1) { c = 1; } fighter[attack_fighter_index].mp -= c; Combat.SetEtherEffectActive(attack_fighter_index, false); fighter[attack_fighter_index].aux = 1; } else { fighter[attack_fighter_index].aux = 0; display_attack_string = 0; return 0; } display_attack_string = 0; fighter[attack_fighter_index].SetInfuse(magic[fighter[attack_fighter_index].csmem].elem); break; case AJATHAR: if (fighter[attack_fighter_index].unl > 0) { strcpy(attack_string, _("Dispel Undead")); display_attack_string = 1; fullblit(double_buffer, back); for (a = 0; a < 14/*MagicNumber*/; a++) { Draw.convert_cframes(PSIZE, 1 + a, 15, 1); for (fighter_index = PSIZE; fighter_index < PSIZE + Combat.GetNumEnemies(); fighter_index++) { if (Effects.is_active(fighter_index)) { Combat.draw_fighter(fighter_index, 0); } } Draw.blit2screen(0, 0); kq_wait(50); fullblit(back, double_buffer); } Draw.revert_cframes(PSIZE, 1); display_attack_string = 0; b = fighter[attack_fighter_index].lvl * 15; for (fighter_index = PSIZE; fighter_index < PSIZE + Combat.GetNumEnemies(); fighter_index++) { if (fighter[fighter_index].IsAlive() && fighter[fighter_index].mhp > 0) { if (fighter[fighter_index].unl == 99 || fighter[fighter_index].unl == 0) { cts = 0; } else { a = (fighter[attack_fighter_index].lvl + 5) - fighter[fighter_index].unl; if (a > 0) { cts = a * 8; } else { cts = 0; } } if (kqrandom->random_range_exclusive(0, 100) < cts) { if (b >= fighter[fighter_index].hp) { b -= fighter[fighter_index].hp; Combat.SetShowDeathEffectAnimation(fighter_index, true); Combat.fkill(fighter_index); } } } } Effects.death_animation(PSIZE, 1); Combat.UnsetDatafileImageCoords(); Combat.battle_render(attack_fighter_index, attack_fighter_index, 0); } else { a = kqrandom->random_range_exclusive(0, 100); c = fighter[attack_fighter_index].lvl / 10 + 1; if (a < 25) { b = kqrandom->random_range_exclusive(0, 5 * c) + 1; } else { if (a < 90) { b = kqrandom->random_range_exclusive(0, 10 * c) + (20 * c); } else { b = kqrandom->random_range_exclusive(0, 25 * c) + (50 * c); } } strcpy(attack_string, _("Divine Cure")); display_attack_string = 1; Effects.draw_spellsprite(0, 1, 15, 1); display_attack_string = 0; for (fighter_index = 0; fighter_index < numchrs; fighter_index++) { if (!fighter[fighter_index].IsStone() && fighter[fighter_index].IsAlive()) { int amount = Magic.do_shell_check(fighter_index, b); Combat.AdjustHealth(fighter_index, amount); } } Effects.display_amount(0, FONT_YELLOW, 1); for (fighter_index = 0; fighter_index < numchrs; fighter_index++) { if (!fighter[fighter_index].IsStone() && fighter[fighter_index].IsAlive()) { Magic.adjust_hp(fighter_index, Combat.GetHealthAdjust(fighter_index)); } } } break; case CASANDRA: fighter[attack_fighter_index].atrack[0] = fighter[attack_fighter_index].stats[eStat::Aura]; fighter[attack_fighter_index].atrack[1] = fighter[attack_fighter_index].stats[eStat::Spirit]; fighter[attack_fighter_index].stats[eStat::Aura] = fighter[attack_fighter_index].stats[eStat::Aura] * 15 / 10; fighter[attack_fighter_index].stats[eStat::Spirit] = fighter[attack_fighter_index].stats[eStat::Spirit] * 15 / 10; fighter[attack_fighter_index].atrack[2] = fighter[attack_fighter_index].mrp; fighter[attack_fighter_index].mrp = fighter[attack_fighter_index].mrp * 15 / 10; if (combat_spell_menu(attack_fighter_index) == 1) { Combat.SetEtherEffectActive(attack_fighter_index, false); fighter[attack_fighter_index].aux = 1; fighter[attack_fighter_index].stats[eStat::Aura] = fighter[attack_fighter_index].atrack[0]; fighter[attack_fighter_index].stats[eStat::Spirit] = fighter[attack_fighter_index].atrack[1]; fighter[attack_fighter_index].mrp = fighter[attack_fighter_index].atrack[2]; } else { fighter[attack_fighter_index].stats[eStat::Aura] = fighter[attack_fighter_index].atrack[0]; fighter[attack_fighter_index].stats[eStat::Spirit] = fighter[attack_fighter_index].atrack[1]; fighter[attack_fighter_index].mrp = fighter[attack_fighter_index].atrack[2]; return 0; } break; case TEMMIN: fighter[attack_fighter_index].aux = 1; fighter[attack_fighter_index].defend = 1; break; case AYLA: tgt = select_enemy(attack_fighter_index, TGT_ENEMY_ONE); if (tgt == -1) { return 0; } enemy_index = (uint32_t)tgt; tx = fighter[attack_fighter_index].cx; ty = fighter[attack_fighter_index].cy; fighter[attack_fighter_index].cx = fighter[enemy_index].cx - 16; fighter[attack_fighter_index].cy = fighter[enemy_index].cy + fighter[enemy_index].cl - 40; fighter[attack_fighter_index].facing = 1; strcpy(attack_string, _("Steal")); display_attack_string = 1; Combat.battle_render(0, attack_fighter_index + 1, 0); Draw.blit2screen(0, 0); kq_wait(100); play_effect(SND_MENU, 128); kq_wait(500); display_attack_string = 0; Combat.battle_render(attack_fighter_index, attack_fighter_index, 0); found_item = 0; #ifdef DEBUGMODE if (debugging > 2) { if (fighter[enemy_index].steal_item_rare > 0) { /* This steals a rare item from monster, if there is one */ found_item = fighter[enemy_index].steal_item_rare; fighter[enemy_index].steal_item_rare = 0; } else if (fighter[enemy_index].steal_item_common > 0) { /* This steals a common item from a monster, if there is one */ found_item = fighter[enemy_index].steal_item_common; fighter[enemy_index].steal_item_common = 0; } if (found_item > 0) { if (check_inventory(found_item, 1) != 0) { sprintf(strbuf, _("%s taken!"), items[found_item].name); Draw.message(strbuf, items[found_item].icon, 0, 0, 0); } } else { if (fighter[enemy_index].steal_item_common == 0 && fighter[enemy_index].steal_item_rare == 0) { Draw.message(_("Nothing to steal!"), 255, 0, 0, 0); } else { Draw.message(_("Couldn't steal!"), 255, 0, 0, 0); } } } #else cts = party[pidx[attack_fighter_index]].lvl * 2 + 35; if (cts > 95) { cts = 95; } if (kqrandom->random_range_exclusive(0, 100) < cts) { if (fighter[enemy_index].steal_item_rare > 0 && (kqrandom->random_range_exclusive(0, 100) < 5)) { /* This steals a rare item from monster, if there is one */ found_item = fighter[enemy_index].steal_item_rare; fighter[enemy_index].steal_item_rare = 0; } else if (fighter[enemy_index].steal_item_common > 0 && (kqrandom->random_range_exclusive(0, 100) < 95)) { /* This steals a common item from a monster, if there is one */ found_item = fighter[enemy_index].steal_item_common; fighter[enemy_index].steal_item_common = 0; } if (found_item > 0) { if (check_inventory(found_item, 1) != 0) { sprintf(strbuf, _("%s taken!"), items[found_item].name); Draw.message(strbuf, items[found_item].icon, 0, 0, 0); } } else { if (fighter[enemy_index].steal_item_common == 0 && fighter[enemy_index].steal_item_rare == 0) { Draw.message(_("Nothing to steal!"), 255, 0, 0, 0); } else { Draw.message(_("Couldn't steal!"), 255, 0, 0, 0); } } } else { Draw.message(_("Couldn't steal!"), 255, 0, 0, 0); } #endif fighter[attack_fighter_index].cx = tx; fighter[attack_fighter_index].cy = ty; display_attack_string = 0; fighter[attack_fighter_index].facing = 0; Combat.battle_render(attack_fighter_index, attack_fighter_index, 0); Draw.blit2screen(0, 0); break; case NOSLOM: tgt = select_enemy(attack_fighter_index, TGT_ENEMY_ONE); if (tgt == -1) { return 0; } enemy_index = (uint32_t)tgt; reveal(enemy_index); break; default: break; } return 1; }
/** 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; }
/* Generischer Kampfzauber */ int sp_kampfzauber(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; troop at, dt; message *m; /* Immer aus der ersten Reihe nehmen */ int force, enemies; int killed = 0; const char *damage; if (power <= 0) return 0; at.fighter = fi; at.index = 0; switch (sp->id) { /* lovar halbiert im Schnitt! */ case SPL_FIREBALL: damage = spell_damage(0); force = lovar(get_force(power, 0)); break; case SPL_HAGEL: damage = spell_damage(2); force = lovar(get_force(power, 4)); break; case SPL_METEORRAIN: damage = spell_damage(1); force = lovar(get_force(power, 1)); break; default: damage = spell_damage(10); force = lovar(get_force(power, 10)); } enemies = count_enemies(b, fi, FIGHT_ROW, BEHIND_ROW - 1, SELECT_ADVANCE); if (enemies == 0) { message *m = msg_message("battle::out_of_range", "mage spell", fi->unit, sp); message_all(b, m); msg_release(m); return 0; } while (force > 0 && killed < enemies) { dt = select_enemy(fi, FIGHT_ROW, BEHIND_ROW - 1, SELECT_ADVANCE); assert(dt.fighter); --force; killed += terminate(dt, at, AT_COMBATSPELL, damage, false); } m = msg_message("battle::combatspell", "mage spell dead", fi->unit, sp, killed); message_all(b, m); msg_release(m); return level; }