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; }
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); }
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; }
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; }
/** 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)); } } }
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); }
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; }
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; }
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; } } }
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); }
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)); } }
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); } } } }
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); } }
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)); } } } } }
/* 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; }
/** 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; }
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()); } } } } } }
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(); }
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)); } } }
const terrain_type *get_ocean(direction_t dir) { return newterrain(T_OCEAN); }
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; }
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)); }