server/src/common/kernel/curse.c

1145 lines
25 KiB
C
Raw Normal View History

2001-01-25 10:37:55 +01:00
/* vi: set ts=2:
*
*
2001-01-25 10:37:55 +01:00
* Eressea PB(E)M host Copyright (C) 1998-2000
* Christian Schlittchen (corwin@amber.kn-bremen.de)
* Katja Zedel (katze@felidae.kn-bremen.de)
* Henning Peters (faroul@beyond.kn-bremen.de)
* Enno Rehling (enno@eressea-pbem.de)
* Ingo Wilken (Ingo.Wilken@informatik.uni-oldenburg.de)
*
* based on:
*
* Atlantis v1.0 13 September 1993 Copyright 1993 by Russell Wallace
* Atlantis v1.7 Copyright 1996 by Alex Schr<EFBFBD>der
*
* This program may not be used, modified or distributed without
* prior permission by the authors of Eressea.
* This program may not be sold or used commercially without prior written
* permission from the authors.
*/
#include <config.h>
#include "eressea.h"
#include "curse.h"
/* kernel includes */
#include "magic.h"
#include "skill.h"
2001-01-25 10:37:55 +01:00
#include "unit.h"
#include "region.h"
#include "race.h"
#include "faction.h"
#include "building.h"
#include "ship.h"
2001-01-25 10:37:55 +01:00
#include "objtypes.h"
/* util includes */
#include <resolve.h>
#include <base36.h>
/* libc includes */
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <limits.h>
#include <assert.h>
#include <math.h>
2002-05-09 12:22:12 +02:00
/* spells includes */
#include <spells/regioncurse.h>
#include <spells/unitcurse.h>
#include <spells/shipcurse.h>
#include <spells/buildingcurse.h>
2001-01-25 10:37:55 +01:00
/* ------------------------------------------------------------- */
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)
2001-01-25 10:37:55 +01:00
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;
2001-01-25 10:37:55 +01:00
}
/* ------------------------------------------------------------- */
/* Spruch identifizieren */
#include "umlaut.h"
typedef struct cursetype_list {
struct cursetype_list * next;
const curse_type * type;
} cursetype_list;
cursetype_list * cursetypes;
2001-01-25 10:37:55 +01:00
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;
2001-01-25 10:37:55 +01:00
}
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;
}
2001-01-25 10:37:55 +01:00
/* ------------------------------------------------------------- */
boolean
is_normalcurse(const curse_type * ct)
2001-01-25 10:37:55 +01:00
{
2002-04-28 10:23:34 +02:00
if (!ct) return false;
if (ct->typ == CURSETYP_NORM)
2001-01-25 10:37:55 +01:00
return true;
return false;
}
boolean
is_curseunit(const curse_type * ct)
2001-01-25 10:37:55 +01:00
{
2002-04-28 10:23:34 +02:00
if (!ct) return false;
if (ct->typ == CURSETYP_UNIT)
2001-01-25 10:37:55 +01:00
return true;
return false;
}
/* ------------------------------------------------------------- */
/* get_curse identifiziert eine Verzauberung <20>ber die ID und gibt
* einen pointer auf die struct zur<EFBFBD>ck.
*/
typedef struct cid {
2001-01-25 10:37:55 +01:00
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);
}
2001-01-25 10:37:55 +01:00
boolean
cmp_curse(const attrib * a, const void * data) {
const curse * c = (const curse*)data;
2001-01-25 10:37:55 +01:00
if (a->type->flags & ATF_CURSE) {
if (!data || c == (curse*)a->data.v) return true;
2001-01-25 10:37:55 +01:00
}
return false;
}
boolean
cmp_cursetype(const attrib * a, const void * data)
2001-01-25 10:37:55 +01:00
{
const curse_type * ct = (const curse_type *)data;
if (a->type->flags & ATF_CURSE) {
if (!data || ct == ((curse*)a->data.v)->type) return true;
2001-01-25 10:37:55 +01:00
}
return false;
2001-01-25 10:37:55 +01:00
}
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;
2001-01-25 10:37:55 +01:00
}
curse *
get_curse(attrib *ap, const curse_type * ctype)
2001-01-25 10:37:55 +01:00
{
attrib * a = a_select(ap, ctype, cmp_cursetype);
2001-01-25 10:37:55 +01:00
if (!a) return NULL;
return (curse*)a->data.v;
}
/* ------------------------------------------------------------- */
/* findet einen curse global anhand seiner 'curse-Einheitnummer' */
curse *
findcurse(int cid)
{
return cfindhash(cid);
}
2001-01-25 10:37:55 +01:00
/* ------------------------------------------------------------- */
/* Normalerweise ist alles ausser der Id eines curse und dem
* verzauberten Objekt nicht bekannt. Um den Zauber eindeutig zu
* identifizieren ben<EFBFBD>tigt man je nach Typ einen weiteren Identifier.
*/
void
remove_cursetype(attrib **ap, const curse_type *ct)
2001-01-25 10:37:55 +01:00
{
attrib *a = a_select(*ap, ct, cmp_cursetype);
2001-01-25 10:37:55 +01:00
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 *))
2001-01-25 10:37:55 +01:00
{
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<53>rke der Verzauberung zur<75>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)
2001-01-25 10:37:55 +01:00
{
if (c) return c->vigour;
return 0;
2001-01-25 10:37:55 +01:00
}
/* setzt die St<53>rke der Verzauberung auf i */
static void
set_cursevigour(curse *c, int vigour)
2001-01-25 10:37:55 +01:00
{
assert(c && vigour > 0);
c->vigour = vigour;
2001-01-25 10:37:55 +01:00
}
/* ver<65>ndert die St<53>rke der Verzauberung um +i und gibt die neue
* St<EFBFBD>rke zur<EFBFBD>ck. Sollte die Zauberst<EFBFBD>rke unter Null sinken, l<EFBFBD>st er
* sich auf.
*/
int
curse_changevigour(attrib **ap, curse *c, int vigour)
2001-01-25 10:37:55 +01:00
{
vigour += get_cursevigour(c);
2001-01-25 10:37:55 +01:00
if (vigour <= 0) {
remove_curse(ap, c);
vigour = 0;
} else {
set_cursevigour(c, vigour);
2001-01-25 10:37:55 +01:00
}
return vigour;
2001-01-25 10:37:55 +01:00
}
/* ------------------------------------------------------------- */
int
curse_geteffect(const curse *c)
2001-01-25 10:37:55 +01:00
{
if (c) return c->effect;
return 0;
2001-01-25 10:37:55 +01:00
}
/* ------------------------------------------------------------- */
void
set_curseingmagician(struct unit *magician, struct attrib *ap_target, const curse_type *ct)
2001-01-25 10:37:55 +01:00
{
curse * c = get_curse(ap_target, ct);
if (c) {
2001-01-25 10:37:55 +01:00
c->magician = magician;
}
}
unit *
get_cursingmagician(struct attrib *ap, const curse_type *ct)
2001-01-25 10:37:55 +01:00
{
curse *c = get_curse(ap, ct);
2001-01-25 10:37:55 +01:00
if( !c )
return NULL;
return c->magician;
}
/* Wichtig! Alle struct curse<typ>, die den Verweis auf den zaubenden
* Magier enthalten, m<EFBFBD>ssen sie hier mit abgepr<EFBFBD>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<68>nkten Verzauberungen die Anzahl der
* betroffenen Personen zur<EFBFBD>ck. Ansonsten wird 0 zur<EFBFBD>ckgegeben. */
2001-01-25 10:37:55 +01:00
int
get_cursedmen(unit *u, curse *c)
2001-01-25 10:37:55 +01:00
{
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;
2001-01-25 10:37:55 +01:00
}
return min(u->number, cursedmen);
2001-01-25 10:37:55 +01:00
}
/* setzt die Anzahl der betroffenen Personen auf cursedmen */
static void
set_cursedmen(curse *c, int cursedmen)
2001-01-25 10:37:55 +01:00
{
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;
}
2001-01-25 10:37:55 +01:00
}
int
change_cursedmen(attrib **ap, curse *c, int cursedmen)
2001-01-25 10:37:55 +01:00
{
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;
2001-01-25 10:37:55 +01:00
}
if (cursedmen <= 0) {
remove_curse(ap, c);
} else {
set_cursedmen(c, cursedmen);
}
2001-01-25 10:37:55 +01:00
return cursedmen;
}
/* ------------------------------------------------------------- */
void
curse_setflag(curse *c, int flag)
2001-01-25 10:37:55 +01:00
{
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<EFBFBD>ck.
*/
curse *
set_curse(unit *mage, attrib **ap, const curse_type *ct, int vigour,
2001-01-25 10:37:55 +01:00
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;
2001-01-25 10:37:55 +01:00
c->vigour = vigour;
c->duration = duration;
c->effect = effect;
c->magician = mage;
c->no = newunitid();
chash(c);
switch (c->type->typ) {
2001-01-25 10:37:55 +01:00
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,
2001-01-25 10:37:55 +01:00
int duration, int effect, int men)
{
curse *c;
2002-04-06 22:45:55 +02:00
/* die Kraft eines Spruchs darf nicht 0 sein*/
assert(vigour >= 0);
c = get_curse(*ap, ct);
2001-01-25 10:37:55 +01:00
if(c && (c->flag & CURSE_ONLYONE)){
return NULL;
}
assert(c==NULL || ct==c->type);
2001-01-25 10:37:55 +01:00
/* es gibt schon eins diese Typs */
if (c && ct->mergeflags != NO_MERGE) {
if(ct->mergeflags & M_DURATION){
2001-01-25 10:37:55 +01:00
c->duration = max(c->duration, duration);
}
if(ct->mergeflags & M_SUMDURATION){
2001-01-25 10:37:55 +01:00
c->duration += duration;
}
if(ct->mergeflags & M_SUMEFFECT){
2001-01-25 10:37:55 +01:00
c->effect += effect;
}
if(ct->mergeflags & M_MAXEFFECT){
2001-01-25 10:37:55 +01:00
c->effect = max(c->effect, effect);
}
if(ct->mergeflags & M_VIGOUR){
2001-01-25 10:37:55 +01:00
c->vigour = max(vigour, c->vigour);
}
if(ct->mergeflags & M_VIGOUR_ADD){
2001-01-31 18:40:53 +01:00
c->vigour = vigour + c->vigour;
}
if(ct->mergeflags & M_MEN){
switch (ct->typ) {
2001-01-25 10:37:55 +01:00
case CURSETYP_UNIT:
{
curse_unit * cc = (curse_unit*)c->data;
cc->cursedmen += men;
}
}
}
set_curseingmagician(magician, *ap, ct);
2001-01-25 10:37:55 +01:00
} else {
c = set_curse(magician, ap, ct, vigour, duration, effect, men);
2001-01-25 10:37:55 +01:00
}
return c;
}
/* ------------------------------------------------------------- */
/* hier m<>ssen alle c-typen, die auf Einheiten gezaubert werden k<>nnen,
* ber<EFBFBD>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;
2001-01-25 10:37:55 +01:00
switch (ct->typ) {
2001-01-25 10:37:55 +01:00
case CURSETYP_UNIT:
{
curse_unit * cc = (curse_unit*)c->data;
men = cc->cursedmen;
break;
}
default:
cursedmen = u->number;
}
switch (ct->spread){
2001-01-25 10:37:55 +01:00
case CURSE_SPREADALWAYS:
dogive = true;
men = u2->number + n;
break;
case CURSE_SPREADMODULO:
{
int i;
int u_number = u->number;
for (i=0;i<n+1 && u_number>0;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,
2001-01-25 10:37:55 +01:00
effect, men);
curse_setflag(cnew, flag);
2001-01-25 10:37:55 +01:00
if (ct->typ == CURSETYP_UNIT) set_cursedmen(cnew, men);
2001-01-25 10:37:55 +01:00
}
}
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)
2001-01-25 10:37:55 +01:00
{
if (!c) return false;
if (c->flag & CURSE_ISNEW) return false;
if (c->vigour <= 0) return false;
2002-04-06 22:45:55 +02:00
2001-01-25 10:37:55 +01:00
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;
}
2001-01-25 10:37:55 +01:00
/* ------------------------------------------------------------- */
/* Diese Funktionen werden von reports.c:print_curses() w<>hrend der
* Generierung des Normalreports aufgerufen und ersetzen
* cursedisplay
*/
/* C_MAGICSTONE*/
2001-01-25 10:37:55 +01:00
static int
cinfo_magicrunes(void * obj, typ_t typ, curse *c, int self)
2001-01-25 10:37:55 +01:00
{
if (typ == TYP_BUILDING){
building * b;
b = (building*)obj;
if (self){
sprintf(buf, "Auf den Mauern von %s erkennt man seltsame Runen. (%s)",
b->name, curseid(c));
return 1;
}
} else if (typ == TYP_SHIP) {
ship *sh;
sh = (ship*)obj;
if (self){
sprintf(buf, "Auf den Planken von %s erkennt man seltsame Runen. (%s)",
sh->name, curseid(c));
return 1;
}
2001-01-25 10:37:55 +01:00
}
return 0;
}
/* C_DISORIENTATION */
2001-01-25 10:37:55 +01:00
static int
cinfo_disorientation(void * obj, typ_t typ, curse *c, int self)
2001-01-25 10:37:55 +01:00
{
unused(typ);
unused(obj);
unused(self);
2001-01-25 10:37:55 +01:00
assert(typ == TYP_SHIP);
sprintf(buf, "Der Kompa<70> kaputt, die Segel zerrissen, der Himmel "
"wolkenverhangen. Wohin fahren wir? (%s)", curseid(c));
2001-01-25 10:37:55 +01:00
return 1;
}
static int
read_skill(FILE * F, curse * c)
{
int skill;
if (global.data_version<CURSETYPE_VERSION) {
int men;
fscanf(F, "%d %d", &skill, &men);
} else {
fscanf(F, "%d", &skill);
}
c->data = (void*)skill;
return 0;
}
static int
write_skill(FILE * F, const curse * c)
{
fprintf(F, "%d ", (int)c->data);
return 0;
}
2001-01-25 10:37:55 +01:00
/* ------------------------------------------------------------- */
/* cursedata */
/* ------------------------------------------------------------- */
/* typedef struct cursedata {
2002-04-28 10:40:21 +02:00
* int id; (altlast f<EFBFBD>r kompatibili<EFBFBD>t)
* char *name;
2001-01-25 10:37:55 +01:00
* int typ;
* spread_t spread;
2001-01-25 10:37:55 +01:00
* 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 curse_type cursedaten[MAXCURSE] =
2001-01-25 10:37:55 +01:00
{
/* struct's vom typ curse: */
{
"fogtrap",
2001-01-25 10:37:55 +01:00
CURSETYP_NORM, 0, (M_DURATION | M_VIGOUR),
"",
2002-05-09 12:22:12 +02:00
(cdesc_fun)cinfo_region
2001-01-25 10:37:55 +01:00
},
{
"antimagiczone",
2001-01-25 10:37:55 +01:00
CURSETYP_NORM, 0, (M_DURATION | M_VIGOUR),
"Dieser Zauber scheint magische Energien irgendwie abzuleiten und "
"so alle in der Region gezauberten Spr<70>che in ihrer Wirkung zu "
"schw<EFBFBD>chen oder ganz zu verhindern.",
NULL
},
{
"farvision",
2001-01-25 10:37:55 +01:00
CURSETYP_NORM, 0, (NO_MERGE),
"",
NULL
},
{
"gbdream",
2001-01-25 10:37:55 +01:00
CURSETYP_NORM, 0, (NO_MERGE),
"",
2002-05-09 13:17:31 +02:00
(cdesc_fun)cinfo_dreamcurse
2001-01-25 10:37:55 +01:00
},
{ /* Ver<65>ndert die max Aura und Regeneration um effect% */
"auraboost",
2001-01-25 10:37:55 +01:00
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.",
2002-05-09 12:12:08 +02:00
/* cinfo_auraboost */
2001-01-25 10:37:55 +01:00
},
{
"maelstrom",
2001-01-25 10:37:55 +01:00
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<EFBFBD>digen.",
NULL
},
{
"blessedharvest",
2001-01-25 10:37:55 +01:00
CURSETYP_NORM, 0, ( M_DURATION | M_VIGOUR ),
"Dieser Fruchtbarkeitszauber erh<72>ht die Ertr<74>ge der Felder.",
2002-05-09 12:22:12 +02:00
(cdesc_fun)cinfo_region
2001-01-25 10:37:55 +01:00
},
{
"drought",
2001-01-25 10:37:55 +01:00
CURSETYP_NORM, 0, ( M_DURATION | M_VIGOUR ),
"Dieser Zauber strahlt starke negative Energien aus. Warscheinlich "
"ist er die Ursache der D<>rre." ,
2002-05-09 12:22:12 +02:00
(cdesc_fun)cinfo_region
2001-01-25 10:37:55 +01:00
},
{
"badlearn",
2001-01-25 10:37:55 +01:00
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. ",
2002-05-09 12:22:12 +02:00
(cdesc_fun)cinfo_region
2001-01-25 10:37:55 +01:00
},
{ /* Sturmwind-Zauber, wirkt nur 1 Runde */
"stormwind",
2001-01-25 10:37:55 +01:00
CURSETYP_NORM, 0, NO_MERGE,
"",
NULL
},
{ /* Luftschiff-Zauber, wirkt nur 1 Runde */
"flyingship",
2001-01-25 10:37:55 +01:00
CURSETYP_NORM, 0, NO_MERGE,
"",
NULL
},
{ /* G<>nstigeWinde-Zauber */
"nodrift",
2001-01-25 10:37:55 +01:00
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<EFBFBD><EFBFBD>t es leichter durch die Wellen gleiten und der der Luft verbundene "
"Teil scheint es vor widrigen Winden zu sch<63>tzen.",
2002-05-09 12:12:08 +02:00
/* cinfo_shipnodrift */
2001-01-25 10:37:55 +01:00
},
{ /* Tr<54>bsal-Zauber */
"depression",
2001-01-25 10:37:55 +01:00
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<61>rlich. Dieser Fluch "
"hat sich wie ein bleiernes Tuch auf die Gem<65>ter der Bev<65>lkerung "
"gelegt und eh er nicht gebrochen oder verklungen ist, wird keiner "
"sich an Gaukelleien erfreuen k<>nnen.",
2002-05-09 12:22:12 +02:00
(cdesc_fun)cinfo_region
2001-01-25 10:37:55 +01:00
},
{ /* Heimstein-Zauber */
"magicwalls",
2001-01-25 10:37:55 +01:00
CURSETYP_NORM, 0, NO_MERGE,
"Die Macht dieses Zaubers ist fast greifbar und tief in die Mauern "
"gebunden. Starke elementarmagische Kr<4B>fte sind zu sp<73>ren. "
"Vieleicht wurde gar ein Erdelementar in diese Mauern gebannt. "
"Ausser ebenso starkter Antimagie wird nichts je diese Mauern "
"gef<EFBFBD>hrden k<>nnen.",
2002-05-09 12:12:08 +02:00
/* cinfo_magicstone */
2001-01-25 10:37:55 +01:00
},
{ /* Feste Mauer - Pr<50>kampfzauber, wirkt nur 1 Runde */
"strongwall",
2001-01-25 10:37:55 +01:00
CURSETYP_NORM, 0, NO_MERGE,
"",
NULL
},
{ /* Astralblock, auf Astralregion */
"astralblock",
2001-01-25 10:37:55 +01:00
CURSETYP_NORM, 0, NO_MERGE,
"",
2002-05-09 12:22:12 +02:00
(cdesc_fun)cinfo_region
2001-01-25 10:37:55 +01:00
},
{ /* Unterhaltungsanteil vermehren */
"generous",
2001-01-25 10:37:55 +01:00
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.",
2002-05-09 12:22:12 +02:00
(cdesc_fun)cinfo_region
2001-01-25 10:37:55 +01:00
},
{ /* verhindert Attackiere regional */
"peacezone",
2001-01-25 10:37:55 +01:00
CURSETYP_NORM, 0, NO_MERGE,
"Dieser machtvoller Beeinflussungszauber erstickt jeden Streit schon im "
"Keim.",
2002-05-09 12:22:12 +02:00
(cdesc_fun)cinfo_region
2001-01-25 10:37:55 +01:00
},
{ /* erschwert geordnete Bewegungen */
"disorientationzone",
2001-01-25 10:37:55 +01:00
CURSETYP_NORM, 0, NO_MERGE,
"",
2002-05-09 12:22:12 +02:00
(cdesc_fun)cinfo_region
2001-01-25 10:37:55 +01:00
},
{ /* erzeugt Stra<72>ennetz */
"magicstreet",
2001-01-25 10:37:55 +01:00
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<EFBFBD>e kommt man so viel besser und schneller vorw<72>rts.",
2002-05-09 12:12:08 +02:00
/* cinfo_magicstreet */
2001-01-25 10:37:55 +01:00
},
{
"magicrunes",
2001-01-25 10:37:55 +01:00
CURSETYP_NORM, 0, M_SUMEFFECT,
"Dieses Zauber verst<73>rkt die nat<61>rliche Widerstandskraft gegen eine "
"Verzauberung.",
2002-05-09 12:12:08 +02:00
/* cinfo_magicrunes */
2001-01-25 10:37:55 +01:00
},
{ /* erniedigt Magieresistenz von nicht-aliierten Einheiten, wirkt nur
2001-01-25 10:37:55 +01:00
1x pro Einheit */
"badmagicresistancezone",
2001-01-25 10:37:55 +01:00
CURSETYP_NORM, 0, NO_MERGE,
"Dieses Lied, das irgendwie in die magische Essenz der Region gewoben "
"ist, schw<68>cht die nat<61>rliche Widerstandskraft gegen eine "
"Verzauberung. Es scheint jedoch nur auf bestimmte Einheiten zu wirken.",
NULL
},
{ /* erh<72>ht Magieresistenz von aliierten Einheiten, wirkt nur 1x pro
2001-01-25 10:37:55 +01:00
Einheit */
"goodmagicresistancezone",
2001-01-25 10:37:55 +01:00
CURSETYP_NORM, 0, NO_MERGE,
"Dieser Lied, das irgendwie in die magische Essenz der Region gewoben "
"ist, verst<73>rkt die nat<61>rliche Widerstandskraft gegen eine "
"Verzauberung. Es scheint jedoch nur auf bestimmte Einheiten zu wirken.",
NULL
},
{ /* dient fremder Partei. Z<>hlt nicht zu Migranten, attackiert nicht */
"slavery",
2001-01-25 10:37:55 +01:00
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.",
2002-05-09 12:12:08 +02:00
/* cinfo_slave */
2001-01-25 10:37:55 +01:00
},
{
"shipdisorientation",
2001-01-25 10:37:55 +01:00
CURSETYP_NORM, 0, NO_MERGE,
"Dieses Schiff hat sich verfahren.",
2002-05-09 12:12:08 +02:00
/* cinfo_disorientation */
2001-01-25 10:37:55 +01:00
},
{
"calmmonster",
2001-01-25 10:37:55 +01:00
CURSETYP_NORM, CURSE_SPREADNEVER, NO_MERGE,
"Dieser Beeinflussungszauber scheint die Einheit einem ganz "
"bestimmten Volk wohlgesonnen zu machen.",
2002-05-09 12:12:08 +02:00
/* cinfo_calm */
2001-01-25 10:37:55 +01:00
},
{ /* Merkt sich die alte 'richtige' Rasse einer gestalltwandelnden
2001-01-25 10:37:55 +01:00
Einheit */
"oldrace",
2001-01-25 10:37:55 +01:00
CURSETYP_NORM, CURSE_SPREADALWAYS, NO_MERGE,
"",
NULL
},
{
"fumble",
2001-01-25 10:37:55 +01:00
CURSETYP_NORM, CURSE_SPREADNEVER, NO_MERGE,
"Eine Wolke negativer Energie umgibt die Einheit.",
2002-05-09 12:12:08 +02:00
/* cinfo_fumble */
2001-01-25 10:37:55 +01:00
},
{
"riotzone",
2001-01-25 10:37:55 +01:00
CURSETYP_NORM, 0, (M_DURATION),
"Eine Wolke negativer Energie liegt <20>ber der Region.",
2002-05-09 12:22:12 +02:00
(cdesc_fun)cinfo_region
2001-01-25 10:37:55 +01:00
},
{ /* Ewige Mauern-Zauber */
"nocostbuilding",
2001-01-25 10:37:55 +01:00
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<65>ude wohl "
"auf Ewig stehen.",
2002-05-09 12:22:12 +02:00
(cdesc_fun)cinfo_region
2001-01-25 10:37:55 +01:00
},
{
"holyground",
2001-01-31 18:40:53 +01:00
CURSETYP_NORM, 0, (M_VIGOUR_ADD),
"Verschiedene Naturgeistern sind im Boden der Region gebunden und "
"besch<EFBFBD>tzen diese vor dem der dunklen Magie des lebenden Todes.",
2002-05-09 12:22:12 +02:00
(cdesc_fun)cinfo_region
2001-01-25 10:37:55 +01:00
},
{
"godcursezone",
2001-01-25 10:37:55 +01:00
CURSETYP_NORM, 0, (NO_MERGE),
"Diese Region wurde von den G<>ttern verflucht. Stinkende Nebel ziehen "
"<EFBFBD>ber die tote Erde, furchbare Kreaturen ziehen <20>ber das Land. Die Brunnen "
"sind vergiftet, und die wenigen essbaren Fr<46>chte sind von einem rosa Pilz "
"<EFBFBD>berzogen. Niemand kann hier lange <20>berleben.",
2002-05-09 12:12:08 +02:00
/* cinfo_cursed_by_the_gods, */
2001-01-25 10:37:55 +01:00
},
{
2001-01-25 10:37:55 +01:00
"",
CURSETYP_NORM, 0, (NO_MERGE),
2001-01-25 10:37:55 +01:00
"",
NULL
},
{
2001-01-25 10:37:55 +01:00
"",
CURSETYP_NORM, 0, (NO_MERGE),
2001-01-25 10:37:55 +01:00
"",
NULL
},
{
2001-01-25 10:37:55 +01:00
"",
CURSETYP_NORM, 0, (NO_MERGE),
2001-01-25 10:37:55 +01:00
"",
NULL
},
{
2001-01-25 10:37:55 +01:00
"",
CURSETYP_NORM, 0, (NO_MERGE),
2001-01-25 10:37:55 +01:00
"",
NULL
},
{
2001-01-25 10:37:55 +01:00
"",
CURSETYP_NORM, 0, (NO_MERGE),
2001-01-25 10:37:55 +01:00
"",
NULL
},
{
2001-01-25 10:37:55 +01:00
"",
CURSETYP_NORM, 0, (NO_MERGE),
2001-01-25 10:37:55 +01:00
"",
NULL
},
/* struct's vom typ curse_unit: */
{
"speed",
CURSETYP_UNIT, CURSE_SPREADNEVER, M_MEN,
2001-01-25 10:37:55 +01:00
"Diese Einheit bewegt sich doppelt so schnell.",
2002-05-09 12:12:08 +02:00
/* cinfo_speed */
2001-01-25 10:37:55 +01:00
},
{
"orcish",
CURSETYP_UNIT, CURSE_SPREADMODULO, M_MEN,
"Dieser Zauber scheint die Einheit zu 'orkisieren'. Wie bei Orks "
2001-01-25 10:37:55 +01:00
"ist eine deutliche Neigung zur Fortpflanzung zu beobachten.",
2002-05-09 12:12:08 +02:00
/* cinfo_orc */
2001-01-25 10:37:55 +01:00
},
{
"magicboost",
CURSETYP_UNIT, CURSE_SPREADMODULO, M_MEN,
2001-01-25 10:37:55 +01:00
"",
NULL
},
{
"insectfur",
CURSETYP_UNIT, CURSE_SPREADMODULO, ( M_MEN | M_DURATION ),
2001-01-25 10:37:55 +01:00
"Dieser Zauber sch<63>tzt vor den Auswirkungen der K<>lte.",
2002-05-09 12:12:08 +02:00
/* cinfo_kaelteschutz */
2001-01-25 10:37:55 +01:00
},
{ /* */
"strength",
CURSETYP_UNIT, CURSE_SPREADMODULO, M_MEN,
2001-01-25 10:37:55 +01:00
"Dieser Zauber vermehrt die St<53>rke der verzauberten Personen um ein "
"vielfaches.",
2002-05-09 12:12:08 +02:00
/* cinfo_strength */
2001-01-25 10:37:55 +01:00
},
{ /* Alp */
"worse",
CURSETYP_UNIT, CURSE_SPREADMODULO, M_MEN,
2001-01-25 10:37:55 +01:00
"",
2002-05-09 12:12:08 +02:00
/* cinfo_allskills */
2001-01-25 10:37:55 +01:00
},
{ /* */
"magicresistance",
CURSETYP_UNIT, CURSE_SPREADMODULO, M_MEN,
2001-01-25 10:37:55 +01:00
"Dieser Zauber verst<73>rkt die nat<61>rliche Widerstandskraft gegen eine "
"Verzauberung.",
NULL
},
{ /* */
"itemcloak",
CURSETYP_UNIT, CURSE_SPREADNEVER, M_DURATION,
2001-01-25 10:37:55 +01:00
"Dieser Zauber macht die Ausr<73>stung unsichtbar.",
2002-05-09 12:12:08 +02:00
/* cinfo_itemcloak */
2001-01-25 10:37:55 +01:00
},
{ /* */
"sparkle",
CURSETYP_UNIT, CURSE_SPREADMODULO, ( M_MEN | M_DURATION ),
2001-01-25 10:37:55 +01:00
"Dieser Zauber ist einer der ersten, den junge Magier in der Schule lernen.",
2002-05-09 12:12:08 +02:00
/* cinfo_sparkle */
2001-01-25 10:37:55 +01:00
},
{
2001-01-25 10:37:55 +01:00
"",
CURSETYP_UNIT, 0, (NO_MERGE),
2001-01-25 10:37:55 +01:00
"",
NULL
},
{
2001-01-25 10:37:55 +01:00
"",
CURSETYP_UNIT, 0, (NO_MERGE),
2001-01-25 10:37:55 +01:00
"",
NULL
},
{
2001-01-25 10:37:55 +01:00
"",
CURSETYP_UNIT, 0, (NO_MERGE),
2001-01-25 10:37:55 +01:00
"",
NULL
},
/* struct's vom typ curse_skill: */
{
"skillmod",
CURSETYP_NORM, CURSE_SPREADMODULO, M_MEN,
2001-01-25 10:37:55 +01:00
"",
2002-05-09 12:12:08 +02:00
/* cinfo_skill, */
NULL, NULL, /* void (*change_vigour)(curse*, int); */
read_skill, write_skill
}
2001-01-25 10:37:55 +01:00
};
const char *
oldcursename(int id)
{
return cursedaten[id].cname;
}
2001-01-25 10:37:55 +01:00
void *
resolve_curse(void * id)
{
return cfindhash((int)id);
}
void
register_curses(void)
2001-01-25 10:37:55 +01:00
{
int i;
for (i=0;i!=MAXCURSE;++i) {
if (strlen(cursedaten[i].cname)) ct_register(&cursedaten[i]);
}
2001-01-25 10:37:55 +01:00
}