From b5bffaf75e3199fb4dadefa1eea3c1da313c039a Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Fri, 6 Jun 2008 21:54:19 +0000 Subject: [PATCH] - reorganizing units for faster report-generation - more xml functionality --- src/common/gamecode/creport.c | 96 +++-------- src/common/gamecode/economy.c | 10 +- src/common/gamecode/laws.c | 8 +- src/common/gamecode/report.c | 272 ++++++++++++++------------------ src/common/gamecode/xmlreport.c | 125 ++++++++++++++- src/common/kernel/eressea.c | 174 ++++++++++---------- src/common/kernel/eressea.h | 2 +- src/common/kernel/item.c | 4 +- src/common/kernel/reports.c | 161 ++++++++++++++++--- src/common/kernel/reports.h | 16 +- src/eressea/korrektur.c | 4 +- src/eressea/lua/ship.cpp | 2 +- src/eressea/lua/test.cpp | 2 + 13 files changed, 519 insertions(+), 357 deletions(-) diff --git a/src/common/gamecode/creport.c b/src/common/gamecode/creport.c index 328ef94f4..d68b1277e 100644 --- a/src/common/gamecode/creport.c +++ b/src/common/gamecode/creport.c @@ -669,6 +669,7 @@ cr_output_unit(FILE * F, const region * r, boolean itemcloak = false; static const curse_type * itemcloak_ct = 0; static boolean init = false; + item result[MAX_INVENTORY]; if (fval(u->race, RCF_INVISIBLE)) return; @@ -889,29 +890,12 @@ cr_output_unit(FILE * F, const region * r, if (f == u->faction || omniscient(u->faction)) { show = u->items; } else if (itemcloak==false && mode>=see_unit && !(a_fshidden - && a_fshidden->data.ca[1] == 1 && effskill(u, SK_STEALTH) >= 3)) { - show = NULL; - for (itm=u->items;itm;itm=itm->next) { - item * ishow; - const char * ic; - int in; - report_item(u, itm, f, NULL, &ic, &in, true); - if (in>0 && ic && *ic) { - for (ishow = show; ishow; ishow=ishow->next) { - const char * sc; - int sn; - if (ishow->type==itm->type) sc=ic; - else report_item(u, ishow, f, NULL, &sc, &sn, true); - if (sc==ic || strcmp(sc, ic)==0) { - ishow->number+=itm->number; - break; - } - } - if (ishow==NULL) { - ishow = i_add(&show, i_new(itm->type, itm->number)); - } - } - } + && a_fshidden->data.ca[1] == 1 && effskill(u, SK_STEALTH) >= 3)) + { + int n = report_items(u->items, result, MAX_INVENTORY, u, f); + assert(n>=0); + if (n>0) show = result; + else show = NULL; } else { show = NULL; } @@ -928,12 +912,6 @@ cr_output_unit(FILE * F, const region * r, } fprintf(F, "%d;%s\n", in, add_translation(ic, locale_string(f->locale, ic))); } - if (show!=u->items) { - /* free the temporary items */ - while (show) { - i_free(i_remove(&show, show)); - } - } print_curses(F, f, u, TYP_UNIT); } @@ -1057,7 +1035,7 @@ encode_region(const faction * f, const region * r) { } static char * -report_resource(char * buf, const char * name, const struct locale * loc, int amount, int level) +cr_output_resource(char * buf, const char * name, const struct locale * loc, int amount, int level) { buf += sprintf(buf, "RESOURCE %u\n", hashstring(name)); buf += sprintf(buf, "\"%s\";type\n", add_translation(name, LOC(loc, name))); @@ -1117,61 +1095,32 @@ cr_borders(seen_region ** seen, const region * r, const faction * f, int seemode } static void -cr_output_resources(FILE * F, report_context * ctx, region * r, struct rawmaterial * res, int see_mode) +cr_output_resources(FILE * F, report_context * ctx, seen_region * sr) { char cbuf[BUFFERSIZE], *pos = cbuf; + region * r = sr->r; faction * f = ctx->f; + resource_report result[MAX_RAWMATERIALS]; + int n, size = report_resources(sr, result, MAX_RAWMATERIALS, f); +#ifdef RESOURCECOMPAT int trees = rtrees(r, 2); int saplings = rtrees(r, 1); -#ifdef RESOURCECOMPAT if (trees > 0) fprintf(F, "%d;Baeume\n", trees); if (saplings > 0) fprintf(F, "%d;Schoesslinge\n", saplings); if (fval(r, RF_MALLORN) && (trees > 0 || saplings > 0)) fprintf(F, "1;Mallorn\n"); -#endif - - if (!fval(r, RF_MALLORN)) { - if (saplings) pos = report_resource(pos, "rm_sapling", f->locale, saplings, -1); - if (trees) pos = report_resource(pos, "rm_trees", f->locale, trees, -1); - } else { - if (saplings) pos = report_resource(pos, "rm_mallornsapling", f->locale, saplings, -1); - if (trees) pos = report_resource(pos, "rm_mallorn", f->locale, trees, -1); + for (n=0;n=0 && result[n].number>=0) { + fprintf(F, "%d;%s\n", result[n].number, crtag(result[n].name)); + } } - - if (see_mode>=see_unit) { - while (res) { - int maxskill = 0; - int level = -1; - int visible = -1; - 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) { - assert(itype->construction->minskill>0); - level = res->level + itype->construction->minskill - 1; - } - maxskill = s; - visible = res->type->visible(res, maxskill); - } - } - } - } - if (level>=0 && visible >=0) { - pos = report_resource(pos, res->type->name, f->locale, visible, level); -#ifdef RESOURCECOMPAT - if (visible>=0) fprintf(F, "%d;%s\n", visible, crtag(res->type->name)); #endif - } - res = res->next; + + for (n=0;n=0) { + pos = cr_output_resource(pos, result[n].name, f->locale, result[n].number, result[n].level); } } if (pos!=cbuf) fputs(cbuf, F); @@ -1248,7 +1197,7 @@ cr_output_region(FILE * F, report_context * ctx, seen_region * sr) /* this writes both some tags (RESOURCECOMPAT) and a block. * must not write any blocks before it */ - cr_output_resources(F, ctx, r, r->resources, sr->mode); + cr_output_resources(F, ctx, sr); if (sr->mode>=see_unit) { /* trade */ @@ -1350,6 +1299,7 @@ cr_output_region(FILE * F, report_context * ctx, seen_region * sr) } } } + /* main function of the creport. creates the header and traverses all regions */ static int report_computer(const char * filename, report_context * ctx, const char * charset) diff --git a/src/common/gamecode/economy.c b/src/common/gamecode/economy.c index 6591357f6..0780a537a 100644 --- a/src/common/gamecode/economy.c +++ b/src/common/gamecode/economy.c @@ -3003,16 +3003,16 @@ do_work(unit * u, order * ord, request * o) region * r = u->region; int w; - if(fval(u, UFL_WERE)) { - cmistake(u, ord, 313, MSG_INCOME); + if (fval(u, UFL_WERE)) { + if (ord) cmistake(u, ord, 313, MSG_INCOME); return -1; } if (besieged(u)) { - cmistake(u, ord, 60, MSG_INCOME); + if (ord) cmistake(u, ord, 60, MSG_INCOME); return -1; } if (u->ship && is_guarded(r, u, GUARD_CREWS)) { - cmistake(u, ord, 69, MSG_INCOME); + if (ord) cmistake(u, ord, 69, MSG_INCOME); return -1; } w = wage(r, u->faction, u->race); @@ -3022,7 +3022,7 @@ do_work(unit * u, order * ord, request * o) working += u->number; return 0; } - else if (!is_monsters(u->faction)) { + else if (ord && !is_monsters(u->faction)) { ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "race_cantwork", "race", u->race)); } diff --git a/src/common/gamecode/laws.c b/src/common/gamecode/laws.c index c13f6936b..f2aa35ca4 100644 --- a/src/common/gamecode/laws.c +++ b/src/common/gamecode/laws.c @@ -3917,8 +3917,6 @@ processorders (void) process(); /*************************************************/ - for (r = regions;r;r=r->next) reorder_owners(r); - puts(" - Attribute altern"); ageing(); remove_empty_units(); @@ -3932,6 +3930,12 @@ processorders (void) * Beschreibungen geändert haben */ update_spells(); warn_password(); + + /* we reorder the owners to be at the top of the building + * and also everyone in the same building/ship in sequence */ + for (r = regions;r;r=r->next) { + reorder_units(r); + } } int diff --git a/src/common/gamecode/report.c b/src/common/gamecode/report.c index cce3ee9a6..892d3d4d6 100644 --- a/src/common/gamecode/report.c +++ b/src/common/gamecode/report.c @@ -651,7 +651,7 @@ rps_nowrap(FILE * F, const char *s) } static void -rpunit(FILE * F, const faction * f, const unit * u, int indent, int mode) +report_unit(FILE * F, const faction * f, const unit * u, int indent, int mode) { attrib *a_otherfaction; char marker; @@ -829,8 +829,9 @@ see_border(const border * b, const faction * f, const region * r) } static void -describe(FILE * F, const region * r, int partial, faction * f) +describe(FILE * F, const seen_region * sr, faction * f) { + const region * r = sr->r; int n; boolean dh; direction_t d; @@ -885,13 +886,13 @@ describe(FILE * F, const region * r, int partial, faction * f) bytes = (int)f_regionid(r, f, bufp, size); if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - if (partial == 1) { + if (sr->mode==see_travel) { bytes = (int)strlcpy(bufp, " (durchgereist)", size); } - else if (partial == 3) { + else if (sr->mode==see_neighbour) { bytes = (int)strlcpy(bufp, " (benachbart)", size); } - else if (partial == 2) { + else if (sr->mode==see_lighthouse) { bytes = (int)strlcpy(bufp, " (vom Turm erblickt)", size); } else { bytes = 0; @@ -931,35 +932,14 @@ describe(FILE * F, const region * r, int partial, faction * f) } /* 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) { - bytes = snprintf(bufp, size, ", %d %s/%d", visible, - LOC(f->locale, res->type->name), - res->level + itype->construction->minskill - 1); + if (sr->mode==see_unit && f != (faction *) NULL) { + resource_report result[MAX_RAWMATERIALS]; + int n, numresults = report_resources(sr, result, MAX_RAWMATERIALS, f); + + for (n=0;n=0 && result[n].level>=0) { + bytes = snprintf(bufp, size, ", %d %s/%d", result[n].number, + LOC(f->locale, result[n].name), result[n].level); if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); } } @@ -983,7 +963,7 @@ describe(FILE * F, const region * r, int partial, faction * f) } if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); } - if (rmoney(r) && partial == 0) { + if (rmoney(r) && sr->mode==see_unit) { bytes = snprintf(bufp, size, ", %d ", rmoney(r)); if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); bytes = (int)strlcpy(bufp, LOC(f->locale, resourcename(oldresourcetype[R_SILVER], rmoney(r)!=1)), size); @@ -1091,7 +1071,7 @@ describe(FILE * F, const region * r, int partial, faction * f) *bufp = 0; rparagraph(F, buf, 0, 0, 0); - if (partial==0 && rplane(r) == get_astralplane() && + if (sr->mode==see_unit && rplane(r) == get_astralplane() && !is_cursed(r->attribs, C_ASTRALBLOCK, 0)) { /* Sonderbehandlung Teleport-Ebene */ region_list *rl = astralregions(r, inhabitable); @@ -1728,11 +1708,72 @@ list_address(FILE * F, const faction * uf, const faction_list * seenfactions) rpline(F); } -void -report_building(FILE *F, const region * r, const building * b, const faction * f, int mode) +static void +report_ship(FILE * F, const seen_region * sr, const ship * sh, const faction * f, const unit * captain) { + const region * r = sr->r; + char buffer[8192], * bufp = buffer; + size_t size = sizeof(buffer) - 1; + int bytes; + char ch; + + rnl(F); + + if (captain && captain->faction == f) { + int n = 0, p = 0; + getshipweight(sh, &n, &p); + n = (n+99) / 100; /* 1 Silber = 1 GE */ + + bytes = snprintf(bufp, size, "%s, %s, (%d/%d)", shipname(sh), + LOC(f->locale, sh->type->name[0]), n, shipcapacity(sh) / 100); + } else { + bytes = snprintf(bufp, size, "%s, %s", shipname(sh), LOC(f->locale, sh->type->name[0])); + } + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + + assert(sh->type->construction->improvement==NULL); /* sonst ist construction::size nicht ship_type::maxsize */ + if (sh->size!=sh->type->construction->maxsize) { + bytes = snprintf(bufp, size, ", %s (%d/%d)", + LOC(f->locale, "nr_undercons"), sh->size, + sh->type->construction->maxsize); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + if (sh->damage) { + int percent = (sh->damage*100+DAMAGE_SCALE-1)/(sh->size*DAMAGE_SCALE); + bytes = snprintf(bufp, size, ", %d%% %s", percent, LOC(f->locale, "nr_damaged")); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + if (!fval(r->terrain, SEA_REGION)) { + if (sh->coast != NODIRECTION) { + bytes = (int)strlcpy(bufp, ", ", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = (int)strlcpy(bufp, LOC(f->locale, coasts[sh->coast]), size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + } + ch = 0; + if (sh->display && sh->display[0]) { + bytes = (int)strlcpy(bufp, "; ", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = (int)strlcpy(bufp, sh->display, size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + ch = sh->display[strlen(sh->display) - 1]; + } + if (ch != '!' && ch != '?' && ch != '.') { + bytes = (int)strlcpy(bufp, ".", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + *bufp = 0; + rparagraph(F, buffer, 2, 0, 0); + + print_curses(F, f, sh, TYP_SHIP, 4); +} + +static void +report_building(FILE *F, const seen_region * sr, const building * b, const faction * f) +{ + region * r = sr->r; int i, bytes; - unit *u; const char * bname; const struct locale * lang = NULL; const building_type * type = b->type; @@ -1740,6 +1781,8 @@ report_building(FILE *F, const region * r, const building * b, const faction * f char buffer[8192], * bufp = buffer; size_t size = sizeof(buffer) - 1; + rnl(F); + if (!bt_illusion) bt_illusion = bt_find("illusion"); if (f) lang = f->locale; @@ -1770,7 +1813,7 @@ report_building(FILE *F, const region * r, const building * b, const faction * f if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); } - if (b->besieged > 0 && mode>=see_lighthouse) { + if (b->besieged > 0 && sr->mode>=see_lighthouse) { bytes = (int)strlcpy(bufp, ", belagert von ", size); if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); bytes = (int)strlcpy(bufp, itoa10(b->besieged), size); @@ -1852,21 +1895,9 @@ report_building(FILE *F, const region * r, const building * b, const faction * f *bufp = 0; rparagraph(F, buffer, 2, 0, 0); - if (modemodeunits; 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 @@ -1874,12 +1905,9 @@ report_plaintext(const char * filename, report_context * ctx, const char * chars { 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; @@ -1955,7 +1983,6 @@ report_plaintext(const char * filename, report_context * ctx, const char * chars } #endif - dh = 0; if (f->age <= 2) { const char * s; if (f->age <= 1) { @@ -2154,13 +2181,15 @@ report_plaintext(const char * filename, report_context * ctx, const char * chars for (;sr!=NULL;sr=sr->next) { region * r = sr->r; int stealthmod = stealth_modifier(sr->mode); + building * b = r->buildings; + ship * sh = r->ships; if (sr->modemode==see_unit) { anyunits = 1; - describe(F, r, 0, f); + describe(F, sr, f); if (!fval(r->terrain, SEA_REGION) && rpeasants(r)/TRADE_FRACTION > 0) { rnl(F); prices(F, r, f); @@ -2170,15 +2199,15 @@ report_plaintext(const char * filename, report_context * ctx, const char * chars } else { if (sr->mode==see_far) { - describe(F, r, 3, f); + describe(F, sr, f); guards(F, r, f); durchreisende(F, r, f); } else if (sr->mode==see_lighthouse) { - describe(F, r, 2, f); + describe(F, sr, f); durchreisende(F, r, f); } else { - describe(F, r, 1, f); + describe(F, sr, f); durchreisende(F, r, f); } } @@ -2194,106 +2223,43 @@ report_plaintext(const char * filename, report_context * ctx, const char * chars 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); - } + /* report all units. they are pre-sorted in an efficient manner */ + u = r->units; + while (b) { + while (b && (!u || u->building!=b)) { + report_building(F, sr, b, f); + b = b->next; + } + if (b) { + report_building(F, sr, b, f); + while (u && u->building==b) { + report_unit(F, f, u, 6, sr->mode); + u = u->next; } + b = b->next; } } - - /* 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; + while (u && !u->ship) { + if (stealthmod>INT_MIN) { + if (u->faction == f || cansee(f, r, u, stealthmod)) { + report_unit(F, f, u, 4, sr->mode); } } - - bufp = buf; - size = sizeof(buf) - 1; - if (of == f) { - int n = 0, p = 0; - getshipweight(sh, &n, &p); - n = (n+99) / 100; /* 1 Silber = 1 GE */ - - bytes = snprintf(bufp, size, "%s, %s, (%d/%d)", shipname(sh), - LOC(f->locale, sh->type->name[0]), n, shipcapacity(sh) / 100); - } else { - bytes = snprintf(bufp, size, "%s, %s", shipname(sh), LOC(f->locale, sh->type->name[0])); + u = u->next; + } + while (sh) { + while (sh && (!u || u->ship!=sh)) { + report_ship(F, sr, sh, f, NULL); + sh = sh->next; } - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - - assert(sh->type->construction->improvement==NULL); /* sonst ist construction::size nicht ship_type::maxsize */ - if (sh->size!=sh->type->construction->maxsize) { - bytes = snprintf(bufp, size, ", %s (%d/%d)", - LOC(f->locale, "nr_undercons"), sh->size, - sh->type->construction->maxsize); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - } - if (sh->damage) { - int percent = (sh->damage*100+DAMAGE_SCALE-1)/(sh->size*DAMAGE_SCALE); - bytes = snprintf(bufp, size, ", %d%% %s", percent, LOC(f->locale, "nr_damaged")); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - } - if (!fval(r->terrain, SEA_REGION)) { - if (sh->coast != NODIRECTION) { - bytes = (int)strlcpy(bufp, ", ", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - bytes = (int)strlcpy(bufp, LOC(f->locale, coasts[sh->coast]), size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - } - } - ch = 0; - if (sh->display && sh->display[0]) { - bytes = (int)strlcpy(bufp, "; ", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - bytes = (int)strlcpy(bufp, sh->display, size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - ch = sh->display[strlen(sh->display) - 1]; - } - if (ch != '!' && ch != '?' && ch != '.') { - bytes = (int)strlcpy(bufp, ".", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - } - *bufp = 0; - 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); + if (sh) { + report_ship(F, sr, sh, f, u); + while (u && u->ship==sh) { + report_unit(F, f, u, 6, sr->mode); + u = u->next; } + sh = sh->next; } } diff --git a/src/common/gamecode/xmlreport.c b/src/common/gamecode/xmlreport.c index fe6d2f9b1..80242d889 100644 --- a/src/common/gamecode/xmlreport.c +++ b/src/common/gamecode/xmlreport.c @@ -114,17 +114,116 @@ xml_i(double number) } static xmlNodePtr -report_unit(report_context * ctx, unit * u, int mode) +report_inventory(report_context * ctx, item * items, unit * u) +{ + xml_context* xct = (xml_context*)ctx->userdata; + xmlNodePtr node = xmlNewNode(xct->ns_atl, BAD_CAST "items"); + item * itm; + + for (itm=items;itm;itm=itm->next) { + xmlNodePtr child = xmlNewNode(xct->ns_atl, BAD_CAST "item"); + const char * name; + int n; + + report_item(u, itm, ctx->f, NULL, &name, &n, true); + xmlNewNsProp(child, xct->ns_atl, BAD_CAST "type", (xmlChar *)name); + xmlNodeAddContent(child, (xmlChar*)itoab(n, 10)); + xmlAddChild(node, child); + } + return node; +} + +static xmlNodePtr +xml_unit(report_context * ctx, unit * u, int mode) { xml_context* xct = (xml_context*)ctx->userdata; xmlNodePtr node = xmlNewNode(xct->ns_atl, BAD_CAST "unit"); - char unit_id[20]; + char idbuffer[20]; + static const curse_type * itemcloak_ct = 0; + static boolean init = false; + xmlNodePtr child; - sprintf(unit_id, "unit_%d", u->no); - xmlNewNsProp(node, xct->ns_xml, XML_XML_ID, (xmlChar *)unit_id); + snprintf(idbuffer, sizeof(idbuffer), "unit_%d", u->no); + xmlNewNsProp(node, xct->ns_xml, XML_XML_ID, (xmlChar *)idbuffer); xmlNewNsProp(node, xct->ns_atl, BAD_CAST "key", BAD_CAST itoa36(u->no)); xmlNewTextChild(node, xct->ns_atl, BAD_CAST "name", (const xmlChar *)u->name); + snprintf(idbuffer, sizeof(idbuffer), "faction_%d", u->faction->no); + child = xmlNewNode(xct->ns_atl, BAD_CAST "faction"); + xmlNewNsProp(child, xct->ns_atl, BAD_CAST "ref", (xmlChar *)idbuffer); + xmlAddChild(node, child); + + if (!init) { + init = true; + itemcloak_ct = ct_find("itemcloak"); + } + + if (u->items) { + item result[MAX_INVENTORY]; + item * show = NULL; + + if (ctx->f == u->faction || omniscient(ctx->f)) { + show = u->items; + } else { + boolean see_items = (mode >= see_unit); + if (see_items) { + if (itemcloak_ct && !curse_active(get_curse(u->attribs, itemcloak_ct))) { + see_items = false; + } else { + see_items = effskill(u, SK_STEALTH) < 3; + } + } + if (see_items) { + int n = report_items(u->items, result, MAX_INVENTORY, u, ctx->f); + assert(n>=0); + if (n>0) show = result; + else show = NULL; + } else { + show = NULL; + } + } + + if (show) { + xmlAddChild(node, report_inventory(ctx, show, u)); + } + } + + return node; +} + +static xmlNodePtr +report_link(report_context * ctx, const xmlChar * role, const xmlChar * ref) +{ + xml_context* xct = (xml_context*)ctx->userdata; + xmlNodePtr node = xmlNewNode(xct->ns_atl, BAD_CAST "link"); + + xmlNewNsProp(node, xct->ns_atl, BAD_CAST "role", role); + xmlNewNsProp(node, xct->ns_atl, BAD_CAST "ref", ref); + + return node; +} + +static xmlNodePtr +xml_resources(report_context * ctx, const seen_region * sr) +{ + xml_context* xct = (xml_context*)ctx->userdata; + xmlNodePtr node = xmlNewNode(xct->ns_atl, BAD_CAST "resources"); + resource_report result[MAX_RAWMATERIALS]; + int n, size = report_resources(sr, result, MAX_RAWMATERIALS, ctx->f); + + for (n=0;n=0) { + xmlNodePtr child = xmlNewNode(xct->ns_atl, BAD_CAST "resource"); + xmlNewNsProp(child, xct->ns_atl, BAD_CAST "type", (xmlChar*)result[n].name); + if (result[n].level>=0) { + xmlNewNsProp(child, xct->ns_atl, BAD_CAST "level", (xmlChar*)itoab(result[n].level, 10)); + } + xmlNodeAddContent(child, (xmlChar*)itoab(result[n].number, 10)); + + /* TODO: the visibility logic from creport */ + xmlAddChild(node, child); + } + } return node; } @@ -135,11 +234,15 @@ report_faction(report_context * ctx, faction * f) xmlNodePtr node = xmlNewNode(xct->ns_atl, BAD_CAST "faction"); char faction_id[20]; - sprintf(faction_id, "faction_%d", f->no); + snprintf(faction_id, sizeof(faction_id), "faction_%d", f->no); xmlNewNsProp(node, xct->ns_xml, XML_XML_ID, (xmlChar *)faction_id); xmlNewNsProp(node, xct->ns_atl, BAD_CAST "key", BAD_CAST itoa36(f->no)); xmlNewTextChild(node, xct->ns_atl, BAD_CAST "name", (const xmlChar *)f->name); + if (ctx->f==f) { + xmlAddChild(node, report_link(ctx, BAD_CAST "race", BAD_CAST f->race->_name[0])); + if (f->items) xmlAddChild(node, report_inventory(ctx, f->items, NULL)); + } return node; } @@ -165,16 +268,24 @@ report_region(report_context * ctx, seen_region * sr) } xmlAddChild(node, child); + child = xmlNewNode(xct->ns_atl, BAD_CAST "terrain"); + xmlNewNsProp(child, xct->ns_atl, BAD_CAST "ref", (xmlChar *)r->terrain->_name); + xmlAddChild(node, child); + if (r->land!=NULL) { child = xmlNewTextChild(node, xct->ns_atl, BAD_CAST "name", (const xmlChar *)r->land->name); + if (r->land->items) { + xmlAddChild(node, report_inventory(ctx, r->land->items, NULL)); + } } + xmlAddChild(node, xml_resources(ctx, sr)); child = xmlNewNode(xct->ns_atl, BAD_CAST "terrain"); xmlNewNsProp(child, xct->ns_atl, BAD_CAST "ref", (const xmlChar *)terrain_name(r)); for (u=r->units;u;u=u->next) { if (u->building || u->ship || (stealthmod>INT_MIN && cansee(ctx->f, r, u, stealthmod))) { - xmlAddChild(node, report_unit(ctx, u, sr->mode)); + xmlAddChild(node, xml_unit(ctx, u, sr->mode)); } } return node; @@ -219,6 +330,8 @@ report_xml(const char * filename, report_context * ctx, const char * encoding) xmlSaveFormatFileEnc(filename, doc, "utf-8", 1); xmlFreeDoc(doc); + ctx->userdata = NULL; + return 0; } diff --git a/src/common/kernel/eressea.c b/src/common/kernel/eressea.c index 3231fd6eb..cfa0c77ad 100644 --- a/src/common/kernel/eressea.c +++ b/src/common/kernel/eressea.c @@ -2484,7 +2484,7 @@ int besieged(const unit * u) { /* belagert kann man in schiffen und burgen werden */ - return (u + return (u && !global.disabled[K_BESIEGE] && u->building && u->building->besieged && u->building->besieged >= u->building->size * SIEGEFACTOR); } @@ -2775,95 +2775,105 @@ add_income(unit * u, int type, int want, int qty) } void -reorder_owners(region * r) +reorder_units(region * r) { - unit ** up=&r->units, ** useek; - building * b=NULL; - ship * sh=NULL; -#ifndef NDEBUG - size_t len = listlen(r->units); -#endif - for (b = r->buildings;b;b=b->next) { - unit ** ubegin = up; - unit ** uend = up; + unit ** unext = &r->units; - useek = up; - while (*useek) { - unit * u = *useek; - if (u->building==b) { - unit ** insert; - if (fval(u, UFL_OWNER)) { - unit * nu = *ubegin; - insert = ubegin; - if (nu!=u && nu->building==u->building && fval(nu, UFL_OWNER)) { - log_error(("[reorder_owners] %s hat mehrere Besitzer mit UFL_OWNER.\n", buildingname(nu->building))); - freset(nu, UFL_OWNER); + if (r->buildings) { + building * b = r->buildings; + while (*unext && b) { + unit ** ufirst = unext; /* where the first unit in the building should go */ + unit ** umove = unext; /* a unit we consider moving */ + unit * owner = NULL; + while (*umove) { + unit * u = *umove; + if (u->number && u->building==b) { + unit ** uinsert = unext; + if (fval(u, UFL_OWNER)) { + uinsert = ufirst; + owner = u; } - } - else insert = uend; - if (insert != useek) { - *useek = u->next; /* raus aus der liste */ - u->next = *insert; - *insert = u; - } - if (insert==uend) uend=&u->next; - } - if (*useek==u) useek = &u->next; - } - up = uend; - } - - useek=up; - while (*useek) { - unit * u = *useek; - assert(!u->building); - if (u->ship==NULL) { - if (fval(u, UFL_OWNER)) { - log_warning(("[reorder_owners] Einheit %s war Besitzer von nichts.\n", unitname(u))); - freset(u, UFL_OWNER); - } - if (useek!=up) { - *useek = u->next; /* raus aus der liste */ - u->next = *up; - *up = u; - } - up = &u->next; - } - if (*useek==u) useek = &u->next; - } - - for (sh = r->ships;sh;sh=sh->next) { - unit ** ubegin = up; - unit ** uend = up; - - useek = up; - while (*useek) { - unit * u = *useek; - if (u->ship==sh) { - unit ** insert; - if (fval(u, UFL_OWNER)) { - unit * nu = *ubegin; - insert = ubegin; - if (nu!=u && nu->ship==u->ship && fval(nu, UFL_OWNER)) { - log_error(("[reorder_owners] %s hat mehrere Besitzer mit UFL_OWNER.\n", shipname(nu->ship))); - freset(nu, UFL_OWNER); + if (umove!=uinsert) { + *umove = u->next; + u->next = *uinsert; + *uinsert = u; + } else { + /* no need to move, skip ahead */ + umove = &u->next; } + if (unext==uinsert) { + /* we have a new well-placed unit. jump over it */ + unext = &u->next; + } + } else { + umove = &u->next; } - else insert = uend; - if (insert!=useek) { - *useek = u->next; /* raus aus der liste */ - u->next = *insert; - *insert = u; - } - if (insert==uend) uend=&u->next; } - if (*useek==u) useek = &u->next; + if (!owner && ufirst!=unext) { + owner = *ufirst; + fset(owner, UFL_OWNER); + } + b = b->next; + } + } + + if (r->ships) { + ship * sh = r->ships; + /* first, move all units up that are not on ships */ + unit ** umove = unext; /* a unit we consider moving */ + while (*umove) { + unit * u = *umove; + if (u->number && !u->ship) { + if (umove!=unext) { + *umove = u->next; + u->next = *unext; + *unext = u; + } else { + /* no need to move, skip ahead */ + umove = &u->next; + } + /* we have a new well-placed unit. jump over it */ + unext = &u->next; + } else { + umove = &u->next; + } + } + + while (*unext && sh) { + unit ** ufirst = unext; /* where the first unit in the building should go */ + unit ** umove = unext; /* a unit we consider moving */ + unit * owner = NULL; + while (*umove) { + unit * u = *umove; + if (u->number && u->ship==sh) { + unit ** uinsert = unext; + if (fval(u, UFL_OWNER)) { + uinsert = ufirst; + owner = u; + } + if (umove!=uinsert) { + *umove = u->next; + u->next = *uinsert; + *uinsert = u; + } else { + /* no need to move, skip ahead */ + umove = &u->next; + } + if (unext==uinsert) { + /* we have a new well-placed unit. jump over it */ + unext = &u->next; + } + } else { + umove = &u->next; + } + } + if (!owner && ufirst!=unext) { + owner = *ufirst; + fset(owner, UFL_OWNER); + } + sh = sh->next; } - up = uend; } -#ifndef NDEBUG - assert(len==listlen(r->units)); -#endif } int diff --git a/src/common/kernel/eressea.h b/src/common/kernel/eressea.h index 8d9265a50..3d23b9dac 100644 --- a/src/common/kernel/eressea.h +++ b/src/common/kernel/eressea.h @@ -355,7 +355,7 @@ extern const char * resourcepath(void); extern void kernel_init(void); extern void kernel_done(void); -extern void reorder_owners(struct region * r); +extern void reorder_units(struct region * r); extern const char *localenames[]; diff --git a/src/common/kernel/item.c b/src/common/kernel/item.c index 67d2c2ef3..b05708667 100644 --- a/src/common/kernel/item.c +++ b/src/common/kernel/item.c @@ -203,9 +203,9 @@ new_itemtype(resource_type * rtype, int iflags, int weight, int capacity) { item_type * itype; - assert (resource2item(rtype) == NULL); - + assert(resource2item(rtype) == NULL); assert(rtype->flags & RTF_ITEM); + itype = calloc(sizeof(item_type), 1); itype->rtype = rtype; diff --git a/src/common/kernel/reports.c b/src/common/kernel/reports.c index da007047b..3d42a66e9 100644 --- a/src/common/kernel/reports.c +++ b/src/common/kernel/reports.c @@ -37,6 +37,7 @@ #include #include #include +#include #include #include #include @@ -146,12 +147,12 @@ hp_status(const unit * u) void report_item(const unit * owner, const item * i, const faction * viewer, const char ** name, const char ** basename, int * number, boolean singular) { - assert(owner->number); - if (owner->faction == viewer) { + assert(!owner || owner->number); + if (owner && owner->faction == viewer) { if (name) *name = locale_string(viewer->locale, resourcename(i->type->rtype, ((i->number!=1 && !singular)?GR_PLURAL:0))); if (basename) *basename = resourcename(i->type->rtype, 0); if (number) *number = i->number; - } else if (i->type->rtype==r_silver) { + } else if (owner && i->type->rtype==r_silver) { int pp = i->number/owner->number; if (number) *number = 1; if (pp > 50000 && dragonrace(owner->race)) { @@ -240,6 +241,132 @@ buforder(char * bufp, size_t size, const order * ord, int mode) return tsize; } +/** create a report of a list of items to a non-owner. + * \param result: an array of size items. + * \param size: maximum number of items to return + * \param owner: the owner of the items, or NULL for faction::items etc. + * \param viewer: the faction looking at the items + */ +int +report_items(const item * items, item * result, int size, const unit * owner, const faction * viewer) +{ + const item * itm; + int n = 0; /* number of results */ + + assert(owner==NULL || viewer!=owner->faction || !"not required for owner=viewer!"); + assert(size); + + for (itm=items;itm;itm=itm->next) { + item * ishow; + const char * ic; + + report_item(owner, itm, viewer, NULL, &ic, NULL, false); + if (ic && *ic) { + for (ishow = result; ishow!=result+n; ishow=ishow->next) { + const char * sc; + + if (ishow->type==itm->type) sc = ic; + else report_item(owner, ishow, viewer, NULL, &sc, NULL, false); + if (sc==ic || strcmp(sc, ic)==0) { + ishow->number+=itm->number; + break; + } + } + if (ishow==result+n) { + if (n==size) { + return -1; + } + result[n].number = itm->number; + result[n].type = itm->type; + result[n].next = (n+1==size)?NULL:result+n+1; + ++n; + } + } + } + if (n>0) result[n-1].next = NULL; + return n; +} + +static void +report_resource(resource_report * result, const char * name, int number, int level) +{ + result->name = name; + result->number = number; + result->level = level; +} + +int +report_resources(const seen_region * sr, resource_report * result, int size, const faction * viewer) +{ + const region * r = sr->r; + int n = 0; + + if (r->land) { + int peasants = rpeasants(r); + int horses = rhorses(r); + int trees = rtrees(r, 2); + int saplings = rtrees(r, 1); + boolean mallorn = fval(r, RF_MALLORN)!=0; + + if (peasants) { + if (n>=size) return -1; + report_resource(result+n, "rm_peasant", peasants, -1); + ++n; + } + if (horses) { + if (n>=size) return -1; + report_resource(result+n, "rm_horse", horses, -1); + ++n; + } + if (saplings) { + if (n>=size) return -1; + report_resource(result+n, mallorn?"rm_mallornsapling":"rm_sapling", saplings, -1); + ++n; + } + if (trees) { + if (n>=size) return -1; + report_resource(result+n, mallorn?"rm_mallorn":"rm_tree", trees, -1); + ++n; + } + } + + if (sr->mode>=see_unit) { + rawmaterial * res = r->resources; + while (res) { + int maxskill = 0; + int level = -1; + int visible = -1; + 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 == viewer) { + int s = eff_skill(u, itype->construction->skill, r); + if (s>maxskill) { + if (s>=itype->construction->minskill) { + assert(itype->construction->minskill>0); + level = res->level + itype->construction->minskill - 1; + } + maxskill = s; + visible = res->type->visible(res, maxskill); + } + } + } + } + if (level>=0 && visible>=0) { + if (n>=size) return -1; + report_resource(result+n, res->type->name, visible, level); + n++; + } + res = res->next; + } + } + return n; +} + int bufunit(const faction * f, const unit * u, int indent, int mode, char * buf, size_t size) { @@ -258,6 +385,7 @@ bufunit(const faction * f, const unit * u, int indent, int mode, char * buf, siz static const curse_type * itemcloak_ct = 0; static boolean init = false; int bytes; + item result[MAX_INVENTORY]; if (!init) { init = true; @@ -425,28 +553,10 @@ bufunit(const faction * f, const unit * u, int indent, int mode, char * buf, siz } else if (!itemcloak && mode >= see_unit && !(a_fshidden && a_fshidden->data.ca[1] == 1 && effskill(u, SK_STEALTH) >= 3)) { - show = NULL; - for (itm=u->items;itm;itm=itm->next) { - item * ishow; - const char * ic; - int in; - report_item(u, itm, f, NULL, &ic, &in, false); - if (ic && *ic && in>0) { - for (ishow = show; ishow; ishow=ishow->next) { - const char * sc; - int sn; - if (ishow->type==itm->type) sc=ic; - else report_item(u, ishow, f, NULL, &sc, &sn, false); - if (sc==ic || strcmp(sc, ic)==0) { - ishow->number+=itm->number; - break; - } - } - if (ishow==NULL) { - ishow = i_add(&show, i_new(itm->type, itm->number)); - } - } - } + int n = report_items(u->items, result, MAX_INVENTORY, u, f); + assert(n>=0); + if (n>0) show = result; + else show = NULL; } else { show = NULL; } @@ -470,7 +580,6 @@ bufunit(const faction * f, const unit * u, int indent, int mode, char * buf, siz } if (bytes<0 || wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); } - if (show!=u->items) while (show) i_free(i_remove(&show, show)); if (u->faction == f || telepath_see) { sc_mage * m = get_mage(u); diff --git a/src/common/kernel/reports.h b/src/common/kernel/reports.h index e8c4f1e4b..539210a60 100644 --- a/src/common/kernel/reports.h +++ b/src/common/kernel/reports.h @@ -95,9 +95,8 @@ typedef struct report_context { typedef int (*report_fun)(const char * filename, report_context * ctx, const char * charset); extern void register_reporttype(const char * extension, report_fun write, int flag); - -extern void report_item(const struct unit * owner, const struct item * i, const struct faction * viewer, const char ** name, const char ** basename, int * number, boolean singular); -extern void report_building(FILE *F, const struct region * r, const struct building * b, const struct faction * f, int mode); + + extern int bufunit(const struct faction * f, const struct unit * u, int indent, int mode, char * buf, size_t size); extern const char * reportpath(void); @@ -116,9 +115,20 @@ extern const char * report_kampfstatus(const struct unit * u, const struct local struct region ** regions; } arg_regions; + typedef struct resource_report { + const char * name; + int number; + int level; + } resource_report; + int report_resources(const struct seen_region * sr, struct resource_report * result, int size, const struct faction * viewer); + int report_items(const struct item * items, struct item * result, int size, const struct unit * owner, const struct faction * viewer); + void report_item(const struct unit * owner, const struct item * i, const struct faction * viewer, const char ** name, const char ** basename, int * number, boolean singular); + extern size_t f_regionid(const struct region * r, const struct faction * f, char * buffer, size_t size); #define GR_PLURAL 0x01 /* grammar: plural */ +#define MAX_INVENTORY 64 /* maimum number of different items in an inventory */ +#define MAX_RAWMATERIALS 8 /* maximum kinds of raw materials in a regions */ #ifdef __cplusplus } diff --git a/src/eressea/korrektur.c b/src/eressea/korrektur.c index d365a24c3..c486e9d17 100644 --- a/src/eressea/korrektur.c +++ b/src/eressea/korrektur.c @@ -88,8 +88,6 @@ #undef XMAS2001 #undef XMAS2002 -extern void reorder_owners(struct region * r); - static int curse_emptiness(void) { @@ -164,7 +162,7 @@ verify_owners(boolean bOnce) } } } - if (bFail) reorder_owners(r); + if (bFail) reorder_units(r); } } diff --git a/src/eressea/lua/ship.cpp b/src/eressea/lua/ship.cpp index 86f4d8800..8d326ad63 100644 --- a/src/eressea/lua/ship.cpp +++ b/src/eressea/lua/ship.cpp @@ -45,7 +45,7 @@ operator==(const ship& a, const ship& sh) } static ship * -add_ship(const char * sname, region& r) +add_ship(region& r, const char * sname) { const ship_type * stype = st_find(sname); ship * sh = new_ship(stype, NULL, &r); diff --git a/src/eressea/lua/test.cpp b/src/eressea/lua/test.cpp index 08c25a4a2..acc080fa3 100644 --- a/src/eressea/lua/test.cpp +++ b/src/eressea/lua/test.cpp @@ -21,6 +21,7 @@ using namespace luabind; #include #include #include +#include static const char * loc_getskill(const char * loc, const char * locstring) @@ -46,6 +47,7 @@ bind_test(lua_State * L) module(L, "test")[ def("loc_skill", &loc_getskill), def("loc_keyword", &loc_getkeyword), + def("reorder_units", &reorder_units), def("rng_int", &rng_int) ]; }