Beispiel #1
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;
}
Beispiel #2
0
static int
useonother_trappedairelemental(struct unit *u, int shipId,
const struct item_type *itype, int amount, struct order *ord)
{
    curse *c;
    ship *sh;

    if (shipId <= 0) {
        cmistake(u, ord, 20, MSG_MOVE);
        return -1;
    }

    sh = findshipr(u->region, shipId);
    if (!sh) {
        cmistake(u, ord, 20, MSG_MOVE);
        return -1;
    }

    c =
        create_curse(u, &sh->attribs, ct_find("shipspeedup"), 20, INT_MAX, SPEEDUP,
        0);
    c_setflag(c, CURSE_NOAGE);

    ADDMSG(&u->faction->msgs, msg_message("trappedairelemental_success",
        "unit region command ship", u, u->region, ord, sh));

    use_pooled(u, itype->rtype, GET_DEFAULT, 1);

    return 0;
}
Beispiel #3
0
static bool validate_pirate(unit *u, order *ord) {
    if (!u->ship) {
        cmistake(u, ord, 144, MSG_MOVE);
        return false;
    }

    if (!u->ship || u != ship_owner(u->ship)) {
        cmistake(u, ord, 146, MSG_MOVE);
        return false;
    }
    return true;
}
Beispiel #4
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);
}
Beispiel #5
0
static void destroy_road(unit * u, int nmax, struct order *ord)
{
    char token[128];
    const char *s = gettoken(token, sizeof(token));
    direction_t d = s ? get_direction(s, u->faction->locale) : NODIRECTION;
    if (d == NODIRECTION) {
        /* Die Richtung wurde nicht erkannt */
        cmistake(u, ord, 71, MSG_PRODUCE);
    }
    else {
        unit *u2;
        region *r = u->region;
        short road, n = (short)nmax;

        if (nmax > SHRT_MAX) {
            n = SHRT_MAX;
        }
        else if (nmax < 0) {
            n = 0;
        }

        for (u2 = r->units; u2; u2 = u2->next) {
            if (u2->faction != u->faction && is_guard(u2, GUARD_TAX)
                && cansee(u2->faction, u->region, u, 0)
                && !alliedunit(u, u2->faction, HELP_GUARD)) {
                cmistake(u, ord, 70, MSG_EVENT);
                return;
            }
        }

        road = rroad(r, d);
        n = _min(n, road);
        if (n != 0) {
            region *r2 = rconnect(r, d);
            int willdo = eff_skill(u, SK_ROAD_BUILDING, r) * u->number;
            willdo = _min(willdo, n);
            if (willdo == 0) {
                /* TODO: error message */
            }
            if (willdo > SHRT_MAX)
                road = 0;
            else
                road = road - (short)willdo;
            rsetroad(r, d, road);
            ADDMSG(&u->faction->msgs, msg_message("destroy_road",
                "unit from to", u, r, r2));
        }
    }
}
Beispiel #6
0
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);
}
Beispiel #7
0
static int
use_museumexitticket(unit * u, const struct item_type *itype, int amount,
order * ord)
{
    attrib *a;
    region *r;
    unit *warden = findunit(atoi36("mwar"));
    int unit_cookie;

    unused_arg(amount);

    /* Prüfen ob in Eingangshalle */
    if (u->region->x != 9525 || u->region->y != 9525) {
        cmistake(u, ord, 266, MSG_MAGIC);
        return 0;
    }

    a = a_find(u->attribs, &at_museumexit);
    assert(a);
    r = findregion(a->data.sa[0], a->data.sa[1]);
    assert(r);
    a_remove(&u->attribs, a);
    /* Übergebene Gegenstände zurückgeben */

    a = a_find(u->attribs, &at_museumgivebackcookie);
    if (a) {
        unit_cookie = a->data.i;
        a_remove(&u->attribs, a);

        for (a = a_find(warden->attribs, &at_museumgiveback);
            a && a->type == &at_museumgiveback; a = a->next) {
            if (((museumgiveback *)(a->data.v))->cookie == unit_cookie)
                break;
        }
        if (a && a->type == &at_museumgiveback) {
            museumgiveback *gb = (museumgiveback *)(a->data.v);
            item *it;

            for (it = gb->items; it; it = it->next) {
                i_change(&u->items, it->type, it->number);
            }
            ADDMSG(&u->faction->msgs, msg_message("museumgiveback",
                "region unit sender items", r, u, warden, gb->items));
            a_remove(&warden->attribs, a);
        }
    }

    /* Benutzer zurück teleportieren */
    move_unit(u, r, NULL);

    /* Exitticket abziehen */
    i_change(&u->items, itype, -1);

    return 0;
}
Beispiel #8
0
static int
use_museumticket(unit * u, const struct item_type *itype, int amount,
order * ord)
{
    attrib *a;
    region *r = u->region;
    plane *pl = rplane(r);

    unused_arg(amount);

    /* Pruefen ob in normaler Plane und nur eine Person */
    if (pl != get_homeplane()) {
        cmistake(u, ord, 265, MSG_MAGIC);
        return 0;
    }
    if (u->number != 1) {
        cmistake(u, ord, 267, MSG_MAGIC);
        return 0;
    }
    if (has_horses(u)) {
        cmistake(u, ord, 272, MSG_MAGIC);
        return 0;
    }

    /* In diesem Attribut merken wir uns, wohin die Einheit zurückgesetzt
     * wird, wenn sie das Museum verläßt. */

    a = a_add(&u->attribs, a_new(&at_museumexit));
    a->data.sa[0] = (short)r->x;
    a->data.sa[1] = (short)r->y;

    /* Benutzer in die Halle teleportieren */
    move_unit(u, findregion(9525, 9525), NULL);

    /* Ticket abziehen */
    i_change(&u->items, itype, -1);

    /* Benutzer ein Exitticket geben */
    i_change(&u->items, itype, 1);

    return 0;
}
Beispiel #9
0
static int
use_trappedairelemental(struct unit *u,
const struct item_type *itype, int amount, struct order *ord)
{
    ship *sh = u->ship;

    if (sh == NULL) {
        cmistake(u, ord, 20, MSG_MOVE);
        return -1;
    }
    return useonother_trappedairelemental(u, sh->no, itype, amount, ord);
}
Beispiel #10
0
void herbsearch(region * r, unit * u, int max)
{
  int herbsfound;
  const item_type *whichherb;

  if (eff_skill(u, SK_HERBALISM, r) == 0) {
    cmistake(u, u->thisorder, 59, MSG_PRODUCE);
    return;
  }

  if (is_guarded(r, u, GUARD_PRODUCE)) {
    cmistake(u, u->thisorder, 70, MSG_EVENT);
    return;
  }

  whichherb = rherbtype(r);
  if (whichherb == NULL) {
    cmistake(u, u->thisorder, 108, MSG_PRODUCE);
    return;
  }

  if (max)
    max = _min(max, rherbs(r));
  else
    max = rherbs(r);
  herbsfound = ntimespprob(eff_skill(u, SK_HERBALISM, r) * u->number,
    (double)rherbs(r) / 100.0F, -0.01F);
  herbsfound = _min(herbsfound, max);
  rsetherbs(r, rherbs(r) - herbsfound);

  if (herbsfound) {
    produceexp(u, SK_HERBALISM, u->number);
    i_change(&u->items, whichherb, herbsfound);
    ADDMSG(&u->faction->msgs, msg_message("herbfound",
        "unit region amount herb", u, r, herbsfound, whichherb->rtype));
  } else {
    ADDMSG(&u->faction->msgs, msg_message("researchherb_none",
        "unit region", u, u->region));
  }
}
Beispiel #11
0
static int
teach_unit(unit * teacher, unit * scholar, int nteaching, skill_t sk,
    bool report, int *academy_students)
{
    teaching_info *teach = NULL;
    attrib *a;
    int students;

    if (magic_lowskill(scholar)) {
        cmistake(teacher, teacher->thisorder, 292, MSG_EVENT);
        return 0;
    }

    students = scholar->number;
    /* subtract already taught students */
    a = a_find(scholar->attribs, &at_learning);
    if (a != NULL) {
        teach = (teaching_info *)a->data.v;
        students -= teach->students;
    }

    if (students > nteaching) students = nteaching;

    if (students > 0) {
        if (teach == NULL) {
            a = a_add(&scholar->attribs, a_new(&at_learning));
            teach = (teaching_info *)a->data.v;
        }
        selist_push(&teach->teachers, teacher);
        teach->days += students * STUDYDAYS;
        teach->students += students; 

        if (scholar->building && teacher->building == scholar->building) {
            /* Solange Akademien groessenbeschraenkt sind, sollte Lehrer und
             * Student auch in unterschiedlichen Gebaeuden stehen duerfen */
            /* FIXME comment contradicts implementation */
            if (academy_can_teach(teacher, scholar, sk)) {
                /* Jeder Schueler zusaetzlich +10 Tage wenn in Uni. */
                teach->days += students * EXPERIENCEDAYS;  /* learning erhoehen */
                /* Lehrer zusaetzlich +1 Tag pro Schueler. */
                if (academy_students) {
                    *academy_students += students;
                }
            }
        }
    }
    return students;
}
Beispiel #12
0
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;
}
Beispiel #13
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;
}
Beispiel #14
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;
}
Beispiel #15
0
int destroy_cmd(unit * u, struct order *ord)
{
    char token[128];
    ship *sh;
    unit *u2;
    region *r = u->region;
    const construction *con = NULL;
    int size = 0;
    const char *s;
    int n = INT_MAX;

    if (u->number < 1)
        return 0;

    init_order(ord);
    s = gettoken(token, sizeof(token));

    if (findparam(s, u->faction->locale) == P_ROAD) {
        destroy_road(u, INT_MAX, ord);
        return 0;
    }

    if (s && *s) {
        n = atoi((const char *)s);
        if (n <= 0) {
            cmistake(u, ord, 288, MSG_PRODUCE);
            return 0;
        }
    }

    if (getparam(u->faction->locale) == P_ROAD) {
        destroy_road(u, n, ord);
        return 0;
    }

    if (u->building) {
        building *b = u->building;

        if (u != building_owner(b)) {
            cmistake(u, ord, 138, MSG_PRODUCE);
            return 0;
        }
        if (fval(b->type, BTF_INDESTRUCTIBLE)) {
            cmistake(u, ord, 138, MSG_PRODUCE);
            return 0;
        }
        if (n >= b->size) {
            /* destroy completly */
            /* all units leave the building */
            for (u2 = r->units; u2; u2 = u2->next) {
                if (u2->building == b) {
                    leave_building(u2);
                }
            }
            ADDMSG(&u->faction->msgs, msg_message("destroy", "building unit", b, u));
            con = b->type->construction;
            remove_building(&r->buildings, b);
        }
        else {
            /* partial destroy */
            b->size -= n;
            ADDMSG(&u->faction->msgs, msg_message("destroy_partial",
                "building unit", b, u));
        }
    }
    else if (u->ship) {
        sh = u->ship;

        if (u != ship_owner(sh)) {
            cmistake(u, ord, 138, MSG_PRODUCE);
            return 0;
        }
        if (fval(r->terrain, SEA_REGION)) {
            cmistake(u, ord, 14, MSG_EVENT);
            return 0;
        }

        if (n >= (sh->size * 100) / sh->type->construction->maxsize) {
            /* destroy completly */
            /* all units leave the ship */
            for (u2 = r->units; u2; u2 = u2->next) {
                if (u2->ship == sh) {
                    leave_ship(u2);
                }
            }
            ADDMSG(&u->faction->msgs, msg_message("shipdestroy",
                "unit region ship", u, r, sh));
            con = sh->type->construction;
            remove_ship(&sh->region->ships, sh);
        }
        else {
            /* partial destroy */
            sh->size -= (sh->type->construction->maxsize * n) / 100;
            ADDMSG(&u->faction->msgs, msg_message("shipdestroy_partial",
                "unit region ship", u, r, sh));
        }
    }
    else {
        cmistake(u, ord, 138, MSG_PRODUCE);
        return 0;
    }

    if (con) {
        /* TODO: Nicht an ZERSTÖRE mit Punktangabe angepaßt! */
        int c;
        for (c = 0; con->materials[c].number; ++c) {
            const requirement *rq = con->materials + c;
            int recycle = (rq->number * size / con->reqsize) / 2;
            if (recycle) {
                change_resource(u, rq->rtype, recycle);
            }
        }
    }
    return 0;
}
Beispiel #16
0
int
build_building(unit * u, const building_type * btype, int id, int want, order * ord)
{
    region *r = u->region;
    int n = want, built = 0;
    building *b = NULL;
    /* einmalige Korrektur */
    const char *btname;
    order *new_order = NULL;
    const struct locale *lang = u->faction->locale;
    static int rule_other = -1;

    assert(u->number);
    assert(btype->construction);
    if (eff_skill(u, SK_BUILDING, r) == 0) {
        cmistake(u, ord, 101, MSG_PRODUCE);
        return 0;
    }

    /* Falls eine Nummer angegeben worden ist, und ein Gebaeude mit der
     * betreffenden Nummer existiert, ist b nun gueltig. Wenn keine Burg
     * gefunden wurde, dann wird nicht einfach eine neue erbaut. Ansonsten
     * baut man an der eigenen burg weiter. */

    /* Wenn die angegebene Nummer falsch ist, KEINE Burg bauen! */
    if (id > 0) {                 /* eine Nummer angegeben, keine neue Burg bauen */
        b = findbuilding(id);
        if (!b || b->region != u->region) { /* eine Burg mit dieser Nummer gibt es hier nicht */
            /* vieleicht Tippfehler und die eigene Burg ist gemeint? */
            if (u->building && u->building->type == btype) {
                b = u->building;
            }
            else {
                /* keine neue Burg anfangen wenn eine Nummer angegeben war */
                cmistake(u, ord, 6, MSG_PRODUCE);
                return 0;
            }
        }
    }
    else if (u->building && u->building->type == btype) {
        b = u->building;
    }

    if (b)
        btype = b->type;

    if (fval(btype, BTF_UNIQUE) && buildingtype_exists(r, btype, false)) {
        /* only one of these per region */
        cmistake(u, ord, 93, MSG_PRODUCE);
        return 0;
    }
    if (besieged(u)) {
        /* units under siege can not build */
        cmistake(u, ord, 60, MSG_PRODUCE);
        return 0;
    }
    if (btype->flags & BTF_NOBUILD) {
        /* special building, cannot be built */
        cmistake(u, ord, 221, MSG_PRODUCE);
        return 0;
    }
    if ((r->terrain->flags & LAND_REGION) == 0) {
        /* special terrain, cannot build */
        cmistake(u, ord, 221, MSG_PRODUCE);
        return 0;
    }
    if (btype->flags & BTF_ONEPERTURN) {
        if (b && fval(b, BLD_EXPANDED)) {
            cmistake(u, ord, 318, MSG_PRODUCE);
            return 0;
        }
        n = 1;
    }
    if (b) {
        if (rule_other < 0) {
            rule_other =
                get_param_int(global.parameters, "rules.build.other_buildings", 1);
        }
        if (!rule_other) {
            unit *owner = building_owner(b);
            if (!owner || owner->faction != u->faction) {
                cmistake(u, ord, 1222, MSG_PRODUCE);
                return 0;
            }
        }
    }

    if (b)
        built = b->size;
    if (n <= 0 || n == INT_MAX) {
        if (b == NULL) {
            if (btype->maxsize > 0) {
                n = btype->maxsize - built;
            }
            else {
                n = INT_MAX;
            }
        }
        else {
            if (b->type->maxsize > 0) {
                n = b->type->maxsize - built;
            }
            else {
                n = INT_MAX;
            }
        }
    }
    built = build(u, btype->construction, built, n);

    switch (built) {
    case ECOMPLETE:
        /* the building is already complete */
        cmistake(u, ord, 4, MSG_PRODUCE);
        break;
    case ENOMATERIALS:
        ADDMSG(&u->faction->msgs, msg_materials_required(u, ord,
            btype->construction, want));
        break;
    case ELOWSKILL:
    case ENEEDSKILL:
        /* no skill, or not enough skill points to build */
        cmistake(u, ord, 50, MSG_PRODUCE);
        break;
    }
    if (built <= 0) {
        return built;
    }
    /* at this point, the building size is increased. */
    if (b == NULL) {
        /* build a new building */
        b = new_building(btype, r, lang);
        b->type = btype;
        fset(b, BLD_MAINTAINED | BLD_WORKING);

        /* Die Einheit befindet sich automatisch im Inneren der neuen Burg. */
        if (u->number && leave(u, false)) {
            u_set_building(u, b);
        }
    }

    btname = LOC(lang, btype->_name);

    if (want - built <= 0) {
        /* gebäude fertig */
        new_order = default_order(lang);
    }
    else if (want != INT_MAX) {
        /* reduzierte restgröße */
        const char *hasspace = strchr(btname, ' ');
        if (hasspace) {
            new_order =
                create_order(K_MAKE, lang, "%d \"%s\" %i", n - built, btname, b->no);
        }
        else {
            new_order =
                create_order(K_MAKE, lang, "%d %s %i", n - built, btname, b->no);
        }
    }
    else if (btname) {
        /* Neues Haus, Befehl mit Gebäudename */
        const char *hasspace = strchr(btname, ' ');
        if (hasspace) {
            new_order = create_order(K_MAKE, lang, "\"%s\" %i", btname, b->no);
        }
        else {
            new_order = create_order(K_MAKE, lang, "%s %i", btname, b->no);
        }
    }

    if (new_order) {
        replace_order(&u->orders, ord, new_order);
        free_order(new_order);
    }

    b->size += built;
    fset(b, BLD_EXPANDED);

    update_lighthouse(b);

    ADDMSG(&u->faction->msgs, msg_message("buildbuilding",
        "building unit size", b, u, built));
    return built;
}
Beispiel #17
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));
}
Beispiel #18
0
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;
}
Beispiel #19
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;
}
Beispiel #20
0
/* 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;
}
Beispiel #21
0
static int
teach_unit(unit * teacher, unit * student, int nteaching, skill_t sk,
bool report, int *academy)
{
    teaching_info *teach = NULL;
    attrib *a;
    int n;

    /* learning sind die Tage, die sie schon durch andere Lehrer zugute
     * geschrieben bekommen haben. Total darf dies nicht ueber 30 Tage pro Mann
     * steigen.
     *
     * n ist die Anzahl zusaetzlich gelernter Tage. n darf max. die Differenz
     * von schon gelernten Tagen zum _max(30 Tage pro Mann) betragen. */

    if (magic_lowskill(student)) {
        cmistake(teacher, teacher->thisorder, 292, MSG_EVENT);
        return 0;
    }

    n = 30 * student->number;
    a = a_find(student->attribs, &at_learning);
    if (a != NULL) {
        teach = (teaching_info *)a->data.v;
        n -= teach->value;
    }

    n = _min(n, nteaching);

    if (n != 0) {
        struct building *b = inside_building(teacher);
        const struct building_type *btype = b ? b->type : NULL;
        int index = 0;

        if (teach == NULL) {
            a = a_add(&student->attribs, a_new(&at_learning));
            teach = (teaching_info *)a->data.v;
        }
        else {
            while (teach->teachers[index] && index != MAXTEACHERS)
                ++index;
        }
        if (index < MAXTEACHERS)
            teach->teachers[index++] = teacher;
        if (index < MAXTEACHERS)
            teach->teachers[index] = NULL;
        teach->value += n;

        /* Solange Akademien groessenbeschraenkt sind, sollte Lehrer und
         * Student auch in unterschiedlichen Gebaeuden stehen duerfen */
        if (btype == bt_find("academy")
            && student->building && student->building->type == bt_find("academy")) {
            int j = study_cost(student, sk);
            j = _max(50, j * 2);
            /* kann Einheit das zahlen? */
            if (get_pooled(student, get_resourcetype(R_SILVER), GET_DEFAULT, j) >= j) {
                /* Jeder Schueler zusaetzlich +10 Tage wenn in Uni. */
                teach->value += (n / 30) * 10;  /* learning erhoehen */
                /* Lehrer zusaetzlich +1 Tag pro Schueler. */
                if (academy)
                    *academy += n;
            }                         /* sonst nehmen sie nicht am Unterricht teil */
        }

        /* Teaching ist die Anzahl Leute, denen man noch was beibringen kann. Da
         * hier nicht n verwendet wird, werden die Leute gezaehlt und nicht die
         * effektiv gelernten Tage. -> FALSCH ? (ENNO)
         *
         * Eine Einheit A von 11 Mann mit Talent 0 profitiert vom ersten Lehrer B
         * also 10x30=300 tage, und der zweite Lehrer C lehrt fuer nur noch 1x30=30
         * Tage (damit das Maximum von 11x30=330 nicht ueberschritten wird).
         *
         * Damit es aber in der Ausfuehrung nicht auf die Reihenfolge drauf ankommt,
         * darf der zweite Lehrer C keine weiteren Einheiten D mehr lehren. Also
         * wird student 30 Tage gutgeschrieben, aber teaching sinkt auf 0 (300-11x30 <=
         * 0).
         *
         * Sonst traete dies auf:
         *
         * A: lernt B: lehrt A C: lehrt A D D: lernt
         *
         * Wenn B vor C dran ist, lehrt C nur 30 Tage an A (wie oben) und
         * 270 Tage an D.
         *
         * Ist C aber vor B dran, lehrt C 300 tage an A, und 0 tage an D,
         * und B lehrt auch 0 tage an A.
         *
         * Deswegen darf C D nie lehren duerfen.
         *
         * -> Das ist wirr. wer hat das entworfen?
         * Besser waere, man macht erst vorab alle zuordnungen, und dann
         * die Talentaenderung (enno).
         */

        nteaching = _max(0, nteaching - student->number * 30);

    }
    return n;
}