Exemplo n.º 1
0
static int do_potion(unit * u, region *r, const potion_type * ptype, int amount)
{
  if (ptype == oldpotiontype[P_LIFE]) {
    int holz = 0;
    static int tree_type = -1;
    static int tree_count = -1;
    if (tree_type < 0) {
      tree_type = get_param_int(global.parameters, "rules.magic.wol_type", 1);
      tree_count =
        get_param_int(global.parameters, "rules.magic.wol_effect", 10);
    }
    /* mallorn is required to make mallorn forests, wood for regular ones */
    if (fval(r, RF_MALLORN)) {
      holz = use_pooled(u, rt_find("mallorn"),
        GET_SLACK | GET_RESERVE | GET_POOLED_SLACK, tree_count * amount);
    } else {
      holz = use_pooled(u, rt_find("log"),
        GET_SLACK | GET_RESERVE | GET_POOLED_SLACK, tree_count * amount);
    }
    if (r->land == 0)
      holz = 0;
    if (holz < tree_count * amount) {
      int x = holz / tree_count;
      if (holz % tree_count)
        ++x;
      if (x < amount)
        amount = x;
    }
    rsettrees(r, tree_type, rtrees(r, tree_type) + holz);
    ADDMSG(&u->faction->msgs, msg_message("growtree_effect",
        "mage amount", u, holz));
  } else if (ptype == oldpotiontype[P_HEILWASSER]) {
    u->hp = _min(unit_max_hp(u) * u->number, u->hp + 400 * amount);
  } else if (ptype == oldpotiontype[P_PEOPLE]) {
    attrib *a = (attrib *) a_find(r->attribs, &at_peasantluck);
    if (!a)
      a = a_add(&r->attribs, a_new(&at_peasantluck));
    a->data.i += amount;
  } else if (ptype == oldpotiontype[P_HORSE]) {
    attrib *a = (attrib *) a_find(r->attribs, &at_horseluck);
    if (!a)
      a = a_add(&r->attribs, a_new(&at_horseluck));
    a->data.i += amount;
  } else if (ptype == oldpotiontype[P_WAHRHEIT]) {
    fset(u, UFL_DISBELIEVES);
    amount = 1;
  } else if (ptype == oldpotiontype[P_MACHT]) {
    /* Verfünffacht die HP von max. 10 Personen in der Einheit */
    u->hp += _min(u->number, 10 * amount) * unit_max_hp(u) * 4;
  } else {
    change_effect(u, ptype, 10 * amount);
  }
  return amount;
}
Exemplo n.º 2
0
static int
damage_unit(unit * u, const char *dam, bool physical, bool magic)
{
  int *hp = malloc(u->number * sizeof(int));
  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;
  }

  h = u->hp / u->number;
  /* HP verteilen */
  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;

  free(hp);

  return dead;
}
Exemplo n.º 3
0
void transfermen(unit * u, unit * u2, int n)
{
  const attrib *a;
  int hp = u->hp;
  region *r = u->region;

  if (n == 0)
    return;
  assert(n > 0);
  /* "hat attackiert"-status wird übergeben */

  if (u2) {
    skill *sv, *sn;
    skill_t sk;
    ship *sh;

    assert(u2->number + n > 0);

    for (sk = 0; sk != MAXSKILLS; ++sk) {
      int weeks, level = 0;

      sv = get_skill(u, sk);
      sn = get_skill(u2, sk);

      if (sv == NULL && sn == NULL)
        continue;
      if (sn == NULL && u2->number == 0) {
        /* new unit, easy to solve */
        level = sv->level;
        weeks = sv->weeks;
      } else {
        double dlevel = 0.0;

        if (sv && sv->level) {
          dlevel += (sv->level + 1 - sv->weeks / (sv->level + 1.0)) * n;
          level += sv->level * n;
        }
        if (sn && sn->level) {
          dlevel +=
            (sn->level + 1 - sn->weeks / (sn->level + 1.0)) * u2->number;
          level += sn->level * u2->number;
        }

        dlevel = dlevel / (n + u2->number);
        level = level / (n + u2->number);
        if (level <= dlevel) {
          /* apply the remaining fraction to the number of weeks to go.
           * subtract the according number of weeks, getting closer to the
           * next level */
          level = (int)dlevel;
          weeks = (level + 1) - (int)((dlevel - level) * (level + 1));
        } else {
          /* make it harder to reach the next level. 
           * weeks+level is the max difficulty, 1 - the fraction between
           * level and dlevel applied to the number of weeks between this
           * and the previous level is the added difficutly */
          level = (int)dlevel + 1;
          weeks = 1 + 2 * level - (int)((1 + dlevel - level) * level);
        }
      }
      if (level) {
        if (sn == NULL)
          sn = add_skill(u2, sk);
        sn->level = (unsigned char)level;
        sn->weeks = (unsigned char)weeks;
        assert(sn->weeks > 0 && sn->weeks <= sn->level * 2 + 1);
        assert(u2->number != 0 || (sn->level == sv->level
            && sn->weeks == sv->weeks));
      } else if (sn) {
        remove_skill(u2, sk);
        sn = NULL;
      }
    }
    a = a_find(u->attribs, &at_effect);
    while (a && a->type == &at_effect) {
      effect_data *olde = (effect_data *) a->data.v;
      if (olde->value)
        change_effect(u2, olde->type, olde->value);
      a = a->next;
    }
    sh = leftship(u);
    if (sh != NULL)
      set_leftship(u2, sh);
    u2->flags |=
      u->flags & (UFL_LONGACTION | UFL_NOTMOVING | UFL_HUNGER | UFL_MOVED |
      UFL_ENTER);
    if (u->attribs) {
      transfer_curse(u, u2, n);
    }
  }
  scale_number(u, u->number - n);
  if (u2) {
    set_number(u2, u2->number + n);
    hp -= u->hp;
    u2->hp += hp;
    /* TODO: Das ist schnarchlahm! und gehört nicht hierhin */
    a = a_find(u2->attribs, &at_effect);
    while (a && a->type == &at_effect) {
      attrib *an = a->next;
      effect_data *olde = (effect_data *) a->data.v;
      int e = get_effect(u, olde->type);
      if (e != 0)
        change_effect(u2, olde->type, -e);
      a = an;
    }
  } else if (r->land) {
    if ((u_race(u)->ec_flags & ECF_REC_ETHEREAL) == 0) {
      const race *rc = u_race(u);
      if (rc->ec_flags & ECF_REC_HORSES) {      /* Zentauren an die Pferde */
        int h = rhorses(r) + n;
        rsethorses(r, h);
      } else {
        int p = rpeasants(r);
        p += (int)(n * rc->recruit_multi);
        rsetpeasants(r, p);
      }
    }
  }
}
Exemplo n.º 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;
}
Exemplo n.º 5
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;
}
Exemplo n.º 6
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);
    }
}
Exemplo n.º 7
0
/** Use up resources for building an object.
* Build up to 'size' points of 'type', where 'completed'
* of the first object have already been finished. return the
* actual size that could be built.
*/
int build(unit * u, const construction * ctype, int completed, int want)
{
    const construction *type = ctype;
    int skills = INT_MAX;         /* number of skill points remainig */
    int basesk = 0;
    int made = 0;

    if (want <= 0)
        return 0;
    if (type == NULL)
        return ENOMATERIALS;
    if (type->improvement == NULL && completed == type->maxsize)
        return ECOMPLETE;
    if (type->btype != NULL) {
        building *b;
        if (!u->building || u->building->type != type->btype) {
            return EBUILDINGREQ;
        }
        b = inside_building(u);
        if (b == NULL)
            return EBUILDINGREQ;
    }

    if (type->skill != NOSKILL) {
        int effsk;
        int dm = get_effect(u, oldpotiontype[P_DOMORE]);

        assert(u->number);
        basesk = effskill(u, type->skill);
        if (basesk == 0)
            return ENEEDSKILL;

        effsk = basesk;
        if (inside_building(u)) {
            effsk = skillmod(u->building->type->attribs, u, u->region, type->skill,
                effsk, SMF_PRODUCTION);
        }
        effsk = skillmod(type->attribs, u, u->region, type->skill,
            effsk, SMF_PRODUCTION);
        if (effsk < 0)
            return effsk;             /* pass errors to caller */
        if (effsk == 0)
            return ENEEDSKILL;

        skills = effsk * u->number;

        /* technically, nimblefinge and domore should be in a global set of
         * "game"-attributes, (as at_skillmod) but for a while, we're leaving
         * them in here. */

        if (dm != 0) {
            /* Auswirkung Schaffenstrunk */
            dm = _min(dm, u->number);
            change_effect(u, oldpotiontype[P_DOMORE], -dm);
            skills += dm * effsk;
        }
    }
    for (; want > 0 && skills > 0;) {
        int c, n;

        /* skip over everything that's already been done:
         * type->improvement==NULL means no more improvements, but no size limits
         * type->improvement==type means build another object of the same time
         * while material lasts type->improvement==x means build x when type
         * is finished */
        while (type->improvement != NULL &&
            type->improvement != type &&
            type->maxsize > 0 && type->maxsize <= completed) {
            completed -= type->maxsize;
            type = type->improvement;
        }
        if (type == NULL) {
            if (made == 0)
                return ECOMPLETE;
            break;                    /* completed */
        }

        /*  Hier ist entweder maxsize == -1, oder completed < maxsize.
         *  Andernfalls ist das Datenfile oder sonstwas kaputt...
         *  (enno): Nein, das ist für Dinge, bei denen die nächste Ausbaustufe
         *  die gleiche wie die vorherige ist. z.b. gegenstände.
         */
        if (type->maxsize > 1) {
            completed = completed % type->maxsize;
        }
        else {
            completed = 0;
            assert(type->reqsize >= 1);
        }

        if (basesk < type->minskill) {
            if (made == 0)
                return ELOWSKILL;       /* not good enough to go on */
        }

        /* n = maximum buildable size */
        if (type->minskill > 1) {
            n = skills / type->minskill;
        }
        else {
            n = skills;
        }
        /* Flinkfingerring wirkt nicht auf Mengenbegrenzte (magische)
         * Talente */
        if (skill_limit(u->faction, type->skill) == INT_MAX) {
            const resource_type *ring = get_resourcetype(R_RING_OF_NIMBLEFINGER);
            item *itm = ring ? *i_find(&u->items, ring->itype) : 0;
            int i = itm ? itm->number : 0;
            if (i > 0) {
                int rings = _min(u->number, i);
                n = n * ((roqf_factor() - 1) * rings + u->number) / u->number;
            }
        }

        if (want < n) n = want;

        if (type->maxsize > 0) {
            n = _min(type->maxsize - completed, n);
            if (type->improvement == NULL) {
                want = n;
            }
        }

        if (type->materials)
            for (c = 0; n > 0 && type->materials[c].number; c++) {
                const struct resource_type *rtype = type->materials[c].rtype;
                int need, prebuilt;
                int canuse = get_pooled(u, rtype, GET_DEFAULT, INT_MAX);

                if (inside_building(u)) {
                    canuse = matmod(u->building->type->attribs, u, rtype, canuse);
                }

                if (canuse < 0)
                    return canuse;        /* pass errors to caller */
                canuse = matmod(type->attribs, u, rtype, canuse);
                if (type->reqsize > 1) {
                    prebuilt =
                        required(completed, type->reqsize, type->materials[c].number);
                    for (; n;) {
                        need =
                            required(completed + n, type->reqsize, type->materials[c].number);
                        if (need - prebuilt <= canuse)
                            break;
                        --n;                /* TODO: optimieren? */
                    }
                }
                else {
                    int maxn = canuse / type->materials[c].number;
                    if (maxn < n)
                        n = maxn;
                }
            }
        if (n <= 0) {
            if (made == 0)
                return ENOMATERIALS;
            else
                break;
        }
        if (type->materials)
            for (c = 0; type->materials[c].number; c++) {
                const struct resource_type *rtype = type->materials[c].rtype;
                int prebuilt =
                    required(completed, type->reqsize, type->materials[c].number);
                int need =
                    required(completed + n, type->reqsize, type->materials[c].number);
                int multi = 1;
                int canuse = 100;       /* normalization */
                if (inside_building(u))
                    canuse = matmod(u->building->type->attribs, u, rtype, canuse);
                if (canuse < 0)
                    return canuse;        /* pass errors to caller */
                canuse = matmod(type->attribs, u, rtype, canuse);

                assert(canuse % 100 == 0
                    || !"only constant multipliers are implemented in build()");
                multi = canuse / 100;
                if (canuse < 0)
                    return canuse;        /* pass errors to caller */

                use_pooled(u, rtype, GET_DEFAULT,
                    (need - prebuilt + multi - 1) / multi);
            }
        made += n;
        skills -= n * type->minskill;
        want -= n;
        completed = completed + n;
    }
    /* Nur soviel PRODUCEEXP wie auch tatsaechlich gemacht wurde */
    produceexp(u, ctype->skill, _min(made, u->number));

    return made;
}
Exemplo n.º 8
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));
}
Exemplo n.º 9
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;
}
Exemplo n.º 10
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;
}