/** ** GM: TELEPORT <unit> <x> <y> ** requires: permission-key "gmtele" **/ static void gm_teleport(const void *tnext, struct unit *u, struct order *ord) { const struct plane *p = rplane(u->region); unit *to = findunit(getid()); int x = rel_to_abs(p, u->faction, getint(), 0); int y = rel_to_abs(p, u->faction, getint(), 1); region *r = findregion(x, y); if (r == NULL || p != rplane(r)) { mistake(u, ord, "region is in another plane."); } else if (to == NULL) { ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", "")); } else if (rplane(to->region) != rplane(r) && !ucontact(to, u)) { ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_no_contact", "target", to)); } else { /* checking permissions */ attrib *permissions = a_find(u->faction->attribs, &at_permissions); if (!permissions || !has_permission(permissions, atoi36("gmtele"))) { mistake(u, ord, "permission denied."); } else move_unit(to, r, NULL); } }
/** ** GM: SKILL <unit> <skill> <tage> ** requires: permission-key "gmskil" **/ static void gm_skill(const void *tnext, struct unit *u, struct order *ord) { unit *to = findunit(getid()); skill_t skill = findskill(getstrtoken(), u->faction->locale); int num = getint(); if (to == NULL || rplane(to->region) != rplane(u->region)) { /* unknown or in another plane */ ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", "")); } else if (skill == NOSKILL || skill == SK_MAGIC || skill == SK_ALCHEMY) { /* unknown or not enough */ mistake(u, ord, "unknown skill, or skill cannot be raised."); } else if (num < 0 || num > 30) { /* sanity check failed */ mistake(u, ord, "invalid value."); } else { /* checking permissions */ attrib *permissions = a_find(u->faction->attribs, &at_permissions); if (!permissions || !has_permission(permissions, atoi36("gmskil"))) { mistake(u, ord, "permission denied."); } else { set_level(to, skill, num); } } }
static int give_igjarjuk(struct unit *src, struct unit *d, const struct item_type *itype, int n, struct order *ord) { ADDMSG(&src->faction->msgs, msg_feedback(src, ord, "error_giveeye", "")); return 0; }
static int use_speedsail(struct unit *u, const struct item_type *itype, int amount, struct order *ord) { struct plane *p = rplane(u->region); unused_arg(amount); unused_arg(itype); if (p != NULL) { ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "use_realworld_only", "")); } else { if (u->ship) { attrib *a = a_find(u->ship->attribs, &at_speedup); if (a == NULL) { a = a_add(&u->ship->attribs, a_new(&at_speedup)); a->data.sa[0] = 50; /* speed */ a->data.sa[1] = 50; /* decay */ ADDMSG(&u->faction->msgs, msg_message("use_speedsail", "unit", u)); /* Ticket abziehen */ i_change(&u->items, itype, -1); return 0; } else { cmistake(u, ord, 211, MSG_EVENT); } } else { cmistake(u, ord, 144, MSG_EVENT); } } return EUNUSABLE; }
static void mistake(const unit * u, struct order *ord, const char *comment) { if (!is_monsters(u->faction)) { ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "mistake", "error", comment)); } }
/** ** GM: TAKE <unit> <int> <itemtype> ** requires: permission-key "gmtake" **/ static void gm_take(const void *tnext, struct unit *u, struct order *ord) { unit *to = findunit(getid()); int num = getint(); const item_type *itype = finditemtype(getstrtoken(), u->faction->locale); if (to == NULL || rplane(to->region) != rplane(u->region)) { /* unknown or in another plane */ ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", "")); } else if (itype == NULL || i_get(to->items, itype) == 0) { /* unknown or not enough */ mistake(u, ord, "invalid item or item not found."); } else { /* checking permissions */ attrib *permissions = a_find(u->faction->attribs, &at_permissions); if (!permissions || !has_permission(permissions, atoi36("gmtake"))) { mistake(u, ord, "permission denied."); } else { int i = i_get(to->items, itype); if (i < num) num = i; if (num) { i_change(&to->items, itype, -num); i_change(&u->items, itype, num); } } } }
/** ** GM: TELL <unit> <string> ** requires: permission-key "gmmsgr" **/ static void gm_messageunit(const void *tnext, struct unit *u, struct order *ord) { const struct plane *p = rplane(u->region); unit *target = findunit(getid()); const char *msg = getstrtoken(); region *r; if (target == NULL) { ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", "")); return; } r = target->region; if (r == NULL || p != rplane(r)) { mistake(u, ord, "region is in another plane."); } else { /* checking permissions */ attrib *permissions = a_find(u->faction->attribs, &at_permissions); if (!permissions || !has_permission(permissions, atoi36("gmmsgu"))) { mistake(u, ord, "permission denied."); } else { add_message(&target->faction->msgs, msg_message("regionmessage", "region sender string", r, u, msg)); } } }
static int use_hornofdancing(struct unit *u, const struct item_type *itype, int amount, struct order *ord) { region *r; int regionsPacified = 0; for (r = regions; r; r = r->next) { if (distance(u->region, r) < HORNRANGE) { if (a_find(r->attribs, &at_peaceimmune) == NULL) { attrib *a; create_curse(u, &r->attribs, ct_find("peacezone"), 20, HORNDURATION, 1.0, 0); a = a_add(&r->attribs, a_new(&at_peaceimmune)); a->data.i = HORNIMMUNITY; ADDMSG(&r->msgs, msg_message("hornofpeace_r_success", "unit region", u, u->region)); regionsPacified++; } else { ADDMSG(&r->msgs, msg_message("hornofpeace_r_nosuccess", "unit region", u, u->region)); } } } if (regionsPacified > 0) { ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "hornofpeace_u_success", "pacified", regionsPacified)); } else { ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "hornofpeace_u_nosuccess", "")); } return 0; }
void create_ship(region * r, unit * u, const struct ship_type *newtype, int want, order * ord) { ship *sh; int msize; const construction *cons = newtype->construction; order *new_order; if (!eff_skill(u, SK_SHIPBUILDING, r)) { cmistake(u, ord, 100, MSG_PRODUCE); return; } if (besieged(u)) { cmistake(u, ord, 60, MSG_PRODUCE); return; } /* check if skill and material for 1 size is available */ if (eff_skill(u, cons->skill, r) < cons->minskill) { ADDMSG(&u->faction->msgs, msg_feedback(u, u->thisorder, "error_build_skill_low", "value", cons->minskill)); return; } msize = maxbuild(u, cons); if (msize == 0) { cmistake(u, ord, 88, MSG_PRODUCE); return; } if (want > 0) want = _min(want, msize); else want = msize; sh = new_ship(newtype, r, u->faction->locale); if (leave(u, false)) { if (fval(u_race(u), RCF_CANSAIL)) { u_set_ship(u, sh); } } new_order = create_order(K_MAKE, u->faction->locale, "%s %i", LOC(u->faction->locale, parameters[P_SHIP]), sh->no); replace_order(&u->orders, ord, new_order); free_order(new_order); build_ship(u, sh, want); }
static int summon_igjarjuk(struct unit *u, const struct item_type *itype, int amount, struct order *ord) { struct plane *p = rplane(u->region); unused_arg(amount); unused_arg(itype); if (p != NULL) { ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "use_realworld_only", "")); return EUNUSABLE; } else { assert(!"not implemented"); return EUNUSABLE; } }
static void test_noerror(CuTest *tc) { unit *u; struct locale *lang; message *msg; test_setup(); lang = test_create_locale(); u = test_create_unit(test_create_faction(NULL), test_create_region(0, 0, NULL)); u->thisorder = parse_order("!@move", lang); CuAssertIntEquals(tc, K_MOVE | CMD_QUIET | CMD_PERSIST, u->thisorder->command); CuAssertTrue(tc, !is_persistent(u->thisorder)); CuAssertPtrEquals(tc, NULL, msg = msg_error(u, u->thisorder, 100)); assert(!msg); CuAssertPtrEquals(tc, NULL, msg = msg_feedback(u, u->thisorder, "error_unit_not_found", NULL)); assert(!msg); test_teardown(); }
message *msg_materials_required(unit * u, order * ord, const construction * ctype, int multi) { int c; /* something missing from the list of materials */ resource *reslist = NULL; if (multi <= 0 || multi == INT_MAX) multi = 1; for (c = 0; ctype && ctype->materials[c].number; ++c) { resource *res = malloc(sizeof(resource)); res->number = multi * ctype->materials[c].number / ctype->reqsize; res->type = ctype->materials[c].rtype; res->next = reslist; reslist = res; } return msg_feedback(u, ord, "build_required", "required", reslist); }
void continue_ship(region * r, unit * u, int want) { const construction *cons; ship *sh; int msize; if (!eff_skill(u, SK_SHIPBUILDING, r)) { cmistake(u, u->thisorder, 100, MSG_PRODUCE); return; } /* Die Schiffsnummer bzw der Schiffstyp wird eingelesen */ sh = getship(r); if (!sh) sh = u->ship; if (!sh) { cmistake(u, u->thisorder, 20, MSG_PRODUCE); return; } cons = sh->type->construction; assert(cons->improvement == NULL); /* sonst ist construction::size nicht ship_type::maxsize */ if (sh->size == cons->maxsize && !sh->damage) { cmistake(u, u->thisorder, 16, MSG_PRODUCE); return; } if (eff_skill(u, cons->skill, r) < cons->minskill) { ADDMSG(&u->faction->msgs, msg_feedback(u, u->thisorder, "error_build_skill_low", "value", cons->minskill)); return; } msize = maxbuild(u, cons); if (msize == 0) { cmistake(u, u->thisorder, 88, MSG_PRODUCE); return; } if (want > 0) want = _min(want, msize); else want = msize; build_ship(u, sh, want); }
bool check_student(const struct unit *u, struct order *ord, skill_t sk) { int err = 0; const race *rc = u_race(u); if (sk < 0) { err = 77; } /* Hack: Talente mit Malus -99 koennen nicht gelernt werden */ else if (rc->bonus[sk] == -99) { err = 771; } else { static int config; static bool learn_newskills; if (config_changed(&config)) { learn_newskills = config_get_int("study.newskills", 1) != 0; } if (!learn_newskills) { skill *sv = unit_skill(u, sk); if (sv == NULL) { /* we can only learn skills we already have */ err = 771; } } } if (err) { if (ord) { cmistake(u, ord, err, MSG_EVENT); } return false; } if ((u_race(u)->flags & RCF_NOLEARN) || fval(u, UFL_WERE)) { if (ord) { ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error_race_nolearn", "race", u_race(u))); } return false; } return true; }
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; }
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; }
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; }
void build_road(region * r, unit * u, int size, direction_t d) { int n, left; region *rn = rconnect(r, d); assert(u->number); if (!eff_skill(u, SK_ROAD_BUILDING, r)) { cmistake(u, u->thisorder, 103, MSG_PRODUCE); return; } if (besieged(u)) { cmistake(u, u->thisorder, 60, MSG_PRODUCE); return; } if (rn == NULL || rn->terrain->max_road < 0) { cmistake(u, u->thisorder, 94, MSG_PRODUCE); return; } if (r->terrain->max_road < 0) { cmistake(u, u->thisorder, 94, MSG_PRODUCE); return; } if (r->terrain == newterrain(T_SWAMP)) { /* wenn kein Damm existiert */ const struct building_type *bt_dam = bt_find("dam"); if (!bt_dam || !buildingtype_exists(r, bt_dam, true)) { cmistake(u, u->thisorder, 132, MSG_PRODUCE); return; } } else if (r->terrain == newterrain(T_DESERT)) { const struct building_type *bt_caravan = bt_find("caravan"); /* wenn keine Karawanserei existiert */ if (!bt_caravan || !buildingtype_exists(r, bt_caravan, true)) { cmistake(u, u->thisorder, 133, MSG_PRODUCE); return; } } else if (r->terrain == newterrain(T_GLACIER)) { const struct building_type *bt_tunnel = bt_find("tunnel"); /* wenn kein Tunnel existiert */ if (!bt_tunnel || !buildingtype_exists(r, bt_tunnel, true)) { cmistake(u, u->thisorder, 131, MSG_PRODUCE); return; } } /* left kann man noch bauen */ left = r->terrain->max_road - rroad(r, d); /* hoffentlich ist r->road <= r->terrain->max_road, n also >= 0 */ if (left <= 0) { ADDMSG(&u->faction->msgs, msg_feedback(u, u->thisorder, "error_roads_finished", "")); return; } if (size > 0) left = _min(size, left); /* baumaximum anhand der rohstoffe */ if (u_race(u) == get_race(RC_STONEGOLEM)) { n = u->number * GOLEM_STONE; } else { n = get_pooled(u, get_resourcetype(R_STONE), GET_DEFAULT, left); if (n == 0) { cmistake(u, u->thisorder, 151, MSG_PRODUCE); return; } } left = _min(n, left); /* n = maximum by skill. try to maximize it */ n = u->number * eff_skill(u, SK_ROAD_BUILDING, r); if (n < left) { const resource_type *ring = get_resourcetype(R_RING_OF_NIMBLEFINGER); item *itm = ring ? *i_find(&u->items, ring->itype) : 0; if (itm != NULL && itm->number > 0) { int rings = _min(u->number, itm->number); n = n * ((roqf_factor() - 1) * rings + u->number) / u->number; } } if (n < left) { int dm = get_effect(u, oldpotiontype[P_DOMORE]); if (dm != 0) { int sk = eff_skill(u, SK_ROAD_BUILDING, r); int todo = (left - n + sk - 1) / sk; todo = _min(todo, u->number); dm = _min(dm, todo); change_effect(u, oldpotiontype[P_DOMORE], -dm); n += dm * sk; } /* Auswirkung Schaffenstrunk */ } /* make minimum of possible and available: */ n = _min(left, n); /* n is now modified by several special effects, so we have to * minimize it again to make sure the road will not grow beyond * maximum. */ rsetroad(r, d, rroad(r, d) + (short)n); if (u_race(u) == get_race(RC_STONEGOLEM)) { int golemsused = n / GOLEM_STONE; if (n % GOLEM_STONE != 0) { ++golemsused; } scale_number(u, u->number - golemsused); } else { use_pooled(u, get_resourcetype(R_STONE), GET_DEFAULT, n); /* Nur soviel PRODUCEEXP wie auch tatsaechlich gemacht wurde */ produceexp(u, SK_ROAD_BUILDING, _min(n, u->number)); } ADDMSG(&u->faction->msgs, msg_message("buildroad", "region unit size", r, u, n)); }
/* Name: Luftschiff * Stufe: 6 * * Wirkung: * Laesst ein Schiff eine Runde lang fliegen. Wirkt nur auf Boote * bis Kapazitaet 50. * Kombinierbar mit "Guenstige Winde", aber nicht mit "Sturmwind". * * Flag: * (ONSHIPCAST | SHIPSPELL | TESTRESISTANCE) */ int sp_flying_ship(castorder * co) { ship *sh; unit *u; region *r; unit *caster; int cast_level; double power; spellparameter *pa; message *m = NULL; int cno; assert(co); r = co_get_region(co); caster = co_get_caster(co); cast_level = co->level; power = co->force; pa = co->par; /* wenn kein Ziel gefunden, Zauber abbrechen */ if (pa->param[0]->flag == TARGET_NOTFOUND) return 0; sh = pa->param[0]->data.sh; if (sh->type->construction->maxsize > 50) { ADDMSG(&caster->faction->msgs, msg_feedback(caster, co->order, "error_flying_ship_too_big", "ship", sh)); return 0; } /* Duration = 1, nur diese Runde */ cno = levitate_ship(sh, caster, power, 1); if (cno == 0) { if (is_cursed(sh->attribs, &ct_flyingship)) { /* Auf dem Schiff befindet liegt bereits so ein Zauber. */ cmistake(caster, co->order, 211, MSG_MAGIC); } else if (is_cursed(sh->attribs, &ct_shipspeedup)) { /* Es ist zu gefaehrlich, ein sturmgepeitschtes Schiff fliegen zu lassen. */ cmistake(caster, co->order, 210, MSG_MAGIC); } return 0; } sh->coast = NODIRECTION; /* melden, 1x pro Partei */ for (u = r->units; u; u = u->next) u->faction->flags &= ~FFL_SELECT; for (u = r->units; u; u = u->next) { /* das sehen natuerlich auch die Leute an Land */ if (!(u->faction->flags & FFL_SELECT)) { u->faction->flags |= FFL_SELECT; if (!m) { m = msg_message("flying_ship_result", "mage ship", caster, sh); } add_message(&u->faction->msgs, m); } } if (m) { msg_release(m); } return cast_level; }
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; }