/* 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. */ #define INDENT 0 #define ECHECK_VERSION "4.01" #include #include /* modules includes */ #include /* attributes includes */ #include #include #include #include #ifdef AT_OPTION # include #endif /* gamecode includes */ #include "creport.h" #include "economy.h" #include "monster.h" #include "laws.h" /* 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 #include #include #include #include #include /* util includes */ #include #include #include #include #include #include #include #include #include #include /* libc includes */ #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_STAT #include #include #endif extern int quiet; extern int *storms; extern int weeks_per_month; extern int months_per_year; static size_t strxcpy(char * dst, const char * src) { size_t s = 0; while ((*dst++ = *src++)!=0) ++s; return s; } static char * gamedate_season(const struct locale * lang) { static char buf[256]; gamedate gd; get_gamedate(turn, &gd); sprintf(buf, (const char *)LOC(lang, "nr_calendar_season"), LOC(lang, weeknames[gd.week]), LOC(lang, monthnames[gd.month]), gd.year, LOC(lang, agename), LOC(lang, seasonnames[gd.season])); return buf; } void rpc(FILE * F, char c, size_t num) { while(num > 0) { putc(c, F); num--; } } void rnl(FILE * F) { fputc('\n', F); } static void centre(FILE * F, const char *s, boolean breaking) { /* Bei Namen die genau 80 Zeichen lang sind, kann es hier Probleme * geben. Seltsamerweise wird i dann auf MAXINT oder aehnlich * initialisiert. Deswegen keine Strings die laenger als REPORTWIDTH * sind! */ if (breaking && REPORTWIDTH < strlen(s)) { strlist *T, *SP = 0; sparagraph(&SP, s, 0, 0); T = SP; while (SP) { centre(F, SP->s, false); SP = SP->next; } freestrlist(T); } else { rpc(F, ' ', (REPORTWIDTH - strlen(s)+1) / 2); fputs(s, F); putc('\n', F); } } static void rparagraph(FILE *F, const char *str, ptrdiff_t indent, int hanging_indent, char mark) { static const char * spaces = " "; size_t length = REPORTWIDTH; const char * end, * begin; /* find out if there's a mark + indent already encoded in the string. */ if (!mark) { const char * x = str; while (*x == ' ') ++x; indent += x - str; if (x[0] && indent && x[1]==' ') { indent += 2; mark = x[0]; str = x + 2; hanging_indent -= 2; } } begin = end = str; while (*begin) { const char * last_space = begin; if (mark && indent>=2) { fwrite(spaces, sizeof(char), indent-2, F); fputc(mark, F); fputc(' ', F); mark = 0; } else if (begin==str) { fwrite(spaces, sizeof(char), indent, F); } else { fwrite(spaces, sizeof(char), indent+ hanging_indent, F); } while (*end && end<=begin+length-indent) { if (*end==' ') { last_space = end; } ++end; } if (*end==0) last_space = end; if (last_space==begin) { /* there was no space in this line. clip it */ last_space = end; } fwrite(begin, sizeof(char), last_space-begin, F); begin = last_space; while (*begin==' ') { ++begin; } if (begin>end) begin = end; fputc('\n', F); } } static void report_spell(FILE * F, spell *sp, const struct locale * lang) { int k, itemanz, costtyp; int dh = 0; char buf[4096]; char * bufp; rnl(F); centre(F, spell_name(sp, lang), true); rnl(F); rparagraph(F, LOC(lang, "nr_spell_description"), 0, 0, 0); rparagraph(F, spell_info(sp, lang), 2, 0, 0); bufp = buf; bufp += strlcpy(bufp, LOC(lang, "nr_spell_type"), sizeof(buf)-(bufp-buf)); *bufp++ = ' '; if (sp->sptyp & PRECOMBATSPELL) { bufp += strlcpy(bufp, LOC(lang, "sptype_precombat"), sizeof(buf)-(bufp-buf)); } else if (sp->sptyp & COMBATSPELL) { bufp += strlcpy(bufp, LOC(lang, "sptype_combat"), sizeof(buf)-(bufp-buf)); } else if (sp->sptyp & POSTCOMBATSPELL) { bufp += strlcpy(bufp, LOC(lang, "sptype_postcombat"), sizeof(buf)-(bufp-buf)); } else { bufp += strlcpy(bufp, LOC(lang, "sptype_normal"), sizeof(buf)-(bufp-buf)); } rparagraph(F, buf, 0, 0, 0); sprintf(buf, "%s %d", LOC(lang, "nr_spell_level"), sp->level); rparagraph(F, buf, 0, 0, 0); sprintf(buf, "%s %d", LOC(lang, "nr_spell_rank"), sp->rank); rparagraph(F, buf, 0, 0, 0); rparagraph(F, LOC(lang, "nr_spell_components"), 0, 0, 0); for (k = 0; sp->components[k].type; ++k) { const resource_type * rtype = sp->components[k].type; itemanz = sp->components[k].amount; costtyp = sp->components[k].cost; if (itemanz > 0){ if (sp->sptyp & SPELLLEVEL) { bufp = buf + sprintf(buf, " %d %s", itemanz, LOC(lang, resourcename(rtype, itemanz!=1))); if (costtyp == SPC_LEVEL || costtyp == SPC_LINEAR ) { bufp += sprintf(bufp, " * %s", LOC(lang, "nr_level")); } } else { if (costtyp == SPC_LEVEL || costtyp == SPC_LINEAR ) { itemanz *= sp->level; } sprintf(buf, "%d %s", itemanz, LOC(lang, resourcename(rtype, itemanz!=1))); } rparagraph(F, buf, 2, 2, '-'); } } bufp = buf + strlcpy(buf, LOC(lang, "nr_spell_modifiers"), sizeof(buf)-(bufp-buf)); if (sp->sptyp & FARCASTING) { bufp += strlcpy(bufp, " Fernzauber", sizeof(buf)-(bufp-buf)); dh = 1; } if (sp->sptyp & OCEANCASTABLE) { if (dh == 1) { bufp += strlcpy(bufp, ",", sizeof(buf)-(bufp-buf)); } bufp += strlcpy(bufp, " Seezauber", sizeof(buf)-(bufp-buf)); dh = 1; } if (sp->sptyp & ONSHIPCAST) { if (dh == 1){ bufp += strlcpy(bufp, ",", sizeof(buf)-(bufp-buf)); } bufp += strlcpy(bufp, " Schiffszauber", sizeof(buf)-(bufp-buf)); dh = 1; } if (sp->sptyp & NOTFAMILIARCAST) { if (dh == 1){ bufp += strlcpy(bufp, ", k", sizeof(buf)-(bufp-buf)); } else { bufp += strlcpy(bufp, " K", sizeof(buf)-(bufp-buf)); } bufp += strlcpy(bufp, "ann nicht vom Vertrauten gezaubert werden", sizeof(buf)-(bufp-buf)); dh = 1; } if (dh == 0) bufp += strlcpy(bufp, " Keine", sizeof(buf)-(bufp-buf)); rparagraph(F, buf, 0, 0, 0); rparagraph(F, LOC(lang, "nr_spell_syntax"), 0, 0, 0); if (!sp->syntax) { if (sp->sptyp & ISCOMBATSPELL) { bufp = buf + strxcpy(buf, LOC(lang, keywords[K_COMBAT])); } else { bufp = buf + strxcpy(buf, LOC(lang, keywords[K_CAST])); } /* Reihenfolge beachten: Erst REGION, dann STUFE! */ if (sp->sptyp & FARCASTING) { bufp += snprintf(bufp, sizeof(buf)-(bufp-buf), " [%s x y]", LOC(lang, parameters[P_REGION])); } if (sp->sptyp & SPELLLEVEL) { bufp += snprintf(bufp, sizeof(buf)-(bufp-buf), " [%s n]", LOC(lang, parameters[P_LEVEL])); } bufp += strxcpy(bufp, " \""); bufp += strxcpy(bufp, spell_name(sp, lang)); bufp += strxcpy(bufp, "\" "); if (sp->sptyp & ONETARGET){ if (sp->sptyp & UNITSPELL) { bufp += strxcpy(bufp, ""); } else if (sp->sptyp & SHIPSPELL) { bufp += strxcpy(bufp, ""); } else if (sp->sptyp & BUILDINGSPELL) { bufp += strxcpy(bufp, ""); } } else { if (sp->sptyp & UNITSPELL) { bufp += strxcpy(bufp, " [ ...]"); } else if (sp->sptyp & SHIPSPELL) { bufp += strxcpy(bufp, " [ ...]"); } else if (sp->sptyp & BUILDINGSPELL) { bufp += strxcpy(bufp, " [ ...]"); } } rparagraph(F, buf, 2, 0, 0); } else { rparagraph(F, sp->syntax, 2, 0, 0); } rnl(F); } void sparagraph(strlist ** SP, const char *s, int indent, char mark) { /* Die Liste SP wird mit dem String s aufgefuellt, mit indent und einer * mark, falls angegeben. SP wurde also auf 0 gesetzt vor dem Aufruf. * Vgl. spunit (). */ int i, j, width; int firstline; static char buf[REPORTWIDTH + 1]; width = REPORTWIDTH - indent; firstline = 1; for (;;) { i = 0; do { j = i; while (s[j] && s[j] != ' ') j++; if (j > width) { /* j zeigt auf das ende der aktuellen zeile, i zeigt auf den anfang der * nächsten zeile. existiert ein wort am anfang der zeile, welches * länger als eine zeile ist, muss dieses hier abgetrennt werden. */ if (i == 0) i = width - 1; break; } i = j + 1; } while (s[j]); for (j = 0; j != indent; j++) buf[j] = ' '; if (firstline && mark) buf[indent - 2] = mark; for (j = 0; j != i - 1; j++) buf[indent + j] = s[j]; buf[indent + j] = 0; addstrlist(SP, buf); if (s[i - 1] == 0) break; s += i; firstline = 0; } } int hat_in_region(item_t it, region * r, faction * f) { unit *u; for (u = r->units; u; u = u->next) { if (u->faction == f && get_item(u, it) > 0) { return 1; } } return 0; } static void print_curses(FILE *F, const faction *viewer, const void * obj, typ_t typ, int indent) { attrib *a = NULL; int self = 0; region *r; /* Die Sichtbarkeit eines Zaubers und die Zaubermeldung sind bei * Gebäuden und Schiffen je nach, ob man Besitzer ist, verschieden. * Bei Einheiten sieht man Wirkungen auf eigene Einheiten immer. * Spezialfälle (besonderes Talent, verursachender Magier usw. werde * bei jedem curse gesondert behandelt. */ if (typ == TYP_SHIP){ ship * sh = (ship*)obj; unit * owner = shipowner(sh); a = sh->attribs; r = sh->region; if (owner) { if (owner->faction == viewer){ self = 2; } else { /* steht eine person der Partei auf dem Schiff? */ unit *u = NULL; for (u = r->units; u; u = u->next) { if (u->ship == sh) { self = 1; break; } } } } } else if (typ == TYP_BUILDING) { building * b = (building*)obj; unit * owner; a = b->attribs; r = b->region; if ((owner = buildingowner(r,b)) != NULL){ if (owner->faction == viewer){ self = 2; } else { /* steht eine Person der Partei in der Burg? */ unit *u = NULL; for (u = r->units; u; u = u->next) { if (u->building == b) { self = 1; break; } } } } } else if (typ == TYP_UNIT) { unit *u = (unit *)obj; a = u->attribs; r = u->region; if (u->faction == viewer){ self = 2; } } else if (typ == TYP_REGION) { r = (region *)obj; a = r->attribs; } else { /* fehler */ } for (;a;a=a->next) { char buf[4096]; if (fval(a->type, ATF_CURSE)) { curse *c = (curse *)a->data.v; message * msg; if (c->type->cansee) { self = c->type->cansee(viewer, obj, typ, c, self); } msg = msg_curse(c, obj, typ, self); if (msg) { rnl(F); nr_render(msg, viewer->locale, buf, sizeof(buf), viewer); rparagraph(F, buf, indent, 2, 0); msg_release(msg); } } else if (a->type==&at_effect && self) { effect_data * data = (effect_data *)a->data.v; if (data->value>0) { sprintf(buf, "Auf der Einheit lieg%s %d Wirkung%s %s.", (data->value==1 ? "t" : "en"), data->value, (data->value==1 ? "" : "en"), LOC(default_locale, resourcename(data->type->itype->rtype, 0))); rnl(F); rparagraph(F, buf, indent, 2, 0); } } } } static void rps_nowrap(FILE * F, const char *s) { const char *x = s; size_t indent = 0; while (*x++ == ' '); indent = x - s - 1; if (*(x - 1) && indent && *x == ' ') indent += 2; x = s; while (*s) { if (s == x) { x = strchr(x + 1, ' '); if (!x) x = s + strlen(s); } rpc(F, *s++, 1); } } static void rpunit(FILE * F, const faction * f, const unit * u, int indent, int mode) { attrib *a_otherfaction; char marker; int dh; boolean isbattle = (boolean)(mode == see_battle); char buf[8192]; if (u->race == new_race[RC_SPELL]) return; { rnl(F); dh = bufunit(f, u, indent, mode, buf, sizeof(buf)); } a_otherfaction = a_find(u->attribs, &at_otherfaction); if (u->faction == f) { marker = '*'; } else { if (a_otherfaction && f != u->faction && get_otherfaction(a_otherfaction) == f && !fval(u, UFL_PARTEITARNUNG)) { marker = '!'; } else { if (dh && !fval(u, UFL_PARTEITARNUNG)) { marker = '+'; } else { marker = '-'; } } } rparagraph(F, buf, indent, 0, marker); if (!isbattle) { print_curses(F, f, u, TYP_UNIT, indent); } } static void rp_messages(FILE * F, message_list * msgs, faction * viewer, int indent, boolean categorized) { nrsection * section; if (!msgs) return; for (section = sections; section; section=section->next) { int k = 0; struct mlist * m = msgs->begin; while (m) { /* messagetype * mt = m->type; */ if (strcmp(nr_section(m->msg), section->name)==0) { char lbuf[8192]; if (!k && categorized) { const char * section_title; char cat_identifier[24]; rnl(F); sprintf(cat_identifier, "section_%s", section->name); section_title = LOC(viewer->locale, cat_identifier); centre(F, section_title, true); rnl(F); k = 1; } nr_render(m->msg, viewer->locale, lbuf, sizeof(lbuf), viewer); rparagraph(F, lbuf, indent, 2, 0); } m = m->next; } } } static void rp_battles(FILE * F, faction * f) { if (f->battles!=NULL) { struct bmsg * bm = f->battles; rnl(F); centre(F, LOC(f->locale, "section_battle"), false); rnl(F); while (bm) { char buf[80]; RENDER(f, buf, sizeof(buf), ("battle::header", "region", bm->r)); rnl(F); centre(F, buf, true); rnl(F); rp_messages(F, bm->msgs, f, 0, false); bm = bm->next; } } } static void prices(FILE * F, const region * r, const faction * f) { const luxury_type *sale=NULL; struct demand * dmd; message * m; int n = 0; char buf[4096]; if (r->land==NULL || r->land->demands==NULL) return; for (dmd=r->land->demands;dmd;dmd=dmd->next) { if (dmd->value==0) sale = dmd->type; else if (dmd->value > 0) n++; } assert(sale!=NULL); m = msg_message("nr_market_sale", "product price", sale->itype->rtype, sale->price); nr_render(m, f->locale, buf, sizeof(buf), f); msg_release(m); if (n > 0) { char * bufp = buf + strlen(buf); bufp += strlcpy(bufp, " ", sizeof(buf)-(bufp-buf)); bufp += strlcpy(bufp, LOC(f->locale, "nr_trade_intro"), sizeof(buf)-(bufp-buf)); bufp += strlcpy(bufp, " ", sizeof(buf)-(bufp-buf)); for (dmd=r->land->demands;dmd;dmd=dmd->next) if(dmd->value > 0) { m = msg_message("nr_market_price", "product price", dmd->type->itype->rtype, dmd->value * dmd->type->price); bufp += nr_render(m, f->locale, bufp, sizeof(buf)-(bufp-buf), f); msg_release(m); n--; if (n == 0) { bufp += strlcpy(bufp, LOC(f->locale, "nr_trade_end"), sizeof(buf)-(bufp-buf)); } else if (n == 1) { bufp += strlcpy(bufp, " ", sizeof(buf)-(bufp-buf)); bufp += strlcpy(bufp, LOC(f->locale, "nr_trade_final"), sizeof(buf)-(bufp-buf)); bufp += strlcpy(bufp, " ", sizeof(buf)-(bufp-buf)); } else { bufp += strlcpy(bufp, LOC(f->locale, "nr_trade_next"), sizeof(buf)-(bufp-buf)); bufp += strlcpy(bufp, " ", sizeof(buf)-(bufp-buf)); } } } /* Schreibe Paragraphen */ rparagraph(F, buf, 0, 0, 0); } boolean see_border(const border * b, const faction * f, const region * r) { boolean cs = b->type->fvisible(b, f, r); if (!cs) { cs = b->type->rvisible(b, r); if (!cs) { const unit * us = r->units; while (us && !cs) { if (us->faction==f) { cs = b->type->uvisible(b, us); if (cs) break; } us=us->next; } } } return cs; } static void describe(FILE * F, const region * r, int partial, faction * f) { int n; boolean dh; direction_t d; int trees; int saplings; attrib *a; const char *tname; struct edge { struct edge * next; char * name; boolean transparent; boolean block; boolean exist[MAXDIRECTIONS]; direction_t lastd; } * edges = NULL, * e; boolean see[MAXDIRECTIONS]; char buf[8192]; char * bufp = buf; for (d = 0; d != MAXDIRECTIONS; d++) { /* Nachbarregionen, die gesehen werden, ermitteln */ region *r2 = rconnect(r, d); border *b; see[d] = true; if (!r2) continue; for (b=get_borders(r, r2);b;) { struct edge * e = edges; boolean transparent = b->type->transparent(b, f); const char * name = b->type->name(b, r, f, GF_DETAILED|GF_ARTICLE); if (!transparent) see[d] = false; if (!see_border(b, f, r)) { b = b->next; continue; } while (e && (e->transparent != transparent || strcmp(name,e->name))) e = e->next; if (!e) { e = calloc(sizeof(struct edge), 1); e->name = strdup(name); e->transparent = transparent; e->next = edges; edges = e; } e->lastd=d; e->exist[d] = true; b = b->next; } } bufp += f_regionid(r, f, bufp, sizeof(buf)-(bufp-buf)); if (partial == 1) { bufp += strxcpy(bufp, " (durchgereist)"); } else if (partial == 3) { bufp += strxcpy(bufp, " (benachbart)"); } else if (partial == 2) { bufp += strxcpy(bufp, " (vom Turm erblickt)"); } /* Terrain */ bufp += strxcpy(bufp, ", "); tname = terrain_name(r); bufp += strxcpy(bufp, LOC(f->locale, tname)); /* Trees */ trees = rtrees(r,2); saplings = rtrees(r,1); if (production(r)) { if (trees > 0 || saplings > 0) { bufp += sprintf(bufp, ", %d/%d ", trees, saplings); if (fval(r, RF_MALLORN)) { if (trees == 1) { bufp += strxcpy(bufp, LOC(f->locale, "nr_mallorntree")); } else { bufp += strxcpy(bufp, LOC(f->locale, "nr_mallorntree_p")); } } else if (trees == 1) { bufp += strxcpy(bufp, LOC(f->locale, "nr_tree")); } else { bufp += strxcpy(bufp, LOC(f->locale, "nr_tree_p")); } } } /* iron & stone */ if (partial == 0 && f != (faction *) NULL) { struct rawmaterial * res; for (res=r->resources;res;res=res->next) { int level = -1; int visible = -1; int maxskill = 0; const item_type * itype = resource2item(res->type->rtype); if (res->type->visible==NULL) { visible = res->amount; level = res->level + itype->construction->minskill - 1; } else { const unit * u; for (u=r->units; visible!=res->amount && u!=NULL; u=u->next) { if (u->faction == f) { int s = eff_skill(u, itype->construction->skill, r); if (s>maxskill) { if (s>=itype->construction->minskill) { level = res->level + itype->construction->minskill - 1; } maxskill = s; visible = res->type->visible(res, maxskill); } } } } if (level>=0 && visible >= 0) { bufp += snprintf(bufp, sizeof(buf)-(bufp-buf), ", %d %s/%d", visible, LOC(f->locale, res->type->name), res->level + itype->construction->minskill - 1); } } } /* peasants & silver */ if (rpeasants(r)) { int n = rpeasants(r); bufp += sprintf(bufp, ", %d", n); if(fval(r, RF_ORCIFIED)) { strcpy(bufp++, " "); bufp += strxcpy(bufp, LOC(f->locale, n==1?"rc_orc":"rc_orc_p")); } else { strcpy(bufp++, " "); bufp += strxcpy(bufp, LOC(f->locale, n==1?"peasant":"peasant_p")); } } if (rmoney(r) && partial == 0) { bufp += sprintf(bufp, ", %d ", rmoney(r)); bufp += strxcpy(bufp, LOC(f->locale, resourcename(oldresourcetype[R_SILVER], rmoney(r)!=1))); } /* Pferde */ if (rhorses(r)) { bufp += sprintf(bufp, ", %d ", rhorses(r)); bufp += strxcpy(bufp, LOC(f->locale, resourcename(oldresourcetype[R_HORSE], (rhorses(r)>1)?GR_PLURAL:0))); } strcpy(bufp++, "."); if (r->display && r->display[0]) { strcpy(bufp++, " "); bufp += strxcpy(bufp, r->display); n = r->display[strlen(r->display) - 1]; if (n != '!' && n != '?' && n != '.') { strcpy(bufp++, "."); } } { const faction * owner = region_owner(r); if (owner!=NULL) { bufp += strxcpy(bufp, " Die Region ist im Besitz von "); bufp += strxcpy(bufp, factionname(owner)); strcpy(bufp++, "."); } } a = a_find(r->attribs, &at_overrideroads); if (a) { strcpy(bufp++, " "); bufp += strxcpy(bufp, (char *)a->data.v); } else { int nrd = 0; /* Nachbarregionen, die gesehen werden, ermitteln */ for (d = 0; d != MAXDIRECTIONS; d++) if (see[d] && rconnect(r, d)) nrd++; /* list directions */ dh = false; for (d = 0; d != MAXDIRECTIONS; d++) if (see[d]) { region * r2 = rconnect(r, d); if(!r2) continue; nrd--; if (dh) { char regname[4096]; if (nrd == 0) { strcpy(bufp++, " "); bufp += strxcpy(bufp, LOC(f->locale, "nr_nb_final")); } else { bufp += strxcpy(bufp, LOC(f->locale, "nr_nb_next")); } bufp += strxcpy(bufp, LOC(f->locale, directions[d])); strcpy(bufp++, " "); f_regionid(r2, f, regname, sizeof(regname)); bufp += sprintf(bufp, trailinto(r2, f->locale), regname); } else { strcpy(bufp++, " "); MSG(("nr_vicinitystart", "dir region", d, r2), bufp, sizeof(buf)-(bufp-buf), f->locale, f); bufp += strlen(bufp); dh = true; } } /* Spezielle Richtungen */ for (a = a_find(r->attribs, &at_direction);a && a->type==&at_direction;a=a->next) { spec_direction * d = (spec_direction *)(a->data.v); bufp += strlcpy(bufp, " ", sizeof(buf) - (bufp-buf)); bufp += strlcpy(bufp, LOC(f->locale, d->desc), sizeof(buf) - (bufp-buf)); bufp += strlcpy(bufp, " (\"", sizeof(buf) - (bufp-buf)); bufp += strlcpy(bufp, LOC(f->locale, d->keyword), sizeof(buf) - (bufp-buf)); bufp += strlcpy(bufp, "\")", sizeof(buf) - (bufp-buf)); bufp += strlcpy(bufp, ".", sizeof(buf) - (bufp-buf)); dh = 1; } } rnl(F); rparagraph(F, buf, 0, 0, 0); if (partial==0 && rplane(r) == get_astralplane() && !is_cursed(r->attribs, C_ASTRALBLOCK, 0)) { /* Sonderbehandlung Teleport-Ebene */ region_list *rl = astralregions(r, inhabitable); region_list *rl2; if (rl) { /* TODO: Avoid buffer overflows */ char * c = buf; c += strxcpy(c, "Schemen der Regionen "); rl2 = rl; while (rl2) { c += f_regionid(rl2->data, f, c, sizeof(buf)-(c-buf)); rl2 = rl2->next; if (rl2) { c += strxcpy(c, ", "); } } strcpy(c, " sind erkennbar."); free_regionlist(rl); /* Schreibe Paragraphen */ rnl(F); rparagraph(F, buf, 0, 0, 0); } } n = 0; /* Wirkungen permanenter Sprüche */ print_curses(F, f, r, TYP_REGION,0); /* Produktionsreduktion */ a = a_find(r->attribs, &at_reduceproduction); if(a) { sprintf(buf, "Die Region ist verwüstet, der Boden karg."); rparagraph(F, buf, 0, 0, 0); } if (edges) rnl(F); for (e=edges;e;e=e->next) { char * bufp = buf; boolean first = true; for (d=0;d!=MAXDIRECTIONS;++d) { if (!e->exist[d]) continue; if (first) bufp += strxcpy(bufp, "Im "); else { if (e->lastd==d) bufp += strxcpy(bufp, " und im "); else bufp += strxcpy(bufp, ", im "); } bufp += strxcpy(bufp, LOC(f->locale, directions[d])); first = false; } if (!e->transparent) bufp += strxcpy(bufp, " versperrt "); else bufp += strxcpy(bufp, " befindet sich "); bufp += strxcpy(bufp, e->name); if (!e->transparent) bufp += strxcpy(bufp, " die Sicht."); else strcpy(bufp++, "."); rparagraph(F, buf, 0, 0, 0); } if (edges) { while (edges) { e = edges->next; free(edges->name); free(edges); edges = e; } } } static void statistics(FILE * F, const region * r, const faction * f) { const unit *u; int number = 0, p = rpeasants(r); message * m; item *itm, *items = NULL; char buf[4096]; /* count */ for (u = r->units; u; u = u->next) { if (u->faction == f && u->race != new_race[RC_SPELL]) { for (itm=u->items;itm;itm=itm->next) { i_change(&items, itm->type, itm->number); } number += u->number; } } /* print */ rnl(F); m = msg_message("nr_stat_header", "region", r); nr_render(m, f->locale, buf, sizeof(buf), f); msg_release(m); rparagraph(F, buf, 0, 0, 0); rnl(F); /* Region */ if (fval(r->terrain, LAND_REGION) && rmoney(r)) { m = msg_message("nr_stat_maxentertainment", "max", entertainmoney(r)); nr_render(m, f->locale, buf, sizeof(buf), f); rparagraph(F, buf, 2, 2, 0); msg_release(m); } if (production(r) && (!fval(r->terrain, SEA_REGION) || f->race == new_race[RC_AQUARIAN])) { m = msg_message("nr_stat_salary", "max", wage(r, f, f->race)); nr_render(m, f->locale, buf, sizeof(buf), f); rparagraph(F, buf, 2, 2, 0); msg_release(m); } if (p) { m = msg_message("nr_stat_recruits", "max", p / RECRUITFRACTION); nr_render(m, f->locale, buf, sizeof(buf), f); rparagraph(F, buf, 2, 2, 0); msg_release(m); if (!TradeDisabled()) { if (buildingtype_exists(r, bt_find("caravan"))) { m = msg_message("nr_stat_luxuries", "max", (p * 2) / TRADE_FRACTION); } else { m = msg_message("nr_stat_luxuries", "max", p / TRADE_FRACTION); } nr_render(m, f->locale, buf, sizeof(buf), f); rparagraph(F, buf, 2, 2, 0); msg_release(m); } } /* info about units */ m = msg_message("nr_stat_people", "max", number); nr_render(m, f->locale, buf, sizeof(buf), f); rparagraph(F, buf, 2, 2, 0); msg_release(m); for (itm = items; itm; itm=itm->next) { sprintf(buf, "%s: %d", LOC(f->locale, resourcename(itm->type->rtype, GR_PLURAL)), itm->number); rparagraph(F, buf, 2, 2, 0); } while (items) i_free(i_remove(&items, items)); } static void durchreisende(FILE * F, const region * r, const faction * f) { if (fval(r, RF_TRAVELUNIT)) { attrib *abegin = a_find(r->attribs, &at_travelunit), *a; int counter = 0, maxtravel = 0; char buf[8192]; char * str = buf; /* How many are we listing? For grammar. */ for (a = abegin; a && a->type==&at_travelunit; a = a->next) { unit * u = (unit*)a->data.v; if (r!=u->region && (u->ship==NULL || fval(u, UFL_OWNER))) { if (cansee_durchgezogen(f, r, u, 0)) { ++maxtravel; } } } if (maxtravel==0) { return; } /* Auflisten. */ *str = '\0'; rnl(F); for (a = abegin; a && a->type==&at_travelunit; a = a->next) { unit * u = (unit*)a->data.v; if (r!=u->region && (u->ship==NULL || fval(u, UFL_OWNER))) { if (cansee_durchgezogen(f, r, u, 0)) { ++counter; if (u->ship != NULL) { if (counter == 1) { str += strlcpy(str, "Die ", sizeof(buf)-(str-buf)); } else { str += strlcpy(str, "die ", sizeof(buf)-(str-buf)); } str += strlcpy(str, shipname(u->ship), sizeof(buf)-(str-buf)); } else { str += strlcpy(str, unitname(u), sizeof(buf)-(str-buf)); } if (counter + 1 < maxtravel) { str += strlcpy(str, ", ", sizeof(buf)-(str-buf)); } else if (counter + 1 == maxtravel) { str += strlcpy(str, LOC(f->locale, "list_and"), sizeof(buf)-(str-buf)); } } } } if (maxtravel == 1) { str += strlcpy(str, " hat die Region durchquert.", sizeof(buf)-(str-buf)); rparagraph(F, buf, 0, 0, 0); } else { str += strlcpy(str, " haben die Region durchquert.", sizeof(buf)-(str-buf)); rparagraph(F, buf, 0, 0, 0); } } } static int buildingmaintenance(const building * b, const resource_type * rtype) { const building_type * bt = b->type; int c, cost=0; static boolean init = false; static const curse_type * nocost_ct; if (!init) { init = true; nocost_ct = ct_find("nocostbuilding"); } if (curse_active(get_curse(b->attribs, nocost_ct))) { return 0; } for (c=0;bt->maintenance && bt->maintenance[c].number;++c) { const maintenance * m = bt->maintenance + c; if (m->rtype==rtype) { if (fval(m, MTF_VARIABLE)) cost += (b->size * m->number); else cost += m->number; } } return cost; } static int report_template(const char * filename, report_context * ctx, const char * charset) { faction * f = ctx->f; region *r; plane *pl; FILE * F = fopen(filename, "wt"); seen_region * sr = NULL; char buf[8192]; char * bufp; int enc = xmlParseCharEncoding(charset); if (F==NULL) { perror(filename); return -1; } if (enc==XML_CHAR_ENCODING_UTF8) { const unsigned char utf8_bom[4] = { 0xef, 0xbb, 0xbf }; fwrite(utf8_bom, 1, 3, F); } rps_nowrap(F, ""); rnl(F); rps_nowrap(F, LOC(f->locale, "nr_template")); rnl(F); rps_nowrap(F, ""); rnl(F); sprintf(buf, "%s %s \"%s\"", LOC(f->locale, "ERESSEA"), factionid(f), LOC(f->locale, "enterpasswd")); rps_nowrap(F, buf); rnl(F); rps_nowrap(F, ""); rnl(F); sprintf(buf, "; ECHECK %s-w4 -r%d -v%s", (f->options & want(O_SILBERPOOL)) ? "-l " : "", f->race->recruitcost, ECHECK_VERSION); /* -v3.4: ECheck Version 3.4.x */ rps_nowrap(F, buf); rnl(F); for (r=ctx->first; sr==NULL && r!=ctx->last; r=r->next) { sr = find_seen(ctx->seen, r); } for (;sr!=NULL;sr=sr->next) { region * r = sr->r; unit *u; int dh = 0; if (sr->modeunits; u; u = u->next) { if (u->faction == f && u->race != new_race[RC_SPELL]) { order * ord; if (!dh) { rps_nowrap(F, ""); rnl(F); pl = getplane(r); if (pl && fval(pl, PFL_NOCOORDS)) { sprintf(buf, "%s; %s", LOC(f->locale, parameters[P_REGION]), rname(r, f->locale)); } else if (pl && pl->id != 0) { sprintf(buf, "%s %d,%d,%d ; %s", LOC(f->locale, parameters[P_REGION]), region_x(r,f), region_y(r,f), pl->id, rname(r, f->locale)); } else { sprintf(buf, "%s %d,%d ; %s", LOC(f->locale, parameters[P_REGION]), region_x(r,f), region_y(r,f), rname(r, f->locale)); } rps_nowrap(F, buf); rnl(F); sprintf(buf,"; ECheck Lohn %d", wage(r, f, f->race)); rps_nowrap(F, buf); rnl(F); rps_nowrap(F, ""); rnl(F); } dh = 1; bufp = buf + sprintf(buf, "%s %s; %s [%d,%d$", LOC(u->faction->locale, parameters[P_UNIT]), unitid(u), u->name, u->number, get_money(u)); if (u->building != NULL && fval(u, UFL_OWNER)) { building * b = u->building; int cost = buildingmaintenance(b, r_silver); if (cost > 0) { bufp += strlcpy(bufp, ",U", sizeof(buf)-(bufp-buf)); bufp += strlcpy(bufp, itoa10(cost), sizeof(buf)-(bufp-buf)); } } else if (u->ship) { if (fval(u, UFL_OWNER)) bufp += strlcpy(bufp, ",S", sizeof(buf)-(bufp-buf)); else bufp += strlcpy(bufp, ",s", sizeof(buf)-(bufp-buf)); bufp += strlcpy(bufp, shipid(u->ship), sizeof(buf)-(bufp-buf)); } if (lifestyle(u) == 0) bufp += strlcpy(bufp, ",I", sizeof(buf)-(bufp-buf)); bufp += strlcpy(bufp, "]", sizeof(buf)-(bufp-buf)); rps_nowrap(F, buf); rnl(F); #ifndef LASTORDER for (ord = u->old_orders; ord; ord = ord->next) { /* this new order will replace the old defaults */ strcpy(buf, " "); write_order(ord, u->faction->locale, buf+2, sizeof(buf)-2); rps_nowrap(F, buf); rnl(F); } #endif for (ord = u->orders; ord; ord = ord->next) { if (u->old_orders && is_repeated(ord)) continue; /* unit has defaults */ if (is_persistent(ord)) { strcpy(buf, " "); write_order(ord, u->faction->locale, buf+2, sizeof(buf)-2); rps_nowrap(F, buf); rnl(F); } } /* If the lastorder begins with an @ it should have * been printed in the loop before. */ #ifdef LASTORDER if (u->lastorder && !is_persistent(u->lastorder)) { strcpy(buf, " "); write_order(u->lastorder, u->faction->locale, buf+2, sizeof(buf)-2); rps_nowrap(F, buf); rnl(F); } #endif } } } rps_nowrap(F, ""); rnl(F); sprintf(buf, LOC(f->locale, parameters[P_NEXT])); rps_nowrap(F, buf); rnl(F); fclose(F); return 0; } static void show_allies(FILE * F, const faction * f, const ally * allies, char * buf, size_t size) { int allierte = 0; int i=0, h, hh = 0; int dh = 0; const ally * sf; char * bufp = buf + strlen(buf); /* buf already contains data */ for (sf = allies; sf; sf = sf->next) { int mode = alliedgroup(NULL, f, sf->faction, sf, HELP_ALL); if (mode > 0) ++allierte; } for (sf = allies; sf; sf = sf->next) { int mode = alliedgroup(NULL, f, sf->faction, sf, HELP_ALL); if (mode <= 0) continue; i++; if (dh) { if (i == allierte) bufp += strlcpy(bufp, LOC(f->locale, "list_and"), size-(bufp-buf)); else bufp += strlcpy(bufp, ", ", size-(bufp-buf)); } dh = 1; hh = 0; bufp += strlcpy(bufp, factionname(sf->faction), size-(bufp-buf)); bufp += strlcpy(bufp, " (", size-(bufp-buf)); if ((mode & HELP_ALL) == HELP_ALL) { bufp += strlcpy(bufp, "Alles", size-(bufp-buf)); } else { for (h = 1; h < HELP_ALL; h *= 2) { int p = MAXPARAMS; if ((mode & h) == h) { switch (h) { case HELP_TRAVEL: p = P_TRAVEL; break; case HELP_MONEY: p = P_MONEY; hh = 1; break; case HELP_FIGHT: p = P_FIGHT; break; case HELP_GIVE: p = P_GIVE; break; case HELP_GUARD: p = P_GUARD; break; case HELP_FSTEALTH: p = P_FACTIONSTEALTH; break; } } if (p!=MAXPARAMS) { if (hh) strlcpy(bufp, ", ", size-(bufp-buf)); bufp += strlcpy(bufp, parameters[p], size-(bufp-buf)); hh = 1; } } } strlcpy(bufp, ")", size-(bufp-buf)); } strlcpy(bufp, ".", size-(bufp-buf)); rparagraph(F, buf, 0, 0, 0); rnl(F); } static void allies(FILE * F, const faction * f) { const group * g = f->groups; char buf[8192]; if (f->allies) { if (!f->allies->next) { strcpy(buf, "Wir helfen der Partei "); } else { strcpy(buf, "Wir helfen den Parteien "); } show_allies(F, f, f->allies, buf, sizeof(buf)); } while (g) { if (g->allies) { if (!g->allies->next) { sprintf(buf, "%s hilft der Partei ", g->name); } else { sprintf(buf, "%s hilft den Parteien ", g->name); } show_allies(F, f, g->allies, buf, sizeof(buf)); } g = g->next; } } #ifdef ENEMIES static void enemies(FILE * F, const faction * f) { faction_list * flist = f->enemies; if (flist!=NULL) { strcpy(buf, "Wir liegen im Krieg mit "); for (;flist!=NULL;flist = flist->next) { const faction * enemy = flist->data; scat(factionname(enemy)); if (flist->next) { scat(", "); } else { scat("."); } } rparagraph(F, buf, 0, 0, 0); rnl(F); } } #endif static void guards(FILE * F, const region * r, const faction * see) { /* die Partei see sieht dies; wegen * "unbekannte Partei", wenn man es selbst ist... */ faction* guardians[512]; int nextguard = 0; unit *u; int i; boolean tarned = false; /* Bewachung */ for (u = r->units; u; u = u->next) { if (getguard(u)) { faction *f = u->faction; faction *fv = visible_faction(see, u); if(fv != f && see != fv) { f = fv; } if (f != see && fval(u, UFL_PARTEITARNUNG)) { tarned=true; } else { for (i=0;i!=nextguard;++i) if (guardians[i]==f) break; if (i==nextguard) { guardians[nextguard++] = f; } } } } if (nextguard || tarned) { char buf[8192]; char * bufp = buf; bufp += strlcpy(bufp, "Die Region wird von ", sizeof(buf) - (bufp-buf)); for (i = 0; i!=nextguard+(tarned?1:0); ++i) { if (i!=0) { if (i == nextguard-(tarned?0:1)) strlcpy(bufp, LOC(see->locale, "list_and"), sizeof(buf) - (bufp-buf)); else strlcpy(bufp, ", ", sizeof(buf) - (bufp-buf)); } if (ilocale, "nr_addresses"), false); rnl(F); while (flist!=NULL) { const faction * f = flist->data; if (f->no!=MONSTER_FACTION) { char buf[8192]; sprintf(buf, "%s: %s; %s", factionname(f), f->email, f->banner); rparagraph(F, buf, 4, 0, (char)(ALLIED(uf, f)?'+':'*')); #ifdef SHORTPWDS if (f->shortpwds) { shortpwd * spwd = f->shortpwds; while (spwd) { if (spwd->used) { sprintf(buf, "Vertretung: %s", spwd->email); rparagraph(F, buf, 6, '-'); } spwd=spwd->next; } } #endif } flist = flist->next; } rnl(F); rpline(F); } void report_building(FILE *F, const region * r, const building * b, const faction * f, int mode) { int i; unit *u; const char * bname; const struct locale * lang = NULL; const building_type * type = b->type; static const struct building_type * bt_illusion; char buffer[8192]; char * bufp = buffer; if (!bt_illusion) bt_illusion = bt_find("illusion"); if (f) lang = f->locale; bufp += snprintf(bufp, sizeof(buffer)-(bufp-buffer), "%s, %s %d, ", buildingname(b), LOC(f->locale, "nr_size"), b->size); if (b->type==bt_illusion) { attrib * a = a_find(b->attribs, &at_icastle); if (a!=NULL) { type = ((icastle_data*)a->data.v)->type; } } bname = LOC(lang, buildingtype(type, b, b->size)); bufp += strlcpy(bufp, bname, sizeof(buffer)-(bufp-buffer)); if (type!=b->type) { unit * owner = buildingowner(r, b); if (owner && owner->faction==f) { /* illusion. report real type */ char lbuf[32]; bname = LOC(lang, buildingtype(b->type, b, b->size)); sprintf(lbuf, " (%s)", bname); bufp += strlcpy(bufp, lbuf, sizeof(buffer)-(bufp-buffer)); } } if (b->size < type->maxsize) { bufp += strlcpy(bufp, " (im Bau)", sizeof(buffer)-(bufp-buffer)); } if (b->besieged > 0 && mode>=see_lighthouse) { bufp += strlcpy(bufp, ", belagert von ", sizeof(buffer)-(bufp-buffer)); bufp += strlcpy(bufp, itoa10(b->besieged), sizeof(buffer)-(bufp-buffer)); bufp += strlcpy(bufp, " Personen ", sizeof(buffer)-(bufp-buffer)); if (b->besieged >= b->size * SIEGEFACTOR) { bufp += strlcpy(bufp, "(abgeschnitten)", sizeof(buffer)-(bufp-buffer)); } } i = 0; if (b->display && b->display[0]) { bufp += strlcpy(bufp, "; ", sizeof(buffer)-(bufp-buffer)); bufp += strlcpy(bufp, b->display, sizeof(buffer)-(bufp-buffer)); i = b->display[strlen(b->display) - 1]; } #ifdef WDW_PYRAMID if (i != '!' && i != '?' && i != '.') { scat(", "); } if (b->type == bt_find("pyramid")) { unit * owner = buildingowner(r, b); scat("Größenstufe "); icat(wdw_pyramid_level(b)); scat("."); if (owner && owner->faction==f) { const construction *ctype = b->type->construction; int completed = b->size; int c; scat(" Baukosten pro Größenpunkt: "); while(ctype->improvement != NULL && ctype->improvement != ctype && ctype->maxsize > 0 && ctype->maxsize <= completed) { completed -= ctype->maxsize; ctype = ctype->improvement; } assert(ctype->materials != NULL); for (c=0;ctype->materials[c].number;c++) { const resource_type * rtype = ctype->materials[c].rtype; int number = ctype->materials[c].number; if(c > 0) { scat(", "); } icat(number); scat(" "); scat(locale_string(lang, resourcename(rtype, number!=1?GR_PLURAL:0))); } scat("."); scat(" Erforderlicher Talentwert: "); icat(b->type->construction->minskill); scat("."); } } #else if (i != '!' && i != '?' && i != '.') bufp += strlcpy(bufp, ".", sizeof(buffer)-(bufp-buffer)); #endif rparagraph(F, buffer, 2, 0, 0); if (modeunits; u; u = u->next) { if (u->building == b) { assert(fval(u, UFL_OWNER) || !"you must call reorder_owners() first!"); rpunit(F, f, u, 6, mode); u = u->next; break; } } for (;u!=NULL && u->building==b;u=u->next) { rpunit(F, f, u, 6, mode); } } int report_plaintext(const char * filename, report_context * ctx, const char * charset) { int flag = 0; char ch; int dh; int anyunits; const struct region *r; faction * f = ctx->f; building *b; ship *sh; unit *u; char pzTime[64]; attrib *a; message * m; unsigned char op; int ix = want(O_STATISTICS); int wants_stats = (f->options & ix); FILE * F = fopen(filename, "wt"); seen_region * sr = NULL; char buf[8192]; char * bufp; int enc = xmlParseCharEncoding(charset); if (F==NULL) { perror(filename); return -1; } if (enc==XML_CHAR_ENCODING_UTF8) { const unsigned char utf8_bom[4] = { 0xef, 0xbb, 0xbf }; fwrite(utf8_bom, 1, 3, F); } strftime(pzTime, 64, "%A, %d. %B %Y, %H:%M", localtime(&ctx->report_time)); m = msg_message("nr_header_date", "game date", global.gamename, pzTime); nr_render(m, f->locale, buf, sizeof(buf), f); msg_release(m); centre(F, buf, true); centre(F, gamedate_season(f->locale), true); rnl(F); sprintf(buf, "%s, %s/%s (%s)", factionname(f), LOC(f->locale, rc_name(f->race, 1)), LOC(f->locale, mkname("school", magietypen[f->magiegebiet])), f->email); centre(F, buf, true); if (f->alliance!=NULL) { centre(F, alliancename(f->alliance), true); } #ifdef KARMA_MODULE buf[0] = 0; dh = 0; for (a=a_find(f->attribs, &at_faction_special); a && a->type==&at_faction_special; a=a->next) { char buf2[80]; dh++; if (fspecials[a->data.sa[0]].maxlevel != 100) { sprintf(buf2, "%s (%d)", fspecials[a->data.sa[0]].name, a->data.sa[1]); } else { sprintf(buf2, "%s", fspecials[a->data.sa[0]].name); } if(dh > 1) strcat(buf, ", "); strcat(buf, buf2); } if(dh > 0) centre(F, buf, true); if (f->karma > 0) { sprintf(buf, "Deine Partei hat %d Karma.", f->karma); centre(F, buf, true); } #endif dh = 0; if (f->age <= 2) { const char * s; if (f->age <= 1) { ADDMSG(&f->msgs, msg_message("changepasswd", "value", f->passw)); } RENDER(f, buf, sizeof(buf), ("newbie_password", "password", f->passw)); rnl(F); centre(F, buf, true); s = locale_getstring(f->locale, "newbie_info_1"); if (s) { rnl(F); centre(F, s, true); } s = locale_getstring(f->locale, "newbie_info_2"); if (s) { rnl(F); centre(F, s, true); } if ((f->options & want(O_COMPUTER)) == 0) { f->options |= want(O_COMPUTER); s = locale_getstring(f->locale, "newbie_info_3"); if (s) { rnl(F); centre(F, s, true); } } } rnl(F); #ifdef SCORE_MODULE if (f->options & want(O_SCORE) && f->age > DISPLAYSCORE) { RENDER(f, buf, sizeof(buf), ("nr_score", "score average", f->score, average_score_of_age(f->age, f->age / 24 + 1))); centre(F, buf, true); } #endif m = msg_message("nr_population", "population units", count_all(f), f->no_units); nr_render(m, f->locale, buf, sizeof(buf), f); msg_release(m); centre(F, buf, true); if (f->race == new_race[RC_HUMAN]) { int maxmig = count_maxmigrants(f); m = msg_message("nr_migrants", "units maxunits", count_migrants(f), maxmig); nr_render(m, f->locale, buf, sizeof(buf), f); msg_release(m); centre(F, buf, true); } #ifdef HEROES { int maxh = maxheroes(f); if (maxh) { message * msg = msg_message("nr_heroes", "units maxunits", countheroes(f), maxh); nr_render(msg, f->locale, buf, sizeof(buf), f); msg_release(msg); centre(F, buf, true); } } #endif if (f->items!=NULL) { message * msg = msg_message("nr_claims", "items", f->items); nr_render(msg, f->locale, buf, sizeof(buf), f); msg_release(msg); rnl(F); centre(F, buf, true); } /* Insekten-Winter-Warnung */ if (f->race == new_race[RC_INSECT]) { static int thisseason = -1; if (thisseason<0) thisseason = get_gamedate(turn+1, 0)->season; if (thisseason == 0) { centre(F, LOC(f->locale, "nr_insectwinter"), true); rnl(F); } else { static int nextseason = -1; if (nextseason<0) nextseason = get_gamedate(turn+2, 0)->season; if (nextseason == 0) { centre(F, LOC(f->locale, "nr_insectfall"), true); rnl(F); } } } bufp = buf + sprintf(buf, "%s:", LOC(f->locale, "nr_options")); for (op = 0; op != MAXOPTIONS; op++) { if (f->options & want(op)) { bufp += strlcpy(bufp, " ", sizeof(buf)-(bufp-buf)); bufp += strlcpy(bufp, LOC(f->locale, options[op]), sizeof(buf)-(bufp-buf)); #ifdef AT_OPTION if(op == O_NEWS) { attrib *a = a_find(f->attribs, &at_option_news); if(!a) { /* Zur Altlastenbeseitigung */ f->options = f->options & ~op; } else { int sec = a->data.i; int i; bufp += strlcpy(bufp, "(", sizeof(buf)-(bufp-buf)); for(i=1; sec != 0; i *= 2) { if(sec & i) { bufp += strlcpy(bufp, itoa10(i), sizeof(buf)-(bufp-buf)); sec = sec & ~i; if (sec) bufp += strlcpy(bufp, ",", sizeof(buf)-(bufp-buf)); } } bufp += strlcpy(bufp, ")", sizeof(buf)-(bufp-buf)); } } #endif flag++; } } if (flag > 0) { rnl(F); centre(F, buf, true); } rp_messages(F, f->msgs, f, 0, true); rp_battles(F, f); a = a_find(f->attribs, &at_reportspell); if (a) { rnl(F); centre(F, LOC(f->locale, "section_newspells"), true); while (a && a->type==&at_reportspell) { spell *sp = (spell *)a->data.v; report_spell(F, sp, f->locale); a = a->next; } } ch = 0; for (a=a_find(f->attribs, &at_showitem);a && a->type==&at_showitem;a=a->next) { const potion_type * ptype = resource2potion(((const item_type*)a->data.v)->rtype); const char * description = NULL; requirement * m; if (ptype!=NULL) { const char * pname = resourcename(ptype->itype->rtype, 0); char * bufp; m = ptype->itype->construction->materials; if (ch==0) { rnl(F); centre(F, LOC(f->locale, "section_newpotions"), true); ch = 1; } rnl(F); centre(F, LOC(f->locale, pname), true); sprintf(buf, "%s %d", LOC(f->locale, "nr_level"), ptype->level); centre(F, buf, true); rnl(F); bufp = buf + sprintf(buf, "%s: ", LOC(f->locale, "nr_herbsrequired")); while (m->number) { bufp += strlcpy(bufp, resourcename(m->rtype, 0), sizeof(buf)-(bufp-buf)); ++m; if (m->number) bufp += strlcpy(bufp, ", ", sizeof(buf)-(bufp-buf)); } centre(F, buf, true); rnl(F); if (description==NULL) { const char * potiontext = mkname("potion", pname); description = LOC(f->locale, potiontext); } centre(F, description, true); } } rnl(F); centre(F, LOC(f->locale, "nr_alliances"), false); rnl(F); #ifdef ENEMIES enemies(F, f); #endif allies(F, f); rpline(F); anyunits = 0; for (r=ctx->first;sr==NULL && r!=ctx->last;r=r->next) { sr = find_seen(ctx->seen, r); } for (;sr!=NULL;sr=sr->next) { region * r = sr->r; int stealthmod = stealth_modifier(sr->mode); if (sr->modemode==see_unit) { anyunits = 1; describe(F, r, 0, f); if (!TradeDisabled() && !fval(r->terrain, SEA_REGION) && rpeasants(r)/TRADE_FRACTION > 0) { rnl(F); prices(F, r, f); } guards(F, r, f); durchreisende(F, r, f); } else { if (sr->mode==see_far) { describe(F, r, 3, f); guards(F, r, f); durchreisende(F, r, f); } else if (sr->mode==see_lighthouse) { describe(F, r, 2, f); durchreisende(F, r, f); } else { describe(F, r, 1, f); durchreisende(F, r, f); } } /* Statistik */ if (wants_stats && sr->mode==see_unit) statistics(F, r, f); /* Nachrichten an REGION in der Region */ if (sr->mode==see_unit || sr->mode==see_travel) { message_list * mlist = r_getmessages(r, f); rp_messages(F, r->msgs, f, 0, true); if (mlist) rp_messages(F, mlist, f, 0, true); } /* Burgen und ihre Einheiten */ for (b = rbuildings(r); b; b = b->next) { rnl(F); report_building(F, r, b, f, sr->mode); } /* Restliche Einheiten */ if (stealthmod>INT_MIN) { for (u = r->units; u; u = u->next) { if (!u->building && !u->ship) { if (u->faction == f || cansee(f, r, u, stealthmod)) { if (dh == 0 && !(rbuildings(r) || r->ships)) { dh = 1; /* rnl(F); */ } rpunit(F, f, u, 4, sr->mode); } } } } /* Schiffe und ihre Einheiten */ for (sh = r->ships; sh; sh = sh->next) { faction *of = NULL; rnl(F); /* Gewicht feststellen */ for (u = r->units; u; u = u->next) { if (u->ship == sh && fval(u, UFL_OWNER)) { of = u->faction; break; } } if (of == f) { int n = 0, p = 0; getshipweight(sh, &n, &p); n = (n+99) / 100; /* 1 Silber = 1 GE */ bufp = buf + sprintf(buf, "%s, %s, (%d/%d)", shipname(sh), LOC(f->locale, sh->type->name[0]), n, shipcapacity(sh) / 100); } else { bufp = buf + sprintf(buf, "%s, %s", shipname(sh), LOC(f->locale, sh->type->name[0])); } assert(sh->type->construction->improvement==NULL); /* sonst ist construction::size nicht ship_type::maxsize */ if (sh->size!=sh->type->construction->maxsize) { bufp += sprintf(bufp, ", %s (%d/%d)", LOC(f->locale, "nr_undercons"), sh->size, sh->type->construction->maxsize); } if (sh->damage) { int percent = (sh->damage*100+DAMAGE_SCALE-1)/(sh->size*DAMAGE_SCALE); bufp += sprintf(bufp, ", %d%% %s", percent, LOC(f->locale, "nr_damaged")); } if (!fval(r->terrain, SEA_REGION)) { if (sh->coast != NODIRECTION) { bufp += strlcpy(bufp, ", ", sizeof(buf) - (bufp-buf)); bufp += strlcpy(bufp, LOC(f->locale, coasts[sh->coast]), sizeof(buf) - (bufp-buf)); } } ch = 0; if (sh->display && sh->display[0]) { bufp += strlcpy(bufp, "; ", sizeof(buf) - (bufp-buf)); bufp += strlcpy(bufp, sh->display, sizeof(buf) - (bufp-buf)); ch = sh->display[strlen(sh->display) - 1]; } if (ch != '!' && ch != '?' && ch != '.') bufp += strlcpy(bufp, ".", sizeof(buf) - (bufp-buf)); rparagraph(F, buf, 2, 0, 0); print_curses(F,f,sh,TYP_SHIP,4); for (u = r->units; u; u = u->next) { if (u->ship == sh && fval(u, UFL_OWNER)) { rpunit(F, f, u, 6, sr->mode); break; } } for (u = r->units; u; u = u->next) { if (u->ship == sh && !fval(u, UFL_OWNER)) { rpunit(F, f, u, 6, sr->mode); } } } rnl(F); rpline(F); } if (f->no != MONSTER_FACTION) { if (!anyunits) { rnl(F); rparagraph(F, LOC(f->locale, "nr_youaredead"), 0, 2, 0); } else { list_address(F, f, ctx->addresses); } } fclose(F); return 0; } void base36conversion(void) { region * r; for (r=regions;r;r=r->next) { unit * u; for (u=r->units;u;u=u->next) { if (forbiddenid(u->no)) { uunhash(u); u->no = newunitid(); uhash(u); } } } } #define FMAXHASH 1021 struct fsee { struct fsee * nexthash; faction * f; struct see { struct see * next; faction * seen; unit * proof; } * see; } * fsee[FMAXHASH]; #define REPORT_NR (1 << O_REPORT) #define REPORT_CR (1 << O_COMPUTER) #define REPORT_ZV (1 << O_ZUGVORLAGE) #define REPORT_ZIP (1 << O_COMPRESS) #define REPORT_BZIP2 (1 << O_BZIP2) unit * can_find(faction * f, faction * f2) { int key = f->no % FMAXHASH; struct fsee * fs = fsee[key]; struct see * ss; if (f==f2) return f->units; while (fs && fs->f!=f) fs=fs->nexthash; if (!fs) return NULL; ss=fs->see; while (ss && ss->seen!=f2) ss=ss->next; if (ss) { /* bei TARNE PARTEI yxz muss die Partei von unit proof nicht * wirklich Partei f2 sein! */ /* assert(ss->proof->faction==f2); */ return ss->proof; } return NULL; } static void add_find(faction * f, unit * u, faction *f2) { /* faction f sees f2 through u */ int key = f->no % FMAXHASH; struct fsee ** fp = &fsee[key]; struct fsee * fs; struct see ** sp; struct see * ss; while (*fp && (*fp)->f!=f) fp=&(*fp)->nexthash; if (!*fp) { fs = *fp = calloc(sizeof(struct fsee), 1); fs->f = f; } else fs = *fp; sp = &fs->see; while (*sp && (*sp)->seen!=f2) sp=&(*sp)->next; if (!*sp) { ss = *sp = calloc(sizeof(struct see), 1); ss->proof = u; ss->seen = f2; } else ss = *sp; ss->proof = u; } static void update_find(void) { region * r; static boolean initial = true; if (initial) for (r=regions;r;r=r->next) { unit * u; for (u=r->units;u;u=u->next) { faction * lastf = u->faction; unit * u2; for (u2=r->units;u2;u2=u2->next) { if (u2->faction==lastf || u2->faction==u->faction) continue; if (seefaction(u->faction, r, u2, 0)) { faction *fv = visible_faction(u->faction, u2); lastf = fv; add_find(u->faction, u2, fv); } } } } initial = false; } boolean kann_finden(faction * f1, faction * f2) { update_find(); return (boolean)(can_find(f1, f2)!=NULL); } /******* end summary ******/ void report_init(void) { register_reporttype("nr", &report_plaintext, 1<nexthash; free(fsee[i]); fsee[i] = fs; } } }