void reduce_skill_days(unit *u, skill_t sk, int days) { skill *sv = unit_skill(u, sk); if (sv) { while (days > 0) { if (days >= STUDYDAYS * u->number) { reduce_skill(u, sv, 1); days -= STUDYDAYS; } else { if (chance (days / ((double) STUDYDAYS * u->number))) /* (rng_int() % (30 * u->number) < days)*/ reduce_skill(u, sv, 1); days = 0; } } } }
static void godcurse(void) { region *r; for (r = regions; r; r = r->next) { if (is_cursed(r->attribs, C_CURSED_BY_THE_GODS, 0)) { unit *u; for (u = r->units; u; u = u->next) { skill *sv = u->skills; while (sv != u->skills + u->skill_size) { int weeks = 1 + rng_int() % 3; reduce_skill(u, sv, weeks); ++sv; } } if (fval(r->terrain, SEA_REGION)) { ship *sh; for (sh = r->ships; sh;) { ship *shn = sh->next; double dmg = config_get_flt("rules.ship.damage.godcurse", 0.1); damage_ship(sh, dmg); if (sh->damage >= sh->size * DAMAGE_SCALE) { unit *u = ship_owner(sh); if (u) ADDMSG(&u->faction->msgs, msg_message("godcurse_destroy_ship", "ship", sh)); remove_ship(&sh->region->ships, sh); } sh = shn; } } } } }
/** Talente von Dämonen verschieben sich. */ static void demon_skillchanges(void) { region *r; for (r = regions; r; r = r->next) { unit *u; for (u = r->units; u; u = u->next) { if (u_race(u) == get_race(RC_DAEMON)) { skill *sv = u->skills; int upchance = 15; int downchance = 10; if (fval(u, UFL_HUNGER)) { /* hungry demons only go down, never up in skill */ static int rule_hunger = -1; if (rule_hunger < 0) { rule_hunger = get_param_int(global.parameters, "hunger.demon.skill", 0); } if (rule_hunger) { upchance = 0; downchance = 15; } } while (sv != u->skills + u->skill_size) { int roll = rng_int() % 100; if (sv->level > 0 && roll < upchance + downchance) { int weeks = 1 + rng_int() % 3; if (roll < downchance) { reduce_skill(u, sv, weeks); if (sv->level < 1) { /* demons should never forget below 1 */ set_level(u, sv->id, 1); } } else { while (weeks--) learn_skill(u, sv->id, 1.0); } if (sv->old > sv->level) { if (verbosity >= 3) { log_printf(stdout, "%s dropped from %u to %u:%u in %s\n", unitname(u), sv->old, sv->level, sv->weeks, skillname(sv->id, NULL)); } } } ++sv; } } } } }
/** Talente von Daemonen verschieben sich. */ void demon_skillchange(unit *u) { skill *sv = u->skills; int upchance = 15, downchance = 10; static int config; static bool rule_hunger; static int cfgup, cfgdown; if (config_changed(&config)) { rule_hunger = config_get_int("hunger.demon.skills", 0) != 0; cfgup = config_get_int("skillchange.demon.up", 15); cfgdown = config_get_int("skillchange.demon.down", 10); } if (cfgup == 0) { /* feature is disabled */ return; } upchance = cfgup; downchance = cfgdown; if (fval(u, UFL_HUNGER)) { /* hungry demons only go down, never up in skill */ if (rule_hunger) { downchance = upchance; upchance = 0; } } while (sv != u->skills + u->skill_size) { int roll = rng_int() % 100; if (sv->level > 0 && roll < upchance + downchance) { int weeks = 1 + rng_int() % 3; if (roll < downchance) { reduce_skill(u, sv, weeks); if (sv->level < 1) { /* demons should never forget below 1 */ set_level(u, sv->id, 1); } } else { learn_skill(u, sv->id, STUDYDAYS * u->number * weeks); } } ++sv; } }
static int use_wand_of_tears(unit * user, const struct item_type *itype, int amount, order * ord) { int n; unused(ord); for (n = 0; n != amount; ++n) { unit *u; for (u = user->region->units; u; u = u->next) { if (u->faction != user->faction) { int i; for (i = 0; i != u->skill_size; ++i) { if (rng_int() % 3) reduce_skill(u, u->skills + i, 1); } ADDMSG(&u->faction->msgs, msg_message("wand_of_tears_effect", "unit", u)); } } } ADDMSG(&user->region->msgs, msg_message("wand_of_tears_usage", "unit", user)); return 0; }
static void do_shock(unit * u, const char *reason) { int i; if (u->number > 0) { /* HP - Verlust */ u->hp = (unit_max_hp(u) * u->number) / 10; u->hp = _max(1, u->hp); } /* Aura - Verlust */ if (is_mage(u)) { set_spellpoints(u, max_spellpoints(u->region, u) / 10); } /* Evt. Talenttageverlust */ for (i = 0; i != u->skill_size; ++i) if (rng_int() % 5 == 0) { skill *sv = u->skills + i; int weeks = (sv->level * sv->level - sv->level) / 2; int change = (weeks + 9) / 10; reduce_skill(u, sv, change); } /* Dies ist ein Hack, um das skillmod und familiar-Attribut beim Mage * zu löschen wenn der Familiar getötet wird. Da sollten wir über eine * saubere Implementation nachdenken. */ if (strcmp(reason, "trigger") == 0) { remove_familiar(u); } if (u->faction != NULL) { ADDMSG(&u->faction->msgs, msg_message("shock", "mage reason", u, _strdup(reason))); } }
/** 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; }