forked from github/server
1752 lines
52 KiB
C
1752 lines
52 KiB
C
/* vi: set ts=2:
|
||
+-------------------+ Enno Rehling <enno@eressea.de>
|
||
| Eressea PBEM host | Christian Schlittchen <corwin@amber.kn-bremen.de>
|
||
| (c) 1998 - 2008 | Katja Zedel <katze@felidae.kn-bremen.de>
|
||
+-------------------+
|
||
This program may not be used, modified or distributed
|
||
without prior permission by the authors of Eressea.
|
||
*/
|
||
|
||
#include <platform.h>
|
||
#include <kernel/config.h>
|
||
#include "buildno.h"
|
||
#include "creport.h"
|
||
|
||
/* tweakable features */
|
||
#define RENDER_CRMESSAGES
|
||
#define BUFFERSIZE 32768
|
||
#define RESOURCECOMPAT
|
||
|
||
/* modules include */
|
||
#include <modules/score.h>
|
||
|
||
/* attributes include */
|
||
#include <attributes/follow.h>
|
||
#include <attributes/orcification.h>
|
||
#include <attributes/otherfaction.h>
|
||
#include <attributes/racename.h>
|
||
#include <attributes/raceprefix.h>
|
||
#include <attributes/stealth.h>
|
||
|
||
/* gamecode includes */
|
||
#include "laws.h"
|
||
#include "economy.h"
|
||
#include "move.h"
|
||
#include "reports.h"
|
||
#include "alchemy.h"
|
||
|
||
/* kernel includes */
|
||
#include <kernel/alliance.h>
|
||
#include <kernel/ally.h>
|
||
#include <kernel/connection.h>
|
||
#include <kernel/building.h>
|
||
#include <kernel/curse.h>
|
||
#include <kernel/faction.h>
|
||
#include <kernel/group.h>
|
||
#include <kernel/item.h>
|
||
#include <kernel/messages.h>
|
||
#include <kernel/order.h>
|
||
#include <kernel/plane.h>
|
||
#include <kernel/race.h>
|
||
#include <kernel/region.h>
|
||
#include <kernel/resources.h>
|
||
#include <kernel/ship.h>
|
||
#include <kernel/spell.h>
|
||
#include <kernel/spellbook.h>
|
||
#include <kernel/teleport.h>
|
||
#include <kernel/terrain.h>
|
||
#include <kernel/unit.h>
|
||
#include <kernel/save.h>
|
||
|
||
/* util includes */
|
||
#include <util/attrib.h>
|
||
#include <util/base36.h>
|
||
#include <util/crmessage.h>
|
||
#include <util/goodies.h>
|
||
#include <util/language.h>
|
||
#include <util/log.h>
|
||
#include <util/message.h>
|
||
#include <util/nrmessage.h>
|
||
#include <quicklist.h>
|
||
|
||
/* libc includes */
|
||
#include <assert.h>
|
||
#include <errno.h>
|
||
#include <math.h>
|
||
#include <limits.h>
|
||
#include <stdio.h>
|
||
#include <stdlib.h>
|
||
#include <string.h>
|
||
|
||
/* imports */
|
||
extern int verbosity;
|
||
bool opt_cr_absolute_coords = false;
|
||
|
||
/* globals */
|
||
#define C_REPORT_VERSION 66
|
||
|
||
#define TAG_LOCALE "de"
|
||
#ifdef TAG_LOCALE
|
||
static const char *crtag(const char *key)
|
||
{
|
||
static const struct locale *lang = NULL;
|
||
if (!lang)
|
||
lang = get_locale(TAG_LOCALE);
|
||
return locale_string(lang, key);
|
||
}
|
||
#else
|
||
#define crtag(x) (x)
|
||
#endif
|
||
/*
|
||
* translation table
|
||
*/
|
||
typedef struct translation {
|
||
struct translation *next;
|
||
char *key;
|
||
const char *value;
|
||
} translation;
|
||
|
||
#define TRANSMAXHASH 257
|
||
static translation *translation_table[TRANSMAXHASH];
|
||
static translation *junkyard;
|
||
|
||
static const char *translate(const char *key, const char *value)
|
||
{
|
||
int kk = ((key[0] << 5) + key[0]) % TRANSMAXHASH;
|
||
translation *t = translation_table[kk];
|
||
while (t && strcmp(t->key, key) != 0)
|
||
t = t->next;
|
||
if (!t) {
|
||
if (junkyard) {
|
||
t = junkyard;
|
||
junkyard = junkyard->next;
|
||
}
|
||
else
|
||
t = malloc(sizeof(translation));
|
||
t->key = _strdup(key);
|
||
t->value = value;
|
||
t->next = translation_table[kk];
|
||
translation_table[kk] = t;
|
||
}
|
||
return crtag(key);
|
||
}
|
||
|
||
static void write_translations(FILE * F)
|
||
{
|
||
int i;
|
||
fputs("TRANSLATION\n", F);
|
||
for (i = 0; i != TRANSMAXHASH; ++i) {
|
||
translation *t = translation_table[i];
|
||
while (t) {
|
||
fprintf(F, "\"%s\";%s\n", t->value, crtag(t->key));
|
||
t = t->next;
|
||
}
|
||
}
|
||
}
|
||
|
||
static void reset_translations(void)
|
||
{
|
||
int i;
|
||
for (i = 0; i != TRANSMAXHASH; ++i) {
|
||
translation *t = translation_table[i];
|
||
while (t) {
|
||
translation *c = t->next;
|
||
free(t->key);
|
||
t->next = junkyard;
|
||
junkyard = t;
|
||
t = c;
|
||
}
|
||
translation_table[i] = 0;
|
||
}
|
||
}
|
||
|
||
#include <kernel/objtypes.h>
|
||
|
||
static void print_items(FILE * F, item * items, const struct locale *lang)
|
||
{
|
||
item *itm;
|
||
|
||
for (itm = items; itm; itm = itm->next) {
|
||
int in = itm->number;
|
||
const char *ic = resourcename(itm->type->rtype, 0);
|
||
if (itm == items)
|
||
fputs("GEGENSTAENDE\n", F);
|
||
fprintf(F, "%d;%s\n", in, translate(ic, LOC(lang, ic)));
|
||
}
|
||
}
|
||
|
||
static void
|
||
cr_output_curses(FILE * F, const faction * viewer, const void *obj, objtype_t typ)
|
||
{
|
||
bool header = false;
|
||
attrib *a = NULL;
|
||
int self = 0;
|
||
region *r;
|
||
|
||
/* Die Sichtbarkeit eines Zaubers und die Zaubermeldung sind bei
|
||
* Geb<65>uden und Schiffen je nach, ob man Besitzer ist, verschieden.
|
||
* Bei Einheiten sieht man Wirkungen auf eigene Einheiten immer.
|
||
* Spezialf<6C>lle (besonderes Talent, verursachender Magier usw. werde
|
||
* bei jedem curse gesondert behandelt. */
|
||
if (typ == TYP_SHIP) {
|
||
ship *sh = (ship *)obj;
|
||
unit *owner = ship_owner(sh);
|
||
a = sh->attribs;
|
||
r = sh->region;
|
||
if (owner != NULL) {
|
||
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 = building_owner(b);
|
||
a = b->attribs;
|
||
r = b->region;
|
||
if (owner != 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 */
|
||
}
|
||
|
||
while (a) {
|
||
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) {
|
||
char buf[BUFFERSIZE];
|
||
if (!header) {
|
||
header = 1;
|
||
fputs("EFFECTS\n", F);
|
||
}
|
||
nr_render(msg, viewer->locale, buf, sizeof(buf), viewer);
|
||
fprintf(F, "\"%s\"\n", buf);
|
||
msg_release(msg);
|
||
}
|
||
}
|
||
else if (a->type == &at_effect && self) {
|
||
effect_data *data = (effect_data *)a->data.v;
|
||
if (data->value > 0) {
|
||
const char *key = resourcename(data->type->itype->rtype, 0);
|
||
if (!header) {
|
||
header = 1;
|
||
fputs("EFFECTS\n", F);
|
||
}
|
||
fprintf(F, "\"%d %s\"\n", data->value, translate(key,
|
||
locale_string(default_locale, key)));
|
||
}
|
||
}
|
||
a = a->next;
|
||
}
|
||
}
|
||
|
||
static int cr_unit(variant var, char *buffer, const void *userdata)
|
||
{
|
||
unit *u = (unit *)var.v;
|
||
sprintf(buffer, "%d", u ? u->no : -1);
|
||
return 0;
|
||
}
|
||
|
||
static int cr_ship(variant var, char *buffer, const void *userdata)
|
||
{
|
||
ship *u = (ship *)var.v;
|
||
sprintf(buffer, "%d", u ? u->no : -1);
|
||
return 0;
|
||
}
|
||
|
||
static int cr_building(variant var, char *buffer, const void *userdata)
|
||
{
|
||
building *u = (building *)var.v;
|
||
sprintf(buffer, "%d", u ? u->no : -1);
|
||
return 0;
|
||
}
|
||
|
||
static int cr_faction(variant var, char *buffer, const void *userdata)
|
||
{
|
||
faction *f = (faction *)var.v;
|
||
sprintf(buffer, "%d", f ? f->no : -1);
|
||
return 0;
|
||
}
|
||
|
||
static int cr_region(variant var, char *buffer, const void *userdata)
|
||
{
|
||
const faction *report = (const faction *)userdata;
|
||
region *r = (region *)var.v;
|
||
if (r) {
|
||
plane *pl = rplane(r);
|
||
int nx = r->x, ny = r->y;
|
||
pnormalize(&nx, &ny, pl);
|
||
adjust_coordinates(report, &nx, &ny, pl, r);
|
||
sprintf(buffer, "%d %d %d", nx, ny, plane_id(pl));
|
||
return 0;
|
||
}
|
||
return -1;
|
||
}
|
||
|
||
static int cr_resource(variant var, char *buffer, const void *userdata)
|
||
{
|
||
const faction *report = (const faction *)userdata;
|
||
const resource_type *r = (const resource_type *)var.v;
|
||
if (r) {
|
||
const char *key = resourcename(r, 0);
|
||
sprintf(buffer, "\"%s\"",
|
||
translate(key, locale_string(report->locale, key)));
|
||
return 0;
|
||
}
|
||
return -1;
|
||
}
|
||
|
||
static int cr_race(variant var, char *buffer, const void *userdata)
|
||
{
|
||
const faction *report = (const faction *)userdata;
|
||
const struct race *rc = (const race *)var.v;
|
||
const char *key = rc_name_s(rc, NAME_SINGULAR);
|
||
sprintf(buffer, "\"%s\"",
|
||
translate(key, locale_string(report->locale, key)));
|
||
return 0;
|
||
}
|
||
|
||
static int cr_alliance(variant var, char *buffer, const void *userdata)
|
||
{
|
||
const alliance *al = (const alliance *)var.v;
|
||
if (al != NULL) {
|
||
sprintf(buffer, "%d", al->id);
|
||
}
|
||
unused_arg(userdata);
|
||
return 0;
|
||
}
|
||
|
||
static int cr_skill(variant var, char *buffer, const void *userdata)
|
||
{
|
||
const faction *report = (const faction *)userdata;
|
||
skill_t sk = (skill_t)var.i;
|
||
if (sk != NOSKILL)
|
||
sprintf(buffer, "\"%s\"",
|
||
translate(mkname("skill", skillnames[sk]), skillname(sk,
|
||
report->locale)));
|
||
else
|
||
strcpy(buffer, "\"\"");
|
||
return 0;
|
||
}
|
||
|
||
static int cr_order(variant var, char *buffer, const void *userdata)
|
||
{
|
||
order *ord = (order *)var.v;
|
||
if (ord != NULL) {
|
||
char cmd[ORDERSIZE];
|
||
char *wp = buffer;
|
||
const char *rp;
|
||
|
||
get_command(ord, cmd, sizeof(cmd));
|
||
|
||
*wp++ = '\"';
|
||
for (rp = cmd; *rp;) {
|
||
switch (*rp) {
|
||
case '\"':
|
||
case '\\':
|
||
*wp++ = '\\';
|
||
default:
|
||
*wp++ = *rp++;
|
||
}
|
||
}
|
||
*wp++ = '\"';
|
||
*wp++ = 0;
|
||
}
|
||
else
|
||
strcpy(buffer, "\"\"");
|
||
return 0;
|
||
}
|
||
|
||
static int cr_resources(variant var, char *buffer, const void *userdata)
|
||
{
|
||
faction *f = (faction *)userdata;
|
||
resource *rlist = (resource *)var.v;
|
||
char *wp = buffer;
|
||
if (rlist != NULL) {
|
||
const char *name = resourcename(rlist->type, rlist->number != 1);
|
||
wp +=
|
||
sprintf(wp, "\"%d %s", rlist->number, translate(name, LOC(f->locale,
|
||
name)));
|
||
for (;;) {
|
||
rlist = rlist->next;
|
||
if (rlist == NULL)
|
||
break;
|
||
name = resourcename(rlist->type, rlist->number != 1);
|
||
wp +=
|
||
sprintf(wp, ", %d %s", rlist->number, translate(name,
|
||
LOC(f->locale, name)));
|
||
}
|
||
strcat(wp, "\"");
|
||
}
|
||
return 0;
|
||
}
|
||
|
||
static int cr_regions(variant var, char *buffer, const void *userdata)
|
||
{
|
||
faction *f = (faction *)userdata;
|
||
const arg_regions *rdata = (const arg_regions *)var.v;
|
||
|
||
if (rdata != NULL && rdata->nregions > 0) {
|
||
region *r = rdata->regions[0];
|
||
plane *pl = rplane(r);
|
||
int i, z = plane_id(pl);
|
||
char *wp = buffer;
|
||
int nx = r->x, ny = r->y;
|
||
|
||
pnormalize(&nx, &ny, pl);
|
||
adjust_coordinates(f, &nx, &ny, pl, r);
|
||
wp += sprintf(wp, "\"%d %d %d", nx, ny, z);
|
||
for (i = 1; i != rdata->nregions; ++i) {
|
||
r = rdata->regions[i];
|
||
pl = rplane(r);
|
||
z = plane_id(pl);
|
||
wp += sprintf(wp, ", %d %d %d", nx, ny, z);
|
||
}
|
||
strcat(wp, "\"");
|
||
}
|
||
else {
|
||
strcpy(buffer, "\"\"");
|
||
}
|
||
return 0;
|
||
}
|
||
|
||
static int cr_spell(variant var, char *buffer, const void *userdata)
|
||
{
|
||
const faction *report = (const faction *)userdata;
|
||
spell *sp = (spell *)var.v;
|
||
if (sp != NULL)
|
||
sprintf(buffer, "\"%s\"", spell_name(sp, report->locale));
|
||
else
|
||
strcpy(buffer, "\"\"");
|
||
return 0;
|
||
}
|
||
|
||
static int cr_curse(variant var, char *buffer, const void *userdata)
|
||
{
|
||
const faction *report = (const faction *)userdata;
|
||
const curse_type *ctype = (const curse_type *)var.v;
|
||
if (ctype != NULL) {
|
||
sprintf(buffer, "\"%s\"", curse_name(ctype, report->locale));
|
||
}
|
||
else
|
||
strcpy(buffer, "\"\"");
|
||
return 0;
|
||
}
|
||
|
||
/*static int msgno; */
|
||
|
||
#define MTMAXHASH 1021
|
||
|
||
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;
|
||
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) {
|
||
char buffer[DISPLAYSIZE];
|
||
unsigned int hash = kmt->mtype->key;
|
||
assert(hash > 0);
|
||
fprintf(F, "MESSAGETYPE %u\n", hash);
|
||
fputc('\"', F);
|
||
fputs(escape_string(nrt_string(nrt), buffer, sizeof(buffer)), F);
|
||
fputs("\";text\n", F);
|
||
fprintf(F, "\"%s\";section\n", nrt_section(nrt));
|
||
}
|
||
}
|
||
while (mtypehash[i]) {
|
||
kmt = mtypehash[i];
|
||
mtypehash[i] = mtypehash[i]->nexthash;
|
||
free(kmt);
|
||
}
|
||
}
|
||
}
|
||
|
||
static unsigned int messagehash(const struct message *msg)
|
||
{
|
||
variant var;
|
||
var.v = (void *)msg;
|
||
return (unsigned int)var.i;
|
||
}
|
||
|
||
/** writes a quoted string to the file
|
||
* no trailing space, since this is used to make the creport.
|
||
*/
|
||
static int fwritestr(FILE * F, const char *str)
|
||
{
|
||
int nwrite = 0;
|
||
fputc('\"', F);
|
||
if (str)
|
||
while (*str) {
|
||
int c = (int)(unsigned char)*str++;
|
||
switch (c) {
|
||
case '"':
|
||
case '\\':
|
||
fputc('\\', F);
|
||
fputc(c, F);
|
||
nwrite += 2;
|
||
break;
|
||
case '\n':
|
||
fputc('\\', F);
|
||
fputc('n', F);
|
||
nwrite += 2;
|
||
break;
|
||
default:
|
||
fputc(c, F);
|
||
++nwrite;
|
||
}
|
||
}
|
||
fputc('\"', F);
|
||
return nwrite + 2;
|
||
}
|
||
|
||
static void render_messages(FILE * F, faction * f, message_list * msgs)
|
||
{
|
||
struct mlist *m = msgs->begin;
|
||
while (m) {
|
||
char crbuffer[BUFFERSIZE]; /* gross, wegen spionage-messages :-( */
|
||
bool printed = false;
|
||
const struct message_type *mtype = m->msg->type;
|
||
unsigned int hash = mtype->key;
|
||
#ifdef RENDER_CRMESSAGES
|
||
char nrbuffer[1024 * 32];
|
||
nrbuffer[0] = '\0';
|
||
if (nr_render(m->msg, f->locale, nrbuffer, sizeof(nrbuffer), f) > 0) {
|
||
fprintf(F, "MESSAGE %u\n", messagehash(m->msg));
|
||
fprintf(F, "%u;type\n", hash);
|
||
fwritestr(F, nrbuffer);
|
||
fputs(";rendered\n", F);
|
||
printed = true;
|
||
}
|
||
#endif
|
||
crbuffer[0] = '\0';
|
||
if (cr_render(m->msg, crbuffer, (const void *)f) == 0) {
|
||
if (crbuffer[0]) {
|
||
if (!printed) {
|
||
fprintf(F, "MESSAGE %u\n", messagehash(m->msg));
|
||
}
|
||
fputs(crbuffer, F);
|
||
}
|
||
}
|
||
else {
|
||
log_error("could not render cr-message %p: %s\n", m->msg, m->msg->type->name);
|
||
}
|
||
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_building(FILE * F, building * b, const unit * owner, int fno,
|
||
faction * f)
|
||
{
|
||
const char *bname, *billusion;
|
||
|
||
fprintf(F, "BURG %d\n", b->no);
|
||
|
||
report_building(b, &bname, &billusion);
|
||
if (billusion) {
|
||
fprintf(F, "\"%s\";Typ\n", translate(billusion, LOC(f->locale,
|
||
billusion)));
|
||
if (owner && owner->faction == f) {
|
||
fprintf(F, "\"%s\";wahrerTyp\n", translate(bname, LOC(f->locale,
|
||
bname)));
|
||
}
|
||
}
|
||
else {
|
||
fprintf(F, "\"%s\";Typ\n", translate(bname, LOC(f->locale, bname)));
|
||
}
|
||
fprintf(F, "\"%s\";Name\n", b->name);
|
||
if (b->display && b->display[0])
|
||
fprintf(F, "\"%s\";Beschr\n", b->display);
|
||
if (b->size)
|
||
fprintf(F, "%d;Groesse\n", b->size);
|
||
if (owner)
|
||
fprintf(F, "%d;Besitzer\n", owner ? owner->no : -1);
|
||
if (fno >= 0)
|
||
fprintf(F, "%d;Partei\n", fno);
|
||
if (b->besieged)
|
||
fprintf(F, "%d;Belagerer\n", b->besieged);
|
||
cr_output_curses(F, f, b, TYP_BUILDING);
|
||
}
|
||
|
||
/* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
|
||
|
||
/* prints a ship */
|
||
static void
|
||
cr_output_ship(FILE * F, const ship * sh, const unit * u, int fcaptain,
|
||
const faction * f, const region * r)
|
||
{
|
||
int w = 0;
|
||
assert(sh);
|
||
fprintf(F, "SCHIFF %d\n", sh->no);
|
||
fprintf(F, "\"%s\";Name\n", sh->name);
|
||
if (sh->display && sh->display[0])
|
||
fprintf(F, "\"%s\";Beschr\n", sh->display);
|
||
fprintf(F, "\"%s\";Typ\n", translate(sh->type->_name,
|
||
locale_string(f->locale, sh->type->_name)));
|
||
fprintf(F, "%d;Groesse\n", sh->size);
|
||
if (sh->damage) {
|
||
int percent =
|
||
(sh->damage * 100 + DAMAGE_SCALE - 1) / (sh->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))) {
|
||
int n = 0, p = 0;
|
||
int mweight = shipcapacity(sh);
|
||
getshipweight(sh, &n, &p);
|
||
|
||
fprintf(F, "%d;capacity\n", mweight);
|
||
fprintf(F, "%d;cargo\n", n);
|
||
fprintf(F, "%d;speed\n", shipspeed(sh, u));
|
||
}
|
||
/* shore */
|
||
w = NODIRECTION;
|
||
if (!fval(r->terrain, SEA_REGION))
|
||
w = sh->coast;
|
||
if (w != NODIRECTION)
|
||
fprintf(F, "%d;Kueste\n", w);
|
||
|
||
cr_output_curses(F, f, sh, TYP_SHIP);
|
||
}
|
||
|
||
static void
|
||
fwriteorder(FILE * F, const struct order *ord, const struct locale *lang,
|
||
bool escape)
|
||
{
|
||
char ebuf[1025];
|
||
char obuf[1024];
|
||
const char *str = obuf;
|
||
fputc('"', F);
|
||
write_order(ord, obuf, sizeof(obuf));
|
||
if (escape) {
|
||
str = escape_string(obuf, ebuf, sizeof(ebuf));
|
||
if (str == ebuf) {
|
||
ebuf[1024] = 0;
|
||
}
|
||
}
|
||
if (str[0])
|
||
fputs(str, F);
|
||
fputc('"', F);
|
||
}
|
||
|
||
static void cr_output_spells(FILE * F, const unit * u, int maxlevel)
|
||
{
|
||
spellbook * book = unit_get_spellbook(u);
|
||
|
||
if (book) {
|
||
const faction * f = u->faction;
|
||
quicklist *ql;
|
||
int qi, header = 0;
|
||
|
||
for (ql = book->spells, qi = 0; ql; ql_advance(&ql, &qi, 1)) {
|
||
spellbook_entry * sbe = (spellbook_entry *)ql_get(ql, qi);
|
||
if (sbe->level <= maxlevel) {
|
||
spell * sp = sbe->sp;
|
||
const char *name = translate(mkname("spell", sp->sname), spell_name(sp, f->locale));
|
||
if (!header) {
|
||
fputs("SPRUECHE\n", F);
|
||
header = 1;
|
||
}
|
||
fprintf(F, "\"%s\"\n", name);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
/* prints all that belongs to a unit */
|
||
static void cr_output_unit(FILE * F, const region * r, const faction * f, /* observers faction */
|
||
const unit * u, int mode)
|
||
{
|
||
/* Race attributes are always plural and item attributes always
|
||
* singular */
|
||
const char *str;
|
||
const item_type *lasttype;
|
||
int pr;
|
||
item *itm, *show;
|
||
building *b;
|
||
const char *pzTmp;
|
||
skill *sv;
|
||
const attrib *a_fshidden = NULL;
|
||
bool itemcloak = false;
|
||
static const curse_type *itemcloak_ct = 0;
|
||
static bool init = false;
|
||
item result[MAX_INVENTORY];
|
||
|
||
if (fval(u_race(u), RCF_INVISIBLE))
|
||
return;
|
||
|
||
if (!init) {
|
||
init = true;
|
||
itemcloak_ct = ct_find("itemcloak");
|
||
}
|
||
if (itemcloak_ct != NULL) {
|
||
itemcloak = curse_active(get_curse(u->attribs, itemcloak_ct));
|
||
}
|
||
|
||
assert(u && u->number);
|
||
|
||
fprintf(F, "EINHEIT %d\n", u->no);
|
||
fprintf(F, "\"%s\";Name\n", u->name);
|
||
str = u_description(u, f->locale);
|
||
if (str) {
|
||
fprintf(F, "\"%s\";Beschr\n", str);
|
||
}
|
||
{
|
||
/* print faction information */
|
||
const faction *sf = visible_faction(f, u);
|
||
const char *prefix = raceprefix(u);
|
||
if (u->faction == f || omniscient(f)) {
|
||
const attrib *a_otherfaction = a_find(u->attribs, &at_otherfaction);
|
||
const faction *otherfaction =
|
||
a_otherfaction ? get_otherfaction(a_otherfaction) : NULL;
|
||
/* my own faction, full info */
|
||
const attrib *a = NULL;
|
||
unit *mage;
|
||
|
||
if (fval(u, UFL_GROUP))
|
||
a = a_find(u->attribs, &at_group);
|
||
if (a != NULL) {
|
||
const group *g = (const group *)a->data.v;
|
||
fprintf(F, "%d;gruppe\n", g->gid);
|
||
}
|
||
fprintf(F, "%d;Partei\n", u->faction->no);
|
||
if (sf != u->faction)
|
||
fprintf(F, "%d;Verkleidung\n", sf->no);
|
||
if (fval(u, UFL_ANON_FACTION))
|
||
fprintf(F, "%d;Parteitarnung\n", i2b(fval(u, UFL_ANON_FACTION)));
|
||
if (otherfaction) {
|
||
if (otherfaction != u->faction) {
|
||
fprintf(F, "%d;Anderepartei\n", otherfaction->no);
|
||
}
|
||
}
|
||
mage = get_familiar_mage(u);
|
||
if (mage) {
|
||
fprintf(F, "%u;familiarmage\n", mage->no);
|
||
}
|
||
}
|
||
else {
|
||
if (fval(u, UFL_ANON_FACTION)) {
|
||
/* faction info is hidden */
|
||
fprintf(F, "%d;Parteitarnung\n", i2b(fval(u, UFL_ANON_FACTION)));
|
||
}
|
||
else {
|
||
const attrib *a_otherfaction = a_find(u->attribs, &at_otherfaction);
|
||
const faction *otherfaction =
|
||
a_otherfaction ? get_otherfaction(a_otherfaction) : NULL;
|
||
/* other unit. show visible faction, not u->faction */
|
||
fprintf(F, "%d;Partei\n", sf->no);
|
||
if (sf == f) {
|
||
fprintf(F, "1;Verraeter\n");
|
||
}
|
||
if (a_otherfaction) {
|
||
if (otherfaction != u->faction) {
|
||
if (alliedunit(u, f, HELP_FSTEALTH)) {
|
||
fprintf(F, "%d;Anderepartei\n", otherfaction->no);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
if (prefix) {
|
||
prefix = mkname("prefix", prefix);
|
||
fprintf(F, "\"%s\";typprefix\n", translate(prefix, LOC(f->locale,
|
||
prefix)));
|
||
}
|
||
}
|
||
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) {
|
||
fprintf(F, "\"%s\";Typ\n", pzTmp);
|
||
if (u->faction == f && fval(u_race(u), RCF_SHAPESHIFTANY)) {
|
||
const char *zRace = rc_name_s(u_race(u), NAME_PLURAL);
|
||
fprintf(F, "\"%s\";wahrerTyp\n",
|
||
translate(zRace, locale_string(f->locale, zRace)));
|
||
}
|
||
}
|
||
else {
|
||
const race *irace = u_irace(u);
|
||
const char *zRace = rc_name_s(irace, NAME_PLURAL);
|
||
fprintf(F, "\"%s\";Typ\n",
|
||
translate(zRace, locale_string(f->locale, zRace)));
|
||
if (u->faction == f && irace != u_race(u)) {
|
||
assert(skill_enabled(SK_STEALTH)
|
||
|| !"we're resetting this on load, so.. ircase should never be used");
|
||
zRace = rc_name_s(u_race(u), NAME_PLURAL);
|
||
fprintf(F, "\"%s\";wahrerTyp\n",
|
||
translate(zRace, locale_string(f->locale, zRace)));
|
||
}
|
||
}
|
||
|
||
if (u->building) {
|
||
assert(u->building->region);
|
||
fprintf(F, "%d;Burg\n", u->building->no);
|
||
}
|
||
if (u->ship) {
|
||
assert(u->ship->region);
|
||
fprintf(F, "%d;Schiff\n", u->ship->no);
|
||
}
|
||
if (is_guard(u, GUARD_ALL) != 0) {
|
||
fprintf(F, "%d;bewacht\n", 1);
|
||
}
|
||
if ((b = usiege(u)) != NULL) {
|
||
fprintf(F, "%d;belagert\n", b->no);
|
||
}
|
||
/* additional information for own units */
|
||
if (u->faction == f || omniscient(f)) {
|
||
order *ord;
|
||
const char *xc;
|
||
const char *c;
|
||
int i;
|
||
sc_mage *mage;
|
||
|
||
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);
|
||
fprintf(F, "%d;Kampfstatus\n", u->status);
|
||
fprintf(F, "%d;weight\n", weight(u));
|
||
if (fval(u, UFL_NOAID)) {
|
||
fputs("1;unaided\n", F);
|
||
}
|
||
if (fval(u, UFL_STEALTH)) {
|
||
i = u_geteffstealth(u);
|
||
if (i >= 0) {
|
||
fprintf(F, "%d;Tarnung\n", i);
|
||
}
|
||
}
|
||
xc = uprivate(u);
|
||
if (xc) {
|
||
fprintf(F, "\"%s\";privat\n", xc);
|
||
}
|
||
c = hp_status(u);
|
||
if (c && *c && (u->faction == f || omniscient(f))) {
|
||
fprintf(F, "\"%s\";hp\n", translate(c,
|
||
locale_string(u->faction->locale, c)));
|
||
}
|
||
if (fval(u, UFL_HERO)) {
|
||
fputs("1;hero\n", F);
|
||
}
|
||
|
||
if (fval(u, UFL_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");
|
||
for (ord = u->old_orders; ord; ord = ord->next) {
|
||
/* this new order will replace the old defaults */
|
||
if (is_persistent(ord)) {
|
||
fwriteorder(F, ord, f->locale, true);
|
||
fputc('\n', F);
|
||
}
|
||
}
|
||
for (ord = u->orders; ord; ord = ord->next) {
|
||
if (u->old_orders && is_repeated(ord))
|
||
continue; /* unit has defaults */
|
||
if (is_persistent(ord)) {
|
||
fwriteorder(F, ord, f->locale, true);
|
||
fputc('\n', F);
|
||
}
|
||
}
|
||
|
||
/* talents */
|
||
pr = 0;
|
||
for (sv = u->skills; sv != u->skills + u->skill_size; ++sv) {
|
||
if (sv->level > 0) {
|
||
skill_t sk = sv->id;
|
||
int esk = eff_skill(u, sk, r);
|
||
if (!pr) {
|
||
pr = 1;
|
||
fprintf(F, "TALENTE\n");
|
||
}
|
||
fprintf(F, "%d %d;%s\n", u->number * level_days(sv->level), esk,
|
||
translate(mkname("skill", skillnames[sk]), skillname(sk,
|
||
f->locale)));
|
||
}
|
||
}
|
||
|
||
/* spells that this unit can cast */
|
||
mage = get_mage(u);
|
||
if (mage) {
|
||
int i, maxlevel = effskill(u, SK_MAGIC);
|
||
cr_output_spells(F, u, maxlevel);
|
||
|
||
for (i = 0; i != MAXCOMBATSPELLS; ++i) {
|
||
const spell *sp = mage->combatspells[i].sp;
|
||
if (sp) {
|
||
const char *name =
|
||
translate(mkname("spell", sp->sname), spell_name(sp,
|
||
f->locale));
|
||
fprintf(F, "KAMPFZAUBER %d\n", i);
|
||
fprintf(F, "\"%s\";name\n", name);
|
||
fprintf(F, "%d;level\n", mage->combatspells[i].level);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
/* items */
|
||
pr = 0;
|
||
if (f == u->faction || omniscient(f)) {
|
||
show = u->items;
|
||
}
|
||
else if (!itemcloak && mode >= see_unit && !(a_fshidden
|
||
&& 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;
|
||
}
|
||
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, translate(ic, locale_string(f->locale,
|
||
ic)));
|
||
}
|
||
|
||
cr_output_curses(F, f, u, TYP_UNIT);
|
||
}
|
||
|
||
/* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
|
||
|
||
/* prints allies */
|
||
static void show_allies_cr(FILE * F, const faction * f, const ally * sf)
|
||
{
|
||
for (; sf; sf = sf->next)
|
||
if (sf->faction) {
|
||
int mode = alliedgroup(NULL, f, sf->faction, sf, HELP_ALL);
|
||
if (mode != 0 && sf->status > 0) {
|
||
fprintf(F, "ALLIANZ %d\n", sf->faction->no);
|
||
fprintf(F, "\"%s\";Parteiname\n", sf->faction->name);
|
||
fprintf(F, "%d;Status\n", sf->status & HELP_ALL);
|
||
}
|
||
}
|
||
}
|
||
|
||
/* prints allies */
|
||
static void show_alliances_cr(FILE * F, const faction * f)
|
||
{
|
||
alliance *al = f_get_alliance(f);
|
||
if (al) {
|
||
faction *lead = alliance_get_leader(al);
|
||
assert(lead);
|
||
fprintf(F, "ALLIANCE %d\n", al->id);
|
||
fprintf(F, "\"%s\";name\n", al->name);
|
||
fprintf(F, "%d;leader\n", lead->no);
|
||
}
|
||
}
|
||
|
||
/* prints all visible spells in a region */
|
||
static void show_active_spells(const region * r)
|
||
{
|
||
char fogwall[MAXDIRECTIONS];
|
||
#ifdef TODO /* alte Regionszauberanzeigen umstellen */
|
||
unit *u;
|
||
int env = 0;
|
||
#endif
|
||
memset(fogwall, 0, sizeof(char) * MAXDIRECTIONS);
|
||
|
||
}
|
||
|
||
/* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
|
||
|
||
/* this is a copy of laws.c->find_address output changed. */
|
||
static void cr_find_address(FILE * F, const faction * uf, quicklist * addresses)
|
||
{
|
||
int i = 0;
|
||
quicklist *flist = addresses;
|
||
while (flist) {
|
||
const faction *f = (const faction *)ql_get(flist, i);
|
||
if (uf != f) {
|
||
fprintf(F, "PARTEI %d\n", f->no);
|
||
fprintf(F, "\"%s\";Parteiname\n", f->name);
|
||
if (f->email)
|
||
fprintf(F, "\"%s\";email\n", f->email);
|
||
if (f->banner)
|
||
fprintf(F, "\"%s\";banner\n", f->banner);
|
||
fprintf(F, "\"%s\";locale\n", locale_name(f->locale));
|
||
if (f->alliance && f->alliance == uf->alliance) {
|
||
fprintf(F, "%d;alliance\n", f->alliance->id);
|
||
}
|
||
}
|
||
ql_advance(&flist, &i, 1);
|
||
}
|
||
}
|
||
|
||
/* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
|
||
|
||
static void cr_reportspell(FILE * F, spell * sp, int level, const struct locale *lang)
|
||
{
|
||
int k;
|
||
const char *name =
|
||
translate(mkname("spell", sp->sname), spell_name(sp, lang));
|
||
|
||
fprintf(F, "ZAUBER %d\n", hashstring(sp->sname));
|
||
fprintf(F, "\"%s\";name\n", name);
|
||
fprintf(F, "%d;level\n", level);
|
||
fprintf(F, "%d;rank\n", sp->rank);
|
||
fprintf(F, "\"%s\";info\n", spell_info(sp, lang));
|
||
if (sp->parameter)
|
||
fprintf(F, "\"%s\";syntax\n", sp->parameter);
|
||
else
|
||
fputs("\"\";syntax\n", F);
|
||
|
||
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; sp->components[k].type; ++k) {
|
||
const resource_type *rtype = sp->components[k].type;
|
||
int itemanz = sp->components[k].amount;
|
||
int costtyp = sp->components[k].cost;
|
||
if (itemanz > 0) {
|
||
const char *name = resourcename(rtype, 0);
|
||
fprintf(F, "%d %d;%s\n", itemanz, costtyp == SPC_LEVEL
|
||
|| costtyp == SPC_LINEAR, translate(name, LOC(lang, name)));
|
||
}
|
||
}
|
||
}
|
||
|
||
static char *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", translate(name, LOC(loc, name)));
|
||
if (amount >= 0) {
|
||
if (level >= 0)
|
||
buf += sprintf(buf, "%d;skill\n", level);
|
||
buf += sprintf(buf, "%d;number\n", amount);
|
||
}
|
||
return buf;
|
||
}
|
||
|
||
static void
|
||
cr_borders(seen_region ** seen, const region * r, const faction * f,
|
||
int seemode, FILE * F)
|
||
{
|
||
direction_t d;
|
||
int g = 0;
|
||
for (d = 0; d != MAXDIRECTIONS; d++) { /* Nachbarregionen, die gesehen werden, ermitteln */
|
||
const region *r2 = rconnect(r, d);
|
||
const connection *b;
|
||
if (!r2)
|
||
continue;
|
||
if (seemode == see_neighbour) {
|
||
seen_region *sr = find_seen(seen, r2);
|
||
if (sr == NULL || sr->mode <= see_neighbour)
|
||
continue;
|
||
}
|
||
b = get_borders(r, r2);
|
||
while (b) {
|
||
bool 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) {
|
||
const char *bname = mkname("border", b->type->name(b, r, f, GF_PURE));
|
||
fprintf(F, "GRENZE %d\n", ++g);
|
||
fprintf(F, "\"%s\";typ\n", LOC(default_locale, bname));
|
||
fprintf(F, "%d;richtung\n", d);
|
||
if (!b->type->transparent(b, f))
|
||
fputs("1;opaque\n", F);
|
||
/* hack: */
|
||
if (b->type == &bt_road && r->terrain->max_road) {
|
||
int p = rroad(r, d) * 100 / r->terrain->max_road;
|
||
fprintf(F, "%d;prozent\n", p);
|
||
}
|
||
}
|
||
b = b->next;
|
||
}
|
||
}
|
||
}
|
||
|
||
static void
|
||
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);
|
||
|
||
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");
|
||
for (n = 0; n < size; ++n) {
|
||
if (result[n].level >= 0 && result[n].number >= 0) {
|
||
fprintf(F, "%d;%s\n", result[n].number, crtag(result[n].name));
|
||
}
|
||
}
|
||
#endif
|
||
|
||
for (n = 0; n < size; ++n) {
|
||
if (result[n].number >= 0) {
|
||
pos =
|
||
cr_output_resource(pos, result[n].name, f->locale, result[n].number,
|
||
result[n].level);
|
||
}
|
||
}
|
||
if (pos != cbuf)
|
||
fputs(cbuf, F);
|
||
}
|
||
|
||
static void
|
||
cr_region_header(FILE * F, int plid, int nx, int ny, unsigned int uid)
|
||
{
|
||
if (plid == 0) {
|
||
fprintf(F, "REGION %d %d\n", nx, ny);
|
||
}
|
||
else {
|
||
fprintf(F, "REGION %d %d %d\n", nx, ny, plid);
|
||
}
|
||
if (uid)
|
||
fprintf(F, "%d;id\n", uid);
|
||
}
|
||
|
||
static void cr_output_region(FILE * F, report_context * ctx, seen_region * sr)
|
||
{
|
||
faction *f = ctx->f;
|
||
region *r = sr->r;
|
||
plane *pl = rplane(r);
|
||
int plid = plane_id(pl), nx, ny;
|
||
const char *tname;
|
||
int oc[4][2], o = 0;
|
||
int uid = r->uid;
|
||
|
||
#ifdef OCEAN_NEIGHBORS_GET_NO_ID
|
||
if (sr->mode <= see_neighbour && !r->land) {
|
||
uid = 0;
|
||
}
|
||
#endif
|
||
|
||
if (opt_cr_absolute_coords) {
|
||
nx = r->x;
|
||
ny = r->y;
|
||
}
|
||
else {
|
||
nx = r->x, ny = r->y;
|
||
pnormalize(&nx, &ny, pl);
|
||
adjust_coordinates(f, &nx, &ny, pl, r);
|
||
}
|
||
|
||
if (pl) {
|
||
if (ny == pl->maxy) {
|
||
oc[o][0] = nx;
|
||
oc[o++][1] = pl->miny - 1;
|
||
}
|
||
if (nx == pl->maxx) {
|
||
oc[o][0] = pl->minx - 1;
|
||
oc[o++][1] = ny;
|
||
}
|
||
if (ny == pl->miny) {
|
||
oc[o][0] = nx;
|
||
oc[o++][1] = pl->maxy + 1;
|
||
}
|
||
if (nx == pl->minx) {
|
||
oc[o][0] = pl->maxx + 1;
|
||
oc[o++][1] = ny;
|
||
}
|
||
}
|
||
while (o--) {
|
||
cr_region_header(F, plid, oc[o][0], oc[o][1], uid);
|
||
fputs("\"wrap\";visibility\n", F);
|
||
}
|
||
|
||
cr_region_header(F, plid, nx, ny, uid);
|
||
|
||
if (r->land) {
|
||
const char *str = rname(r, f->locale);
|
||
if (str && str[0]) {
|
||
fprintf(F, "\"%s\";Name\n", str);
|
||
}
|
||
}
|
||
tname = terrain_name(r);
|
||
|
||
fprintf(F, "\"%s\";Terrain\n", translate(tname, locale_string(f->locale,
|
||
tname)));
|
||
if (sr->mode != see_unit)
|
||
fprintf(F, "\"%s\";visibility\n", visibility[sr->mode]);
|
||
if (sr->mode == see_neighbour) {
|
||
cr_borders(ctx->seen, r, f, sr->mode, F);
|
||
}
|
||
else {
|
||
building *b;
|
||
ship *sh;
|
||
unit *u;
|
||
int stealthmod = stealth_modifier(sr->mode);
|
||
|
||
if (r->display && r->display[0])
|
||
fprintf(F, "\"%s\";Beschr\n", r->display);
|
||
if (fval(r->terrain, LAND_REGION)) {
|
||
fprintf(F, "%d;Bauern\n", rpeasants(r));
|
||
if (fval(r, RF_ORCIFIED)) {
|
||
fprintf(F, "1;Verorkt\n");
|
||
}
|
||
fprintf(F, "%d;Pferde\n", rhorses(r));
|
||
|
||
if (sr->mode >= see_unit) {
|
||
if (rule_region_owners()) {
|
||
faction *owner = region_get_owner(r);
|
||
if (owner) {
|
||
fprintf(F, "%d;owner\n", owner->no);
|
||
}
|
||
}
|
||
fprintf(F, "%d;Silber\n", rmoney(r));
|
||
if (skill_enabled(SK_ENTERTAINMENT)) {
|
||
fprintf(F, "%d;Unterh\n", entertainmoney(r));
|
||
}
|
||
if (is_cursed(r->attribs, C_RIOT, 0)) {
|
||
fputs("0;Rekruten\n", F);
|
||
}
|
||
else {
|
||
fprintf(F, "%d;Rekruten\n", rpeasants(r) / RECRUITFRACTION);
|
||
}
|
||
if (production(r)) {
|
||
int p_wage = wage(r, NULL, NULL, turn + 1);
|
||
fprintf(F, "%d;Lohn\n", p_wage);
|
||
if (is_mourning(r, turn + 1)) {
|
||
fputs("1;mourning\n", F);
|
||
}
|
||
}
|
||
if (r->land->ownership) {
|
||
fprintf(F, "%d;morale\n", r->land->morale);
|
||
}
|
||
}
|
||
|
||
/* this writes both some tags (RESOURCECOMPAT) and a block.
|
||
* must not write any blocks before it */
|
||
cr_output_resources(F, ctx, sr);
|
||
|
||
if (sr->mode >= see_unit) {
|
||
/* trade */
|
||
if (markets_module() && r->land) {
|
||
const item_type *lux = r_luxury(r);
|
||
const item_type *herb = r->land->herbtype;
|
||
if (lux || herb) {
|
||
fputs("PREISE\n", F);
|
||
if (lux) {
|
||
const char *ch = resourcename(lux->rtype, 0);
|
||
fprintf(F, "%d;%s\n", 1, translate(ch,
|
||
locale_string(f->locale, ch)));
|
||
}
|
||
if (herb) {
|
||
const char *ch = resourcename(herb->rtype, 0);
|
||
fprintf(F, "%d;%s\n", 1, translate(ch,
|
||
locale_string(f->locale, ch)));
|
||
}
|
||
}
|
||
}
|
||
else if (rpeasants(r) / TRADE_FRACTION > 0) {
|
||
struct demand *dmd = r->land->demands;
|
||
fputs("PREISE\n", F);
|
||
while (dmd) {
|
||
const char *ch = resourcename(dmd->type->itype->rtype, 0);
|
||
fprintf(F, "%d;%s\n", (dmd->value
|
||
? dmd->value * dmd->type->price
|
||
: -dmd->type->price),
|
||
translate(ch, locale_string(f->locale, ch)));
|
||
dmd = dmd->next;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
if (r->land) {
|
||
print_items(F, r->land->items, f->locale);
|
||
}
|
||
cr_output_curses(F, f, r, TYP_REGION);
|
||
cr_borders(ctx->seen, r, f, sr->mode, F);
|
||
if (sr->mode == see_unit && is_astral(r)
|
||
&& !is_cursed(r->attribs, C_ASTRALBLOCK, 0)) {
|
||
/* Sonderbehandlung Teleport-Ebene */
|
||
region_list *rl = astralregions(r, inhabitable);
|
||
|
||
if (rl) {
|
||
region_list *rl2 = rl;
|
||
while (rl2) {
|
||
region *r = rl2->data;
|
||
int nx = r->x, ny = r->y;
|
||
plane *plx = rplane(r);
|
||
|
||
pnormalize(&nx, &ny, plx);
|
||
adjust_coordinates(f, &nx, &ny, plx, r);
|
||
fprintf(F, "SCHEMEN %d %d\n", nx, ny);
|
||
fprintf(F, "\"%s\";Name\n", rname(r, f->locale));
|
||
rl2 = rl2->next;
|
||
}
|
||
free_regionlist(rl);
|
||
}
|
||
}
|
||
|
||
/* describe both passed and inhabited regions */
|
||
show_active_spells(r);
|
||
if (fval(r, RF_TRAVELUNIT)) {
|
||
bool seeunits = false, seeships = false;
|
||
const attrib *ru;
|
||
/* show units pulled through region */
|
||
for (ru = a_find(r->attribs, &at_travelunit);
|
||
ru && ru->type == &at_travelunit; ru = ru->next) {
|
||
unit *u = (unit *)ru->data.v;
|
||
if (cansee_durchgezogen(f, r, u, 0) && r != u->region) {
|
||
if (u->ship && ship_owner(u->ship) == u) {
|
||
if (!seeships) {
|
||
fprintf(F, "DURCHSCHIFFUNG\n");
|
||
}
|
||
seeships = true;
|
||
fprintf(F, "\"%s\"\n", shipname(u->ship));
|
||
}
|
||
}
|
||
}
|
||
for (ru = a_find(r->attribs, &at_travelunit);
|
||
ru && ru->type == &at_travelunit; ru = ru->next) {
|
||
unit *u = (unit *)ru->data.v;
|
||
if (cansee_durchgezogen(f, r, u, 0) && r != u->region) {
|
||
if (!u->ship) {
|
||
if (!seeunits) {
|
||
fprintf(F, "DURCHREISE\n");
|
||
}
|
||
seeunits = true;
|
||
fprintf(F, "\"%s\"\n", unitname(u));
|
||
}
|
||
}
|
||
}
|
||
}
|
||
cr_output_messages(F, r->msgs, f);
|
||
{
|
||
message_list *mlist = r_getmessages(r, f);
|
||
if (mlist)
|
||
cr_output_messages(F, mlist, f);
|
||
}
|
||
/* buildings */
|
||
for (b = rbuildings(r); b; b = b->next) {
|
||
int fno = -1;
|
||
u = building_owner(b);
|
||
if (u && !fval(u, UFL_ANON_FACTION)) {
|
||
const faction *sf = visible_faction(f, u);
|
||
fno = sf->no;
|
||
}
|
||
cr_output_building(F, b, u, fno, f);
|
||
}
|
||
|
||
/* ships */
|
||
for (sh = r->ships; sh; sh = sh->next) {
|
||
int fno = -1;
|
||
u = ship_owner(sh);
|
||
if (u && !fval(u, UFL_ANON_FACTION)) {
|
||
const faction *sf = visible_faction(f, u);
|
||
fno = sf->no;
|
||
}
|
||
|
||
cr_output_ship(F, sh, u, fno, f, r);
|
||
}
|
||
|
||
/* visible units */
|
||
for (u = r->units; u; u = u->next) {
|
||
|
||
if (u->building || u->ship || (stealthmod > INT_MIN
|
||
&& cansee(f, r, u, stealthmod))) {
|
||
cr_output_unit(F, r, f, u, sr->mode);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
/* 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)
|
||
{
|
||
static int era = -1;
|
||
int i;
|
||
faction *f = ctx->f;
|
||
const char *prefix;
|
||
region *r;
|
||
const char *mailto = locale_string(f->locale, "mailto");
|
||
const attrib *a;
|
||
seen_region *sr = NULL;
|
||
#if SCORE_MODULE
|
||
int score = 0, avgscore = 0;
|
||
#endif
|
||
FILE *F = fopen(filename, "wt");
|
||
|
||
if (era < 0) {
|
||
era = get_param_int(global.parameters, "world.era", 2);
|
||
}
|
||
if (F == NULL) {
|
||
perror(filename);
|
||
return -1;
|
||
}
|
||
else if (_strcmpl(charset, "utf-8") == 0 || _strcmpl(charset, "utf8") == 0) {
|
||
const unsigned char utf8_bom[4] = { 0xef, 0xbb, 0xbf, 0 };
|
||
fwrite(utf8_bom, 1, 3, F);
|
||
}
|
||
|
||
/* must call this to get all the neighbour regions */
|
||
/* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
|
||
/* initialisations, header and lists */
|
||
|
||
fprintf(F, "VERSION %d\n", C_REPORT_VERSION);
|
||
fprintf(F, "\"%s\";charset\n", charset);
|
||
fprintf(F, "\"%s\";locale\n", locale_name(f->locale));
|
||
fprintf(F, "%d;noskillpoints\n", 1);
|
||
fprintf(F, "%ld;date\n", ctx->report_time);
|
||
fprintf(F, "\"%s\";Spiel\n", game_name());
|
||
fprintf(F, "\"%s\";Konfiguration\n", "Standard");
|
||
fprintf(F, "\"%s\";Koordinaten\n", "Hex");
|
||
fprintf(F, "%d;max_units\n", rule_faction_limit());
|
||
fprintf(F, "%d;Basis\n", 36);
|
||
fprintf(F, "%d;Runde\n", turn);
|
||
fprintf(F, "%d;Zeitalter\n", era);
|
||
fprintf(F, "%d.%d.%d;Build\n", VERSION_MAJOR, VERSION_MINOR, VERSION_BUILD);
|
||
if (mailto != NULL) {
|
||
fprintf(F, "\"%s\";mailto\n", mailto);
|
||
fprintf(F, "\"%s\";mailcmd\n", locale_string(f->locale, "mailcmd"));
|
||
}
|
||
|
||
show_alliances_cr(F, f);
|
||
|
||
fprintf(F, "PARTEI %d\n", f->no);
|
||
fprintf(F, "\"%s\";locale\n", locale_name(f->locale));
|
||
if (f_get_alliance(f)) {
|
||
fprintf(F, "%d;alliance\n", f->alliance->id);
|
||
fprintf(F, "%d;joined\n", f->alliance_joindate);
|
||
}
|
||
fprintf(F, "%d;age\n", f->age);
|
||
fprintf(F, "%d;Optionen\n", f->options);
|
||
#if SCORE_MODULE
|
||
if (f->options & want(O_SCORE) && f->age > DISPLAYSCORE) {
|
||
score = f->score;
|
||
avgscore = average_score_of_age(f->age, f->age / 24 + 1);
|
||
}
|
||
fprintf(F, "%d;Punkte\n", score);
|
||
fprintf(F, "%d;Punktedurchschnitt\n", avgscore);
|
||
#endif
|
||
{
|
||
const char *zRace = rc_name_s(f->race, NAME_PLURAL);
|
||
fprintf(F, "\"%s\";Typ\n", translate(zRace, LOC(f->locale, zRace)));
|
||
}
|
||
prefix = get_prefix(f->attribs);
|
||
if (prefix != NULL) {
|
||
prefix = mkname("prefix", prefix);
|
||
fprintf(F, "\"%s\";typprefix\n",
|
||
translate(prefix, LOC(f->locale, prefix)));
|
||
}
|
||
fprintf(F, "%d;Rekrutierungskosten\n", f->race->recruitcost);
|
||
fprintf(F, "%d;Anzahl Personen\n", count_all(f));
|
||
fprintf(F, "\"%s\";Magiegebiet\n", magic_school[f->magiegebiet]);
|
||
|
||
if (f->race == get_race(RC_HUMAN)) {
|
||
fprintf(F, "%d;Anzahl Immigranten\n", count_migrants(f));
|
||
fprintf(F, "%d;Max. Immigranten\n", count_maxmigrants(f));
|
||
}
|
||
|
||
i = countheroes(f);
|
||
if (i > 0)
|
||
fprintf(F, "%d;heroes\n", i);
|
||
i = maxheroes(f);
|
||
if (i > 0)
|
||
fprintf(F, "%d;max_heroes\n", i);
|
||
|
||
if (f->age > 1 && f->lastorders != turn) {
|
||
fprintf(F, "%d;nmr\n", turn - f->lastorders);
|
||
}
|
||
|
||
fprintf(F, "\"%s\";Parteiname\n", f->name);
|
||
fprintf(F, "\"%s\";email\n", f->email);
|
||
if (f->banner)
|
||
fprintf(F, "\"%s\";banner\n", f->banner);
|
||
print_items(F, f->items, f->locale);
|
||
fputs("OPTIONEN\n", F);
|
||
for (i = 0; i != MAXOPTIONS; ++i) {
|
||
int flag = want(i);
|
||
if (options[i]) {
|
||
fprintf(F, "%d;%s\n", (f->options & flag) ? 1 : 0, options[i]);
|
||
}
|
||
else if (f->options & flag) {
|
||
f->options &= (~flag);
|
||
}
|
||
}
|
||
show_allies_cr(F, f, f->allies);
|
||
{
|
||
group *g;
|
||
for (g = f->groups; g; g = g->next) {
|
||
|
||
fprintf(F, "GRUPPE %d\n", g->gid);
|
||
fprintf(F, "\"%s\";name\n", g->name);
|
||
prefix = get_prefix(g->attribs);
|
||
if (prefix != NULL) {
|
||
prefix = mkname("prefix", prefix);
|
||
fprintf(F, "\"%s\";typprefix\n",
|
||
translate(prefix, LOC(f->locale, prefix)));
|
||
}
|
||
show_allies_cr(F, f, g->allies);
|
||
}
|
||
}
|
||
|
||
cr_output_messages(F, f->msgs, f);
|
||
{
|
||
struct bmsg *bm;
|
||
for (bm = f->battles; bm; bm = bm->next) {
|
||
plane *pl = rplane(bm->r);
|
||
int plid = plane_id(pl);
|
||
region *r = bm->r;
|
||
int nx = r->x, ny = r->y;
|
||
|
||
pnormalize(&nx, &ny, pl);
|
||
adjust_coordinates(f, &nx, &ny, pl, r);
|
||
if (!plid)
|
||
fprintf(F, "BATTLE %d %d\n", nx, ny);
|
||
else {
|
||
fprintf(F, "BATTLE %d %d %d\n", nx, ny, plid);
|
||
}
|
||
cr_output_messages(F, bm->msgs, f);
|
||
}
|
||
}
|
||
|
||
cr_find_address(F, f, ctx->addresses);
|
||
a = a_find(f->attribs, &at_reportspell);
|
||
while (a && a->type == &at_reportspell) {
|
||
spellbook_entry *sbe = (spellbook_entry *)a->data.v;
|
||
cr_reportspell(F, sbe->sp, sbe->level, f->locale);
|
||
a = a->next;
|
||
}
|
||
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 *ch;
|
||
const char *description = NULL;
|
||
|
||
if (ptype == NULL)
|
||
continue;
|
||
ch = resourcename(ptype->itype->rtype, 0);
|
||
fprintf(F, "TRANK %d\n", hashstring(ch));
|
||
fprintf(F, "\"%s\";Name\n", translate(ch, locale_string(f->locale,
|
||
ch)));
|
||
fprintf(F, "%d;Stufe\n", ptype->level);
|
||
|
||
if (description == NULL) {
|
||
const char *pname = resourcename(ptype->itype->rtype, 0);
|
||
const char *potiontext = mkname("potion", pname);
|
||
description = LOC(f->locale, potiontext);
|
||
}
|
||
|
||
fprintf(F, "\"%s\";Beschr\n", description);
|
||
if (ptype->itype->construction) {
|
||
requirement *m = ptype->itype->construction->materials;
|
||
|
||
fprintf(F, "ZUTATEN\n");
|
||
|
||
while (m->number) {
|
||
ch = resourcename(m->rtype, 0);
|
||
fprintf(F, "\"%s\"\n", translate(ch, locale_string(f->locale,
|
||
ch)));
|
||
m++;
|
||
}
|
||
}
|
||
}
|
||
|
||
/* traverse all regions */
|
||
for (r = ctx->first; sr == NULL && r != ctx->last; r = r->next) {
|
||
sr = find_seen(ctx->seen, r);
|
||
}
|
||
for (; sr != NULL; sr = sr->next) {
|
||
cr_output_region(F, ctx, sr);
|
||
}
|
||
report_crtypes(F, f->locale);
|
||
write_translations(F);
|
||
reset_translations();
|
||
fclose(F);
|
||
return 0;
|
||
}
|
||
|
||
int crwritemap(const char *filename)
|
||
{
|
||
FILE *F = fopen(filename, "w");
|
||
region *r;
|
||
|
||
fprintf(F, "VERSION %d\n", C_REPORT_VERSION);
|
||
fputs("\"UTF-8\";charset\n", F);
|
||
|
||
for (r = regions; r; r = r->next) {
|
||
plane *pl = rplane(r);
|
||
int plid = plane_id(pl);
|
||
if (plid) {
|
||
fprintf(F, "REGION %d %d %d\n", r->x, r->y, plid);
|
||
}
|
||
else {
|
||
fprintf(F, "REGION %d %d\n", r->x, r->y);
|
||
}
|
||
fprintf(F, "\"%s\";Name\n\"%s\";Terrain\n", rname(r, default_locale),
|
||
LOC(default_locale, terrain_name(r)));
|
||
}
|
||
fclose(F);
|
||
return 0;
|
||
}
|
||
|
||
void register_cr(void)
|
||
{
|
||
tsf_register("report", &cr_ignore);
|
||
tsf_register("string", &cr_string);
|
||
tsf_register("order", &cr_order);
|
||
tsf_register("spell", &cr_spell);
|
||
tsf_register("curse", &cr_curse);
|
||
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);
|
||
tsf_register("race", &cr_race);
|
||
tsf_register("direction", &cr_int);
|
||
tsf_register("alliance", &cr_alliance);
|
||
tsf_register("resources", &cr_resources);
|
||
tsf_register("items", &cr_resources);
|
||
tsf_register("regions", &cr_regions);
|
||
|
||
if (!nocr)
|
||
register_reporttype("cr", &report_computer, 1 << O_COMPUTER);
|
||
}
|
||
|
||
void creport_cleanup(void)
|
||
{
|
||
while (junkyard) {
|
||
translation *t = junkyard;
|
||
junkyard = junkyard->next;
|
||
free(t);
|
||
}
|
||
junkyard = 0;
|
||
}
|