Exemple #1
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;
}
Exemple #2
0
/** Spells: chaosrow / song of confusion.
 * German Title: 'Gesang der Verwirrung'
 */
int sp_chaosrow(struct castorder * co)
{
    fighter * fi = co->magician.fig;
    int level = co->level;
    double power = co->force;
    const spell * sp = co->sp;
    battle *b = fi->side->battle;
    unit *mage = fi->unit;
    selist *fgs, *ql;
    message *m;
    const char *mtype;
    int qi, k = 0;
    bool chaosrow = strcmp(sp->sname, "chaosrow") == 0;

    if (!count_enemies(b, fi, FIGHT_ROW, NUMROWS, SELECT_ADVANCE | SELECT_FIND)) {
        m = msg_message("spell_out_of_range", "mage spell", fi->unit, sp);
        message_all(b, m);
        msg_release(m);
        return 0;
    }

    power = chaosrow ? (power * 40) : get_force(power, 5);

    fgs = select_fighters(b, fi->side, FS_ENEMY, select_alive, NULL);
    scramble_fighters(fgs);

    for (qi = 0, ql = fgs; ql; selist_advance(&ql, &qi, 1)) {
        fighter *df = (fighter *)selist_get(ql, qi);
        int n = df->unit->number;

        if (df->alive == 0)
            continue;
        if (power <= 0.0)
            break;

        if (is_magic_resistant(mage, df->unit, 0))
            continue;

        if (chance(power / n)) {
            int row = statusrow(df->status);
            df->side->size[row] -= df->alive;
            if (u_race(df->unit)->battle_flags & BF_NOBLOCK) {
                df->side->nonblockers[row] -= df->alive;
            }
            row = FIRST_ROW + (rng_int() % (NUMROWS - FIRST_ROW));
            switch (row) {
            case FIGHT_ROW:
                df->status = ST_FIGHT;
                break;
            case BEHIND_ROW:
                df->status = ST_CHICKEN;
                break;
            case AVOID_ROW:
                df->status = ST_AVOID;
                break;
            case FLEE_ROW:
                df->status = ST_FLEE;
                break;
            default:
                assert(!"unknown combatrow");
            }
            assert(statusrow(df->status) == row);
            df->side->size[row] += df->alive;
            if (u_race(df->unit)->battle_flags & BF_NOBLOCK) {
                df->side->nonblockers[row] += df->alive;
            }
            k += df->alive;
        }
        power = fmax(0, power - n);
    }
    selist_free(fgs);

    if (chaosrow) {
        mtype = (k > 0) ? "sp_chaosrow_effect_1" : "sp_chaosrow_effect_0";
    }
    else {
        mtype = (k > 0) ? "sp_confusion_effect_1" : "sp_confusion_effect_0";
    }
    m = msg_message(mtype, "mage", mage);
    message_all(b, m);
    msg_release(m);
    return level;
}
Exemple #3
0
/** Untote können entstehen */
void spawn_undead(void)
{
    region *r;
    faction *monsters = get_monsters();

    for (r = regions; r; r = r->next) {
        int unburied = deathcount(r);
        static const curse_type *ctype = NULL;

        if (!ctype)
            ctype = ct_find("holyground");
        if (ctype && curse_active(get_curse(r->attribs, ctype)))
            continue;

        /* Chance 0.1% * chaosfactor */
        if (r->land && unburied > r->land->peasants / 20
            && rng_int() % 10000 < (100 + 100 * chaosfactor(r))) {
            message *msg;
            unit *u;
            /* es ist sinnfrei, wenn irgendwo im Wald 3er-Einheiten Untote entstehen.
             * Lieber sammeln lassen, bis sie mindestens 5% der Bevölkerung sind, und
             * dann erst auferstehen. */
            int undead = unburied / (rng_int() % 2 + 1);
            const race *rc = NULL;
            int i;
            if (r->age < 100)
                undead = undead * r->age / 100; /* newbie-regionen kriegen weniger ab */

            if (!undead || r->age < 20)
                continue;

            switch (rng_int() % 3) {
            case 0:
                rc = get_race(RC_SKELETON);
                break;
            case 1:
                rc = get_race(RC_ZOMBIE);
                break;
            default:
                rc = get_race(RC_GHOUL);
                break;
            }

            u = create_unit(r, monsters, undead, rc, 0, NULL, NULL);
            fset(u, UFL_ISNEW | UFL_MOVED);
            if ((rc == get_race(RC_SKELETON) || rc == get_race(RC_ZOMBIE))
                && rng_int() % 10 < 4) {
                equip_unit(u, get_equipment("rising_undead"));
            }

            for (i = 0; i < MAXSKILLS; i++) {
                if (rc->bonus[i] >= 1) {
                    set_level(u, (skill_t)i, 1);
                }
            }
            u->hp = unit_max_hp(u) * u->number;

            deathcounts(r, -undead);
            name_unit(u);

            log_debug("spawning %d %s in %s.\n", u->number,
                LOC(default_locale,
                rc_name_s(u_race(u), (u->number == 1) ? NAME_SINGULAR : NAME_PLURAL)), regionname(r, NULL));
          msg = msg_message("undeadrise", "region", r);
          add_message(&r->msgs, msg);
          for (u = r->units; u; u = u->next)
              freset(u->faction, FFL_SELECT);
          for (u = r->units; u; u = u->next) {
              if (fval(u->faction, FFL_SELECT))
                  continue;
              fset(u->faction, FFL_SELECT);
              add_message(&u->faction->msgs, msg);
          }
          msg_release(msg);
        }
        else {
            int i = deathcount(r);
            if (i) {
                /* Gräber verwittern, 3% der Untoten finden die ewige Ruhe */
                deathcounts(r, (int)(-i * 0.03));
            }
        }
    }
}
Exemple #4
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;
}
Exemple #5
0
int shipspeed(const ship * sh, const unit * u)
{
    int k = sh->type->range;
    static const struct curse_type *stormwind_ct, *nodrift_ct;
    static bool init;
    attrib *a;
    struct curse *c;
    int bonus;

    assert(sh);
    if (!u) u = ship_owner(sh);
    if (!u) return 0;
    assert(u->ship == sh);
    assert(u == ship_owner(sh));
    assert(sh->type->construction);
    assert(sh->type->construction->improvement == NULL);  /* sonst ist construction::size nicht ship_type::maxsize */

    if (!init) {
        init = true;
        stormwind_ct = ct_find("stormwind");
        nodrift_ct = ct_find("nodrift");
    }
    if (sh->size != sh->type->construction->maxsize)
        return 0;

    if (curse_active(get_curse(sh->attribs, stormwind_ct)))
        k *= 2;
    if (curse_active(get_curse(sh->attribs, nodrift_ct)))
        k += 1;

    if (u->faction->race == u_race(u)) {
        /* race bonus for this faction? */
        if (fval(u_race(u), RCF_SHIPSPEED)) {
            k += 1;
        }
    }

    bonus = ShipSpeedBonus(u);
    if (bonus > 0 && sh->type->range_max>sh->type->range) {
        int crew = crew_skill(sh);
        int crew_bonus = (crew / sh->type->sumskill / 2) - 1;
        if (crew_bonus > 0) {
            bonus = _min(bonus, crew_bonus);
            bonus = _min(bonus, sh->type->range_max - sh->type->range);
        }
        else {
            bonus = 0;
        }
    }
    k += bonus;

    a = a_find(sh->attribs, &at_speedup);
    while (a != NULL && a->type == &at_speedup) {
        k += a->data.sa[0];
        a = a->next;
    }

    c = get_curse(sh->attribs, ct_find("shipspeedup"));
    while (c) {
        k += curse_geteffect_int(c);
        c = c->nexthash;
    }

    if (sh->damage>0) {
        int size = sh->size * DAMAGE_SCALE;
        k *= (size - sh->damage);
        k = (k + size - 1) / size;
    }
    return k;
}
Exemple #6
0
static order *plan_dragon(unit * u)
{
    attrib *ta = a_find(u->attribs, &at_targetregion);
    region *r = u->region;
    region *tr = NULL;
    bool move = false;
    order *long_order = NULL;

    if (ta == NULL) {
        move |= (r->land == 0 || r->land->peasants == 0);   /* when no peasants, move */
        move |= (r->land == 0 || r->land->money == 0);      /* when no money, move */
    }
    move |= chance(0.04);         /* 4% chance to change your mind */

    if (u_race(u) == get_race(RC_WYRM) && !move) {
        unit *u2;
        for (u2 = r->units; u2; u2 = u2->next) {
            /* wyrme sind einzelgänger */
            if (u2 == u) {
                /* we do not make room for newcomers, so we don't need to look at them */
                break;
            }
            if (u2 != u && u_race(u2) == u_race(u) && chance(0.5)) {
                move = true;
                break;
            }
        }
    }

    if (move) {
        /* dragon gets bored and looks for a different place to go */
        ta = set_new_dragon_target(u, u->region, DRAGON_RANGE);
    }
    else
        ta = a_find(u->attribs, &at_targetregion);
    if (ta != NULL) {
        tr = (region *)ta->data.v;
        if (tr == NULL || !path_exists(u->region, tr, DRAGON_RANGE, allowed_dragon)) {
            ta = set_new_dragon_target(u, u->region, DRAGON_RANGE);
            if (ta)
                tr = findregion(ta->data.sa[0], ta->data.sa[1]);
        }
    }
    if (tr != NULL) {
        assert(long_order == NULL);
        switch (old_race(u_race(u))) {
        case RC_FIREDRAGON:
            long_order = make_movement_order(u, tr, 4, allowed_dragon);
            break;
        case RC_DRAGON:
            long_order = make_movement_order(u, tr, 3, allowed_dragon);
            break;
        case RC_WYRM:
            long_order = make_movement_order(u, tr, 1, allowed_dragon);
            break;
        default:
            break;
        }
        if (long_order) {
            reduce_weight(u);
        }
        if (rng_int() % 100 < 15) {
            const struct locale *lang = u->faction->locale;
            /* do a growl */
            if (rname(tr, lang)) {
                addlist(&u->orders,
                    create_order(K_MAIL, lang, "%s '%s... %s %s %s'",
                    LOC(lang, parameters[P_REGION]),
                    random_growl(),
                    u->number ==
                    1 ? "Ich rieche" : "Wir riechen",
                    "etwas in", rname(tr, u->faction->locale)));
            }
        }
    }
    else {
        /* we have no target. do we like it here, then? */
        long_order = get_money_for_dragon(u->region, u, income(u));
        if (long_order == NULL) {
            /* money is gone, need a new target */
            set_new_dragon_target(u, u->region, DRAGON_RANGE);
        }
        else if (u_race(u) != get_race(RC_FIREDRAGON)) {
            /* neue dracoiden! */
            if (r->land && !fval(r->terrain, FORBIDDEN_REGION)) {
                int ra = 20 + rng_int() % 100;
                if (get_money(u) > ra * 50 + 100 && rng_int() % 100 < 50) {
                    recruit_dracoids(u, ra);
                }
            }
        }
    }
    if (long_order == NULL) {
        skill_t sk = SK_PERCEPTION;
        /* study perception (or a random useful skill) */
        while (!skill_enabled(sk) || u_race(u)->bonus[sk] < -5) {
            sk = (skill_t)(rng_int() % MAXSKILLS);
        }
        long_order = create_order(K_STUDY, u->faction->locale, "'%s'",
            skillname(sk, u->faction->locale));
    }
    return long_order;
}
Exemple #7
0
void get_food(region * r)
{
    plane *pl = rplane(r);
    unit *u;
    int peasantfood = rpeasants(r) * 10;
    static int food_rules = -1;
    static int gamecookie = -1;

    if (food_rules < 0 || gamecookie != global.cookie) {
        gamecookie = global.cookie;
        food_rules = get_param_int(global.parameters, "rules.economy.food", 0);
    }

    if (food_rules & FOOD_IS_FREE) {
        return;
    }
    /* 1. Versorgung von eigenen Einheiten. Das vorhandene Silber
    * wird zunächst so auf die Einheiten aufgeteilt, dass idealerweise
    * jede Einheit genug Silber für ihren Unterhalt hat. */

    for (u = r->units; u; u = u->next) {
        int need = lifestyle(u);

        /* Erstmal zurücksetzen */
        freset(u, UFL_HUNGER);

        if (u->ship && (u->ship->flags & SF_FISHING)) {
            unit *v;
            int c = 2;
            for (v = u; c > 0 && v; v = v->next) {
                if (v->ship == u->ship) {
                    int get = 0;
                    if (v->number <= c) {
                        get = lifestyle(v);
                    }
                    else {
                        get = lifestyle(v) * c / v->number;
                    }
                    if (get) {
                        change_money(v, get);
                    }
                }
                c -= v->number;
            }
            u->ship->flags -= SF_FISHING;
        }

        if (food_rules & FOOD_FROM_PEASANTS) {
            struct faction *owner = region_get_owner(r);
            /* if the region is owned, and the owner is nice, then we'll get
            * food from the peasants - should not be used with WORK */
            if (owner != NULL && (get_alliance(owner, u->faction) & HELP_MONEY)) {
                int rm = rmoney(r);
                int use = _min(rm, need);
                rsetmoney(r, rm - use);
                need -= use;
            }
        }

        need -= get_money(u);
        if (need > 0) {
            unit *v;

            for (v = r->units; need && v; v = v->next) {
                if (v->faction == u->faction && help_money(v)) {
                    int give = get_money(v) - lifestyle(v);
                    give = _min(need, give);
                    if (give > 0) {
                        change_money(v, -give);
                        change_money(u, give);
                        need -= give;
                    }
                }
            }
        }
    }

    /* 2. Versorgung durch Fremde. Das Silber alliierter Einheiten wird
    * entsprechend verteilt. */
    for (u = r->units; u; u = u->next) {
        int need = lifestyle(u);
        faction *f = u->faction;

        need -= _max(0, get_money(u));

        if (need > 0) {
            unit *v;

            if (food_rules & FOOD_FROM_OWNER) {
                /* the owner of the region is the first faction to help out when you're hungry */
                faction *owner = region_get_owner(r);
                if (owner && owner != u->faction) {
                    for (v = r->units; v; v = v->next) {
                        if (v->faction == owner && alliedunit(v, f, HELP_MONEY)
                            && help_money(v)) {
                            help_feed(v, u, &need);
                            break;
                        }
                    }
                }
            }
            for (v = r->units; need && v; v = v->next) {
                if (v->faction != f && alliedunit(v, f, HELP_MONEY)
                    && help_money(v)) {
                    help_feed(v, u, &need);
                }
            }

            /* Die Einheit hat nicht genug Geld zusammengekratzt und
            * nimmt Schaden: */
            if (need > 0) {
                int lspp = lifestyle(u) / u->number;
                if (lspp > 0) {
                    int number = (need + lspp - 1) / lspp;
                    if (hunger(number, u))
                        fset(u, UFL_HUNGER);
                }
            }
        }
    }

    /* 3. bestimmen, wie viele Bauern gefressen werden.
    * bei fehlenden Bauern den Dämon hungern lassen
    */
    for (u = r->units; u; u = u->next) {
        if (u_race(u) == get_race(RC_DAEMON)) {
            int hungry = u->number;

            /* use peasantblood before eating the peasants themselves */
            const struct potion_type *pt_blood = 0;
            const resource_type *rt_blood = rt_find("peasantblood");
            if (rt_blood) {
                pt_blood = rt_blood->ptype;
            }
            if (pt_blood) {
                /* always start with the unit itself, then the first known unit that may have some blood */
                unit *donor = u;
                while (donor != NULL && hungry > 0) {
                    int blut = get_effect(donor, pt_blood);
                    blut = _min(blut, hungry);
                    if (blut) {
                        change_effect(donor, pt_blood, -blut);
                        hungry -= blut;
                    }
                    if (donor == u)
                        donor = r->units;
                    while (donor != NULL) {
                        if (u_race(donor) == get_race(RC_DAEMON) && donor != u) {
                            if (get_effect(donor, pt_blood)) {
                                /* if he's in our faction, drain him: */
                                if (donor->faction == u->faction)
                                    break;
                            }
                        }
                        donor = donor->next;
                    }
                }
            }
            /* remaining demons feed on peasants */
            if (pl == NULL || !fval(pl, PFL_NOFEED)) {
                if (peasantfood >= hungry) {
                    peasantfood -= hungry;
                    hungry = 0;
                }
                else {
                    hungry -= peasantfood;
                    peasantfood = 0;
                }
                if (hungry > 0) {
                    static int demon_hunger = -1;
                    if (demon_hunger < 0) {
                        demon_hunger = get_param_int(global.parameters, "hunger.demons", 0);
                    }
                    if (demon_hunger == 0) {
                        /* demons who don't feed are hungry */
                        if (hunger(hungry, u))
                            fset(u, UFL_HUNGER);
                    }
                    else {
                        /* no damage, but set the hungry-flag */
                        fset(u, UFL_HUNGER);
                    }
                }
            }
        }
    }
    rsetpeasants(r, peasantfood / 10);

    /* 3. Von den überlebenden das Geld abziehen: */
    for (u = r->units; u; u = u->next) {
        int need = _min(get_money(u), lifestyle(u));
        change_money(u, -need);
    }
}
Exemple #8
0
static int
damage_unit(unit * u, const char *dam, bool physical, bool magic)
{
    int *hp, hpstack[20];
    int h;
    int i, dead = 0, hp_rem = 0, heiltrank;
    double magres = magic_resistance(u);

    assert(u->number);
    if (fval(u_race(u), RCF_ILLUSIONARY) || u_race(u) == get_race(RC_SPELL)) {
        return 0;
    }

    assert(u->number <= u->hp);
    h = u->hp / u->number;
    /* HP verteilen */
    if (u->number < 20) {
        hp = hpstack;
    }
    else {
        hp = malloc(u->number * sizeof(int));
    }
    for (i = 0; i < u->number; i++)
        hp[i] = h;
    h = u->hp - (u->number * h);
    for (i = 0; i < h; i++)
        hp[i]++;

    /* Schaden */
    for (i = 0; i < u->number; i++) {
        int damage = dice_rand(dam);
        if (magic)
            damage = (int)(damage * (1.0 - magres));
        if (physical)
            damage -= nb_armor(u, i);
        hp[i] -= damage;
    }

    /* Auswirkungen */
    for (i = 0; i < u->number; i++) {
        if (hp[i] <= 0) {
            heiltrank = 0;

            /* Sieben Leben */
            if (old_race(u_race(u)) == RC_CAT && (chance(1.0 / 7))) {
                hp[i] = u->hp / u->number;
                hp_rem += hp[i];
                continue;
            }

            /* Heiltrank */
            if (oldpotiontype[P_HEAL]) {
                if (get_effect(u, oldpotiontype[P_HEAL]) > 0) {
                    change_effect(u, oldpotiontype[P_HEAL], -1);
                    heiltrank = 1;
                }
                else if (i_get(u->items, oldpotiontype[P_HEAL]->itype) > 0) {
                    i_change(&u->items, oldpotiontype[P_HEAL]->itype, -1);
                    change_effect(u, oldpotiontype[P_HEAL], 3);
                    heiltrank = 1;
                }
                if (heiltrank && (chance(0.50))) {
                    hp[i] = u->hp / u->number;
                    hp_rem += hp[i];
                    continue;
                }
            }
            dead++;
        }
        else {
            hp_rem += hp[i];
        }
    }

    scale_number(u, u->number - dead);
    u->hp = hp_rem;

    if (hp != hpstack) {
        free(hp);
    }

    return dead;
}
Exemple #9
0
/** A mind blast spell for monsters.
 * This spell PERMANENTLY reduces the skill of the victims or kills them
 * when they have no skills left. Not currently in use.
 */
int sp_mindblast(struct castorder * co)
{
    fighter * fi = co->magician.fig;
    int level = co->level;
    double power = co->force;
    const spell * sp = co->sp;
    battle *b = fi->side->battle;
    unit *mage = fi->unit;
    int killed = 0, k = 0, reset = 0;
    message *m;
    int force = lovar(power * 25);
    int enemies = count_enemies(b, fi, FIGHT_ROW, BEHIND_ROW, SELECT_ADVANCE);

    if (!enemies) {
        m = msg_message("battle::out_of_range", "mage spell", fi->unit, sp);
        message_all(b, m);
        msg_release(m);
        return 0;
    }

    while (enemies > 0 && force > 0) {
        unit *du;
        troop dt = select_enemy(fi, FIGHT_ROW, BEHIND_ROW, SELECT_ADVANCE);

        assert(dt.fighter);
        du = dt.fighter->unit;
        if (du->flags & UFL_MARK) {
            /* not this one again */
            continue;
        }

        if (humanoidrace(u_race(du)) && force >= du->number) {
            if (!is_magic_resistant(mage, du, 0)) {
                skill_t sk = random_skill(du, false);
                if (sk != NOSKILL) {
                    skill *sv = unit_skill(du, sk);
                    if (sv) {
                        int n = 1 + rng_int() % 3;

                        reduce_skill(du, sv, n);
                        k += du->number;
                    }
                }
                else {
                    /* unit has no skill. kill it. */
                    kill_troop(dt);
                    ++killed;
                }
            }
            force -= du->number;
        }
        else {
            /* only works against humanoids, don't try others. but do remove them
             * from 'force' once or we may never terminate. */
            du->flags |= UFL_MARK;
            reset = 1;
        }
        enemies -= du->number;
    }

    if (reset) {
        unit *u;
        for (u = b->region->units; u; u = u->next) {
            u->flags &= ~UFL_MARK;
        }
    }

    m =
        msg_message("sp_mindblast_effect", "mage spell amount dead", mage, sp, k,
        killed);
    message_all(b, m);
    msg_release(m);
    return level;
}
Exemple #10
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));
}
Exemple #11
0
int sp_undeadhero(struct castorder * co)
{
    fighter * fi = co->magician.fig;
    int level = co->level;
    double power = co->force;
    battle *b = fi->side->battle;
    unit *mage = fi->unit;
    region *r = b->region;
    quicklist *fgs, *ql;
    int qi, n, undead = 0;
    message *msg;
    int force = (int)get_force(power, 0);
    double c = 0.50 + 0.02 * power;

    /* Liste aus allen K�mpfern */
    fgs = fighters(b, fi->side, FIGHT_ROW, AVOID_ROW, FS_ENEMY | FS_HELP);
    scramble_fighters(fgs);

    for (qi = 0, ql = fgs; ql; ql_advance(&ql, &qi, 1)) {
        fighter *df = (fighter *)ql_get(ql, qi);
        unit *du = df->unit;

        if (force <= 0)
            break;

        /* keine Monster */
        if (!playerrace(u_race(du)))
            continue;

        if (df->alive + df->run.number < du->number) {
            int j = 0;

            /* Wieviele Untote k�nnen wir aus dieser Einheit wecken? */
            for (n = df->alive + df->run.number; n != du->number; n++) {
                if (chance(c)) {
                    ++j;
                    if (--force <= 0)
                        break;
                }
            }

            if (j > 0) {
                item **ilist;
                unit *u =
                    create_unit(r, mage->faction, 0, get_race(RC_UNDEAD), 0, unit_getname(du),
                    du);

                /* new units gets some stats from old unit */

                if (du->display) {
                    unit_setinfo(u, du->display);
                }
                else {
                    unit_setinfo(u, NULL);
                }
                setstatus(u, du->status);
                setguard(u, false);
                for (ilist = &du->items; *ilist;) {
                    item *itm = *ilist;
                    int loot = itm->number * j / du->number;
                    if (loot != itm->number) {
                        int split = itm->number * j % du->number;
                        if (split > 0 && (rng_int() % du->number) < split) {
                            ++loot;
                        }
                    }
                    i_change(&u->items, itm->type, loot);
                    i_change(ilist, itm->type, -loot);
                    if (*ilist == itm) {
                        ilist = &itm->next;
                    }
                }

                /* inherit stealth from magician */
                if (mage->flags & UFL_ANON_FACTION) {
                    u->flags |= UFL_ANON_FACTION;
                }

                /* transfer dead people to new unit, set hitpoints to those of old unit */
                transfermen(du, u, j);
                u->hp = u->number * unit_max_hp(du);
                assert(j <= df->side->casualties);
                df->side->casualties -= j;
                df->side->dead -= j;

                /* counting total number of undead */
                undead += j;
            }
        }
    }
    ql_free(fgs);

    level = _min(level, undead);
    if (undead == 0) {
        msg =
            msg_message("summonundead_effect_0", "mage region", mage, mage->region);
    }
    else {
        msg =
            msg_message("summonundead_effect_1", "mage region amount", mage,
            mage->region, undead);
    }

    message_all(b, msg);
    msg_release(msg);
    return level;
}
Exemple #12
0
int sp_flee(struct castorder * co)
{
    fighter * fi = co->magician.fig;
    int level = co->level;
    double power = co->force;
    const spell * sp = co->sp;
    battle *b = fi->side->battle;
    unit *mage = fi->unit;
    quicklist *fgs, *ql;
    int force, n, qi;
    int panik = 0;
    message *msg;

    switch (sp->id) {
    case SPL_FLEE:
        force = (int)get_force(power, 4);
        break;
    case SPL_SONG_OF_FEAR:
        force = (int)get_force(power, 3);
        break;
    case SPL_AURA_OF_FEAR:
        force = (int)get_force(power, 5);
        break;
    default:
        force = (int)get_force(power, 10);
    }

    if (!count_enemies(b, fi, FIGHT_ROW, AVOID_ROW, SELECT_ADVANCE | SELECT_FIND)) {
        msg = msg_message("sp_flee_effect_0", "mage spell", mage, sp);
        message_all(b, msg);
        msg_release(msg);
        return 0;
    }

    fgs = fighters(b, fi->side, FIGHT_ROW, AVOID_ROW, FS_ENEMY);
    scramble_fighters(fgs);

    for (qi = 0, ql = fgs; ql; ql_advance(&ql, &qi, 1)) {
        fighter *df = (fighter *)ql_get(ql, qi);

        for (n = 0; n != df->alive; ++n) {
            if (force < 0)
                break;

            if (df->person[n].flags & FL_PANICED) {   /* bei SPL_SONG_OF_FEAR m�glich */
                df->person[n].attack -= 1;
                --force;
                ++panik;
            }
            else if (!(df->person[n].flags & FL_COURAGE)
                || !(u_race(df->unit)->flags & RCF_UNDEAD)) {
                if (!is_magic_resistant(mage, df->unit, 0)) {
                    df->person[n].flags |= FL_PANICED;
                    ++panik;
                }
                --force;
            }
        }
    }
    ql_free(fgs);

    msg = msg_message("sp_flee_effect_1", "mage spell amount", mage, sp, panik);
    message_all(b, msg);
    msg_release(msg);

    return level;
}
Exemple #13
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;
}
Exemple #14
0
void randomevents(void)
{
    region *r;
    faction *monsters = get_monsters();

    icebergs();
    godcurse();
    orc_growth();
    demon_skillchanges();

    /* Orkifizierte Regionen mutieren und mutieren zurück */

    for (r = regions; r; r = r->next) {
        if (fval(r, RF_ORCIFIED)) {
            direction_t dir;
            double probability = 0.0;
            for (dir = 0; dir < MAXDIRECTIONS; dir++) {
                region *rc = rconnect(r, dir);
                if (rc && rpeasants(rc) > 0 && !fval(rc, RF_ORCIFIED))
                    probability += 0.02;
            }
            if (chance(probability)) {
                ADDMSG(&r->msgs, msg_message("deorcified", "region", r));
                freset(r, RF_ORCIFIED);
            }
        }
        else {
            attrib *a = a_find(r->attribs, &at_orcification);
            if (a != NULL) {
                double probability = 0.0;
                if (rpeasants(r) <= 0)
                    continue;
                probability = a->data.i / (double)rpeasants(r);
                if (chance(probability)) {
                    fset(r, RF_ORCIFIED);
                    a_remove(&r->attribs, a);
                    ADDMSG(&r->msgs, msg_message("orcified", "region", r));
                }
                else {
                    a->data.i -= _max(10, a->data.i / 10);
                    if (a->data.i <= 0)
                        a_remove(&r->attribs, a);
                }
            }
        }
    }

    /* Vulkane qualmen, brechen aus ... */
    for (r = regions; r; r = r->next) {
        if (r->terrain == newterrain(T_VOLCANO_SMOKING)) {
            if (a_find(r->attribs, &at_reduceproduction)) {
                ADDMSG(&r->msgs, msg_message("volcanostopsmoke", "region", r));
                rsetterrain(r, T_VOLCANO);
            }
            else {
                if (rng_int() % 100 < 12) {
                    ADDMSG(&r->msgs, msg_message("volcanostopsmoke", "region", r));
                    rsetterrain(r, T_VOLCANO);
                }
                else if (r->age > 20 && rng_int() % 100 < 8) {
                    volcano_outbreak(r);
                    rsetterrain(r, T_VOLCANO);
                }
            }
        }
        else if (r->terrain == newterrain(T_VOLCANO)) {
            if (rng_int() % 100 < 4) {
                ADDMSG(&r->msgs, msg_message("volcanostartsmoke", "region", r));
                rsetterrain(r, T_VOLCANO_SMOKING);
            }
        }
    }

    /* Monumente zerfallen, Schiffe verfaulen */

    for (r = regions; r; r = r->next) {
        building **blist = &r->buildings;
        while (*blist) {
            building *b = *blist;
            if (fval(b->type, BTF_DECAY) && !building_owner(b)) {
                b->size -= _max(1, (b->size * 20) / 100);
                if (b->size == 0) {
                    remove_building(blist, r->buildings);
                }
            }
            if (*blist == b)
                blist = &b->next;
        }
    }

    /* monster-einheiten desertieren */
    if (monsters) {
        for (r = regions; r; r = r->next) {
            unit *u;

            for (u = r->units; u; u = u->next) {
                if (u->faction && !is_monsters(u->faction)
                    && (u_race(u)->flags & RCF_DESERT)) {
                    if (fval(u, UFL_ISNEW))
                        continue;
                    if (rng_int() % 100 < 5) {
                        ADDMSG(&u->faction->msgs, msg_message("desertion",
                            "unit region", u, r));
                        u_setfaction(u, monsters);
                    }
                }
            }
        }
    }

    chaos_update();
#ifdef HERBS_ROT
    rotting_herbs();
#endif

    dissolve_units();
}
Exemple #15
0
static bool help_money(const unit * u)
{
    if (u_race(u)->ec_flags & GIVEITEM)
        return true;
    return false;
}
Exemple #16
0
static void get_allies(region * r, unit * u)
{
    unit *newunit = NULL;
    const char *name;
    const char *equip;
    int number;
    message *msg;

    assert(u->number);

    switch (rterrain(r)) {
    case T_PLAIN:
        if (!r_isforest(r)) {
            if (get_money(u) / u->number < 100 + rng_int() % 200)
                return;
            name = "random_plain_men";
            equip = "random_plain";
            number = rng_int() % 8 + 2;
            break;
        }
        else {
            if (effskill(u, SK_LONGBOW, r) < 3
                && effskill(u, SK_HERBALISM, r) < 2
                && effskill(u, SK_MAGIC, r) < 2) {
                return;
            }
            name = "random_forest_men";
            equip = "random_forest";
            number = rng_int() % 6 + 2;
        }
        break;

    case T_SWAMP:
        if (effskill(u, SK_MELEE, r) <= 1) {
            return;
        }
        name = "random_swamp_men";
        equip = "random_swamp";
        number = rng_int() % 6 + 2;
        break;

    case T_DESERT:
        if (effskill(u, SK_RIDING, r) <= 2) {
            return;
        }
        name = "random_desert_men";
        equip = "random_desert";
        number = rng_int() % 12 + 2;
        break;

    case T_HIGHLAND:
        if (effskill(u, SK_MELEE, r) <= 1) {
            return;
        }
        name = "random_highland_men";
        equip = "random_highland";
        number = rng_int() % 8 + 2;
        break;

    case T_MOUNTAIN:
        if (effskill(u, SK_MELEE, r) <= 1 || effskill(u, SK_TRADE, r) <= 2) {
            return;
        }
        name = "random_mountain_men";
        equip = "random_mountain";
        number = rng_int() % 6 + 2;
        break;

    case T_GLACIER:
        if (effskill(u, SK_MELEE, r) <= 1 || effskill(u, SK_TRADE, r) <= 1) {
            return;
        }
        name = "random_glacier_men";
        equip = "random_glacier";
        number = rng_int() % 4 + 2;
        break;

    default:
        return;
    }

    newunit =
        create_unit(r, u->faction, number, u->faction->race, 0,
        LOC(u->faction->locale, name), u);
    equip_unit(newunit, get_equipment(equip));

    u_setfaction(newunit, u->faction);
    set_racename(&newunit->attribs, get_racename(u->attribs));
    if (u_race(u)->flags & RCF_SHAPESHIFT) {
        newunit->irace = u->irace;
    }
    if (fval(u, UFL_ANON_FACTION))
        fset(newunit, UFL_ANON_FACTION);
    fset(newunit, UFL_ISNEW);

    msg = msg_message("encounter_allies", "unit name", u, name);
    r_addmessage(r, u->faction, msg);
    msg_release(msg);
}
Exemple #17
0
void destroyfaction(faction ** fp)
{
    faction * f = *fp;
    unit *u = f->units;

    *fp = f->next;
    f->next = dead_factions;
    dead_factions = f;

    fset(f, FFL_QUIT);
    f->_alive = false;

    if (f->spellbook) {
        spellbook_clear(f->spellbook);
        free(f->spellbook);
        f->spellbook = 0;
    }

    if (f->seen_factions) {
        selist_free(f->seen_factions);
        f->seen_factions = 0;
    }

    while (u) {
        /* give away your stuff, to ghosts if you cannot (quest items) */
        if (u->items) {
            region *r = u->region;
            int result = gift_items(u, GIFT_FRIENDS | GIFT_PEASANTS);
            if (result != 0) {
                save_special_items(u);
            }
            if (r->land && !!playerrace(u_race(u))) {
                const race *rc = u_race(u);
                int m = rmoney(r);

                /* Personen gehen nur an die Bauern, wenn sie auch von dort
                    * stammen */
                if ((rc->ec_flags & ECF_REC_ETHEREAL) == 0) {
                    int p = rpeasants(u->region);
                    int h = rhorses(u->region);
                    item *itm;

                    p += (int)(u->number * rc->recruit_multi);
                    for (itm = u->items; itm; itm = itm->next) {
                        if (itm->type->flags & ITF_ANIMAL) {
                            h += itm->number;
                        }
                    }
                    rsetpeasants(r, p);
                    rsethorses(r, h);
                }
                m += get_money(u);
                rsetmoney(r, m);
            }
        }
        set_number(u, 0);
        u = u->nextF;
    }

    handle_event(f->attribs, "destroy", f);
    if (f->alliance) {
        setalliance(f, NULL);
    }

    funhash(f);

    /* units of other factions that were disguised as this faction
     * have their disguise replaced by ordinary faction hiding. */
    if (rule_stealth_other()) {
        region *rc;
        for (rc = regions; rc; rc = rc->next) {
            for (u = rc->units; u; u = u->next) {
                if (u->attribs && get_otherfaction(u) == f) {
                    a_removeall(&u->attribs, &at_otherfaction);
                    if (rule_stealth_anon()) {
                        fset(u, UFL_ANON_FACTION);
                    }
                }
            }
        }
    }
}
Exemple #18
0
/* In a->data.ca[1] steht der Prozentsatz mit dem sich die Einheit
 * auflöst, in a->data.ca[0] kann angegeben werden, wohin die Personen
 * verschwinden. Passiert bereits in der ersten Runde! */
static void dissolve_units(void)
{
    region *r;
    unit *u;
    int n;
    int i;

    for (r = regions; r; r = r->next) {
        for (u = r->units; u; u = u->next) {
            attrib *a = a_find(u->attribs, &at_unitdissolve);
            if (a) {
                message *msg;

                if (u->age == 0 && a->data.ca[1] < 100)
                    continue;

                /* TODO: Durch einzelne Berechnung ersetzen */
                if (a->data.ca[1] == 100) {
                    n = u->number;
                }
                else {
                    n = 0;
                    for (i = 0; i < u->number; i++) {
                        if (rng_int() % 100 < a->data.ca[1])
                            n++;
                    }
                }

                /* wenn keiner verschwindet, auch keine Meldung */
                if (n == 0) {
                    continue;
                }

                scale_number(u, u->number - n);

                switch (a->data.ca[0]) {
                case 1:
                    rsetpeasants(r, rpeasants(r) + n);
                    msg =
                        msg_message("dissolve_units_1", "unit region number race", u, r,
                        n, u_race(u));
                    break;
                case 2:
                    if (r->land && !fval(r, RF_MALLORN)) {
                        rsettrees(r, 2, rtrees(r, 2) + n);
                        msg =
                            msg_message("dissolve_units_2", "unit region number race", u, r,
                            n, u_race(u));
                    }
                    else {
                        msg =
                            msg_message("dissolve_units_3", "unit region number race", u, r,
                            n, u_race(u));
                    }
                    break;
                default:
                    if (u_race(u) == get_race(RC_STONEGOLEM)
                        || u_race(u) == get_race(RC_IRONGOLEM)) {
                        msg =
                            msg_message("dissolve_units_4", "unit region number race", u, r,
                            n, u_race(u));
                    }
                    else {
                        msg =
                            msg_message("dissolve_units_5", "unit region number race", u, r,
                            n, u_race(u));
                    }
                    break;
                }

                add_message(&u->faction->msgs, msg);
                msg_release(msg);
            }
        }
    }

    remove_empty_units();
}
Exemple #19
0
static const char *generic_name(const unit * u)
{
    const char * name = rc_name_s(u_race(u), (u->no == 1) ? NAME_SINGULAR : NAME_PLURAL);
    return LOC(u->faction->locale, name);
}
Exemple #20
0
static void chaos(region * r)
{
    if (rng_int() % 100 < 8) {
        switch (rng_int() % 3) {
        case 0:                  /* Untote */
            if (!fval(r->terrain, SEA_REGION)) {
                unit *u = random_unit(r);
                if (u && playerrace(u_race(u))) {
                    ADDMSG(&u->faction->msgs, msg_message("chaos_disease", "unit", u));
                    u_setfaction(u, get_monsters());
                    u_setrace(u, get_race(RC_GHOUL));
                }
            }
            break;
        case 1:                  /* Drachen */
            if (random_unit(r)) {
                int mfac = 0;
                unit *u;
                switch (rng_int() % 3) {
                case 0:
                    mfac = 100;
                    u =
                        create_unit(r, get_monsters(), rng_int() % 8 + 1,
                        get_race(RC_FIREDRAGON), 0, NULL, NULL);
                    break;
                case 1:
                    mfac = 500;
                    u =
                        create_unit(r, get_monsters(), rng_int() % 4 + 1,
                        get_race(RC_DRAGON), 0, NULL, NULL);
                    break;
                default:
                    mfac = 1000;
                    u =
                        create_unit(r, get_monsters(), rng_int() % 2 + 1,
                        get_race(RC_WYRM), 0, NULL, NULL);
                    break;
                }
                if (mfac)
                    set_money(u, u->number * (rng_int() % mfac));
                fset(u, UFL_ISNEW | UFL_MOVED);
            }
            break;
        case 2:                  /* Terrainveränderung */
            if (!fval(r->terrain, FORBIDDEN_REGION)) {
                if (!fval(r->terrain, SEA_REGION)) {
                    direction_t dir;
                    for (dir = 0; dir != MAXDIRECTIONS; ++dir) {
                        region *rn = rconnect(r, dir);
                        if (rn && fval(rn->terrain, SEA_REGION))
                            break;
                    }
                    if (dir != MAXDIRECTIONS) {
                        ship *sh = r->ships;
                        unit **up;

                        while (sh) {
                            ship *nsh = sh->next;
                            double dmg =
                                config_get_flt("rules.ship.damage.atlantis",
                                0.50);
                            damage_ship(sh, dmg);
                            if (sh->damage >= sh->size * DAMAGE_SCALE) {
                                remove_ship(&sh->region->ships, sh);
                            }
                            sh = nsh;
                        }

                        for (up = &r->units; *up;) {
                            unit *u = *up;
                            if (u_race(u) != get_race(RC_SPELL) && u->ship == 0 && !canfly(u)) {
                                ADDMSG(&u->faction->msgs, msg_message("tidalwave_kill",
                                    "region unit", r, u));
                                remove_unit(up, u);
                            }
                            if (*up == u)
                                up = &u->next;
                        }
                        ADDMSG(&r->msgs, msg_message("tidalwave", "region", r));

                        while (r->buildings) {
                            remove_building(&r->buildings, r->buildings);
                        }
                        terraform_region(r, newterrain(T_OCEAN));
                    }
                }
                else {
                    direction_t dir;
                    for (dir = 0; dir != MAXDIRECTIONS; ++dir) {
                        region *rn = rconnect(r, dir);
                        if (rn && fval(rn->terrain, SEA_REGION))
                            break;
                    }
                    if (dir != MAXDIRECTIONS) {
                        terraform_region(r, chaosterrain());
                    }
                }
            }
        }
    }
}
Exemple #21
0
summary *make_summary(void)
{
    faction *f;
    region *r;
    unit *u;
    summary *s = calloc(1, sizeof(summary));
    const struct resource_type *rhorse = get_resourcetype(R_HORSE);

    for (f = factions; f; f = f->next) {
        const struct locale *lang = f->locale;
        struct language *plang = s->languages;
        while (plang && plang->locale != lang)
            plang = plang->next;
        if (!plang) {
            plang = calloc(1, sizeof(struct language));
            plang->next = s->languages;
            s->languages = plang;
            plang->locale = lang;
        }
        ++plang->number;
        if (f->units) {
            s->factions++;
            /* Problem mit Monsterpartei ... */
            if (!is_monsters(f)) {
                int rc = old_race(f->race);
                if (rc >= 0) {
                    s->factionrace[rc]++;
                }
            }
        }
    }

    /* count everything */

    for (r = regions; r; r = r->next) {
        s->pferde += rhorses(r);
        s->schiffe += listlen(r->ships);
        s->gebaeude += listlen(r->buildings);
        if (!fval(r->terrain, SEA_REGION)) {
            s->landregionen++;
            if (r->units) {
                s->landregionen_mit_spielern++;
            }
            if (r->terrain == newterrain(T_VOLCANO)) {
                s->inactive_volcanos++;
            }
            else if (r->terrain == newterrain(T_VOLCANO_SMOKING)) {
                s->active_volcanos++;
            }
        }
        if (r->units) {
            s->regionen_mit_spielern++;
        }
        if (rpeasants(r) || r->units) {
            s->inhabitedregions++;
            s->peasants += rpeasants(r);
            s->peasantmoney += rmoney(r);

            for (u = r->units; u; u = u->next) {
                int orace;
                f = u->faction;
                if (!is_monsters(u->faction)) {
                    skill *sv;
                    item *itm;

                    s->nunits++;
                    s->playerpop += u->number;
                    if (u->flags & UFL_HERO) {
                        s->heroes += u->number;
                    }
                    s->spielerpferde += i_get(u->items, rhorse->itype);
                    s->playermoney += get_money(u);
                    s->armed_men += armedmen(u, true);
                    for (itm = u->items; itm; itm = itm->next) {
                        if (itm->type->rtype->wtype) {
                            s->waffen += itm->number;
                        }
                        if (itm->type->rtype->atype) {
                            s->ruestungen += itm->number;
                        }
                    }

                    s->spielerpferde += i_get(u->items, rhorse->itype);

                    for (sv = u->skills; sv != u->skills + u->skill_size; ++sv) {
                        skill_t sk = sv->id;
                        int aktskill = effskill(u, sk, r);
                        if (aktskill > s->maxskill)
                            s->maxskill = aktskill;
                    }
                }

                orace = (int)old_race(u_race(u));
                if (orace >= 0) {
                    s->poprace[orace] += u->number;
                }
            }
        }
    }

    return s;
}
Exemple #22
0
void plan_monsters(faction * f)
{
    region *r;
    
    assert(f);
    attack_chance = get_param_flt(global.parameters, "rules.monsters.attack_chance", 0.4);
    f->lastorders = turn;

    for (r = regions; r; r = r->next) {
        unit *u;
        bool attacking = false;

        for (u = r->units; u; u = u->next) {
            attrib *ta;
            order *long_order = NULL;

            /* Ab hier nur noch Befehle für NPC-Einheiten. */
            if (!is_monsters(u->faction))
                continue;

            /* Befehle müssen jede Runde neu gegeben werden: */
            free_orders(&u->orders);
            if (skill_enabled(SK_PERCEPTION)) {
                /* Monster bekommen jede Runde ein paar Tage Wahrnehmung dazu */
                /* TODO: this only works for playerrace */
                produceexp(u, SK_PERCEPTION, u->number);
            }

            if (!attacking) {
                if (chance(attack_chance)) attacking = true;
            }
            if (u->status > ST_BEHIND) {
                setstatus(u, ST_FIGHT);
                /* all monsters fight */
            }
            if (attacking && (!r->land || is_guard(u, GUARD_TAX))) {
                monster_attacks(u);
            }
            /* units with a plan to kill get ATTACK orders: */
            ta = a_find(u->attribs, &at_hate);
            if (ta && !monster_is_waiting(u)) {
                unit *tu = (unit *)ta->data.v;
                if (tu && tu->region == r) {
                    order * ord = monster_attack(u, tu);
                    if (ord) {
                        addlist(&u->orders, ord);
                    }
                }
                else if (tu) {
                    tu = findunitg(ta->data.i, NULL);
                    if (tu != NULL) {
                        long_order = make_movement_order(u, tu->region, 2, allowed_walk);
                    }
                }
                else
                    a_remove(&u->attribs, ta);
            }

            /* All monsters guard the region: */
            if (!monster_is_waiting(u) && r->land) {
                addlist(&u->orders, create_order(K_GUARD, u->faction->locale, NULL));
            }

            /* Einheiten mit Bewegungsplan kriegen ein NACH: */
            if (long_order == NULL) {
                attrib *ta = a_find(u->attribs, &at_targetregion);
                if (ta) {
                    if (u->region == (region *)ta->data.v) {
                        a_remove(&u->attribs, ta);
                    }
                }
                else if (u_race(u)->flags & RCF_MOVERANDOM) {
                    if (rng_int() % 100 < MOVECHANCE || check_overpopulated(u)) {
                        long_order = monster_move(r, u);
                    }
                }
            }

            if (long_order == NULL && unit_can_study(u)) {
                /* Einheiten, die Waffenlosen Kampf lernen könnten, lernen es um
                 * zu bewachen: */
                if (u_race(u)->bonus[SK_WEAPONLESS] != -99) {
                    if (effskill(u, SK_WEAPONLESS, 0) < 1) {
                        long_order =
                            create_order(K_STUDY, f->locale, "'%s'",
                            skillname(SK_WEAPONLESS, f->locale));
                    }
                }
            }

            if (long_order == NULL) {
                /* Ab hier noch nicht generalisierte Spezialbehandlungen. */

                if (!u->orders) {
                    handle_event(u->attribs, "ai_move", u);
                }

                switch (old_race(u_race(u))) {
                case RC_SEASERPENT:
                    long_order = create_order(K_PIRACY, f->locale, NULL);
                    break;
#ifdef TODO_ALP
                case RC_ALP:
                    long_order = monster_seeks_target(r, u);
                    break;
#endif
                case RC_FIREDRAGON:
                case RC_DRAGON:
                case RC_WYRM:
                    long_order = plan_dragon(u);
                    break;
                default:
                    if (u_race(u)->flags & RCF_LEARN) {
                        long_order = monster_learn(u);
                    }
                    break;
                }
            }
            if (long_order) {
                addlist(&u->orders, long_order);
            }
        }
    }
    pathfinder_cleanup();
}
Exemple #23
0
/* wiederbeleben */
int sp_reanimate(struct castorder * co)
{
    fighter * fi = co->magician.fig;
    int level = co->level;
    double power = co->force;
    battle *b = fi->side->battle;
    unit *mage = fi->unit;
    int healable, j = 0;
    double c = 0.50 + 0.02 * power;
    int k = (int)(EFFECT_HEALING_SPELL * power);
    bool use_item = has_ao_healing(mage);
    message *msg;

    if (use_item) {
        k *= 2;
        c += 0.10;
    }

    healable = count_healable(b, fi);
    if (healable > k) {
        healable = k;
    }
    while (healable--) {
        fighter *tf = select_corpse(b, fi);
        if (tf != NULL && tf->side->casualties > 0
            && u_race(tf->unit) != get_race(RC_DAEMON)
            && (chance(c))) {
            assert(tf->alive < tf->unit->number);
            /* t.fighter->person[].hp beginnt mit t.index = 0 zu zaehlen,
             * t.fighter->alive ist jedoch die Anzahl lebender in der Einheit,
             * also sind die hp von t.fighter->alive
             * t.fighter->hitpoints[t.fighter->alive-1] und der erste Tote
             * oder weggelaufene ist t.fighter->hitpoints[tf->alive] */
            tf->person[tf->alive].hp = 2;
            ++tf->alive;
            ++tf->side->size[SUM_ROW];
            ++tf->side->size[tf->unit->status + 1];
            ++tf->side->healed;
            --tf->side->casualties;
            assert(tf->side->casualties >= 0);
            --tf->side->dead;
            assert(tf->side->dead >= 0);
            ++j;
        }
    }
    if (j <= 0) {
        level = j;
    }
    if (use_item) {
        msg =
            msg_message("reanimate_effect_1", "mage amount item", mage, j,
            get_resourcetype(R_AMULET_OF_HEALING));
    }
    else {
        msg = msg_message("reanimate_effect_0", "mage amount", mage, j);
    }
    message_all(b, msg);
    msg_release(msg);

    return level;
}
Exemple #24
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;
}
Exemple #25
0
/** The mind blast spell for regular folks.
* This spell temporarily reduces the skill of the victims
*/
int sp_mindblast(struct castorder * co)
{
    fighter * fi = co->magician.fig;
    int level = co->level;
    double power = co->force;
    const spell * sp = co->sp;
    battle *b = fi->side->battle;
    unit *mage = fi->unit;
    int k = 0, reset = 0, maxloss = (level + 2) / 3;
    message *m;
    int force = lovar(power * 25);
    int enemies = count_enemies(b, fi, FIGHT_ROW, BEHIND_ROW, SELECT_ADVANCE);

    if (!enemies) {
        m = msg_message("spell_out_of_range", "mage spell", fi->unit, sp);
        message_all(b, m);
        msg_release(m);
        return 0;
    }

    while (force > 0 && enemies > 0) {
        unit *du;
        troop dt = select_enemy(fi, FIGHT_ROW, BEHIND_ROW, SELECT_ADVANCE);

        assert(dt.fighter);
        du = dt.fighter->unit;
        if (du->flags & UFL_MARK) {
            /* not this one again */
            continue;
        }

        if (humanoidrace(u_race(du)) && force >= du->number) {
            if (!is_magic_resistant(mage, du, 0)) {
                skill_t sk = random_skill(du, true);
                if (sk != NOSKILL) {
                    int n = 1 + rng_int() % maxloss;
                    attrib *a = make_skillmod(sk, NULL, 0.0, n);
                    /* neat: you can add a whole lot of these to a unit, they stack */
                    a_add(&du->attribs, a);
                }
                k += du->number;
            }
            force -= du->number;
        }
        du->flags |= UFL_MARK;
        reset = 1;
        enemies -= du->number;
    }

    if (reset) {
        unit *u;
        for (u = b->region->units; u; u = u->next) {
            u->flags &= ~UFL_MARK;
        }
    }

    m = msg_message("sp_mindblast_temp_effect", "mage spell amount", mage, sp, k);
    message_all(b, m);
    msg_release(m);
    return level;
}
Exemple #26
0
/** creates a new unit.
*
* @param dname: name, set to NULL to get a default.
* @param creator: unit to inherit stealth, group, building, ship, etc. from
*/
unit *create_unit(region * r, faction * f, int number, const struct race *urace,
  int id, const char *dname, unit * creator)
{
  unit *u = (unit *)calloc(1, sizeof(unit));

  assert(urace);
  if (f) {
    assert(f->alive);
    u_setfaction(u, f);

    if (f->locale) {
      order *deford = default_order(f->locale);
      if (deford) {
        set_order(&u->thisorder, NULL);
        addlist(&u->orders, deford);
      }
    }
  }
  u_seteffstealth(u, -1);
  u_setrace(u, urace);
  u->irace = NULL;

  set_number(u, number);

  /* die nummer der neuen einheit muss vor name_unit generiert werden,
   * da der default name immer noch 'Nummer u->no' ist */
  createunitid(u, id);

  /* zuerst in die Region setzen, da zb Drachennamen den Regionsnamen
   * enthalten */
  if (r)
    move_unit(u, r, NULL);

  /* u->race muss bereits gesetzt sein, wird für default-hp gebraucht */
  /* u->region auch */
  u->hp = unit_max_hp(u) * number;

  if (!dname) {
    name_unit(u);
  } else {
    u->name = _strdup(dname);
  }

  if (creator) {
    attrib *a;

    /* erbt Kampfstatus */
    setstatus(u, creator->status);

    /* erbt Gebäude/Schiff */
    if (creator->region == r) {
      if (creator->building) {
        u_set_building(u, creator->building);
      }
      if (creator->ship && fval(u_race(u), RCF_CANSAIL)) {
        u_set_ship(u, creator->ship);
      }
    }

    /* Tarnlimit wird vererbt */
    if (fval(creator, UFL_STEALTH)) {
      attrib *a = a_find(creator->attribs, &at_stealth);
      if (a) {
        int stealth = a->data.i;
        a = a_add(&u->attribs, a_new(&at_stealth));
        a->data.i = stealth;
      }
    }

    /* Temps von parteigetarnten Einheiten sind wieder parteigetarnt */
    if (fval(creator, UFL_ANON_FACTION)) {
      fset(u, UFL_ANON_FACTION);
    }
    /* Daemonentarnung */
    set_racename(&u->attribs, get_racename(creator->attribs));
    if (fval(u_race(u), RCF_SHAPESHIFT) && fval(u_race(creator), RCF_SHAPESHIFT)) {
      u->irace = creator->irace;
    }

    /* Gruppen */
    if (creator->faction == f && fval(creator, UFL_GROUP)) {
      a = a_find(creator->attribs, &at_group);
      if (a) {
        group *g = (group *) a->data.v;
        set_group(u, g);
      }
    }
    a = a_find(creator->attribs, &at_otherfaction);
    if (a) {
      a_add(&u->attribs, make_otherfaction(get_otherfaction(a)));
    }

    a = a_add(&u->attribs, a_new(&at_creator));
    a->data.v = creator;
  }

  return u;
}
Exemple #27
0
/* ------------------------------------------------------------- */
bool magic_lowskill(unit * u)
{
    return (u_race(u) == get_race(RC_TOAD)) ? true : false;
}