diff --git a/src/common/kernel/unit.c b/src/common/kernel/unit.c index 528f65175..23747ff36 100644 --- a/src/common/kernel/unit.c +++ b/src/common/kernel/unit.c @@ -685,21 +685,37 @@ transfermen(unit * u, unit * u2, int n) for (sk=0; sk!=MAXSKILLS; ++sk) { double dlevel = 0.0; - int weeks, level; + int weeks, level = 0; sv = get_skill(u, sk); sn = get_skill(u2, sk); if (sv==NULL && sn==NULL) continue; - if (sv && sv->level) dlevel += (sv->level + 1 - sv->weeks/(sv->level*2.0+1)) * n; - else dlevel += 0.5 * n; - if (sn && sn->level) dlevel += (sn->level + 1 - sn->weeks/(sn->level*2.0+1)) * u2->number; - else dlevel += 0.5 * u2->number; + if (sv && sv->level) { + dlevel += (sv->level + 1 - sv->weeks/(sv->level+1.0)) * n; + level += sv->level * n; + } + if (sn && sn->level) { + dlevel += (sn->level + 1 - sn->weeks/(sn->level+1.0)) * u2->number; + level += sn->level * u2->number; + } dlevel = dlevel / (n + u2->number); - level = (int)dlevel; - weeks = (int)((level*2.0+1) * (1 - dlevel + level)+0.9999999); - + level = level / (n + u2->number); + if (level<=dlevel) { + /* apply the remaining fraction to the number of weeks to go. + * subtract the according number of weeks, getting closer to the + * next level */ + level = (int)dlevel; + weeks = (level+1) - (int)((dlevel - level) * (level+1)); + } else { + /* make it harder to reach the next level. + * weeks+level is the max difficulty, 1 - the fraction between + * level and dlevel applied to the number of weeks between this + * and the previous level is the added difficutly */ + level = (int)dlevel+1; + weeks = 1 + 2 * level - (int)((1 + dlevel - level) * level); + } if (level) { if (sn==NULL) sn = add_skill(u2, sk); sn->level = (unsigned char)level; @@ -784,6 +800,7 @@ u_setfaction(unit * u, faction * f) #endif if (u->faction) { set_number(u, 0); + --u->faction->no_units; join_group(u, NULL); } if (u->prevF) u->prevF->nextF = u->nextF; @@ -802,9 +819,11 @@ u_setfaction(unit * u, faction * f) u->prevF = NULL; u->faction = f; - if (cnt && f) set_number(u, cnt); + if (cnt && f) { + set_number(u, cnt); + ++f->no_units; + } } - /* vorsicht Sprüche können u->number == 0 (RS_FARVISION) haben! */ void set_number(unit * u, int count) diff --git a/src/mapper/autoseed.c b/src/mapper/autoseed.c new file mode 100644 index 000000000..cb97b8d39 --- /dev/null +++ b/src/mapper/autoseed.c @@ -0,0 +1,258 @@ +/* vi: set ts=2: + +-------------------+ Christian Schlittchen + | | Enno Rehling + | Eressea PBEM host | Katja Zedel + | (c) 1998 - 2001 | 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 + +/* libc includes */ +#include +#include + +newfaction * newfactions = NULL; + +static int regions_per_faction = 3; + +void +get_island(regionlist ** rlist) +{ + regionlist *rcurrent = *rlist; + regionlist **rnext = &rcurrent->next; + assert(rcurrent && *rnext==NULL); + + fset(rcurrent->region, FL_MARK); + while (rcurrent!=NULL) { + direction_t dir; + for (dir=0;dir!=MAXDIRECTIONS;++dir) { + region * r = rconnect(rcurrent->region, dir); + if (r!=NULL && r->land && !fval(r, FL_MARK)) { + fset(r, FL_MARK); + add_regionlist(rnext, r); + } + } + rcurrent = *rnext; + rnext = &rcurrent->next; + } + rnext=rlist; + while (*rnext) { + rcurrent = *rnext; + freset(rcurrent->region, FL_MARK); + rnext = &rcurrent->next; + } +} + +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; + } + } +/* + q = q / nplayers; + for (i=0;i!=nplayers;++i) { + quality -= (qarr[i]-q)*(qarr[i]-q); + } + */ + return quality + q; +} + +void +autoseed(struct regionlist * rlist) +{ + int nregions = listlen(rlist); + int nseeds = nregions; + double lastq; + seed_t * seeds = calloc(sizeof(seed_t), nseeds); + int i, nfactions = 0; + newfaction * nf = newfactions; + + while (nf) { + if (nf->bonus==0) ++nfactions; + nf = nf->next; + } + nfactions = min(nfactions, nregions/regions_per_faction); + + nf = newfactions; + for (i=0;i!=nseeds;++i) { + seeds[i].region = rlist->region; + rlist = rlist->next; + if (ibonus!=0) nf=nf->next; + seeds[i].player = nf; + nf = nf->next; + } + } + for (i=0;i!=nseeds;++i) { + direction_t d; + for (d=0;d!=MAXDIRECTIONS;++d) { + region * r = rconnect(seeds[i].region, d); + if (r && r->land) { + int k; + for (k=i+1;k!=nseeds;++k) if (seeds[k].region==r) { + seeds[k].next[back[d]] = seeds+i; + seeds[i].next[d] = seeds+k; + } + } + } + } + + lastq = recalc(seeds, nseeds, nfactions); + for (;;) { + double quality = lastq; + int i; + for (i=0;i!=nseeds;++i) { + int k; + for (k=i+1;k!=nseeds;++k) { + double q; + newfaction * player = seeds[k].player; + if (player==NULL && seeds[i].player==NULL) continue; + seeds[k].player = seeds[i].player; + seeds[i].player = player; + q = recalc(seeds, nseeds, nfactions); + if (q>quality) { + quality = q; + } else { + /* undo */ + seeds[i].player = seeds[k].player; + seeds[k].player = player; + } + } + } + if (lastq==quality) break; + else lastq = quality; + } + for (i=0;i!=nseeds;++i) { + newfaction * nf = seeds[i].player; + if (nf) { + newfaction ** nfp = &newfactions; + while (*nfp!=nf) nfp=&(*nfp)->next; + addplayer(seeds[i].region, nf->email, nf->race, nf->lang); + *nfp = nf->next; + free(nf); + } + } +} diff --git a/src/mapper/autoseed.h b/src/mapper/autoseed.h new file mode 100644 index 000000000..f1116f700 --- /dev/null +++ b/src/mapper/autoseed.h @@ -0,0 +1,33 @@ +/* vi: set ts=2: + +-------------------+ Christian Schlittchen + | | Enno Rehling + | Eressea PBEM host | Katja Zedel + | (c) 1998 - 2001 | Henning Peters + | | Ingo Wilken + +-------------------+ Stefan Reich + + This program may not be used, modified or distributed + without prior permission by the authors of Eressea. +*/ + +#ifndef _REGIONLIST_H +#define _REGIONLIST_H + +struct regionlist; +struct newfaction; + +typedef struct newfaction { + struct newfaction * next; + const char * email; + const struct locale * lang; + const struct race * race; + int bonus; + boolean oldregions; +} newfaction; + +extern newfaction * newfactions; + +extern void autoseed(struct regionlist * rlist); +extern void get_island(struct regionlist ** rlist); + +#endif diff --git a/src/mapper/map_partei.c b/src/mapper/map_partei.c index faf26046b..8bdcdb257 100644 --- a/src/mapper/map_partei.c +++ b/src/mapper/map_partei.c @@ -17,6 +17,8 @@ #include #include "mapper.h" +#include "autoseed.h" + /* kernel includes */ #include #include @@ -160,7 +162,6 @@ typedef struct dropout { } dropout; static dropout * dropouts; -static newfaction * newfactions; void read_orders(const char * filename) @@ -248,9 +249,10 @@ seed_dropouts(void) if (nf->race==drop->race && !nf->bonus) { unit * u = addplayer(r, nf->email, nf->race, nf->lang); if (nf->bonus) give_latestart_bonus(r, u, nf->bonus); - *nfp = nf->next; - *dropp = drop->next; found=true; + *dropp = drop->next; + *nfp = nf->next; + free(nf); break; } nfp = &nf->next; @@ -439,6 +441,7 @@ NeuePartei(region * r) newfaction * nf = *nfp; if (strcmp(email, nf->email)==0) { *nfp = nf->next; + free(nf); } else nfp = &nf->next; } diff --git a/src/mapper/mapper.c b/src/mapper/mapper.c index 8316e4a31..266bea6b0 100644 --- a/src/mapper/mapper.c +++ b/src/mapper/mapper.c @@ -17,11 +17,12 @@ #define BOOL_DEFINED /* wenn config.h nicht vor curses included wird, kompiliert es unter windows nicht */ #include -#include #include #include #include "mapper.h" +#include "autoseed.h" + #include #include #include @@ -52,6 +53,7 @@ #include #include #include +#include #include #include #include @@ -61,6 +63,7 @@ extern char *reportdir; extern char *datadir; extern char *basedir; extern int maxregions; +extern boolean dirtyload; char datafile[256]; /* -------------------- resizeterm ------------------------------------- */ @@ -1042,8 +1045,18 @@ movearound(int rx, int ry) { make_ocean_block(rx, ry); ch = -9; break; + case 'a': + if (r && r->land) { + regionlist * rlist = NULL; + add_regionlist(&rlist, r); + get_island(&rlist); + autoseed(rlist); + modified = 1; + } + break; case 's': seed_dropouts(); + modified = 1; break; case 'S': if (modified) @@ -1467,6 +1480,9 @@ main(int argc, char *argv[]) case 'v': orderfile = argv[++i]; break; + case 'X': + dirtyload = true; + break; case 'x': maxregions = atoi(argv[++i]); maxregions = (maxregions*81+80) / 81; diff --git a/src/mapper/mapper.dsp b/src/mapper/mapper.dsp index 541279d5c..d27ed8ccf 100644 --- a/src/mapper/mapper.dsp +++ b/src/mapper/mapper.dsp @@ -87,6 +87,10 @@ LINK32=link.exe # PROP Default_Filter "*.h" # Begin Source File +SOURCE=.\autoseed.h +# End Source File +# Begin Source File + SOURCE=.\logging.h # End Source File # Begin Source File @@ -112,6 +116,10 @@ SOURCE=..\modules\weather.h # End Group # Begin Source File +SOURCE=.\autoseed.c +# End Source File +# Begin Source File + SOURCE=.\logging.c # End Source File # Begin Source File diff --git a/src/mapper/mapper.h b/src/mapper/mapper.h index 6a4afa8a9..2b4426d5f 100644 --- a/src/mapper/mapper.h +++ b/src/mapper/mapper.h @@ -43,15 +43,6 @@ typedef struct tagregion { struct region *r; } tagregion; -typedef struct newfaction { - struct newfaction * next; - const char * email; - const struct locale * lang; - const struct race * race; - int bonus; - boolean oldregions; -} newfaction; - extern tagregion *Tagged; void saddstr(char *s);