Beispiel #1
0
void free_ship(ship * s)
{
    while (s->attribs)
        a_remove(&s->attribs, s->attribs);
    free(s->name);
    free(s->display);
    free(s);
}
Beispiel #2
0
void free_region(region * r)
{
    if (last == r)
        last = NULL;
    free(r->display);
    if (r->land)
        free_land(r->land);

    if (r->msgs) {
        free_messagelist(r->msgs->begin);
        free(r->msgs);
        r->msgs = 0;
    }

    while (r->individual_messages) {
        struct individual_message *msg = r->individual_messages;
        r->individual_messages = msg->next;
        if (msg->msgs) {
            free_messagelist(msg->msgs->begin);
            free(msg->msgs);
        }
        free(msg);
    }

    while (r->attribs)
        a_remove(&r->attribs, r->attribs);
    while (r->resources) {
        rawmaterial *res = r->resources;
        r->resources = res->next;
        free(res);
    }

    while (r->units) {
        unit *u = r->units;
        r->units = u->next;
        uunhash(u);
        free_unit(u);
        free(u);
    }

    while (r->buildings) {
        building *b = r->buildings;
        assert(b->region == r);
        r->buildings = b->next;
        bunhash(b);                 /* must be done here, because remove_building does it, and wasn't called */
        free_building(b);
    }

    while (r->ships) {
        ship *s = r->ships;
        assert(s->region == r);
        r->ships = s->next;
        sunhash(s);
        free_ship(s);
    }

    free(r);
}
Beispiel #3
0
static void test_attrib_new(CuTest * tc)
{
    attrib_type at_test = { "test" };
    attrib * a;
    CuAssertPtrNotNull(tc, (a = a_new(&at_test)));
    CuAssertPtrEquals(tc, 0, a->next);
    CuAssertPtrEquals(tc, 0, a->nexttype);
    CuAssertPtrEquals(tc, (void *)a->type, (void *)&at_test);
    a_remove(&a, a);
    CuAssertPtrEquals(tc, 0, a);
}
Beispiel #4
0
static void test_attrib_remove_self(CuTest * tc) {
    attrib_type at_foo = { "foo" };
    attrib *a, *alist = 0;

    CuAssertPtrNotNull(tc, a_add(&alist, a_new(&at_foo)));
    CuAssertPtrNotNull(tc, a = a_add(&alist, a_new(&at_foo)));
    CuAssertPtrEquals(tc, a, alist->next);
    CuAssertPtrEquals(tc, 0, alist->nexttype);
    CuAssertIntEquals(tc, 1, a_remove(&alist, alist));
    CuAssertPtrEquals(tc, a, alist);
    a_removeall(&alist, NULL);
}
Beispiel #5
0
static int clonedied_handle(trigger * t, void *data)
{
  /* destroy the unit */
  unit *u = (unit *) t->data.v;
  if (u) {
    attrib *a = a_find(u->attribs, &at_clone);
    if (a)
      a_remove(&u->attribs, a);
  } else
    log_error("could not perform clonedied::handle()\n");
  unused_arg(data);
  return 0;
}
Beispiel #6
0
void usetprivate(unit * u, const char *str)
{
  attrib *a = a_find(u->attribs, &at_private);

  if (str == NULL) {
    if (a)
      a_remove(&u->attribs, a);
    return;
  }
  if (!a)
    a = a_add(&u->attribs, a_new(&at_private));
  if (a->data.v)
    free(a->data.v);
  a->data.v = _strdup((const char *)str);
}
Beispiel #7
0
void add_chaoscount(region * r, int fallen)
{
    attrib *a;

    if (fallen == 0)
        return;

    a = a_find(r->attribs, &at_chaoscount);
    if (!a)
        a = a_add(&r->attribs, a_new(&at_chaoscount));
    a->data.i += fallen;

    if (a->data.i <= 0)
        a_remove(&r->attribs, a);
}
Beispiel #8
0
void usettarget(unit * u, const unit * t)
{
  attrib *a = a_find(u->attribs, &at_target);
  if (!a && t)
    a = a_add(&u->attribs, a_new(&at_target));
  if (a) {
    if (!t) {
      a_remove(&u->attribs, a);
      freset(u, UFL_TARGET);
    } else {
      a->data.v = (void *)t;
      fset(u, UFL_TARGET);
    }
  }
}
Beispiel #9
0
void usetsiege(unit * u, const struct building *t)
{
  attrib *a = a_find(u->attribs, &at_siege);
  if (!a && t)
    a = a_add(&u->attribs, a_new(&at_siege));
  if (a) {
    if (!t) {
      a_remove(&u->attribs, a);
      freset(u, UFL_SIEGE);
    } else {
      a->data.v = (void *)t;
      fset(u, UFL_SIEGE);
    }
  }
}
Beispiel #10
0
static int tolua_region_setkey(lua_State * L)
{
  region *self = (region *) tolua_tousertype(L, 1, 0);
  const char *name = tolua_tostring(L, 2, 0);
  int value = tolua_toboolean(L, 3, 0);

  int flag = atoi36(name);
  attrib *a = find_key(self->attribs, flag);
  if (a == NULL && value) {
    add_key(&self->attribs, flag);
  } else if (a != NULL && !value) {
    a_remove(&self->attribs, a);
  }
  return 0;
}
Beispiel #11
0
static int removecurse_handle(trigger * t, void *data)
{
  /* call an event handler on removecurse.
   * data.v -> ( variant event, int timer )
   */
  removecurse_data *td = (removecurse_data *) t->data.v;
  if (td->curse && td->target) {
    attrib *a = a_select(td->target->attribs, td->curse, cmp_curse);
    if (a) {
      a_remove(&td->target->attribs, a);
    } else
      log_error("could not perform removecurse::handle()\n");
  }
  unused_arg(data);
  return 0;
}
Beispiel #12
0
static void test_curse(CuTest * tc)
{
    attrib *attrs = NULL;
    curse *c, *result;
    int cid;

    curse_type ct_dummy = { "dummy", CURSETYP_NORM, 0, M_SUMEFFECT, NULL };
    c = create_curse(NULL, &attrs, &ct_dummy, 1.0, 1, 1, 1);
    cid = c->no;
    result = findcurse(cid);
    CuAssertPtrEquals(tc, c, result);
    a_remove(&attrs, attrs);
    result = findcurse(cid);
    CuAssertPtrEquals(tc, NULL, result);
    test_cleanup();
}
Beispiel #13
0
int a_age(attrib ** p)
{
    attrib **ap = p;
    /* Attribute altern, und die Entfernung (age()==0) eines Attributs
     * hat Einfluß auf den Besitzer */
    while (*ap) {
        attrib *a = *ap;
        if (a->type->age) {
            int result = a->type->age(a);
            assert(result >= 0 || !"age() returned a negative value");
            if (result == AT_AGE_REMOVE) {
                a_remove(p, a);
                continue;
            }
        }
        ap = &a->next;
    }
    return (*p != NULL);
}
Beispiel #14
0
/** remove the faction from memory.
 * this frees all memory that's only accessible through the faction,
 * but you should still call funhash and remove the faction from the
 * global list.
 */
static void free_faction(faction * f)
{
    funhash(f);
    if (f->msgs) {
        free_messagelist(f->msgs->begin);
        free(f->msgs);
    }
    while (f->battles) {
        struct bmsg *bm = f->battles;
        f->battles = bm->next;
        if (bm->msgs) {
            free_messagelist(bm->msgs->begin);
            free(bm->msgs);
        }
        free(bm);
    }

    if (f->spellbook) {
        free_spellbook(f->spellbook);
    }

    while (f->groups) {
        group *g = f->groups;
        f->groups = g->next;
        free_group(g);
    }
    freelist(f->allies);

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

    while (f->attribs) {
        a_remove(&f->attribs, f->attribs);
    }

    i_freeall(&f->items);

    freelist(f->origin);
}
Beispiel #15
0
void deathcounts(region * r, int fallen)
{
    attrib *a;
    static const curse_type *ctype = NULL;

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

    a = a_find(r->attribs, &at_deathcount);
    if (!a)
        a = a_add(&r->attribs, a_new(&at_deathcount));
    a->data.i += fallen;

    if (a->data.i <= 0)
        a_remove(&r->attribs, a);
}
Beispiel #16
0
void u_seteffstealth(unit * u, int value)
{
  if (skill_enabled[SK_STEALTH]) {
    attrib *a = NULL;
    if (fval(u, UFL_STEALTH)) {
      a = a_find(u->attribs, &at_stealth);
    }
    if (value < 0) {
      if (a != NULL) {
        freset(u, UFL_STEALTH);
        a_remove(&u->attribs, a);
      }
      return;
    }
    if (a == NULL) {
      a = a_add(&u->attribs, a_new(&at_stealth));
      fset(u, UFL_STEALTH);
    }
    a->data.i = value;
  }
}
Beispiel #17
0
/** remove the unit from memory.
 * this frees all memory that's only accessible through the unit,
 * and you should already have called uunhash and removed the unit from the
 * region.
 */
void free_unit(unit * u)
{
  free(u->name);
  free(u->display);
  free_order(u->thisorder);
  free_orders(&u->orders);
  if (u->skills)
    free(u->skills);
  while (u->items) {
    item *it = u->items->next;
    u->items->next = NULL;
    i_free(u->items);
    u->items = it;
  }
  while (u->attribs)
    a_remove(&u->attribs, u->attribs);
  while (u->reservations) {
    struct reservation *res = u->reservations;
    u->reservations = res->next;
    free(res);
  }
}
Beispiel #18
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;
}
int read_borders(gamedata *data)
{
    struct storage *store = data->store;
    for (;;) {
        int bid = 0;
        char zText[32];
        region *from, *to;
        border_type *type;

        READ_TOK(store, zText, sizeof(zText));
        if (!strcmp(zText, "end"))
            break;
        READ_INT(store, &bid);
        if (data->version < UIDHASH_VERSION) {
            int fx, fy, tx, ty;
            READ_INT(store, &fx);
            READ_INT(store, &fy);
            READ_INT(store, &tx);
            READ_INT(store, &ty);
            from = findregion(fx, fy);
            to = findregion(tx, ty);
        }
        else {
            int fid, tid;
            READ_INT(store, &fid);
            READ_INT(store, &tid);
            from = findregionbyid(fid);
            to = findregionbyid(tid);
            if (!to || !from) {
                log_warning("%s connection between incomplete regions %d and %d", zText, fid, tid);
                continue;
            }
        }

        type = find_bordertype(zText);
        if (type == NULL) {
            log_error("[read_borders] unknown connection type '%s' in %s\n", zText, regionname(from, NULL));
            assert(type || !"connection type not registered");
        }

        if (to == from && type && from) {
            direction_t dir = (direction_t)(rng_int() % MAXDIRECTIONS);
            region *r = rconnect(from, dir);
            log_error("[read_borders] invalid %s in %s\n", type->__name, regionname(from, NULL));
            if (r != NULL)
                to = r;
        }
        if ((type->read && !type->write)) {
            log_warning("ignore invalid border '%s' between '%s' and '%s'\n", zText, regionname(from, 0), regionname(to, 0));
        }
        else {
            connection *b = new_border(type, from, to);
            nextborder--;               /* new_border erhöht den Wert */
            b->id = bid;
            assert(bid <= nextborder);
            if (type->read) {
                type->read(b, data);
            }
            if (data->version < NOBORDERATTRIBS_VERSION) {
                attrib *a = NULL;
                int result = read_attribs(data, &a, b);
                if (border_convert_cb) {
                    border_convert_cb(b, a);
                }
                while (a) {
                    a_remove(&a, a);
                }
                if (result < 0) {
                    return result;
                }
            }
        }
    }
    return 0;
}
Beispiel #20
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();
}
Beispiel #21
0
static void move_iceberg(region * r)
{
  attrib *a;
  direction_t dir;
  region *rc;

  a = a_find(r->attribs, &at_iceberg);
  if (!a) {
    dir = (direction_t) (rng_int() % MAXDIRECTIONS);
    a = a_add(&r->attribs, make_iceberg(dir));
  } else {
    if (rng_int() % 100 < 20) {
      dir = (direction_t) (rng_int() % MAXDIRECTIONS);
      a->data.i = dir;
    } else {
      dir = (direction_t) a->data.i;
    }
  }

  rc = rconnect(r, dir);

  if (rc && !fval(rc->terrain, ARCTIC_REGION)) {
    if (fval(rc->terrain, SEA_REGION)) {        /* Eisberg treibt */
      ship *sh, *shn;
      unit *u;
      int x, y;

      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)) {
          fset(u->faction, FFL_SELECT);
          ADDMSG(&u->faction->msgs, msg_message("iceberg_drift",
              "region dir", r, dir));
        }

      x = r->x;
      y = r->y;

      runhash(r);
      runhash(rc);
      r->x = rc->x;
      r->y = rc->y;
      rc->x = x;
      rc->y = y;
      rhash(rc);
      rhash(r);

      /* rc ist der Ozean (Ex-Eisberg), r der Eisberg (Ex-Ozean) */

      /* Schiffe aus dem Zielozean werden in den Eisberg transferiert
       * und nehmen Schaden. */

      for (sh = r->ships; sh; sh = sh->next)
        freset(sh, SF_SELECT);

      for (sh = r->ships; sh; sh = sh->next) {
        /* Meldung an Kapitän */
        float dmg =
          get_param_flt(global.parameters, "rules.ship.damage.intoiceberg",
          0.10F);
        damage_ship(sh, dmg);
        fset(sh, SF_SELECT);
      }

      /* Personen, Schiffe und Gebäude verschieben */
      while (rc->buildings) {
        rc->buildings->region = r;
        translist(&rc->buildings, &r->buildings, rc->buildings);
      }
      while (rc->ships) {
        float dmg =
          get_param_flt(global.parameters, "rules.ship.damage.withiceberg",
          0.10F);
        fset(rc->ships, SF_SELECT);
        damage_ship(rc->ships, dmg);
        move_ship(rc->ships, rc, r, NULL);
      }
      while (rc->units) {
        building *b = rc->units->building;
        u = rc->units;
        u->building = 0; /* prevent leaving in move_unit */
        move_unit(rc->units, r, NULL);
        u_set_building(u, b); /* undo leave-prevention */
      }

      /* Beschädigte Schiffe können sinken */

      for (sh = r->ships; sh;) {
        shn = sh->next;
        if (fval(sh, SF_SELECT)) {
          u = ship_owner(sh);
          if (sh->damage >= sh->size * DAMAGE_SCALE) {
            if (u != NULL) {
              ADDMSG(&u->faction->msgs, msg_message("overrun_by_iceberg_des",
                  "ship", sh));
            }
            remove_ship(&sh->region->ships, sh);
          } else if (u != NULL) {
            ADDMSG(&u->faction->msgs, msg_message("overrun_by_iceberg",
                "ship", sh));
          }
        }
        sh = shn;
      }

    } else if (rng_int() % 100 < 20) {  /* Eisberg bleibt als Gletscher liegen */
      unit *u;

      rsetterrain(r, T_GLACIER);
      a_remove(&r->attribs, a);

      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)) {
          fset(u->faction, FFL_SELECT);
          ADDMSG(&u->faction->msgs, msg_message("iceberg_land", "region", r));
        }
    }
  }
}
Beispiel #22
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);
        }
      }
    } 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 */
  for (r = regions; r; r = r->next) {
    int i;

    if (fval(r, RF_CHAOTIC)) {
      chaos(r);
    }
    i = chaoscount(r);
    if (i) {
      chaoscounts(r, -(int)(i * ((double)(rng_int() % 10)) / 100.0));
    }
  }
#ifdef HERBS_ROT
  rotting_herbs();
#endif

  dissolve_units();
}
Beispiel #23
0
/* ------------------------------------------------------------- */
void remove_curse(attrib ** ap, const curse * c)
{
  attrib *a = a_select(*ap, c, cmp_curse);
  if (a)
    a_remove(ap, a);
}
Beispiel #24
0
void do_markets(void)
{
    quicklist *traders = 0;
    unit *markets[MAX_MARKETS];
    region *r;
    for (r = regions; r; r = r->next) {
        if (r->land) {
            faction *f = region_get_owner(r);
            const struct race *rc = f ? f->race : NULL;
            int p = rpeasants(r);
            int numlux = rc_luxury_trade(rc), numherbs = rc_herb_trade(rc);
            numlux = (p + numlux - MIN_PEASANTS) / numlux;
            numherbs = (p + numherbs - MIN_PEASANTS) / numherbs;
            if (numlux > 0 || numherbs > 0) {
                int d, nmarkets = 0;
                const item_type *lux = r_luxury(r);
                const item_type *herb = r->land->herbtype;

                nmarkets += get_markets(r, markets + nmarkets, MAX_MARKETS - nmarkets);
                for (d = 0; d != MAXDIRECTIONS; ++d) {
                    region *r2 = rconnect(r, d);
                    if (r2 && r2->buildings) {
                        nmarkets +=
                            get_markets(r2, markets + nmarkets, MAX_MARKETS - nmarkets);
                    }
                }
                if (nmarkets) {
                    while (lux && numlux--) {
                        int n = rng_int() % nmarkets;
                        unit *u = markets[n];
                        item *items;
                        attrib *a = a_find(u->attribs, &at_market);
                        if (a == NULL) {
                            a = a_add(&u->attribs, a_new(&at_market));
                            ql_push(&traders, u);
                        }
                        items = (item *)a->data.v;
                        i_change(&items, lux, 1);
                        a->data.v = items;
                        /* give 1 luxury */
                    }
                    while (herb && numherbs--) {
                        int n = rng_int() % nmarkets;
                        unit *u = markets[n];
                        item *items;
                        attrib *a = a_find(u->attribs, &at_market);
                        if (a == NULL) {
                            a = a_add(&u->attribs, a_new(&at_market));
                            ql_push(&traders, u);
                        }
                        items = (item *)a->data.v;
                        i_change(&items, herb, 1);
                        a->data.v = items;
                        /* give 1 herb */
                    }
                }
            }
        }
    }

    if (traders) {
        quicklist *qliter = traders;
        int qli = 0;
        for (qli = 0; qliter; ql_advance(&qliter, &qli, 1)) {
            unit *u = (unit *)ql_get(qliter, qli);
            attrib *a = a_find(u->attribs, &at_market);
            item *items = (item *)a->data.v;

            a->data.v = NULL;
            while (items) {
                item *itm = items;
                items = itm->next;

                if (itm->number) {
                    ADDMSG(&u->faction->msgs, msg_message("buyamount",
                        "unit amount resource", u, itm->number, itm->type->rtype));
                    itm->next = NULL;
                    i_add(&u->items, itm);
                }
                else {
                    i_free(itm);
                }
            }

            a_remove(&u->attribs, a);
        }
        ql_free(traders);
    }
}
Beispiel #25
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;
}