server/src/mapper/map_modify.c
Enno Rehling b7552f0d06 - New random number generator
- Faster get_pooled/use_pooled
- faster peasants()
- faster plagues()
- faster horses()
2006-02-19 22:43:56 +00:00

1258 lines
27 KiB
C

/* vi: set ts=2:
*
* Eressea PB(E)M host Copyright (C) 1998-2003
* Christian Schlittchen (corwin@amber.kn-bremen.de)
* Katja Zedel (katze@felidae.kn-bremen.de)
* Henning Peters (faroul@beyond.kn-bremen.de)
* Enno Rehling (enno@eressea-pbem.de)
* Ingo Wilken (Ingo.Wilken@informatik.uni-oldenburg.de)
*
* This program may not be used, modified or distributed without
* prior permission by the authors of Eressea.
*/
/* wenn config.h nicht vor curses included wird, kompiliert es unter windows nicht */
/* wenn curses.h nicht vor mapper included wird, kennt es die structs nicht. TODO: curses-teil separieren (map_tools.h) */
#include <config.h>
#include <curses.h>
#include <eressea.h>
#include "mapper.h"
/* kernel includes */
#include <build.h>
#include <building.h>
#include <faction.h>
#include <item.h>
#include <movement.h>
#include <plane.h>
#include <region.h>
#include <ship.h>
#include <terrain.h>
#include <terrainid.h>
#include <unit.h>
#include <resources.h>
/* util includes */
#include <util/base36.h>
#include <util/rng.h>
/* libc includes */
#include <string.h>
typedef struct menulist {
struct menulist *next, *prev;
int *val;
char *text;
} menulist;
enum {
C_COOL,
C_TEMPERATE,
C_DRY,
C_TROPIC,
MAXCLIMATES
};
static int
climate(int y)
{
if (y < -BLOCKSIZE)
return C_COOL;
if (y > 2 * BLOCKSIZE)
return C_TROPIC;
if (y > BLOCKSIZE)
return C_DRY;
return C_TEMPERATE;
}
#define MAXSEEDSIZE 17
static char maxseeds[MAXCLIMATES][8] =
{
{0, 1, 3, 3, 0, 3, 3, 4,}, /* Summe muß MAXSEEDSIZE sein */
{0, 5, 4, 2, 0, 2, 3, 1,},
{0, 6, 1, 0, 6, 2, 2, 0,},
{0, 4, 5, 4, 0, 2, 2, 0,},
};
static terrain_t
terrain_create(int climate)
{
int i = rng_int() % MAXSEEDSIZE;
terrain_t terrain = T_OCEAN;
while (i > maxseeds[climate][terrain])
i -= maxseeds[climate][terrain++];
return terrain;
}
static terrain_t newblock[BLOCKSIZE][BLOCKSIZE];
void
block_create(short x1, short y1, int size, char chaotisch, int special, const terrain_type * terrain)
{
int local_climate, k;
short x, y;
vset fringe;
vset_init(&fringe);
/* x1 = blockcoord(x1);
y1 = blockcoord(y1);
*/ local_climate = climate(y1);
memset(newblock, T_OCEAN, sizeof newblock);
x = BLOCKSIZE / 2;
y = BLOCKSIZE / 2;
vset_add(&fringe, (void *) (((short) (x) << 16) +
((short) (y) & 0xFFFF)));
for (x=0;x!=BLOCKSIZE;++x) {
for (y=0;y!=BLOCKSIZE;++y) {
/* add the borders of the block taht have a
* non-ocean region in them to the fringe
* */
int i;
direction_t d;
int nb[4][3];
memset(nb, 0, sizeof(nb));
for (d=0;d!=MAXDIRECTIONS;++d) {
region * r = findregion(x1 + delta_x[d] + x, y1 + delta_y[d]);
if (r && rterrain(r)!=T_OCEAN) {
nb[0][0] = x;
nb[0][1] = 0;
nb[0][2] = 1;
}
r = findregion(x1 + delta_x[d] + x, y1 + BLOCKSIZE - 1 + delta_y[d]);
if (r && rterrain(r)!=T_OCEAN) {
nb[1][0] = x;
nb[1][1] = BLOCKSIZE - 1;
nb[1][2] = 1;
}
r = findregion(x1 + delta_x[d] + BLOCKSIZE - 1, y1 + y + delta_y[d]);
if (r && rterrain(r)!=T_OCEAN) {
nb[2][0] = BLOCKSIZE - 1;
nb[2][1] = y;
nb[2][2] = 1;
}
r = findregion(x1 + delta_x[d], y1 + y + delta_y[d]);
if (r && rterrain(r)!=T_OCEAN) {
nb[3][0] = 0;
nb[3][1] = y;
nb[3][2] = 1;
}
}
for (i=0;i!=3;++i) if (nb[i][2]) {
vset_add(&fringe, (void *) (((short) nb[i][0] << 16) +
((short) nb[i][1] & 0xFFFF)));
}
}
}
for (k = 0; k != size; ++k) {
int c = (int) fringe.data[rng_int() % fringe.size];
direction_t d;
x = (short)(c >> 16);
y = (short)(c & 0xFFFF);
assert(newblock[x][y] == T_OCEAN);
newblock[x][y] = terrain_create(local_climate);
vset_erase(&fringe, (void *) c);
for (d = 0; d != MAXDIRECTIONS; ++d) {
short dx = x+delta_x[d];
short dy = y+delta_y[d];
if (dx >= 0 && dx < BLOCKSIZE && dy >= 0 && dy < BLOCKSIZE && newblock[dx][dy] == T_OCEAN)
vset_add(&fringe, (void *) (((short) (dx) << 16) +
((short) (dy) & 0xFFFF)));
}
}
{
/* newblock wird innerhalb der Rahmen in die Karte kopiert, die
* Landstriche werden benannt und bevoelkert, und die produkte
* p1 und p2 des Kontinentes werden gesetzt. */
region *r;
int i, i1 = -1, i2 = -1;
const luxury_type *ltype, *p1 = NULL, *p2=NULL;
int maxlux = get_maxluxuries();
if (maxlux>0) {
i1 = (item_t)(rng_int() % maxlux);
do {
i2 = (item_t)(rng_int() % maxlux);
}
while (i2 == i1);
}
ltype = luxurytypes;
for (i=0;!p1 || !p2;++i) {
if (i==i1) p1=ltype;
else if (i==i2) p2=ltype;
ltype=ltype->next;
}
for (x = 0; x != BLOCKSIZE; x++) {
for (y = 0; y != BLOCKSIZE; y++) {
const luxury_type * sale = (rng_int()%2)?p1:p2;
r = findregion(x1 + x - BLOCKSIZE/2, y1 + y - BLOCKSIZE/2);
if (r && !fval(r->terrain, SEA_REGION)) continue;
if (r==NULL) r = new_region(x1 + x - BLOCKSIZE/2, y1 + y - BLOCKSIZE/2);
if (chaotisch) fset(r, RF_CHAOTIC);
if (special == 1) {
terraform_region(r, terrain);
} else if (special == 2) {
if (newblock[x][y] != T_OCEAN)
terraform_region(r, terrain);
else
terraform(r, T_OCEAN);
} else {
terraform(r, newblock[x][y]);
}
if (r->land && sale) setluxuries(r, sale);
}
}
}
vset_destroy(&fringe);
}
static void
addmenulist(menulist ** SP, const char *s, int *val)
{
menulist *S, *X;
S = calloc(1, sizeof(menulist));
S->text = strdup(s);
S->val = val;
S->next = 0;
if (*SP) {
for (X = *SP; X->next; X = X->next);
X->next = S;
S->prev = X;
} else {
S->prev = 0;
*SP = S;
}
}
/* Wilder Hack: Zur Übergabe an addmenulist() brauchen wir Adressen,
* die die r*-Funktionen natürlich nicht mehr liefern. Also diese
* Variablen als Zwischenpuffer. */
static int peasants, money, trees, horses, iron, laen, chaotisch;
static int saplings, seeds;
static int ironlevel, laenlevel, stone, stonelevel;
static void
get_region(region *r) {
struct rawmaterial *res;
peasants = rpeasants(r);
money = rmoney(r);
trees = rtrees(r,2);
saplings = rtrees(r,1);
seeds = rtrees(r,0);
horses = rhorses(r);
iron = -1;
ironlevel = -1;
laen = -1;
laenlevel = -1;
stone = -1;
stonelevel = -1;
for (res=r->resources;res;res=res->next) {
const item_type * itype = resource2item(res->type->rtype);
if(itype == olditemtype[I_IRON]) {
iron = res->amount;
ironlevel = res->level + itype->construction->minskill - 1;
} else if(itype == olditemtype[I_LAEN]) {
laen = res->amount;
laenlevel = res->level + itype->construction->minskill - 1;
} else if(itype == olditemtype[I_STONE]) {
stone = res->amount;
stonelevel = res->level + itype->construction->minskill - 1;
}
}
chaotisch = fval(r, RF_CHAOTIC);
}
static void
put_region(region *r) {
struct rawmaterial *res;
rsetpeasants(r, peasants);
rsetmoney(r,money);
rsettrees(r,2,trees);
rsettrees(r,1,saplings);
rsettrees(r,0,seeds);
rsethorses(r, horses);
for (res=r->resources;res;res=res->next) {
const item_type * itype = resource2item(res->type->rtype);
if(itype == olditemtype[I_IRON]) {
res->amount = iron;
res->level = ironlevel - itype->construction->minskill + 1;
} else if(itype == olditemtype[I_LAEN]) {
res->amount = laen;
res->level = laenlevel - itype->construction->minskill + 1;
} else if(itype == olditemtype[I_STONE]) {
res->amount = stone;
res->level = stonelevel - itype->construction->minskill + 1;
}
}
if (chaotisch) fset(r, RF_CHAOTIC); else freset(r, RF_CHAOTIC);
}
static void
create_region_menu(menulist ** menu, region * r)
{
char str[80];
unit *u;
building *b;
ship *sh;
faction *f;
get_region(r);
addmenulist(menu, "Peasants", &peasants);
addmenulist(menu, "Silver", &money);
if (fval(r, RF_MALLORN)) {
addmenulist(menu, "Mallorntrees", &trees);
addmenulist(menu, "Mallornsaplings", &saplings);
addmenulist(menu, "Mallornseeds", &seeds);
} else {
addmenulist(menu, "Trees", &trees);
addmenulist(menu, "Saplings", &saplings);
addmenulist(menu, "Seeds", &seeds);
}
addmenulist(menu, "Horses", &horses);
/* if(iron != -1) { */
addmenulist(menu, "Iron", &iron);
addmenulist(menu, "Ironlevel", &ironlevel);
/* } */
/* if(laen != -1) { */
addmenulist(menu, "Laen", &laen);
addmenulist(menu, "Laenlevel", &laenlevel);
/* } */
/* if(stone != -1) { */
addmenulist(menu, "Stone", &stone);
addmenulist(menu, "Stonelevel", &stonelevel);
/* } */
addmenulist(menu, "Chaos-Factor", &chaotisch);
if (r->planep) {
strcpy(buf,"Plane: ");
strncpy(str, r->planep->name, 30);
str[30] = 0;
sncat(buf, str, BUFSIZE);
sncat(buf, " (", BUFSIZE);
sncat(buf, r->planep->name, BUFSIZE);
sncat(buf, ")", BUFSIZE);
addmenulist(menu, buf, 0);
}
strcpy(buf, "Buildings:");
if (!r->buildings) {
sncat(buf, " keine", BUFSIZE);
addmenulist(menu, buf, 0);
} else {
addmenulist(menu, buf, 0);
for (b = r->buildings; b; b = b->next) {
sprintf(buf, " %s: ", Buildingid(b));
for (u = r->units; u; u = u->next)
if (u->building == b && fval(u, UFL_OWNER)) {
strncpy(str, u->name, 28);
str[28] = 0;
sncat(buf, str, BUFSIZE);
sprintf(str, " (%s), Partei %s", unitid(u), factionid(u->faction));
sncat(buf, str, BUFSIZE);
break;
}
if (!u)
sncat(buf, "steht leer", BUFSIZE);
addmenulist(menu, buf, 0);
}
}
strcpy(buf, "Ships:");
if (!r->ships) {
sncat(buf, " keine", BUFSIZE);
addmenulist(menu, buf, 0);
} else {
addmenulist(menu, buf, 0);
for (sh = r->ships; sh; sh = sh->next) {
sprintf(buf, " %s: ", shipname(sh));
if (sh->size!=sh->type->construction->maxsize)
sncat(buf, "(im Bau) ", BUFSIZE);
for (u = r->units; u; u = u->next)
if (u->ship == sh && fval(u, UFL_OWNER)) {
strncpy(str, u->name, 28);
str[28] = 0;
sncat(buf, str, BUFSIZE);
sprintf(str, " (%s), Partei %s", unitid(u), factionid(u->faction));
sncat(buf, str, BUFSIZE);
break;
}
if (!u)
sncat(buf, "ohne Besitzer", BUFSIZE);
addmenulist(menu, buf, 0);
}
}
strcpy(buf, "Parteien:");
if (!r->units) {
sncat(buf, " keine", BUFSIZE);
addmenulist(menu, buf, 0);
} else {
for (f = factions; f; f = f->next)
f->num_people = f->no_units = 0;
for (u = r->units; u; u = u->next) {
u->faction->no_units++;
u->faction->num_people += u->number;
}
addmenulist(menu, buf, 0);
for (f = factions; f; f = f->next) {
if (f->no_units) {
sprintf(buf, " %s: ", factionname(f));
sprintf(str, "Einheiten: %d; Leute: %d", f->no_units, f->num_people);
sncat(buf, str, BUFSIZE);
addmenulist(menu, buf, 0);
}
}
}
}
char modified = 0;
WINDOW *mywin;
int pline;
#define Printw(x,l) \
{ \
wmove(mywin,l,4); \
Addstr(x->text); \
if (x->val) wprintw(mywin, (NCURSES_CONST char*)": %d",(char*)*(x->val)); \
} \
static void
modify_value(menulist * v)
{
int vl;
vl = map_input(mywin, 40, pline, "Neuer Wert", -1, 999999, *(v->val));
Movexy(4, pline);
wclrtoeol(mywin);
Printw(v, pline);
if (vl != *(v->val)) {
modified = 1;
*(v->val) = vl;
}
}
void
NeuesSchiff(region * r)
{
ship_type *stype[40]; /* Maximal 40 Schiffe */
ship_typelist *st;
ship *s;
WINDOW *win;
int i, q, y, maxtype;
for(st = shiptypes, maxtype=0; st; st=st->next, maxtype++) {
stype[maxtype] = (ship_type *)st->type;
}
win = openwin(SX - 10, 6, "< Neues Schiff erschaffen >");
q = 0;
y = 2;
wmove(win, y, 4);
for (i = 0; i < maxtype; i++) {
sprintf(buf, "%d=%s; ", i, stype[i]->name[0]);
q += strlen(buf);
if (q > SX - 20) {
q = strlen(buf);
y++;
wmove(win, y, 4);
}
waddnstr(win, buf, -1);
}
wrefresh(win);
q = map_input(win, 2, 1, "Schiffstyp", -1, maxtype, 0);
if (q < 0) {
delwin(win);
return;
}
for (; y > 0; y--) {
wmove(win, y, 2);
wclrtoeol(win);
wrefresh(win);
wmove(win, y, win->_maxx);
waddch(win, '|');
wrefresh(win);
}
wmove(win, 1, 2);
wAddstr(stype[q]->name[0]);
wrefresh(win);
s = new_ship(stype[q], default_locale, r);
s->region = r;
strcpy(buf, my_input(win, 2, 2, "Name: ", NULL));
if (strlen(buf) > 0)
set_string(&s->name, buf);
if (clipunit) {
wmove(win, 3, 2);
wAddstr("Einheit im Clip: ");
wAddstr(Unitid(clipunit));
wmove(win, 4, 2);
if (yes_no(win, "Clipunit als Besitzer?", 'n')) {
leave(clipregion, clipunit);
if (r != clipregion)
translist(&clipregion->units, &r->units, clipunit);
clipunit->ship = s;
fset(clipunit, UFL_OWNER);
}
}
delwin(win);
modified = 1;
}
static const char * oldbuildings[] = {
"castle",
"lighthouse",
"mine",
"quarry",
"harbour",
"academy",
"magictower",
"smithy",
"sawmill",
"stables",
"monument",
"dam",
"caravan",
"tunnel",
"inn",
"stonecircle",
"blessedstonecircle",
"illusion",
NULL
};
void
NeueBurg(region * r)
{
building *b;
WINDOW *win;
int i, q, y;
win = openwin(SX - 10, 10, "< Neues Gebäude erschaffen >");
q = 0;
y = 2;
wmove(win, y, 4);
for (i = 0; oldbuildings[i]; i++) {
sprintf(buf, "%d=%s; ", i, oldbuildings[i]);
q += strlen(buf);
if (q > SX - 20) {
q = strlen(buf);
y++;
wmove(win, y, 4);
}
waddnstr(win, buf, -1);
}
wrefresh(win);
q = map_input(win, 2, 1, "Gebäudetyp", -1, i, 0);
if (q < 0) {
delwin(win);
return;
}
for (; y > 0; y--) {
wmove(win, y, 4);
wclrtoeol(win);
wrefresh(win);
wmove(win, y, win->_maxx);
waddch(win, '|');
}
wmove(win, 1, 2);
wAddstr((char*)oldbuildings[q]);
wrefresh(win);
b = new_building(bt_find(oldbuildings[q]), r, NULL);
b->size = map_input(win, 2, 2, "Grösse", 1, 99999, 1);
strcpy(buf, my_input(win, 2, 3, "Name: ", NULL));
if (strlen(buf) > 0)
set_string(&b->name, buf);
if (clipunit) {
wmove(win, 4, 2);
wAddstr("Einheit im Clip: ");
wAddstr(Unitid(clipunit));
wmove(win, 5, 2);
if (yes_no(win, "Clipunit als Besitzer?", 'n')) {
leave(clipregion, clipunit);
if (r != clipregion)
translist(&clipregion->units, &r->units, clipunit);
clipunit->building = b;
fset(clipunit, UFL_OWNER);
}
}
delwin(win);
modified = 1;
}
int
modify_region(region * r)
{
menulist *eh = NULL, *unten, *oben, *hlp = NULL, *such = NULL, *mpoint;
int line, ch, bottom, bot;
size_t lt;
char *s = NULL, *txt, *suchtext = NULL;
create_region_menu(&eh, r);
clear();
strncpy(buf, rname(r, NULL), 65);
buf[65] = 0;
movexy(0, 0);
printw((char*)"%s (%d,%d):", buf, r->x, r->y);
for (line = 0; line <= SX; line++)
buf[line] = '-';
movexy(0, SY - 1);
addstr(buf);
movexy(0, 1);
addstr(buf);
movexy(0, SY);
addstr("<Ret>: Neuer Wert; T: neuer Text; u: Units; B: neue Burg; S: neues Schiff");
refresh();
mywin = newwin(SY - 3, SX, 2, 0);
wclear(mywin);
bot = mywin->_maxy + 1;
for (line = 0, unten = eh; line < bot && unten->next; line++, unten = unten->next) {
Printw(unten, line);
wrefresh(mywin);
}
Printw(unten, line);
wrefresh(mywin);
bottom = line - 1;
mpoint = oben = eh; /* unten=unten->prev; */
scrollok(mywin, TRUE);
pline = 0;
for (;;) {
Movexy(1, pline);
if (mpoint->val) {
wattron(mywin, A_BOLD);
Addstr("=>");
wattroff(mywin, A_BOLD);
move(SY, 0);
clrtoeol();
addstr("<Ret>: Neuer Wert; T: neuer Text; u: Units; B: neue Burg; S: neues Schiff");
refresh();
} else {
Addstr("->");
move(SY, 0);
clrtoeol();
addstr("u: Units; T: neuer Text; B: neue Burg; S: neues Schiff");
refresh();
}
wrefresh(mywin);
ch = getch();
Movexy(1, pline);
Addstr(" ");
switch (ch) {
case KEY_DOWN:
if (mpoint->next) {
mpoint = mpoint->next;
if (pline > bottom) {
pline--;
if (unten->next) {
wscrl(mywin, 1);
Printw(unten, bottom);
unten = unten->next;
oben = oben->next;
}
}
pline++;
} else
beep();
break;
case KEY_UP:
if (mpoint->prev) {
mpoint = mpoint->prev;
pline--;
if (pline < 0) {
pline++;
if (oben->prev) {
unten = unten->prev;
oben = oben->prev;
wscrl(mywin, -1);
Printw(oben, 0);
}
}
} else
beep();
break;
case KEY_RIGHT:
case KEY_NPAGE:
for (line = 0; line < 20 && unten->next; line++) {
oben = oben->next;
unten = unten->next;
if (mpoint->next)
mpoint = mpoint->next;
else
pline--;
}
wclear(mywin);
for (line = 0, hlp = oben; line < bot && hlp->next; line++, hlp = hlp->next) {
Printw(hlp, line);
wrefresh(mywin);
}
Printw(hlp, line);
wrefresh(mywin);
bottom = line - 1;
if (pline < 0)
pline = 0;
break;
case KEY_PPAGE:
case KEY_LEFT:
for (line = 0; line < 20 && oben->prev; line++) {
oben = oben->prev;
unten = unten->prev;
if (mpoint->prev)
mpoint = mpoint->prev;
else
pline++;
}
wclear(mywin);
for (line = 0, hlp = oben; line < bot && hlp->next; line++, hlp = hlp->next) {
Printw(hlp, line);
wrefresh(mywin);
}
Printw(hlp, line);
wrefresh(mywin);
bottom = line - 1;
if (pline > bottom)
pline = bottom;
break;
case 12: /* ^L -> redraw */
wclear(mywin);
for (line = 0, hlp = oben; line < bot && hlp->next; line++, hlp = hlp->next) {
Printw(hlp, line);
wrefresh(mywin);
}
Printw(hlp, line);
wrefresh(mywin);
bottom = line - 1;
break;
case '/':
suchtext = my_input(0, 0, 0, (char*)"Suchtext: ", NULL);
such = eh;
case 'n':
line = 0;
lt = strlen(suchtext);
while (such->next && !line) {
s = such->text;
while (strlen(s) >= lt && !line) {
if (strncasecmp(s, suchtext, lt) == 0)
line = 1;
s++;
}
such = such->next;
}
if (line) {
wclear(mywin);
Movexy(4, 0);
txt = such->prev->text;
s--;
ch = *s;
*s = 0;
Addstr(txt);
wattron(mywin, A_REVERSE);
*s = (char)ch;
txt = s;
ch = txt[lt];
txt[lt] = 0;
Addstr(txt);
wattroff(mywin, A_REVERSE);
txt[lt] = (char)ch;
txt += lt;
Addstr(txt);
if (such->prev->val) {
sprintf(buf, ": %d", *(such->prev->val));
Addstr(buf);
}
for (line = 0, hlp = oben; line < bot && hlp->next; line++, hlp = hlp->next) {
Printw(hlp, line);
wrefresh(mywin);
}
Printw(hlp, line);
wrefresh(mywin);
bottom = line - 1;
oben = such->prev ? such->prev : such;
unten = hlp->prev;
mpoint = oben;
pline = 0;
} else {
movexy(0, SY);
beep();
clrtoeol();
printw((char*)"'%s' nicht gefunden.", suchtext);
refresh();
}
break;
case KEY_HELP:
case '?':
case 'h':
movexy(0, SY);
clrtoeol();
addstr("<Ret>: Neuer Wert; u: Einheitenliste; B: neue Burg; S: neues Schiff");
refresh();
break;
case '>':
wclear(mywin);
do {
unten = unten->next;
oben = oben->next;
} while (unten->next);
for (line = 0, hlp = oben; line < bot && hlp; line++, hlp = hlp->next) {
Printw(hlp, line);
wrefresh(mywin);
}
Printw(hlp, line);
wrefresh(mywin);
bottom = line - 1;
mpoint = unten;
pline = bottom;
break;
case '<':
wclear(mywin);
for (line = 0, unten = eh; line < bot && unten->next; line++, unten = unten->next) {
Printw(unten, line);
wrefresh(mywin);
}
Printw(hlp, line);
wrefresh(mywin);
bottom = line - 1;
mpoint = such = oben = eh;
unten = unten->prev;
pline = 0;
break;
case 10:
case 13:
if (mpoint->val) {
modify_value(mpoint);
for (line = 0, unten = eh; line < bot && unten->next; line++, unten = unten->next) {
Printw(unten, line);
wrefresh(mywin);
}
Printw(unten, line);
wrefresh(mywin);
} else
beep();
break;
case 'T':
case 'B':
if (fval(r->terrain, LAND_REGION)) {
NeueBurg(r);
return 1;
} else
beep();
case 'S':
NeuesSchiff(r);
return 1;
case 'u':
while (showunits(r));
wclear(mywin);
for (line = 0, hlp = oben; line < bot && hlp->next; line++, hlp = hlp->next) {
Printw(hlp, line);
wrefresh(mywin);
}
Printw(hlp, line);
wrefresh(mywin);
bottom = line - 1;
break;
case 27: /* Esc */
case 'q':
put_region(r);
delwin(mywin);
freelist(eh);
return 0;
}
}
}
void
make_new_region(short x, short y)
{
WINDOW *win;
region *r;
const terrain_type * terrain = NULL;
win = openwin(SX - 10, 10, "< Region erzeugen >");
x = (short)map_input(win, 2, 1, "X-Koordinate", -999, 999, x);
y = (short)map_input(win, 2, 2, "Y-Koordinate", -999, 999, y);
wmove(win, 3, 2);
if ((r=findregion(x, y))!=NULL) {
if (!yes_no(win, "Dort ist schon etwas! Überschreiben?", 'n'))
return;
else {
wmove(win, 3, 2);
wclrtoeol(win);
wmove(win, 3, win->_maxx);
waddch(win, '|');
}
} else
r=new_region(x,y);
terrain = select_terrain(NULL);
terraform_region(r, terrain);
wrefresh(win);
wmove(win, 4, 3);
if(yes_no(win, "Chaotische Region?", 'n')) {
fset(r, RF_CHAOTIC);
} else {
freset(r, RF_CHAOTIC);
}
modified=1;
}
#define BLOCK_RADIUS 6
void
make_ocean_block(short x, short y)
{
short cx, cy;
region *r;
for(cx = x - BLOCK_RADIUS; cx < x+BLOCK_RADIUS; cx++) {
for(cy = y - BLOCK_RADIUS; cy < y+BLOCK_RADIUS; cy++) {
if(koor_distance(cx, cy, x, y) < BLOCK_RADIUS) {
if (!findregion(cx, cy)) {
r = new_region(cx, cy);
terraform(r, T_OCEAN);
}
}
}
}
}
const terrain_type *
select_terrain(const terrain_type * default_terrain)
{
selection *prev, *ilist = NULL, **iinsert;
selection *selected = NULL;
const terrain_type * terrain = terrains();
if (!terrain) return NULL;
iinsert = &ilist;
prev = ilist;
while (terrain) {
push_selection(iinsert, terrain->_name, (void*)terrain);
terrain = terrain->next;
}
selected = do_selection(ilist, "Terrain", NULL, NULL);
if (selected==NULL) return NULL;
return (const terrain_type*)selected->data;
}
void
make_new_block(int x, int y)
{
WINDOW *win;
int z, special = 0;
char chaos;
const terrain_type * terrain = NULL;
win = openwin(SX - 10, 10, "< Block erzeugen >");
x = map_input(win, 2, 1, "X-Koordinate innerhalb des Blocks", -999, 999, x);
y = map_input(win, 2, 2, "Y-Koordinate innerhalb des Blocks", -999, 999, y);
wmove(win, 3, 2);
if (findregion(x, y)) {
if (!yes_no(win, "Dort ist schon etwas! Überschreiben?", 'n'))
return;
else {
wmove(win, 3, 2);
wclrtoeol(win);
wmove(win, 3, win->_maxx);
waddch(win, '|');
}
}
z = 2;
wmove(win, ++z, 2);
if (yes_no(win, "Mini-Insel?", 'n'))
special = 4;
else {
wmove(win, ++z, 2);
if (yes_no(win, "Nur Wasser?", 'n')) {
special = 1;
terrain = newterrain(T_OCEAN);
}
else {
wmove(win, ++z, 2);
if (yes_no(win, "1-Terrain-Insel?", 'n')) {
terrain = select_terrain(NULL);
}
}
}
wmove(win, ++z, 2);
if (special != 1)
chaos = (char)(yes_no(win, "Chaotischer Block?", 'n') ? 1 : 0);
else
chaos = 0;
block_create(x, y, ISLANDSIZE, chaos, special, terrain);
if (y < MINY)
MINY -= 9;
else if (y > MAXY)
MAXY += 9;
if (x < MINX)
MINX -= 9;
else if (x > MAXX)
MAXX += 9;
modified = 1;
}
static terrain_t
choose_terrain(terrain_t t) {
int q;
if (rng_int()%100 < 50) return t;
if (rng_int()%100 < 10) return T_OCEAN;
q = rng_int()%100;
switch (t) {
case T_OCEAN:
if(rng_int()%100 < 60) return T_OCEAN;
switch(rng_int()%6) {
case 0:
return T_SWAMP;
case 1:
return T_PLAIN;
case 2:
return T_GLACIER;
case 3:
return T_DESERT;
case 4:
return T_HIGHLAND;
case 5:
return T_MOUNTAIN;
}
break;
case T_PLAIN:
if (q<20)
return T_SWAMP;
if (q<40)
return T_MOUNTAIN;
if (q<50)
return T_HIGHLAND;
if (q<80)
return T_DESERT;
if (q<90)
return T_GLACIER;
break;
case T_SWAMP:
if (q<40)
return T_PLAIN;
if (q<65)
return T_HIGHLAND;
if (q<80)
return T_MOUNTAIN;
if (q<90)
return T_GLACIER;
if (q<95)
return T_DESERT;
break;
case T_HIGHLAND:
if (q<35)
return T_PLAIN;
if (q<50)
return T_MOUNTAIN;
if (q<70)
return T_GLACIER;
if (q<80)
return T_SWAMP;
if (q<90)
return T_DESERT;
break;
case T_DESERT:
if (q<35)
return T_PLAIN;
if (q<45)
return T_MOUNTAIN;
if (q<50)
return T_GLACIER;
if (q<55)
return T_SWAMP;
if (q<70)
return T_HIGHLAND;
break;
case T_MOUNTAIN:
if (q<35)
return T_PLAIN;
if (q<65)
return T_HIGHLAND;
if (q<80)
return T_GLACIER;
if (q<90)
return T_SWAMP;
if (q<95)
return T_DESERT;
break;
case T_GLACIER:
if (q<35)
return T_PLAIN;
if (q<50)
return T_MOUNTAIN;
if (q<70)
return T_HIGHLAND;
if (q<90)
return T_SWAMP;
if (q<95)
return T_DESERT;
break;
}
return t;
}
region *t_queue[10000];
int t_queue_len = 0;
void
push(region *r) {
t_queue[t_queue_len] = r;
t_queue_len++;
}
static region *
shift(void)
{
int p;
region *r;
if(t_queue_len == 0) return NULL;
p = rng_int()%t_queue_len;
r = t_queue[p];
memmove(&t_queue[p], &t_queue[p+1], (10000-p)*sizeof(region *));
t_queue_len--;
return r;
}
static const luxury_type * tradegood = NULL;
void
settg(region *r)
{
const luxury_type * ltype;
int g = get_maxluxuries();
if (tradegood==NULL) tradegood = luxurytypes;
for (ltype=luxurytypes; ltype; ltype=ltype->next) {
if (ltype!=tradegood) r_setdemand(r, ltype, 1 + rng_int() % 5);
}
r_setdemand(r, tradegood, 0);
if (g>0 && (rng_int()%10)<2) {
int t = rng_int() % g;
for (tradegood = luxurytypes;t;--t) {
tradegood = tradegood->next;
}
}
}
boolean
Create_Island(region *r, int * n, const terrain_type * terrain, int x, int y) {
terrain_t t = oldterrain(terrain);
if (!r) return false;
if (*n == 0) return true;
if((t == T_MOUNTAIN || t == T_GLACIER) && rng_int()%100 < 5) {
terraform(r,T_VOLCANO);
} else {
terraform_region(r, terrain);
}
if (r->land) settg(r);
(*n)--;
return false;
}
void
create_island(region *r, int n, const struct terrain_type * terrain)
{
short sx=r->x, sy=r->y, i, x = 0, y = 0;
direction_t d;
boolean abbruch=false;
region *r2;
for(r2=regions; r2; r2=r2->next) {
r2->msgs = (void *)0;
}
tradegood = NULL;
terraform_region(r, terrain);
if(r->land) settg(r);
r->msgs = (void *)(rng_int()%6);
push(r);
for(d=0; d<MAXDIRECTIONS; d++) {
region * r2 = rconnect(r, d);
if(r2) {
push(r2);
r2->msgs = (void *)(int)d;
}
}
while (n>0 && (r=shift())!=NULL) {
for(i = -1; i <= 1; i++) {
int d = ((int)r->msgs + i + 6)%6;
switch(d) {
case 0:
x=r->x-1; y=r->y; /* Westen */
break;
case 1:
x=r->x-1; y=r->y+1; /* Nordwesten */
break;
case 2:
x=r->x; y=r->y+1; /* Nordosten */
break;
case 3:
x=r->x+1; y=r->y; /* Osten */
break;
case 4:
x=r->x+1; y=r->y-1; /* Südosten */
break;
case 5:
x=r->x; y=r->y-1; /* Südwesten */
break;
}
r2 = findregion(x,y);
if (r2 && fval(r2->terrain, SEA_REGION)) {
const terrain_type * terrain = NULL;
do {
terrain_t t = choose_terrain(oldterrain(r2->terrain));
terrain = newterrain(t);
} while (terrain==NULL);
r2->msgs = (void *)d;
push(r2);
abbruch = Create_Island(r2, &n, terrain, sx, sy);
}
if (abbruch) break;
}
}
t_queue_len = 0;
}