Esempio n. 1
0
  loop_char_skill_known(body, e) {
    parent = skill_school(e->skill);
    if (parent == e->skill)
      continue;

    if (has_skill(who, e->skill) || has_skill(who, parent) == 0)
      continue;

    if (rnd(1, 100) > chance)
      continue;

    learn_skill(who, e->skill);
  }
Esempio n. 2
0
static void
get_some_skills(int who, int body, int chance)
{
  struct skill_ent *e;
  int parent;

/*
 *  First do category skills
 */

  loop_char_skill_known(body, e) {
    parent = skill_school(e->skill);
    if (parent != e->skill)
      continue;

    if (has_skill(who, e->skill))
      continue;

    if (e->skill == sk_adv_sorcery)
      continue;

    /*
     *  Fri Sep 20 12:49:59 1996 -- Scott Turner
     *
     *  Can't learn religions by eating the dead!
     *
     */
    if (rp_relig_skill(e->skill))
      continue;

    if (rnd(1, 100) > chance)
      continue;

    learn_skill(who, e->skill);
  }
Esempio n. 3
0
void
alert_scry_attempt(int who, int where, char *t)
{
  int n;
  int has_detect;
  char *source;

  loop_char_here(where, n) {
    has_detect = has_skill(n, sk_detect_scry);

    if (has_detect > exp_novice)
      source = box_name(who);
    else
      source = "Someone";

    if (has_detect)
      wout(n, "%s%s cast %s on this location.",
           source, t, box_name(sk_scry_region));

    if (has_detect >= exp_master)
      wout(n, "%s is in %s.", box_name(who), char_rep_location(who));
/*
 *  If another exp gradient is wanted, use box_name for the loc,
 *  then graduate to char_rep_location, since the latter gives
 *  more info
 */

  }
Esempio n. 4
0
/** handles the "orcish" curse that makes units grow like old orks
 * This would probably be better handled in an age-function for the curse,
 * but it's now being called by randomevents()
 */
static void orc_growth(void)
{
  region *r;
  for (r = regions; r; r = r->next) {
    unit *u;
    for (u = r->units; u; u = u->next) {
      static bool init = false;
      static const curse_type *ct_orcish = 0;
      curse *c = 0;
      if (!init) {
        init = true;
        ct_orcish = ct_find("orcish");
      }
      if (ct_orcish)
        c = get_curse(u->attribs, ct_orcish);

      if (c && !has_skill(u, SK_MAGIC) && !has_skill(u, SK_ALCHEMY)
        && !fval(u, UFL_HERO)) {
        int n;
        int increase = 0;
        int num = get_cursedmen(u, c);
        double prob = curse_geteffect(c);
        const item_type * it_chastity = it_find("ao_chastity");

        if (it_chastity) {
            num -= i_get(u->items, it_chastity); 
        }
        for (n = num; n > 0; n--) {
          if (chance(prob)) {
            ++increase;
          }
        }
        if (increase) {
          unit *u2 = create_unit(r, u->faction, increase, u_race(u), 0, NULL, u);
          transfermen(u2, u, u2->number);

          ADDMSG(&u->faction->msgs, msg_message("orcgrowth",
              "unit amount race", u, increase, u_race(u)));
        }
      }
    }
  }
}
Esempio n. 5
0
static bool improve_all(faction * f, skill_t sk, int by_weeks)
{
    unit *u;
    bool result = false;
    for (u = f->units; u; u = u->nextF) {
        if (has_skill(u, sk)) {
            learn_skill(u, sk, by_weeks * STUDYDAYS);
            result = true;
        }
    }
    return result;
}
Esempio n. 6
0
int count_skill(faction * f, skill_t sk)
{
    int n = 0;
    unit *u;

    for (u = f->units; u; u = u->nextF) {
        if (has_skill(u, sk)) {
            if (!is_familiar(u)) {
                n += u->number;
            }
        }
    }
    return n;
}
Esempio n. 7
0
static int improve_all(faction * f, skill_t sk, int by_weeks)
{
  unit *u;
  bool ret = by_weeks;

  for (u = f->units; u; u = u->nextF) {
    if (has_skill(u, sk)) {
      int weeks = 0;
      for (; weeks != by_weeks; ++weeks) {
        learn_skill(u, sk, 1.0);
        ret = 0;
      }
    }
  }

  return ret;
}
Esempio n. 8
0
int
v_relore(struct command *c)
{
  int i;
  int skill = c->a;

  if (!valid_box(skill) || kind(skill) != T_skill) {
    wout(c->who, "%s is not a skill.", c->parse[1]);
    return FALSE;
  }

  loop_char(i) {
    if (has_skill(i, skill))
      queue_lore(i, skill, TRUE);
  }
  next_char;

  return TRUE;
}
int
d_view_aura(struct command *c)
{
	int n;
	int level;
	int first = TRUE;
	int aura = c->a;
	int where = c->d;
	char *s;
	int has_detect;
	int learned;
	char *source;

	if (!is_loc_or_ship(where))
	{
		wout(c->who, "%s is no longer a valid location.",
				box_code(where));
		return FALSE;
	}

	if (!charge_aura(c->who, aura))
		return FALSE;

	loop_char_here(where, n)
	{
		if (is_magician(n))
		{
/*
 *  Does the viewed magician have Detect ability scry?
 */

			level = char_cur_aura(n);

			if (aura <= char_abil_shroud(n))
			{
				s = "???";
				learned = FALSE;
			}
			else
			{
				s = sout("%d", level);
				learned = TRUE;
			}

			wout(c->who, "%s, current aura: %s", box_name(n), s);
			first = FALSE;

			has_detect = has_skill(n, sk_detect_abil);

			if (has_detect > exp_novice)
				source = box_name(c->who);
			else
				source = "Someone";

			if (has_detect)
				wout(n, "%s cast View aura here.", source);

			if (has_detect > exp_journeyman)
			{
			    if (learned)
			       wout(n, "Our current aura rating was learned.");
			    else
			       wout(n, "Our current aura rating was "
							"not revealed.");
			}
		}
	}
	next_char_here;

	if (first)
	{
		wout(c->who, "No mages are seen here.");
		log_output(LOG_CODE, "d_view_aura: not a mage?\n");
	}

	return TRUE;
}
Esempio n. 10
0
int
d_reveal_mage(struct command *c)
{
	int target = c->a;
	int category = c->b;
	int aura = c->c;
	int has_detect;
	char *source;

	if (!charge_aura(c->who, aura))
		return FALSE;

	assert(valid_box(category));
	assert(skill_school(category) == category && magic_skill(category));

	has_detect = has_skill(target, sk_detect_abil);

	if (has_detect > exp_novice)
		source = box_name(c->who);
	else
		source = "Someone";

	if (aura <= char_abil_shroud(target))
	{
		wout(c->who, "The abilities of %s are shrouded from "
				"your scry.", box_name(target));

		if (has_detect)
			wout(target, "%s cast %s on us, but failed to learn "
				"anything.", source, box_name(sk_reveal_mage));

		if (has_detect > exp_teacher)
			wout(target, "They sought to learn what we "
					"know of %s.", box_name(category));

		return FALSE;
	}

	{
		int first = TRUE;
		struct skill_ent *e;

		loop_char_skill_known(target, e)
		{
			if (skill_school(e->skill) != category ||
			    e->skill == category)
				continue;

			if (first)
			{
				wout(c->who, "%s knows the following "
						"%s spells:",
						box_name(target),
						box_name(category));
				indent += 3;
				first = FALSE;
			}

			if (c->use_exp > exp_journeyman)
				list_skill_sup(c->who, e);
			else
				wout(c->who, "%s", box_name(e->skill));
		}
		next_char_skill_known;

		if (first)
			wout(c->who, "%s knowns no %s spells.",
					box_name(target), box_name(category));
		else
			indent -= 3;

	}

	if (has_detect)
	{
		wout(target, "%s successfully cast %s on us.",
			source, box_name(sk_reveal_mage));

		if (has_detect > exp_teacher)
			wout(target, "Our knowledge of %s was revealed.",
					box_name(category));
	}

	return TRUE;
}
Esempio n. 11
0
/*
 *  Wed Mar  5 12:14:55 1997 -- Scott Turner
 *
 *  Added hooks for npc_breed, which is used by the NPC chars.
 *
 */
int
v_breed(struct command *c)
{
  int i1 = c->a;
  int i2 = c->b;
  int exp;

  if (is_real_npc(c->who)) {
    c->wait += 7;
    return TRUE;
  };

  if (!has_skill(c->who, sk_breed_beasts))
    {
      wout(c->who, "Requires %s.", box_name(sk_breed_beasts));
      return FALSE;
    }
  c->use_skill = sk_breed_beasts;

  if (numargs(c) < 2)
    {
      wout(c->who, "Usage: breed <item> <item>");
      return FALSE;
    }

  if (kind(i1) != T_item)
    {
      wout(c->who, "%s is not an item.", c->parse[1]);
      return FALSE;
    }

  if (kind(i2) != T_item)
    {
      wout(c->who, "%s is not an item.", c->parse[2]);
      return FALSE;
    }

  if (has_item(c->who, i1) < 1)
    {
      wout(c->who, "Don't have any %s.", box_code(i1));
      return FALSE;
    }

  if (has_item(c->who, i2) < 1)
    {
      wout(c->who, "Don't have any %s.", box_code(i2));
      return FALSE;
    }

  if (i1 == i2 && has_item(c->who, i1) < 2)
    {
      wout(c->who, "Don't have two %s.", box_code(i1));
      return FALSE;
    }

  /*
   *  Thu Oct 10 12:15:09 1996 -- Scott Turner
   *
   *  May need a holy symbol & piety.
   *
   */
  if (!normal_union(i1, i2)) {
    if (!has_holy_symbol(c->who)) {
      wout(c->who, "A holy symbol is required for that breeding.");
      return FALSE;
    };

    if (!has_piety(c->who, skill_piety(c->use_skill))) {
      wout(c->who, "You don't have the piety required to use that prayer.");
      return FALSE;
    };
  };

  /* 
   *  Hack to fold experience_use_speedup into this skill
   *  if they use BREED instead of USE xxxx
   */

  c->wait = 7;
  exp = max(has_skill(c->who, sk_breed_beasts) - 1, 0);
  if (exp)
    c->wait--;

  return TRUE;
}
Esempio n. 12
0
int study_cmd(unit * u, order * ord)
{
    region *r = u->region;
    int p;
    int l;
    int studycost, days;
    double multi = 1.0;
    attrib *a = NULL;
    teaching_info *teach = NULL;
    int money = 0;
    skill_t sk;
    int maxalchemy = 0;
    int speed_rule = (study_rule_t)config_get_int("study.speedup", 0);
    static const race *rc_snotling;
    static int rc_cache;

    if (rc_changed(&rc_cache)) {
        rc_snotling = get_race(RC_SNOTLING);
    }

    (void)init_order(ord, u->faction->locale);
    sk = getskill(u->faction->locale);

    if (!check_student(u, ord, sk)) {
        return -1;
    }

    /* snotlings koennen Talente nur bis T8 lernen */
    if (u_race(u) == rc_snotling) {
        if (get_level(u, sk) >= 8) {
            cmistake(u, ord, 308, MSG_EVENT);
            return -1;
        }
    }

    p = studycost = study_cost(u, sk);
    a = a_find(u->attribs, &at_learning);
    if (a != NULL) {
        teach = (teaching_info *)a->data.v;
    }

    /* keine kostenpflichtigen Talente fuer Migranten. Vertraute sind
     * keine Migranten, wird in is_migrant abgefangen. Vorsicht,
     * studycost darf hier noch nicht durch Akademie erhoeht sein */
    if (studycost > 0 && !ExpensiveMigrants() && is_migrant(u)) {
        ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error_migrants_nolearn",
            ""));
        return -1;
    }
    /* Akademie: */
    if (active_building(u, bt_find("academy"))) {
        studycost = studycost * 2;
        if (studycost < 50) studycost = 50;
    }

    if (sk == SK_MAGIC) {
        magic_t mtype;
        if (u->number > 1) {
            cmistake(u, ord, 106, MSG_MAGIC);
            return -1;
        }
        if (is_familiar(u)) {
            /* Vertraute zaehlen nicht zu den Magiern einer Partei,
             * koennen aber nur Graue Magie lernen */
            mtype = M_GRAY;
        }
        else if (!has_skill(u, SK_MAGIC)) {
            int mmax = faction_skill_limit(u->faction, SK_MAGIC);
            /* Die Einheit ist noch kein Magier */
            if (faction_count_skill(u->faction, SK_MAGIC) + u->number > mmax) {
                ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error_max_magicians",
                    "amount", mmax));
                return -1;
            }
            mtype = getmagicskill(u->faction->locale);
            if (mtype == M_NONE || mtype == M_GRAY) {
                /* wurde kein Magiegebiet angegeben, wird davon
                 * ausgegangen, dass das normal gelernt werden soll */
                if (u->faction->magiegebiet != 0) {
                    mtype = u->faction->magiegebiet;
                }
                else {
                    /* Es wurde kein Magiegebiet angegeben und die Partei
                     * hat noch keins gewaehlt. */
                    mtype = getmagicskill(u->faction->locale);
                    if (mtype == M_NONE) {
                        cmistake(u, ord, 178, MSG_MAGIC);
                        return -1;
                    }
                }
            }
            if (mtype != u->faction->magiegebiet) {
                /* Es wurde versucht, ein anderes Magiegebiet zu lernen
                 * als das der Partei */
                if (u->faction->magiegebiet != 0) {
                    cmistake(u, ord, 179, MSG_MAGIC);
                    return -1;
                }
                else {
                    /* Lernt zum ersten mal Magie und legt damit das
                     * Magiegebiet der Partei fest */
                    u->faction->magiegebiet = mtype;
                }
            }
            create_mage(u, mtype);
        }
        else {
            /* ist schon ein Magier und kein Vertrauter */
            if (u->faction->magiegebiet == 0) {
                /* die Partei hat noch kein Magiegebiet gewaehlt. */
                mtype = getmagicskill(u->faction->locale);
                if (mtype == M_NONE) {
                    mtype = getmagicskill(u->faction->locale);
                    if (mtype == M_NONE) {
                        cmistake(u, ord, 178, MSG_MAGIC);
                        return -1;
                    }
                }
                /* Legt damit das Magiegebiet der Partei fest */
                u->faction->magiegebiet = mtype;
            }
        }
    }
    if (sk == SK_ALCHEMY) {
        maxalchemy = effskill(u, SK_ALCHEMY, NULL);
        if (!has_skill(u, SK_ALCHEMY)) {
            int amax = faction_skill_limit(u->faction, SK_ALCHEMY);
            if (faction_count_skill(u->faction, SK_ALCHEMY) + u->number > amax) {
                ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error_max_alchemists",
                    "amount", amax));
                return -1;
            }
        }
    }
    if (studycost) {
        int cost = studycost * u->number;
        money = get_pooled(u, get_resourcetype(R_SILVER), GET_DEFAULT, cost);
        if (money > cost) money = cost;
    }
    if (money < studycost * u->number) {
        studycost = p;              /* Ohne Univertreurung */
        if (money > studycost) money = studycost;
        if (p > 0 && money < studycost * u->number) {
            cmistake(u, ord, 65, MSG_EVENT);
            multi = money / (double)(studycost * u->number);
        }
    }

    if (teach == NULL) {
        a = a_add(&u->attribs, a_new(&at_learning));
        teach = (teaching_info *)a->data.v;
        assert(teach);
        teach->teachers = NULL;
    }
    if (money > 0) {
        use_pooled(u, get_resourcetype(R_SILVER), GET_DEFAULT, money);
        ADDMSG(&u->faction->msgs, msg_message("studycost",
            "unit region cost skill", u, u->region, money, sk));
    }

    if (get_effect(u, oldpotiontype[P_WISE])) {
        l = get_effect(u, oldpotiontype[P_WISE]);
        if (l > u->number) l = u->number;
        teach->days += l * EXPERIENCEDAYS;
        change_effect(u, oldpotiontype[P_WISE], -l);
    }
    if (get_effect(u, oldpotiontype[P_FOOL])) {
        l = get_effect(u, oldpotiontype[P_FOOL]);
        if (l > u->number) l = u->number;
        teach->days -= l * STUDYDAYS;
        change_effect(u, oldpotiontype[P_FOOL], -l);
    }

    if (p != studycost) {
        /* ist_in_gebaeude(r, u, BT_UNIVERSITAET) == 1) { */
        /* p ist Kosten ohne Uni, studycost mit; wenn
         * p!=studycost, ist die Einheit zwangsweise
         * in einer Uni */
        teach->days += u->number * EXPERIENCEDAYS;
    }

    if (is_cursed(r->attribs, &ct_badlearn)) {
        teach->days -= u->number * EXPERIENCEDAYS;
    }

    multi *= study_speedup(u, sk, speed_rule);
    days = study_days(u, sk);
    days = (int)((days + teach->days) * multi);

    /* the artacademy currently improves the learning of entertainment
       of all units in the region, to be able to make it cumulative with
       with an academy */

    if (sk == SK_ENTERTAINMENT
        && buildingtype_exists(r, bt_find("artacademy"), false)) {
        days *= 2;
    }

    learn_skill(u, sk, days);
    if (a != NULL) {
        if (teach->teachers) {
            msg_teachers(teach->teachers, u, sk);
        }
        a_remove(&u->attribs, a);
        a = NULL;
    }
    u->flags |= (UFL_LONGACTION | UFL_NOTMOVING);

    /* Anzeigen neuer Traenke */
    /* Spruchlistenaktualiesierung ist in Regeneration */

    if (sk == SK_ALCHEMY) {
        faction *f = u->faction;
        int skill = effskill(u, SK_ALCHEMY, NULL);
        if (skill > maxalchemy) {
            show_potions(f, skill);
        }
    }
    init_order(NULL, NULL);
    return 0;
}
Esempio n. 13
0
	int32_t Skillbook::get_masterlevel(int32_t id) const
	{
		return has_skill(id) ? skillentries.at(id).masterlevel : 0;
	}
Esempio n. 14
0
int learn_cmd(unit * u, order * ord)
{
    region *r = u->region;
    int p;
    magic_t mtyp;
    int l;
    int studycost, days;
    double multi = 1.0;
    attrib *a = NULL;
    teaching_info *teach = NULL;
    int money = 0;
    skill_t sk;
    int maxalchemy = 0;
    int speed_rule = (study_rule_t)get_param_int(global.parameters, "study.speedup", 0);
    static int learn_newskills = -1;
    if (learn_newskills < 0) {
        const char *str = get_param(global.parameters, "study.newskills");
        if (str && strcmp(str, "false") == 0)
            learn_newskills = 0;
        else
            learn_newskills = 1;
    }
    if (!unit_can_study(u)) {
        ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error_race_nolearn", "race",
            u_race(u)));
        return 0;
    }

    init_order(ord);
    sk = getskill(u->faction->locale);

    if (sk < 0) {
        cmistake(u, ord, 77, MSG_EVENT);
        return 0;
    }
    if (SkillCap(sk) && SkillCap(sk) <= effskill(u, sk)) {
        cmistake(u, ord, 771, MSG_EVENT);
        return 0;
    }
    /* Hack: Talente mit Malus -99 koennen nicht gelernt werden */
    if (u_race(u)->bonus[sk] == -99) {
        cmistake(u, ord, 771, MSG_EVENT);
        return 0;
    }
    if (learn_newskills == 0) {
        skill *sv = unit_skill(u, sk);
        if (sv == NULL) {
            /* we can only learn skills we already have */
            cmistake(u, ord, 771, MSG_EVENT);
            return 0;
        }
    }

    /* snotlings koennen Talente nur bis T8 lernen */
    if (u_race(u) == get_race(RC_SNOTLING)) {
        if (get_level(u, sk) >= 8) {
            cmistake(u, ord, 308, MSG_EVENT);
            return 0;
        }
    }

    p = studycost = study_cost(u, sk);
    a = a_find(u->attribs, &at_learning);
    if (a != NULL) {
        teach = (teaching_info *)a->data.v;
    }

    /* keine kostenpflichtigen Talente fuer Migranten. Vertraute sind
     * keine Migranten, wird in is_migrant abgefangen. Vorsicht,
     * studycost darf hier noch nicht durch Akademie erhoeht sein */
    if (studycost > 0 && !ExpensiveMigrants() && is_migrant(u)) {
        ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error_migrants_nolearn",
            ""));
        return 0;
    }
    /* Akademie: */
  {
      struct building *b = inside_building(u);
      const struct building_type *btype = b ? b->type : NULL;

      if (btype && btype == bt_find("academy")) {
          studycost = _max(50, studycost * 2);
      }
  }

  if (sk == SK_MAGIC) {
      if (u->number > 1) {
          cmistake(u, ord, 106, MSG_MAGIC);
          return 0;
      }
      if (is_familiar(u)) {
          /* Vertraute zaehlen nicht zu den Magiern einer Partei,
           * koennen aber nur Graue Magie lernen */
          mtyp = M_GRAY;
          if (!is_mage(u))
              create_mage(u, mtyp);
      }
      else if (!has_skill(u, SK_MAGIC)) {
          int mmax = skill_limit(u->faction, SK_MAGIC);
          /* Die Einheit ist noch kein Magier */
          if (count_skill(u->faction, SK_MAGIC) + u->number > mmax) {
              ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error_max_magicians",
                  "amount", mmax));
              return 0;
          }
          mtyp = getmagicskill(u->faction->locale);
          if (mtyp == M_NONE || mtyp == M_GRAY) {
              /* wurde kein Magiegebiet angegeben, wird davon
               * ausgegangen, dass das normal gelernt werden soll */
              if (u->faction->magiegebiet != 0) {
                  mtyp = u->faction->magiegebiet;
              }
              else {
                  /* Es wurde kein Magiegebiet angegeben und die Partei
                   * hat noch keins gewaehlt. */
                  mtyp = getmagicskill(u->faction->locale);
                  if (mtyp == M_NONE) {
                      cmistake(u, ord, 178, MSG_MAGIC);
                      return 0;
                  }
              }
          }
          if (mtyp != u->faction->magiegebiet) {
              /* Es wurde versucht, ein anderes Magiegebiet zu lernen
               * als das der Partei */
              if (u->faction->magiegebiet != 0) {
                  cmistake(u, ord, 179, MSG_MAGIC);
                  return 0;
              }
              else {
                  /* Lernt zum ersten mal Magie und legt damit das
                   * Magiegebiet der Partei fest */
                  u->faction->magiegebiet = mtyp;
              }
          }
          if (!is_mage(u))
              create_mage(u, mtyp);
      }
      else {
          /* ist schon ein Magier und kein Vertrauter */
          if (u->faction->magiegebiet == 0) {
              /* die Partei hat noch kein Magiegebiet gewaehlt. */
              mtyp = getmagicskill(u->faction->locale);
              if (mtyp == M_NONE) {
                  mtyp = getmagicskill(u->faction->locale);
                  if (mtyp == M_NONE) {
                      cmistake(u, ord, 178, MSG_MAGIC);
                      return 0;
                  }
              }
              /* Legt damit das Magiegebiet der Partei fest */
              u->faction->magiegebiet = mtyp;
          }
      }
  }
  if (sk == SK_ALCHEMY) {
      maxalchemy = eff_skill(u, SK_ALCHEMY, r);
      if (!has_skill(u, SK_ALCHEMY)) {
          int amax = skill_limit(u->faction, SK_ALCHEMY);
          if (count_skill(u->faction, SK_ALCHEMY) + u->number > amax) {
              ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error_max_alchemists",
                  "amount", amax));
              return 0;
          }
      }
  }
  if (studycost) {
      int cost = studycost * u->number;
      money = get_pooled(u, get_resourcetype(R_SILVER), GET_DEFAULT, cost);
      money = _min(money, cost);
  }
  if (money < studycost * u->number) {
      studycost = p;              /* Ohne Univertreurung */
      money = _min(money, studycost);
      if (p > 0 && money < studycost * u->number) {
          cmistake(u, ord, 65, MSG_EVENT);
          multi = money / (double)(studycost * u->number);
      }
  }

  if (teach == NULL) {
      a = a_add(&u->attribs, a_new(&at_learning));
      teach = (teaching_info *)a->data.v;
      teach->teachers[0] = 0;
  }
  if (money > 0) {
      use_pooled(u, get_resourcetype(R_SILVER), GET_DEFAULT, money);
      ADDMSG(&u->faction->msgs, msg_message("studycost",
          "unit region cost skill", u, u->region, money, sk));
  }

  if (get_effect(u, oldpotiontype[P_WISE])) {
      l = _min(u->number, get_effect(u, oldpotiontype[P_WISE]));
      teach->value += l * 10;
      change_effect(u, oldpotiontype[P_WISE], -l);
  }
  if (get_effect(u, oldpotiontype[P_FOOL])) {
      l = _min(u->number, get_effect(u, oldpotiontype[P_FOOL]));
      teach->value -= l * 30;
      change_effect(u, oldpotiontype[P_FOOL], -l);
  }

  if (p != studycost) {
      /* ist_in_gebaeude(r, u, BT_UNIVERSITAET) == 1) { */
      /* p ist Kosten ohne Uni, studycost mit; wenn
       * p!=studycost, ist die Einheit zwangsweise
       * in einer Uni */
      teach->value += u->number * 10;
  }

  if (is_cursed(r->attribs, C_BADLEARN, 0)) {
      teach->value -= u->number * 10;
  }

  multi *= study_speedup(u, sk, speed_rule);
  days = study_days(u, sk);
  days = (int)((days + teach->value) * multi);

  /* the artacademy currently improves the learning of entertainment
     of all units in the region, to be able to make it cumulative with
     with an academy */

  if (sk == SK_ENTERTAINMENT
      && buildingtype_exists(r, bt_find("artacademy"), false)) {
      days *= 2;
  }

  if (fval(u, UFL_HUNGER))
      days /= 2;

  while (days) {
      if (days >= u->number * 30) {
          learn_skill(u, sk, 1.0);
          days -= u->number * 30;
      }
      else {
          double chance = (double)days / u->number / 30;
          learn_skill(u, sk, chance);
          days = 0;
      }
  }
  if (a != NULL) {
      if (teach != NULL) {
          int index = 0;
          while (teach->teachers[index] && index != MAXTEACHERS) {
              unit *teacher = teach->teachers[index++];
              if (teacher->faction != u->faction) {
                  bool feedback = alliedunit(u, teacher->faction, HELP_GUARD);
                  if (feedback) {
                      ADDMSG(&teacher->faction->msgs, msg_message("teach_teacher",
                          "teacher student skill level", teacher, u, sk,
                          effskill(u, sk)));
                  }
                  ADDMSG(&u->faction->msgs, msg_message("teach_student",
                      "teacher student skill", teacher, u, sk));
              }
          }
      }
      a_remove(&u->attribs, a);
      a = NULL;
  }
  fset(u, UFL_LONGACTION | UFL_NOTMOVING);

  /* Anzeigen neuer Traenke */
  /* Spruchlistenaktualiesierung ist in Regeneration */

  if (sk == SK_ALCHEMY) {
      const potion_type *ptype;
      faction *f = u->faction;
      int skill = eff_skill(u, SK_ALCHEMY, r);
      if (skill > maxalchemy) {
          for (ptype = potiontypes; ptype; ptype = ptype->next) {
              if (skill == ptype->level * 2) {
                  attrib *a = a_find(f->attribs, &at_showitem);
                  while (a && a->type == &at_showitem && a->data.v != ptype)
                      a = a->next;
                  if (a == NULL || a->type != &at_showitem) {
                      a = a_add(&f->attribs, a_new(&at_showitem));
                      a->data.v = (void *)ptype->itype;
                  }
              }
          }
      }
  }
  else if (sk == SK_MAGIC) {
      sc_mage *mage = get_mage(u);
      if (!mage) {
          mage = create_mage(u, u->faction->magiegebiet);
      }
  }

  return 0;
}