diff --git a/src/common/kernel/give.c b/src/common/kernel/give.c new file mode 100644 index 000000000..f4fc28bf6 --- /dev/null +++ b/src/common/kernel/give.c @@ -0,0 +1,254 @@ +/* vi: set ts=2: ++-----------------+ Christian Schlittchen +| Eressea II host | Enno Rehling +| (c) 1998 - 2003 | Katja Zedel ++-----------------+ + +This program may not be used, modified or distributed +without prior permission by the authors of Eressea. +*/ + +#include +#include "eressea.h" + +#include "give.h" + +/* kernel includes */ +#include "message.h" +#include "reports.h" +#include "unit.h" +#include "pool.h" +#include "faction.h" +#include "region.h" +#include "item.h" +#include "skill.h" + +/* items includes */ +#include + +/* attributes includes */ +#include +#include + +/* util includes */ +#include + +/* libc includes */ +#include +#include + +/* Wieviel Fremde eine Partei pro Woche aufnehmen kann */ +#define MAXNEWBIES 5 + +static int +GiveRestriction(void) { + static int value = -1; + if (value<0) { + value = atoi(get_param(global.parameters, "GiveRestriction")); + } + return value; +} + +static void +add_give(unit * u, unit * u2, int n, const resource_type * rtype, struct order * ord, int error) +{ + if (error) { + cmistake(u, ord, error, MSG_COMMERCE); + } else if (!u2 || ufaction(u2)!=ufaction(u)) { + assert(rtype); + add_message(&ufaction(u)->msgs, + msg_message("give", "unit target resource amount", + u, u2?ucansee(ufaction(u), u2, u_unknown()):u_peasants(), rtype, n)); + if (u2) { + add_message(&ufaction(u2)->msgs, + msg_message("give", "unit target resource amount", + ucansee(ufaction(u2), u, u_unknown()), u2, rtype, n)); + } + } +} + +static void +addgive(unit * u, unit * u2, int n, resource_t res, struct order * ord, int error) +{ + add_give(u, u2, n, oldresourcetype[res], ord, error); +} + +static void +give_peasants(int n, const item_type * itype, unit * src) +{ + region *r = uregion(src); + + /* horses are given to the region via itype->give! */ + + if (itype->rtype==itype_money->rtype) { + rsetmoney(r, rmoney(r) + n); + } +} + +int +give_item(int want, const item_type * itype, unit * src, unit * dest, struct order * ord) +{ + short error = 0; + int n; + + assert(itype!=NULL); + n = new_get_pooled(src, item2resource(itype), GET_DEFAULT); + n = min(want, n); + if (dest && src->faction != dest->faction && src->faction->age < GiveRestriction()) { + if (ord!=NULL) { + ADDMSG(&src->faction->msgs, msg_feedback(src, ord, "giverestriction", + "turns", GiveRestriction())); + } + return -1; + } else if (n == 0) { + error = 36; + } else if (itype->flags & ITF_CURSED) { + error = 25; + } else if (itype->give && !itype->give(src, dest, itype, n, ord)) { + return -1; + } else { + int use = new_use_pooled(src, item2resource(itype), GET_SLACK, n); + if (usefaction==dest->faction) { + new_change_resvalue(dest, item2resource(itype), n); + } +#endif + handle_event(&src->attribs, "give", dest); + handle_event(&dest->attribs, "receive", src); +#if defined(MUSEUM_MODULE) && defined(TODO) +TODO: Einen Trigger benutzen! + if (a_find(dest->attribs, &at_warden)) { + /* warden_add_give(src, dest, itype, n); */ + } +#endif + } else { + /* gib bauern */ + give_peasants(use, itype, src); + } + } + add_give(src, dest, n, item2resource(itype), ord, error); + if (error) return -1; + return 0; +} + +void +givemen(int n, unit * u, unit * u2, struct order * ord) +{ + struct ship *sh; + int error = 0; + + if (u2 && ufaction(u) != ufaction(u2) && ufaction(u)->age < GiveRestriction()) { + ADDMSG(&ufaction(u)->msgs, msg_feedback(u, ord, "giverestriction", + "turns", GiveRestriction())); + return; + } + if (u2 && u2->number) { + /* kann keine personen an eine nicht-leere einheit geben */ + error = 155; + } else if (fval(u, UFL_HERO) || (u2 && fval(u2, UFL_HERO))) { + /* heroes cannot be passed on */ + error = 158; + } else if (u == u2) { + error = 10; + } else if (!u2 && u->race == new_race[RC_SNOTLING]) { + /* Snotlings können nicht an Bauern übergeben werden. */ + error = 307; + } else if ((u && unit_has_cursed_item(u)) || (u2 && unit_has_cursed_item(u2))) { + error = 78; + } else if (fval(u, UFL_LOCKED) || fval(u, UFL_HUNGER) || isslave(u)) { + error = 74; + } else if (u2 && (fval(u2, UFL_LOCKED) || isslave(u))) { + error = 75; + } else if (u2 != (unit *) NULL + && ufaction(u2) != ufaction(u) + && ucontact(u2, u) == 0) { + error = 73; + } else if (u2 && fval(u, UFL_WERE) != fval(u2, UFL_WERE)) { + error = 312; + } else { + if (n > u->number) n = u->number; + if (n == 0) { + error = 96; + } else if (u2 && ufaction(u) != ufaction(u2)) { + if (ufaction(u2)->newbies + n > MAXNEWBIES) { + error = 129; + } else if (u->race != ufaction(u2)->race) { + if (ufaction(u2)->race != new_race[RC_HUMAN]) { + error = 120; + } else if (count_migrants(ufaction(u2)) + n > count_maxmigrants(ufaction(u2))) { + error = 128; + } else if (u2->number!=0) { + error = 139; + } + } + } + } + if (!error) { + if (u2 && u2->number == 0) { + set_racename(&u2->attribs, get_racename(u->attribs)); + u2->race = u->race; + u2->irace = u->irace; + } else if (u2 && u2->race != u->race) { + error = 139; + } + } + if (u2) { + skill * sv; + for (sv=u->skills;error==0 && sv!=u->skills+u->skill_size;++sv) { + boolean sk2 = has_skill(u2, sv->id); + if (!sk2 || ufaction(u2)!=ufaction(u)) { + const skill_type * skt = skt_get(sv->id); + int limit = skt->limit?skt->limit(ufaction(u2)):INT_MAX; + if (limit!=INT_MAX) { + int k = count_skill(ufaction(u2), sv->id); + if (ufaction(u)!=ufaction(u2)) k+=n; + if (!sk2) k+=u2->number; + if (k>limit) error = 156; + } + } + } + for (sv=u2->skills;error==0 && sv!=u2->skills+u2->skill_size;++sv) { + boolean sk1 = has_skill(u, sv->id); + if (!sk1 || ufaction(u2)!=ufaction(u)) { + const skill_type * skt = skt_get(sv->id); + int limit = skt->limit?skt->limit(ufaction(u2)):INT_MAX; + if (limit!=INT_MAX) { + int k = count_skill(ufaction(u2), sv->id) + n; + if (k>limit) error = 156; + } + } + } + } + if (!error) { + if (u2) { + /* Einheiten von Schiffen können nicht NACH in von + * Nicht-alliierten bewachten Regionen ausführen */ + sh = leftship(u); + if (sh) set_leftship(u2, sh); + + transfermen(u, u2, n); + if (ufaction(u) != ufaction(u2)) { + ufaction(u2)->newbies += n; + } + } else { + if (getunitpeasants) { +#ifdef ORCIFICATION + if (u->race == new_race[RC_ORC] && !fval(uregion(u), RF_ORCIFIED)) { + attrib *a = a_find(uregion(u)->attribs, &at_orcification); + if (!a) a = a_add(&uregion(u)->attribs, a_new(&at_orcification)); + a->data.i += n; + } +#endif + transfermen(u, NULL, n); + } else { + error = 159; + } + } + } + addgive(u, u2, n, R_PERSON, ord, error); +} diff --git a/src/common/kernel/give.h b/src/common/kernel/give.h new file mode 100644 index 000000000..7ebd8268e --- /dev/null +++ b/src/common/kernel/give.h @@ -0,0 +1,22 @@ +/* vi: set ts=2: ++-----------------+ Christian Schlittchen +| Eressea II host | Enno Rehling +| (c) 1998 - 2003 | Katja Zedel ++-----------------+ + +This program may not be used, modified or distributed +without prior permission by the authors of Eressea. +*/ +#ifndef H_KRNL_GIVE +#define H_KRNL_GIVE +#ifdef __cplusplus +extern "C" { +#endif + + extern int give_item(int want, const struct item_type * itype, struct unit * src, struct unit * dest, struct order * ord); + extern void givemen(int n, struct unit * u, struct unit * u2, struct order * ord); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/common/kernel/order.c b/src/common/kernel/order.c new file mode 100644 index 000000000..532767bea --- /dev/null +++ b/src/common/kernel/order.c @@ -0,0 +1,92 @@ +#include +#include "eressea.h" + +#include "order.h" + +/* libc includes */ +#include +#include +#include +#include + +keyword_t +getkeyword(const order * ord) +{ + if (ord==NULL) { + return NOKEYWORD; + } + igetstrtoken(ord->str); + return ord->keyword; +} + +const char * +getcommand(const order * ord) +{ + return ord->str; +} + +void +free_order(order * ord) +{ + if (ord!=NULL && --ord->refcount==0) { + free(ord->str); + free(ord); + } +} + +order * +copy_order(order * ord) +{ + if (ord!=NULL) ++ord->refcount; + return ord; +} + +void +set_order(struct order ** destp, struct order * src) +{ + free_order(*destp); + *destp = copy_order(src); +} + +void +free_orders(order ** olist) +{ + while (*olist) { + order * ord = *olist; + *olist = ord->next; + free_order(ord); + } +} + +order * +parse_order(const char * s, const struct locale * lang) +{ + order * ord = (order*)malloc(sizeof(order)); + ord->keyword = igetkeyword(s, lang); + ord->refcount = 1; + ord->str = strdup(s); + ord->next = NULL; + return ord; +} + +boolean +is_persistent(const order * cmd) +{ +#ifdef AT_PERSISTENT + if (cmd->str[0] == '@') return true; +#endif /* Nur kurze Befehle! */ + switch (cmd->keyword) { + case K_KOMMENTAR: + case K_LIEFERE: + return true; + break; + } + return false; +} + +char * +write_order(const order * cmd, const struct locale * lang, char * buffer, size_t size) +{ + assert(igetkeyword(cmd->str, lang)==cmd->keyword); + return strncpy(buffer, cmd->str, size); +} diff --git a/src/common/kernel/order.h b/src/common/kernel/order.h new file mode 100644 index 000000000..61b66a6ee --- /dev/null +++ b/src/common/kernel/order.h @@ -0,0 +1,51 @@ +/* vi: set ts=2: + * Eressea PB(E)M host Christian Schlittchen (corwin@amber.kn-bremen.de) + * (C) 1998-2003 Katja Zedel (katze@felidae.kn-bremen.de) + * Henning Peters (faroul@beyond.kn-bremen.de) + * Enno Rehling (enno@eressea-pbem.de) + * Ingo Wilken (Ingo.Wilken@informatik.uni-oldenburg.de) + * + * This program may not be used, modified or distributed without + * prior permission by the authors of Eressea. + **/ + +#ifndef KRNL_ORDER_H +#define KRNL_ORDER_H +#ifdef __cplusplus +extern "C" { +#endif + +/* Encapsulation of an order + * + * This structure contains one order given by a unit. These used to be + * stored in string lists, but by storing them in order-structures, + * it is possible to use reference-counting on them, reduce string copies, + * and reduce overall memory usage by sharing strings between orders (not + * implemented yet) saving approx. 50% of all string-related memory. + */ + +typedef struct order { + struct order * next; + char * str; + keyword_t keyword; + int refcount; +} order; + +/* constructor */ +extern struct order * parse_order(const char * s, const struct locale * lang); + +/* reference counted copies of orders: */ +extern struct order * copy_order(struct order * ord); +extern void free_order(struct order * ord); +extern void free_orders(struct order ** olist); + +/* access functions for orders */ +extern keyword_t getkeyword(const struct order * ord); +extern void set_order(struct order ** destp, struct order * src); +extern const char * getcommand(const struct order * ord); +extern boolean is_persistent(const struct order *ord); +extern char * write_order(const struct order * ord, const struct locale * lang, char * buffer, size_t size); +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/eressea/lua/bindings.h b/src/eressea/lua/bindings.h new file mode 100644 index 000000000..c90e6a683 --- /dev/null +++ b/src/eressea/lua/bindings.h @@ -0,0 +1,39 @@ +#ifndef BINDINGS_H +#define BINDINGS_H + +struct lua_State; + +extern void bind_region(struct lua_State * L); +extern void bind_unit(struct lua_State * L); +extern void bind_ship(struct lua_State * L); +extern void bind_building(struct lua_State * L); + +namespace eressea { + template + class list { + public: + class iterator { + public: + iterator(T * index) : m_index(index) {} + T * operator*() { return m_index; } + bool operator==(const iterator& iter) { + return iter.m_index==m_index; + } + iterator& operator++() { + if (m_index) m_index = m_index->next; + return *this; + } + private: + T * m_index; + }; + typedef iterator const_iterator; + list(T * clist) : m_clist(clist) {} + iterator begin() const { return iterator(m_clist); } + iterator end() const { return iterator(NULL); } + + public: + T * m_clist; + }; +}; + +#endif diff --git a/src/eressea/lua/building.cpp b/src/eressea/lua/building.cpp new file mode 100644 index 000000000..932520aff --- /dev/null +++ b/src/eressea/lua/building.cpp @@ -0,0 +1,28 @@ +#include +#include +#include "bindings.h" + +// kernel includes +#include + +// lua includes +#include +#include +#include + +using namespace luabind; +using namespace eressea; + +void +bind_building(lua_State * L) +{ + module(L)[ + def("get_building", &findbuilding), + + class_("building") + .def_readonly("name", &building::name) + .def_readonly("id", &building::no) + .def_readonly("info", &building::display) + .def_readwrite("size", &building::size) + ]; +} diff --git a/src/eressea/lua/region.cpp b/src/eressea/lua/region.cpp new file mode 100644 index 000000000..b3931a0a8 --- /dev/null +++ b/src/eressea/lua/region.cpp @@ -0,0 +1,78 @@ +#include +#include +#include "bindings.h" + +// kernel includes +#include +#include +#include +#include + +// lua includes +#include +#include +#include + +using namespace luabind; +using namespace eressea; + +static eressea::list +get_regions(void) { + return eressea::list(regions); +} + +static eressea::list +region_units(const region& r) { + return eressea::list(r.units); +} + +static eressea::list +region_buildings(const region& r) { + return eressea::list(r.buildings); +} + +static eressea::list +region_ships(const region& r) { + return eressea::list(r.ships); +} + +static void +region_setname(region& r, const char * name) { + if (r.land) rsetname((&r), name); +} + +static const char * +region_getname(const region& r) { + if (r.land) return r.land->name; + return r.terrain->name; +} + +static void +region_setinfo(region& r, const char * info) { + if (r.land) set_string(&r.land->display, info); +} + +static const char * +region_getinfo(const region& r) { + if (r.land) return r.land->display; + return NULL; +} + +void +bind_region(lua_State * L) +{ + module(L)[ + def("get_regions", &get_regions, return_stl_iterator), + def("get_region", &findregion), + + class_("region") + .property("name", ®ion_getname, ®ion_setname) + .property("info", ®ion_getinfo, ®ion_setinfo) + .def_readonly("x", ®ion::x) + .def_readonly("y", ®ion::y) + .def_readwrite("age", ®ion::age) + .property("units", ®ion_units, return_stl_iterator) + .property("buildings", ®ion_buildings, return_stl_iterator) + .property("ships", ®ion_ships, return_stl_iterator) + ]; +} diff --git a/src/eressea/lua/ship.cpp b/src/eressea/lua/ship.cpp new file mode 100644 index 000000000..6ee9e565f --- /dev/null +++ b/src/eressea/lua/ship.cpp @@ -0,0 +1,31 @@ +#include +#include +#include "bindings.h" + +// kernel includes +#include +#include + +// lua includes +#include +#include +#include + +using namespace luabind; +using namespace eressea; + +void +bind_ship(lua_State * L) +{ + module(L)[ + def("get_ship", &findship), + + class_("ship") + .def_readonly("name", &ship::name) + .def_readonly("region", &ship::region) + .def_readonly("id", &ship::no) + .def_readonly("info", &ship::display) + .def_readwrite("damage", &ship::damage) + .def_readwrite("size", &ship::size) + ]; +} diff --git a/src/eressea/lua/unit.cpp b/src/eressea/lua/unit.cpp new file mode 100644 index 000000000..ad699e883 --- /dev/null +++ b/src/eressea/lua/unit.cpp @@ -0,0 +1,28 @@ +#include +#include +#include "bindings.h" + +// kernel includes +#include +#include + +// lua includes +#include +#include +#include + +using namespace luabind; +using namespace eressea; + +void +bind_unit(lua_State * L) +{ + module(L)[ + def("get_unit", &findunit), + + class_("unit") + .def_readonly("name", &unit::name) + .def_readonly("region", &unit::region) + .def_readonly("id", &unit::no) + ]; +} diff --git a/src/eressea/main.cpp b/src/eressea/main.cpp new file mode 100644 index 000000000..fbe10edb7 --- /dev/null +++ b/src/eressea/main.cpp @@ -0,0 +1,685 @@ +/* vi: set ts=2: + * + * + * Eressea PB(E)M host Copyright (C) 1998-2000 + * Christian Schlittchen (corwin@amber.kn-bremen.de) + * Katja Zedel (katze@felidae.kn-bremen.de) + * Henning Peters (faroul@beyond.kn-bremen.de) + * Enno Rehling (enno@eressea-pbem.de) + * Ingo Wilken (Ingo.Wilken@informatik.uni-oldenburg.de) + * + * based on: + * + * Atlantis v1.0 13 September 1993 Copyright 1993 by Russell Wallace + * Atlantis v1.7 Copyright 1996 by Alex Schrö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 LOCALE_CHECK +#ifdef __LCC__ +#undef LOCALE_CHECK +#endif + +#include +#include + +#include "korrektur.h" + +/* initialization - TODO: init in separate module */ +#include +#include +#include +#include + +/* modules includes */ +#include +#include +#include +#ifdef INFOCMD_MODULE +# include +#endif + +/* gamecode includes */ +#include +#include +#include + +/* kernel includes */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* util includes */ +#include +#include +#include + +#ifdef HAVE_LUA +/* lua includes */ +#include "lua/bindings.h" +#include +#include +#endif + +/* libc includes */ +#include +#include +#include +#include +#include +#include + + +/** + ** global variables we are importing from other modules + **/ + +extern "C" { +#ifdef BETA_CODE +extern int xml_writeitems(const char * filename); +extern int xml_writeships(void); +extern int xml_writebuildings(void); +#endif + +extern item_type * i_silver; + +extern boolean nonr; +extern boolean nocr; +extern boolean noreports; +extern boolean nomer; +extern boolean nomsg; +extern boolean nobattle; +extern boolean nobattledebug; +extern boolean dirtyload; + +extern int loadplane; + +extern void debug_messagetypes(FILE * out); +extern void free_region(region * r); +extern void render_init(void); +extern void free_borders(void); +} + + +/** + ** global variables wthat we are exporting + **/ +static char * orders = NULL; +static char * xmlfile = NULL; +static int nowrite = 0; +static boolean g_writemap = false; +static boolean g_killeiswald = false; + +struct settings global = { + "Eressea", /* gamename */ + "eressea", /* resourcepath */ + 1000, /* maxunits */ +}; + +static int +crwritemap(void) +{ + FILE * F = fopen("world.cr", "w+"); + region * r; + for (r=regions;r;r=r->next) { + plane * p = rplane(r); + fprintf(F, "REGION %d %d %d\n", r->x, r->y, p?p->id:0); + fprintf(F, "\"%s\";Name\n\"%s\";Terrain\n", rname(r, default_locale), LOC(default_locale, rterrain(r)->name)); + } + fclose(F); + return 0; +} + +static void +game_init(void) +{ + init_triggers(); + + report_init(); + creport_init(); + + debug_language("locales.log"); + register_skills(); + + register_raceclass(); + register_races(); + register_resources(); + register_terrains(); + register_buildings(); + register_ships(); + register_items(); +#ifdef MAGIC + register_spells(); +#endif + register_dungeon(); + register_technology(); + register_alchemy(); +#ifdef MUSEUM_MODULE + register_museum(); +#endif +#ifdef ARENA_MODULE + register_arena(); +#endif + + init_data(xmlfile?xmlfile:"eressea.xml"); + init_locales(); + + init_attributes(); + init_resources(); + init_items(); + init_economy(); + init_rawmaterials(); + + init_gmcmd(); +#ifdef INFOCMD_MODULE + init_info(); +#endif + init_conversion(); + +#ifdef REMOVE_THIS + render_init(); + { + FILE * F = fopen("messagetypes.txt", "w"); + debug_messagetypes(F); + fclose(F); + abort(); + } +#endif +} + +static 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 +} + +#if 0 +static void +writefactiondata(void) +{ + FILE *F; + char zText[128]; + + sprintf(zText, "%s/faction-data.xml", basepath()); + F = cfopen(zText, "w"); + if(F) { + faction *f; + for(f = factions; f; f=f->next) { + fprintf(F,"\n"); + fprintf(F,"\t%s\n",itoa36(f->no)); + fprintf(F,"\t%s\n",f->name); + fprintf(F,"\t%s\n",f->email); + fprintf(F,"\t%s\n",f->passw); + fprintf(F,"\t%s\n",rc_name(f->race,1)); + fprintf(F,"\t%s\n",neue_gebiete[f->magiegebiet]); + fprintf(F,"\t%d\n",turn-f->lastorders); + fprintf(F,"\t%d\n",f->score); + fprintf(F,"\n"); + } + } + fclose(F); +} +#endif + +static void +writepasswd(void) +{ + FILE * F; + char zText[128]; + + sprintf(zText, "%s/passwd", basepath()); + F = cfopen(zText, "w"); + if (F) { + faction *f; + puts("Schreibe Passwörter..."); + + for (f = factions; f; f = f->next) { + fprintf(F, "%s:%s:%s:%s\n", + factionid(f), f->email, f->passw, f->override); + } + fclose(F); + } +} + +#ifdef HAVE_LUA +lua_State * luaState; + +void +lua_init(void) +{ + luaState = lua_open(); + luaopen_base(luaState); + luabind::open(luaState); + bind_region(luaState); + bind_unit(luaState); + bind_ship(luaState); + bind_building(luaState); +} + +void +lua_done(void) +{ + lua_close(luaState); +} +#endif + +static int +processturn(char *filename) +{ + struct summary * begin, * end; + int i; + + begin = make_summary(false); + printf(" - Korrekturen Runde %d\n", turn); + korrektur(); +#ifdef HAVE_LUA + lua_dofile(luaState, "test.lua"); +#endif + turn++; + puts(" - entferne Texte der letzten Runde"); + getgarbage(); + puts(" - Nehme Korrekturen am Datenbestand vor"); + if ((i=readorders(filename))!=0) return i; +#if BENCHMARK + exit(0); +#endif + processorders(); + score(); +#ifdef WACH_WAFF + remove_unequipped_guarded(); +#endif + korrektur_end(); + if (!noreports) reports(); + free_units(); + puts(" - Beseitige leere Parteien"); + remove_empty_factions(true); + end = make_summary(true); + report_summary(end, begin, false); + report_summary(end, begin, true); + free(end); + free(begin); + writepasswd(); + if (!nowrite) { + char ztext[64]; + sprintf(ztext, "%s/%d", datapath(), turn); + writegame(ztext, 0); + } + return 0; +} + +#ifdef CLEANUP_CODE +static void +game_done(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ötigt + * wird (temporäre Hilsstrukturen) */ + unit *u, *u2; + region *r, *r2; + building *b, *b2; + faction *f, *f2; + ship *s, *s2; + + 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); + } + r2 = r->next; + free_region(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 + creport_cleanup(); + report_cleanup(); +} +#endif + +#if MALLOCDBG +static 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 + +#if 0 +static void +write_stats(void) +{ + 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", magic_schools[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 }, ", skillname(sk, NULL), race[r].bonus[sk]); + ++i; + } + } + fputs("{ SK_NONE, 0 }\n};\n", F); + } + fclose(F); + } else { + sprintf(buf, "fopen(%s): ", zText); + perror(zText); + } +} +#endif + +static int +usage(const char * prog, const char * arg) +{ + if (arg) { + fprintf(stderr, "unknown argument: %s\n\n", arg); + } + fprintf(stderr, "Usage: %s [options]\n" + "-x n : Lädt nur die ersten n regionen\n" + "-f x y : Lädt nur die regionen ab (x,y)\n" + "-v befehlsdatei : verarbeitet automatisch die angegebene Befehlsdatei\n" + "-d datadir : gibt das datenverzeichnis an\n" + "-b basedir : gibt das basisverzeichnis an\n" + "-r resdir : gibt das resourceverzeichnis an\n" + "-t turn : read this datafile, not the most current one\n" + "-o reportdir : gibt das reportverzeichnis an\n" + "-l logfile : specify an alternative logfile\n" + "--noeiswald : beruhigt ungemein\n" + "--nomsg : keine Messages (RAM sparen)\n" + "--nobattle : keine Kämpfe\n" + "--nodebug : keine Logfiles für Kämpfe\n" + "--debug : schreibt Debug-Ausgaben in die Datei debug\n" + "--nocr : keine CRs\n" + "--nonr : keine Reports\n" +#ifdef USE_MERIAN + "--nomer : keine Meriankarten\n" +#endif + "--help : help\n", prog); + return -1; +} + +static int +read_args(int argc, char **argv) +{ + int i; + for (i=1;i!=argc;++i) { + if (argv[i][0]!='-') { + return usage(argv[0], argv[i]); + } else if (argv[i][1]=='-') { /* long format */ + if (strcmp(argv[i]+2, "nocr")==0) nocr = true; + else if (strcmp(argv[i]+2, "nosave")==0) nowrite = true; + else if (strcmp(argv[i]+2, "noreports")==0) { + noreports = true; + nocr = true; + nocr = true; + } + else if (strcmp(argv[i]+2, "xml")==0) xmlfile = argv[++i]; + else if (strcmp(argv[i]+2, "dirtyload")==0) dirtyload = true; + else if (strcmp(argv[i]+2, "nonr")==0) nonr = true; + else if (strcmp(argv[i]+2, "nomsg")==0) nomsg = true; + else if (strcmp(argv[i]+2, "noeiswald")==0) g_killeiswald = true; + else if (strcmp(argv[i]+2, "nobattle")==0) nobattle = true; + else if (strcmp(argv[i]+2, "nodebug")==0) nobattledebug = true; +#ifdef USE_MERIAN + else if (strcmp(argv[i]+2, "nomer")==0) nomer = true; +#endif + else if (strcmp(argv[i]+2, "help")==0) + return usage(argv[0], NULL); + else + return usage(argv[0], argv[i]); + } else switch(argv[i][1]) { + case 'o': + g_reportdir = argv[++i]; + break; + case 'd': + g_datadir = argv[++i]; + break; + case 'r': + g_resourcedir = argv[++i]; + break; + 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 'v': + if (iage==0) { + fprintf(sqlstream, "UPDATE subscriptions SET status='ACTIVE', faction='%s' WHERE game=%d AND password='%s';\n", itoa36(f->no), GAME_ID, f->passw); + } + f = f->next; + } +} + +int +main(int argc, char *argv[]) +{ + int i; + char zText[MAX_PATH]; + + updatelog = fopen("update.log", "w"); + log_open("eressea.log"); + printf("\n%s PBEM host\n" + "Copyright (C) 1996-2001 C.Schlittchen, K.Zedel, E.Rehling, H.Peters.\n\n" + "Compilation: " __DATE__ " at " __TIME__ "\nVersion: %f\n\n", global.gamename, version()); + + setlocale(LC_ALL, ""); + setlocale(LC_NUMERIC, "C"); +#ifdef LOCALE_CHECK + if (!locale_check()) { + log_error(("The current locale is not suitable for international Eressea.\n")); + return -1; + } +#endif +#if MALLOCDBG + init_malloc_debug(); +#endif + + if ((i=read_args(argc, argv))!=0) return i; + + printf( + "version %d.%d\n" + "turn %d.\n" + "orders %s.\n", + global.data_version / 10, global.data_version % 10, turn, orders); + + strcat(strcpy(zText, resourcepath()), "/timestrings"); + if ((i=read_datenames(zText))!=0) return i; + + kernel_init(); +#ifdef HAVE_LUA + lua_init(); +#endif + game_init(); +#ifdef BETA_CODE + /* xml_writeships(); */ + /* xml_writebuildings(); */ + /* xml_writeitems("items.xml"); */ + return 0; +#endif + + if ((i=readgame(false))!=0) return i; + confirm_newbies(); +#ifdef BETA_CODE + if (dungeonstyles) { + struct dungeon * d = dungeonstyles; + struct region * r = make_dungeon(d); + make_dungeongate(findregion(0, 0), r, d); + } +#endif + writepasswd(); + if (g_killeiswald) { + region * r = findregion(0, 25); + if (r) { + /* mach sie alle zur schnecke... */ + unit * u; + terraform(r, T_OCEAN); + for (u=r->units;u;u=u->next) scale_number(u, 1); + } + } + if (g_writemap) return crwritemap(); + + if ((i=processturn(orders))!=0) return i; + +#ifdef CLEANUP_CODE + game_done(); +#endif +#ifdef HAVE_LUA + lua_done(); +#endif + kernel_done(); + log_close(); + fclose(updatelog); + return 0; +}