diff --git a/src/common/modules/Makefile b/src/common/modules/Makefile new file mode 100644 index 000000000..e8b1c771f --- /dev/null +++ b/src/common/modules/Makefile @@ -0,0 +1,24 @@ +SUBDIRS = + +LIBRARY = libe-modules.a +BINARY = + +SOURCES = $(wildcard *.c) +OBJECTS = $(SOURCES:%.c=$(BUILD_DIR)/%.o) + +include $(ERESSEA)/Makefile.include + +## more definitions + +INCLUDES += -I../util -I../kernel -I../gamecode -I.. + +# library: +$(BUILD_DIR)/$(LIBRARY):: $(BUILD_DIR) $(OBJECTS) + $(AR) $(ARFLAGS) $@ $(OBJECTS) + $(INSTALL) $@ $(PUBLISH_DIR)/ + +# executable: +#$(BUILD_DIR)/$(BINARY):: $(OBJECTS) +# $(LD) $(LDFLAGS) -o $@ $(OBJECTS) +# $(INSTALL) $@ $(PUBLISH_DIR)/ + diff --git a/src/common/modules/Makefile~ b/src/common/modules/Makefile~ new file mode 100644 index 000000000..de862f25b --- /dev/null +++ b/src/common/modules/Makefile~ @@ -0,0 +1,26 @@ +SUBDIRS = + +LIBRARY = libe-modules.a +BINARY = + +SOURCES = $(wildcard *.c) +OBJECTS = $(SOURCES:%.c=$(BUILD_DIR)/%.o) + +OBJECTS -= $(BUILD_DIR)/weather.o + +include $(ERESSEA)/Makefile.include + +## more definitions + +INCLUDES += -I../util -I../kernel -I../gamecode -I.. + +# library: +$(BUILD_DIR)/$(LIBRARY):: $(BUILD_DIR) $(OBJECTS) + $(AR) $(ARFLAGS) $@ $(OBJECTS) + $(INSTALL) $@ $(PUBLISH_DIR)/ + +# executable: +#$(BUILD_DIR)/$(BINARY):: $(OBJECTS) +# $(LD) $(LDFLAGS) -o $@ $(OBJECTS) +# $(INSTALL) $@ $(PUBLISH_DIR)/ + diff --git a/src/common/modules/arena.c b/src/common/modules/arena.c new file mode 100644 index 000000000..cc7902d1f --- /dev/null +++ b/src/common/modules/arena.c @@ -0,0 +1,560 @@ +/* vi: set ts=2: + * + * $Id: arena.c,v 1.1 2001/01/27 11:32:32 enno Exp $ + * Eressea PB(E)M host Copyright (C) 1998-2000 + * Christian Schlittchen (corwin@amber.kn-bremen.de) + * Katja Zedel (katze@felidae.kn-bremen.de) + * Henning Peters (faroul@beyond.kn-bremen.de) + * Enno Rehling (enno@eressea-pbem.de) + * Ingo Wilken (Ingo.Wilken@informatik.uni-oldenburg.de) + * + * This program may not be used, modified or distributed without + * prior permission by the authors of Eressea. + */ + +#include +#include +#include "arena.h" + +/* modules include */ +#include "score.h" + +/* attributes include */ +#include + +/* items include */ +#include + +/* gamecode includes */ +#include + +/* kernel includes */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* util include */ +#include +#include +#include +#include + +/* libc include */ +#include +#include +#include + +extern int hashstring(const char* s); + +/* exports: */ +plane * arena = NULL; + + +/* local vars */ +#define CENTRAL_VOLCANO 1 + +static int arena_id = 0; +static region * arena_center = NULL; +static region * tower_region[6]; +static region * start_region[6]; +static int newarena = 0; + +static region * +arena_region(int magic) { + return tower_region[magic]; +} + +static building * +arena_tower(int magic) { + return arena_region(magic)->buildings; +} + +static boolean +give_igjarjuk(const unit * src, const unit * d, const item_type * itype, int n, const char * cmd) +{ + sprintf(buf, "Eine höhere Macht hindert %s daran, das Objekt zu übergeben. " + "'ES IST DEINS, MEIN KIND. DEINS GANZ ALLEIN'.", unitname(src)); + mistake(src, cmd, buf, MSG_COMMERCE); + return false; +} + +static int +leave_fail(unit * u) { + sprintf(buf, "Der Versuch, die Greifenschwingen zu benutzen, schlug fehl. %s konnte die Ebene der Herausforderung nicht verlassen.", unitname(u)); + addmessage(NULL, u->faction, buf, MSG_MESSAGE, ML_IMPORTANT); + return 1; +} + +static int +leave_arena(struct unit * u, const struct item_type * itype, const char * cmd) +{ + if (!u->building && leave_fail(u)) return -1; + if (u->building!=arena_tower(u->faction->magiegebiet) && leave_fail(u)) return -1; + unused(cmd); + unused(itype); + assert(!"not implemented"); + return 0; +} + +static resource_type rt_gryphonwing = { + { "griphonwing", "griphonwings" }, + { "griphonwing", "griphonwings" }, + RTF_ITEM, + &res_changeitem +}; + +static item_type it_gryphonwing = { + &rt_gryphonwing, /* resourcetype */ + ITF_NOTLOST|ITF_CURSED, 0, 0, /* flags, weight, capacity */ + 0, NOSKILL, /* minskill, skill */ + NULL, /* construction */ + &leave_arena, + &give_igjarjuk +}; + +static int +enter_fail(unit * u) { + sprintf(buf, "In %s erklingt die Stimme des Torwächters: 'Nur wer ohne materielle Güter und noch lernbegierig ist, der darf die Ebene der Herausforderung betreten. Und vergiß nicht mein Trinkgeld.'. %s erhielt keinen Einlaß.", regionid(u->region), unitname(u)); + addmessage(NULL, u->faction, buf, MSG_MESSAGE, ML_IMPORTANT); + return 1; +} + +static int +enter_arena(unit * u, const item_type * itype, const char * cmd) +{ + skill_t sk; + region * r = u->region; + unit * u2; + int fee = u->faction->score / 5; + unused(cmd); + unused(itype); + if (fee>2000) fee = 2000; + if (getplane(r)==arena) return -1; + if (u->number!=1 && enter_fail(u)) return -1; + if (get_pooled(u, r, R_SILVER) < fee && enter_fail(u)) return -1; + for (sk=0;sk!=MAXSKILLS;++sk) { + if (get_skill(u, sk)>30 && enter_fail(u)) return -1; + } + for (u2=r->units;u2;u2=u2->next) if (u2->faction==u->faction) break; +#ifdef NEW_ITEMS + assert(!"not implemented"); +#else + for (res=0;res!=MAXRESOURCES;++res) if (res!=R_SILVER && res!=R_ARENA_GATE && (is_item(res) || is_herb(res) || is_potion(res))) { + int x = get_resource(u, res); + if (x) { + if (u2) { + change_resource(u2, res, x); + change_resource(u, res, -x); + } + else if (enter_fail(u)) return -1; + } + } +#endif + if (get_money(u) > fee) { + if (u2) change_money(u2, get_money(u) - fee); + else if (enter_fail(u)) return -1; + } + sprintf(buf, "In %s öffnet sich ein Portal. Eine Stimme ertönt, und spricht: 'Willkommen in der Ebene der Herausforderung'. %s durchschreitet das Tor zu einer anderen Welt.", regionid(u->region), unitname(u)); + addmessage(NULL, u->faction, buf, MSG_MESSAGE, ML_IMPORTANT); + new_use_pooled(u, &rt_gryphonwing, GET_SLACK|GET_RESERVE, 1); + use_pooled(u, r, R_SILVER, fee); + set_money(u, 109); + fset(u, FL_PARTEITARNUNG); + move_unit(u, start_region[rand() % 6], NULL); + return 0; +} + +static resource_type rt_arenagate = { + { "eyeofdragon", "eyeofdragons" }, + { "eyeofdragon", "eyeofdragons" }, + RTF_ITEM, + &res_changeitem +}; + +static item_type it_arenagate = { + &rt_arenagate, /* resourcetype */ + ITF_NONE, 0, 0, /* flags, weight, capacity */ + 0, NOSKILL, /* minskill, skill */ + NULL, /* construction */ + &enter_arena +}; + +/*** + ** Szepter der Tränen, Demo-Item + ***/ + +static int +use_wand_of_tears(unit * user, const struct item_type * itype, const char * cmd) +{ + unit * u; + unused(cmd); + for (u=user->region->units;u;u=u->next) { + if (u->faction != user->faction) { + int i; + + for (i=0;i!=u->skill_size;++i) + change_skill(u, u->skills[i].id, -10); + add_message(&u->faction->msgs, new_message(u->faction, "wand_of_tears_effect%u:unit", u)); + } + } + add_message(&user->region->msgs, new_message(NULL, "wand_of_tears_usage%u:unit", user)); + return 0; +} + +static void +init_wand_of_tears(void) +{ + const char * names[2] = {"wand_of_tears", "wands_of_tears"}; + const char * appearances[2] = {"wand", "wands"}; + item_type * itype = it_find(names[0]); + int i; + + if (itype==NULL) { + /* Dieser Teil kann, nachdem sie ausgeteilt wurden, gänzlich verschwinden. */ + resource_type * rtype = new_resourcetype(names, appearances, RTF_DYNAMIC|RTF_ITEM); + itype = new_itemtype(rtype, ITF_DYNAMIC|ITF_NOTLOST, 1, 0, 0, NOSKILL); + itype->use = use_wand_of_tears; + for (i=0;i!=6;++i) { + unit * u = tower_region[i]->units; + if (u==NULL) continue; + i_change(&u->items, itype, 1); + } + } +} + +/** + * Tempel der Schreie, Demo-Gebäude **/ + +static int +age_hurting(attrib * a) { + building * b = (building *)a->data.v; + unit * u; + int active = 0; + if (b==NULL) return 0; + for (u=b->region->units;u;u=u->next) { + if (u->building==b) { + if (u->faction->magiegebiet==M_CHAOS) { + active ++; + add_message(&b->region->msgs, new_message(NULL, "praytoigjarjuk%u:unit", u)); + } + } + } + if (active) for (u=b->region->units;u;u=u->next) if (!nonplayer_race(u->faction->race)) { + int i; + if (u->faction->magiegebiet!=M_CHAOS) { + for (i=0;i!=active;++i) u->hp = (u->hp+1) / 2; /* make them suffer, but not die */ + add_message(&b->region->msgs, new_message(NULL, "cryinpain%u:unit", u)); + } + } + return 1; +} + +static void +write_hurting(const attrib * a, FILE * F) { + building * b = a->data.v; + fprintf(F, "%d", b->no); +} + +static int +read_hurting(attrib * a, FILE * F) { + int i; + fscanf(F, "%d", &i); + a->data.v = (void*)findbuilding(i); + if (a->data.v==NULL) { + fprintf(stderr, "WARNING: temple of pain is broken\n"); + return 0; + } + return 1; +} + +static attrib_type at_hurting = { + "hurting", NULL, NULL, age_hurting, write_hurting, read_hurting +}; + +static void +make_temple(region * r) +{ + const building_type * btype = bt_find("temple"); + building * b; + if (btype==NULL) + btype = bt_make("temple", BTF_UNIQUE | BTF_NOBUILD | BTF_INDESTRUCTIBLE, -1, 2, 50); + else { + b = r->buildings; + while (b!=NULL && b->type!=btype) b = b->next; + if (b!=NULL) return; /* gibt schon einen */ + } + + b = new_building(btype, r, NULL); + b->size = btype->maxsize; + b->name = strdup("Igjarjuk's Tempel der Schreie"); + b->display = strdup("Ein Schrein aus spitzen Knochen und lodernden Flammen, gewidmet dem Wyrm der Wyrme"); + a_add(&b->attribs, a_new(&at_hurting))->data.v=b; +} + +/** + * Initialisierung Türme */ + +static void +tower_init(void) +{ + int i, first = newarena; + for (i=0;i!=6;++i) { + region * r = tower_region[i] = findregion(arena_center->x+delta_x[i]*3, arena_center->y+delta_y[i]*3); + if (r) { + start_region[i] = findregion(arena_center->x+delta_x[i]*2, arena_center->y+delta_y[i]*2); + if (r->terrain!=T_DESERT) terraform(r, T_DESERT); + if (!r->buildings) { + building * b = new_building(&bt_castle, r, NULL); + b->size = 10; + if (i!=0) sprintf(buf, "Turm des %s", neue_gebiete[i]); + else sprintf(buf, "Turm der Ahnungslosen"); + set_string(&b->name, buf); + } + } + } + if (first && !arena_center->buildings) { + building * b = new_building(&bt_castle, arena_center, NULL); + attrib * a; + item * items; + + i_add(&items, i_new(&it_gryphonwing))->number=1; + i_add(&items, i_new(&it_demonseye))->number=1; + a = a_add(&b->attribs, make_giveitem(b, items)); + + b->size = 10; + set_string(&b->name, "Höhle des Greifen"); + } +} + +static void +guardian_faction(plane * pl, int id) +{ + unsigned int i; + region * r; + faction * f = findfaction(id); + + if (!f) { + f = calloc(1, sizeof(faction)); + f->banner = strdup("Sie dienen dem großen Wyrm"); + f->passw = strdup(" "); + for (i = 0; i < 4; i++) f->passw[i] = (char) (97 + rand() % 26); + f->email = strdup("igjarjuk@eressea-pbem.de"); + f->name = strdup("Igjarjuks Kundschafter"); + f->race = RC_ILLUSION; + f->age = turn; + f->locale = find_locale("de"); + f->options = want(O_COMPRESS) | want(O_REPORT) | want(O_COMPUTER) | want(O_ADRESSEN) | want(O_DEBUG); + + f->no = id; + addlist(&factions, f); + } + if (f->race != RC_ILLUSION) { + assert(!"guardian id vergeben"); + exit(0); + } + f->lastorders = turn; + f->alive = true; + for (r=regions;r;r=r->next) if (getplane(r)==pl && r->terrain!=T_FIREWALL) + { + unit * u; + freset(r, RF_ENCOUNTER); + for (u=r->units;u;u=u->next) { + if (u->faction==f) break; + } + if (u) continue; + u = createunit(r, f, 1, RC_GOBLIN); + set_string(&u->name, "Igjarjuks Auge"); + set_item(u, I_RING_OF_INVISIBILITY, 1); + u->thisorder = calloc(1, sizeof(char)); + u->lastorder = calloc(1, sizeof(char)); + fset(u, FL_PARTEITARNUNG); + set_money(u, 1000); + } +} + +static void +block_create(int x1, int y1, char terrain) +{ + int x, y; + for (x=0;x!=BLOCKSIZE;++x) { + for (y=0;y!=BLOCKSIZE;++y) { + region * r = new_region(x1 + x, y1 + y); + terraform(r, terrain); + } + } +} + +#ifdef CENTRAL_VOLCANO +building_type bt_caldera = { + "caldera", /* _name */ + BTF_NOBUILD|BTF_INDESTRUCTIBLE, /* flags */ + 1, -1, -1, /* capac, maxcap, maxsize */ + NULL, /* maintenance */ + NULL, /* construction */ + NULL /* name() */ +}; + + +static int +caldera_handle(trigger * t, void * data) +{ + /* call an event handler on caldera. + * data.v -> ( variant event, int timer ) + */ + building *b = (building *)t->data.v; + if (b!=NULL) { + unit ** up = &b->region->units; + while (*up) { + unit * u = *up; + if (u->building==b) { + sprintf(buf, "%s springt in die ewigen Feuer des Kraters.", unitname(u)); + if (u->items) { + item ** ip = &u->items; + strcat(buf, " Mit der sterblichen Hülle des Helden verglühen"); + while (*ip) { + item * i = *ip; + char zText[10]; + sprintf(zText, " %d %s", i->number, locale_string(NULL, resourcename(i->type->rtype, i->number!=1))); + strcat(buf, zText); + i_remove(ip, i); + if (*ip==i) ip=&i->next; + if (i->next) strcat(buf, ","); + } + strcat(buf, "."); + } + addmessage(u->region, NULL, buf, MSG_MESSAGE, ML_IMPORTANT); + set_number(u, 0); + } + if (*up==u) up = &u->next; + } + } else + fprintf(stderr, "\aERROR: could not perform caldera::handle()\n"); + unused(data); + return 0; +} + +static void +caldera_write(const trigger * t, FILE * F) +{ + building *b = (building *)t->data.v; + fprintf(F, "%s ", itoa36(b->no)); +} + +static int +caldera_read(trigger * t, FILE * F) +{ + char zText[128]; + int i; + + fscanf(F, "%s", zText); + i = atoi36(zText); + t->data.v = findbuilding(i); + if (t->data.v==NULL) ur_add((void*)i, &t->data.v, resolve_building); + + return 1; +} + +struct trigger_type tt_caldera = { + "caldera", + NULL, + NULL, + caldera_handle, + caldera_write, + caldera_read +}; + +static trigger * +trigger_caldera(building * b) +{ + trigger * t = t_new(&tt_caldera); + t->data.v = b; + return t; +} + +static void +init_volcano(void) +{ + building * b; + region * r = arena_center; + assert(arena_center); + if (r->terrain!=T_DESERT) return; /* been done before */ + terraform(arena_center, T_VOLCANO_SMOKING); + b = new_building(&bt_caldera, r, NULL); + b->size = 1; + b->name = strdup("Igjarjuk's Schlund"); + b->display = strdup("Feurige Lava fließt aus dem Krater des großen Vulkans. Alles wird von ihr verschlungen."); + add_trigger(&b->attribs, "timer", trigger_caldera(b)); + tt_register(&tt_caldera); +} +#endif + +void +create_arena(void) +{ + int x; + arena_id = hashstring("arena"); + arena = getplanebyid(arena_id); + if (arena!=NULL) return; + score(); /* ist wichtig, damit alle Parteien einen score haben, wenn sie durchs Tor wollen. */ + guardian_faction(arena, 999); + if (arena) arena_center = findregion(plane_center_x(arena), plane_center_y(arena)); + if (!arena_center) { + newarena = 1; + arena = create_new_plane(arena_id, "Arena", -10000, -10000, 0, BLOCKSIZE-1, PFL_LOWSTEALING | PFL_NORECRUITS | PFL_NOALLIANCES); + block_create(arena->minx, arena->miny, T_OCEAN); + arena_center = findregion(plane_center_x(arena), plane_center_y(arena)); + for (x=0;x!=BLOCKSIZE;++x) { + int y; + for (y=0;y!=BLOCKSIZE;++y) { + region * r = findregion(arena->minx+x, arena->miny+y); + freset(r, RF_ENCOUNTER); + r->planep = arena; + switch (distance(r, arena_center)) { + case 4: + terraform(r, T_FIREWALL); + break; + case 0: + terraform(r, T_GLACIER); + break; + case 1: + terraform(r, T_SWAMP); + break; + case 2: + terraform(r, T_MOUNTAIN); + break; + } + } + } + } + make_temple(arena_center); +#ifdef CENTRAL_VOLCANO + init_volcano(); +#else + if (arena_center->terrain!=T_DESERT) terraform(arena_center, T_DESERT); +#endif + rsetmoney(arena_center, 0); + rsetpeasants(arena_center, 0); + tower_init(); + init_wand_of_tears(); +} + +void +init_arena(void) +{ + at_register(&at_hurting); + it_register(&it_demonseye); + it_register(&it_arenagate); + it_register(&it_gryphonwing); + register_function((pf_generic)use_wand_of_tears, "use_wand_of_tears"); + tt_register(&tt_caldera); +} + diff --git a/src/common/modules/arena.h b/src/common/modules/arena.h new file mode 100644 index 000000000..2b0b37fc3 --- /dev/null +++ b/src/common/modules/arena.h @@ -0,0 +1,24 @@ +/* vi: set ts=2: + * + * $Id: arena.h,v 1.1 2001/01/27 11:32:32 enno Exp $ + * Eressea PB(E)M host Copyright (C) 1998-2000 + * Christian Schlittchen (corwin@amber.kn-bremen.de) + * Katja Zedel (katze@felidae.kn-bremen.de) + * Henning Peters (faroul@beyond.kn-bremen.de) + * Enno Rehling (enno@eressea-pbem.de) + * Ingo Wilken (Ingo.Wilken@informatik.uni-oldenburg.de) + * + * This program may not be used, modified or distributed without + * prior permission by the authors of Eressea. + */ + +#ifndef ARENA_H +#define ARENA_H + +/* exports: */ +extern struct plane * arena; + +extern void init_arena(void); +extern void create_arena(void); + +#endif diff --git a/src/common/modules/museum.c b/src/common/modules/museum.c new file mode 100644 index 000000000..f84f0ac01 --- /dev/null +++ b/src/common/modules/museum.c @@ -0,0 +1,407 @@ +/* vi: set ts=2: + * + * $Id: museum.c,v 1.1 2001/01/27 11:32:32 enno Exp $ + * Eressea PB(E)M host Copyright (C) 1998-2000 + * Christian Schlittchen (corwin@amber.kn-bremen.de) + * Katja Zedel (katze@felidae.kn-bremen.de) + * Henning Peters (faroul@beyond.kn-bremen.de) + * Enno Rehling (enno@eressea-pbem.de) + * Ingo Wilken (Ingo.Wilken@informatik.uni-oldenburg.de) + * + * This program may not be used, modified or distributed without + * prior permission by the authors of Eressea. + */ + +/* TODO: + * - Zweite Ausführung des Benutzes in Zielregion verhindern (Befehl + * löschen) + * - Meldungen + */ + +#include + +#include +#include "museum.h" + +/* gamecode includes */ +#include + +/* kernel includes */ +#include "unit.h" +#include "region.h" +#include "plane.h" +#include "item.h" +#include "terrain.h" +#include "movement.h" +#include "building.h" +#include "save.h" + +/* util includes */ +#include +#include + +/* libc includes */ +#include +#include + +resource_type rt_museumticket = { + { "museumticket", "museumtickets"}, + { "museumticket", "museumtickets"}, + RTF_ITEM, + &res_changeitem +}; + +item_type it_museumticket = { + &rt_museumticket, + ITF_NONE, 0, 0, + 0, NOSKILL, + NULL, + &use_museumticket +}; + +resource_type rt_museumexitticket = { + { "museumexitticket", "museumexittickets"}, + { "museumexitticket", "museumexittickets"}, + RTF_ITEM, + &res_changeitem +}; + +item_type it_museumexitticket = { + &rt_museumexitticket, + ITF_CURSED, 0, 0, + 0, NOSKILL, + NULL, + &use_museumexitticket +}; + +attrib_type at_museumexit = { + "museumexit", NULL, NULL, NULL, a_writedefault, a_readdefault +}; + +static void +a_initmuseumgivebackcookie(attrib *a) +{ + a->data.v = calloc(1,sizeof(museumgivebackcookie)); +} + +static void +a_finalizemuseumgivebackcookie(attrib *a) +{ + free(a->data.v); +} + +static void +a_writemuseumgivebackcookie(const attrib *a, FILE *f) +{ + museumgivebackcookie *gbc = (museumgivebackcookie *)a->data.v; + fprintf(f,"%d %d ", gbc->warden_no, gbc->cookie); +} + +static int +a_readmuseumgivebackcookie(attrib *a, FILE *f) +{ + museumgivebackcookie *gbc = (museumgivebackcookie *)a->data.v; + fscanf(f, "%d %d", &gbc->warden_no, &gbc->cookie); + return 1; +} + +attrib_type at_museumgivebackcookie = { + "museumgivebackcookie", + a_initmuseumgivebackcookie, + a_finalizemuseumgivebackcookie, + NULL, + a_writemuseumgivebackcookie, + a_readmuseumgivebackcookie +}; + +attrib_type at_warden = { + "itemwarden", NULL, NULL, NULL, a_writedefault, a_readdefault +}; + +static void +a_initmuseumgiveback(attrib *a) +{ + a->data.v = calloc(1, sizeof(museumgiveback)); +} + +static void +a_finalizemuseumgiveback(attrib *a) +{ + i_freeall(((museumgiveback *)(a->data.v))->items); + free(a->data.v); +} + +static void +a_writemuseumgiveback(const attrib *a, FILE *f) +{ + museumgiveback *gb = (museumgiveback *)a->data.v; + fprintf(f,"%d ", gb->cookie); + write_items(f, gb->items); +} + +static int +a_readmuseumgiveback(attrib *a, FILE *f) +{ + museumgiveback *gb = (museumgiveback *)a->data.v; + fscanf(f, "%d", &gb->cookie); + read_items(f, &gb->items); + return 1; +} + +attrib_type at_museumgiveback = { + "museumgiveback", + a_initmuseumgiveback, + a_finalizemuseumgiveback, + NULL, + a_writemuseumgiveback, + a_readmuseumgiveback +}; + +void +warden_add_give(unit *src, unit *u, const item_type *itype, int n) +{ + attrib *aw = a_find(u->attribs, &at_warden); + museumgiveback *gb = NULL; + museumgivebackcookie *gbc; + attrib *a; + + /* has the giver a cookie corresponding to the warden */ + for(a = a_find(src->attribs, &at_museumgivebackcookie); a; a=a->nexttype) { + if(((museumgivebackcookie *)(a->data.v))->warden_no == u->no) break; + } + + /* if not give it one */ + if(!a) { + a = a_add(&src->attribs, a_new(&at_museumgivebackcookie)); + gbc = (museumgivebackcookie *)a->data.v; + gbc->warden_no = u->no; + gbc->cookie = aw->data.i; + assert(aw->data.i < INT_MAX); + aw->data.i++; + } else { + gbc = (museumgivebackcookie *)(a->data.v); + } + + /* now we search for the warden's corresponding item list */ + for(a = a_find(u->attribs, &at_museumgiveback); a; a=a->nexttype) { + gb = (museumgiveback *)a->data.v; + if(gb->cookie == gbc->cookie) { + break; + } + } + + /* if there's none, give it one */ + if(!gb) { + a = a_add(&u->attribs, a_new(&at_museumgiveback)); + gb = (museumgiveback *)a->data.v; + gb->cookie = gbc->cookie; + } + + /* now register the items */ + i_change(&gb->items, itype, n); + + /* done */ + + /* this has a caveat: If the src-unit is destroyed while inside + * the museum, the corresponding itemlist of the warden will never + * be removed. to circumvent that in a generic way will be extremly + * difficult. */ +} + +void +init_museum(void) +{ + at_register(&at_warden); + at_register(&at_museumexit); + at_register(&at_museumgivebackcookie); + at_register(&at_museumgiveback); + + rt_register(&rt_museumticket); + it_register(&it_museumticket); + + rt_register(&rt_museumexitticket); + it_register(&it_museumexitticket); +} + +void +create_museum(void) +{ + int museum_id = hashstring("museum"); + plane *museum = getplanebyid(museum_id); + region *r; + building *b; + + if (!museum) { + museum = create_new_plane(museum_id, "Museum", 9500, 9550, + 9500, 9550, PFL_MUSEUM); + } + + if(findregion(9525, 9525) == NULL) { + /* Eingangshalle */ + r = new_region(9525, 9525); + terraform(r, T_HALL1); + r->planep = museum; + rsetname(r, "Eingangshalle"); + rsethorses(r, 0); + rsetmoney(r, 0); + rsetpeasants(r, 0); + set_string(&r->display, "Die Eingangshalle des Großen Museum der 1. Welt ist bereits jetzt ein beeindruckender Anblick. Obwohl das Museum noch nicht eröffnet ist, vermittelt sie bereits einen Flair exotischer Welten. In den Boden ist ein großer Kompass eingelassen, der den Besuchern bei Orientierung helfen soll."); + } + + r = findregion(9526, 9525); + if(!r) { + /* Lounge */ + r = new_region(9526, 9525); + terraform(r, T_HALL1); + r->planep = museum; + rsetname(r, "Lounge"); + rsethorses(r, 0); + rsetmoney(r, 0); + rsetpeasants(r, 0); + set_string(&r->display, "Die Lounge des großen Museums ist ein Platz, in dem sich die Besucher treffen, um die Eindrücke, die sie gewonnen haben, zu verarbeiten. Gemütliche Sitzgruppen laden zum Verweilen ein."); + } + + r = findregion(9526, 9525); + if(!r->buildings) { + b = new_building(&bt_generic, r, NULL); + set_string(&b->name, "Séparée im dämonischen Stil"); + set_string(&b->display, "Diese ganz im dämonischen Stil gehaltene Sitzgruppe ist ganz in dunklen Schwarztönen gehalten. Muster fremdartiger Runen bedecken das merkwürdig geformte Mobiliar, das unangenehm lebendig wirkt."); + + b = new_building(&bt_generic, r, NULL); + set_string(&b->name, "Séparée im elfischen Stil"); + set_string(&b->display, "Ganz in Grün- und Brauntönen gehalten wirkt die Sitzgruppe fast lebendig. Bei näherer Betrachtung erschließt sich dem Betrachter, daß sie tatsächlich aus lebenden Pflanzen erstellt ist. So ist der Tisch aus einem eizigen Baum gewachsen, und die Polster bestehen aus weichen Grassoden. Ein wunderschön gemusterter Webteppich mit tausenden naturgetreu eingestickter Blumensarten bedeckt den Boden."); + + b = new_building(&bt_generic, r, NULL); + set_string(&b->name, "Séparée im halblingschen Stil"); + set_string(&b->display, "Dieses rustikale Mobiliar ist aus einem einzigen, gewaltigen Baum hergestellt worden. Den Stamm haben fleißige Halblinge der Länge nach gevierteilt und aus den vier langen Viertelstämmen die Sitzbänke geschnitzt, während der verbleibende Stumpf als Tisch dient. Schon von weitem steigen dem Besucher die Gerüche der Köstlichkeiten entgegen, die auf dem Tisch stapeln."); + + b = new_building(&bt_generic, r, NULL); + set_string(&b->name, "Séparée im orkischen Stil"); + set_string(&b->display, "Grobgeschreinerte, elfenhautbespannte Stühle und ein Tisch aus Knochen, über deren Herkunft man sich lieber keine Gedanken macht, bilden die Sitzgruppe im orkischen Stil. Überall haben Orks ihre Namen, und anderes wenig zitierenswertes in das Holz und Gebein geritzt."); + + b = new_building(&bt_generic, r, NULL); + set_string(&b->name, "Séparée im Meermenschenstil"); + set_string(&b->display, "Ganz in Blau- und Grüntönen gehalten, mit Algen und Muscheln verziert wirken die aus altem Meerholz geschnitzten Stühle immer ein wenig feucht. Seltsammerweise hat der schwere aus alten Planken gezimmerte Tisch einen Mast mit kompletten Segel in der Mitte."); + + b = new_building(&bt_generic, r, NULL); + set_string(&b->name, "Séparée im Katzenstil"); + set_string(&b->display, "Die Wände dieses Séparée sind aus dunklem Holz. Was aus der Ferne wie ein chaotisch durchbrochenes Flechtwerk wirkt, entpuppt sich bei näherer Betrachtung als eine bis in winzige Details gestaltete dschungelartige Landschaft, in die eine Vielzahl von kleinen Bildergeschichten eingewoben sind. Wie es scheint hat sich der Künstler Mühe gegeben wirklich jedes Katzenvolk Eresseas zu porträtieren. Das schummrige Innere wird von einem Kamin dominiert, vor dem einige Sessel und weiche Kissen zu einem gemütlichen Nickerchen einladen. Feiner Anduner Sisal bezieht die Lehnen der Sessel und verlockt dazu, seine Krallen hinein zu versenken. Auf einem kleinen Ecktisch steht ein großer Korb mit roten Wollknäulen und grauen und braunen Spielmäusen."); + } else { + for(b=r->buildings; b; b=b->next) { + b->size = b->type->maxsize; + } + } + + r = findregion(9524, 9526); + if(!r) { + r = new_region(9524, 9526); + terraform(r, T_CORRIDOR1); + r->planep = museum; + rsetname(r, "Nördliche Promenade"); + rsethorses(r, 0); + rsetmoney(r, 0); + rsetpeasants(r, 0); + set_string(&r->display, "Die Nördliche Promenade führt direkt in den naturgeschichtlichen Teil des Museums."); + } + r = findregion(9525, 9524); + if(!r) { + r = new_region(9525, 9524); + terraform(r, T_CORRIDOR1); + r->planep = museum; + rsetname(r, "Südliche Promenade"); + rsethorses(r, 0); + rsetmoney(r, 0); + rsetpeasants(r, 0); + set_string(&r->display, "Die Südliche Promenade führt den Besucher in den kulturgeschichtlichen Teil des Museums."); + } +} + +int +use_museumticket(unit *u, const struct item_type *itype, const char * cmd) +{ + attrib *a; + region *r = u->region; + + /* Prüfen ob in normaler Plane und nur eine Person */ + if(r->planep != NULL) { + cmistake(u, cmd, 265, MSG_MAGIC); + return 0; + } + if(u->number != 1) { + cmistake(u, cmd, 267, MSG_MAGIC); + return 0; + } + if(get_item(u, I_HORSE)) { + cmistake(u, cmd, 272, MSG_MAGIC); + return 0; + } + + /* In diesem Attribut merken wir uns, wohin die Einheit zurückgesetzt + * wird, wenn sie das Museum verläßt. */ + + a = a_add(&u->attribs, a_new(&at_museumexit)); + a->data.sa[0] = (short)r->x; + a->data.sa[1] = (short)r->y; + + /* Benutzer in die Halle teleportieren */ + move_unit(u, findregion(9525, 9525), NULL); + + /* Ticket abziehen */ + i_change(&u->items, &it_museumticket, -1); + + /* Benutzer ein Exitticket geben */ + i_change(&u->items, &it_museumexitticket, 1); + + return 1; +} + +int +use_museumexitticket(unit *u, const struct item_type *itype, const char * cmd) +{ + attrib *a; + region *r; + unit *warden = findunit(atoi36("mwar")); + int unit_cookie; + + /* Prüfen ob in Eingangshalle */ + if(u->region->x != 9525 || u->region->y != 9525) { + cmistake(u, cmd, 266, MSG_MAGIC); + return 0; + } + + a = a_find(u->attribs, &at_museumexit); assert(a); + r = findregion(a->data.sa[0], a->data.sa[1]); assert(r); + a_remove(&u->attribs, a); + + /* Übergebene Gegenstände zurückgeben */ + + a = a_find(u->attribs, &at_museumgivebackcookie); + unit_cookie = a->data.i; + a_remove(&u->attribs, a); + + if(a) { + for(a = a_find(warden->attribs, &at_museumgiveback); a; a = a->nexttype) { + if(((museumgiveback *)(a->data.v))->cookie == unit_cookie) break; + } + if(a) { + museumgiveback *gb = (museumgiveback *)(a->data.v); + item *it; + + for(it = gb->items; it; it = it->next) { + i_change(&u->items, it->type, it->number); + } + sprintf(buf, "von %s: 'Hier habt ihr eure Sachen zurück.'", unitname(warden)); + addstrlist(&u->botschaften, buf); + a_remove(&warden->attribs, a); + } + } + + /* Benutzer zurück teleportieren */ + move_unit(u, r, NULL); + + /* Exitticket abziehen */ + i_change(&u->items, &it_museumexitticket, -1); + + return 1; +} + diff --git a/src/common/modules/museum.h b/src/common/modules/museum.h new file mode 100644 index 000000000..da158fe61 --- /dev/null +++ b/src/common/modules/museum.h @@ -0,0 +1,35 @@ +/* vi: set ts=2: + * + * $Id: museum.h,v 1.1 2001/01/27 11:32:32 enno Exp $ + * Eressea PB(E)M host Copyright (C) 1998-2000 + * Christian Schlittchen (corwin@amber.kn-bremen.de) + * Katja Zedel (katze@felidae.kn-bremen.de) + * Henning Peters (faroul@beyond.kn-bremen.de) + * Enno Rehling (enno@eressea-pbem.de) + * Ingo Wilken (Ingo.Wilken@informatik.uni-oldenburg.de) + * + * This program may not be used, modified or distributed without + * prior permission by the authors of Eressea. + */ + +extern attrib_type at_warden; +extern attrib_type at_museumexit; +extern attrib_type at_museumgivebackcookie; +extern attrib_type at_museumgiveback; + +typedef struct { + int warden_no; + int cookie; +} museumgivebackcookie; + +typedef struct { + int cookie; + struct item *items; +} museumgiveback; + +void warden_add_give(struct unit *src, struct unit *u, const struct item_type *itype, int n); +void init_museum(void); +void create_museum(void); +int use_museumticket(struct unit *u, const struct item_type *itype, const char *cmd); +int use_museumexitticket(struct unit *u, const struct item_type *itype, const char * cmd); + diff --git a/src/common/modules/oceannames.c b/src/common/modules/oceannames.c new file mode 100644 index 000000000..ae426bd33 --- /dev/null +++ b/src/common/modules/oceannames.c @@ -0,0 +1,126 @@ +/* vi: set ts=2: + * + * $Id: oceannames.c,v 1.1 2001/01/27 11:32:32 enno Exp $ + * Eressea PB(E)M host Copyright (C) 1998-2000 + * Christian Schlittchen (corwin@amber.kn-bremen.de) + * Katja Zedel (katze@felidae.kn-bremen.de) + * Henning Peters (faroul@beyond.kn-bremen.de) + * Enno Rehling (enno@eressea-pbem.de) + * Ingo Wilken (Ingo.Wilken@informatik.uni-oldenburg.de) + * + * This program may not be used, modified or distributed without + * prior permission by the authors of Eressea. + */ + +#include +#include +#include "oceannames.h" + +/* kernel includes */ +#include + +/* util includes */ +#include + +/* libc includes */ +#include +#include + +typedef struct namehash { + struct namehash * next; + const char * name; +} namehash; + +#define NMAXHASH 1023 +namehash names[NMAXHASH]; + +void nhash(const char * name); + +typedef struct faction_list { + struct faction_list * next; + struct faction * f; +} faction_list; + +typedef struct name { + struct name * next; + struct faction_list * factions; + const char * name; +} name; + +static void +free_names(attrib * a) +{ + name * data = (name*)a->data.v; + while (a->data.v) { + a->data.v = data->next; + free(data); + } +} + +struct attrib_type at_oceanname = { "names", NULL, free_names, NULL/*, write_names, read_names, ATF_UNIQUE */}; + +const char * +oceanname(const struct region * r, const struct faction * f) +{ + attrib * a = a_find(r->attribs, &at_oceanname); + if (a) { + name * names = (name*)a->data.v; + while (names) { + faction_list * fl = names->factions; + while (fl) { + if (fl->f==f) return names->name; + fl=fl->next; + } + names = names->next; + } + } + return NULL; +} + +void +nameocean(struct region *r, struct faction * f, const char * newname) +{ + attrib * a = a_find(r->attribs, &at_oceanname); + if (!a && newname) a = a_add(&r->attribs, a_new(&at_oceanname)); + if (a) { + faction_list **oldf = NULL, **newf = NULL; + faction_list * fl; + name * names = (name*)a->data.v; + while (names && (!newf && newname) || !oldf) { + faction_list ** fli = &names->factions; + if (oldf==NULL) while (*fli) { + if ((*fli)->f==f) { + oldf = fli; + break; + } + fli=&(*fli)->next; + } + if (newname && !newf && !strcmp(names->name, newname)) { + newf = fli; + } + names = names->next; + } + + if (oldf) { + fl = *oldf; + *oldf = fl->next; + } else if (newname) { + fl = calloc(1, sizeof(faction_list)); + } + + if (newf) { + fl->f = f; + fl->next = *newf; + *newf = fl; + } else if (newname) { + name * nm = calloc(1, sizeof(name)); + nm->factions = fl; + fl->f = f; + fl->next = NULL; + nm->next = (name*)a->data.v; + a->data.v = nm; + } else if (fl) { + free(fl); + } + } +} diff --git a/src/common/modules/oceannames.h b/src/common/modules/oceannames.h new file mode 100644 index 000000000..c65a3dd3d --- /dev/null +++ b/src/common/modules/oceannames.h @@ -0,0 +1,17 @@ +/* vi: set ts=2: + * + * $Id: oceannames.h,v 1.1 2001/01/27 11:32:32 enno Exp $ + * Eressea PB(E)M host Copyright (C) 1998-2000 + * Christian Schlittchen (corwin@amber.kn-bremen.de) + * Katja Zedel (katze@felidae.kn-bremen.de) + * Henning Peters (faroul@beyond.kn-bremen.de) + * Enno Rehling (enno@eressea-pbem.de) + * Ingo Wilken (Ingo.Wilken@informatik.uni-oldenburg.de) + * + * This program may not be used, modified or distributed without + * prior permission by the authors of Eressea. + */ + +struct faction; +struct region; +extern const char * oceanname(const struct region * r, const struct faction * f); diff --git a/src/common/modules/score.c b/src/common/modules/score.c new file mode 100644 index 000000000..0e8c3d797 --- /dev/null +++ b/src/common/modules/score.c @@ -0,0 +1,273 @@ +/* vi: set ts=2: + * + * $Id: score.c,v 1.1 2001/01/27 11:32:32 enno Exp $ + * 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. + */ + +#include +#include "eressea.h" + +#include "magic.h" +#include "item.h" +#include "region.h" +#include +#include +#include "race.h" +#include "unit.h" +#include "skill.h" +#include "goodies.h" +#include "ship.h" + +/* util includes */ +#include + +/* libc includes */ +#include + +static attrib_type a_score = { + "score" +}; + +void +init_scores(void) +{ + int i; + + for (i = 0;olditemtype[i];i++) { + const luxury_type * ltype; + item_type * itype = olditemtype[i]; + attrib * a = a_add(&itype->rtype->attribs, a_new(&a_score)); + switch (i) { + case I_KEKS: + case I_APFEL: + case I_NUSS: + case I_MANDELKERN: + break; + case I_IRON: + case I_WOOD: + case I_STONE: + case I_HORSE: + a->data.i = 10; + break; + case I_MALLORN: + a->data.i = 30; + break; + case I_EOG: + a->data.i = 100; + break; + case I_WAGON: + a->data.i = 60; + break; + case I_CATAPULT: + a->data.i = 200; + break; + case I_SWORD: + case I_SPEAR: + case I_CROSSBOW: + case I_LONGBOW: + case I_LANCE: + case I_HALBERD: + case I_GREATSWORD: + case I_AXE: + case I_SHIELD: + a->data.i = 20; + break; + case I_GREATBOW: + a->data.i = 50; + break; + case I_EOGSHIELD: + case I_EOGSWORD: + a->data.i = 400; + break; + case I_EOGCHAIN: + a->data.i = 1000; + break; + case I_CHAIN_MAIL: + a->data.i = 40; + break; + case I_PLATE_ARMOR: + a->data.i = 60; + break; + case I_BALM: + case I_SPICES: + case I_JEWELERY: + case I_MYRRH: + case I_OIL: + case I_SILK: + case I_INCENSE: + ltype = resource2luxury(itype->rtype); + if (ltype) a->data.i = ltype->price / 5; + break; +#ifdef COMPATIBILITY + case I_AMULET_OF_DARKNESS: + case I_AMULET_OF_DEATH: + case I_SHIELDSTONE: + case I_STAFF_OF_FIRE: + case I_STAFF_OF_LIGHTNING: + case I_WAND_OF_TELEPORTATION: + case I_CLOAK_OF_INVULNERABILITY: +#endif + case I_AMULET_OF_HEALING: + case I_AMULET_OF_TRUE_SEEING: + case I_RING_OF_INVISIBILITY: + case I_RING_OF_POWER: + case I_RUNESWORD: + case I_CHASTITY_BELT: + case I_FIRESWORD: + case I_TROLLBELT: + case I_RING_OF_NIMBLEFINGER: + case I_FEENSTIEFEL: + a->data.i = 6000; + break; + case I_ANTIMAGICCRYSTAL: + a->data.i = 2000; + break; + } + } +} + +int +average_score_of_age(int age, int a) +{ + faction *f; + int sum = 0, count = 0; + + for (f = factions; f; f = f->next) { + if (f->no != MONSTER_FACTION && f->age <= age + a && f->age >= age - a) { + sum += f->score; + count++; + } + } + + if (count == 0) { + return 0; + } + return sum / count; +} + +void +score(void) +{ + FILE *scoreFP; + region *r; + unit *u, *u2; + faction *f, *fbo; + building *b; + ship *s; + int allscores = 0; + int c; + static boolean init = false; + + if (!init) { + init=true; + init_scores(); + } + for (f = factions; f; f = f->next) f->score = 0; + + for (r = regions; r; r = r->next) { + for (b = r->buildings; b; b = b->next) { + if ((u = buildingowner(r, b)) != 0) { + fbo = u->faction; + + if (u->number <= b->size) + fbo->score += u->number * 5; + + fbo->score += b->size; + + c = b->size - u->number; + + for (u2 = r->units; u2 && c > 0; u2 = u2->next) { + if (u2->building == b && u2 != u && u2->number <= c) { + c -= u2->number; + + if (u2->faction == fbo) { + u2->faction->score += u2->number * 5; + } else { + u2->faction->score += u2->number * 3; + } + } + } + } + } + for (s = r->ships; s; s = s->next) { + if ((u = shipowner(r, s)) != 0) { + u->faction->score += s->size * 2; + } + } + for (u = r->units; u; u = u->next) { + char index; + item * itm; + if (u->race == RC_SPELL || u->race == RC_BIRTHDAYDRAGON) + continue; + + f = u->faction; + + if(u->race <= RC_AQUARIAN) { + f->score += (race[u->race].rekrutieren * u->number) / 50; + } + f->score += get_money(u) / 50; + for (itm=u->items; itm; itm=itm->next) { + attrib * a = a_find(itm->type->rtype->attribs, &a_score); + if (a!=NULL) f->score += itm->number * a->data.i / 10; + } + + for (index = 0; index != MAXSKILLS; index++) { + switch (index) { + case SK_MAGIC: + f->score += u->number * ((int) pow((double) eff_skill(u, index, r), + (double) 4)); + break; + case SK_TACTICS: + f->score += u->number * ((int) pow((double) eff_skill(u, index, r), + (double) 3)); + break; + case SK_SPY: + case SK_ALCHEMY: + case SK_HERBALISM: + f->score += u->number * ((int) pow((double) eff_skill(u, index, r), + (double) 2.5)); + break; + default: + f->score += u->number * ((int) pow((double) eff_skill(u, index, r), + (double) 2.5)) / 10; + break; + } + } + } + } + + for (f = factions; f; f = f->next) { + f->score = f->score / 5; + if (f->no != MONSTER_FACTION) + allscores += f->score; + } + if( allscores == 0 ) + allscores = 1; + + sprintf(buf, "%s/score", basepath()); + + scoreFP = fopen(buf, "w"); + for (f = factions; f; f = f->next) { + fprintf(scoreFP, "%8d (%7d/%4.2f%%) %32.32s (%3.3s) %5s (%3d)\n", + f->score, f->score - average_score_of_age(f->age, f->age / 24 + 1), + ((float) f->score / (float) allscores) * 100.0, f->name, + race[f->race].name[0], factionid(f), f->age); + } + + fclose(scoreFP); +} diff --git a/src/common/modules/score.h b/src/common/modules/score.h new file mode 100644 index 000000000..23cc8756c --- /dev/null +++ b/src/common/modules/score.h @@ -0,0 +1,28 @@ +/* vi: set ts=2: + * + * $Id: score.h,v 1.1 2001/01/27 11:32:32 enno Exp $ + * 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. + */ + +#ifndef SCORE_H +#define SCORE_H + +extern void score(void); +extern int average_score_of_age(int age, int a); + +#endif diff --git a/src/common/modules/weather.c b/src/common/modules/weather.c new file mode 100644 index 000000000..c88a96dfc --- /dev/null +++ b/src/common/modules/weather.c @@ -0,0 +1,148 @@ +/* vi: set ts=2: + * + * $Id: weather.c,v 1.1 2001/01/27 11:32:32 enno Exp $ + * 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. + */ + +/* + * Eressea Weather system. Compile with -DWEATHER to use this module + */ + +#ifdef WEATHER + +#include +#include +#include "weather.h" + +/* libc includes */ +#include + +weather * +create_weather(region *r, weather_t type) + +{ + weather *w; + + w = calloc(1, sizeof(weather)); + w->center[0] = r->x; + w->center[1] = r->y; + w->type = type; + w->move[0] = (rand()%3) - 1; + w->move[1] = (rand()%3) - 1; + + switch(type) { + case WEATHER_STORM: + w->radius = rand()%2+1; + break; + case WEATHER_HURRICANE: + w->radius = 1; + break; + default: + w->radius = 0; + } + + addlist(&weathers, w); + + return w; +} + +double +distance(int x1, int y1, int x2, int y2) + +{ + return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2)); +} + +/* Diese Funktion ermittelt für jede Region, welches Wetter in ihr + herrscht. Die Wettertypen sind dabei nach ihrer Reihenfolge in der + enumeration priorisiert. + + - Einladen + set_weather(); + - Eigentliche Auswertung + - Veränderungen des Wetters + set_weather(); + - Report generieren + - Abspeichern + + Diese Routine ist sehr rechenaufwendig! +*/ + +void +set_weather(void) + +{ + weather_t i; + weather *w; + short x, y; + int d; + region *r; + + for(r=regions;r;r=r->next) { + r->weathertype = WEATHER_NONE; + } + + for(i = 0; i < MAXWEATHERS; i++) { + for(w = weathers; w; w = w->next) { + if(w->type == i) { + for(x=w->center[0]-w->radius; x<=w->center[0]+w->radius; x++) { + for(y=w->center[1]-w->radius; y<=w->center[1]+w->radius; y++) { + d = distance(w->center[0], w->center[1], x, y); + if(floor(d+0.5) <= w->radius) { + r = findregion(x,y); + if(r) { + r->weathertype = w->type; + } + } + } + } + } + } + } +} + +void +move_weather(void) + +{ + weather *w, *wnext; + region *r; + + for(w = weathers; w;) { + wnext = w->next; + w->center[0] = w->center[0] + w->move[0]; + w->center[1] = w->center[1] + w->move[1]; + r = findregion(w->center[0], w->center[1]); + if(!r || rand()%100 < 5) { + removelist(&weathers, w); + } + w = wnext; + } +} + +#else +#include +static const char* copyright = "(c) Eressea PBEM 2000"; + +void +init_weather(void) +{ + fputs(copyright, stderr); + /* TODO: Initialization */ +} +#endif diff --git a/src/common/modules/weather.h b/src/common/modules/weather.h new file mode 100644 index 000000000..087c92c36 --- /dev/null +++ b/src/common/modules/weather.h @@ -0,0 +1,44 @@ +/* vi: set ts=2: + * + * $Id: weather.h,v 1.1 2001/01/27 11:32:32 enno Exp $ + * Eressea PB(E)M host Copyright (C) 1998-2000 + * Christian Schlittchen (corwin@amber.kn-bremen.de) + * Katja Zedel (katze@felidae.kn-bremen.de) + * Henning Peters (faroul@beyond.kn-bremen.de) + * Enno Rehling (enno@eressea-pbem.de) + * Ingo Wilken (Ingo.Wilken@informatik.uni-oldenburg.de) + * + * This program may not be used, modified or distributed without + * prior permission by the authors of Eressea. + */ + +#ifndef WEATHER_H +#define WEATHER_H + +#ifndef WEATHER +# error "the weather system is disabled" +#endif + +enum { + WEATHER_NONE, + WEATHER_STORM, + WEATHER_HURRICANE, + MAXWEATHERS +}; + +typedef unsigned char weather_t; + +typedef struct weather { + struct weather *next; + weather_t type; /* Typ der Wetterzone */ + int center[2]; /* Koordinaten des Zentrums */ + int radius; + int move[2]; +} weather; + +weather *weathers; + +void set_weather(void); +void move_weather(void); + +#endif diff --git a/src/common/modules/xmas2000.c b/src/common/modules/xmas2000.c new file mode 100644 index 000000000..b25c254bf --- /dev/null +++ b/src/common/modules/xmas2000.c @@ -0,0 +1,239 @@ +/* vi: set ts=2: + * + * $Id: xmas2000.c,v 1.1 2001/01/27 11:32:32 enno Exp $ + * Eressea PB(E)M host Copyright (C) 1998-2000 + * Christian Schlittchen (corwin@amber.kn-bremen.de) + * Katja Zedel (katze@felidae.kn-bremen.de) + * Henning Peters (faroul@beyond.kn-bremen.de) + * Enno Rehling (enno@eressea-pbem.de) + * Ingo Wilken (Ingo.Wilken@informatik.uni-oldenburg.de) + * + * This program may not be used, modified or distributed without + * prior permission by the authors of Eressea. + */ + +#include +#include +#include "xmas2000.h" + +/* gamecode includes */ +#include + +/* kernel includes */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* util includes */ +#include +#include +#include + +#include + +static int +xmasgate_handle(trigger * t, void * data) +{ + /* call an event handler on xmasgate. + * data.v -> ( variant event, int timer ) + */ + unit * santa = ufindhash(atoi36("xmas")); + building *b = (building *)t->data.v; + if (b!=NULL) { + unit ** up = &b->region->units; + if (santa->region!=b->region) santa = NULL; + while (*up) { + unit * u = *up; + if (u->building==b) { + region * r = u->region; + faction * f = u->faction; + unit * home = f->units; + unit * u2 = r->units; + while (u2) { + if (u2->faction==f && u2!=u && u2->number) break; + u2 = u2->next; + } + while (home && (home->region==b->region || home->region->land==NULL)) home = home->nextF; + if (home==NULL) continue; + if (santa!=NULL && u2==NULL) { + char zText[256]; + item_type * itype = olditemtype[(rand() % 4) + I_KEKS]; + i_change(&u->items, itype, 1); + sprintf(zText, "%s gibt %d %s an %s.", unitname(santa), 1, locale_string(f->locale, resourcename(itype->rtype, GR_PLURAL)), unitname(u)); + i_change(&u->items, itype, 1); + addmessage(home->region, u->faction, zText, MSG_COMMERCE, ML_INFO); + } + move_unit(u, home->region, NULL); + } + if (*up==u) up = &u->next; + } + } else + fprintf(stderr, "\aERROR: could not perform xmasgate::handle()\n"); + unused(data); + return 0; +} + +static void +xmasgate_write(const trigger * t, FILE * F) +{ + building *b = (building *)t->data.v; + fprintf(F, "%s ", itoa36(b->no)); +} + +static int +xmasgate_read(trigger * t, FILE * F) +{ + char zText[128]; + int i; + + fscanf(F, "%s", zText); + i = atoi36(zText); + t->data.v = findbuilding(i); + if (t->data.v==NULL) ur_add((void*)i, &t->data.v, resolve_building); + + return 1; +} + +struct trigger_type tt_xmasgate = { + "xmasgate", + NULL, + NULL, + xmasgate_handle, + xmasgate_write, + xmasgate_read +}; + +static trigger * +trigger_xmasgate(building * b) +{ + trigger * t = t_new(&tt_xmasgate); + t->data.v = b; + return t; +} + +static void +make_gates(region * r) +{ + const building_type * btype = bt_find("xmas_exit"); + building * b; + if (btype==NULL) + btype = bt_make("xmas_exit", BTF_NOBUILD | BTF_INDESTRUCTIBLE, -1, 2, 10); + else { + b = r->buildings; + while (b!=NULL && b->type!=btype) b = b->next; + if (b!=NULL) return; /* gibt schon einen */ + } + + b = new_building(btype, r, NULL); + b->size = btype->maxsize; + b->name = "Der Weg nach Hause"; + b->display = "Achtung, hier gibt es die Geschenke!"; + add_trigger(&b->attribs, "timer", trigger_xmasgate(b)); +} + +static unit * +make_santa(region * r) +{ + unit * santa = ufindhash(atoi36("xmas")); + + while (santa && santa->race!=RC_ILLUSION) { + uunhash(santa); + santa->no = newunitid(); + uhash(santa); + santa = ufindhash(atoi36("xmas")); + } + if (!santa) { + faction * f = findfaction(atoi36("rr")); + if (f==NULL) return NULL; + f->alive = true; + santa = createunit(r, f, 1, RC_ILLUSION); + uunhash(santa); + santa->no = atoi36("xmas"); + uhash(santa); + fset(santa, FL_PARTEITARNUNG); + santa->irace = RC_GNOME; + set_string(&santa->name, "Ein dicker Gnom mit einem Rentierschlitten"); + set_string(&santa->display, "hat: 12 Rentiere, Schlitten, Sack mit Geschenken, Kekse für Khorne"); + } + return santa; +} + +static void +santa_comes_to_town(region * r) +{ + unit * santa = make_santa(r); + faction * f; + + fset(santa, FL_TRAVELTHRU); + for (f = factions;f;f=f->next) { + unit * u; + unit * senior = f->units; + if (nonplayer_race(f->race)) continue; + for (u = f->units; u; u=u->nextF) { + if (senior->age < u->age) senior = u; + } + if (!senior) continue; + + sprintf(buf, "von %s: 'Ho ho ho. Frohe Weihnachten, und alles Gute für dein Volk, %s.'", unitname(santa), unitname(senior)); + addmessage(senior->region, 0, buf, MSG_MESSAGE, ML_IMPORTANT); + + travelthru(santa, senior->region); + } +} + +void +init_xmas2000(void) +{ + tt_register(&tt_xmasgate); +} + +void +create_xmas2000(int x, int y) +{ + const int prefixes = 18; + const char *prefix[] = { + "Artige", "Brave", "Liebe", "Nette", "Anständige", + "Rechtschaffene", "Tugendhafte", "Sittsame", "Ehrbare", "Keusche", + "Tugendsame", "Züchtige", "Fromme", "Musterhafte", "Manierliche", + "Tadellose", "Unverdorbene", "Höfliche" + }; + plane * xmas = getplanebyname("Nordpol"); + faction * f; + region * r = findregion(x, y); + direction_t dir; + + if (r!=NULL) { + make_santa(r); + return; + } + if (xmas==NULL) xmas = create_new_plane(2000, "Nordpol", x-1, x+1, y-1, y+1, PFL_NORECRUITS|PFL_NOALLIANCES|PFL_LOWSTEALING|PFL_NOGIVE|PFL_NOATTACK|PFL_NOMAGIC|PFL_NOSTEALTH|PFL_NOTEACH|PFL_NOBUILD|PFL_NOFEED|PFL_FRIENDLY); + r = new_region(x, y); + terraform(r, T_PLAIN); + set_string(&r->land->name, "Weihnachtsinsel"); + rsettrees(r, 1000); + rsetpeasants(r, 0); + rsetmoney(r, 0); + for (dir=0;dir!=MAXDIRECTIONS;++dir) { + region * n = findregion(x + delta_x[dir], y + delta_y[dir]); + if (n==NULL) n = new_region(x + delta_x[dir], y + delta_y[dir]); + terraform(n, T_OCEAN); + } + santa_comes_to_town(r); + for (f = factions; f != NULL; f = f->next) if (f->alive && f->units) { + char zText[128]; + unit * u; + + u = createunit(r, f, 2, f->race); + if (f->race==RC_DAEMON) u->irace = RC_HUMAN; + sprintf(zText, "%s %s", prefix[rand()%prefixes], race[u->irace].name[1]); + fset(u, FL_PARTEITARNUNG); + set_string(&u->name, zText); + } + make_gates(r); +} diff --git a/src/common/modules/xmas2000.h b/src/common/modules/xmas2000.h new file mode 100644 index 000000000..aadcb58a0 --- /dev/null +++ b/src/common/modules/xmas2000.h @@ -0,0 +1,21 @@ +/* vi: set ts=2: + * + * $Id: xmas2000.h,v 1.1 2001/01/27 11:32:32 enno Exp $ + * Eressea PB(E)M host Copyright (C) 1998-2000 + * Christian Schlittchen (corwin@amber.kn-bremen.de) + * Katja Zedel (katze@felidae.kn-bremen.de) + * Henning Peters (faroul@beyond.kn-bremen.de) + * Enno Rehling (enno@eressea-pbem.de) + * Ingo Wilken (Ingo.Wilken@informatik.uni-oldenburg.de) + * + * This program may not be used, modified or distributed without + * prior permission by the authors of Eressea. + */ + +#ifndef XMAS2000_H +#define XMAS2000_H + +extern void init_xmas2000(void); +extern void create_xmas2000(int x, int y); + +#endif