Пример #1
0
faction *gm_addquest(const char *email, const char *name, int radius,
  unsigned int flags)
{
  plane *pl;
  watcher *w = calloc(sizeof(watcher), 1);
  region *center;
  bool invalid = false;
  int minx, miny, maxx, maxy, cx, cy;
  int x;
  faction *f;

  /* GM playfield */
  do {
    minx = ((rng_int() % (2 * EXTENSION)) - EXTENSION);
    miny = ((rng_int() % (2 * EXTENSION)) - EXTENSION);
    for (x = 0; !invalid && x <= radius * 2; ++x) {
      int y;
      for (y = 0; !invalid && y <= radius * 2; ++y) {
        region *r = findregion(minx + x, miny + y);
        if (r)
          invalid = true;
      }
    }
  } while (invalid);
  maxx = minx + 2 * radius;
  cx = minx + radius;
  maxy = miny + 2 * radius;
  cy = miny + radius;
  pl = create_new_plane(rng_int(), name, minx, maxx, miny, maxy, flags);
  center = new_region(cx, cy, pl, 0);
  for (x = 0; x <= 2 * radius; ++x) {
    int y;
    for (y = 0; y <= 2 * radius; ++y) {
      region *r = findregion(minx + x, miny + y);
      if (!r) {
        r = new_region(minx + x, miny + y, pl, 0);
      }
      freset(r, RF_ENCOUNTER);
      if (distance(r, center) == radius) {
        terraform_region(r, newterrain(T_FIREWALL));
      } else if (r == center) {
        terraform_region(r, newterrain(T_PLAIN));
      } else {
        terraform_region(r, newterrain(T_OCEAN));
      }
    }
  }

  /* watcher: */
  f = gm_addfaction(email, pl, center);
  w->faction = f;
  w->mode = see_unit;
  w->next = pl->watchers;
  pl->watchers = w;

  return f;
}
Пример #2
0
static void melt_iceberg(region * r)
{
  attrib *a;
  unit *u;

  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_melt", "region", r));
    }

  /* driftrichtung löschen */
  a = a_find(r->attribs, &at_iceberg);
  if (a)
    a_remove(&r->attribs, a);

  /* Gebäude löschen */
  while (r->buildings) {
    remove_building(&r->buildings, r->buildings);
  }

  /* in Ozean wandeln */
  terraform_region(r, newterrain(T_OCEAN));

  /* Einheiten, die nicht schwimmen können oder in Schiffen sind,
   * ertrinken */
  drown(r);
}
Пример #3
0
plane *gm_addplane(int radius, unsigned int flags, const char *name)
{
  region *center;
  plane *pl;
  bool invalid = false;
  int minx, miny, maxx, maxy, cx, cy;
  int x;

  /* GM playfield */
  do {
    minx = (rng_int() % (2 * EXTENSION)) - EXTENSION;
    miny = (rng_int() % (2 * EXTENSION)) - EXTENSION;
    for (x = 0; !invalid && x <= radius * 2; ++x) {
      int y;
      for (y = 0; !invalid && y <= radius * 2; ++y) {
        region *r = findregion(minx + x, miny + y);
        if (r)
          invalid = true;
      }
    }
  } while (invalid);
  maxx = minx + 2 * radius;
  cx = minx + radius;
  maxy = miny + 2 * radius;
  cy = miny + radius;
  pl = create_new_plane(rng_int(), name, minx, maxx, miny, maxy, flags);
  center = new_region(cx, cy, pl, 0);
  for (x = 0; x <= 2 * radius; ++x) {
    int y;
    for (y = 0; y <= 2 * radius; ++y) {
      region *r = findregion(minx + x, miny + y);
      if (!r)
        r = new_region(minx + x, miny + y, pl, 0);
      freset(r, RF_ENCOUNTER);
      if (distance(r, center) == radius) {
        terraform_region(r, newterrain(T_FIREWALL));
      } else if (r == center) {
        terraform_region(r, newterrain(T_PLAIN));
      } else {
        terraform_region(r, newterrain(T_OCEAN));
      }
    }
  }
  return pl;
}
Пример #4
0
int skill_mod(const race * rc, skill_t sk, const struct terrain_type *terrain)
{
    int result = 0;

    result = rc->bonus[sk];

    if (rc == get_race(RC_DWARF)) {
        if (sk == SK_TACTICS) {
            if (terrain == newterrain(T_MOUNTAIN) || fval(terrain, ARCTIC_REGION))
                ++result;
        }
    }
    else if (rc == get_race(RC_INSECT)) {
        if (terrain == newterrain(T_MOUNTAIN) || fval(terrain, ARCTIC_REGION))
            --result;
        else if (terrain == newterrain(T_DESERT) || terrain == newterrain(T_SWAMP))
            ++result;
    }

    return result;
}
Пример #5
0
/** Drachen und Seeschlangen können entstehen */
void spawn_dragons(void)
{
    region *r;
    faction *monsters = get_or_create_monsters();

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

        if (fval(r->terrain, SEA_REGION) && rng_int() % 10000 < 1) {
            u = create_unit(r, monsters, 1, get_race(RC_SEASERPENT), 0, NULL, NULL);
            fset(u, UFL_ISNEW | UFL_MOVED);
            equip_unit(u, get_equipment("monster_seaserpent"));
        }

        if ((r->terrain == newterrain(T_GLACIER)
            || r->terrain == newterrain(T_SWAMP)
            || r->terrain == newterrain(T_DESERT))
            && rng_int() % 10000 < (5 + 100 * chaosfactor(r))) {
            if (chance(0.80)) {
                u = create_unit(r, monsters, nrand(60, 20) + 1, get_race(RC_FIREDRAGON), 0, NULL, NULL);
            }
            else {
                u = create_unit(r, monsters, nrand(30, 20) + 1, get_race(RC_DRAGON), 0, NULL, NULL);
            }
            fset(u, UFL_ISNEW | UFL_MOVED);
            equip_unit(u, get_equipment("monster_dragon"));

            log_debug("spawning %d %s in %s.\n", u->number,
                LOC(default_locale,
                rc_name_s(u_race(u), (u->number == 1) ? NAME_SINGULAR : NAME_PLURAL)), regionname(r, NULL));

            name_unit(u);

            /* add message to the region */
            ADDMSG(&r->msgs,
                msg_message("sighting", "region race number", r, u_race(u), u->number));
        }
    }
}
Пример #6
0
static const terrain_type *preferred_terrain(const struct race *rc)
{
    terrain_t t = T_PLAIN;
    if (rc == rc_find("dwarf"))
        t = T_MOUNTAIN;
    if (rc == rc_find("insect"))
        t = T_DESERT;
    if (rc == rc_find("halfling"))
        t = T_SWAMP;
    if (rc == rc_find("troll"))
        t = T_MOUNTAIN;
    return newterrain(t);
}
Пример #7
0
static struct skillmods *init_skills(const race * rc)
{
    terrain_t t;
    struct skillmods *mods =
        (struct skillmods *)calloc(1, sizeof(struct skillmods));
    mods->race = rc;

    for (t = 0; t != MAXTERRAINS; ++t) {
        skill_t sk;
        for (sk = 0; sk != MAXSKILLS; ++sk) {
            mods->mod[t].value[sk] = skill_mod(rc, sk, newterrain(t));
        }
    }
    return mods;
}
Пример #8
0
int region_quality(const region * r, region * rn[])
{
    int n, result = 0;

    for (n = 0; n != MAXDIRECTIONS; ++n) {
        if (rn[n] && rn[n]->land) {
            if (rn[n]->terrain == newterrain(T_VOLCANO)) {
                /* nobody likes volcanoes */
                result -= 2000;
            }
            result += rn[n]->land->peasants;
        }
    }
    return result;
}
Пример #9
0
static void oceans_around(region * r, region * rn[])
{
    int n;
    for (n = 0; n != MAXDIRECTIONS; ++n) {
        region *rx = rn[n];
        if (rx == NULL) {
            plane *pl = rplane(r);
            int x = r->x + delta_x[n];
            int y = r->y + delta_y[n];
            pnormalize(&x, &y, pl);
            rx = new_region(x, y, pl, 0);
            terraform_region(rx, newterrain(T_OCEAN));
            rn[n] = rx;
        }
    }
}
Пример #10
0
const terrain_type *random_terrain_e3(direction_t dir)
{
    static const terrain_type **terrainarr = 0;
    static int *distribution = 0;

    if (!distribution) {
        int n = 0;

        terrainarr = malloc(GEOMAX * sizeof(const terrain_type *));
        distribution = malloc(GEOMAX * sizeof(int));
        for (n = 0; n != GEOMAX; ++n) {
            terrainarr[n] = newterrain(geography_e3[n].type);
            distribution[n] = geography_e3[n].distribution;
        }
    }
    return random_terrain(terrainarr, distribution, GEOMAX);
}
Пример #11
0
static void eaten_by_monster(unit * u)
{
  /* adjustment for smaller worlds */
  static double multi = 0.0;
  int n = 0;
  int horse = 0;

  if (multi == 0.0) {
    multi = RESOURCE_QUANTITY * newterrain(T_PLAIN)->size / 10000.0;
  }

  switch (old_race(u_race(u))) {
    case RC_FIREDRAGON:
      n = rng_int() % 80 * u->number;
      horse = get_item(u, I_HORSE);
      break;
    case RC_DRAGON:
      n = rng_int() % 200 * u->number;
      horse = get_item(u, I_HORSE);
      break;
    case RC_WYRM:
      n = rng_int() % 500 * u->number;
      horse = get_item(u, I_HORSE);
      break;
    default:
      n = rng_int() % (u->number / 20 + 1);
  }

  n = (int)(n * multi);
  if (n > 0) {
    n = lovar(n);
    n = MIN(rpeasants(u->region), n);

    if (n > 0) {
      deathcounts(u->region, n);
      rsetpeasants(u->region, rpeasants(u->region) - n);
      ADDMSG(&u->region->msgs, msg_message("eatpeasants", "unit amount", u, n));
    }
  }
  if (horse > 0) {
    set_item(u, I_HORSE, 0);
    ADDMSG(&u->region->msgs, msg_message("eathorse", "unit amount", u, horse));
  }
}
Пример #12
0
static void move_icebergs(void)
{
  region *r;

  for (r = regions; r; r = r->next) {
    if (r->terrain == newterrain(T_ICEBERG) && !fval(r, RF_SELECT)) {
      int select = rng_int() % 10;
      if (select < 4) {
        /* 4% chance */
        fset(r, RF_SELECT);
        melt_iceberg(r);
      } else if (select < 64) {
        /* 60% chance */
        fset(r, RF_SELECT);
        move_iceberg(r);
      }
    }
  }
}
Пример #13
0
static void starting_region(newfaction ** players, region * r, region * rn[])
{
    int n;
    oceans_around(r, rn);
    freset(r, RF_MARK);
    for (n = 0; n != MAXDIRECTIONS; ++n) {
        freset(rn[n], RF_MARK);
    }
    terraform_region(r, newterrain(T_PLAIN));
    prepare_starting_region(r);
    if (players && *players) {
        newfaction *nf = *players;
        const struct race *rc = nf->race ? nf->race : races;
        const struct locale *lang = nf->lang ? nf->lang : default_locale;
        const char * passwd = nf->password ? nf->password : itoa36(rng_int());
        addplayer(r, addfaction(nf->email, passwd, rc, lang, 0));
        *players = nf->next;
        free_newfaction(nf);
    }
}
Пример #14
0
void create_icebergs(void)
{
  region *r;

  for (r = regions; r; r = r->next) {
    if (r->terrain == newterrain(T_ICEBERG_SLEEP) && chance(0.05)) {
      bool has_ocean_neighbour = false;
      direction_t dir;
      region *rc;
      unit *u;

      freset(r, RF_SELECT);
      for (dir = 0; dir < MAXDIRECTIONS; dir++) {
        rc = rconnect(r, dir);
        if (rc && fval(rc->terrain, SEA_REGION)) {
          has_ocean_neighbour = true;
          break;
        }
      }
      if (!has_ocean_neighbour)
        continue;

      rsetterrain(r, T_ICEBERG);

      fset(r, RF_SELECT);
      move_iceberg(r);

      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_create", "region", r));
        }
      }
    }
  }
}
Пример #15
0
/* E3A island generation */
int build_island_e3(newfaction ** players, int x, int y, int numfactions, int minsize)
{
#define MIN_QUALITY 1000
    int nfactions = 0;
    region_list *rlist = NULL;
    region_list *island = NULL;
    plane *pl = findplane(x, y);
    region *r = findregion(x, y);
    int nsize = 1;
    int q, maxq = INT_MIN, minq = INT_MAX;

    if (!r)
        r = new_region(x, y, pl, 0);
    assert(!r->units);
    do {
        terraform_region(r, random_terrain_e3(NODIRECTION));
    } while (!r->land);

    while (r) {
        fset(r, RF_MARK);
        if (r->land) {
            if (nsize < minsize) {
                nsize += random_neighbours(r, &rlist, &random_terrain_e3);
            }
            else {
                nsize += random_neighbours(r, &rlist, &get_ocean);
            }
        }
        regionqueue_push(&island, r);
        r = regionqueue_pop(&rlist);
    }

    smooth_island(island);

    if (nsize > minsize / 2) {
        for (rlist = island; rlist; rlist = rlist->next) {
            r = rlist->data;
            if (r->land && fval(r, RF_MARK)) {
                region *rn[MAXDIRECTIONS];

                get_neighbours(r, rn);
                q = region_quality(r, rn);
                if (q >= MIN_QUALITY && nfactions < numfactions && *players) {
                    starting_region(players, r, rn);
                    minq = _min(minq, q);
                    maxq = _max(maxq, q);
                    ++nfactions;
                }
            }
        }

        for (rlist = island; rlist && nfactions < numfactions; rlist = rlist->next) {
            r = rlist->data;
            if (!r->land && fval(r, RF_MARK)) {
                region *rn[MAXDIRECTIONS];
                get_neighbours(r, rn);
                q = region_quality(r, rn);
                if (q >= MIN_QUALITY * 4 / 3 && nfactions < numfactions && *players) {
                    starting_region(players, r, rn);
                    minq = _min(minq, q);
                    maxq = _max(maxq, q);
                    ++nfactions;
                }
            }
        }
    }

    for (rlist = island; rlist; rlist = rlist->next) {
        r = rlist->data;
        if (r->units) {
            region *rn[MAXDIRECTIONS];
            get_neighbours(r, rn);
            q = region_quality(r, rn);
            if (q - minq > (maxq - minq) * 2 / 3) {
                terraform_region(r, newterrain(T_HIGHLAND));
                prepare_starting_region(r);
            }
            r->land->money = 50000;   /* 2% = 1000 silver */
        }
        else if (r->land) {
            r->land->money *= 4;
        }
    }
    return nfactions;
}
Пример #16
0
/** create new island with up to nsize players
 * returns the number of players placed on the new island.
 */
int autoseed(newfaction ** players, int nsize, int max_agediff)
{
    region *r = NULL;
    region_list *rlist = NULL;
    int rsize = 0, tsize = 0;
    int isize = REGIONS_PER_FACTION;      /* target size for the island */
    int psize = 0;                /* players on this island */
    const terrain_type *volcano_terrain = get_terrain("volcano");
    static int nterrains = -1;
    static const terrain_type **terrainarr = 0;
    static int *distribution;

    assert(players);
    if (nterrains < 0) {
        int n = 0;
        const terrain_type *terrain = terrains();
        for (nterrains = 0; terrain; terrain = terrain->next) {
            if (terrain->distribution) {
                ++nterrains;
            }
        }
        terrainarr = malloc(sizeof(terrain_type *) * nterrains);
        distribution = malloc(sizeof(int) * nterrains);
        for (terrain = terrains(); terrain; terrain = terrain->next) {
            if (terrain->distribution) {
                terrainarr[n] = terrain;
                distribution[n++] = terrain->distribution;
            }
        }
    }
    frame_regions(16, newterrain(T_FIREWALL));

    if (listlen(*players) < MINFACTIONS)
        return 0;

    if (max_agediff > 0) {
        region *rmin = NULL;
        plane *hplane = get_homeplane();
        /* find a spot that's adjacent to the previous island, but virgin.
         * like the last land virgin ocean region adjacent to land.
         */
        for (r = regions; r; r = r->next) {
            struct plane *pl = rplane(r);
            if (r->age <= max_agediff && r->terrain == newterrain(T_OCEAN)
                && pl == hplane && virgin_region(r)) {
                direction_t d;
                for (d = 0; d != MAXDIRECTIONS; ++d) {
                    region *rn = rconnect(r, d);
                    if (rn && rn->land && rn->age <= max_agediff && virgin_region(rn)) {
                        /* only expand islands that aren't single-islands and not too big already */
                        int size, inhabitants, maxage;
                        get_island_info(rn, &size, &inhabitants, &maxage);
                        if (maxage <= max_agediff && size >= 2 && size < MAXISLANDSIZE) {
                            rmin = rn;
                            break;
                        }
                    }
                }
            }
        }
        if (rmin != NULL) {
            faction *f;
            quicklist *ql, *rlist = get_island(rmin);
            int qi;

            for (ql = rlist, qi = 0; ql; ql_advance(&ql, &qi, 1)) {
                region *r = (region *)ql_get(ql, qi);
                unit *u;
                for (u = r->units; u; u = u->next) {
                    f = u->faction;
                    if (!fval(f, FFL_MARK)) {
                        ++psize;
                        fset(f, FFL_MARK);
                    }
                }
            }
            ql_free(rlist);
            if (psize > 0) {
                for (f = factions; f; f = f->next) {
                    freset(f, FFL_MARK);
                }
            }
            if (psize < PLAYERS_PER_ISLAND) {
                r = rmin;
            }
        }
    }
    if (r == NULL) {
        region *rmin = NULL;
        direction_t dmin = MAXDIRECTIONS;
        plane *hplane = get_homeplane();
        /* find an empty spot.
         * rmin = the youngest ocean region that has a missing neighbour
         * dmin = direction in which it's empty
         */
        for (r = regions; r; r = r->next) {
            struct plane *pl = rplane(r);
            if (r->terrain == newterrain(T_OCEAN) && pl == hplane && (rmin == NULL
                || r->age <= max_agediff)) {
                direction_t d;
                for (d = 0; d != MAXDIRECTIONS; ++d) {
                    region *rn = rconnect(r, d);
                    if (rn == NULL)
                        break;
                }
                if (d != MAXDIRECTIONS) {
                    rmin = r;
                    dmin = d;
                }
            }
        }

        /* create a new region where we found the empty spot, and make it the first
         * in our island. island regions are kept in rlist, so only new regions can
         * get populated, and old regions are not overwritten */
        if (rmin != NULL) {
            plane *pl = rplane(rmin);
            int x = rmin->x + delta_x[dmin];
            int y = rmin->y + delta_y[dmin];
            pnormalize(&x, &y, pl);
            assert(virgin_region(rconnect(rmin, dmin)));
            r = new_region(x, y, pl, 0);
            terraform_region(r, newterrain(T_OCEAN));
        }
    }
    if (r != NULL) {
        add_regionlist(&rlist, r);
        fset(r, RF_MARK);
        rsize = 1;
    }

    while (rsize && (nsize || isize >= REGIONS_PER_FACTION)) {
        int i = rng_int() % rsize;
        region_list **rnext = &rlist;
        region_list *rfind;
        direction_t d;
        while (i--)
            rnext = &(*rnext)->next;
        rfind = *rnext;
        r = rfind->data;
        freset(r, RF_MARK);
        *rnext = rfind->next;
        free(rfind);
        --rsize;
        for (d = 0; d != MAXDIRECTIONS; ++d) {
            region *rn = rconnect(r, d);
            if (rn && fval(rn, RF_MARK))
                continue;
            if (rn == NULL) {
                plane *pl = rplane(r);
                int x = r->x + delta_x[d];
                int y = r->y + delta_y[d];
                pnormalize(&x, &y, pl);
                rn = new_region(x, y, pl, 0);
                terraform_region(rn, newterrain(T_OCEAN));
            }
            if (virgin_region(rn)) {
                add_regionlist(&rlist, rn);
                fset(rn, RF_MARK);
                ++rsize;
            }
        }
        if (volcano_terrain != NULL && (rng_int() % VOLCANO_CHANCE == 0)) {
            terraform_region(r, volcano_terrain);
        }
        else if (nsize && (rng_int() % isize == 0 || rsize == 0)) {
            newfaction **nfp, *nextf = *players;
            faction *f;
            unit *u;

            isize += REGIONS_PER_FACTION;
            terraform_region(r, preferred_terrain(nextf->race));
            prepare_starting_region(r);
            ++tsize;
            assert(r->land && r->units == 0);
            u = addplayer(r, addfaction(nextf->email, nextf->password, nextf->race,
                nextf->lang, nextf->subscription));
            f = u->faction;
            fset(f, FFL_ISNEW);
            f->alliance = nextf->allies;

            /* remove duplicate email addresses */
            nfp = &nextf->next;
            while (*nfp) {
                newfaction *nf = *nfp;
                if (strcmp(nextf->email, nf->email) == 0) {
                    *nfp = nf->next;
                    free_newfaction(nf);
                }
                else
                    nfp = &nf->next;
            }
            *players = nextf->next;
            free_newfaction(nextf);

            ++psize;
            --nsize;
            --isize;
            if (psize >= PLAYERS_PER_ISLAND)
                break;
        }
        else {
            terraform_region(r, random_terrain(terrainarr, distribution, nterrains));
            --isize;
        }
    }

    if (nsize != 0) {
        log_error(
            ("Could not place all factions on the same island as requested\n"));
    }

    if (rlist) {
#define MINOCEANDIST 3
#define MAXOCEANDIST 6
#define MAXFILLDIST 10
#define SPECIALCHANCE 80
        region_list **rbegin = &rlist;
        int special = 1;
        int oceandist = MINOCEANDIST + (rng_int() % (MAXOCEANDIST - MINOCEANDIST));
        while (oceandist--) {
            region_list **rend = rbegin;
            while (*rend)
                rend = &(*rend)->next;
            while (rbegin != rend) {
                direction_t d;
                region *r = (*rbegin)->data;
                rbegin = &(*rbegin)->next;
                for (d = 0; d != MAXDIRECTIONS; ++d) {
                    region *rn = rconnect(r, d);
                    if (rn == NULL) {
                        const struct terrain_type *terrain = newterrain(T_OCEAN);
                        plane *pl = rplane(r);
                        int x = r->x + delta_x[d];
                        int y = r->y + delta_y[d];
                        pnormalize(&x, &y, pl);
                        rn = new_region(x, y, pl, 0);
                        if (rng_int() % SPECIALCHANCE < special) {
                            terrain = random_terrain(terrainarr, distribution, nterrains);
                            special = SPECIALCHANCE / 3;      /* 33% chance auf noch eines */
                        }
                        else {
                            special = 1;
                        }
                        terraform_region(rn, terrain);
                        /* the new region has an extra 20% chance to have mallorn */
                        if (rng_int() % 100 < 20)
                            fset(r, RF_MALLORN);
                        add_regionlist(rend, rn);
                    }
                }
            }

        }
        while (*rbegin) {
            region *r = (*rbegin)->data;
            plane *pl = rplane(r);
            direction_t d;
            rbegin = &(*rbegin)->next;
            for (d = 0; d != MAXDIRECTIONS; ++d)
                if (rconnect(r, d) == NULL) {
                    int i;
                    for (i = 1; i != MAXFILLDIST; ++i) {
                        int x = r->x + delta_x[d] * i;
                        int y = r->y + delta_y[d] * i;
                        pnormalize(&x, &y, pl);
                        if (findregion(x, y)) {
                            break;
                        }
                    }
                    if (i != MAXFILLDIST) {
                        while (--i) {
                            region *rn;
                            int x = r->x + delta_x[d] * i;
                            int y = r->y + delta_y[d] * i;
                            pnormalize(&x, &y, pl);
                            rn = new_region(x, y, pl, 0);
                            terraform_region(rn, newterrain(T_OCEAN));
                        }
                    }
                }
        }
        while (rlist) {
            region_list *self = rlist;
            rlist = rlist->next;
            freset(self->data, RF_MARK);
            free(self);
        }
    }
    return tsize;
}
Пример #17
0
void chaos(region * r)
{
  if (rng_int() % 100 < 8) {
    switch (rng_int() % 3) {
      case 0:                  /* Untote */
        if (!fval(r->terrain, SEA_REGION)) {
          unit *u = random_unit(r);
          if (u && playerrace(u_race(u))) {
            ADDMSG(&u->faction->msgs, msg_message("chaos_disease", "unit", u));
            u_setfaction(u, get_monsters());
            u_setrace(u, get_race(RC_GHOUL));
          }
        }
        break;
      case 1:                  /* Drachen */
        if (random_unit(r)) {
          int mfac = 0;
          unit *u;
          switch (rng_int() % 3) {
            case 0:
              mfac = 100;
              u =
                createunit(r, get_monsters(), rng_int() % 8 + 1,
                get_race(RC_FIREDRAGON));
              break;
            case 1:
              mfac = 500;
              u =
                createunit(r, get_monsters(), rng_int() % 4 + 1,
                get_race(RC_DRAGON));
              break;
            default:
              mfac = 1000;
              u =
                createunit(r, get_monsters(), rng_int() % 2 + 1,
                get_race(RC_WYRM));
              break;
          }
          if (mfac)
            set_money(u, u->number * (rng_int() % mfac));
          fset(u, UFL_ISNEW | UFL_MOVED);
        }
      case 2:                  /* Terrainveränderung */
        if (!fval(r->terrain, FORBIDDEN_REGION)) {
          if (!fval(r->terrain, SEA_REGION)) {
            direction_t dir;
            for (dir = 0; dir != MAXDIRECTIONS; ++dir) {
              region *rn = rconnect(r, dir);
              if (rn && fval(rn->terrain, SEA_REGION))
                break;
            }
            if (dir != MAXDIRECTIONS) {
              ship *sh = r->ships;
              unit **up;

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

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

              while (r->buildings) {
                remove_building(&r->buildings, r->buildings);
              }
              terraform_region(r, newterrain(T_OCEAN));
            }
          } else {
            direction_t dir;
            for (dir = 0; dir != MAXDIRECTIONS; ++dir) {
              region *rn = rconnect(r, dir);
              if (rn && fval(rn->terrain, SEA_REGION))
                break;
            }
            if (dir != MAXDIRECTIONS) {
              terraform_region(r, chaosterrain());
            }
          }
        }
    }
  }
}
Пример #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();
}
Пример #19
0
void terraform_region(region * r, const terrain_type * terrain)
{
    /* Resourcen, die nicht mehr vorkommen können, löschen */
    const terrain_type *oldterrain = r->terrain;
    rawmaterial **lrm = &r->resources;

    assert(terrain);

    while (*lrm) {
        rawmaterial *rm = *lrm;
        const resource_type *rtype = NULL;

        if (terrain->production != NULL) {
            int i;
            for (i = 0; terrain->production[i].type; ++i) {
                if (rm->type->rtype == terrain->production[i].type) {
                    rtype = rm->type->rtype;
                    break;
                }
            }
        }
        if (rtype == NULL) {
            *lrm = rm->next;
            free(rm);
        }
        else {
            lrm = &rm->next;
        }
    }

    r->terrain = terrain;
    terraform_resources(r);

    if (!fval(terrain, LAND_REGION)) {
        region_setinfo(r, NULL);
        if (r->land != NULL) {
            i_freeall(&r->land->items);
            freeland(r->land);
            r->land = NULL;
        }
        rsettrees(r, 0, 0);
        rsettrees(r, 1, 0);
        rsettrees(r, 2, 0);
        rsethorses(r, 0);
        rsetpeasants(r, 0);
        rsetmoney(r, 0);
        freset(r, RF_ENCOUNTER);
        freset(r, RF_MALLORN);
        /* Beschreibung und Namen löschen */
        return;
    }

    if (r->land) {
        int d;
        for (d = 0; d != MAXDIRECTIONS; ++d) {
            rsetroad(r, d, 0);
        }
        i_freeall(&r->land->items);
    }
    else {
        static struct surround {
            struct surround *next;
            const luxury_type *type;
            int value;
        } *trash = NULL, *nb = NULL;
        const luxury_type *ltype = NULL;
        direction_t d;
        int mnr = 0;

        r->land = calloc(1, sizeof(land_region));
        r->land->ownership = NULL;
        region_set_morale(r, MORALE_DEFAULT, -1);
        region_setname(r, makename());
        for (d = 0; d != MAXDIRECTIONS; ++d) {
            region *nr = rconnect(r, d);
            if (nr && nr->land) {
                struct demand *sale = r->land->demands;
                while (sale && sale->value != 0)
                    sale = sale->next;
                if (sale) {
                    struct surround *sr = nb;
                    while (sr && sr->type != sale->type)
                        sr = sr->next;
                    if (!sr) {
                        if (trash) {
                            sr = trash;
                            trash = trash->next;
                        }
                        else {
                            sr = calloc(1, sizeof(struct surround));
                        }
                        sr->next = nb;
                        sr->type = sale->type;
                        sr->value = 1;
                        nb = sr;
                    }
                    else
                        sr->value++;
                    ++mnr;
                }
            }
        }
        if (!nb) {
            // TODO: this is really lame
            int i = get_maxluxuries();
            if (i > 0) {
                i = rng_int() % i;
                ltype = luxurytypes;
                while (i--)
                    ltype = ltype->next;
            }
        }
        else {
            int i = rng_int() % mnr;
            struct surround *srd = nb;
            while (i > srd->value) {
                i -= srd->value;
                srd = srd->next;
            }
            if (srd->type)
                setluxuries(r, srd->type);
            while (srd->next != NULL)
                srd = srd->next;
            srd->next = trash;
            trash = nb;
            nb = NULL;
        }
    }

    if (fval(terrain, LAND_REGION)) {
        const item_type *itype = NULL;
        char equip_hash[64];

        /* TODO: put the equipment in struct terrain, faster */
        sprintf(equip_hash, "terrain_%s", terrain->_name);
        equip_items(&r->land->items, get_equipment(equip_hash));

        if (r->terrain->herbs) {
            int len = 0;
            while (r->terrain->herbs[len])
                ++len;
            if (len)
                itype = r->terrain->herbs[rng_int() % len];
        }
        if (itype != NULL) {
            rsetherbtype(r, itype);
            rsetherbs(r, (short)(50 + rng_int() % 31));
        }
        else {
            rsetherbtype(r, NULL);
        }
        if (oldterrain == NULL || !fval(oldterrain, LAND_REGION)) {
            if (rng_int() % 100 < 3)
                fset(r, RF_MALLORN);
            else
                freset(r, RF_MALLORN);
            if (rng_int() % 100 < ENCCHANCE) {
                fset(r, RF_ENCOUNTER);
            }
        }
    }

    if (oldterrain == NULL || terrain->size != oldterrain->size) {
        if (terrain == newterrain(T_PLAIN)) {
            rsethorses(r, rng_int() % (terrain->size / 50));
            if (rng_int() % 100 < 40) {
                rsettrees(r, 2, terrain->size * (30 + rng_int() % 40) / 1000);
            }
        }
        else if (chance(0.2)) {
            rsettrees(r, 2, terrain->size * (30 + rng_int() % 40) / 1000);
        }
        else {
            rsettrees(r, 2, 0);
        }
        rsettrees(r, 1, rtrees(r, 2) / 4);
        rsettrees(r, 0, rtrees(r, 2) / 8);

        if (!fval(r, RF_CHAOTIC)) {
            int peasants;
            peasants = (maxworkingpeasants(r) * (20 + dice_rand("6d10"))) / 100;
            rsetpeasants(r, _max(100, peasants));
            rsetmoney(r, rpeasants(r) * ((wage(r, NULL, NULL,
                INT_MAX) + 1) + rng_int() % 5));
        }
    }
}
Пример #20
0
const terrain_type *get_ocean(direction_t dir)
{
    return newterrain(T_OCEAN);
}
Пример #21
0
summary *make_summary(void)
{
    faction *f;
    region *r;
    unit *u;
    summary *s = calloc(1, sizeof(summary));
    const struct resource_type *rhorse = get_resourcetype(R_HORSE);

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

  /* count everything */

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

      /* Einheiten Info. nregions darf nur einmal pro Partei
       * incrementiert werden. */

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

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

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

          for (sv = u->skills; sv != u->skills + u->skill_size; ++sv) {
            skill_t sk = sv->id;
            int aktskill = eff_skill(u, sk, r);
            if (aktskill > s->maxskill)
              s->maxskill = aktskill;
          }
          if (!fval(f, FFL_SELECT)) {
            f->nregions++;
            fset(f, FFL_SELECT);
          }
        }

        f->num_total += u->number;
        f->money += get_money(u);
        s->poprace[old_race(u_race(u))] += u->number;
      }
    }
  }

  return s;
}
Пример #22
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));
}