/* 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. */ #include #include "eressea.h" #include "curse.h" /* kernel includes */ #include "magic.h" #include "skill.h" #include "unit.h" #include "region.h" #include "race.h" #include "faction.h" #include "building.h" #include "ship.h" #include "objtypes.h" /* util includes */ #include #include /* libc includes */ #include #include #include #include #include #include /* spells includes */ #include #include #include #include /* ------------------------------------------------------------- */ direction_t dirmirror(direction_t dir) { return (direction_t)((dir+MAXDIRECTIONS/2) % MAXDIRECTIONS); } /* ------------------------------------------------------------- */ /* at_curse */ void curse_init(attrib * a) { a->data.v = calloc(1, sizeof(curse)); } int curse_age(attrib * a) { curse * c = (curse*)a->data.v; if (c->flag & CURSE_NOAGE) { c->duration = 1; } else { c->duration = max(0, c->duration-1); } return (c->duration); } void curse_done(attrib * a) { curse *c = (curse *)a->data.v; cunhash(c); if( c->data && c->type->typ == CURSETYP_UNIT) free(c->data); free(c); } attrib_type at_curse = { "curse", curse_init, curse_done, curse_age, curse_write, curse_read, ATF_CURSE }; /* ------------------------------------------------------------- */ #define MAXENTITYHASH 8191 curse *cursehash[MAXENTITYHASH]; void chash(curse *c) { curse *old = cursehash[c->no %MAXENTITYHASH]; cursehash[c->no %MAXENTITYHASH] = c; c->nexthash = old; } void cunhash(curse *c) { curse **show; for (show = &cursehash[c->no % MAXENTITYHASH]; *show; show = &(*show)->nexthash) { if ((*show)->no == c->no) break; } if (*show) { assert(*show == c); *show = (*show)->nexthash; c->nexthash = 0; } } curse * cfindhash(int i) { curse *old; for (old = cursehash[i % MAXENTITYHASH]; old; old = old->nexthash) if (old->no == i) return old; return NULL; } /* ------------------------------------------------------------- */ /* Spruch identifizieren */ #include "umlaut.h" typedef struct cursetype_list { struct cursetype_list * next; const curse_type * type; } cursetype_list; cursetype_list * cursetypes; void ct_register(const curse_type * ct) { cursetype_list ** ctlp = &cursetypes; while (*ctlp) { cursetype_list * ctl = *ctlp; if (ctl->type==ct) return; ctlp=&ctl->next; } *ctlp = calloc(1, sizeof(cursetype_list)); (*ctlp)->type = ct; } const curse_type * ct_find(const char *c) { cursetype_list * ctl = cursetypes; while (ctl) { int k = min(strlen(c), strlen(ctl->type->cname)); if (!strncasecmp(c, ctl->type->cname, k)) return ctl->type; ctl = ctl->next; } /* disable this assert to be able to remoce certain curses from the game * make sure that all locations using that curse can deal with a NULL * return value. */ assert(!"unknown cursetype"); return NULL; } /* ------------------------------------------------------------- */ boolean is_normalcurse(const curse_type * ct) { if (!ct) return false; if (ct->typ == CURSETYP_NORM) return true; return false; } boolean is_curseunit(const curse_type * ct) { if (!ct) return false; if (ct->typ == CURSETYP_UNIT) return true; return false; } /* ------------------------------------------------------------- */ /* get_curse identifiziert eine Verzauberung über die ID und gibt * einen pointer auf die struct zurück. */ typedef struct cid { int id; int id2; } twoids; boolean cmp_curseeffect(const curse * c, const void * data) { int effect = (int)data; return (c->effect==effect); } boolean cmp_cursedata(const curse * c, const void * data) { return (c->data==data); } boolean cmp_curse(const attrib * a, const void * data) { const curse * c = (const curse*)data; if (a->type->flags & ATF_CURSE) { if (!data || c == (curse*)a->data.v) return true; } return false; } boolean cmp_cursetype(const attrib * a, const void * data) { const curse_type * ct = (const curse_type *)data; if (a->type->flags & ATF_CURSE) { if (!data || ct == ((curse*)a->data.v)->type) return true; } return false; } curse * get_cursex(attrib *ap, const curse_type * ctype, void * data, boolean(*compare)(const curse *, const void *)) { attrib * a = a_select(ap, ctype, cmp_cursetype); while (a) { curse * c = (curse*)a->data.v; if (compare(c, data)) return c; a = a_select(a->next, ctype, cmp_cursetype); } return NULL; } curse * get_curse(attrib *ap, const curse_type * ctype) { attrib * a = a_select(ap, ctype, cmp_cursetype); if (!a) return NULL; return (curse*)a->data.v; } /* ------------------------------------------------------------- */ /* findet einen curse global anhand seiner 'curse-Einheitnummer' */ curse * findcurse(int cid) { return cfindhash(cid); } /* ------------------------------------------------------------- */ /* Normalerweise ist alles ausser der Id eines curse und dem * verzauberten Objekt nicht bekannt. Um den Zauber eindeutig zu * identifizieren benötigt man je nach Typ einen weiteren Identifier. */ void remove_cursetype(attrib **ap, const curse_type *ct) { attrib *a = a_select(*ap, ct, cmp_cursetype); if (a) a_remove(ap, a); } void remove_curse(attrib **ap, const curse *c) { attrib *a = a_select(*ap, c, cmp_curse); if (a) a_remove(ap, a); } void remove_allcurse(attrib **ap, const void * data, boolean(*compare)(const attrib *, const void *)) { attrib * a = a_select(*ap, data, compare); while (a) { attrib * next = a->nexttype; a_remove(ap, a); a = a_select(next, data, compare); } } /* gibt die allgemeine Stärke der Verzauberung zurück. id2 wird wie * oben benutzt. Dies ist nicht die Wirkung, sondern die Kraft und * damit der gegen Antimagie wirkende Widerstand einer Verzauberung */ static int get_cursevigour(const curse *c) { if (c) return c->vigour; return 0; } /* setzt die Stärke der Verzauberung auf i */ static void set_cursevigour(curse *c, int vigour) { assert(c && vigour > 0); c->vigour = vigour; } /* verändert die Stärke der Verzauberung um +i und gibt die neue * Stärke zurück. Sollte die Zauberstärke unter Null sinken, löst er * sich auf. */ int curse_changevigour(attrib **ap, curse *c, int vigour) { vigour += get_cursevigour(c); if (vigour <= 0) { remove_curse(ap, c); vigour = 0; } else { set_cursevigour(c, vigour); } return vigour; } /* ------------------------------------------------------------- */ int curse_geteffect(const curse *c) { if (c) return c->effect; return 0; } /* ------------------------------------------------------------- */ void set_curseingmagician(struct unit *magician, struct attrib *ap_target, const curse_type *ct) { curse * c = get_curse(ap_target, ct); if (c) { c->magician = magician; } } unit * get_cursingmagician(struct attrib *ap, const curse_type *ct) { curse *c = get_curse(ap, ct); if( !c ) return NULL; return c->magician; } /* Wichtig! Alle struct curse, die den Verweis auf den zaubenden * Magier enthalten, müssen sie hier mit abgeprüft werden */ void remove_cursemagepointer(unit *magician, attrib *ap_target) { const attrib * a; a = a_find(ap_target, &at_curse); while (a) { curse *c = (curse*)a->data.v; if(c->magician == magician) c->magician = (unit*)NULL; a = a->nexttype; } } /* ------------------------------------------------------------- */ /* gibt bei Personenbeschränkten Verzauberungen die Anzahl der * betroffenen Personen zurück. Ansonsten wird 0 zurückgegeben. */ int get_cursedmen(unit *u, curse *c) { int cursedmen = u->number; if (!c) return 0; /* je nach curse_type andere data struct */ if (c->type->typ == CURSETYP_UNIT){ curse_unit * cc = (curse_unit*)c->data; cursedmen = cc->cursedmen; } return min(u->number, cursedmen); } /* setzt die Anzahl der betroffenen Personen auf cursedmen */ static void set_cursedmen(curse *c, int cursedmen) { if (!c) return; /* je nach curse_type andere data struct */ if (c->type->typ == CURSETYP_UNIT) { curse_unit * cc = (curse_unit*)c->data; cc->cursedmen = cursedmen; } } int change_cursedmen(attrib **ap, curse *c, int cursedmen) { if (!c) return 0; /* je nach curse_type andere data struct */ if (c->type->typ == CURSETYP_UNIT) { curse_unit * cc = (curse_unit*)c->data; cursedmen += cc->cursedmen; } if (cursedmen <= 0) { remove_curse(ap, c); } else { set_cursedmen(c, cursedmen); } return cursedmen; } /* ------------------------------------------------------------- */ void curse_setflag(curse *c, int flag) { if (c) c->flag = (c->flag | flag); } /* ------------------------------------------------------------- */ /* Legt eine neue Verzauberung an. Sollte es schon einen Zauber * dieses Typs geben, gibt es den bestehenden zurück. */ curse * set_curse(unit *mage, attrib **ap, const curse_type *ct, int vigour, int duration, int effect, int men) { curse *c; attrib * a; a = a_new(&at_curse); a_add(ap, a); c = (curse*)a->data.v; c->type = ct; c->flag = 0; c->vigour = vigour; c->duration = duration; c->effect = effect; c->magician = mage; c->no = newunitid(); chash(c); switch (c->type->typ) { case CURSETYP_NORM: break; case CURSETYP_UNIT: { curse_unit *cc = calloc(1, sizeof(curse_unit)); cc->cursedmen += men; c->data = cc; break; } } return c; } /* Mapperfunktion für das Anlegen neuer curse. Automatisch wird zum * passenden Typ verzweigt und die relevanten Variablen weitergegeben. */ curse * create_curse(unit *magician, attrib **ap, const curse_type *ct, int vigour, int duration, int effect, int men) { curse *c; /* die Kraft eines Spruchs darf nicht 0 sein*/ assert(vigour >= 0); c = get_curse(*ap, ct); if(c && (c->flag & CURSE_ONLYONE)){ return NULL; } assert(c==NULL || ct==c->type); /* es gibt schon eins diese Typs */ if (c && ct->mergeflags != NO_MERGE) { if(ct->mergeflags & M_DURATION){ c->duration = max(c->duration, duration); } if(ct->mergeflags & M_SUMDURATION){ c->duration += duration; } if(ct->mergeflags & M_SUMEFFECT){ c->effect += effect; } if(ct->mergeflags & M_MAXEFFECT){ c->effect = max(c->effect, effect); } if(ct->mergeflags & M_VIGOUR){ c->vigour = max(vigour, c->vigour); } if(ct->mergeflags & M_VIGOUR_ADD){ c->vigour = vigour + c->vigour; } if(ct->mergeflags & M_MEN){ switch (ct->typ) { case CURSETYP_UNIT: { curse_unit * cc = (curse_unit*)c->data; cc->cursedmen += men; } } } set_curseingmagician(magician, *ap, ct); } else { c = set_curse(magician, ap, ct, vigour, duration, effect, men); } return c; } /* ------------------------------------------------------------- */ /* hier müssen alle c-typen, die auf Einheiten gezaubert werden können, * berücksichtigt werden */ void do_transfer_curse(curse *c, unit * u, unit * u2, int n) { int flag = c->flag; int duration = c->duration; int vigour = c->vigour; unit *magician = c->magician; int effect = c->effect; int cursedmen = 0; int men = 0; boolean dogive = false; const curse_type *ct = c->type; switch (ct->typ) { case CURSETYP_UNIT: { curse_unit * cc = (curse_unit*)c->data; men = cc->cursedmen; break; } default: cursedmen = u->number; } switch (ct->spread){ case CURSE_SPREADALWAYS: dogive = true; men = u2->number + n; break; case CURSE_SPREADMODULO: { int i; int u_number = u->number; for (i=0;i0;i++){ if (rand()%u_number < cursedmen){ ++men; --cursedmen; dogive = true; } --u_number; } break; } case CURSE_SPREADCHANCE: { int chance = u2->number * 100 / (u2->number + n); if (rand()%100 > chance ){ men = u2->number + n; dogive = true; } break; } case CURSE_SPREADNEVER: break; } if (dogive == true) { curse * cnew = set_curse(magician, &u2->attribs, c->type, vigour, duration, effect, men); curse_setflag(cnew, flag); if (ct->typ == CURSETYP_UNIT) set_cursedmen(cnew, men); } } void transfer_curse(unit * u, unit * u2, int n) { attrib * a; a = a_find(u->attribs, &at_curse); while (a) { curse *c = (curse*)a->data.v; do_transfer_curse(c, u, u2, n); a = a->nexttype; } } /* ------------------------------------------------------------- */ boolean curse_active(const curse *c) { if (!c) return false; if (c->flag & CURSE_ISNEW) return false; if (c->vigour <= 0) return false; return true; } boolean is_cursed_internal(attrib *ap, const curse_type *ct) { curse *c = get_curse(ap, ct); if (!c) return false; return true; } boolean is_cursed_with(attrib *ap, curse *c) { attrib *a = ap; while (a) { if ((a->type->flags & ATF_CURSE) && (c == (curse *)a->data.v)) { return true; } a = a->next; } return false; } /* ------------------------------------------------------------- */ static int read_skill(FILE * F, curse * c) { int skill; if (global.data_versiondata = (void*)skill; return 0; } static int write_skill(FILE * F, const curse * c) { fprintf(F, "%d ", (int)c->data); return 0; } /* ------------------------------------------------------------- */ /* cursedata */ /* ------------------------------------------------------------- */ /* typedef struct cursedata { * int id; (altlast für kompatibiliät) * char *name; * int typ; * spread_t spread; * int mergeflags; * char *info; * void (*display)(void*,typ_t, curse*); *} cursedata; */ /* die Beschreibung wird bei einer gelungenen Zauberanalyse ausgegeben * und hat die Form: * Magier (xx) gelang es folgendes herauszufinden: * Unit (xyz) steht unter dem Einfluss des Zaubers %name,/ Auf * Region/Schiff/Burg (xy) liegt der Zauber %name, * der wohl noch etwa %s Wochen andauert. * %info, "Dieser Zauber blafalsel blub" */ static struct curse_type ct_fogtrap = { "fogtrap", CURSETYP_NORM, 0, (M_DURATION | M_VIGOUR), "", cinfo_region }; static struct curse_type ct_antimagiczone = { "antimagiczone", CURSETYP_NORM, 0, (M_DURATION | M_VIGOUR), "Dieser Zauber scheint magische Energien irgendwie abzuleiten und " "so alle in der Region gezauberten Sprüche in ihrer Wirkung zu " "schwächen oder ganz zu verhindern.", NULL }; static struct curse_type ct_farvision = { "farvision", CURSETYP_NORM, 0, (NO_MERGE), "", NULL }; static struct curse_type ct_gbdream = { "gbdream", CURSETYP_NORM, 0, (NO_MERGE), "", cinfo_region }; static struct curse_type ct_auraboost = { "auraboost", CURSETYP_NORM, CURSE_SPREADMODULO, (NO_MERGE), "Dieser Zauber greift irgendwie in die Verbindung zwischen Magier " "und Magischer Essenz ein. Mit positiver Ausrichtung kann er wohl " "wie ein Fokus für Aura wirken, jedoch genauso für das Gegenteil " "benutzt werden." }; static struct curse_type ct_maelstrom = { "maelstrom", CURSETYP_NORM, 0, (M_DURATION | M_VIGOUR), "Dieser Zauber verursacht einen gigantischen magischen Strudel. Der " "Mahlstrom wird alle Schiffe, die in seinen Sog geraten, schwer " "beschädigen.", NULL }; static struct curse_type ct_blessedharvest = { "blessedharvest", CURSETYP_NORM, 0, ( M_DURATION | M_VIGOUR ), "Dieser Fruchtbarkeitszauber erhöht die Erträge der Felder.", cinfo_region }; static struct curse_type ct_drought = { "drought", CURSETYP_NORM, 0, ( M_DURATION | M_VIGOUR ), "Dieser Zauber strahlt starke negative Energien aus. Warscheinlich " "ist er die Ursache der Dürre." , cinfo_region }; static struct curse_type ct_badlearn = { "badlearn", CURSETYP_NORM, 0, ( M_DURATION | M_VIGOUR ), "Dieser Zauber scheint die Ursache für die Schlaflosigkeit und " "Mattigkeit zu sein, unter der die meisten Leute hier leiden und " "die dazu führt, das Lernen weniger Erfolg bringt. ", cinfo_region }; static struct curse_type ct_stormwind = { "stormwind", CURSETYP_NORM, 0, NO_MERGE, "", NULL }; static struct curse_type ct_flyingship = { "flyingship", CURSETYP_NORM, 0, NO_MERGE, "", NULL }; static struct curse_type ct_nodrift = { "nodrift", CURSETYP_NORM, 0, ( M_DURATION | M_VIGOUR ), "Der Zauber auf diesem Schiff ist aus den elementaren Magien der Luft " "und des Wassers gebunden. Der dem Wasser verbundene Teil des Zaubers " "läßt es leichter durch die Wellen gleiten und der der Luft verbundene " "Teil scheint es vor widrigen Winden zu schützen." }; static struct curse_type ct_depression = { "depression", CURSETYP_NORM, 0, ( M_DURATION | M_VIGOUR ), "Wie schon zu vermuten war, sind der ewig graue Himmel und die " "depressive Stimmung in der Region nicht natürlich. Dieser Fluch " "hat sich wie ein bleiernes Tuch auf die Gemüter der Bevölkerung " "gelegt und eh er nicht gebrochen oder verklungen ist, wird keiner " "sich an Gaukelleien erfreuen können.", cinfo_region }; static struct curse_type ct_magicwalls = { "magicwalls", CURSETYP_NORM, 0, NO_MERGE, "Die Macht dieses Zaubers ist fast greifbar und tief in die Mauern " "gebunden. Starke elementarmagische Kräfte sind zu spüren. " "Vieleicht wurde gar ein Erdelementar in diese Mauern gebannt. " "Ausser ebenso starkter Antimagie wird nichts je diese Mauern " "gefährden können." }; static struct curse_type ct_strongwall = { "strongwall", CURSETYP_NORM, 0, NO_MERGE, "", NULL }; static struct curse_type ct_astralblock = { "astralblock", CURSETYP_NORM, 0, NO_MERGE, "", cinfo_region }; static struct curse_type ct_generous = { "generous", CURSETYP_NORM, 0, ( M_DURATION | M_VIGOUR | M_MAXEFFECT ), "Dieser Zauber beeinflusst die allgemeine Stimmung in der Region positiv. " "Die gute Laune macht die Leute freigiebiger.", cinfo_region }; static struct curse_type ct_peacezone = { "peacezone", CURSETYP_NORM, 0, NO_MERGE, "Dieser machtvoller Beeinflussungszauber erstickt jeden Streit schon im " "Keim.", cinfo_region }; static struct curse_type ct_disorientationzone = { "disorientationzone", CURSETYP_NORM, 0, NO_MERGE, "", cinfo_region }; static struct curse_type ct_magicstreet = { "magicstreet", CURSETYP_NORM, 0, (M_DURATION | M_VIGOUR), "Es scheint sich um einen elementarmagischen Zauber zu handeln, der alle " "Pfade und Wege so gut festigt, als wären sie gepflastert. Wie auf einer " "Straße kommt man so viel besser und schneller vorwärts." }; static struct curse_type ct_magicrunes = { "magicrunes", CURSETYP_NORM, 0, M_SUMEFFECT, "Dieses Zauber verstärkt die natürliche Widerstandskraft gegen eine " "Verzauberung." }; static struct curse_type ct_badmagicresistancezone = { "badmagicresistancezone", CURSETYP_NORM, 0, NO_MERGE, "Dieses Lied, das irgendwie in die magische Essenz der Region gewoben " "ist, schwächt die natürliche Widerstandskraft gegen eine " "Verzauberung. Es scheint jedoch nur auf bestimmte Einheiten zu wirken.", NULL }; static struct curse_type ct_goodmagicresistancezone = { "goodmagicresistancezone", CURSETYP_NORM, 0, NO_MERGE, "Dieser Lied, das irgendwie in die magische Essenz der Region gewoben " "ist, verstärkt die natürliche Widerstandskraft gegen eine " "Verzauberung. Es scheint jedoch nur auf bestimmte Einheiten zu wirken.", NULL }; static struct curse_type ct_slavery = { "slavery", CURSETYP_NORM, 0, NO_MERGE, "Dieser mächtige Bann scheint die Einheit ihres freien Willens " "zu berauben. Solange der Zauber wirkt, wird sie nur den Befehlen " "ihres neuen Herrn gehorchen." }; static struct curse_type ct_shipdisorientation = { "shipdisorientation", CURSETYP_NORM, 0, NO_MERGE, "Dieses Schiff hat sich verfahren." }; static struct curse_type ct_calmmonster = { "calmmonster", CURSETYP_NORM, CURSE_SPREADNEVER, NO_MERGE, "Dieser Beeinflussungszauber scheint die Einheit einem ganz " "bestimmten Volk wohlgesonnen zu machen." }; static struct curse_type ct_oldrace = { "oldrace", CURSETYP_NORM, CURSE_SPREADALWAYS, NO_MERGE, "", NULL }; static struct curse_type ct_fumble = { "fumble", CURSETYP_NORM, CURSE_SPREADNEVER, NO_MERGE, "Eine Wolke negativer Energie umgibt die Einheit." }; static struct curse_type ct_riotzone = { "riotzone", CURSETYP_NORM, 0, (M_DURATION), "Eine Wolke negativer Energie liegt über der Region.", cinfo_region }; static struct curse_type ct_nocostbuilding = { "nocostbuilding", CURSETYP_NORM, 0, NO_MERGE, "Die Macht dieses Zaubers ist fast greifbar und tief in die Mauern " "gebunden. Unbeeindruck vom Zahn der Zeit wird dieses Gebäude wohl " "auf Ewig stehen.", cinfo_region }; static struct curse_type ct_holyground = { "holyground", CURSETYP_NORM, 0, (M_VIGOUR_ADD), "Verschiedene Naturgeistern sind im Boden der Region gebunden und " "beschützen diese vor dem der dunklen Magie des lebenden Todes.", cinfo_region }; static struct curse_type ct_godcursezone = { "godcursezone", CURSETYP_NORM, 0, (NO_MERGE), "Diese Region wurde von den Göttern verflucht. Stinkende Nebel ziehen " "über die tote Erde, furchbare Kreaturen ziehen über das Land. Die Brunnen " "sind vergiftet, und die wenigen essbaren Früchte sind von einem rosa Pilz " "überzogen. Niemand kann hier lange überleben." }; static struct curse_type ct_speed = { "speed", CURSETYP_UNIT, CURSE_SPREADNEVER, M_MEN, "Diese Einheit bewegt sich doppelt so schnell." }; static struct curse_type ct_orcish = { "orcish", CURSETYP_UNIT, CURSE_SPREADMODULO, M_MEN, "Dieser Zauber scheint die Einheit zu 'orkisieren'. Wie bei Orks " "ist eine deutliche Neigung zur Fortpflanzung zu beobachten." }; static struct curse_type ct_magicboost = { "magicboost", CURSETYP_UNIT, CURSE_SPREADMODULO, M_MEN, "", NULL }; static struct curse_type ct_insectfur = { "insectfur", CURSETYP_UNIT, CURSE_SPREADMODULO, ( M_MEN | M_DURATION ), "Dieser Zauber schützt vor den Auswirkungen der Kälte." }; static struct curse_type ct_strength = { "strength", CURSETYP_UNIT, CURSE_SPREADMODULO, M_MEN, "Dieser Zauber vermehrt die Stärke der verzauberten Personen um ein " "vielfaches." }; static struct curse_type ct_worse = { "worse", CURSETYP_UNIT, CURSE_SPREADMODULO, M_MEN, "" }; static struct curse_type ct_magicresistance = { "magicresistance", CURSETYP_UNIT, CURSE_SPREADMODULO, M_MEN, "Dieser Zauber verstärkt die natürliche Widerstandskraft gegen eine " "Verzauberung.", NULL }; static struct curse_type ct_itemcloak = { "itemcloak", CURSETYP_UNIT, CURSE_SPREADNEVER, M_DURATION, "Dieser Zauber macht die Ausrüstung unsichtbar." }; static struct curse_type ct_sparkle = { "sparkle", CURSETYP_UNIT, CURSE_SPREADMODULO, ( M_MEN | M_DURATION ), "Dieser Zauber ist einer der ersten, den junge Magier in der Schule lernen." }; static struct curse_type ct_skillmod = { "skillmod", CURSETYP_NORM, CURSE_SPREADMODULO, M_MEN, "", cinfo_unit, NULL, read_skill, write_skill }; void * resolve_curse(void * id) { return cfindhash((int)id); } void register_curses(void) { ct_register(&ct_fogtrap); ct_register(&ct_antimagiczone); ct_register(&ct_farvision); ct_register(&ct_gbdream); ct_register(&ct_auraboost); ct_register(&ct_maelstrom); ct_register(&ct_blessedharvest); ct_register(&ct_drought); ct_register(&ct_badlearn); ct_register(&ct_stormwind); ct_register(&ct_flyingship); ct_register(&ct_nodrift); ct_register(&ct_depression); ct_register(&ct_magicwalls); ct_register(&ct_strongwall); ct_register(&ct_astralblock); ct_register(&ct_generous); ct_register(&ct_peacezone); ct_register(&ct_disorientationzone); ct_register(&ct_magicstreet); ct_register(&ct_magicrunes); ct_register(&ct_badmagicresistancezone); ct_register(&ct_goodmagicresistancezone); ct_register(&ct_slavery); ct_register(&ct_shipdisorientation); ct_register(&ct_calmmonster); ct_register(&ct_oldrace); ct_register(&ct_fumble); ct_register(&ct_riotzone); ct_register(&ct_nocostbuilding); ct_register(&ct_holyground); ct_register(&ct_godcursezone); ct_register(&ct_speed); ct_register(&ct_orcish); ct_register(&ct_magicboost); ct_register(&ct_insectfur); ct_register(&ct_strength); ct_register(&ct_worse); ct_register(&ct_magicresistance); ct_register(&ct_itemcloak); ct_register(&ct_sparkle); ct_register(&ct_skillmod); } static const char * oldnames[MAXCURSE] = { "fogtrap", "antimagiczone", "farvision", "gbdream", "auraboost", "maelstrom", "blessedharvest", "drought", "badlearn", "stormwind", "flyingship", "nodrift", "depression", "magicwalls", "strongwall", "astralblock", "generous", "peacezone", "disorientationzone", "magicstreet", "magicrunes", "badmagicresistancezone", "goodmagicresistancezone", "slavery", "shipdisorientation", "calmmonster", "oldrace", "fumble", "riotzone", "nocostbuilding", "holyground", "godcursezone", "", "", "", "", "", "", "speed", "orcish", "magicboost", "insectfur", "strength", "worse", "magicresistance", "itemcloak", "sparkle", "", "", "", "skillmod" }; const char * oldcursename(int id) { return oldnames[id]; }