server/src/eressea/main.c

767 lines
17 KiB
C
Raw Normal View History

2001-01-25 10:37:55 +01:00
/* vi: set ts=2:
*
* $Id: main.c,v 1.9 2001/02/03 13:45:34 enno Exp $
2001-01-25 10:37:55 +01:00
* 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)
*
* based on:
*
* Atlantis v1.0 13 September 1993 Copyright 1993 by Russell Wallace
* Atlantis v1.7 Copyright 1996 by Alex Schr<EFBFBD>der
*
* This program may not be used, modified or distributed without
* prior permission by the authors of Eressea.
* This program may not be sold or used commercially without prior written
* permission from the authors.
*/
#define BENCHMARK 0
#ifdef DMALLOC
# define ENNO_CLEANUP 1
#else
# define ENNO_CLEANUP 0
#endif
#define LOCALE_CHECK
#ifdef __LCC__
#undef LOCALE_CHECK
#endif
#include <config.h>
#include <eressea.h>
#include "korrektur.h"
2001-01-26 17:19:41 +01:00
/* initialization - TODO: init in separate module */
#include <attributes/attributes.h>
#include <spells/spells.h>
#include <triggers/triggers.h>
#include <items/items.h>
2001-01-26 17:19:41 +01:00
2001-01-25 10:37:55 +01:00
/* modules includes */
#include <modules/arena.h>
#include <modules/museum.h>
#include <modules/score.h>
#include <modules/xmas2000.h>
#include <modules/gmcmd.h>
2001-01-25 10:37:55 +01:00
/* gamecode includes */
#include <creation.h>
#include <laws.h>
/* kernel includes */
#include <building.h>
#include <unit.h>
#include <message.h>
#include <teleport.h>
#include <faction.h>
#include <race.h>
#include <reports.h>
#include <save.h>
#include <time.h>
#include <border.h>
#include <region.h>
#include <item.h>
/* util includes */
#include <rand.h>
#include <base36.h>
/* libc includes */
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include <locale.h>
int nodescriptions = 0;
int nowrite = 0;
extern char * g_reportdir;
extern char * g_datadir;
extern char * g_basedir;
extern char * g_resourcedir;
2001-01-25 10:37:55 +01:00
extern boolean nonr;
extern boolean nocr;
extern boolean nomer;
extern boolean nomsg;
extern boolean nobattle;
extern boolean nobattledebug;
int mapdetail = 0;
extern void render_init(void);
static void
init_game(void)
{
init_triggers();
2001-01-25 10:37:55 +01:00
init_locales();
init_races();
init_spells();
2001-01-25 10:37:55 +01:00
init_resources();
init_items();
2001-01-26 17:19:41 +01:00
init_attributes();
2001-01-25 10:37:55 +01:00
#ifdef USE_GM_COMMANDS
init_gmcmd();
#endif
2001-01-25 10:37:55 +01:00
init_conversion();
init_museum();
init_arena();
init_xmas2000();
render_init();
}
void
create_game(void)
{
assert(regions==NULL || !"game is initialized");
printf("Keine Spieldaten gefunden, erzeuge neues Spiel in %s...\n", datapath());
makedir(datapath(), 0700);
2001-01-25 10:37:55 +01:00
/* erste Insel generieren */
new_region(0, 0);
/* Monsterpartei anlegen */
createmonsters();
/* Teleportebene anlegen */
create_teleport_plane();
}
void
map(void)
{
FILE * f;
region * r;
sprintf(buf, "map-%d.cr", turn);
f = fopen(buf, "wt");
fputs("VERSION 42\n", f);
fputs("\"Standard\";konfiguration\n", f);
fprintf(f, "%d;runde\n", turn);
for (r=regions;r;r=r->next) {
fprintf(f, "REGION %d %d\n", r->x, r->y);
fprintf(f, "\"%s\";name\n", rname(r, NULL));
fprintf(f, "\"%s\";terrain\n", terrain[rterrain(r)].name);
if (!mapdetail) continue;
fprintf(f, "%d;silber\n", rmoney(r));
if (r->display && strlen(r->display))
fprintf(f, "\"%s\";beschr\n", r->display);
fprintf(f, "%d;bauern\n", rpeasants(r));
fprintf(f, "%d;baeume\n", rtrees(r));
fprintf(f, "%d;pferde\n", rhorses(r));
if (rterrain(r) == T_MOUNTAIN || rterrain(r) == T_GLACIER) {
fprintf(f, "%d;eisen\n", riron(r));
if (rlaen(r)>=0) fprintf(f, "%d;laen\n", rlaen(r));
}
}
fclose(f);
}
void
getgarbage(void)
{
faction *f;
/* Get rid of stuff that was only relevant last turn */
for (f = factions; f; f = f->next) {
/* memset(f->showdata, 0, sizeof f->showdata); */
freestrlist(f->mistakes);
f->mistakes = 0;
/* TODO: free msgs */
}
#if 0
for (r = regions; r; r = r->next) {
freestrlist(r->comments);
r->comments = 0;
freestrlist(r->botschaften);
r->botschaften = 0;
}
#endif
}
int quickleave = 0;
void
writepasswd(void)
{
FILE * F;
char zText[128];
2001-01-25 10:37:55 +01:00
sprintf(zText, "%s/passwd", basepath());
F = cfopen(zText, "w");
if (F) {
faction *f;
puts("Schreibe Passw<73>rter...");
for (f = factions; f; f = f->next) {
fprintf(F, "%s:%s:%s\n", factionid(f), f->email, f->passw);
}
fclose(F);
2001-01-25 10:37:55 +01:00
}
}
#ifdef FUZZY_BASE36
extern int fuzzy_hits;
#endif /* FUZZY_BASE36 */
void
processturn(char *filename)
{
struct summary * begin, * end;
begin = make_summary(false);
printf(" - Korrekturen Runde %d\n", turn);
korrektur();
turn++;
if (!quickleave) {
puts(" - entferne Texte der letzten Runde");
getgarbage();
puts(" - Nehme Korrekturen am Datenbestand vor");
if (!readorders(filename)) return;
#if BENCHMARK
exit(0);
#endif
processorders();
score();
}
#ifdef WACH_WAFF
remove_unequipped_guarded();
#endif
korrektur_end();
reports();
free_units();
puts(" - Beseitige leere Parteien");
remove_empty_factions();
end = make_summary(true);
report_summary(end, begin, false);
report_summary(end, begin, true);
free(end);
free(begin);
writepasswd();
#ifdef FUZZY_BASE36
fputs("==--------------------------==\n", stdout);
fprintf(stdout, "## fuzzy base10 hits: %5d ##\n", fuzzy_hits);
fputs("==--------------------------==\n", stdout);
#endif /* FUZZY_BASE36 */
if (!nowrite) {
char ztext[64];
sprintf(ztext, "%s/%d", datapath(), turn);
2001-01-25 10:37:55 +01:00
writegame(ztext, 0);
}
}
void
doreports(void)
{
struct summary * begin;
begin = make_summary(true);
printf("Schreibe die Reports der %d. Runde...\n", turn);
reports();
report_summary(begin, begin, false);
free(begin);
}
void
showmap(int mode)
{
FILE * F = cfopen("karte", "w");
if (!F)
return;
puts("Schreibe Karte...");
writemap(F, mode);
fclose(F);
}
#if ENNO_CLEANUP
extern void creport_cleanup(void);
extern void reports_cleanup(void);
extern void render_cleanup(void);
void
cleanup(void)
{
/* Diese Routine enfernt allen allokierten Speicher wieder. Das ist nur
* zum Debugging interessant, wenn man Leak Detection hat, und nach
* nicht freigegebenem Speicher sucht, der nicht bis zum Ende ben<EFBFBD>tigt
* wird (tempor<EFBFBD>re Hilsstrukturen) */
unit *u, *u2;
region *r, *r2;
building *b, *b2;
faction *f, *f2;
ship *s, *s2;
creport_cleanup();
reports_cleanup();
render_cleanup();
free(used_faction_ids);
for (r = regions; r; r = r2) {
#if 0
msg * m = r->msgs;
while (m) {
msg * x = m;
m = m->next;
if (x->type->finalize) x->type->finalize(x);
free(x);
}
rm = rm->next;
}
#endif
for (u = r->units; u; u = u2) {
u2 = u->next;
stripunit(u);
uunhash(u);
free(u);
}
for (b = r->buildings; b; b = b2) {
free(b->name);
free(b->display);
b2 = b->next;
free(b);
}
for (s = r->ships; s; s = s2) {
free(s->name);
free(s->display);
s2 = s->next;
free(s);
}
free(r->display);
if (r->land) freeland(r->land);
r2 = r->next;
while (r->attribs) a_remove (&r->attribs, r->attribs);
free(r);
}
for (f = factions; f; f = f2) {
stripfaction(f);
f2 = f->next;
free(f);
}
while (planes) {
plane * pl = planes;
planes = planes->next;
free(pl);
}
#ifdef LEAK_DETECT
leak_report(stderr);
#endif
}
#endif
#include "magic.h"
static boolean
locale_check(void)
{
int i, errorlevel = 0;
unsigned char * umlaute = (unsigned char*)"<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>";
/* E: das pr<70>ft, ob umlaute funktionieren. Wenn <20><><EFBFBD> nicht mit isalpha() true sind, kriegen wir <20>rger. */
for (i=0;i!=3;++i) {
if (toupper(umlaute[i])!=(int)umlaute[i+3]) {
++errorlevel;
fprintf(stderr, "error in locale[%d, %d]: toupper(%c)==%c\n", i, umlaute[i], umlaute[i], toupper(umlaute[i]));
}
}
for (i=0;umlaute[i]!=0;++i) {
if (!isalpha(umlaute[i]) || isspace(umlaute[i]) || iscntrl(umlaute[i])) {
++errorlevel;
if (!isalpha(umlaute[i]))
fprintf(stderr, "error in locale[%d, %d]: !isalpha(%c)\n", i, umlaute[i], umlaute[i]);
if (iscntrl(umlaute[i]))
fprintf(stderr, "error in locale(%d, %d]: iscntrl(%c)\n", i, umlaute[i], umlaute[i]);
if (isspace(umlaute[i]))
fprintf(stderr, "error in locale[%d, %d]: isspace(%c)\n", i, umlaute[i], umlaute[i]);
}
}
if (errorlevel) return false;
return true;
}
#if MALLOCDBG
void
init_malloc_debug(void)
{
#if (defined(_MSC_VER))
# if MALLOCDBG == 2
# define CHECKON() _CrtSetDbgFlag(_CrtSetDbgFlag(_CRTDBG_REPORT_FLAG) | _CRTDBG_LEAK_CHECK_DF | _CRTDBG_DELAY_FREE_MEM_DF | _CRTDBG_CHECK_ALWAYS_DF)
# elif MALLOCDBG == 1
# define CHECKON() _CrtSetDbgFlag(_CrtSetDbgFlag(_CRTDBG_REPORT_FLAG) | _CRTDBG_ALLOC_MEM_DF | _CRTDBG_CHECK_CRT_DF | _CRTDBG_DELAY_FREE_MEM_DF)
# endif
#endif
}
#endif
int
main(int argc, char *argv[])
{
int i, errorlevel = 0;
setlocale(LC_ALL, "");
#ifdef LOCALE_CHECK
if (!locale_check())
puts("ERROR: The current locale is not suitable for international Eressea.\n");
2001-01-25 10:37:55 +01:00
#endif
#if MALLOCDBG
init_malloc_debug();
#endif
debug = 0;
quickleave = 0;
printf(
"\n"
"%s PBEM host\n"
"Copyright (C) 1996-99 C.Schlittchen, K.Zedel, E.Rehling, H.Peters.\n\n"
"based on Atlantis v1.0\n"
"Copyright (C) 1993 by Russell Wallace.\n"
"and on German Atlantis v2.3\n"
"Copyright (C) 1996 by Alexander Schroeder.\n\n"
"Eressea is distributed in the hope that it will be useful,\n"
"but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
"MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n"
"This program may be freely used, modified and distributed. It may\n"
"not be sold or used commercially without prior written permission\n"
"from the author.\n\n"
"Compilation: " __DATE__ " at " __TIME__ "\nVersion: %f\n", global.gamename, version());
for (i = 1; i != argc; i++)
if ((argv[i][0] == '-' || argv[i][0] == '/'))
switch (argv[i][1]) {
case 'o':
g_reportdir = argv[++i];
break;
case 'd':
if (!strcmp(argv[i] + 1, "debug")) {
nodescriptions = 1;
debug = fopen("debug", "w");
break;
}
g_datadir = argv[++i];
break;
case 'r':
g_resourcedir = argv[++i];
break;
2001-01-25 10:37:55 +01:00
case 'b':
g_basedir = argv[++i];
break;
case 't':
turn = atoi(argv[++i]);
break;
case 'f':
firstx = atoi(argv[++i]);
firsty = atoi(argv[++i]);
break;
case 'q':
quiet = 1;
break;
case 'i':
inside_only = 1;
printf(" - Lade nur die innersten Regionen.\n");
break;
case 'x':
maxregions = atoi(argv[++i]);
maxregions = (maxregions*81+80) / 81;
break;
}
{
char zText[MAX_PATH];
strcat(strcpy(zText, resourcepath()), "/timestrings");
2001-01-25 10:37:55 +01:00
read_datenames(zText);
}
#ifdef WRITE_STATS
{
FILE * F;
char zText[MAX_PATH];
strcat(strcpy(zText, resourcepath()), "/spells");
F = fopen(zText, "wt");
if (F) {
int i, m = -1;
for (i=0;spelldaten[i].id;++i) {
if (spelldaten[i].magietyp!=m) {
m=spelldaten[i].magietyp;
fprintf(F, "\n%s\n", magietypen[m]);
}
fprintf(F, "%d\t%s\n", spelldaten[i].level, spelldaten[i].name);
}
fclose(F);
} else {
sprintf(buf, "fopen(%s): ", zText);
perror(buf);
}
strcat(strcpy(zText, resourcepath()), "/bonus");
F = fopen(buf, "wt");
if (F) {
race_t r;
for (r=0;r!=MAXRACES;++r) {
skill_t sk;
int i = 0;
fprintf(F, "const bonus %s_bonus = {\n\t", race[r].name[0]);
for (sk=0;sk!=MAXSKILLS;sk++) {
if (race[r].bonus[sk]) {
if (i==8) {
i = 0;
fputs("\n\t", F);
}
fprintf(F, "{ SK_%s, %d }, ", skillnames[sk], race[r].bonus[sk]);
++i;
}
}
fputs("{ SK_NONE, 0 }\n};\n", F);
}
fclose(F);
} else {
sprintf(buf, "fopen(%s): ", zText);
perror(zText);
}
}
#endif
2001-01-25 10:37:55 +01:00
init_game();
initgame();
readgame(false);
#if MALLOCDBG
assert(_CrtCheckMemory());
#endif
/* verify_data(); */
if (turn == 0)
srand(time((time_t *) NULL));
else
srand(turn);
/* Problem: In jedem Report ist die Regionsreihenfolge eine andere. */
/* { int nregions=0; region *r; for(r=regions;r;r=r->next) nregions++;
* scramble(regions, nregions, sizeof(region *)); } */
errorlevel = -1;
for (i = 1; i != argc; i++)
if (argv[i][0] == '-' ||
argv[i][0] == '/')
switch (argv[i][1]) {
case 'c':
korrektur();
break;
case 'Q':
quickleave = 1;
break;
case 'n':
if (strcmp(argv[i]+1, "nocr")==0) nocr = true;
else if (strcmp(argv[i]+1, "nosave")==0) nowrite = true;
else if (strcmp(argv[i]+1, "nonr")==0) nonr = true;
else if (strcmp(argv[i]+1, "nomer")==0) nomer = true;
else if (strcmp(argv[i]+1, "nomsg")==0) nomsg = true;
else if (strcmp(argv[i]+1, "nobattle")==0) nobattle = true;
else if (strcmp(argv[i]+1, "nodebug")==0) nobattledebug = true;
break;
case 'v':
++i;
#define TEST_BORDERS 0
#if TEST_BORDERS
{
border * b;
new_border(&bt_fogwall, findregion(5,-6), findregion(5, -5));
new_border(&bt_noway, findregion(4,-5), findregion(5, -5));
new_border(&bt_wall, findregion(5,-5), findregion(6, -5));
b = new_border(&bt_illusionwall, findregion(4,-4), findregion(5, -5));
b->data = (void*) 1; /* partei 1 hat's gezaubert */
}
#endif
if (i >= argc || argv[i][0]) {
printf(" - verwende Befehlsdatei: %s\n", argv[i]);
processturn(argv[i]);
errorlevel = 0;
} else {
puts("Fehler: keine Befehlsdatei angegeben.\n\n");
errorlevel = 1;
}
break;
#ifdef EXTRA_CR
case 'p' :
{
FILE * out = fopen("planes.cr", "wt");
faction * f;
region * r;
if (!out) break;
fprintf(out, "VERSION 36\n");
for (f = factions; f; f = f->next) cr_faction(out, f);
for (r = regions;r;r=r->next) if (getplane(r)) cr_region(out, r);
fclose(out);
}
break;
case 'w' :
{
FILE * out = fopen("world.cr", "wt");
faction * f;
region * r;
if (!out) break;
fprintf(out, "VERSION 36\n");
for (f = factions; f; f = f->next) cr_faction(out, f);
for (r = regions;r;r=r->next) cr_region(out, r);
fclose(out);
}
break;
#endif
case '#':
score();
exit(0);
break;
case 'm':
if (argv[i][2]=='d') mapdetail = 1;
map();
break;
case 'f':
i++;
case 'r':
2001-01-28 09:20:05 +01:00
case 'b':
2001-01-25 10:37:55 +01:00
case 't':
case 'x':
i++;
case 'q':
case 'i':
/* inner_world, quiet, minfaction und maxregions wird schon vorher abgefragt */
break;
default:
fprintf(stderr, "Usage: %s [options]\n"
"-r : schreibt die Reports neu\n"
"-x n : L<>dt nur die ersten n regionen\n"
"-g befehlsdatei : verarbeitet Spielleiterbefehle\n"
"-v befehlsdatei : verarbeitet automatisch die angegebene Befehlsdatei\n"
"-# : gibt Scoreliste aus\n"
"-d datadir : gibt das datenverzeichnis an\n"
"-o reportdir : gibt das reportverzeichnis an\n"
"-nomsg : keine Messages (RAM sparen)\n"
#ifdef USE_MERIAN
"-nomer : keine Meriankarten\n"
#endif
"-nocr : keine CRs\n"
"-nonr : keine Reports\n"
"-nobattle : keine K<>mpfe\n"
"-debug : schreibt Debug-Ausgaben in die Datei debug\n"
"-? : help\n", argv[0]);
errorlevel = 1;
break;
}
if (errorlevel >= 0) {
#if ENNO_CLEANUP
cleanup();
#endif
game_done();
return errorlevel;
}
puts("? zeigt das Menue an.");
printf("sizeof:\n region\t%d (%d)\n unit\t%d (%d)\n", (int)sizeof(region), listlen(regions), (int)sizeof(unit), -1);
printf(" ship\t%d (%d)\n building\t%d(%d)\n", (int)sizeof(ship), -1, (int)sizeof(building), -1);
for (;;) {
if (quickleave) break;
printf("> ");
fgets(buf, 1024, stdin);
switch (buf[0]) {
case 'c':
korrektur();
break;
case 'k':
showmap(M_TERRAIN);
break;
case 'p':
showmap(M_FACTIONS);
break;
case 'u':
showmap(M_UNARMED);
break;
case 'v':
printf("Datei mit den Befehlen? ");
fgets(buf, 1024, stdin);
if (buf[0])
processturn(buf);
break;
case 's':
{
char ztext[64];
sprintf(ztext, "data/%d", turn);
writegame(ztext, 0);
}
break;
case 'q':
#if ENNO_CLEANUP
cleanup();
#endif
game_done();
return 0;
case 'Q':
quickleave = 1;
break;
case 'l':
listnames();
break;
case '#':
score();
break;
#ifdef QTMAP
case '*':
qt_edit_map(argc, argv);
break;
#endif
default:
puts("modify:\n"
" v - Befehle verarbeiten.\n"
" g - Spielleiterbefehle verarbeiten.\n"
" e - Erzeuge Regionen.\n"
" t - Terraform Region.\n"
" T - Terraform Block.\n"
" m - Erschaffe Einheiten und Monster.\n"
" b - Erbaue eine Burg.\n"
" n - Neue Spieler hinzufuegen.\n"
" M - Move unit.\n"
" c - Korrekturen durchf<68>hren.\n"
"information:\n"
" a - Adressen anzeigen.\n"
" i - Info ueber eine Region.\n"
" U - Info ueber units einer Region.\n"
" k - Karte anzeigen.\n"
" p - Politische Karte anzeigen.\n"
" u - Karte unbewaffneter Regionen anzeigen.\n"
" l - Liste aller Laendernamen zeigen.\n"
#ifdef QTMAP
" * - Qt-Karte anzeigen.\n"
#endif
"save:\n"
" r - Reports schreiben.\n"
" # - Scoreliste speichern.\n"
" s - Spielstand speichern.\n"
"\n"
" q - Beenden.");
}
}
return 0;
}
struct settings global = {
"Eressea", /* gamename */
};