Пример #1
0
void test_buildingowner_goes_to_empty_unit_after_leave(CuTest * tc)
{
    struct region *r;
    struct building *bld;
    struct unit *u1, *u2, *u3;
    struct faction *f1;

    test_setup();

    f1 = test_create_faction(NULL);
    r = test_create_plain(0, 0);

    bld = test_create_building(r, NULL);
    CuAssertPtrNotNull(tc, bld);

    u1 = test_create_unit(f1, r);
    u2 = test_create_unit(f1, r);
    u3 = test_create_unit(f1, r);
    u_set_building(u1, bld);
    u_set_building(u2, bld);
    u_set_building(u3, bld);

    CuAssertPtrEquals(tc, u1, building_owner(bld));
    u2->number = 0;
    leave_building(u1);
    CuAssertPtrEquals(tc, u3, building_owner(bld));
    leave_building(u3);
    CuAssertPtrEquals(tc, NULL, building_owner(bld));
    u2->number = 1;
    CuAssertPtrEquals(tc, u2, building_owner(bld));
    test_teardown();
}
Пример #2
0
static void test_buildingowner_goes_to_other_when_empty(CuTest * tc)
{
    struct region *r;
    struct building *bld;
    struct unit *u, *u2;
    struct faction *f;

    test_setup();

    f = test_create_faction(NULL);
    r = test_create_plain(0, 0);

    bld = test_create_building(r, NULL);
    CuAssertPtrNotNull(tc, bld);

    u2 = test_create_unit(f, r);
    u = test_create_unit(f, r);
    CuAssertPtrNotNull(tc, u);
    u_set_building(u, bld);
    CuAssertPtrEquals(tc, u, building_owner(bld));
    u_set_building(u2, bld);
    CuAssertPtrEquals(tc, u, building_owner(bld));
    u->number = 0;
    CuAssertPtrEquals(tc, u2, building_owner(bld));
    test_teardown();
}
Пример #3
0
static void test_buildingowner_goes_to_same_faction_after_leave(CuTest * tc)
{
    struct region *r;
    struct building *bld;
    struct unit *u, *u2, *u3;
    struct faction *f1, *f2;

    test_setup();

    f1 = test_create_faction(NULL);
    f2 = test_create_faction(NULL);
    r = test_create_plain(0, 0);

    bld = test_create_building(r, NULL);
    CuAssertPtrNotNull(tc, bld);

    u2 = test_create_unit(f2, r);
    u3 = test_create_unit(f1, r);
    u = test_create_unit(f1, r);
    CuAssertPtrNotNull(tc, u);
    u_set_building(u, bld);
    u_set_building(u2, bld);
    u_set_building(u3, bld);
    CuAssertPtrEquals(tc, u, building_owner(bld));
    leave_building(u);
    CuAssertPtrEquals(tc, u3, building_owner(bld));
    leave_building(u3);
    CuAssertPtrEquals(tc, u2, building_owner(bld));
    leave_building(u2);
    CuAssertPtrEquals(tc, NULL, building_owner(bld));
    test_teardown();
}
Пример #4
0
static unit *building_owner_ex(const building * bld, const struct faction * last_owner)
{
    unit *u, *heir = 0;
    /* Eigentümer tot oder kein Eigentümer vorhanden. Erste lebende Einheit
      * nehmen. */
    for (u = bld->region->units; u; u = u->next) {
        if (u->building == bld) {
            if (u->number > 0) {
                if (heir && last_owner && heir->faction != last_owner && u->faction == last_owner) {
                    heir = u;
                    break; /* we found someone from the same faction who is not dead. let's take this guy */
                }
                else if (!heir) {
                    heir = u; /* you'll do in an emergency */
                }
            }
        }
    }
    if (!heir && config_token("rules.region_owner_pay_building", bld->type->_name)) {
        if (rule_region_owners()) {
            u = building_owner(largestbuilding(bld->region, &cmp_taxes, false));
        }
        else {
            u = building_owner(largestbuilding(bld->region, &cmp_wage, false));
        }
        if (u) {
            heir = u;
        }
    }
    return heir;
}
Пример #5
0
int bt_effsize(const building_type * btype, const building * b, int bsize)
{
    int i = bsize, n = 0;
    const construction *cons = btype->construction;

    /* TECH DEBT: simplest thing that works for E3 dwarf/halfling faction rules */
    if (b && config_get_int("rules.dwarf_castles", 0)
        && strcmp(btype->_name, "castle") == 0) {
        unit *u = building_owner(b);
        if (u && u->faction->race == get_race(RC_HALFLING)) {
            i = bsize * 10 / 8;
        }
    }

    if (!cons || !cons->improvement) {
        return 0;
    }

    while (cons && cons->maxsize != -1 && i >= cons->maxsize) {
        i -= cons->maxsize;
        cons = cons->improvement;
        ++n;
    }

    return n;
}
Пример #6
0
static int tolua_building_get_owner(lua_State * L)
{
    building *b = (building *)tolua_tousertype(L, 1, 0);
    unit *u = b ? building_owner(b) : NULL;
    tolua_pushusertype(L, u, TOLUA_CAST "unit");
    return 1;
}
Пример #7
0
static void test_give_control_building(CuTest * tc)
{
    unit *u1, *u2;
    building *b;
    struct faction *f;
    region *r;

    test_cleanup();
    f = test_create_faction(0);
    r = test_create_region(0, 0, 0);
    b = test_create_building(r, 0);
    u1 = test_create_unit(f, r);
    u_set_building(u1, b);
    u2 = test_create_unit(f, r);
    u_set_building(u2, b);
    CuAssertPtrEquals(tc, u1, building_owner(b));
    give_control(u1, u2);
    CuAssertPtrEquals(tc, u2, building_owner(b));
    test_cleanup();
}
Пример #8
0
void randomevents(void)
{
    region *r;
    faction *monsters = get_monsters();

    icebergs();
    godcurse();
    orc_growth();
    demon_skillchanges();
    volcano_update();
    /* Monumente zerfallen, Schiffe verfaulen */

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

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

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

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

    dissolve_units();
}
Пример #9
0
faction *update_owners(region * r)
{
    faction *f = NULL;
    assert(rule_region_owners());
    if (r->land) {
        building *bowner = largestbuilding(r, &cmp_current_owner, false);
        building *blargest = largestbuilding(r, &cmp_taxes, false);
        if (blargest) {
            if (!bowner || bowner->size < blargest->size) {
                /* region owners update? */
                unit *u = building_owner(blargest);
                f = region_get_owner(r);
                if (u == NULL) {
                    if (f) {
                        region_set_owner(r, NULL, turn);
                        r->land->ownership->flags |= OWNER_MOURNING;
                        f = NULL;
                    }
                }
                else if (u->faction != f) {
                    if (!r->land->ownership) {
                        /* there has never been a prior owner */
                        region_set_morale(r, MORALE_DEFAULT, turn);
                    }
                    else {
                        alliance *al = region_get_alliance(r);
                        if (al && u->faction->alliance == al) {
                            int morale = _max(0, r->land->morale - MORALE_TRANSFER);
                            region_set_morale(r, morale, turn);
                        }
                        else {
                            region_set_morale(r, MORALE_TAKEOVER, turn);
                            if (f) {
                                r->land->ownership->flags |= OWNER_MOURNING;
                            }
                        }
                    }
                    region_set_owner(r, u->faction, turn);
                    f = u->faction;
                }
            }
        }
        else if (r->land->ownership && r->land->ownership->owner) {
            r->land->ownership->flags |= OWNER_MOURNING;
            region_set_owner(r, NULL, turn);
            f = NULL;
        }
    }
    return f;
}
Пример #10
0
static void test_building_set_owner(CuTest * tc)
{
    struct region *r;
    struct building *bld;
    struct unit *u1, *u2;
    struct faction *f;

    test_setup();

    f = test_create_faction(NULL);
    r = test_create_region(0, 0, NULL);

    bld = test_create_building(r, NULL);
    u1 = test_create_unit(f, r);
    u_set_building(u1, bld);
    CuAssertPtrEquals(tc, u1, building_owner(bld));

    u2 = test_create_unit(f, r);
    u_set_building(u2, bld);
    CuAssertPtrEquals(tc, u1, building_owner(bld));
    building_set_owner(u2);
    CuAssertPtrEquals(tc, u2, building_owner(bld));
    test_teardown();
}
Пример #11
0
bool can_leave(unit * u)
{
  static int gamecookie = -1;
  static int rule_leave = -1;

  if (!u->building) {
    return true;
  }

  if (rule_leave < 0 || gamecookie != global.cookie) {
    gamecookie = global.cookie;
    rule_leave = get_param_int(global.parameters, "rules.move.owner_leave", 0);
  }

  if (rule_leave && u->building && u == building_owner(u->building)) {
    return false;
  }
  return true;
}
Пример #12
0
static bool is_guardian_r(const unit * guard)
{
    if (guard->number == 0)
        return false;
    if (besieged(guard))
        return false;

    /* if region_owners exist then they may be guardians: */
    if (guard->building && rule_region_owners() && guard == building_owner(guard->building)) {
        faction *owner = region_get_owner(guard->region);
        if (owner == guard->faction) {
            building *bowner = largestbuilding(guard->region, &cmp_taxes, false);
            if (bowner == guard->building) {
                return true;
            }
        }
    }

    if ((guard->flags & UFL_GUARD) == 0)
        return false;
    return fval(u_race(guard), RCF_UNARMEDGUARD) || is_monsters(guard->faction) || (armedmen(guard, true) > 0);
}
Пример #13
0
int lighthouse_range(const building * b, const faction * f)
{
    int d = 0;
    if (fval(b, BLD_MAINTAINED) && b->size >= 10) {
        int maxd = (int)log10(b->size) + 1;

        if (skill_enabled(SK_PERCEPTION)) {
            region *r = b->region;
            int c = 0;
            int cap = buildingcapacity(b);
            unit *u, *uown = building_owner(b);

            for (u = r->units; u; u = u->next) {
                if (u->building == b || u == uown) {
                    c += u->number;
                    if (c > cap) {
                        break;
                    }
                    else if (f == NULL || u->faction == f) {
                        int sk = effskill(u, SK_PERCEPTION, 0) / 3;
                        d = _max(d, sk);
                        d = _min(maxd, d);
                        if (d == maxd)
                            break;
                    }
                }
                else if (c)
                    break;                /* first unit that's no longer in the house ends the search */
            }
        }
        else {
            /* E3A rule: no perception req'd */
            return maxd;
        }
    }
    return d;
}
Пример #14
0
static unsigned int get_markets(region * r, unit ** results, size_t size)
{
    unsigned int n = 0;
    building *b;
    const building_type *btype = bt_find("market");
    if (!btype)
        return 0;
    for (b = r->buildings; n < size && b; b = b->next) {
        if (b->type == btype && building_is_active(b)) {
            unit *u = building_owner(b);
            /* I decided to omit check for inside_building(u) */
            unsigned int i;
            for (i = 0; u && i != n; ++i) {
                /* only one market per faction */
                if (results[i]->faction == u->faction)
                    u = NULL;
            }
            if (u) {
                results[n++] = u;
            }
        }
    }
    return n;
}
Пример #15
0
static unsigned int get_markets(region * r, unit ** results, size_t size)
{
    unsigned int n = 0;
    building *b;
    const building_type *btype = bt_find("market");
    if (!btype)
        return 0;
    for (b = r->buildings; n < size && b; b = b->next) {
        if (b->type == btype && (b->flags & BLD_WORKING)
            && b->size >= b->type->maxsize) {
            unit *u = building_owner(b);
            unsigned int i;
            for (i = 0; u && i != n; ++i) {
                /* only one market per faction */
                if (results[i]->faction == u->faction)
                    u = NULL;
            }
            if (u) {
                results[n++] = u;
            }
        }
    }
    return n;
}
Пример #16
0
int
build_building(unit * u, const building_type * btype, int id, int want, order * ord)
{
    region *r = u->region;
    int n = want, built = 0;
    building *b = NULL;
    /* einmalige Korrektur */
    const char *btname;
    order *new_order = NULL;
    const struct locale *lang = u->faction->locale;
    static int rule_other = -1;

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

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

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

    if (b)
        btype = b->type;

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

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

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

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

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

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

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

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

    update_lighthouse(b);

    ADDMSG(&u->faction->msgs, msg_message("buildbuilding",
        "building unit size", b, u, built));
    return built;
}
Пример #17
0
int destroy_cmd(unit * u, struct order *ord)
{
    char token[128];
    ship *sh;
    unit *u2;
    region *r = u->region;
    const construction *con = NULL;
    int size = 0;
    const char *s;
    int n = INT_MAX;

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

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

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

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

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

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

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

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

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

    if (con) {
        /* TODO: Nicht an ZERSTÖRE mit Punktangabe angepaßt! */
        int c;
        for (c = 0; con->materials[c].number; ++c) {
            const requirement *rq = con->materials + c;
            int recycle = (rq->number * size / con->reqsize) / 2;
            if (recycle) {
                change_resource(u, rq->rtype, recycle);
            }
        }
    }
    return 0;
}
Пример #18
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();
}