int unit_max_hp(const unit * u) { static int rules_stamina = -1; int h; double p; static const curse_type *heal_ct = NULL; if (rules_stamina < 0) { rules_stamina = get_param_int(global.parameters, "rules.stamina", STAMINA_AFFECTS_HP); } h = u_race(u)->hitpoints; if (heal_ct == NULL) heal_ct = ct_find("healingzone"); if (rules_stamina & 1) { p = pow(effskill(u, SK_STAMINA) / 2.0, 1.5) * 0.2; h += (int)(h * p + 0.5); } /* der healing curse verändert die maximalen hp */ if (heal_ct) { curse *c = get_curse(u->region->attribs, heal_ct); if (c) { h = (int)(h * (1.0 + (curse_geteffect(c) / 100))); } } return h; }
static int att_modification(const unit * u, skill_t sk) { double result = 0; static bool init = false; static const curse_type *skillmod_ct, *gbdream_ct, *worse_ct; curse *c; if (!init) { init = true; skillmod_ct = ct_find("skillmod"); gbdream_ct = ct_find("gbdream"); worse_ct = ct_find("worse"); } c = get_curse(u->attribs, worse_ct); if (c != NULL) result += curse_geteffect(c); if (skillmod_ct) { attrib *a = a_find(u->attribs, &at_curse); while (a && a->type == &at_curse) { curse *c = (curse *) a->data.v; if (c->type == skillmod_ct && c->data.i == sk) { result += curse_geteffect(c); break; } a = a->next; } } /* TODO hier kann nicht mit get/iscursed gearbeitet werden, da nur der * jeweils erste vom Typ C_GBDREAM zurückgegen wird, wir aber alle * durchsuchen und aufaddieren müssen */ if (u->region) { double bonus = 0, malus = 0; attrib *a = a_find(u->region->attribs, &at_curse); while (a && a->type == &at_curse) { curse *c = (curse *) a->data.v; if (curse_active(c) && c->type == gbdream_ct) { double mod = curse_geteffect(c); unit *mage = c->magician; /* wir suchen jeweils den größten Bonus und den größten Malus */ if (mod > bonus) { if (mage == NULL || mage->number == 0 || alliedunit(mage, u->faction, HELP_GUARD)) { bonus = mod; } } else if (mod < malus) { if (mage == NULL || !alliedunit(mage, u->faction, HELP_GUARD)) { malus = mod; } } } a = a->next; } result = result + bonus + malus; } return (int)result; }
int production(const region * r) { /* muß rterrain(r) sein, nicht rterrain() wegen rekursion */ int p = r->terrain->size; if (curse_active(get_curse(r->attribs, ct_find("drought")))) p /= 2; return p; }
/* ------------------------------------------------------------- */ static void set_curseingmagician(struct unit *magician, struct attrib *ap_target, const curse_type * ct) { curse *c = get_curse(ap_target, ct); if (c) { c->magician = magician; } }
bool is_cursed_internal(attrib * ap, const curse_type * ct) { curse *c = get_curse(ap, ct); if (!c) return false; return true; }
/* Mapperfunktion für das Anlegen neuer curse. Automatisch wird zum * passenden Typ verzweigt und die relevanten Variablen weitergegeben. */ curse *create_curse(unit * magician, attrib ** ap, const curse_type * ct, float vigour, int duration, float effect, int men) { curse *c; /* die Kraft eines Spruchs darf nicht 0 sein */ assert(vigour > 0); c = get_curse(*ap, ct); if (c && (c_flags(c) & CURSE_ONLYONE)) { return NULL; } assert(c == NULL || ct == c->type); /* es gibt schon eins diese Typs */ if (c && ct->mergeflags != NO_MERGE) { if (ct->mergeflags & M_DURATION) { c->duration = _max(c->duration, duration); } if (ct->mergeflags & M_SUMDURATION) { c->duration += duration; } if (ct->mergeflags & M_SUMEFFECT) { c->effect += effect; } if (ct->mergeflags & M_MAXEFFECT) { c->effect = _max(c->effect, effect); } if (ct->mergeflags & M_VIGOUR) { c->vigour = _max(vigour, c->vigour); } if (ct->mergeflags & M_VIGOUR_ADD) { c->vigour = vigour + c->vigour; } if (ct->mergeflags & M_MEN) { switch (ct->typ) { case CURSETYP_UNIT: { c->data.i += men; } } } set_curseingmagician(magician, *ap, ct); } else { c = make_curse(magician, ap, ct, vigour, duration, effect, men); } return c; }
/** 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))); } } } } }
bool can_survive(const unit * u, const region * r) { if ((fval(r->terrain, WALK_INTO) && (u_race(u)->flags & RCF_WALK)) || (fval(r->terrain, SWIM_INTO) && (u_race(u)->flags & RCF_SWIM)) || (fval(r->terrain, FLY_INTO) && (u_race(u)->flags & RCF_FLY))) { static const curse_type *ctype = NULL; if (has_horses(u) && !fval(r->terrain, WALK_INTO)) return false; if (!ctype) ctype = ct_find("holyground"); if (fval(u_race(u), RCF_UNDEAD) && curse_active(get_curse(r->attribs, ctype))) return false; return true; } return false; }
void deathcounts(region * r, int fallen) { attrib *a; static const curse_type *ctype = NULL; if (fallen == 0) return; if (!ctype) ctype = ct_find("holyground"); if (ctype && curse_active(get_curse(r->attribs, ctype))) return; a = a_find(r->attribs, &at_deathcount); if (!a) a = a_add(&r->attribs, a_new(&at_deathcount)); a->data.i += fallen; if (a->data.i <= 0) a_remove(&r->attribs, a); }
static curse *shipcurse_flyingship(ship * sh, unit * mage, double power, int duration) { curse *c; if (sh->attribs) { if (curse_active(get_curse(sh->attribs, &ct_flyingship))) { return NULL; } if (is_cursed(sh->attribs, &ct_shipspeedup)) { return NULL; } } /* mit C_SHIP_NODRIFT haben wir kein Problem */ c = create_curse(mage, &sh->attribs, &ct_flyingship, power, duration, 0.0, 0); if (c) { c->data.v = sh; if (c->duration > 0) { sh->flags |= SF_FLYING; } } return c; }
int shipspeed(const ship * sh, const unit * u) { attrib *a; struct curse *c; int k, bonus; assert(sh); if (!u) u = ship_owner(sh); if (!u) return 0; assert(u->ship == sh); assert(u == ship_owner(sh)); assert(sh->type->construction); k = sh->type->range; if (sh->size != sh->type->construction->maxsize) return 0; if (sh->attribs) { if (curse_active(get_curse(sh->attribs, &ct_stormwind))) { k *= 2; } if (curse_active(get_curse(sh->attribs, &ct_nodrift))) { k += 1; } } if (u->faction->race == u_race(u)) { /* race bonus for this faction? */ if (fval(u_race(u), RCF_SHIPSPEED)) { k += 1; } } bonus = ShipSpeedBonus(u); if (bonus > 0 && sh->type->range_max > sh->type->range) { int crew = crew_skill(sh); int crew_bonus = (crew / sh->type->sumskill / 2) - 1; if (crew_bonus > 0) { int sbonus = sh->type->range_max - sh->type->range; if (bonus > sbonus) bonus = sbonus; if (bonus > crew_bonus) bonus = crew_bonus; } else { bonus = 0; } } k += bonus; a = a_find(sh->attribs, &at_speedup); while (a != NULL && a->type == &at_speedup) { k += a->data.sa[0]; a = a->next; } c = get_curse(sh->attribs, &ct_shipspeedup); while (c) { k += curse_geteffect_int(c); c = c->nexthash; } if (sh->damage > 0) { int size = sh->size * DAMAGE_SCALE; k *= (size - sh->damage); k = (k + size - 1) / size; } return k; }
int teach_cmd(unit * teacher, struct order *ord) { plane *pl; region *r = teacher->region; skill_t sk_academy = NOSKILL; int teaching, i, j, count, academy_students = 0; if (r->attribs) { if (get_curse(r->attribs, &ct_gbdream)) { ADDMSG(&teacher->faction->msgs, msg_feedback(teacher, ord, "gbdream_noteach", "")); return 0; } } if ((u_race(teacher)->flags & RCF_NOTEACH) || fval(teacher, UFL_WERE)) { cmistake(teacher, ord, 274, MSG_EVENT); return 0; } pl = rplane(r); if (pl && fval(pl, PFL_NOTEACH)) { cmistake(teacher, ord, 273, MSG_EVENT); return 0; } teaching = teacher->number * TEACHNUMBER; if ((i = get_effect(teacher, oldpotiontype[P_FOOL])) > 0) { /* Trank "Dumpfbackenbrot" */ if (i > teaching) i = teaching; /* Trank wirkt pro Schueler, nicht pro Lehrer */ teaching -= i; change_effect(teacher, oldpotiontype[P_FOOL], -i); j = teaching; ADDMSG(&teacher->faction->msgs, msg_message("teachdumb", "teacher amount", teacher, j)); } if (teaching <= 0) return 0; count = 0; init_order_depr(ord); #if TEACH_ALL if (getparam(teacher->faction->locale) == P_ANY) { skill_t sk; unit *scholar; skill_t teachskill[MAXSKILLS]; int t = 0; do { sk = getskill(teacher->faction->locale); teachskill[t] = getskill(teacher->faction->locale); } while (sk != NOSKILL); for (scholar = r->units; teaching > 0 && scholar; scholar = scholar->next) { if (LongHunger(scholar)) { continue; } else if (scholar->faction == teacher->faction) { if (getkeyword(scholar->thisorder) == K_STUDY) { /* Input ist nun von student->thisorder !! */ init_order(scholar->thisorder, scholar->faction->locale); sk = getskill(scholar->faction->locale); if (sk != NOSKILL && teachskill[0] != NOSKILL) { for (t = 0; teachskill[t] != NOSKILL; ++t) { if (sk == teachskill[t]) { break; } } sk = teachskill[t]; } if (sk != NOSKILL && effskill_study(teacher, sk) - TEACHDIFFERENCE > effskill_study(scholar, sk)) { teaching -= teach_unit(teacher, scholar, teaching, sk, true, &academy_students); } } } #ifdef TEACH_FRIENDS else if (alliedunit(teacher, scholar->faction, HELP_GUARD)) { if (getkeyword(scholar->thisorder) == K_STUDY) { /* Input ist nun von student->thisorder !! */ init_order(scholar->thisorder, scholar->faction->locale); sk = getskill(scholar->faction->locale); if (sk != NOSKILL && effskill_study(teacher, sk) - TEACHDIFFERENCE >= effskill(scholar, sk, NULL)) { teaching -= teach_unit(teacher, scholar, teaching, sk, true, &academy_students); } } } #endif } } else #endif { char zOrder[4096]; size_t sz = sizeof(zOrder); order *new_order; zOrder[0] = '\0'; init_order_depr(ord); while (!parser_end()) { skill_t sk; unit *scholar; bool feedback; getunit(r, teacher->faction, &scholar); ++count; /* Falls die Unit nicht gefunden wird, Fehler melden */ if (!scholar) { char tbuf[20]; const char *uid; const char *token; /* Finde den string, der den Fehler verursacht hat */ parser_pushstate(); init_order_depr(ord); for (j = 0; j != count - 1; ++j) { /* skip over the first 'count' units */ getunit(r, teacher->faction, NULL); } token = getstrtoken(); /* Beginne die Fehlermeldung */ if (isparam(token, teacher->faction->locale, P_TEMP)) { token = getstrtoken(); sprintf(tbuf, "%s %s", LOC(teacher->faction->locale, parameters[P_TEMP]), token); uid = tbuf; } else { uid = token; } ADDMSG(&teacher->faction->msgs, msg_feedback(teacher, ord, "unitnotfound_id", "id", uid)); parser_popstate(); continue; } feedback = teacher->faction == scholar->faction || alliedunit(scholar, teacher->faction, HELP_GUARD); /* Neuen Befehl zusammenbauen. TEMP-Einheiten werden automatisch in * ihre neuen Nummern uebersetzt. */ if (zOrder[0]) { strncat(zOrder, " ", sz - 1); --sz; } sz -= str_strlcpy(zOrder + 4096 - sz, itoa36(scholar->no), sz); if (getkeyword(scholar->thisorder) != K_STUDY) { ADDMSG(&teacher->faction->msgs, msg_feedback(teacher, ord, "teach_nolearn", "student", scholar)); continue; } /* Input ist nun von student->thisorder !! */ parser_pushstate(); init_order(scholar->thisorder, scholar->faction->locale); sk = getskill(scholar->faction->locale); parser_popstate(); if (sk == NOSKILL) { ADDMSG(&teacher->faction->msgs, msg_feedback(teacher, ord, "teach_nolearn", "student", scholar)); continue; } if (effskill_study(scholar, sk) > effskill_study(teacher, sk) - TEACHDIFFERENCE) { if (feedback) { ADDMSG(&teacher->faction->msgs, msg_feedback(teacher, ord, "teach_asgood", "student", scholar)); } continue; } if (sk == SK_MAGIC) { /* ist der Magier schon spezialisiert, so versteht er nur noch * Lehrer seines Gebietes */ magic_t mage2 = unit_get_magic(scholar); if (mage2 != M_GRAY) { magic_t mage1 = unit_get_magic(teacher); if (mage1 != mage2) { if (feedback) { ADDMSG(&teacher->faction->msgs, msg_feedback(teacher, ord, "error_different_magic", "target", scholar)); } continue; } } } sk_academy = sk; teaching -= teach_unit(teacher, scholar, teaching, sk, false, &academy_students); } new_order = create_order(K_TEACH, teacher->faction->locale, "%s", zOrder); replace_order(&teacher->orders, ord, new_order); free_order(new_order); /* parse_order & set_order have each increased the refcount */ } if (academy_students > 0 && sk_academy!=NOSKILL) { academy_teaching_bonus(teacher, sk_academy, academy_students); } init_order_depr(NULL); return 0; }
/** Untote können entstehen */ void spawn_undead(void) { region *r; faction *monsters = get_monsters(); for (r = regions; r; r = r->next) { int unburied = deathcount(r); static const curse_type *ctype = NULL; if (!ctype) ctype = ct_find("holyground"); if (ctype && curse_active(get_curse(r->attribs, ctype))) continue; /* Chance 0.1% * chaosfactor */ if (r->land && unburied > r->land->peasants / 20 && rng_int() % 10000 < (100 + 100 * chaosfactor(r))) { message *msg; unit *u; /* es ist sinnfrei, wenn irgendwo im Wald 3er-Einheiten Untote entstehen. * Lieber sammeln lassen, bis sie mindestens 5% der Bevölkerung sind, und * dann erst auferstehen. */ int undead = unburied / (rng_int() % 2 + 1); const race *rc = NULL; int i; if (r->age < 100) undead = undead * r->age / 100; /* newbie-regionen kriegen weniger ab */ if (!undead || r->age < 20) continue; switch (rng_int() % 3) { case 0: rc = get_race(RC_SKELETON); break; case 1: rc = get_race(RC_ZOMBIE); break; default: rc = get_race(RC_GHOUL); break; } u = create_unit(r, monsters, undead, rc, 0, NULL, NULL); fset(u, UFL_ISNEW | UFL_MOVED); if ((rc == get_race(RC_SKELETON) || rc == get_race(RC_ZOMBIE)) && rng_int() % 10 < 4) { equip_unit(u, get_equipment("rising_undead")); } for (i = 0; i < MAXSKILLS; i++) { if (rc->bonus[i] >= 1) { set_level(u, (skill_t)i, 1); } } u->hp = unit_max_hp(u) * u->number; deathcounts(r, -undead); name_unit(u); log_debug("spawning %d %s in %s.\n", u->number, LOC(default_locale, rc_name_s(u_race(u), (u->number == 1) ? NAME_SINGULAR : NAME_PLURAL)), regionname(r, NULL)); msg = msg_message("undeadrise", "region", r); add_message(&r->msgs, msg); for (u = r->units; u; u = u->next) freset(u->faction, FFL_SELECT); for (u = r->units; u; u = u->next) { if (fval(u->faction, FFL_SELECT)) continue; fset(u->faction, FFL_SELECT); add_message(&u->faction->msgs, msg); } msg_release(msg); } else { int i = deathcount(r); if (i) { /* Gräber verwittern, 3% der Untoten finden die ewige Ruhe */ deathcounts(r, (int)(-i * 0.03)); } } } }
int shipspeed(const ship * sh, const unit * u) { int k = sh->type->range; static const struct curse_type *stormwind_ct, *nodrift_ct; static bool init; attrib *a; struct curse *c; int bonus; assert(sh); if (!u) u = ship_owner(sh); if (!u) return 0; assert(u->ship == sh); assert(u == ship_owner(sh)); assert(sh->type->construction); assert(sh->type->construction->improvement == NULL); /* sonst ist construction::size nicht ship_type::maxsize */ if (!init) { init = true; stormwind_ct = ct_find("stormwind"); nodrift_ct = ct_find("nodrift"); } if (sh->size != sh->type->construction->maxsize) return 0; if (curse_active(get_curse(sh->attribs, stormwind_ct))) k *= 2; if (curse_active(get_curse(sh->attribs, nodrift_ct))) k += 1; if (u->faction->race == u_race(u)) { /* race bonus for this faction? */ if (fval(u_race(u), RCF_SHIPSPEED)) { k += 1; } } bonus = ShipSpeedBonus(u); if (bonus > 0 && sh->type->range_max>sh->type->range) { int crew = crew_skill(sh); int crew_bonus = (crew / sh->type->sumskill / 2) - 1; if (crew_bonus > 0) { bonus = _min(bonus, crew_bonus); bonus = _min(bonus, sh->type->range_max - sh->type->range); } else { bonus = 0; } } k += bonus; a = a_find(sh->attribs, &at_speedup); while (a != NULL && a->type == &at_speedup) { k += a->data.sa[0]; a = a->next; } c = get_curse(sh->attribs, ct_find("shipspeedup")); while (c) { k += curse_geteffect_int(c); c = c->nexthash; } if (sh->damage>0) { int size = sh->size * DAMAGE_SCALE; k *= (size - sh->damage); k = (k + size - 1) / size; } return k; }
int teach_cmd(unit * u, struct order *ord) { static const curse_type *gbdream_ct = NULL; plane *pl; region *r = u->region; int teaching, i, j, count, academy = 0; skill_t sk = NOSKILL; if (gbdream_ct == 0) gbdream_ct = ct_find("gbdream"); if (gbdream_ct) { if (get_curse(u->region->attribs, gbdream_ct)) { ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "gbdream_noteach", "")); return 0; } } if ((u_race(u)->flags & RCF_NOTEACH) || fval(u, UFL_WERE)) { cmistake(u, ord, 274, MSG_EVENT); return 0; } pl = rplane(r); if (pl && fval(pl, PFL_NOTEACH)) { cmistake(u, ord, 273, MSG_EVENT); return 0; } teaching = u->number * 30 * TEACHNUMBER; if ((i = get_effect(u, oldpotiontype[P_FOOL])) > 0) { /* Trank "Dumpfbackenbrot" */ i = _min(i, u->number * TEACHNUMBER); /* Trank wirkt pro Schueler, nicht pro Lehrer */ teaching -= i * 30; change_effect(u, oldpotiontype[P_FOOL], -i); j = teaching / 30; ADDMSG(&u->faction->msgs, msg_message("teachdumb", "teacher amount", u, j)); } if (teaching == 0) return 0; count = 0; init_order(ord); #if TEACH_ALL if (getparam(u->faction->locale) == P_ANY) { unit *student = r->units; skill_t teachskill[MAXSKILLS]; int i = 0; do { sk = getskill(u->faction->locale); teachskill[i++] = sk; } while (sk != NOSKILL); while (teaching && student) { if (student->faction == u->faction) { if (LongHunger(student)) continue; if (getkeyword(student->thisorder) == K_STUDY) { /* Input ist nun von student->thisorder !! */ init_order(student->thisorder); sk = getskill(student->faction->locale); if (sk != NOSKILL && teachskill[0] != NOSKILL) { for (i = 0; teachskill[i] != NOSKILL; ++i) if (sk == teachskill[i]) break; sk = teachskill[i]; } if (sk != NOSKILL && eff_skill_study(u, sk, r) - TEACHDIFFERENCE > eff_skill_study(student, sk, r)) { teaching -= teach_unit(u, student, teaching, sk, true, &academy); } } } student = student->next; } #ifdef TEACH_FRIENDS while (teaching && student) { if (student->faction != u->faction && alliedunit(u, student->faction, HELP_GUARD)) { if (LongHunger(student)) continue; if (getkeyword(student->thisorder) == K_STUDY) { /* Input ist nun von student->thisorder !! */ init_order(student->thisorder); sk = getskill(student->faction->locale); if (sk != NOSKILL && eff_skill_study(u, sk, r) - TEACHDIFFERENCE >= eff_skill(student, sk, r)) { teaching -= teach_unit(u, student, teaching, sk, true, &academy); } } } student = student->next; } #endif } else #endif { char zOrder[4096]; order *new_order; zOrder[0] = '\0'; init_order(ord); while (!parser_end()) { unit *u2; bool feedback; getunit(r, u->faction, &u2); ++count; /* Falls die Unit nicht gefunden wird, Fehler melden */ if (!u2) { char tbuf[20]; const char *uid; const char *token; /* Finde den string, der den Fehler verursacht hat */ parser_pushstate(); init_order(ord); for (j = 0; j != count - 1; ++j) { /* skip over the first 'count' units */ getunit(r, u->faction, NULL); } token = getstrtoken(); /* Beginne die Fehlermeldung */ if (isparam(token, u->faction->locale, P_TEMP)) { token = getstrtoken(); sprintf(tbuf, "%s %s", LOC(u->faction->locale, parameters[P_TEMP]), token); uid = tbuf; } else { uid = token; } ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "unitnotfound_id", "id", uid)); parser_popstate(); continue; } feedback = u->faction == u2->faction || alliedunit(u2, u->faction, HELP_GUARD); /* Neuen Befehl zusammenbauen. TEMP-Einheiten werden automatisch in * ihre neuen Nummern uebersetzt. */ if (zOrder[0]) strcat(zOrder, " "); strcat(zOrder, unitid(u2)); if (getkeyword(u2->thisorder) != K_STUDY) { ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "teach_nolearn", "student", u2)); continue; } /* Input ist nun von u2->thisorder !! */ parser_pushstate(); init_order(u2->thisorder); sk = getskill(u2->faction->locale); parser_popstate(); if (sk == NOSKILL) { ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "teach_nolearn", "student", u2)); continue; } /* u is teacher, u2 is student */ if (eff_skill_study(u2, sk, r) > eff_skill_study(u, sk, r) - TEACHDIFFERENCE) { if (feedback) { ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "teach_asgood", "student", u2)); } continue; } if (sk == SK_MAGIC) { /* ist der Magier schon spezialisiert, so versteht er nur noch * Lehrer seines Gebietes */ sc_mage *mage1 = get_mage(u); sc_mage *mage2 = get_mage(u2); if (!mage2 || !mage1 || (mage2->magietyp != M_GRAY && mage1->magietyp != mage2->magietyp)) { if (feedback) { ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error_different_magic", "target", u2)); } continue; } } teaching -= teach_unit(u, u2, teaching, sk, false, &academy); } new_order = create_order(K_TEACH, u->faction->locale, "%s", zOrder); replace_order(&u->orders, ord, new_order); free_order(new_order); /* parse_order & set_order have each increased the refcount */ } if (academy && sk != NOSKILL) { academy = academy / 30; /* anzahl gelehrter wochen, max. 10 */ learn_skill(u, sk, academy / 30.0 / TEACHNUMBER); } return 0; }