/* vi: set ts=2: * * Eressea PB(E)M host Copyright (C) 1998-2000 * 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) * * based on: * * Atlantis v1.0 13 September 1993 Copyright 1993 by Russell Wallace * Atlantis v1.7 Copyright 1996 by Alex Schröder * * This program may not be used, modified or distributed without * prior permission by the authors of Eressea. * This program may not be sold or used commercially without prior written * permission from the authors. */ #include #include /* misc includes */ #include #include #include #include /* gamecode includes */ #include #include /* kernel includes */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* util includes */ #include #include #include #include #include #include #include /* libc includes */ #include #include #include #include /* attributes includes */ #include #include #undef XMAS1999 #undef XMAS2000 #undef XMAS2001 extern void reorder_owners(struct region * r); static void verify_owners(boolean bOnce) { region * r; for (r=regions;r;r=r->next) { unit * u; boolean bFail = false; for (u=r->units;u;u=u->next) { if (u->building) { unit * bo = buildingowner(r, u->building); if (!fval(bo, FL_OWNER)) { log_error(("[verify_owners] %u ist Besitzer von %s, hat aber FL_OWNER nicht.\n", unitname(bo), buildingname(u->building))); bFail = true; if (bOnce) break; } if (bo!=u && fval(u, FL_OWNER)) { log_error(("[verify_owners] %u ist NICHT Besitzer von %s, hat aber FL_OWNER.\n", unitname(u), buildingname(u->building))); bFail = true; if (bOnce) break; } } if (u->ship) { unit * bo = shipowner(r, u->ship); if (!fval(bo, FL_OWNER)) { log_error(("[verify_owners] %u ist Besitzer von %s, hat aber FL_OWNER nicht.\n", unitname(bo), shipname(u->ship))); bFail = true; if (bOnce) break; } if (bo!=u && fval(u, FL_OWNER)) { log_error(("[verify_owners] %u ist NICHT Besitzer von %s, hat aber FL_OWNER.\n", unitname(u), shipname(u->ship))); bFail = true; if (bOnce) break; } } } if (bFail) reorder_owners(r); } } /* make sure that this is done only once! */ #define do_once(magic, fun) \ { \ attrib * a = find_key(global.attribs, atoi36(magic)); \ if (a) { \ log_warning(("[do_once] a unique fix %d=\"%s\" was called a second time\n", atoi36(magic), magic)); \ } else { \ if (fun == 0) a_add(&global.attribs, make_key(atoi36(magic))); \ } \ } int warn_items(void) { boolean found = 0; region * r; for (r=regions;r;r=r->next) { unit * u; for (u=r->units;u;u=u->next) { item * itm; for (itm=u->items;itm;itm=itm->next) { if (itm->number>100000) { found = 1; log_error(("Einheit %s hat %u %s\n", unitid(u), itm->number, resourcename(itm->type->rtype, 0))); } } } } return found; } #ifdef XMAS1999 #include "race.h" #include "movement.h" static void santa_comes_to_town(void) { unit * santa = ufindhash(atoi36("xmas")); unit * tans = ufindhash(atoi36("tans")); faction * f; region * r; if (!tans) r = findregion(0,0); else r = tans->region; if (!r) return; while (santa && santa->race!=RC_ILLUSION) { uunhash(santa); santa->no = newunitid(); uhash(santa); santa = ufindhash(atoi36("xmas")); } if (!santa) { santa = createunit(r, findfaction(MONSTER_FACTION), 1, new_race[RC_ILLUSION]); uunhash(santa); santa->no = atoi36("xmas"); uhash(santa); } santa->age = 2; santa->irace = new_race[RC_DAEMON]; set_string(&santa->name, "Ein dicker Gnom mit einem Rentierschlitten"); set_string(&santa->display, "hat: 6 Rentiere, Schlitten, Sack mit Geschenken, Kekse für Khorne"); fset(santa, FL_TRAVELTHRU); for (f=factions;f;f=f->next) { unit * u; runit *ru; region * r; item_t i = (item_t) (rand() % 4 + I_KEKS); unit * senior = f->units; for (u = f->units; u; u=u->nextF) { if (senior->age < u->age) senior = u; } if (!senior) continue; r = senior->region; sprintf(buf, "%s gibt %d %s an %s.", unitname(santa), 1, itemdata[i].name[0], unitname(senior)); change_item(senior, i, 1); addmessage(r, senior->faction, buf, MSG_COMMERCE, ML_INFO); sprintf(buf, "von %s: 'Ho ho ho. Frohe Weihnachten, und %s für %s.'", unitname(santa), itemdata[i].name[1], unitname(senior)); addmessage(r, 0, buf, MSG_MESSAGE, ML_IMPORTANT); for (ru = r->durchgezogen; ru ; ru=ru->next) if (ru->unit==santa) break; if (!ru) { ru = calloc(1, sizeof(runit)); ru->next = r->durchgezogen; ru->unit = santa; r->durchgezogen = ru; } } } #endif #if 0 static void init_hp(void) { region *r; unit *u; for (r = regions; r; r = r->next) { for (u = r->units; u; u = u->next) { if (u->hp == -1) { u->hp = unit_max_hp(u) * u->number; } } } } static void convert(int x, int y, int *nx, int *ny) { *ny = -y; *nx = x + (y + ((y>=0)?1:0))/2; } #endif #if 0 static void loesche_coasts(void) { region *r; ship *sh; for(r=regions;r;r=r->next) { for(sh=r->ships;sh;sh=sh->next) { sh->coast = NODIRECTION; } } } #endif #if 0 static void create_underworld(void) { int x, y; region *r; attrib *a; plane * hell = create_new_plane(-1, "Hölle", 100000, 100000, 100020, 100020, PFL_NONE); for(x=0;x<=20;x++) { for(y=0;y<=20;y++) { r = new_region(x+100000,y); r->planep = hell; if(x==0 || x == 20 || y == 0 || y == 20) { rsetterrain(r, T_FIREWALL); } else { rsetterrain(r, T_HELL); } } } /* Verbindungen schaffen */ a = create_special_direction(findregion(4,4),100005,5,-1, "Ein dunkler Schlund fuehrt in die Tiefe der Erde", "Schlund"); a = create_special_direction(findregion(100005,5),4,4,-1, "Ein hell erleuchteter Tunnel fuehrt nach oben", "Tunnel"); } #endif #if 0 static void bename_dracoide(void) { region *r; unit *u; for(r=regions;r;r=r->next) { for(u=r->units;u;u=u->next) { if(u->race == new_race[RC_DRACOID]) name_unit(u); } } } #endif static void fix_migrants(void) { region * r; for (r=regions;r;r=r->next) { unit * u; for (u=r->units;u;u=u->next) { if (u->race == new_race[RC_HUMAN]) u->irace = u->race; if (u->irace!=u->race && (u->race->flags & RCF_SHAPESHIFT)==0) { log_warning(("[fix_migrants] %s ist ein %s, als %s getarnt\n", unitname(u), LOC(default_locale, rc_name(u->race, 0)), LOC(default_locale, rc_name(u->irace, 0)))); } } } } static boolean kor_teure_talente(unit *u) { if(effskill(u, SK_TACTICS) >= 1 || effskill(u, SK_MAGIC) >= 1 || effskill(u, SK_ALCHEMY) >= 1 || effskill(u, SK_HERBALISM) >= 1 || effskill(u, SK_SPY) >= 1) { return true; } return false; } static void no_teurefremde(boolean convert) { region *r; unit *u; for(r=regions;r;r=r->next) { for(u=r->units;u;u=u->next) { if(u->faction->no != MONSTER_FACTION && is_migrant(u) && kor_teure_talente(u)) { log_printf("* Warnung, teurer Migrant: %s %s\n", unitname(u), factionname(u->faction)); if(convert) { u->race = u->faction->race; u->irace = u->faction->race; u->faction->num_migrants -= u->number; sprintf(buf, "Die Götter segnen %s mit der richtigen Rasse", unitname(u)); addmessage(0, u->faction, buf, MSG_MESSAGE, ML_IMPORTANT); } } } } } #if 0 static void give_arena_gates(void) { faction * f; for (f=factions;f;f=f->next) { unit * u; region * r; unit * senior = f->units; if (f->age>2) return; for (u = f->units; u; u=u->nextF) { if (senior->age < u->age) senior = u; if (f->no==MONSTER_FACTION && get_item(u, I_ARENA_GATE)) return; } if (!senior) continue; r = senior->region; sprintf(buf, "Der Himmel über %s reißt auf und ein Licht aus den Wolken scheint auf %s. Ein Gesang wie von tausend Walküren ertönt, dazu Schlachtenlärm. Nach einer Weile endet die Vision, und %s hält ein %s in den Händen.", regionid(senior->region), unitname(senior), unitname(senior), itemdata[I_ARENA_GATE].name[0]); change_item(senior, I_ARENA_GATE, 1); addmessage(NULL, senior->faction, buf, MSG_MESSAGE, ML_IMPORTANT); } } static void remove_impossible_dragontargets(void) { region *r; for (r=regions;r;r=r->next) { unit *u; for (u=r->units;u;u=u->next) { attrib *a; if(u->faction->no != MONSTER_FACTION) continue; a = a_find(u->attribs, &at_targetregion); if (a!=NULL) { boolean cango = false; region * r2 = a->data.v; if(r2!=NULL) { #ifdef NEW_PATH cango = path_exists(r, r2, DRAGON_RANGE, allowed_dragon); #else cango = path_exists(r, r2, FLY|DRAGON_LIMIT); #endif } if(!cango) { printf("Lösche Ziel von %s\n", unitname(u)); a_remove(&u->attribs, a); } } } } } static void fix_score_option(void) { faction * f; for (f=factions;f;f=f->next) { f->options &= ((1<options &= ~(1<options |= (1<next) { for(u=r->units; u; u=u->next) { int wounds = unit_max_hp(u)*u->number - u->hp; u->hp = max(1, u->hp - wounds); } } } #endif #if 0 static void fix_beached(void) { region * r; for (r=regions;r;r=r->next) { if (r->land && rterrain(r)!=T_PLAIN) { ship * s; building *b; for(b=r->buildings; b; b=b->next) { if(b->typ == BT_HAFEN) break; } if(b == NULL) { for (s=r->ships;s;s=s->next) { if (s->coast!=NODIRECTION && s->type>SH_BOAT) { region * r2 = rconnect(r, s->coast); assert(rterrain(r2)==T_OCEAN || fval(r2, RF_CHAOTIC)); move_ship(s, r, r2, NULL); } } } } } } #endif #if 0 static void fix_hungrydead(void) { region *r; unit *u; for (r=regions;r;r=r->next) { for (u=r->units;u;u=u->next) { if(u->hp == 0) u->hp = 1; } } } static void name_seaserpents(void) { region *r; unit *u; for (r=regions;r;r=r->next) { for (u=r->units;u;u=u->next) { if(u->race == new_race[RC_SEASERPENT] && strncmp(u->name, "Nummer ", 7)) { set_string(&u->name, "Seeschlange"); } } } } #endif static int old_rroad(region * r) { attrib * a = a_find(r->attribs, &at_road); if (!a) return 0; return a->data.i; } attrib_type at_roadfix = { "roadfix", DEFAULT_INIT, DEFAULT_FINALIZE, DEFAULT_AGE, #if RELEASE_VERSIONnext) if (terrain[rterrain(r)].roadreq>0) { direction_t d; int connections = 0; int maxcon = MAXDIRECTIONS; int stones = old_rroad(r); if (stones<=0) continue; for (d=0;d!=MAXDIRECTIONS;++d) { region * r2 = rconnect(r, d); if (r2 && old_rroad(r2)) ++connections; else if (terrain[rterrain(r2)].roadreq<=0) --maxcon; } if (!connections) connections=maxcon; else maxcon=0; for (d=0;d!=MAXDIRECTIONS && connections;++d) { region * r2 = rconnect(r, d); int use = stones/connections; if (!r2 || terrain[rterrain(r2)].roadreq<=0 || (old_rroad(r2)<=0 && !maxcon)) continue; if (use>terrain[rterrain(r)].roadreq) { /* wenn etwas übrig bleibt (connections==1) kriegt es der regionserste */ int give = use-terrain[rterrain(r)].roadreq; unit * u = r->units; use = terrain[rterrain(r)].roadreq; if (u) change_item(u, I_STONE, give); } rsetroad(r, d, use); stones = stones - use; --connections; if (old_rroad(r)==terrain[rterrain(r)].roadreq*2 && old_rroad(r2)==terrain[rterrain(r2)].roadreq*2) { border * b = get_borders(r, r2); attrib * a = a_find(b->attribs, &at_roadfix); if (a) continue; while (b && b->type!=&bt_road) b = b->next; assert(b); a = a_add(&b->attribs, a_new(&at_roadfix)); } } } } /* ************************************************************ */ /* GANZ WICHTIG! ALLE GEÄNDERTEN SPRÜCHE NEU ANZEIGEN */ /* GANZ WICHTIG! FÜGT AUCH NEUE ZAUBER IN DIE LISTE DER BEKANNTEN EIN */ /* ************************************************************ */ static void show_newspells(void) { region *r; /* Alle geänderten Zauber in das array newspellids[]. mit SPL_NOSPELL * terminieren */ spellid_t newspellids[] = { SPL_NOSPELL }; /* die id's der neuen oder veränderten Sprüche werden in newspellids[] * abgelegt */ for(r=regions; r; r=r->next) { unit *u; for(u=r->units;u;u=u->next) { sc_mage *m = get_mage(u); if (u->faction->no == MONSTER_FACTION) continue; if (m != NULL) { int i; if (m->magietyp == M_GRAU) continue; for (i = 0; newspellids[i] != SPL_NOSPELL; i++) { spell *sp = find_spellbyid(newspellids[i]); if (!sp) continue; if (m->magietyp == sp->magietyp || getspell(u, sp->id)) { attrib * a = a_find(u->faction->attribs, &at_reportspell); while (a && a->data.i != sp->id) a = a->nexttype; if (!a) { /* spell is not being shown yet. if seen before, remove to show again */ a = a_find(u->faction->attribs, &at_seenspell); while (a && a->data.i != sp->id) a = a->nexttype; if (a) a_remove(&u->faction->attribs, a); } } } } } } } #if 0 static void fix_feuerwand_orks(void) { unit *u; if((u=findunitg(atoi36("1j1L"), NULL))==NULL) { printf("Korrektur: kann Orks nicht finden!\n"); return; } if(u->number < 1000) { printf("Korrektur: Orks sind schon korrigiert!\n"); return; } scale_number(u,170); u->hp=2337; /* Buggy Anzahl Personen = Normale HP */ } static void fix_buildings(void) { building *burg; unit *u, *uf = NULL; const requirement *req; const construction *con; FILE *statfile; vset done; int s1, s2; char buf[256]; int a,b,c,d; int first; if((statfile=fopen("building.txt","r"))==NULL) { log_warning(("fix_buildings: cannot open building.txt!\n")); return; } vset_init(&done); s1=s2=-1; while(fgets(buf, 256, statfile)!=NULL) { if(*buf=='#') continue; a=b=c=d=0; first=0; sscanf(buf,"%d;%d;%d;%d",&a,&b,&c,&d); if((u=findunitg(b,NULL))==NULL) { printf("fix_buildings: Einheit %d nicht gefunden.\n",b); continue; } if((burg=findbuilding(a))==NULL) { printf("fix_buildings: Burg %d nicht gefunden.\n", a); if((burg=u->building)==NULL) { printf("Einheit %d steht auch in keinem Gebäude. (gebe auf)\n",u->no); continue; } if(burg->type->construction->maxsize > 0 && burg->type->construction->reqsize > 0) printf("Ersatz: Burg %d\n",burg->no); else { printf("Ersatzgebäude ist nicht vom betroffenen Typ.\n"); continue; } } printf("Burg %d; Einheit %d; vorher %d; + %d\n",burg->no,u->no,c,d); s2=vset_add(&done, (void *)a); if(s2>s1) { printf("ERSTER !\n"); first=1; uf=u; } s1=s2; con=burg->type->construction; if(con->maxsize != -1 || con->reqsize == 1) continue; for(req=con->materials; req->number!=0; req++) { int diff=burg->size-c; if(req->type==R_SILVER) change_resource(uf, R_SILVER, diff*req->number-d*req->number/con->reqsize); else { if(first) change_resource(uf, req->type, diff*req->number); assert(uf!=NULL); change_resource(uf, req->type, -d*req->number/con->reqsize); } } if(first) burg->size=c+d; else burg->size+=d; } vset_destroy(&done); fclose(statfile); } #endif extern plane * arena; static void fix_age(void) { faction * f; for (f=factions;f;f=f->next) { if (f->no!=MONSTER_FACTION && playerrace(f->race)) continue; if (f->age!=turn) { log_printf("Alter von Partei %s auf %d angepasst.\n", factionid(f), turn); f->age = turn; } } } #if 0 static boolean balsambug(const region *r) { direction_t dir; for (dir=0; dir 0) return false; } return true; } static void fix_balsamfiasko(void) { region *r, *rc; direction_t dir; int i; for (r=regions; r; r=r->next) freset(r, RF_DH); /* Zufällig verteilen */ for (r=regions; r; r=r->next) { if (r->x < -36 && r->y < -45 && landregion(rterrain(r))) { if(rdemand(r,0) <= 0 && balsambug(r)) { rsetdemand(r,0,(char)(1+rand()%5)); rsetdemand(r,rand()%7,0); fset(r, RF_DH); } } } /* Smoothing */ for(i=0; i<3; i++) { for (r=regions; r; r=r->next) if(fval(r, RF_DH)) { for (dir=0; dir < MAXDIRECTIONS; dir++) { rc = rconnect(r, dir); if(rc && fval(rc, RF_DH) && rand()%100 < 20) { int p1, p2; for (p1 = 0; p1 != MAXLUXURIES; p1++) if (rdemand(r, p1) == 0) break; for (p2 = 0; p2 != MAXLUXURIES; p2++) if (rdemand(rc, p2) == 0) break; if(p1 != p2) { rsetdemand(rc, p2, (char)(1+rand()%5)); rsetdemand(rc, p1, 0); } } } } } } #endif #if 1 static int count_demand(const region *r) { struct demand *dmd; int c = 0; if (r->land) { for (dmd=r->land->demands;dmd;dmd=dmd->next) c++; } return c; } #endif static int recurse_regions(region * r, regionlist **rlist, boolean(*fun)(const region * r)) { if (!fun(r)) return 0; else { int len = 0; direction_t d; regionlist * rl = calloc(sizeof(regionlist), 1); rl->next = *rlist; rl->region = r; (*rlist) = rl; fset(r, FL_MARK); for (d=0;d!=MAXDIRECTIONS;++d) { region * nr = rconnect(r, d); if (nr && !fval(nr, FL_MARK)) len += recurse_regions(nr, rlist, fun); } return len+1; } } #if 1 static int maxluxuries = 0; static boolean f_nolux(const region * r) { if (r->land && count_demand(r) != maxluxuries) return true; return false; } static int fix_demand_region(region *r) { regionlist *rl, *rlist = NULL; static const luxury_type **mlux = 0, ** ltypes; const luxury_type *sale = NULL; int maxlux = 0; recurse_regions(r, &rlist, f_nolux); if (mlux==0) { int i = 0; if (maxluxuries==0) for (sale=luxurytypes;sale;sale=sale->next) { maxluxuries++; } mlux = (const luxury_type **)gc_add(calloc(maxluxuries, sizeof(const luxury_type *))); ltypes = (const luxury_type **)gc_add(calloc(maxluxuries, sizeof(const luxury_type *))); for (sale=luxurytypes;sale;sale=sale->next) { ltypes[i++] = sale; } } else { int i; for (i=0;i!=maxluxuries;++i) mlux[i] = 0; } for (rl=rlist;rl;rl=rl->next) { region * r = rl->region; direction_t d; for (d=0;d!=MAXDIRECTIONS;++d) { region * nr = rconnect(r, d); if (nr && nr->land && nr->land->demands) { struct demand * dmd; for (dmd = nr->land->demands;dmd;dmd=dmd->next) { if (dmd->value == 0) { int i; for (i=0;i!=maxluxuries;++i) { if (mlux[i]==NULL) { maxlux = i; mlux[i] = dmd->type; break; } else if (mlux[i]==dmd->type) { break; } } break; } } } } freset(r, FL_MARK); /* undo recursive marker */ } if (maxlux<2) { int i; for (i=maxlux;i!=2;++i) { int j; do { int k = rand() % maxluxuries; mlux[i] = ltypes[k]; for (j=0;j!=i;++j) { if (mlux[j]==mlux[i]) break; } } while (j!=i); } maxlux=2; } for (rl=rlist;rl;rl=rl->next) { region * r = rl->region; log_warning(("fixing demand in %s\n", regionname(r, NULL))); setluxuries(r, mlux[rand() % maxlux]); } while (rlist) { rl = rlist->next; free(rlist); rlist = rl; } return 0; } #endif static void fix_firewalls(void) { region * r = regions; while (r) { direction_t d; for (d=0;d!=MAXDIRECTIONS;++d) { region * r2 = rconnect(r, d); if (r2) { border * b = get_borders(r, r2); while (b) { if (b->type==&bt_firewall) { attrib * a = a_find(b->attribs, &at_countdown); if (a==NULL || a->data.i <= 0) { erase_border(b); log_warning(("firewall between regions %s and %s was bugged. removed.\n", regionid(r), regionid(r2))); b = get_borders(r, r2); } else { b = b->next; } } else { b = b->next; } } } } r = r->next; } } extern attrib * make_atgmcreate(const struct item_type * itype); extern attrib * make_atpermissions(void); extern struct attrib_type at_permissions; extern struct attrib_type at_gmcreate; static void update_gms(void) { faction * f; for (f=factions;f;f=f->next) { attrib * permissions = a_find(f->attribs, &at_permissions); if (permissions) { const char * keys[] = { "gmgate", "gmmsgr", "gmkill", "gmmsgu", NULL }; int k; item_t i; for (k=0;keys[k];++k) { add_key((attrib**)&permissions->data.v, atoi36(keys[k])); } for (i=I_GREATSWORD;i!=I_KEKS;++i) { attrib * a = a_find(permissions, &at_gmcreate); while (a && a->data.v!=(void*)olditemtype[i]) a=a->nexttype; if (!a) a_add((attrib**)&permissions->data.v, make_atgmcreate(olditemtype[i])); } } } } static int fix_gms(void) { faction * f; for (f=factions;f;f=f->next) { attrib * permissions = a_find(f->attribs, &at_permissions); if (permissions) { const char * keys[] = { "gmgate", "gmmsgr", "gmmsgr", "gmmsgu", NULL }; int k; item_t i; for (k=0;keys[k];++k) { attrib * a = find_key((attrib*)permissions->data.v, atoi36("gmgate")); if (a) { attrib ** ap = &a->nexttype; while (*ap) { attrib * an = *ap; if (a->data.i==an->data.i) a_remove(ap, an); else ap = &an->next; } } } for (i=I_GREATSWORD;i!=I_KEKS;++i) { attrib * a = a_find(permissions, &at_gmcreate); while (a && a->data.v!=(void*)olditemtype[i]) a=a->nexttype; if (a) { attrib ** ap = &a->nexttype; while (*ap) { attrib * an = *ap; if (a->data.v==an->data.v) a_remove(ap, an); else ap = &an->next; } } } } } return 0; } #if 1 static int fix_demand(void) { region *r; const luxury_type *sale = NULL; if (maxluxuries==0) for (sale=luxurytypes;sale;sale=sale->next) ++maxluxuries; for (r=regions; r; r=r->next) { if ((r->land) && count_demand(r) != maxluxuries) { fix_demand_region(r); } } return 0; } #endif #if 0 static void read_laenrepair(boolean active) { FILE * f = fopen("repair.laen", "rt"); FILE * log = fopen("report.laen", "wt"); if (!f || !log) return; while (!feof(f)) { int n, x, y; region * r; fscanf(f, "%d %d %d", &x, &y, &n); r = findregion(x, y); if (!r) fprintf(log, "%d,%d:\tnot found\n", x, y); else if (fval(r, RF_CHAOTIC)) continue; else { int laen = rlaen(r); if (n==-1 && laen>=0) { fprintf(log, "%d,%d:\tillegal laen (%d)\n", x, y, laen); if (active) rsetlaen(r, n); } else if (laen==-1 && n!=-1) { fprintf(log, "%d,%d:\tlaen was lost (%d)\n", x, y, n); if (active) rsetlaen(r, n); } } } fclose(f); } static void write_laenrepair(void) { FILE * f = fopen("repair.laen", "wt"); region * r; for (r=regions;r;r=r->next) if (!fval(r, RF_CHAOTIC)) { int laen = rlaen(r); fprintf(f, "%d %d %d\n", r->x, r->y, laen); } fclose(f); } #endif #include "group.h" static void fix_allies(void) { faction * f; for (f=factions;f;f=f->next) { group * g; for (g=f->groups;g;g=g->next) { ally ** ap=&g->allies; while (*ap) { ally * an, * a = *ap; for (an = a->next;an;an=an->next) { if (a->faction==an->faction) { *ap = a->next; free(a); break; } } if (an==NULL) ap = &(*ap)->next; } } } } #ifdef FUZZY_BASE36 extern boolean enable_fuzzy; #endif static void fix_icastles(void) { region * r; for (r=regions; r; r=r->next) { building * b; for (b=r->buildings; b; b=b->next) { attrib * a; const building_type * btype = &bt_castle; icastle_data * data; a = a_find(b->attribs, &at_icastle); if (b->type!=&bt_illusion && !a) continue; if (!a) { /* attribut hat gefehle */ a = a_add(&b->attribs, a_new(&at_icastle)); } if (b->type!=&bt_illusion) { /* gebäudetyp war falsch */ btype = b->type; b->type = &bt_illusion; } data = (icastle_data*)a->data.v; if (data->time<=0) { /* zeit war kaputt oder abgelaufen */ data->time = 1; } if (!data->type) { /* typ muss gesetzt werden, weil er nicht geladen wurde */ data->type = btype; } if (data->building!=b) { /* rückwärtszeiger auf das gebäude reparieren */ data->building=b; } } } } #if 0 static void fix_ponnukis(void) /* Es kann nur einen geben! */ { unit * ponn = findunit(atoi36("ponn")); if (ponn) { region * mag = ponn->region; unit * u; for (u=mag->units;u;u=u->next) { if (u!=ponn && u->faction==ponn->faction && u->race==ponn->race && !strcmp(ponn->name, u->name)) { set_number(u, 0); } } } } #endif #if 0 static void fix_traveldir(void) { region *r; attrib *a, *a2; traveldir *t; for(r=regions; r; r=r->next) { a = a_find(r->attribs, &at_traveldir); while (a) { a2 = a_add(&r->attribs, a_new(&at_traveldir_new)); t = (traveldir *)(a2->data.v); t->no = a->data.sa[0]; t->dir = a->data.ca[2]; t->age = a->data.ca[3]; a = a->nexttype; } } for(r=regions; r; r=r->next) { a = a_find(r->attribs, &at_traveldir); while(a) { a_remove(&r->attribs, a); a = a->nexttype; } } } #endif static void stats(void) { FILE * F; item * items = NULL; char zText[MAX_PATH]; strcat(strcpy(zText, resourcepath()), "/stats"); F = fopen(zText, "wt"); if (F) { region * r; const item_type * itype; for (r=regions;r;r=r->next) { unit * u; item * itm; for (u=r->units;u;u=u->next) { for (itm=u->items;itm;itm=itm->next) { i_change(&items, itm->type, itm->number); } } } for (itype=itemtypes;itype;itype=itype->next) { item * itm = *i_find(&items, itype); if (itm && itm->number) fprintf(F, "%4d %s\n", itm->number, locale_string(NULL, resourcename(itype->rtype, 0))); else fprintf(F, "%4d %s\n", 0, locale_string(NULL, resourcename(itype->rtype, 0))); } fclose(F); } else { perror(zText); } } #if 0 static void fix_prices(void) { region *r; puts(" - Korrigiere Handelsgüterpreise"); for(r=regions; r; r=r->next) if(r->land) { int sales = 0, buys = 0; const luxury_type *sale = NULL, *ltype; struct demand *dmd; for (dmd=r->land->demands;dmd;dmd=dmd->next) { if(dmd->value == 0) { sales++; sale = dmd->type; } else { buys++; } } if(sales == 0) { int c = 0; for(ltype=luxurytypes; ltype; ltype=ltype->next) c++; c = rand()%c; for(ltype=luxurytypes; c>0; c--) ltype=ltype->next; r_setdemand(r, ltype, 0); sale = ltype; } assert(sale); if(buys == 0) { for(ltype=luxurytypes; ltype; ltype=ltype->next) { if(ltype != sale) r_setdemand(r, ltype, 1 + rand() % 5); } } } } static void fix_options(void) { faction *f; puts(" - Korrigiere Parteioptionen"); for(f=factions;f;f=f->next) { f->options = f->options | Pow(O_REPORT); f->options = f->options | Pow(O_ZUGVORLAGE); } } static void init_region_age(void) { region *r; puts(" - Initialisiere r->age"); /* Initialisieren mit dem Alter der ältesten Partei in 2 Feldern * Umkreis */ for(r=regions; r; r=r->next) { regionlist *rl = all_in_range(r,2); regionlist *rl2; unit *u; int maxage = 0; for(rl2 = rl; rl2; rl2 = rl2->next) { for(u=rl2->region->units; u; u=u->next) { if(u->faction->age > maxage) maxage = u->faction->age; } } r->age = (unsigned short)maxage; } } static void fix_herbtypes(void) { region * r; for (r=regions;r!=NULL;r=r->next) if (r->land) { const herb_type * htype = r->land->herbtype; if (htype==NULL) { if (terrain[r->terrain].herbs!=NULL) { const item_type * itype; int i=0; while (terrain[r->terrain].herbs[i]!=NULL) ++i; itype = finditemtype(terrain[r->terrain].herbs[rand()%i], NULL); r->land->herbtype = resource2herb(itype->rtype); } } else { if (r->terrain==T_PLAIN) { if (r_isforest(r)) { int i = rand()%3+3; const char * name = terrain[T_PLAIN].herbs[i]; const item_type * itype = finditemtype(name, NULL); r->land->herbtype = resource2herb(itype->rtype); } } else { /* Das geht so nicht, wegen der Eisberg-Terrains */ /* assert(htype->terrain==r->terrain); */ } } } } #endif #ifdef SKILLFIX_SAVE typedef struct skillfix_data { unit * u; skill_t skill; int value; int number; int self; int teach; } skillfix_data; static void init_skillfix(attrib * a) { a->data.v = calloc(sizeof(skillfix_data), 1); } static void free_skillfix(attrib * a) { free(a->data.v); } attrib_type at_skillfix = { "skillfix", init_skillfix, free_skillfix }; void skillfix(struct unit * u, skill_t skill, int from, int self, int teach) { attrib * a = a_add(&u->attribs, a_new(&at_skillfix)); skillfix_data * data = (skillfix_data*)a->data.v; data->u = u; data->skill = skill; data->number = u->number; data->value = from; data->self = self; data->teach = teach; } void write_skillfix(void) { FILE * F = fopen("skills.fix", "w+"); region * r; fprintf(F, "S%d\n", turn); for (r=regions;r;r=r->next) { unit * u; for (u=r->units;u;u=u->next) { attrib * a = a_find(u->attribs, &at_skillfix); while (a) { skillfix_data * data = (skillfix_data*)a->data.v; fprintf(F, "%s %d %d %d %d %d\n", itoa36(data->u->no), data->skill, data->number, data->value, data->self, data->teach); a = a->nexttype; } } } fclose(F); } #endif #if 0 static void init_mwarden(void) { unit *u = findunitg(atoi36("mwar"), NULL); attrib *a; if(!u) return; a = a_add(&u->attribs, a_new(&at_warden)); a->data.i = 0; } #endif #ifdef CONVERT_TRIGGER #include "old/relation.h" #include "old/trigger.h" #include "old/trigger_internal.h" #include #include #include #include #include #include #include #include #include typedef struct { void *obj2; typ_t typ2; relation_t id; spread_t spread; } reldata; extern timeout *all_timeouts; static void convert_triggers(void) { region * r=regions; timeout * t; while (r) { unit * u = r->units; while (u) { attrib * a = a_find(u->attribs, &at_relation); while (a) { reldata *rel = (reldata *)a->data.v; unit * u2 = (unit*)rel->obj2; switch (rel->id) { case REL_FAMILIAR: if (u && u2) { if (!playerrace(u->race) || (playerrace(u2->race) && u->race==RC_GOBLIN)) set_familiar(u2, u); else set_familiar(u, u2); } else { if (u2) fprintf(stderr, "WARNING: FAMILIAR info for %s may be broken!\n", unitname(u2)); if (u) fprintf(stderr, "WARNING: FAMILIAR info for %s may be broken!\n", unitname(u)); } break; case REL_CREATOR: break; case REL_TARGET: fprintf(stderr, "WARNING: TARGET relation between %s and 0x%p not converted\n", unitname(u), u2); break; default: fprintf(stderr, "WARNING: unknown relation %d between %s and 0x%p not converted\n", rel->id, unitname(u), u2); break; } a = a->nexttype; } u = u->next; } r=r->next; } for (t=all_timeouts;t;t=t->next) { actionlist * al = t->acts; int time = t->ticks; for (;al;al=al->next) { action * act = al->act; if (act) switch( act->atype ) { case AC_DESTROY: { /* conversion keeper */ unit * u = (unit*)act->obj; trigger * tkill = trigger_killunit(u); add_trigger(&u->attribs, "timer", trigger_timeout(time, tkill)); } case AC_CHANGERACE: { /* conversion for toads */ unit *u = (unit*)act->obj; race_t race = (race_t)act->i[0]; race_t irace = (race_t)act->i[1]; trigger * trestore = trigger_changerace(u, race, irace); if (rand()%10>2) t_add(&trestore, trigger_giveitem(u, olditemtype[I_TOADSLIME], 1)); add_trigger(&u->attribs, "timer", trigger_timeout(time, trestore)); break; } case AC_CHANGEIRACE: { /* conversion for shapeshift */ unit *u = (unit*)act->obj; race_t irace = (race_t)act->i[0]; trigger * trestore = trigger_changerace(u, NORACE, irace); add_trigger(&u->attribs, "timer", trigger_timeout(time, trestore)); break; } case AC_CHANGEFACTION: { /* charmingsong */ faction *f = findfaction_unique_id(act->i[0]); unit *u = (unit*)act->obj; trigger *trestore = trigger_changefaction(u, f); add_trigger(&u->attribs, "timer", trigger_timeout(time, trestore)); add_trigger(&u->faction->attribs, "destroy", trigger_killunit(u)); add_trigger(&f->attribs, "destroy", trigger_killunit(u)); break; } case AC_CREATEUNIT: { /* conversion summon_dragon */ faction *f = findfaction_unique_id(act->i[0]); region *r = (region *)act->obj; int number = act->i[1]; race_t race = (race_t)act->i[2]; trigger *tsummon = trigger_createunit(r, f, race, number); add_trigger(&r->attribs, "timer", trigger_timeout(time, tsummon)); break; } case AC_CREATEMAGICBOOSTCURSE:{ /* delayed magic boost curse */ unit *mage = (unit*)act->obj; trigger *tsummon = trigger_createcurse(mage, mage, C_AURA, 0, act->i[0], 6, 50, 1); add_trigger(&mage->attribs, "timer", trigger_timeout(5, tsummon)); break; } default: fprintf(stderr, "WARNING: timeout not converted\n"); } } } } #endif #if 0 #include static void lms_special(unit * u) { if (u) i_change(&u->items, &it_lmsreward, 1); } #endif #if 0 #define LIFEEXPECTANCY (27*40) static void undo_deadpeasants(void) { region * r = regions; while (r) { int dead = rpeasants(r) / LIFEEXPECTANCY; deathcounts(r, -dead); r = r->next; } } static void fix_undead3percent(void) { region * r = regions; while (r) { int dead = deathcount(r); deathcounts(r, -(dead/2)); r = r->next; } } static void fix_targetregion_resolve(void) { region *r; unit *u; attrib *a; for(r=regions; r; r=r->next) { for(u=r->units; u; u=u->next) { a = a_find(u->attribs, &at_targetregion); if(a) a->data.v = findregion(a->data.sa[0], a->data.sa[1]); } } } static void fix_herbs(void) { const char * plain_herbs[] = {"Flachwurz", "Würziger Wagemut", "Eulenauge", "Grüner Spinnerich", "Blauer Baumringel", "Elfenlieb"}; const herb_type * htypes[6]; int herbs[6]; int hneed[6]; region *r; int i, hsum = 0, left = 0; for (i=0;i!=6;++i) { htypes[i] = resource2herb(finditemtype(plain_herbs[i], NULL)->rtype); herbs[i] = 0; } for (r=regions; r; r=r->next) if (rterrain(r) == T_PLAIN) { const herb_type *htype = rherbtype(r); if (htype==NULL) { htype = htypes[i]; rsetherbtype(r, htype); } for (i=0;i!=6;++i) if (htypes[i]==htype) break; assert(i!=6); herbs[i]++; hsum++; } for (i=0;i!=6;++i) { int hwant = hsum / (6-i); hneed[i] = hwant - herbs[i]; if (hneed[i]>0) left += hneed[i]; hsum -= hwant; } for (r=regions; r; r=r->next) if (rterrain(r) == T_PLAIN) { const herb_type *htype = rherbtype(r); assert(htype); for (i=0;i!=6;++i) if (htypes[i]==htype) break; assert(i!=6); if (hneed[i]<0) { int p; int k = rand() % left; for (p=0;p!=6;++p) if (hneed[p]>0) { k-=hneed[p]; if (k<0) break; } assert(p!=6); hneed[p]--; hneed[i]++; left--; rsetherbtype(r, htypes[p]); } hsum++; } for (i=0;i!=6;++i) herbs[i] = 0; for (r=regions; r; r=r->next) if (rterrain(r) == T_PLAIN) { const herb_type *htype = rherbtype(r); assert(htype); for (i=0;i!=6;++i) if (htypes[i]==htype) break; assert(i!=6); herbs[i]++; } for (i=0;i!=6;++i) { fprintf(stderr, "%s : %d\n", locale_string(NULL, resourcename(htypes[i]->itype->rtype, 0)), herbs[i]); } } #endif #include #include #include #include #include #include #include #include typedef struct handler_info { char * event; trigger * triggers; } handler_info; typedef struct timeout_data { trigger * triggers; int timer; variant trigger_data; } timeout_data; trigger * get_timeout(trigger * td, trigger * tfind) { trigger * t = td; while (t) { if (t->type==&tt_timeout) { timeout_data * tdata = (timeout_data *)t->data.v; trigger * tr = tdata->triggers; while (tr) { if (tr==tfind) break; tr=tr->next; } if (tr==tfind) break; } t=t->next; } return t; } #if 0 static void fix_timeouts(void) { region * r; for (r=regions;r;r=r->next) { unit * u; for (u=r->units;u;u=u->next) { attrib * a = a_find(u->attribs, &at_eventhandler); boolean toad = (u->race==RC_TOAD); boolean keeper = (u->race==RC_IRONKEEPER); while (a!=NULL) { trigger * t; handler_info * td = (handler_info *)a->data.v; for (t=td->triggers;t;t=t->next) { trigger ** tptr=&t->next; while (*tptr) { /* remove duplicates */ if ((*tptr)->type==t->type) { *tptr = (*tptr)->next; } else tptr = &(*tptr)->next; } if (t->type == &tt_changerace || t->type == &tt_changefaction || t->type == &tt_createcurse || t->type == &tt_createunit) { trigger * timer = get_timeout(td->triggers, t); if (toad && t->type == &tt_changerace) { toad = false; } if (timer==NULL) { add_trigger(&u->attribs, "timer", trigger_timeout(1+(rand()%2), t)); } } else if (t->type == &tt_killunit) { if (u->race==RC_IRONKEEPER) { trigger * timer = get_timeout(td->triggers, t); keeper = false; if (timer==NULL) { add_trigger(&u->attribs, "timer", trigger_timeout(1+(rand()%2), t)); } } } } a = a->nexttype; } if (keeper) { int duration = 1+ (rand() % 2); trigger * tkill = trigger_killunit(u); add_trigger(&u->attribs, "timer", trigger_timeout(duration, tkill)); } if (toad) { /* repair toad-only mage */ int duration = 1+ (rand() % 2); trigger * trestore = trigger_changerace(u, u->faction->race, u->faction->race); if (rand()%10>2) t_add(&trestore, trigger_giveitem(u, olditemtype[I_TOADSLIME], 1)); add_trigger(&u->attribs, "timer", trigger_timeout(duration, trestore)); } } } } #endif #include static int regatta_quest(void) { plane * p = gm_addplane(20, PFL_NORECRUITS, "Regatta"); region * center = findregion(p->minx+(p->maxx-p->minx)/2, p->miny+(p->maxy-p->miny)/2); gm_addfaction("gregorjochmann@gmx.de", p, center); return 0; } static int secondfaction(faction * pf) { unit * u = findunit(atoi36("5q9w")); if (u!=NULL) { plane * p = rplane(u->region); if (p!=NULL) { region * center = findregion((p->maxx-p->minx)/2, (p->maxy-p->miny)/2); if (center!=NULL) { gm_addfaction(pf->email, p, center); return 0; } } } return -1; } static void update_gmquests(void) { /* gm04 will keine Orks */ faction * f = findfaction(atoi36("gm04")); if (f) { unit * u = f->units; potion_t p; attrib * permissions = a_find(f->attribs, &at_permissions); do_once("et02", secondfaction(f)); if (u!=NULL) { plane * p = rplane(u->region); if (p!=NULL) p->flags |= PFL_NOORCGROWTH; } for (p=0;p!=MAX_POTIONS;++p) { attrib * a = a_find(permissions, &at_gmcreate); while (a && a->data.v!=(void*)oldpotiontype[p]->itype) a=a->nexttype; if (!a) a_add((attrib**)&permissions->data.v, make_atgmcreate(oldpotiontype[p]->itype)); } } do_once("rq01", regatta_quest()); } #if 0 static void test_gmquest(void) { const struct faction * f; /* enno's world */ f = gm_addquest("enno@eressea.upb.de", "GM Zone", 1, PFL_NOATTACK|PFL_NOALLIANCES|PFL_NOFEED|PFL_FRIENDLY); log_printf("Neue Questenpartei %s\n", factionname(f)); f = gm_addquest("xandril@att.net", "Mardallas Welt", 40, 0); log_printf("Neue Questenpartei %s\n", factionname(f)); f = gm_addquest("moritzsalinger@web.de", "Laen-Kaiser", 7, /*PFL_NORECRUITS |*/ PFL_NOMAGIC /*| PFL_NOBUILD*/); log_printf("Neue Questenpartei %s\n", factionname(f)); f = gm_addquest("Denise.Muenstermann@home.gelsen-net.de", "Mochikas Queste", 7, PFL_NOMAGIC); log_printf("Neue Questenpartei %s\n", factionname(f)); f = gm_addquest("feeron@aol.com", "Eternath", 11, 0); log_printf("Neue Questenpartei %s\n", factionname(f)); f = gm_addquest("BigBear@nord-com.net", "Leonidas Vermächtnis", 15, PFL_NOMAGIC|PFL_NOSTEALTH); log_printf("Neue Questenpartei %s\n", factionname(f)); } #endif #define TEST_LOCALES 0 #if TEST_LOCALES static void setup_locales(void) { locale * lang = find_locale("en"); faction * f = factions; while (f) { f->locale = lang; f = f->next; } } #endif #include #include #if 0 #error "this is broken, it duplicates triggers" static void fix_unitrefs(void) { region * r=regions; while (r) { unit * u = r->units; while (u) { attrib * a; a = a_find(u->attribs, &at_familiar); if (a) { /* magier, hat einen familiar */ unit * ufamiliar = get_familiar(u); if (ufamiliar) { attrib * ae; /* killunit attribut am magier */ ae = a_find(u->attribs, &at_eventhandler); if (ae) { trigger * tkillunit = NULL; trigger ** tlist = get_triggers(u->attribs, "destroy"); if (tlist!=NULL) { tkillunit = *tlist; while (tkillunit) { if (strcmp(tkillunit->type->name, "killunit")==0) break; tkillunit = tkillunit->next; } if (tkillunit && !tkillunit->data.v) { log_warning(("killunit-trigger für Magier %s und Vertrauten %s restauriert.\n", itoa36(u->no), itoa36(ufamiliar->no))); tkillunit->data.v = ufamiliar; } else ae = NULL; } } if (ae==NULL) { /* Wenn der Magier stirbt, dann auch der Vertraute */ add_trigger(&u->attribs, "destroy", trigger_killunit(ufamiliar)); } /* killunit attribut am magier */ ae = a_find(ufamiliar->attribs, &at_eventhandler); if (ae) { trigger * tshockunit = NULL; trigger ** tlist = get_triggers(ufamiliar->attribs, "destroy"); if (tlist!=NULL) { tshockunit = *tlist; while (tshockunit) { if (strcmp(tshockunit->type->name, "shock")==0) break; tshockunit = tshockunit->next; } if (tshockunit && !tshockunit->data.v) { log_warning(("shockunit-trigger für Magier %s und Vertrauten %s restauriert.\n", itoa36(u->no), itoa36(ufamiliar->no))); tshockunit->data.v = u; } else ae = NULL; } } if (ae==NULL) { /* Wenn der Vertraute stirbt, schockt er den Magier */ add_trigger(&ufamiliar->attribs, "destroy", trigger_shock(u)); } } else { log_error(("Magier %s hat ein at_familiar, aber keinen Vertrauten.\n", itoa36(u->no))); } } u = u->next; } r=r->next; } } #endif static void update_igjarjuk_quest(void) { unit * u; faction *f = findfaction(atoi36("rr")); if (!f) return; for (u=f->units;u;u=u->nextF) { u->race = new_race[RC_TEMPLATE]; } } #if RESOURCE_CONVERSION extern struct attrib_type at_resources; void init_resourcefix(void) { at_register(&at_resources); } static int read_resfix(void) { #if 0 FILE * F = fopen("resource.fix", "r"); if (F==NULL) return; while (!feof(F)) { int x, y, stone, iron, laen, age; int lstone, liron, llaen; /* level */ region * r; fscanf(F, "%d %d %d %d %d %d %d %d %d\n", &x, &y, &age, &stone, &iron, &laen, &lstone, &liron, &llaen); r = findregion(x, y); if (r) { rawmaterial * rm = r->resources; while (rm) { if (rm->type==&rm_iron && liron>0) { rm->amount = iron; rm->level = liron; } else if (rm->type==&rm_laen && llaen>0) { rm->amount = laen; rm->level = llaen; } else if (rm->type==&rm_stones && lstone>0) { rm->amount = stone; rm->level = lstone; } rm = rm->next; } r->age = (unsigned short)age; } } fclose(F); #else return -1; #endif } static int convert_resources(void) { #if 0 region *r; for(r=regions;r;r=r->next) { attrib *a = a_find(r->attribs, &at_resources); r->resources = 0; terraform_resources(r); if (a==NULL) continue; else { int INIT_STONE = 20; /* skip this many weeks */ double ironmulti = 0.40; double laenmulti = 0.50; double stonemulti = 0.30; /* half the stones used */ rawmaterial * rmiron = rm_get(r, rm_iron.rtype); rawmaterial * rmlaen = rm_get(r, rm_laen.rtype); rawmaterial * rmstone = rm_get(r, rm_stones.rtype); int oldiron; int oldlaen = MAXLAENPERTURN * min(r->age, 100) / 2; int oldstone = terrain[rterrain(r)].quarries * max(0, r->age - INIT_STONE); int iron = a->data.sa[0]; int laen = a->data.sa[1]; int stone, level; int i, base; /** STONE **/ for (i=0;terrain[r->terrain].rawmaterials[i].type;++i) { if (terrain[r->terrain].rawmaterials[i].type == &rm_stones) break; } if (terrain[r->terrain].rawmaterials[i].type) { base = terrain[r->terrain].rawmaterials[i].base; stone = max (0, (int)(oldstone * stonemulti)); level = 1; base = (int)(terrain[r->terrain].rawmaterials[i].base*(1+level*terrain[r->terrain].rawmaterials[i].divisor)); while (stone >= base) { stone-=base; ++level; base = (int)(terrain[r->terrain].rawmaterials[i].base*(1+level*terrain[r->terrain].rawmaterials[i].divisor)); } rmstone->level = level; rmstone->amount = base - stone; assert (rmstone->amount > 0); log_printf("CONVERSION: %d stones @ level %d in %s\n", rmstone->amount, rmstone->level, regionname(r, NULL)); } else { log_error(("found stones in %s of %s\n", terrain[r->terrain].name, regionname(r, NULL))); } /** IRON **/ if (r_isglacier(r) || r->terrain==T_ICEBERG) { oldiron = GLIRONPERTURN * min(r->age, 100) / 2; } else { oldiron = IRONPERTURN * r->age; } for (i=0;terrain[r->terrain].rawmaterials[i].type;++i) { if (terrain[r->terrain].rawmaterials[i].type == &rm_iron) break; } if (terrain[r->terrain].rawmaterials[i].type) { base = terrain[r->terrain].rawmaterials[i].base; iron = max(0, (int)(oldiron * ironmulti - iron )); level = 1; base = (int)(terrain[r->terrain].rawmaterials[i].base*(1+level*terrain[r->terrain].rawmaterials[i].divisor)); while (iron >= base) { iron-=base; ++level; base = (int)(terrain[r->terrain].rawmaterials[i].base*(1+level*terrain[r->terrain].rawmaterials[i].divisor)); } rmiron->level = level; rmiron->amount = base - iron; assert (rmiron->amount > 0); log_printf("CONVERSION: %d iron @ level %d in %s\n", rmiron->amount, rmiron->level, regionname(r, NULL)); } else { log_error(("found iron in %s of %s\n", terrain[r->terrain].name, regionname(r, NULL))); } /** LAEN **/ if (laen>=0) { if (rmlaen==NULL) { rmlaen = calloc(sizeof(rawmaterial), 1); rmlaen->next = r->resources; r->resources = rmlaen; } for (i=0;terrain[r->terrain].rawmaterials[i].type;++i) { if (terrain[r->terrain].rawmaterials[i].type == &rm_laen) break; } if (terrain[r->terrain].rawmaterials[i].type) { laen = max(0, (int)(oldlaen * laenmulti - laen)); level = 1; base = (int)(terrain[r->terrain].rawmaterials[i].base*(1+level*terrain[r->terrain].rawmaterials[i].divisor)); while (laen >= base) { laen-=base; ++level; base = (int)(terrain[r->terrain].rawmaterials[i].base*(1+level*terrain[r->terrain].rawmaterials[i].divisor)); } rmlaen->level = level; rmlaen->amount = base - laen; assert(rmlaen->amount>0); log_printf("CONVERSION: %d laen @ level %d in %s\n", rmlaen->amount, rmlaen->level, regionname(r, NULL)); rmlaen = NULL; } } if (rmlaen) { struct rawmaterial *res; struct rawmaterial ** pres = &r->resources; if (laen!=-1) log_error(("found laen in %s of %s\n", terrain[r->terrain].name, regionname(r, NULL))); while (*pres!=rmlaen) pres = &(*pres)->next; res = *pres; *pres = (*pres)->next; free(res); } #ifndef NDEBUG { rawmaterial * res = r->resources; while (res) { assert(res->amount>0); assert(res->level>0); res = res->next; } } #endif } } return 0; #else return -1; #endif } #endif #if 0 static int convert_resources(void) { region *r; attrib *a; for(r=regions;r;r=r->next) { /* Iron */ if(rterrain(r) == T_MOUNTAIN) { a_add(&r->attribs, a_new(&at_iron))->data.i = 25; } else if(rterrain(r) == T_GLACIER || rterrain(r) == T_ICEBERG_SLEEP) { a_add(&r->attribs, a_new(&at_iron))->data.i = 2; } /* Laen */ if(rterrain(r) == T_MOUNTAIN) { a = a_find(r->attribs, &at_laen); if(a) a->data.i = 6; } /* Stone */ if(terrain[rterrain(r)].quarries > 0) { a_add(&r->attribs, a_new(&at_stone))->data.i = terrain[rterrain(r)].quarries; } } return 0; } static void fix_negpotion(void) { region *r; unit *u; int i; for(r=regions; r; r=r->next) { for(u=r->units; u; u=u->next) { i = get_effect(u, oldpotiontype[P_FAST]); if (i < 0){ change_effect(u, oldpotiontype[P_FAST], -i); } } } } #endif #if GROWING_TREES int growing_trees(void) { region *r; for(r=regions; r; r=r->next) { if(rtrees(r, 2)) { rsettrees(r, 1, rtrees(r, 2)/4); rsettrees(r, 0, rtrees(r, 2)/2); } } return 0; } #endif #include #include typedef struct gate_data { struct building * gate; struct region * target; } gate_data; static void fix_gates(void) { region * r; for (r=regions;r;r=r->next) { unit * u; building * b; for (u=r->units;u;u=u->next) { trigger ** triggers = get_triggers(u->attribs, "timer"); if (triggers) { trigger * t = *triggers; while (t && t->type!= &tt_gate) t=t->next; if (t!=NULL) { gate_data * gd = (gate_data*)t->data.v; struct building * b = gd->gate; struct region * rtarget = gd->target; if (r!=b->region) { add_trigger(&b->attribs, "timer", trigger_gate(b, rtarget)); add_trigger(&b->attribs, "create", trigger_unguard(b)); fset(b, BLD_UNGUARDED); } } remove_triggers(&u->attribs, "timer", &tt_gate); remove_triggers(&u->attribs, "create", &tt_unguard); } } for (b=r->buildings;b;b=b->next) { trigger ** triggers = get_triggers(b->attribs, "timer"); if (triggers) { trigger * t = *triggers; while (t && t->type!= &tt_gate) t=t->next; if (t!=NULL) { gate_data * gd = (gate_data*)t->data.v; struct building * b = gd->gate; struct region * rtarget = gd->target; remove_triggers(&b->attribs, "timer", &tt_gate); remove_triggers(&b->attribs, "create", &tt_unguard); if (r!=b->region) { add_trigger(&b->attribs, "timer", trigger_gate(b, rtarget)); add_trigger(&b->attribs, "create", trigger_unguard(b)); fset(b, BLD_UNGUARDED); } } } } } } static int dump_sql(void) { faction * f; for (f=factions;f;f=f->next) { if (f->unique_id==0) { f->unique_id = ++max_unique_id; } if (f->age!=1 && f->no!=MONSTER_FACTION) { fprintf(sqlstream, "INSERT INTO users (id, email) VALUES (%d, '%s');\n", f->unique_id, f->email); fprintf(sqlstream, "INSERT INTO factions (id, user, name, password, race, locale, lastorders, banner, email) " "VALUES ('%s', %d, '%s', '%s', '%s', '%s', %u, '%s', '%s');\n", itoa36(f->no), f->unique_id, sqlquote(f->name), sqlquote(f->passw), LOC(default_locale, rc_name(f->race, 1)), locale_name(f->locale), f->lastorders, sqlquote(f->banner), f->email); } } return 0; } #if NEW_RESOURCEGROWTH static int randomized_resources(void) { region *r; for(r = regions; r; r=r->next) if(r->land) { terrain_t ter = rterrain(r); /* Dieses if verhindert, das Laen nocheinmal verteilt wird. */ if(ter == T_MOUNTAIN || ter == T_GLACIER || ter == T_ICEBERG || ter == T_ICEBERG_SLEEP) continue; terraform_resources(r); } return 0; } #endif static int fix_idleout(void) { faction *f; f = findfaction(0); if(f){ fset(f, FL_NOIDLEOUT); } f = findfaction(atoi36("muse")); if(f){ fset(f, FL_NOIDLEOUT); } return 0; } static int set_zip(void) { faction *f; for(f=factions;f;f=f->next) { if(!(f->options & (1 << O_BZIP2)) && !(f->options & (1 << O_COMPRESS))) { f->options = f->options | (1 << O_COMPRESS); } } f = findfaction(0); f->options = f->options & ~(1 << O_COMPRESS); f->options = f->options | (1 << O_BZIP2); return 0; } static int heal_all(void) { region *r; unit *u; faction *f; message *msg = msg_message("healall",""); for(f=factions; f; f=f->next) { freset(f, FL_DH); } for(r=regions; r; r=r->next) { for(u=r->units;u;u=u->next) { int max_hp = unit_max_hp(u) * u->number; if(u->hp < max_hp) { u->hp = max_hp; fset(u->faction, FL_DH); } } } for (f=factions; f; f=f->next) { if(fval(f,FL_DH)) { add_message(&f->msgs, msg); freset(f, FL_DH); } } msg_release(msg); return 0; } #if PEASANT_ADJUSTMENT == 1 #define WEIGHT ((double)0.5) #define PLWEIGHT ((double)0.80) static int peasant_adjustment(void) { terrain_t ter; int sum, avg, c; double freeall, pool; /* long long is illegal */ double s; region *r; s = 0; for(r=regions; r; r=r->next) { s += rpeasants(r); } log_printf("BAUERN vorher: %lld\n",s); for(ter = 0; ter < MAXTERRAINS; ter++) { if(terrain[ter].production_max <= 0) continue; c = 0; sum = 0; pool = 0; freeall = 0; for(r=regions; r; r=r->next) if(rterrain(r) == ter) { unit *u; c++; sum += rpeasants(r); for(u = r->units; u; u=u->next) { if(lifestyle(u) > 0) sum += u->number; /* Sonderregel Bauernmob */ if (u->race == new_race[RC_PEASANT]) sum += u->number; } } if (c==0) continue; avg = sum/c; for(r=regions; r; r=r->next) if(rterrain(r) == ter) { unit *u; int playerp = 0; int p_weg; int soll; for(u = r->units; u; u=u->next) { if(lifestyle(u) > 0) playerp += u->number; /* Sonderregel Bauernmob */ if (u->race == new_race[RC_PEASANT]) playerp += u->number; } soll = (int)((avg + playerp + rpeasants(r)) * WEIGHT); if(playerp * PLWEIGHT + rpeasants(r) > soll) { p_weg = (int)(min(((playerp * PLWEIGHT) + rpeasants(r)) - soll, rpeasants(r))); assert(p_weg >= 0); if (p_weg > 0){ log_printf("BAUERN %s: war %d, minus %d, playerp %d\n", regionname(r, NULL), rpeasants(r), p_weg, playerp); } pool += p_weg; rsetpeasants(r, rpeasants(r) - p_weg); assert(rpeasants(r) >= 0); } freeall += max(0,production(r) * MAXPEASANTS_PER_AREA - ((rtrees(r,2)+rtrees(r,1)/2) * TREESIZE) - playerp); } for(r=regions; r; r=r->next) if(rterrain(r) == ter) { unit *u; double free; int newp; int playerp = 0; for(u = r->units; u; u=u->next) { if(lifestyle(u) > 0) playerp += u->number; /* Sonderregel Bauernmob */ if (u->race == new_race[RC_PEASANT]) playerp += u->number; } free = max(0,production(r) * MAXPEASANTS_PER_AREA - ((rtrees(r,2)+rtrees(r,1)/2) * TREESIZE) - playerp); newp = (int)((pool * free)/freeall); rsetpeasants(r, rpeasants(r)+newp); assert(rpeasants(r) >= 0); } } s = 0; for(r=regions; r; r=r->next) { s += rpeasants(r); } log_printf("BAUERN nachher: %lld\n",s); return 0; } static int orc_conversion2(void) { faction *f; unit *u; region *r; for(f=factions; f; f=f->next) { if(f->race == new_race[RC_ORC]) { f->race = new_race[RC_URUK]; } } for(r=regions; r; r=r->next) { for(u=r->units; u; u=u->next) { if (u->race==new_race[RC_ORC] || u->race==new_race[RC_SNOTLING]) { /* convert to either uruk or snotling */ if (has_skill(u, SK_MAGIC) || has_skill(u, SK_ALCHEMY)) { u->race = new_race[RC_URUK]; u->irace = new_race[RC_URUK]; } } } } return 0; } static int orc_conversion(void) { faction *f; unit *u; region *r; for(f=factions; f; f=f->next) { if(f->race == new_race[RC_ORC]) { f->race = new_race[RC_URUK]; } } for(r=regions; r; r=r->next) { for(u=r->units; u; u=u->next) { if(u->race == new_race[RC_ORC]) { /* convert to either uruk or snotling */ if(effskill(u, SK_MAGIC) >= 1 || effskill(u, SK_ALCHEMY) >= 1 || get_item(u, I_CHASTITY_BELT) >= u->number) { u->race = new_race[RC_URUK]; u->irace = new_race[RC_URUK]; } else { u->race = new_race[RC_SNOTLING]; u->irace = new_race[RC_SNOTLING]; } } } } return 0; } #endif static int fix_astralplane(void) { plane * astralplane = getplanebyname("Astralraum"); if (astralplane) { freset(astralplane, PFL_NOCOORDS); set_ursprung(findfaction(MONSTER_FACTION), astralplane->id, 0, 0); } return 0; } static int fix_watchers(void) { plane * p = getplanebyid (59034966); if (p) { faction * f = findfaction(atoi36("gm04")); watcher * w = calloc(sizeof(watcher), 1); w->faction = f; w->mode = see_unit; w->next = p->watchers; p->watchers = w; } p = getplanebyid(1137); if (p) { faction * f = findfaction(atoi36("rr")); watcher * w = calloc(sizeof(watcher), 1); w->faction = f; w->mode = see_unit; w->next = p->watchers; p->watchers = w; } return 0; } static int fix_questcoors(void) { plane * p = getplanebyid (59034966); if (p) { faction * f; region * eternath = findregion(-8750, 3631); if (eternath) for (f=factions;f;f=f->next) { ursprung * u = f->ursprung; while (u) { if (u->id == p->id) { u->x = 0; u->y = 0; break; } u=u->next; } } } return 0; } static int warn_password(void) { faction * f = factions; while (f) { boolean pwok = true; const char * c = f->passw; while (*c) { if (!isalnum(*c)) pwok = false; c++; } if (pwok == false) { ADDMSG(&f->msgs, msg_message("msg_errors", "string", "Dein Passwort enthält Zeichen, die bei der Nachsendung " "von Reports Probleme bereiten können. Bitte wähle ein neues " "Passwort, bevorzugt nur aus Buchstaben und Zahlen bestehend.")); } f = f->next; } return 0; } static int fix_seeds(void) { region *r; for(r=regions; r; r=r->next) { if(rtrees(r,0) > 25 && rtrees(r,0) > rtrees(r,2)/2) { rsettrees(r,0,rtrees(r,2)/2); } } return 0; } void korrektur(void) { #if TEST_LOCALES setup_locales(); #endif fix_astralplane(); fix_firewalls(); fix_gates(); #ifdef TEST_GM_COMMANDS setup_gm_faction(); #endif update_gms(); verify_owners(false); /* fix_herbtypes(); */ #ifdef CONVERT_TRIGGER convert_triggers(); #endif fix_migrants(); no_teurefremde(1); update_igjarjuk_quest(); fix_allies(); update_gmquests(); /* test gm quests */ /* fix_unitrefs(); */ stats(); do_once("sql2", dump_sql()); do_once("fw01", fix_watchers()); #if NEW_RESOURCEGROWTH /* do not remove do_once calls - old datafiles need them! */ do_once("rgrw", convert_resources()); do_once("rsfx", read_resfix()); #endif /* do_once("xepl", create_xe()); */ #if GROWING_TREES do_once("grtr", growing_trees()); #endif do_once("fgms", fix_gms()); #if NEW_RESOURCEGROWTH do_once("rndr", randomized_resources()); #endif do_once("idlo", fix_idleout()); do_once("szip", set_zip()); do_once("heal", heal_all()); do_once("fquc", fix_questcoors()); do_once("fsee", fix_seeds()); do_once("orc2", orc_conversion2()); do_once("witm", warn_items()); warn_password(); /* seems something fishy is going on, do this just * to be on the safe side: */ fix_demand(); /* trade_orders(); */ if (global.data_version < NEWROAD_VERSION) { newroads(); } /* immer ausführen, wenn neue Sprüche dazugekommen sind, oder sich * Beschreibungen geändert haben */ show_newspells(); fix_age(); /* Immer ausführen! Erschafft neue Teleport-Regionen, wenn nötig */ create_teleport_plane(); if (global.data_version