server/src/common/gamecode/creport.c
Enno Rehling 1e51d0e9e2 - Neue Messages fertig
Messages werden jetzt in einem anderen Meta-Format (message* of 
  message_type*) gespeichert, das man in beliebige Formate (CR oder NR) 
  rendern kann. crmessage.c und nrmessage.c sind die render-engines dafür.
  Die Messagetypen werden in res/{de,en}/messages.xml gesammelt, ultimativ
  kann das aber durchaus eine einzelne Datei sein. Die ist derzeit nicht 
  wirklich xml (Umlaute drin, keine Definitionsdatei), aber gut lesbar.

- make_message
  Diese Funktion ersetzt new_message, und ist etwas einfacher in der Syntax:
  make_message("dumb_mistake", "unit region command", u, r, cmd) erzeugt
  eine neue Nachricht, die dann einfach mit add_message wie bisher an die
  Nachrichtenliste gehängt werden kann.
  TODO: Messages könnte man durchaus reference-counten, und in mehrere Listen
  einfügen, solang sie a) mehrfachverwendet (Kampf!) und b) vom Betrachter
  unabhängig sind. Das spart einigen Speicher.

- CR Version erhöht.
  Weil die MESSAGETYPES Blocks anders sind als früher

- OFFENSIVE_DELAY
  Verbietet Einheiten, deren Partei eine Reigon niht bewachen, den 
  Angriff in der Region, wenn sie sich in der Runde zuvor bewegt haben.
  Status der letzten Runde wird in neuem Attribut at_moved gespeichert.

- SHORT_ATTACKS
  ein define, das angibt ob Kämpfen grundsätzlich keine lange Aktion ist.

- XML Parser
  xml.[hc] enthält einen XML-Parser, dem man ein plugin mit callbacks
  übergibt, die nach dem Parsen eines tokens aufgerufen werden.
2001-04-12 17:21:57 +00:00

1001 lines
26 KiB
C
Raw Blame History

/* 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)
*
* This program may not be used, modified or distributed without
* prior permission by the authors of Eressea.
*/
#include <config.h>
#include <eressea.h>
#include "creport.h"
/* tweakable features */
#define ENCODE_SPECIAL 1
#define RENDER_CRMESSAGES 1
/* modules include */
#include <modules/score.h>
/* attributes include */
#include <attributes/follow.h>
#include <attributes/racename.h>
/* gamecode includes */
#include "laws.h"
#include "economy.h"
/* kernel includes */
#include <alchemy.h>
#include <border.h>
#include <building.h>
#include <faction.h>
#include <group.h>
#include <item.h>
#include <karma.h>
#include <magic.h>
#include <message.h>
#include <movement.h>
#include <plane.h>
#include <race.h>
#include <region.h>
#include <reports.h>
#include <ship.h>
#include <skill.h>
#include <teleport.h>
#include <unit.h>
#include <save.h>
/* util includes */
#include <util/message.h>
#include <goodies.h>
#include <crmessage.h>
#include <nrmessage.h>
/* libc includes */
#include <math.h>
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
#include <string.h>
/* imports */
extern const char *directions[];
extern const char *spelldata[];
extern int quiet;
/* globals */
#define C_REPORT_VERSION 57
/* implementation */
void
cr_output_str_list(FILE * F, const char *title, const strlist * S, faction * f)
{
char *s;
if (!S) return;
fprintf(F, "%s\n", title);
while (S) {
s = replace_global_coords(S->s, f);
fprintf(F, "\"%s\"\n", s);
S = S->next;
}
}
#include "objtypes.h"
static void
print_curses(FILE * F, void * obj, typ_t typ, attrib *a, int self)
{
boolean header = false;
while (a) {
int dh = 0;
curse *c;
if (fval(a->type, ATF_CURSE)) {
c = (curse *)a->data.v;
if (c->type->curseinfo)
dh = c->type->curseinfo(obj, typ, c, self);
if (dh == 1) {
if (!header) {
header = 1;
fputs("EFFECTS\n", F);
}
fprintf(F, "\"%s\"\n", buf);
}
} else if (a->type==&at_effect && self) {
effect_data * data = (effect_data *)a->data.v;
if (!header) {
header = 1;
fputs("EFFECTS\n", F);
}
fprintf(F, "\"%d %s\"\n", data->value, locale_string(NULL, resourcename(data->type->itype->rtype, 0)));
}
a = a->next;
}
}
static int
cr_unit(const void * v, char * buffer, const void * userdata)
{
const faction * report = (const faction*)userdata;
unit * u = (unit *)v;
sprintf(buffer, "%d", u?u->no:-1);
unused(report);
return 0;
}
static int
cr_ship(const void * v, char * buffer, const void * userdata)
{
const faction * report = (const faction*)userdata;
ship * u = (ship *)v;
sprintf(buffer, "%d", u?u->no:-1);
unused(report);
return 0;
}
static int
cr_building(const void * v, char * buffer, const void * userdata)
{
const faction * report = (const faction*)userdata;
building * u = (building *)v;
sprintf(buffer, "%d", u?u->no:-1);
unused(report);
return 0;
}
static int
cr_faction(const void * v, char * buffer, const void * userdata)
{
const faction * report = (const faction*)userdata;
faction * f = (faction *)v;
sprintf(buffer, "%d", f?f->no:-1);
unused(report);
return 0;
}
static int
cr_region(const void * v, char * buffer, const void * userdata)
{
const faction * report = (const faction*)userdata;
region * r = (region *)v;
if (r) {
plane * p = rplane(r);
if (!p || !(p->flags & PFL_NOCOORDS)) {
sprintf(buffer, "%d %d %d", region_x(r, report), region_y(r, report), p?p->id:0);
return 0;
}
}
return -1;
}
static int
cr_resource(const void * v, char * buffer, const void * userdata)
{
const faction * report = (const faction*)userdata;
const resource_type * r = (const resource_type *)v;
if (r) {
sprintf(buffer, "\"%s\"", locale_string(report->locale, resourcename(r, 0)));
return 0;
}
return -1;
}
static int
cr_skill(const void * v, char * buffer, const void * userdata)
{
const faction * report = (const faction*)userdata;
skill_t sk = (skill_t)v;
if (sk!=NOSKILL) sprintf(buffer, "\"%s\"", locale_string(report->locale, skillnames[sk]));
else strcpy(buffer, "\"\"");
return 0;
}
void
creport_init(void)
{
tsf_register("report", &cr_ignore);
tsf_register("string", &cr_string);
tsf_register("int", &cr_int);
tsf_register("unit", &cr_unit);
tsf_register("region", &cr_region);
tsf_register("faction", &cr_faction);
tsf_register("ship", &cr_ship);
tsf_register("building", &cr_building);
tsf_register("skill", &cr_skill);
tsf_register("resource", &cr_resource);
}
void
creport_cleanup(void)
{
}
static int msgno;
#define MTMAXHASH 1023
static struct known_mtype {
const struct message_type * mtype;
struct known_mtype * nexthash;
} * mtypehash[MTMAXHASH];
static void
report_crtypes(FILE * F, const struct locale* lang)
{
int i;
fputs("MESSAGETYPES\n", F);
for (i=0;i!=MTMAXHASH;++i) {
struct known_mtype * kmt;
for (kmt=mtypehash[i];kmt;kmt=kmt->nexthash) {
const struct nrmessage_type * nrt = nrt_find(lang, kmt->mtype);
if (nrt) {
unsigned int hash = hashstring(mt_name(kmt->mtype));
fputc('\"', F);
fputs(escape_string(nrt_string(nrt), NULL, 0), F);
fprintf(F, "\";%d\n", hash);
}
}
while (mtypehash[i]) {
kmt = mtypehash[i];
mtypehash[i] = mtypehash[i]->nexthash;
free(kmt);
}
}
}
static void
render_messages(FILE * F, faction * f, message_list *msgs)
{
struct mlist* m = msgs->begin;
while (m) {
char crbuffer[1024];
boolean printed = false;
const struct message_type * mtype = m->msg->type;
unsigned int hash = hashstring(mtype->name);
#if RENDER_CRMESSAGES
char nrbuffer[4096];
nrbuffer[0] = '\0';
if (nr_render(m->msg, f->locale, nrbuffer, f)==0 && nrbuffer[0]) {
fprintf(F, "MESSAGE %d\n", ++msgno);
fprintf(F, "%d;type\n", hash);
fputs("\"", F);
fputs(nrbuffer, F);
fputs("\";rendered\n", F);
printed = true;
}
#endif
crbuffer[0] = '\0';
if (cr_render(m->msg, crbuffer, (const void*)f)==0 && crbuffer[0]) {
if (!printed) fprintf(F, "MESSAGE %d\n", ++msgno);
fputs(crbuffer, F);
}
else log_error(("could not render cr-message %p\n", m->msg));
if (printed) {
unsigned int ihash = hash % MTMAXHASH;
struct known_mtype * kmt = mtypehash[ihash];
while (kmt && kmt->mtype != mtype) kmt = kmt->nexthash;
if (kmt==NULL) {
kmt = (struct known_mtype*)malloc(sizeof(struct known_mtype));
kmt->nexthash = mtypehash[ihash];
kmt->mtype = mtype;
mtypehash[ihash] = kmt;
}
}
m = m->next;
}
}
static void
cr_output_messages(FILE * F, message_list *msgs, faction * f)
{
if (msgs) render_messages(F, f, msgs);
}
/* prints a building */
static void
cr_output_buildings(FILE * F, building * b, unit * u, int fno, faction *f)
{
const building_type * type = b->type;
unit * bo = buildingowner(b->region, b);
assert(b);
fprintf(F, "BURG %d\n", b->no);
if (!u || u->faction != f) {
const attrib * a = a_find(b->attribs, &at_icastle);
if (a) type = ((icastle_data*)a->data.v)->type;
}
fprintf(F, "\"%s\";Typ\n", buildingtype(b, b->size, f->locale));
fprintf(F, "\"%s\";Name\n", b->name);
if (strlen(b->display))
fprintf(F, "\"%s\";Beschr\n", b->display);
if (b->size)
fprintf(F, "%d;Groesse\n", b->size);
if (u)
fprintf(F, "%d;Besitzer\n", u ? u->no : -1);
if (fno >= 0)
fprintf(F, "%d;Partei\n", fno);
#ifdef TODO
int cost = buildingdaten[b->type].per_size * b->size + buildingdaten[b->type].unterhalt;
if (u && u->faction == f && cost)
fprintf(F, "%d;Unterhalt\n", cost);
#endif
if (b->besieged)
fprintf(F, "%d;Belagerer\n", b->besieged);
if(bo != NULL){
print_curses(F, b, TYP_BUILDING, b->attribs,
(bo->faction == f)? 1 : 0);
} else {
print_curses(F, b, TYP_BUILDING, b->attribs, 0);
}
}
/* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
/* prints a ship */
static void
cr_output_ship(FILE * F, ship * s, unit * u, int fcaptain, faction * f, region * r)
{
unit *u2;
int w = 0;
assert(s);
fprintf(F, "SCHIFF %d\n", s->no);
fprintf(F, "\"%s\";Name\n", s->name);
if (strlen(s->display))
fprintf(F, "\"%s\";Beschr\n", s->display);
fprintf(F, "\"%s\";Typ\n", s->type->name[0]);
fprintf(F, "%d;Groesse\n", s->size);
if (s->damage) {
int percent = s->damage*100/(s->size*DAMAGE_SCALE);
fprintf(F, "%d;Schaden\n", percent);
}
if (u)
fprintf(F, "%d;Kapitaen\n", u ? u->no : -1);
if (fcaptain >= 0)
fprintf(F, "%d;Partei\n", fcaptain);
/* calculate cargo */
if (u && (u->faction == f || omniscient(f))) {
for (u2 = r->units; u2; u2 = u2->next)
if (u2->ship == s)
w += weight(u2);
fprintf(F, "%d;Ladung\n", (w + 99) / 100);
fprintf(F, "%d;MaxLadung\n", shipcapacity(s) / 100);
}
/* shore */
w = NODIRECTION;
if (rterrain(r) != T_OCEAN) w = s->coast;
if (w != NODIRECTION)
fprintf(F, "%d;Kueste\n", w);
if(shipowner(r, s) != NULL){
print_curses(F, s, TYP_SHIP, s->attribs,
(shipowner(r, s)->faction == f)? 1 : 0);
} else {
print_curses(F, s, TYP_SHIP, s->attribs, 0);
}
}
/* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
/* prints all that belongs to a unit */
static void
cr_output_unit(FILE * F, region * r,
faction * f, /* observers faction */
unit * u, int mode)
{
/* Race attributes are always plural and item attributes always
* singular */
const item_type * lasttype;
int pr;
item *itm, *show;
boolean itemcloak = is_cursed(u->attribs, C_ITEMCLOAK, 0);
building * b;
const char * pzTmp;
skill_t sk;
strlist *S;
const attrib *a_fshidden = NULL;
assert(u);
if(fspecial(u->faction, FS_HIDDEN))
a_fshidden = a_find(u->attribs, &at_fshidden);
fprintf(F, "EINHEIT %d\n", u->no);
fprintf(F, "\"%s\";Name\n", u->name);
if (strlen(u->display))
fprintf(F, "\"%s\";Beschr\n", u->display);
if ((u->faction == f || omniscient(f)) || !fval(u, FL_PARTEITARNUNG)) {
#ifdef GROUPS
if (u->faction == f) {
const attrib * a = a_find(u->attribs, &at_group);
if (a) {
const group * g = (const group*)a->data.v;
fprintf(F, "%d;gruppe\n", g->gid);
}
}
#endif
fprintf(F, "%d;Partei\n", u->faction->no);
}
if(u->faction != f && a_fshidden
&& a_fshidden->data.ca[0] == 1 && effskill(u, SK_STEALTH) >= 6) {
fprintf(F, "-1;Anzahl\n");
} else {
fprintf(F, "%d;Anzahl\n", u->number);
}
pzTmp = get_racename(u->attribs);
if (pzTmp==NULL) fprintf(F, "\"%s\";Typ\n", race[u->irace].name[1]);
else fprintf(F, "\"%s\";Typ\n", pzTmp);
if ((pzTmp || u->irace != u->race) && u->faction==f) {
fprintf(F, "\"%s\";wahrerTyp\n", race[u->race].name[1]);
}
if (u->building)
fprintf(F, "%d;Burg\n", u->building->no);
if (u->ship)
fprintf(F, "%d;Schiff\n", u->ship->no);
if (getguard(u))
fprintf(F, "%d;bewacht\n", getguard(u)?1:0);
if ((b=usiege(u))!=NULL)
fprintf(F, "%d;belagert\n", b->no);
if (fval(u, FL_PARTEITARNUNG))
fprintf(F, "%d;Parteitarnung\n", fval(u, FL_PARTEITARNUNG));
/* additional information for own units */
if (u->faction == f || omniscient(f)) {
const char *c;
int i;
const attrib * a;
a = a_find(u->attribs, &at_follow);
if (a) {
unit * u = (unit*)a->data.v;
if (u) fprintf(F, "%d;folgt\n", u->no);
}
i = ualias(u);
if (i>0)
fprintf(F, "%d;temp\n", i);
else if (i<0)
fprintf(F, "%d;alias\n", -i);
i = get_money(u);
if (u->status)
fprintf(F, "%d;Kampfstatus\n", u->status);
i = u_geteffstealth(u);
if (i >= 0)
fprintf(F, "%d;Tarnung\n", i);
c = uprivate(u);
if (c)
fprintf(F, "\"%s\";privat\n", c);
c = hp_status(u);
if (c && *c && (u->faction == f || omniscient(f)))
fprintf(F, "\"%s\";hp\n", c);
if (fval(u, FL_HUNGER) && (u->faction == f))
fputs("1;hunger\n", F);
if (is_mage(u)) {
fprintf(F, "%d;Aura\n", get_spellpoints(u));
fprintf(F, "%d;Auramax\n", max_spellpoints(u->region,u));
}
/* default commands */
fprintf(F, "COMMANDS\n");
if(u->lastorder[0]) fprintf(F, "\"%s\"\n", u->lastorder);
for (S = u->orders; S; S = S->next) {
if(is_persistent(S->s)) {
fprintf(F, "\"%s\"\n", S->s);
}
}
/* talents */
pr = 0;
for (sk = 0; sk != MAXSKILLS; ++sk)
if (get_skill(u, sk)) {
if (!pr) {
pr = 1;
fprintf(F, "TALENTE\n");
}
#ifdef NOVISIBLESKILLPOINTS
/* 0 ist nur der Kompatibilit<69>t wegen drin, rausnehmen */
fprintf(F, "0 %d;%s\n", eff_skill(u, sk, r), skillnames[sk]);
#else
fprintf(F, "%d %d;%s\n", get_skill(u, sk), eff_skill(u, sk, r), skillnames[sk]);
#endif
}
/* spells */
if (is_mage(u)) {
sc_mage * mage = get_mage(u);
spell_ptr *spt = mage->spellptr;
if (spt) {
spell *sp;
int i;
fprintf(F, "SPRUECHE\n");
for (;spt; spt = spt->next) {
sp = find_spellbyid(spt->spellid);
fprintf(F, "\"%s\"\n", sp->name);
}
for (i=0;i!=MAXCOMBATSPELLS;++i) {
sp = find_spellbyid(mage->combatspell[i]);
if (sp) {
fprintf(F, "KAMPFZAUBER %d\n", i);
fprintf(F, "\"%s\";name\n", sp->name);
fprintf(F, "%d;level\n", mage->combatspelllevel[i]);
}
}
}
}
}
/* items */
pr = 0;
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));
ishow->number = itm->number;
}
}
}
} else {
show = NULL;
}
lasttype = NULL;
for (itm=show; itm; itm=itm->next) {
const char * ic;
int in;
assert(itm->type!=lasttype || !"error: list contains two objects of the same item");
report_item(u, itm, f, NULL, &ic, &in, true);
if (in==0) continue;
if (!pr) {
pr = 1;
fputs("GEGENSTAENDE\n", F);
}
fprintf(F, "%d;%s\n", in, locale_string(NULL, ic));
}
if ((u->faction == f || omniscient(f)) && u->botschaften)
cr_output_str_list(F, "EINHEITSBOTSCHAFTEN", u->botschaften, f);
print_curses(F, u, TYP_UNIT, u->attribs, (u->faction == f)? 1 : 0);
}
/* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
/* prints allies */
static void
show_allies(FILE * F, ally * sf)
{
for (; sf; sf = sf->next) if(sf->faction) {
fprintf(F, "ALLIANZ %d\n", sf->faction->no);
fprintf(F, "\"%s\";Parteiname\n", sf->faction->name);
fprintf(F, "%d;Status\n", sf->status);
}
}
/* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
/* prints all visible spells in a region */
static void
show_active_spells(region * r)
{
char fogwall[MAXDIRECTIONS];
#ifdef TODO /* alte Regionszauberanzeigen umstellen */
unit *u;
int env = 0;
#endif
memset(fogwall, 0, sizeof(char) * MAXDIRECTIONS);
}
/* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
extern int fcompare(const void *a, const void *b);
/* this is a copy of laws.c->find_address output changed. */
static void
cr_find_address(FILE * F, faction * uf)
{
faction *f;
void **fp;
cvector *fcts = malloc(sizeof(cvector));
cv_init(fcts);
for (f = factions; f; f = f->next) {
if (f->no != 0 && kann_finden(uf, f) != 0) {
cv_pushback(fcts, f);
}
}
v_sort(fcts->begin, fcts->end, fcompare);
/* FIND orders - diese duerfen erst ablaufen, nachdem alle ihre Adresse
* gesetzt haben! */
if (!quiet)
puts(" - gebe Adressen heraus (CR)");
for (fp = fcts->begin; fp != fcts->end; ++fp) {
f = *fp;
if (uf!=f && f->no != 0 && kann_finden(uf, f) != 0) {
fprintf(F, "PARTEI %d\n", f->no);
fprintf(F, "\"%s\";Parteiname\n", f->name);
fprintf(F, "\"%s\";email\n", f->email);
fprintf(F, "\"%s\";banner\n", f->banner);
}
}
free(cv_kill(fcts));
}
/* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
static void
cr_reportspell(FILE * F, spellid_t id)
{
int k, itemanz, res, costtyp;
spell *sp = find_spellbyid(id);
fprintf(F, "ZAUBER %d\n", hashstring(sp->name));
fprintf(F, "\"%s\";name\n", sp->name);
fprintf(F, "%d;level\n", sp->level);
fprintf(F, "%d;rank\n", sp->rank);
fprintf(F, "\"%s\";info\n", sp->beschreibung);
if (sp->sptyp & PRECOMBATSPELL) fputs("\"precombat\";class\n", F);
else if (sp->sptyp & COMBATSPELL) fputs("\"combat\";class\n", F);
else if (sp->sptyp & POSTCOMBATSPELL) fputs("\"postcombat\";class\n", F);
else fputs("\"normal\";class\n", F);
if (sp->sptyp & FARCASTING) fputs("1;far\n", F);
if (sp->sptyp & OCEANCASTABLE) fputs("1;ocean\n", F);
if (sp->sptyp & ONSHIPCAST) fputs("1;ship\n", F);
if (!(sp->sptyp & NOTFAMILIARCAST)) fputs("1;familiar\n", F);
fputs("KOMPONENTEN\n", F);
for (k = 0; k < MAXINGREDIENT; k++) {
res = sp->komponenten[k][0];
itemanz = sp->komponenten[k][1];
costtyp = sp->komponenten[k][2];
if(itemanz > 0) {
fprintf(F, "%d %d;%s\n", itemanz, costtyp == SPC_LEVEL || costtyp == SPC_LINEAR, resname(res, 0));
}
}
}
static unsigned int
encode_region(faction * f, region * r) {
unsigned int id;
char *cp, c;
/* obfuscation */
assert(sizeof(int)==sizeof(char)*4);
id = (((((r->x ^ f->no) % 1024) << 20) | ((r->y ^ f->no) % 1024)));
cp = (char*)&id;
c = cp[0];
cp[0] = cp[2];
cp[2] = cp[1];
cp[1] = cp[3];
cp[3] = c;
return id;
}
/* main function of the creport. creates the header and traverses all regions */
void
report_computer(FILE * F, faction * f)
{
int i;
region *r;
building *b;
ship *sh;
unit *u;
seen_region * sd;
const attrib * a;
int maxmining;
/* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
/* initialisations, header and lists */
if (quiet) {
printf(" CR");
fflush(stdout);
}
else printf(" - schreibe Computerreport\n");
fprintf(F, "VERSION %d\n", C_REPORT_VERSION);
fprintf(F, "\"%s\";Spiel\n", global.gamename);
fprintf(F, "\"%s\";Konfiguration\n", "Standard");
fprintf(F, "\"%s\";Koordinaten\n", "Hex");
fprintf(F, "%d;Basis\n", 36);
fprintf(F, "%d;Umlaute\n", 1);
fprintf(F, "%d;Runde\n", turn);
fputs("2;Zeitalter\n", F);
fprintf(F, "PARTEI %d\n", f->no);
/* fprintf(F, "\"%s\";Passwort\n", f->passw); */
fprintf(F, "\"%s\";locale\n", locale_name(f->locale));
fprintf(F, "%d;Optionen\n", f->options);
if (f->options & want(O_SCORE) && f->age>DISPLAYSCORE) {
fprintf(F, "%d;Punkte\n", f->score);
fprintf(F, "%d;Punktedurchschnitt\n", average_score_of_age(f->age, f->age / 24 + 1));
}
fprintf(F, "\"%s\";Typ\n", race[f->race].name[1]);
fprintf(F, "%d;Rekrutierungskosten\n", race[f->race].rekrutieren);
fprintf(F, "%d;Anzahl Personen\n", count_all(f));
fprintf(F, "\"%s\";Magiegebiet\n", neue_gebiete[f->magiegebiet]);
if (f->race == RC_HUMAN) {
fprintf(F, "%d;Anzahl Immigranten\n", count_migrants(f));
fprintf(F, "%d;Max. Immigranten\n", count_maxmigrants(f));
}
fprintf(F, "\"%s\";Parteiname\n", f->name);
fprintf(F, "\"%s\";email\n", f->email);
fprintf(F, "\"%s\";banner\n", f->banner);
fputs("OPTIONEN\n", F);
for (i=0;i!=MAXOPTIONS;++i) {
fprintf(F, "%d;%s\n", (f->options&want(i))?1:0, options[i]);
}
show_allies(F, f->allies);
#ifdef GROUPS
{
group * g;
for (g=f->groups;g;g=g->next) {
fprintf(F, "GRUPPE %d\n", g->gid);
fprintf(F, "\"%s\";name\n", g->name);
show_allies(F, g->allies);
}
}
#endif
cr_output_str_list(F, "FEHLER", f->mistakes, f);
cr_output_messages(F, f->msgs, f);
{
struct bmsg * bm;
for (bm=f->battles;bm;bm=bm->next) {
fprintf(F, "BATTLE %d %d\n", region_x(bm->r, f), region_y(bm->r, f));
cr_output_messages(F, bm->msgs, f);
}
}
cr_find_address(F, f);
a = a_find(f->attribs, &at_reportspell);
while (a) {
cr_reportspell(F, (spellid_t)a->data.i);
a = a->nexttype;
}
for (a=a_find(f->attribs, &at_showitem);a;a=a->nexttype) {
const potion_type * ptype = resource2potion(((const item_type*)a->data.v)->rtype);
requirement * m;
const char * ch;
if (ptype==NULL) continue;
m = ptype->itype->construction->materials;
ch = resourcename(ptype->itype->rtype, 0);
fprintf(F, "TRANK %d\n", hashstring(ch));
fprintf(F, "\"%s\";Name\n", locale_string(f->locale, ch));
fprintf(F, "%d;Stufe\n", ptype->level);
fprintf(F, "\"%s\";Beschr\n", ptype->text);
fprintf(F, "ZUTATEN\n");
while (m->number) {
fprintf(F, "\"%s\"\n", locale_string(f->locale, resourcename(oldresourcetype[m->type], 0)));
m++;
}
}
/* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
* = = = */
/* traverse all regions */
for (sd = seen; sd!=NULL; sd = sd->next) {
int modifier = 0;
const char * tname;
r = sd->r;
if (!rplane(r)) fprintf(F, "REGION %d %d\n", region_x(r, f), region_y(r, f));
else {
#if ENCODE_SPECIAL
if (rplane(r)->flags & PFL_NOCOORDS) fprintf(F, "SPEZIALREGION %d %d\n", encode_region(f, r), rplane(r)->id);
#else
if (rplane(r)->flags & PFL_NOCOORDS) continue;
#endif
else fprintf(F, "REGION %d %d %d\n", region_x(r, f), region_y(r, f), rplane(r)->id);
}
if (r->land && strlen(rname(r, f->locale))) fprintf(F, "\"%s\";Name\n", rname(r, f->locale));
if (is_cursed(r->attribs,C_MAELSTROM, 0))
tname = "maelstrom";
else {
if (r_isforest(r)) tname = "forest";
else tname = terrain[rterrain(r)].name;
}
fprintf(F, "\"%s\";Terrain\n", locale_string(f->locale, tname));
if (sd->mode != see_neighbour)
{
int g = 0;
direction_t d;
if (r->display && strlen(r->display))
fprintf(F, "\"%s\";Beschr\n", r->display);
if (landregion(rterrain(r))) {
fprintf(F, "%d;Bauern\n", rpeasants(r));
fprintf(F, "%d;Pferde\n", rhorses(r));
fprintf(F, "%d;Baeume\n", rtrees(r));
if (fval(r, RF_MALLORN) && rtrees(r))
fprintf(F, "1;Mallorn\n");
if (sd->mode>=see_unit) {
struct demand * dmd = r->land->demands;
if (rterrain(r) == T_MOUNTAIN || rterrain(r) == T_GLACIER) {
maxmining = 0;
for (u = r->units; u; u = u->next) {
int s = eff_skill(u, SK_MINING, r);
if (u->faction == f || omniscient(f))
maxmining = max(maxmining, s);
}
if (maxmining >= 4)
fprintf(F, "%d;Eisen\n", riron(r));
if (maxmining >= 7)
fprintf(F, "%d;Laen\n", rlaen(r));
}
fprintf(F, "%d;Silber\n", rmoney(r));
fprintf(F, "%d;Unterh\n", entertainmoney(r));
if (is_cursed(r->attribs, C_RIOT, 0)){
fprintf(F, "0;Rekruten\n");
} else {
fprintf(F, "%d;Rekruten\n", rpeasants(r) / RECRUITFRACTION);
}
if (production(r)) {
fprintf(F, "%d;Lohn\n", fwage(r, f, true));
}
/* trade */
if(rpeasants(r)/TRADE_FRACTION > 0) {
fputs("PREISE\n", F);
while (dmd) {
fprintf(F, "%d;%s\n", (dmd->value
? dmd->value*dmd->type->price
: -dmd->type->price),
locale_string(f->locale, resourcename(dmd->type->itype->rtype, 0)));
dmd=dmd->next;
}
}
}
}
for (d = 0; d != MAXDIRECTIONS; d++)
{ /* Nachbarregionen, die gesehen werden, ermitteln */
region * r2 = rconnect(r, d);
border * b;
if (!r2) continue;
b = get_borders(r, r2);
while (b) {
boolean cs = b->type->fvisible(b, f, r);
if (!cs) {
cs = b->type->rvisible(b, r);
if (!cs) {
unit * us = r->units;
while (us && !cs) {
if (us->faction==f) {
cs = b->type->uvisible(b, us);
if (cs) break;
}
us=us->next;
}
}
}
if (cs) {
fprintf(F, "GRENZE %d\n", ++g);
fprintf(F, "\"%s\";typ\n", b->type->name(b, r, f, GF_NONE));
fprintf(F, "%d;richtung\n", d);
if (!b->type->transparent(b, f)) fputs("1;opaque\n", F);
/* pfusch: */
if (b->type==&bt_road) {
int p = rroad(r, d)*100/terrain[rterrain(r)].roadreq;
fprintf(F, "%d;prozent\n", p);
}
}
b = b->next;
}
}
if (sd->mode==see_unit && r->planep && r->planep->id == 1 && !is_cursed(r->attribs, C_ASTRALBLOCK, 0))
{
/* Sonderbehandlung Teleport-Ebene */
regionlist *rl = allinhab_in_range(r_astral_to_standard(r),TP_RADIUS);
if (rl) {
regionlist *rl2 = rl;
while(rl2) {
region * r = rl2->region;
fprintf(F, "SCHEMEN %d %d\n", region_x(r, f), region_y(r, f));
fprintf(F, "\"%s\";Name\n", rname(r, f->locale));
rl2 = rl2->next;
if(rl2) scat(", ");
}
free_regionlist(rl);
}
}
print_curses(F, r, TYP_REGION, r->attribs, 0);
/* describe both passed and inhabited regions */
show_active_spells(r);
{
boolean see = false;
const attrib * ru;
/* show units pulled throuth region */
for (ru = a_find(r->attribs, &at_travelunit); ru; ru = ru->nexttype) {
unit * u = (unit*)ru->data.v;
if (cansee_durchgezogen(f, r, u, 0) && in_region(r, u) == 0) {
if (u->ship && !fval(u, FL_OWNER))
continue;
if (!see) fprintf(F, "DURCHREISE\n");
see = true;
if (u->ship)
fprintf(F, "\"%s\"\n", shipname(u->ship));
else
fprintf(F, "\"%s\"\n", unitname(u));
}
}
}
cr_output_messages(F, r->msgs, f);
/* buildings */
for (b = rbuildings(r); b; b = b->next) {
int fno = -1;
u = buildingowner(r, b);
if (u && !fval(u, FL_PARTEITARNUNG))
fno = u->faction->no;
cr_output_buildings(F, b, u, fno, f);
}
/* ships */
for (sh = r->ships; sh; sh = sh->next) {
int fno = -1;
u = shipowner(r, sh);
if (u && !fval(u, FL_PARTEITARNUNG))
fno = u->faction->no;
cr_output_ship(F, sh, u, fno, f, r);
}
/* visible units */
for (u = r->units; u; u = u->next) {
boolean visible = true;
switch (sd->mode) {
case see_unit:
modifier=0;
break;
#ifdef SEE_FAR
case see_far:
#endif
case see_lighthouse:
modifier = -2;
break;
case see_travel:
modifier = -1;
break;
default:
visible=false;
}
if (u->building || u->ship || (visible && cansee(f, r, u, modifier)))
cr_output_unit(F, r, f, u, sd->mode);
}
} /* region traversal */
}
report_crtypes(F, f->locale);
}