From fa2072b6e0d15af7c3f3e0e4bad1146c7ed7402e Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Tue, 23 Jun 2009 16:17:38 +0000 Subject: [PATCH] world generation algorithm for E3 --- src/common/kernel/types.h | 336 +++++++++++++++++----------------- src/common/modules/autoseed.c | 215 ++++++++++++++++++++-- src/common/modules/autoseed.h | 3 +- src/eressea/gmtool.c | 7 + 4 files changed, 376 insertions(+), 185 deletions(-) diff --git a/src/common/kernel/types.h b/src/common/kernel/types.h index 8dde92b42..506ff82aa 100644 --- a/src/common/kernel/types.h +++ b/src/common/kernel/types.h @@ -1,6 +1,6 @@ /* vi: set ts=2: * - * Eressea PB(E)M host Copyright (C) 1998-2003 + * 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) @@ -72,9 +72,9 @@ struct unit_list; struct weapon_type; typedef struct ursprung { - struct ursprung *next; - int id; - short x, y; + struct ursprung *next; + int id; + short x, y; } ursprung; /* ----------------- Befehle ----------------------------------- */ @@ -169,80 +169,80 @@ enum { typedef unsigned char param_t; enum { - P_LOCALE, + P_LOCALE, P_ANY, P_EACH, - P_PEASANT, - P_BUILDING, - P_UNIT, - P_PRIVAT, - P_BEHIND, - P_CONTROL, - P_HERBS, - P_NOT, - P_NEXT, - P_FACTION, - P_GAMENAME, - P_PERSON, - P_REGION, - P_SHIP, - P_MONEY, - P_ROAD, - P_TEMP, - P_FLEE, - P_GEBAEUDE, - P_GIVE, - P_FIGHT, + P_PEASANT, + P_BUILDING, + P_UNIT, + P_PRIVAT, + P_BEHIND, + P_CONTROL, + P_HERBS, + P_NOT, + P_NEXT, + P_FACTION, + P_GAMENAME, + P_PERSON, + P_REGION, + P_SHIP, + P_MONEY, + P_ROAD, + P_TEMP, + P_FLEE, + P_GEBAEUDE, + P_GIVE, + P_FIGHT, P_TRAVEL, - P_GUARD, - P_ZAUBER, - P_PAUSE, - P_VORNE, - P_AGGRO, - P_CHICKEN, - P_LEVEL, - P_HELP, - P_FOREIGN, - P_AURA, - P_FOR, - P_AID, - P_MERCY, - P_AFTER, - P_BEFORE, - P_NUMBER, - P_ITEMS, - P_POTIONS, - P_GROUP, - P_FACTIONSTEALTH, - P_TREES, - P_XEPOTION, - P_XEBALLOON, - P_XELAEN, - MAXPARAMS, - NOPARAM = (param_t) - 1 + P_GUARD, + P_ZAUBER, + P_PAUSE, + P_VORNE, + P_AGGRO, + P_CHICKEN, + P_LEVEL, + P_HELP, + P_FOREIGN, + P_AURA, + P_FOR, + P_AID, + P_MERCY, + P_AFTER, + P_BEFORE, + P_NUMBER, + P_ITEMS, + P_POTIONS, + P_GROUP, + P_FACTIONSTEALTH, + P_TREES, + P_XEPOTION, + P_XEBALLOON, + P_XELAEN, + MAXPARAMS, + NOPARAM = (param_t) - 1 }; -typedef enum { /* Fehler und Meldungen im Report */ - MSG_BATTLE, - MSG_EVENT, - MSG_MOVE, - MSG_INCOME, - MSG_COMMERCE, - MSG_PRODUCE, - MSG_ORCVERMEHRUNG, - MSG_MESSAGE, - MSG_COMMENT, - MSG_MAGIC, - MAX_MSG +typedef enum { /* Fehler und Meldungen im Report */ + MSG_BATTLE, + MSG_EVENT, + MSG_MOVE, + MSG_INCOME, + MSG_COMMERCE, + MSG_PRODUCE, + MSG_ORCVERMEHRUNG, + MSG_MESSAGE, + MSG_COMMENT, + MSG_MAGIC, + MAX_MSG } msg_t; -enum { /* Message-Level */ - ML_IMPORTANT, /* Sachen, die IMO erscheinen _muessen_ */ - ML_DEBUG, - ML_MISTAKE, - ML_WARN, - ML_INFO, - ML_MAX +enum { /* Message-Level */ + ML_IMPORTANT, /* Sachen, die IMO erscheinen _muessen_ */ + ML_DEBUG, + ML_MISTAKE, + ML_WARN, + ML_INFO, + ML_MAX }; extern const char *parameters[MAXPARAMS]; @@ -250,147 +250,147 @@ extern const char *parameters[MAXPARAMS]; /* --------------- Reports Typen ------------------------------- */ enum { - O_REPORT, /* 1 */ - O_COMPUTER, /* 2 */ - O_ZUGVORLAGE, /* 4 */ + O_REPORT, /* 1 */ + O_COMPUTER, /* 2 */ + O_ZUGVORLAGE, /* 4 */ O_UNUSED_3, - O_STATISTICS, /* 16 */ - O_DEBUG, /* 32 */ - O_COMPRESS, /* 64 */ - O_NEWS, /* 128 */ + O_STATISTICS, /* 16 */ + O_DEBUG, /* 32 */ + O_COMPRESS, /* 64 */ + O_NEWS, /* 128 */ O_UNUSED_8, - O_ADRESSEN, /* 512 */ - O_BZIP2, /* 1024 - compress as bzip2 */ - O_SCORE, /* 2048 - punkte anzeigen? */ - O_SHOWSKCHANGE, /* 4096 - Skillveränderungen anzeigen? */ - O_XML, /* 8192 - XML report versenden */ + O_ADRESSEN, /* 512 */ + O_BZIP2, /* 1024 - compress as bzip2 */ + O_SCORE, /* 2048 - punkte anzeigen? */ + O_SHOWSKCHANGE, /* 4096 - Skillveränderungen anzeigen? */ + O_XML, /* 8192 - XML report versenden */ MAXOPTIONS }; /* ------------------ Talente ---------------------------------- */ enum { - SK_ALCHEMY, - SK_CROSSBOW, - SK_MINING, - SK_LONGBOW, - SK_BUILDING, - SK_TRADE, - SK_LUMBERJACK, - SK_CATAPULT, - SK_HERBALISM, - SK_MAGIC, - SK_HORSE_TRAINING, /* 10 */ - SK_RIDING, - SK_ARMORER, - SK_SHIPBUILDING, - SK_MELEE, - SK_SAILING, - SK_SPEAR, - SK_SPY, - SK_QUARRYING, - SK_ROAD_BUILDING, - SK_TACTICS, /* 20 */ - SK_STEALTH, - SK_ENTERTAINMENT, - SK_WEAPONSMITH, - SK_CARTMAKER, - SK_PERCEPTION, - SK_TAXING, - SK_STAMINA, - SK_WEAPONLESS, - MAXSKILLS, - NOSKILL = (skill_t) -1 + SK_ALCHEMY, + SK_CROSSBOW, + SK_MINING, + SK_LONGBOW, + SK_BUILDING, + SK_TRADE, + SK_LUMBERJACK, + SK_CATAPULT, + SK_HERBALISM, + SK_MAGIC, + SK_HORSE_TRAINING, /* 10 */ + SK_RIDING, + SK_ARMORER, + SK_SHIPBUILDING, + SK_MELEE, + SK_SAILING, + SK_SPEAR, + SK_SPY, + SK_QUARRYING, + SK_ROAD_BUILDING, + SK_TACTICS, /* 20 */ + SK_STEALTH, + SK_ENTERTAINMENT, + SK_WEAPONSMITH, + SK_CARTMAKER, + SK_PERCEPTION, + SK_TAXING, + SK_STAMINA, + SK_WEAPONLESS, + MAXSKILLS, + NOSKILL = (skill_t) -1 }; /* ------------- Typ von Einheiten ----------------------------- */ enum { - RC_DWARF, /* 0 - Zwerg */ - RC_ELF, - RC_ORC, - RC_GOBLIN, - RC_HUMAN, + RC_DWARF, /* 0 - Zwerg */ + RC_ELF, + RC_ORC, + RC_GOBLIN, + RC_HUMAN, RC_TROLL, RC_DAEMON, - RC_INSECT, - RC_HALFLING, - RC_CAT, + RC_INSECT, + RC_HALFLING, + RC_CAT, RC_AQUARIAN, RC_URUK, - RC_SNOTLING, - RC_UNDEAD, - RC_ILLUSION, + RC_SNOTLING, + RC_UNDEAD, + RC_ILLUSION, RC_FIREDRAGON, RC_DRAGON, - RC_WYRM, - RC_TREEMAN, - RC_BIRTHDAYDRAGON, + RC_WYRM, + RC_TREEMAN, + RC_BIRTHDAYDRAGON, RC_DRACOID, - RC_SPECIAL, - RC_SPELL, - RC_IRONGOLEM, - RC_STONEGOLEM, + RC_SPECIAL, + RC_SPELL, + RC_IRONGOLEM, + RC_STONEGOLEM, RC_SHADOW, RC_SHADOWLORD, - RC_IRONKEEPER, - RC_ALP, - RC_TOAD, + RC_IRONKEEPER, + RC_ALP, + RC_TOAD, RC_HIRNTOETER, - RC_PEASANT, - RC_WOLF = 32, + RC_PEASANT, + RC_WOLF = 32, - RC_SONGDRAGON = 37, + RC_SONGDRAGON = 37, RC_SEASERPENT = 51, - RC_SHADOWKNIGHT, - RC_CENTAUR, - RC_SKELETON, + RC_SHADOWKNIGHT, + RC_CENTAUR, + RC_SKELETON, RC_SKELETON_LORD, - RC_ZOMBIE, - RC_ZOMBIE_LORD, - RC_GHOUL, - RC_GHOUL_LORD, + RC_ZOMBIE, + RC_ZOMBIE_LORD, + RC_GHOUL, + RC_GHOUL_LORD, - RC_MUS_SPIRIT, - RC_GNOME, - RC_TEMPLATE, - RC_CLONE, + RC_MUS_SPIRIT, + RC_GNOME, + RC_TEMPLATE, + RC_CLONE, - MAXRACES, - NORACE = (race_t) - 1 + MAXRACES, + NORACE = (race_t) - 1 }; /* Richtungen */ enum { - D_NORTHWEST, - D_NORTHEAST, - D_EAST, - D_SOUTHEAST, - D_SOUTHWEST, - D_WEST, - MAXDIRECTIONS, - D_PAUSE, + D_NORTHWEST, + D_NORTHEAST, + D_EAST, + D_SOUTHEAST, + D_SOUTHWEST, + D_WEST, + MAXDIRECTIONS, + D_PAUSE, D_SPECIAL, - NODIRECTION = (direction_t) - 1 + NODIRECTION = (direction_t) - 1 }; #define DONT_HELP 0 -#define HELP_MONEY 1 /* Mitversorgen von Einheiten */ -#define HELP_FIGHT 2 /* Bei Verteidigung mithelfen */ -#define HELP_OBSERVE 4 /* Bei Wahrnehmung mithelfen */ -#define HELP_GIVE 8 /* Dinge annehmen ohne KONTAKTIERE */ -#define HELP_GUARD 16 /* Laesst Steuern eintreiben etc. */ -#define HELP_FSTEALTH 32 /* Parteitarnung anzeigen. */ -#define HELP_TRAVEL 64 /* Laesst Regionen betreten. */ -#define HELP_ALL (127-HELP_TRAVEL-HELP_OBSERVE) /* Alle "positiven" HELPs zusammen */ +#define HELP_MONEY 1 /* Mitversorgen von Einheiten */ +#define HELP_FIGHT 2 /* Bei Verteidigung mithelfen */ +#define HELP_OBSERVE 4 /* Bei Wahrnehmung mithelfen */ +#define HELP_GIVE 8 /* Dinge annehmen ohne KONTAKTIERE */ +#define HELP_GUARD 16 /* Laesst Steuern eintreiben etc. */ +#define HELP_FSTEALTH 32 /* Parteitarnung anzeigen. */ +#define HELP_TRAVEL 64 /* Laesst Regionen betreten. */ +#define HELP_ALL (127-HELP_TRAVEL-HELP_OBSERVE) /* Alle "positiven" HELPs zusammen */ /* HELP_OBSERVE deaktiviert */ /* ------------------------------------------------------------- */ /* Prototypen */ diff --git a/src/common/modules/autoseed.c b/src/common/modules/autoseed.c index 46076202e..6f9e6210a 100644 --- a/src/common/modules/autoseed.c +++ b/src/common/modules/autoseed.c @@ -49,23 +49,30 @@ #include const terrain_type * -random_terrain(boolean distribution) +random_terrain(const terrain_type * terrains[], int distribution[], int size) { - static int nterrains; - static int ndistribution; + int ndistribution = size; const terrain_type * terrain; int n; - if (nterrains==0) { - for (terrain=terrains();terrain;terrain=terrain->next) { - ndistribution += terrain->distribution; - ++nterrains; + + if (distribution) { + ndistribution = 0; + for (n=0;n!=size;++n) { + ndistribution += distribution[n]; } } - n = rng_int() % (distribution?ndistribution:nterrains); - for (terrain=terrains();terrain;terrain=terrain->next) { - n -= distribution?terrain->distribution:1; - if (n<0) break; + n = rng_int() % ndistribution; + if (distribution) { + int i; + for (i=0;i!=size;++i) { + n -= distribution[i]; + if (n<0) break; + } + assert(ipassword); free(nf); } -/** create new island with up to nsize players - * returns the number of players placed on the new island. - */ + static void frame_regions(int age, const terrain_type * terrain) { @@ -435,6 +440,7 @@ frame_regions(int age, const terrain_type * terrain) } } } + static void prepare_starting_region(region * r) { @@ -467,6 +473,9 @@ prepare_starting_region(region * r) fix_demand(r); } +/** 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) { @@ -477,7 +486,27 @@ autoseed(newfaction ** players, int nsize, int max_agediff) 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; + 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)=PLAYERS_PER_ISLAND) break; } else { - terraform_region(r, random_terrain(true)); + terraform_region(r, random_terrain(terrainarr, distribution, nterrains)); --isize; } } @@ -664,7 +693,7 @@ autoseed(newfaction ** players, int nsize, int max_agediff) const struct terrain_type * terrain = newterrain(T_OCEAN); rn = new_region(r->x + delta_x[d], r->y + delta_y[d], 0); if (rng_int() % SPECIALCHANCE < special) { - terrain = random_terrain(true); + terrain = random_terrain(terrainarr, distribution, nterrains); special = SPECIALCHANCE / 3; /* 33% chance auf noch eines */ } else { special = 1; @@ -706,3 +735,157 @@ autoseed(newfaction ** players, int nsize, int max_agediff) } return tsize; } + +static void get_neighbours(const region * r, region ** list) +{ + direction_t dir; + for (dir=0;dir!=MAXDIRECTIONS;++dir) { + list[dir] = rconnect(r, dir); + } +} + +region_list * regionqueue_push(region_list ** rlist, region * r) +{ + region_list * rnew = malloc(sizeof(region_list)); + rnew->data = r; + rnew->next = 0; + while (*rlist) { rlist = &(*rlist)->next; } + *rlist = rnew; + return rnew; +} + +region * regionqueue_pop(region_list ** rlist) +{ + if (*rlist) { + region * r = (*rlist)->data; + region_list * rpop = *rlist; + *rlist = rpop->next; + free(rpop); + return r; + } + return 0; +} + +#define GEOMAX 8 +static struct geo { + int distribution; + terrain_t type; +} geography_e3[GEOMAX] = { + { 8, T_OCEAN }, + { 3, T_SWAMP }, + { 1, T_VOLCANO }, + { 3, T_DESERT }, + { 3, T_HIGHLAND }, + { 3, T_MOUNTAIN }, + { 2, T_GLACIER }, + { 1, T_PLAIN } +}; + +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); +} + +int +random_neighbours(region * r, region_list ** rlist, const terrain_type *(*terraformer)(direction_t)) +{ + int nsize = 0; + direction_t dir; + for (dir=0;dir!=MAXDIRECTIONS;++dir) { + region * rn = rconnect(r, dir); + if (rn==NULL) { + const terrain_type * terrain = terraformer(dir); + rn = new_region(r->x+delta_x[dir], r->y+delta_y[dir], 0); + terraform_region(rn, terrain); + if (rn->land) { + regionqueue_push(rlist, rn); + ++nsize; + } + } + } + return nsize; +} + +const terrain_type * get_ocean(direction_t dir) +{ + return newterrain(T_OCEAN); +} + +int region_quality(const region * r) +{ + region * rn[MAXDIRECTIONS]; + int n, result = 0; + get_neighbours(r, rn); + for (n=0;n!=MAXDIRECTIONS;++n) { + if (rn[n] && rn[n]->land) { + result += rn[n]->land->peasants; + } + } +// result += r->land->peasants * 2; + return result; +} + +/* E3A island generation */ +int +build_island_e3(short x, short y, int numfactions, int minsize) +{ + int nfactions = 0; + region_list * rlist = NULL; + region_list * island = NULL; + region * r = new_region(x, y, 0); + int nsize = 1; + int q, maxq = INT_MIN, minq = INT_MAX; + + terraform_region(r, random_terrain_e3(NODIRECTION)); + + while (r) { + if (r->land) { + fset(r, RF_MARK); + regionqueue_push(&island, r); + } + if (nsizenext) { + r = rlist->data; + if (fval(r, RF_MARK)) { + region *rn[MAXDIRECTIONS]; + int n; + unit * u; + + freset(r, RF_MARK); + get_neighbours(r, rn); + for (n=0;n!=MAXDIRECTIONS;++n) { + freset(rn[n], RF_MARK); + } + q = region_quality(r); + if (q>1500 && nfactions #endif #include +#include #if DUNGEON_MODULE #include #endif @@ -56,6 +57,7 @@ #include #include +#include #include #include @@ -727,6 +729,7 @@ handlekey(state * st, int c) region *r; char sbuffer[80]; static char kbuffer[80]; + int n; switch(c) { case FAST_RIGHT: @@ -785,7 +788,11 @@ handlekey(state * st, int c) } break; case 'B': + /* make_block((short)st->cursor.x, (short)st->cursor.y, 6, select_terrain(st, NULL)); + */ + n = rng_int() % 8 + 8; + build_island_e3((short)st->cursor.x, (short)st->cursor.y, n, n*4); st->modified = 1; st->wnd_info->update |= 1; st->wnd_status->update |= 1;