/* vi: set ts=2: +-------------------+ Christian Schlittchen | | Enno Rehling | Eressea PBEM host | Katja Zedel | (c) 1998 - 2003 | Henning Peters | | Ingo Wilken +-------------------+ Stefan Reich This program may not be used, modified or distributed without prior permission by the authors of Eressea. */ #include #include #include "autoseed.h" /* kernel includes */ #include #include #include #include #include #include /* util includes */ #include #include /* libc includes */ #include #include #include #include newfaction * read_newfactions(const char * filename) { newfaction * newfactions = NULL; FILE * F = fopen(filename, "r"); if (F==NULL) return NULL; for (;;) { faction * f; char race[20], email[64], lang[8], password[16]; newfaction *nf, **nfi; int bonus, subscription; int alliance = 0; if (alliances!=NULL) { /* email;race;locale;startbonus;subscription;alliance */ if (fscanf(F, "%s %s %s %d %d %s %d", email, race, lang, &bonus, &subscription, password, &alliance)<=0) break; } else { /* email;race;locale;startbonus;subscription */ if (fscanf(F, "%s %s %s %d %d %s", email, race, lang, &bonus, &subscription, password)<=0) break; } for (f=factions;f;f=f->next) { if (strcmp(f->email, email)==0 && f->subscription) break; } if (f) continue; /* skip the ones we've already got */ for (nf=newfactions;nf;nf=nf->next) { if (strcmp(nf->email, email)==0) break; } if (nf) continue; nf = calloc(sizeof(newfaction), 1); if (set_email(&nf->email, email)!=0) { log_error(("Invalid email address for subscription %s: %s\n", itoa36(subscription), email)); continue; } nf->password = strdup(password); nf->race = rc_find(race); nf->subscription = subscription; if (alliances!=NULL) { struct alliance * al = findalliance(alliance); if (al==NULL) { char zText[64]; sprintf(zText, "Allianz %d", alliance); al = makealliance(alliance, zText); } nf->allies = al; } else { nf->allies = NULL; } if (nf->race==NULL) nf->race = findrace(race, default_locale); nf->lang = find_locale(lang); nf->bonus = bonus; assert(nf->race && nf->email && nf->lang); nfi = &newfactions; while (*nfi) { if ((*nfi)->race==nf->race) break; nfi=&(*nfi)->next; } nf->next = *nfi; *nfi = nf; } fclose(F); return newfactions; } typedef struct seed_t { struct region * region; struct newfaction * player; struct seed_t * next[MAXDIRECTIONS]; } seed_t; double get_influence(struct seed_t * seed, struct seed_t * target) { double q = 0.0; direction_t d; if (target==0 || seed==0) return q; for (d=0;d!=MAXDIRECTIONS;++d) { seed_t * s = seed->next[d]; if (s==target) { if (target->player) { if (seed->player) { /* neighbours bad. */ q -= 4.0; if (seed->player->race==target->player->race) { /* don't want similar people next to each other */ q -= 2.0; } else if (seed->player->race==new_race[RC_ELF]) { if (target->player->race==new_race[RC_TROLL]) { /* elf sitting next to troll: poor troll */ q -= 5.0; } } } else if (target->player) { /* empty regions good */ q += 1.0; } } } } return q; } double get_quality(struct seed_t * seed) { double q = 0.0; int nterrains[MAXTERRAINS]; direction_t d; memset(nterrains, 0, sizeof(nterrains)); for (d=0;d!=MAXDIRECTIONS;++d) { seed_t * ns = seed->next[d]; if (ns) ++nterrains[rterrain(ns->region)]; } ++nterrains[rterrain(seed->region)]; if (nterrains[T_MOUNTAIN]) { /* 5 points for the first, and 2 points for every other mountain */ q += (3+nterrains[T_MOUNTAIN]*2); } else if (seed->player->race==new_race[RC_DWARF]) { /* -10 for a dwarf who isn't close to a mountain */ q -= 10.0; } if (nterrains[T_PLAIN]) { /* 5 points for the first, and 2 points for every other plain */ q += (3+nterrains[T_PLAIN]*2); } else if (seed->player->race==new_race[RC_ELF]) { /* -10 for an elf who isn't close to a plain */ q -= 10.0; } if (nterrains[T_DESERT]) { /* +10 points for the first if we are insects, and -2 points for every * other desert */ if (seed->player->race==new_race[RC_INSECT]) q += 12; q -= (nterrains[T_DESERT]*2); } switch (rterrain(seed->region)) { case T_DESERT: q -=8.0; break; case T_VOLCANO: q -=20.0; break; case T_GLACIER: q -=10.0; break; case T_SWAMP: q -= 1.0; break; case T_PLAIN: q += 4.0; break; case T_MOUNTAIN: q += 5.0; break; } return 2.0; } double recalc(seed_t * seeds, int nseeds, int nplayers) { int i, p = 0; double quality = 0.0, q = 0.0, *qarr = malloc(sizeof(int) * nplayers); for (i=0;i!=nseeds;++i) { if (seeds[i].player) { double quality = get_quality(seeds+i); direction_t d; for (d=0;d!=MAXDIRECTIONS;++d) { quality += get_influence(seeds[i].next[d], seeds+i); } qarr[p++] = quality; q += quality; } } return quality + q; } extern int numnewbies; static terrain_t preferred_terrain(const struct race * rc) { if (rc==rc_find("dwarf")) return T_MOUNTAIN; if (rc==rc_find("insect")) return T_DESERT; if (rc==rc_find("halfling")) return T_SWAMP; if (rc==rc_find("troll")) return T_MOUNTAIN; return T_PLAIN; } #define REGIONS_PER_FACTION 2 #define MINFACTIONS 1 #define MAXAGEDIFF 5 #define VOLCANO_CHANCE 100 int autoseed(newfaction ** players, int nsize) { int x = 0, y = 0; region * r; region_list * rlist = NULL; int rsize, isize=0; region * rmin = NULL; direction_t d; int dist; for (r=regions;r;r=r->next) { struct plane * p = rplane(r); if (r->terrain==T_OCEAN && p==NULL && (rmin==NULL || r->age<=MAXAGEDIFF)) { direction_t d; for (d=0;d!=MAXDIRECTIONS;++d) { if (rconnect(r, d)==NULL) break; } if (d!=MAXDIRECTIONS) rmin=r; } } r = NULL; for (dist=1;r!=rmin;++dist) { for (d=0;r!=rmin && d!=MAXDIRECTIONS;++d) { int i; region * rn = rmin; for (i=0;i!=dist;++i) rn=rconnect(rn, d); if (rn==NULL) { r = rmin; x = rmin->x + delta_x[d] * dist; y = rmin->y + delta_y[d] * dist; } } } if (listlen(*players)next; r = (*rnext)->data; *rnext = (*rnext)->next; if (rsize==0) { log_error(("Could not place all factions on the same island as requested\n")); break; } --rsize; assert(r->terrain==T_OCEAN); for (d=0;d!=MAXDIRECTIONS;++d) { region * rn = rconnect(r, d); if (rn==NULL) { rn = new_region(r->x + delta_x[d], r->y + delta_y[d]); terraform(rn, T_OCEAN); add_regionlist(&rlist, rn); ++rsize; } } if (rand() % VOLCANO_CHANCE == 0) { terraform(r, T_VOLCANO); } else if (rand() % REGIONS_PER_FACTION == 0 || rsize==0) { newfaction ** nfp, * nextf = *players; unit * u; terraform(r, preferred_terrain(nextf->race)); ++isize; u = addplayer(r, addfaction(nextf->email, nextf->password, nextf->race, nextf->lang, nextf->subscription)); u->faction->alliance = nextf->allies; /* remove duplicate email addresses */ nfp = players; while (*nfp) { newfaction * nf = *nfp; if (strcmp(nextf->email, nf->email)==0) { *nfp = nf->next; if (nextf!=nf) free(nf); } else nfp = &nf->next; } --nsize; } else { terraform(r, (terrain_t)((rand() % T_GLACIER)+1)); } } if (rlist) { #define MINOCEANDIST 3 #define MAXFILLDIST 10 #define SPECIALCHANCE 80 region_list ** rbegin = &rlist; int i; int special = 1; for (i=0;i!=MINOCEANDIST;++i) { 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) { terrain_t terrain = T_OCEAN; rn = new_region(r->x + delta_x[d], r->y + delta_y[d]); if (rand() % SPECIALCHANCE < special) { terrain = (terrain_t)(1 + rand() % T_GLACIER); special = SPECIALCHANCE / 3; /* 33% chance auf noch eines */ } else { special = 1; } terraform(rn, terrain); /* the new region has an extra 15% chance to have laen */ if (rand() % 100 < 15) rsetlaen(r, 5 + rand() % 5); /* the new region has an extra 20% chance to have mallorn */ if (rand() % 100 < 20) fset(r, RF_MALLORN); add_regionlist(rend, rn); } } } } while (*rbegin) { region * r = (*rbegin)->data; 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) { if (findregion(r->x + i*delta_x[d], r->y + i*delta_y[d])) break; } if (i!=MAXFILLDIST) { while (--i) { region * rn = new_region(r->x + i*delta_x[d], r->y + i*delta_y[d]); terraform(rn, T_OCEAN); } } } } } return isize; }