code cleanup, reports. report types are now registered (some code I had on my disk since the days I was writing xml reports), and a new mailit format (reports.txt replaces mailit). Also, no more writing of shellscripts from the server, since that's done by an external script now.

This commit is contained in:
Enno Rehling 2005-11-02 21:10:40 +00:00
parent cc7a1d15bb
commit d2a75f15fe
10 changed files with 604 additions and 670 deletions

View File

@ -404,37 +404,6 @@ cr_spell(variant var, char * buffer, const void * userdata)
return 0;
}
void
creport_init(void)
{
tsf_register("report", &cr_ignore);
tsf_register("string", &cr_string);
tsf_register("order", &cr_order);
tsf_register("spell", &cr_spell);
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);
}
void
creport_cleanup(void)
{
while (junkyard) {
translation * t = junkyard;
junkyard = junkyard->next;
free(t);
}
junkyard = 0;
}
/*static int msgno; */
#define MTMAXHASH 1021
@ -1071,11 +1040,11 @@ cr_borders(seen_region ** seen, const region * r, const faction * f, int seemode
}
/* main function of the creport. creates the header and traverses all regions */
int
report_computer(FILE * F, faction * f, struct seen_region ** seen, const faction_list * addresses,
const time_t report_time)
static int
report_computer(FILE * F, report_context * ctx)
{
int i;
faction * f = ctx->f;
item * itm;
const char * prefix;
region * r;
@ -1090,14 +1059,14 @@ report_computer(FILE * F, faction * f, struct seen_region ** seen, const faction
#endif
/* must call this to get all the neighbour regions */
get_seen_interval(seen, &first, &last);
get_seen_interval(ctx->seen, &first, &last);
/* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
/* initialisations, header and lists */
fprintf(F, "VERSION %d\n", C_REPORT_VERSION);
fprintf(F, "\"%s\";locale\n", locale_name(f->locale));
fprintf(F, "%d;noskillpoints\n", 1);
fprintf(F, "%ld;date\n", report_time);
fprintf(F, "%ld;date\n", ctx->report_time);
fprintf(F, "\"%s\";Spiel\n", global.gamename);
fprintf(F, "\"%s\";Konfiguration\n", "Standard");
fprintf(F, "\"%s\";Koordinaten\n", "Hex");
@ -1196,7 +1165,7 @@ report_computer(FILE * F, faction * f, struct seen_region ** seen, const faction
}
}
cr_find_address(F, f, addresses);
cr_find_address(F, f, ctx->addresses);
a = a_find(f->attribs, &at_reportspell);
while (a) {
cr_reportspell(F, (spellid_t)a->data.i, f->locale);
@ -1234,7 +1203,7 @@ report_computer(FILE * F, faction * f, struct seen_region ** seen, const faction
for (r=first;r!=last;r=r->next) {
int modifier = 0;
const char * tname;
const seen_region * sd = find_seen(seen, r);
const seen_region * sd = find_seen(ctx->seen, r);
if (sd==NULL) continue;
@ -1278,7 +1247,7 @@ report_computer(FILE * F, faction * f, struct seen_region ** seen, const faction
}
}
if (sd->mode == see_neighbour) {
cr_borders(seen, r, f, sd->mode, F);
cr_borders(ctx->seen, r, f, sd->mode, F);
} else {
#define RESOURCECOMPAT
char cbuf[8192], *pos = cbuf;
@ -1371,7 +1340,7 @@ report_computer(FILE * F, faction * f, struct seen_region ** seen, const faction
if (pos!=cbuf) fputs(cbuf, F);
}
print_curses(F, f, r, TYP_REGION);
cr_borders(seen, r, f, sd->mode, F);
cr_borders(ctx->seen, r, f, sd->mode, F);
if (sd->mode==see_unit && rplane(r)==get_astralplane() && !is_cursed(r->attribs, C_ASTRALBLOCK, 0))
{
/* Sonderbehandlung Teleport-Ebene */
@ -1489,3 +1458,36 @@ crwritemap(const char * filename)
return 0;
}
void
creport_init(void)
{
tsf_register("report", &cr_ignore);
tsf_register("string", &cr_string);
tsf_register("order", &cr_order);
tsf_register("spell", &cr_spell);
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);
register_reporttype("cr", &report_computer, 1<<O_COMPUTER);
}
void
creport_cleanup(void)
{
while (junkyard) {
translation * t = junkyard;
junkyard = junkyard->next;
free(t);
}
junkyard = 0;
}

View File

@ -17,17 +17,9 @@ extern "C" {
#include <time.h>
struct faction_list;
struct seen_region;
struct faction;
extern int report_computer(FILE * F, struct faction * f, struct seen_region ** seen,
const struct faction_list * addresses, const time_t report_time);
extern void creport_cleanup(void);
extern void creport_init(void);
extern void report_init(void);
extern void report_cleanup(void);
extern int crwritemap(const char * filename);
#ifdef __cplusplus

View File

@ -835,28 +835,6 @@ forget_cmd(unit * u, order * ord)
return 0;
}
/* ------------------------------------------------------------- */
void
report_donations(void)
{
region * r;
for (r=regions;r;r=r->next) {
while (r->donations) {
donation * sp = r->donations;
if (sp->amount > 0) {
struct message * msg = msg_message("donation",
"from to amount", sp->f1, sp->f2, sp->amount);
r_addmessage(r, sp->f1, msg);
r_addmessage(r, sp->f2, msg);
msg_release(msg);
}
r->donations = sp->next;
free(sp);
}
}
}
void
add_spende(faction * f1, faction * f2, int amount, region * r)
{

View File

@ -53,7 +53,6 @@ void produce(void);
enum { IC_WORK, IC_ENTERTAIN, IC_TAX, IC_TRADE, IC_TRADETAX, IC_STEAL, IC_MAGIC };
void maintain_buildings(boolean crash);
extern void add_spende(struct faction * f1, struct faction * f2, int betrag, struct region * r);
void report_donations(void);
extern void init_economy(void);
#ifdef __cplusplus

View File

@ -200,6 +200,9 @@
<File
RelativePath=".\randenc.h">
</File>
<File
RelativePath=".\report.h">
</File>
</Filter>
<File
RelativePath=".\creation.c">

View File

@ -71,7 +71,6 @@
/* util includes */
#include <util/bsdstring.h>
#include <functions.h>
#include <goodies.h>
#include <base36.h>
#include <nrmessage.h>
@ -113,16 +112,6 @@ strxcpy(char * dst, const char * src) {
return s;
}
static const char*
MailitPath(void)
{
static const char * value = NULL;
if (value==NULL) {
value = get_param(global.parameters, "report.mailit");
}
return value;
}
int
read_datenames(const char *filename)
{
@ -531,26 +520,6 @@ report_spell(FILE * F, spellid_t id, const struct locale * lang)
rnl(F);
}
void
nmr_warnings(void)
{
faction *f,*fa;
#define FRIEND (HELP_GUARD|HELP_MONEY)
for(f=factions;f;f=f->next) {
if(f->no != MONSTER_FACTION && (turn-f->lastorders) >= 2) {
for(fa=factions;fa;fa=fa->next) {
if (alliedfaction(NULL, f, fa, FRIEND) && alliedfaction(NULL, fa, f, FRIEND)) {
sprintf(buf, "Achtung: %s hat einige Zeit keine "
"Züge eingeschickt und könnte dadurch in Kürze aus dem "
"Spiel ausscheiden.", factionname(f));
addmessage(0, fa, buf, MSG_EVENT, ML_WARN);
}
}
}
}
}
void
sparagraph(strlist ** SP, const char *s, int indent, char mark)
{
@ -1448,8 +1417,9 @@ buildingmaintenance(const building * b, const resource_type * rtype)
}
static int
order_template(FILE * F, faction * f)
report_template(FILE * F, report_context * ctx)
{
faction * f = ctx->f;
region *r;
plane *pl;
region *last = lastregion(f);
@ -1923,28 +1893,27 @@ report_building(FILE *F, const region * r, const building * b, const faction * f
rpunit(F, f, u, 6, mode);
}
static int
report(FILE *F, faction * f, struct seen_region ** seen, const faction_list * addresses,
const char * pzTime)
int
report_plaintext(FILE *F, report_context * ctx)
{
int flag = 0;
char ch;
int dh;
int anyunits;
const struct region *r;
region * last = lastregion(f);
faction * f = ctx->f;
building *b;
ship *sh;
unit *u;
char pzTime[64];
attrib *a;
message * m;
int wants_stats;
int ix;
unsigned char op;
char buf2[80];
ix = Pow(O_STATISTICS);
wants_stats = (f->options & ix);
region * last = lastregion(f);
int ix = Pow(O_STATISTICS);
int wants_stats = (f->options & ix);
strftime(pzTime, 64, "%A, %d. %B %Y, %H:%M", localtime(&ctx->report_time));
m = msg_message("nr_header_date", "game date", global.gamename, pzTime);
nr_render(m, f->locale, buf, sizeof(buf), f);
msg_release(m);
@ -1964,6 +1933,7 @@ report(FILE *F, faction * f, struct seen_region ** seen, const faction_list * ad
buf[0] = 0;
dh = 0;
for (a=a_find(f->attribs, &at_faction_special); a; a=a->nexttype) {
char buf2[80];
dh++;
if(fspecials[a->data.sa[0]].maxlevel != 100) {
sprintf(buf2, "%s (%d)", fspecials[a->data.sa[0]].name, a->data.sa[1]);
@ -2182,7 +2152,7 @@ report(FILE *F, faction * f, struct seen_region ** seen, const faction_list * ad
boolean unit_in_region = false;
boolean durchgezogen_in_region = false;
int turm_sieht_region = false;
seen_region * sd = find_seen(seen, r);
seen_region * sd = find_seen(ctx->seen, r);
if (sd==NULL) continue;
switch (sd->mode) {
@ -2345,60 +2315,12 @@ report(FILE *F, faction * f, struct seen_region ** seen, const faction_list * ad
rnl(F);
rparagraph(F, LOC(f->locale, "nr_youaredead"), 0, 0);
} else {
list_address(F, f, addresses);
list_address(F, f, ctx->addresses);
}
}
return 0;
}
FILE *
openbatch(void)
{
faction *f;
FILE * BAT = NULL;
/* falls und mind. ein internet spieler gefunden wird, schreibe den
* header des batch files. ab nun kann BAT verwendet werden, um zu
* pruefen, ob netspieler vorhanden sind und ins mailit batch
* geschrieben werden darf. */
for (f = factions; f; f = f->next) {
/* bei "internet:" verschicken wir die mail per batchfile. für
* unix kann man alles in EIN batchfile schreiben, als
* sogenanntes "herefile". Konnte der batchfile nicht geoeffnet
* werden, schreiben wir die reports einzeln. der BAT file wird
* nur gemacht, wenn es auch internet benutzer gibt. */
if (f->email) {
sprintf(buf, "%s/mailit", reportpath());
if ((BAT = fopen(buf, "w")) == NULL)
log_error(("mailit konnte nicht geöffnet werden!\n"));
else
fprintf(BAT,
"#!/bin/sh\n\n"
"# MAILIT shell file, vom Eressea Host generiert\n#\n"
"# Verwendung: nohup mailit &\n#\n\n"
"PATH=%s\n\n"
"chmod 755 *.sh\n"
"\n", MailitPath());
break;
}
}
return BAT;
}
void
closebatch(FILE * BAT)
{
if (BAT) {
fputs("\n", BAT);
fclose(BAT);
}
}
void
base36conversion(void)
{
@ -2415,249 +2337,6 @@ base36conversion(void)
}
}
extern void init_intervals(void);
static void
view_default(struct seen_region ** seen, region *r, faction *f)
{
direction_t dir;
for (dir=0;dir!=MAXDIRECTIONS;++dir) {
region * r2 = rconnect(r, dir);
if (r2) {
border * b = get_borders(r, r2);
while (b) {
if (!b->type->transparent(b, f)) break;
b = b->next;
}
if (!b) add_seen(seen, r2, see_neighbour, false);
}
}
}
static void
view_neighbours(struct seen_region ** seen, region * r, faction * f)
{
direction_t dir;
for (dir=0;dir!=MAXDIRECTIONS;++dir) {
region * r2 = rconnect(r, dir);
if (r2) {
border * b = get_borders(r, r2);
while (b) {
if (!b->type->transparent(b, f)) break;
b = b->next;
}
if (!b) {
if (add_seen(seen, r2, see_far, false)) {
if (!(fval(r2->terrain, FORBIDDEN_REGION))) {
direction_t dir;
for (dir=0;dir!=MAXDIRECTIONS;++dir) {
region * r3 = rconnect(r2, dir);
if (r3) {
border * b = get_borders(r2, r3);
while (b) {
if (!b->type->transparent(b, f)) break;
b = b->next;
}
if (!b) add_seen(seen, r3, see_neighbour, false);
}
}
}
}
}
}
}
}
static void
recurse_regatta(struct seen_region ** seen, region *center, region *r, faction *f, int maxdist)
{
direction_t dir;
int dist = distance(center, r);
for (dir=0;dir!=MAXDIRECTIONS;++dir) {
region * r2 = rconnect(r, dir);
if (r2) {
int ndist = distance(center, r2);
if (ndist>dist && fval(r2->terrain, SEA_REGION)) {
border * b = get_borders(r, r2);
while (b) {
if (!b->type->transparent(b, f)) break;
b = b->next;
}
if (!b) {
if (ndist<maxdist) {
if (add_seen(seen, r2, see_far, false)) {
recurse_regatta(seen, center, r2, f, maxdist);
}
} else add_seen(seen, r2, see_neighbour, false);
}
}
}
}
}
static void
view_regatta(struct seen_region ** seen, region * r, faction * f)
{
unit *u;
int skill = 0;
for (u=r->units; u; u=u->next) {
if (u->faction==f) {
int es = effskill(u, SK_OBSERVATION);
if (es>skill) skill=es;
}
}
recurse_regatta(seen, r, r, f, skill/2);
}
static void
global_report(const char * filename)
{
FILE * F = fopen(filename, "w");
region * r;
faction * f;
faction * monsters = findfaction(MONSTER_FACTION);
faction_list * addresses = NULL;
struct seen_region ** seen;
if (!monsters) return;
if (!F) return;
/* list of all addresses */
for (f=factions;f;f=f->next) {
faction_list * flist = calloc(1, sizeof(faction_list));
flist->data = f;
flist->next = addresses;
addresses = flist;
}
seen = seen_init();
for (r = regions; r; r = r->next) {
add_seen(seen, r, see_unit, true);
}
report_computer(F, monsters, seen, addresses, time(NULL));
freelist(addresses);
seen_done(seen);
fclose(F);
}
region_list *
get_regions_distance(region * root, int radius)
{
region_list * rptr, * rlist = NULL;
region_list ** rp = &rlist;
add_regionlist(rp, root);
fset(root, FL_MARK);
while (*rp) {
region_list * r = *rp;
direction_t d;
rp = &r->next;
for (d=0;d!=MAXDIRECTIONS;++d) {
region * rn = rconnect(r->data, d);
if (rn!=NULL && !fval(rn, FL_MARK) && distance(rn, root)<=radius) {
add_regionlist(rp, rn);
fset(rn, FL_MARK);
}
}
}
for (rptr=rlist;rptr;rptr=rptr->next) {
freset(rptr->data, FL_MARK);
}
return rlist;
}
static struct seen_region **
prepare_report(faction * f)
{
region * r;
region * end = lastregion(f);
struct seen_region ** seen = seen_init();
static const struct building_type * bt_lighthouse = NULL;
if (bt_lighthouse==NULL) bt_lighthouse = bt_find("lighthouse");
for (r = firstregion(f); r != end; r = r->next) {
attrib *ru;
unit * u;
plane * p = rplane(r);
unsigned char mode = see_none;
boolean dis = false;
int light = 0;
if (p) {
watcher * w = p->watchers;
while (w) {
if (f==w->faction) {
mode = w->mode;
break;
}
w = w->next;
}
}
for (u = r->units; u; u = u->next) {
if (u->faction == f) {
if (u->building && u->building->type==bt_lighthouse) {
int r = lighthouse_range(u->building, f);
if (r>light) light = r;
}
if (u->race != new_race[RC_SPELL] || u->number == RS_FARVISION) {
mode = see_unit;
if (fval(u, UFL_DISBELIEVES)) {
dis = true;
break;
}
}
}
}
if (light) {
/* we are in a lighthouse. add the others! */
region_list * rlist = get_regions_distance(r, light);
region_list * rp = rlist;
while (rp) {
region * rl = rp->data;
if (fval(rl->terrain, SEA_REGION)) {
direction_t d;
add_seen(seen, rl, see_lighthouse, false);
for (d=0;d!=MAXDIRECTIONS;++d) {
region * rn = rconnect(rl, d);
if (rn!=NULL) {
add_seen(seen, rn, see_neighbour, false);
}
}
}
rp = rp->next;
}
free_regionlist(rlist);
}
if (mode<see_travel && fval(r, RF_TRAVELUNIT)) {
for (ru = a_find(r->attribs, &at_travelunit); ru; ru = ru->nexttype) {
unit * u = (unit*)ru->data.v;
if (u->faction == f) {
mode = see_travel;
break;
}
}
}
if (mode == see_none)
continue;
add_seen(seen, r, mode, dis);
/* nicht, wenn Verwirrung herrscht: */
if (!is_cursed(r->attribs, C_REGCONF, 0)) {
void (*view)(struct seen_region **, region * r, faction * f) = view_default;
if (p && fval(p, PFL_SEESPECIAL)) {
attrib * a = a_find(p->attribs, &at_viewrange);
if (a) view = (void (*)(struct seen_region **, region * r, faction * f))a->data.f;
}
view(seen, r, f);
}
}
return seen;
}
#define FMAXHASH 1021
struct fsee {
@ -2676,81 +2355,6 @@ struct fsee {
#define REPORT_ZIP (1 << O_COMPRESS)
#define REPORT_BZIP2 (1 << O_BZIP2)
int
write_reports(faction * f, time_t ltime)
{
FILE * F;
boolean gotit = false;
faction_list * addresses;
char zTime[64];
struct seen_region ** seen = prepare_report(f);
strftime(zTime, sizeof(zTime), "%A, %d. %B %Y, %H:%M", localtime(&ltime));
printf("Reports for %s: \r", factionname(f));
fflush(stdout);
addresses = get_addresses(f, seen);
/* NR schreiben: */
if (!nonr && (f->options & REPORT_NR)) {
fprintf(stdout, "Reports for %s: NR\r", factionname(f));
fflush(stdout);
sprintf(buf, "%s/%d-%s.nr", reportpath(), turn, factionid(f));
F = cfopen(buf, "wt");
if (F) {
int status = report(F, f, seen, addresses, zTime);
fclose(F);
gotit = true;
if (status!=0) {
seen_done(seen);
return status; /* catch errors */
}
}
}
/* CR schreiben: */
if (!nocr && (f->options & REPORT_CR || f->age<3)) {
fprintf(stdout, "Reports for %s: CR\r", factionname(f));
fflush(stdout);
sprintf(buf, "%s/%d-%s.cr", reportpath(), turn, factionid(f));
F = cfopen(buf, "wt");
if (F) {
int status = report_computer(F, f, seen, addresses, ltime);
fclose(F);
gotit = true;
if (status!=0) {
seen_done(seen);
return status; /* catch errors */
}
}
}
/* ZV schreiben: */
if (f->options & REPORT_ZV) {
fprintf(stdout, "Reports for %s: ZV\r", factionname(f));
fflush(stdout);
sprintf(buf, "%s/%d-%s.txt", reportpath(), turn, factionid(f));
F = cfopen(buf, "wt");
if (F) {
int status = order_template(F, f);
fclose(F);
if (status!=0) {
seen_done(seen);
return status; /* catch errors */
}
}
}
fprintf(stdout, "Reports for %s: DONE\n", factionname(f));
if (!gotit) {
log_warning(("No report for faction %s!\n", factionid(f)));
}
freelist(addresses);
seen_done(seen);
return 0;
}
int
init_reports(void)
{
@ -2771,136 +2375,6 @@ init_reports(void)
return 0;
}
int
reports(void)
{
faction *f;
FILE *shfp, *BAT;
time_t ltime = time(NULL);
const char * str;
int retval = 0;
nmr_warnings();
report_donations();
remove_empty_units();
BAT = openbatch();
for (f = factions; f; f = f->next) {
int error = write_reports(f, ltime);
if (error) retval = error;
if (!nosh && f->email && strlen(f->email) && BAT) {
sprintf(buf, "%s/%s.sh", reportpath(), factionid(f));
shfp = fopen(buf, "w");
fprintf(shfp,"#!/bin/sh\n\nPATH=%s\n\n",MailitPath());
fprintf(shfp,"if [ $# -ge 1 ]; then\n");
fprintf(shfp,"\taddr=$1\n");
fprintf(shfp,"else\n");
fprintf(shfp,"\taddr=%s\n", f->email);
fprintf(shfp,"fi\n\n");
fprintf(BAT, "\n\ndate;echo %s\n", f->email);
if (f->options & REPORT_ZIP) {
fprintf(BAT, "ls %d-%s.nr %d-%s.txt %d-%s.cr | zip -m -j -9 -@ %d-%s.zip\n",
turn, factionid(f),
turn, factionid(f),
turn, factionid(f),
turn, factionid(f));
if (f->age == 1) {
fprintf(BAT, "zip -j -9 %d-%s.zip %s/%s/%s/welcome.txt\n",
turn, factionid(f), resourcepath(), global.welcomepath, locale_name(f->locale));
}
fprintf(shfp, "eresseamail.zipped $addr \"%s %s\" \"%d-%s.zip\" "
"%d-%s.zip\n", global.gamename, gamedate_short(f->locale),
turn, factionid(f),
turn, factionid(f));
} else if(f->options & REPORT_BZIP2) {
fprintf(BAT, "bzip2 -9v `ls %d-%s.nr %d-%s.txt %d-%s.cr`\n",
turn, factionid(f),
turn, factionid(f),
turn, factionid(f));
fprintf(shfp, "eresseamail.bzip2 $addr \"%s %s\"", global.gamename, gamedate_short(f->locale));
if (!nonr && f->options & REPORT_NR)
fprintf(shfp,
" \\\n\t\"application/x-bzip2\" \"Report\" %d-%s.nr.bz2",
turn,factionid(f));
if (f->options & (1 << O_ZUGVORLAGE))
fprintf(shfp,
" \\\n\t\"application/x-bzip2\" \"Zugvorlage\" %d-%s.txt.bz2",
turn,factionid(f));
if (!nocr && (f->options & REPORT_CR || f->age<3))
fprintf(shfp,
" \\\n\t\"application/x-bzip2\" \"Computer-Report\" %d-%s.cr.bz2",
turn, factionid(f));
if (f->age == 1) {
fprintf(shfp,
" \\\n\t\"text/plain\" \"Willkommen\" %s/%s/%s/welcome.txt",
resourcepath(), global.welcomepath, locale_name(f->locale));
}
} else {
fprintf(shfp, MAIL " $addr \"%s %s\"", global.gamename, gamedate_short(f->locale));
if (!nonr && f->options & REPORT_NR)
fprintf(shfp,
" \\\n\t\"text/plain\" \"Report\" %d-%s.nr",
turn, factionid(f));
if (f->options & (1 << O_ZUGVORLAGE))
fprintf(shfp,
" \\\n\t\"text/plain\" \"Zugvorlage\" %d-%s.txt",
turn, factionid(f));
if (!nocr && (f->options & REPORT_CR || f->age<3))
fprintf(shfp,
" \\\n\t\"text/x-eressea-cr\" \"Computer-Report\" %d-%s.cr",
turn, factionid(f));
if (f->age == 1) {
fprintf(shfp,
" \\\n\t\"text/plain\" \"Willkommen\" %s/%s/%s/welcome.txt",
resourcepath(), global.welcomepath, locale_name(f->locale));
}
}
fprintf(BAT, ". %s.sh %s\n", factionid(f), f->email);
fclose(shfp);
}
}
str = get_param(global.parameters, "globalreport");
if (str!=NULL) {
sprintf(buf, "%s/%s.%u.cr", reportpath(), str, turn);
global_report(buf);
}
/* schliesst BAT und verschickt Zeitungen und Kommentare */
closebatch(BAT);
free_seen();
return retval;
}
void
report_cleanup(void)
{
int i;
for (i=0;i!=FMAXHASH;++i) {
while (fsee[i]) {
struct fsee * fs = fsee[i]->nexthash;
free(fsee[i]);
fsee[i] = fs;
}
}
}
unit *
can_find(faction * f, faction * f2)
@ -3737,35 +3211,10 @@ eval_int36(struct opstack ** stack, const void * userdata)
unused(userdata);
}
static variant
var_copy_string(variant x)
{
x.v = strdup((const char*)x.v);
return x;
}
static void
var_free_string(variant x)
{
free(x.v);
}
static variant
var_copy_order(variant x)
{
x.v = copy_order((order*)x.v);
return x;
}
static void
var_free_order(variant x)
{
free_order(x.v);
}
void
report_init(void)
{
/* register functions that turn message contents to readable strings */
add_function("alliance", &eval_alliance);
add_function("region", &eval_region);
add_function("weight", &eval_weight);
@ -3784,21 +3233,20 @@ report_init(void)
add_function("trail", &eval_trail);
add_function("spell", &eval_spell);
register_argtype("alliance", NULL, NULL, VAR_VOIDPTR);
register_argtype("building", NULL, NULL, VAR_VOIDPTR);
register_argtype("direction", NULL, NULL, VAR_INT);
register_argtype("faction", NULL, NULL, VAR_VOIDPTR);
register_argtype("race", NULL, NULL, VAR_VOIDPTR);
register_argtype("region", NULL, NULL, VAR_VOIDPTR);
register_argtype("resource", NULL, NULL, VAR_VOIDPTR);
register_argtype("ship", NULL, NULL, VAR_VOIDPTR);
register_argtype("skill", NULL, NULL, VAR_VOIDPTR);
register_argtype("spell", NULL, NULL, VAR_VOIDPTR);
register_argtype("unit", NULL, NULL, VAR_VOIDPTR);
register_argtype("int", NULL, NULL, VAR_INT);
register_argtype("string", var_free_string, var_copy_string, VAR_VOIDPTR);
register_argtype("order", var_free_order, var_copy_order, VAR_VOIDPTR);
register_function((pf_generic)view_neighbours, "view_neighbours");
register_function((pf_generic)view_regatta, "view_regatta");
register_reporttype("nr", &report_plaintext, 1<<O_REPORT);
register_reporttype("txt", &report_template, 1<<O_ZUGVORLAGE);
}
void
report_cleanup(void)
{
int i;
for (i=0;i!=FMAXHASH;++i) {
while (fsee[i]) {
struct fsee * fs = fsee[i]->nexthash;
free(fsee[i]);
fsee[i] = fs;
}
}
}

View File

@ -0,0 +1,25 @@
/* vi: set ts=2:
+-------------------+ Christian Schlittchen <corwin@amber.kn-bremen.de>
| | Enno Rehling <enno@eressea-pbem.de>
| Eressea PBEM host | Katja Zedel <katze@felidae.kn-bremen.de>
| (c) 1998 - 2003 | Henning Peters <faroul@beyond.kn-bremen.de>
| | Ingo Wilken <Ingo.Wilken@informatik.uni-oldenburg.de>
+-------------------+ Stefan Reich <reich@halbling.de>
This program may not be used, modified or distributed
without prior permission by the authors of Eressea.
*/
#ifndef H_GC_REPORT
#define H_GC_REPORT
#ifdef __cplusplus
extern "C" {
#endif
extern void report_init(void);
extern void report_cleanup(void);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -22,39 +22,44 @@
#include "reports.h"
/* kernel includes */
#include "building.h"
#include "faction.h"
#include "group.h"
#include "item.h"
#include "karma.h"
#include "magic.h"
#include "message.h"
#include "order.h"
#include "plane.h"
#include "race.h"
#include "region.h"
#include "ship.h"
#include "skill.h"
#include "unit.h"
#include <kernel/building.h>
#include <kernel/border.h>
#include <kernel/terrain.h>
#include <kernel/faction.h>
#include <kernel/group.h>
#include <kernel/item.h>
#include <kernel/karma.h>
#include <kernel/magic.h>
#include <kernel/message.h>
#include <kernel/order.h>
#include <kernel/plane.h>
#include <kernel/race.h>
#include <kernel/region.h>
#include <kernel/ship.h>
#include <kernel/skill.h>
#include <kernel/unit.h>
#ifdef USE_UGROUPS
# include "ugroup.h"
# include <kernel/ugroup.h>
# include <attributes/ugroup.h>
#endif
/* util includes */
#include <util/bsdstring.h>
#include <util/base36.h>
#include <util/functions.h>
#include <util/goodies.h>
/* libc includes */
#include <assert.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
/* attributes includes */
#include <attributes/follow.h>
#include <attributes/otherfaction.h>
#include <attributes/racename.h>
#include <attributes/viewrange.h>
const char * g_reportdir;
@ -1250,3 +1255,469 @@ add_seen(struct seen_region * seehash[], struct region * r, unsigned char mode,
return true;
}
typedef struct report_type {
struct report_type * next;
report_fun write;
const char * extension;
int flag;
} report_type;
static report_type * report_types;
void
register_reporttype(const char * extension, report_fun write, int flag)
{
report_type * type = malloc(sizeof(report_type));
type->extension = extension;
type->write = write;
type->flag = flag;
type->next = report_types;
report_types = type;
}
static region_list *
get_regions_distance(region * root, int radius)
{
region_list * rptr, * rlist = NULL;
region_list ** rp = &rlist;
add_regionlist(rp, root);
fset(root, FL_MARK);
while (*rp) {
region_list * r = *rp;
direction_t d;
rp = &r->next;
for (d=0;d!=MAXDIRECTIONS;++d) {
region * rn = rconnect(r->data, d);
if (rn!=NULL && !fval(rn, FL_MARK) && distance(rn, root)<=radius) {
add_regionlist(rp, rn);
fset(rn, FL_MARK);
}
}
}
for (rptr=rlist;rptr;rptr=rptr->next) {
freset(rptr->data, FL_MARK);
}
return rlist;
}
static void
view_default(struct seen_region ** seen, region *r, faction *f)
{
direction_t dir;
for (dir=0;dir!=MAXDIRECTIONS;++dir) {
region * r2 = rconnect(r, dir);
if (r2) {
border * b = get_borders(r, r2);
while (b) {
if (!b->type->transparent(b, f)) break;
b = b->next;
}
if (!b) add_seen(seen, r2, see_neighbour, false);
}
}
}
static void
view_neighbours(struct seen_region ** seen, region * r, faction * f)
{
direction_t dir;
for (dir=0;dir!=MAXDIRECTIONS;++dir) {
region * r2 = rconnect(r, dir);
if (r2) {
border * b = get_borders(r, r2);
while (b) {
if (!b->type->transparent(b, f)) break;
b = b->next;
}
if (!b) {
if (add_seen(seen, r2, see_far, false)) {
if (!(fval(r2->terrain, FORBIDDEN_REGION))) {
direction_t dir;
for (dir=0;dir!=MAXDIRECTIONS;++dir) {
region * r3 = rconnect(r2, dir);
if (r3) {
border * b = get_borders(r2, r3);
while (b) {
if (!b->type->transparent(b, f)) break;
b = b->next;
}
if (!b) add_seen(seen, r3, see_neighbour, false);
}
}
}
}
}
}
}
}
static void
recurse_regatta(struct seen_region ** seen, region *center, region *r, faction *f, int maxdist)
{
direction_t dir;
int dist = distance(center, r);
for (dir=0;dir!=MAXDIRECTIONS;++dir) {
region * r2 = rconnect(r, dir);
if (r2) {
int ndist = distance(center, r2);
if (ndist>dist && fval(r2->terrain, SEA_REGION)) {
border * b = get_borders(r, r2);
while (b) {
if (!b->type->transparent(b, f)) break;
b = b->next;
}
if (!b) {
if (ndist<maxdist) {
if (add_seen(seen, r2, see_far, false)) {
recurse_regatta(seen, center, r2, f, maxdist);
}
} else add_seen(seen, r2, see_neighbour, false);
}
}
}
}
}
static void
view_regatta(struct seen_region ** seen, region * r, faction * f)
{
unit *u;
int skill = 0;
for (u=r->units; u; u=u->next) {
if (u->faction==f) {
int es = effskill(u, SK_OBSERVATION);
if (es>skill) skill=es;
}
}
recurse_regatta(seen, r, r, f, skill/2);
}
static struct seen_region **
prepare_report(faction * f)
{
region * r;
region * end = lastregion(f);
struct seen_region ** seen = seen_init();
static const struct building_type * bt_lighthouse = NULL;
if (bt_lighthouse==NULL) bt_lighthouse = bt_find("lighthouse");
for (r = firstregion(f); r != end; r = r->next) {
attrib *ru;
unit * u;
plane * p = rplane(r);
unsigned char mode = see_none;
boolean dis = false;
int light = 0;
if (p) {
watcher * w = p->watchers;
while (w) {
if (f==w->faction) {
mode = w->mode;
break;
}
w = w->next;
}
}
for (u = r->units; u; u = u->next) {
if (u->faction == f) {
if (u->building && u->building->type==bt_lighthouse) {
int r = lighthouse_range(u->building, f);
if (r>light) light = r;
}
if (u->race != new_race[RC_SPELL] || u->number == RS_FARVISION) {
mode = see_unit;
if (fval(u, UFL_DISBELIEVES)) {
dis = true;
break;
}
}
}
}
if (light) {
/* we are in a lighthouse. add the others! */
region_list * rlist = get_regions_distance(r, light);
region_list * rp = rlist;
while (rp) {
region * rl = rp->data;
if (fval(rl->terrain, SEA_REGION)) {
direction_t d;
add_seen(seen, rl, see_lighthouse, false);
for (d=0;d!=MAXDIRECTIONS;++d) {
region * rn = rconnect(rl, d);
if (rn!=NULL) {
add_seen(seen, rn, see_neighbour, false);
}
}
}
rp = rp->next;
}
free_regionlist(rlist);
}
if (mode<see_travel && fval(r, RF_TRAVELUNIT)) {
for (ru = a_find(r->attribs, &at_travelunit); ru; ru = ru->nexttype) {
unit * u = (unit*)ru->data.v;
if (u->faction == f) {
mode = see_travel;
break;
}
}
}
if (mode == see_none)
continue;
add_seen(seen, r, mode, dis);
/* nicht, wenn Verwirrung herrscht: */
if (!is_cursed(r->attribs, C_REGCONF, 0)) {
void (*view)(struct seen_region **, region * r, faction * f) = view_default;
if (p && fval(p, PFL_SEESPECIAL)) {
attrib * a = a_find(p->attribs, &at_viewrange);
if (a) view = (void (*)(struct seen_region **, region * r, faction * f))a->data.f;
}
view(seen, r, f);
}
}
return seen;
}
int
write_reports(faction * f, time_t ltime)
{
boolean gotit = false;
struct seen_region ** seen = prepare_report(f);
faction_list * addresses = get_addresses(f, seen);
report_type * rtype = report_types;
struct report_context ctx;
ctx.f = f;
ctx.addresses = addresses;
ctx.report_time = time(NULL);
ctx.seen = seen;
ctx.userdata = NULL;
printf("Reports für %s: ", factionname(f));
fflush(stdout);
for (;rtype!=NULL;rtype=rtype->next) {
if (f->options & rtype->flag) {
FILE * F;
sprintf(buf, "%s/%d-%s.%s", reportpath(), turn, factionid(f), rtype->extension);
F = fopen(buf, "wt");
if (F!=NULL) {
rtype->write(F, &ctx);
fclose(F);
gotit = true;
} else {
perror(buf);
}
}
}
printf("Reports for %s: DONE\n", factionname(f));
if (!gotit) {
log_warning(("No report for faction %s!\n", factionid(f)));
}
freelist(addresses);
seen_done(seen);
return 0;
}
static void
nmr_warnings(void)
{
faction *f,*fa;
#define FRIEND (HELP_GUARD|HELP_MONEY)
for (f=factions;f;f=f->next) {
if (f->no != MONSTER_FACTION && (turn-f->lastorders) >= 2) {
message * msg = NULL;
for (fa=factions;fa;fa=fa->next) {
if (alliedfaction(NULL, f, fa, FRIEND) && alliedfaction(NULL, fa, f, FRIEND)) {
if (msg==NULL) {
sprintf(buf, "Achtung: %s hat einige Zeit keine "
"Züge eingeschickt und könnte dadurch in Kürze aus dem "
"Spiel ausscheiden.", factionname(f));
msg = msg_message("msg_event", "string", buf);
}
add_message(&fa->msgs, msg);
}
}
if (msg!=NULL) msg_release(msg);
}
}
}
static void
report_donations(void)
{
region * r;
for (r=regions;r;r=r->next) {
while (r->donations) {
donation * sp = r->donations;
if (sp->amount > 0) {
struct message * msg = msg_message("donation",
"from to amount", sp->f1, sp->f2, sp->amount);
r_addmessage(r, sp->f1, msg);
r_addmessage(r, sp->f2, msg);
msg_release(msg);
}
r->donations = sp->next;
free(sp);
}
}
}
static const char*
MailitPath(void)
{
static const char * value = NULL;
if (value==NULL) {
value = get_param(global.parameters, "report.mailit");
}
return value;
}
static void
write_script(FILE * F, const faction * f)
{
report_type * rtype;
fprintf(F, "faction=%s:email=%s", factionid(f), f->email);
if (f->options & (1<<O_BZIP2)) fputs(":compression=bz2", F);
else fputs(":compression=zip", F);
fputs(":reports=", F);
buf[0] = 0;
for (rtype=report_types;rtype!=NULL;rtype=rtype->next) {
if (f->options&rtype->flag) {
if (buf[0]) strcat(buf, ",");
strcat(buf, rtype->extension);
}
}
fputs(buf, F);
fputc('\n', F);
}
#if 0
static void
global_report(const char * filename)
{
FILE * F = fopen(filename, "w");
region * r;
faction * f;
faction * monsters = findfaction(MONSTER_FACTION);
faction_list * addresses = NULL;
struct seen_region ** seen;
if (!monsters) return;
if (!F) return;
/* list of all addresses */
for (f=factions;f;f=f->next) {
faction_list * flist = calloc(1, sizeof(faction_list));
flist->data = f;
flist->next = addresses;
addresses = flist;
}
seen = seen_init();
for (r = regions; r; r = r->next) {
add_seen(seen, r, see_unit, true);
}
report_computer(F, monsters, seen, addresses, time(NULL));
freelist(addresses);
seen_done(seen);
fclose(F);
}
#endif
int
reports(void)
{
faction *f;
FILE *mailit;
time_t ltime = time(NULL);
const char * str;
int retval = 0;
nmr_warnings();
report_donations();
remove_empty_units();
sprintf(buf, "%s/reports.txt", reportpath());
mailit = fopen(buf, "w");
if (mailit == NULL) {
log_error(("%s konnte nicht geöffnet werden!\n", buf));
}
for (f = factions; f; f = f->next) {
int error = write_reports(f, ltime);
if (error) retval = error;
if (mailit) write_script(mailit, f);
}
if (mailit) fclose(mailit);
free_seen();
str = get_param(global.parameters, "globalreport");
#if 0
if (str!=NULL) {
sprintf(buf, "%s/%s.%u.cr", reportpath(), str, turn);
global_report(buf);
}
#endif
return retval;
}
static variant
var_copy_string(variant x)
{
x.v = strdup((const char*)x.v);
return x;
}
static void
var_free_string(variant x)
{
free(x.v);
}
static variant
var_copy_order(variant x)
{
x.v = copy_order((order*)x.v);
return x;
}
static void
var_free_order(variant x)
{
free_order(x.v);
}
void
reports_init(void)
{
/* register datatypes for the different message objects */
register_argtype("alliance", NULL, NULL, VAR_VOIDPTR);
register_argtype("building", NULL, NULL, VAR_VOIDPTR);
register_argtype("direction", NULL, NULL, VAR_INT);
register_argtype("faction", NULL, NULL, VAR_VOIDPTR);
register_argtype("race", NULL, NULL, VAR_VOIDPTR);
register_argtype("region", NULL, NULL, VAR_VOIDPTR);
register_argtype("resource", NULL, NULL, VAR_VOIDPTR);
register_argtype("ship", NULL, NULL, VAR_VOIDPTR);
register_argtype("skill", NULL, NULL, VAR_VOIDPTR);
register_argtype("spell", NULL, NULL, VAR_VOIDPTR);
register_argtype("unit", NULL, NULL, VAR_VOIDPTR);
register_argtype("int", NULL, NULL, VAR_INT);
register_argtype("string", var_free_string, var_copy_string, VAR_VOIDPTR);
register_argtype("order", var_free_order, var_copy_order, VAR_VOIDPTR);
/* register alternative visibility functions */
register_function((pf_generic)view_neighbours, "view_neighbours");
register_function((pf_generic)view_regatta, "view_regatta");
}

View File

@ -86,6 +86,17 @@ extern void seen_done(struct seen_region * seehash[]);
extern void free_seen(void);
extern void get_seen_interval(struct seen_region ** seen, struct region ** first, struct region ** last);
typedef struct report_context {
struct faction * f;
struct faction_list * addresses;
struct seen_region ** seen;
time_t report_time;
void * userdata;
} report_context;
typedef void (*report_fun)(FILE * F, report_context * ctx);
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);
@ -97,6 +108,8 @@ extern const char * reportpath(void);
extern struct faction_list * get_addresses(struct faction * f, struct seen_region * seehash[]);
extern const char * trailinto(const struct region * r, const struct locale * lang);
extern void reports_init(void);
#ifdef __cplusplus
}
#endif

View File

@ -56,6 +56,7 @@
/* gamecode includes */
#include <gamecode/creport.h>
#include <gamecode/report.h>
#include <gamecode/economy.h>
#include <gamecode/items.h>
#include <gamecode/laws.h>
@ -202,6 +203,8 @@ game_init(void)
{
init_triggers();
init_xmas();
reports_init();
report_init();
creport_init();