diff --git a/src/kernel/curse.c b/src/kernel/curse.c index 1761d754d..7735e3333 100644 --- a/src/kernel/curse.c +++ b/src/kernel/curse.c @@ -1,7 +1,7 @@ /* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel +Copyright (c) 1998-2014, Enno Rehling +Katja Zedel Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above @@ -61,228 +61,233 @@ curse *cursehash[MAXENTITYHASH]; void c_setflag(curse * c, unsigned int flags) { - assert(c); - c->flags = (c->flags & ~flags) | (flags & (c->type->flags ^ flags)); + assert(c); + c->flags = (c->flags & ~flags) | (flags & (c->type->flags ^ flags)); } /* -------------------------------------------------------------------------- */ void c_clearflag(curse * c, unsigned int flags) { - assert(c); - c->flags = (c->flags & ~flags) | (c->type->flags & flags); + assert(c); + c->flags = (c->flags & ~flags) | (c->type->flags & flags); } void chash(curse * c) { - curse *old = cursehash[c->no % MAXENTITYHASH]; + curse *old = cursehash[c->no % MAXENTITYHASH]; - cursehash[c->no % MAXENTITYHASH] = c; - c->nexthash = old; + cursehash[c->no % MAXENTITYHASH] = c; + c->nexthash = old; } static void cunhash(curse * c) { - curse **show; + 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; - } + 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; + curse *old; - for (old = cursehash[i % MAXENTITYHASH]; old; old = old->nexthash) - if (old->no == i) - return old; - return NULL; + for (old = cursehash[i % MAXENTITYHASH]; old; old = old->nexthash) + if (old->no == i) + return old; + return NULL; } /* ------------------------------------------------------------- */ /* at_curse */ void curse_init(attrib * a) { - a->data.v = calloc(1, sizeof(curse)); + a->data.v = calloc(1, sizeof(curse)); } int curse_age(attrib * a) { - curse *c = (curse *) a->data.v; - int result = 0; + curse *c = (curse *)a->data.v; + int result = 0; - if (c_flags(c) & CURSE_NOAGE) { - c->duration = INT_MAX; - } - if (c->type->age) { - result = c->type->age(c); - } - if (result != 0) { - c->duration = 0; - } else if (c->duration != INT_MAX) { - c->duration = _max(0, c->duration - 1); - } - return c->duration; + if (c_flags(c) & CURSE_NOAGE) { + c->duration = INT_MAX; + } + if (c->type->age) { + result = c->type->age(c); + } + if (result != 0) { + c->duration = 0; + } + else if (c->duration != INT_MAX) { + c->duration = _max(0, c->duration - 1); + } + return c->duration; } void destroy_curse(curse * c) { - cunhash(c); - free(c); + cunhash(c); + free(c); } void curse_done(attrib * a) { - destroy_curse((curse *) a->data.v); + destroy_curse((curse *)a->data.v); } /** reads curses that have been removed from the code */ static int read_ccompat(const char *cursename, struct storage *store) { - struct compat { - const char *name; - const char *tokens; - } *seek, old_curses[] = { { - "disorientationzone", ""}, { - "shipdisorientation", ""}, { - NULL, NULL}}; - for (seek = old_curses; seek->name; ++seek) { - if (strcmp(seek->tokens, cursename) == 0) { - const char *p; - for (p = seek->name; p; ++p) { - switch (*p) { - case 'd': - READ_INT(store, 0); - break; - case 's': - READ_STR(store, 0, 0); - break; - case 't': - READ_TOK(store, 0, 0); - break; - case 'i': - READ_INT(store, 0); - break; - case 'f': - READ_FLT(store, 0); - break; + struct compat { + const char *name; + const char *tokens; + } *seek, old_curses[] = { { + "disorientationzone", "" }, { + "shipdisorientation", "" }, { + NULL, NULL } }; + for (seek = old_curses; seek->name; ++seek) { + if (strcmp(seek->tokens, cursename) == 0) { + const char *p; + for (p = seek->name; p; ++p) { + switch (*p) { + case 'd': + READ_INT(store, 0); + break; + case 's': + READ_STR(store, 0, 0); + break; + case 't': + READ_TOK(store, 0, 0); + break; + case 'i': + READ_INT(store, 0); + break; + case 'f': + READ_FLT(store, 0); + break; + } + } + return 0; } - } - return 0; } - } - return -1; + return -1; } int curse_read(attrib * a, void *owner, struct storage *store) { - curse *c = (curse *) a->data.v; - int ur; - char cursename[64]; - int n; - int flags; - float flt; + curse *c = (curse *)a->data.v; + int ur; + char cursename[64]; + int n; + int flags; + float flt; - READ_INT(store, &c->no); - chash(c); - READ_TOK(store, cursename, sizeof(cursename)); - READ_INT(store, &flags); - READ_INT(store, &c->duration); - if (global.data_version >= CURSEVIGOURISFLOAT_VERSION) { - READ_FLT(store, &flt); - c->vigour = flt; - } else { - READ_INT(store, &n); - c->vigour = (float)n; - } - if (global.data_version < INTPAK_VERSION) { - ur = read_reference(&c->magician, store, read_int, resolve_unit); - } else { - ur = read_reference(&c->magician, store, read_unit_reference, resolve_unit); - } - if (global.data_version < CURSEFLOAT_VERSION) { - READ_INT(store, &n); - c->effect = (float)n; - } else { - READ_FLT(store, &flt); - c->effect = flt; - } - c->type = ct_find(cursename); - if (c->type == NULL) { - int result = read_ccompat(cursename, store); - if (result != 0) { - log_error("missing curse %s, no compatibility code either.\n", cursename); + READ_INT(store, &c->no); + chash(c); + READ_TOK(store, cursename, sizeof(cursename)); + READ_INT(store, &flags); + READ_INT(store, &c->duration); + if (global.data_version >= CURSEVIGOURISFLOAT_VERSION) { + READ_FLT(store, &flt); + c->vigour = flt; } - assert(result == 0); - return AT_READ_FAIL; - } - if (global.data_version < CURSEFLAGS_VERSION) { - c_setflag(c, flags); - } else { - c->flags = flags; - } - c_clearflag(c, CURSE_ISNEW); - - if (c->type->read) - c->type->read(store, c, owner); - else if (c->type->typ == CURSETYP_UNIT) { - READ_INT(store, &c->data.i); - } - if (c->type->typ == CURSETYP_REGION) { - int rr = - read_reference(&c->data.v, store, read_region_reference, - RESOLVE_REGION(global.data_version)); - if (ur == 0 && rr == 0 && !c->data.v) { - return AT_READ_FAIL; + else { + READ_INT(store, &n); + c->vigour = (float)n; } - } + if (global.data_version < INTPAK_VERSION) { + ur = read_reference(&c->magician, store, read_int, resolve_unit); + } + else { + ur = read_reference(&c->magician, store, read_unit_reference, resolve_unit); + } + if (global.data_version < CURSEFLOAT_VERSION) { + READ_INT(store, &n); + c->effect = (float)n; + } + else { + READ_FLT(store, &flt); + c->effect = flt; + } + c->type = ct_find(cursename); + if (c->type == NULL) { + int result = read_ccompat(cursename, store); + if (result != 0) { + log_error("missing curse %s, no compatibility code either.\n", cursename); + } + assert(result == 0); + return AT_READ_FAIL; + } + if (global.data_version < CURSEFLAGS_VERSION) { + c_setflag(c, flags); + } + else { + c->flags = flags; + } + c_clearflag(c, CURSE_ISNEW); - return AT_READ_OK; + if (c->type->read) + c->type->read(store, c, owner); + else if (c->type->typ == CURSETYP_UNIT) { + READ_INT(store, &c->data.i); + } + if (c->type->typ == CURSETYP_REGION) { + int rr = + read_reference(&c->data.v, store, read_region_reference, + RESOLVE_REGION(global.data_version)); + if (ur == 0 && rr == 0 && !c->data.v) { + return AT_READ_FAIL; + } + } + + return AT_READ_OK; } void curse_write(const attrib * a, const void *owner, struct storage *store) { - unsigned int flags; - curse *c = (curse *) a->data.v; - const curse_type *ct = c->type; - unit *mage = (c->magician && c->magician->number) ? c->magician : NULL; + unsigned int flags; + curse *c = (curse *)a->data.v; + const curse_type *ct = c->type; + unit *mage = (c->magician && c->magician->number) ? c->magician : NULL; - /* copied from c_clearflag */ - flags = (c->flags & ~CURSE_ISNEW) | (c->type->flags & CURSE_ISNEW); + /* copied from c_clearflag */ + flags = (c->flags & ~CURSE_ISNEW) | (c->type->flags & CURSE_ISNEW); - WRITE_INT(store, c->no); - WRITE_TOK(store, ct->cname); - WRITE_INT(store, flags); - WRITE_INT(store, c->duration); - WRITE_FLT(store, (float)c->vigour); - write_unit_reference(mage, store); - WRITE_FLT(store, (float)c->effect); + WRITE_INT(store, c->no); + WRITE_TOK(store, ct->cname); + WRITE_INT(store, flags); + WRITE_INT(store, c->duration); + WRITE_FLT(store, (float)c->vigour); + write_unit_reference(mage, store); + WRITE_FLT(store, (float)c->effect); - if (c->type->write) - c->type->write(store, c, owner); - else if (c->type->typ == CURSETYP_UNIT) { - WRITE_INT(store, c->data.i); - } - if (c->type->typ == CURSETYP_REGION) { - write_region_reference((region *) c->data.v, store); - } + if (c->type->write) + c->type->write(store, c, owner); + else if (c->type->typ == CURSETYP_UNIT) { + WRITE_INT(store, c->data.i); + } + if (c->type->typ == CURSETYP_REGION) { + write_region_reference((region *)c->data.v, store); + } } attrib_type at_curse = { - "curse", - curse_init, - curse_done, - curse_age, - curse_write, - curse_read, - ATF_CURSE + "curse", + curse_init, + curse_done, + curse_age, + curse_write, + curse_read, + ATF_CURSE }; /* ------------------------------------------------------------- */ @@ -295,31 +300,32 @@ static quicklist *cursetypes[256]; void ct_register(const curse_type * ct) { - unsigned int hash = tolower(ct->cname[0]); - quicklist **ctlp = cursetypes + hash; + unsigned int hash = tolower(ct->cname[0]); + quicklist **ctlp = cursetypes + hash; - ql_set_insert(ctlp, (void *)ct); + ql_set_insert(ctlp, (void *)ct); } const curse_type *ct_find(const char *c) { - unsigned int hash = tolower(c[0]); - quicklist *ctl = cursetypes[hash]; - int qi; + unsigned int hash = tolower(c[0]); + quicklist *ctl = cursetypes[hash]; + int qi; - for (qi = 0; ctl; ql_advance(&ctl, &qi, 1)) { - curse_type *type = (curse_type *) ql_get(ctl, qi); + for (qi = 0; ctl; ql_advance(&ctl, &qi, 1)) { + curse_type *type = (curse_type *)ql_get(ctl, qi); - if (strcmp(c, type->cname) == 0) { - return type; - } else { - size_t k = _min(strlen(c), strlen(type->cname)); - if (!_memicmp(c, type->cname, k)) { - return type; - } + if (strcmp(c, type->cname) == 0) { + return type; + } + else { + size_t k = _min(strlen(c), strlen(type->cname)); + if (!_memicmp(c, type->cname, k)) { + return type; + } + } } - } - return NULL; + return NULL; } /* ------------------------------------------------------------- */ @@ -327,56 +333,34 @@ const curse_type *ct_find(const char *c) * einen pointer auf die struct zurück. */ -bool cmp_curse(const attrib * a, const void *data) +static bool 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; -} - -bool 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, variant data, - bool(*compare) (const curse *, variant)) -{ - 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; + const curse *c = (const curse *)data; + if (a->type->flags & ATF_CURSE) { + if (!data || c == (curse *)a->data.v) + return true; + } + return false; } curse *get_curse(attrib * ap, const curse_type * ctype) { - attrib *a = ap; - while (a) { - if (a->type->flags & ATF_CURSE) { - const attrib_type *at = a->type; - while (a && a->type == at) { - curse *c = (curse *) a->data.v; - if (c->type == ctype) - return c; - a = a->next; - } - } else { - a = a->nexttype; + attrib *a = ap; + while (a) { + if (a->type->flags & ATF_CURSE) { + const attrib_type *at = a->type; + while (a && a->type == at) { + curse *c = (curse *)a->data.v; + if (c->type == ctype) + return c; + a = a->next; + } + } + else { + a = a->nexttype; + } } - } - return NULL; + return NULL; } /* ------------------------------------------------------------- */ @@ -384,15 +368,14 @@ curse *get_curse(attrib * ap, const curse_type * ctype) curse *findcurse(int cid) { - return cfindhash(cid); + return cfindhash(cid); } /* ------------------------------------------------------------- */ -void remove_curse(attrib ** ap, const curse * c) +bool remove_curse(attrib ** ap, const curse * c) { - attrib *a = a_select(*ap, c, cmp_curse); - if (a) - a_remove(ap, a); + attrib *a = a_select(*ap, c, cmp_curse); + return a && a_remove(ap, a) == 1; } /* gibt die allgemeine Stärke der Verzauberung zurück. id2 wird wie @@ -400,16 +383,16 @@ void remove_curse(attrib ** ap, const curse * c) * damit der gegen Antimagie wirkende Widerstand einer Verzauberung */ static float get_cursevigour(const curse * c) { - if (c) - return c->vigour; - return 0; + if (c) + return c->vigour; + return 0; } /* setzt die Stärke der Verzauberung auf i */ static void set_cursevigour(curse * c, float vigour) { - assert(c && vigour > 0); - c->vigour = vigour; + assert(c && vigour > 0); + c->vigour = vigour; } /* verändert die Stärke der Verzauberung um +i und gibt die neue @@ -418,47 +401,48 @@ static void set_cursevigour(curse * c, float vigour) */ float curse_changevigour(attrib ** ap, curse * c, float vigour) { - vigour += get_cursevigour(c); + vigour += get_cursevigour(c); - if (vigour <= 0) { - remove_curse(ap, c); - vigour = 0; - } else { - set_cursevigour(c, vigour); - } - return vigour; + if (vigour <= 0) { + remove_curse(ap, c); + vigour = 0; + } + else { + set_cursevigour(c, vigour); + } + return vigour; } /* ------------------------------------------------------------- */ float curse_geteffect(const curse * c) { - if (c == NULL) - return 0; - if (c_flags(c) & CURSE_ISNEW) - return 0; - return c->effect; + if (c == NULL) + return 0; + if (c_flags(c) & CURSE_ISNEW) + return 0; + return c->effect; } int curse_geteffect_int(const curse * c) { - float effect = curse_geteffect(c); - if (effect - (int)effect != 0) { - log_error("curse has an integer attribute with float value: '%s' = %lf", - c->type->cname, effect); - } - return (int)effect; + float effect = curse_geteffect(c); + if (effect - (int)effect != 0) { + log_error("curse has an integer attribute with float value: '%s' = %lf", + c->type->cname, effect); + } + return (int)effect; } /* ------------------------------------------------------------- */ static void set_curseingmagician(struct unit *magician, struct attrib *ap_target, - const curse_type * ct) +const curse_type * ct) { - curse *c = get_curse(ap_target, ct); - if (c) { - c->magician = magician; - } + curse *c = get_curse(ap_target, ct); + if (c) { + c->magician = magician; + } } /* ------------------------------------------------------------- */ @@ -466,29 +450,29 @@ set_curseingmagician(struct unit *magician, struct attrib *ap_target, * betroffenen Personen zurück. Ansonsten wird 0 zurückgegeben. */ int get_cursedmen(unit * u, const curse * c) { - int cursedmen = u->number; + int cursedmen = u->number; - if (!c) - return 0; + if (!c) + return 0; - /* je nach curse_type andere data struct */ - if (c->type->typ == CURSETYP_UNIT) { - cursedmen = c->data.i; - } + /* je nach curse_type andere data struct */ + if (c->type->typ == CURSETYP_UNIT) { + cursedmen = c->data.i; + } - return _min(u->number, 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; + if (!c) + return; - /* je nach curse_type andere data struct */ - if (c->type->typ == CURSETYP_UNIT) { - c->data.i = cursedmen; - } + /* je nach curse_type andere data struct */ + if (c->type->typ == CURSETYP_UNIT) { + c->data.i = cursedmen; + } } /* ------------------------------------------------------------- */ @@ -496,90 +480,91 @@ static void set_cursedmen(curse * c, int cursedmen) * dieses Typs geben, gibt es den bestehenden zurück. */ static curse *make_curse(unit * mage, attrib ** ap, const curse_type * ct, - float vigour, int duration, float effect, int men) + float vigour, int duration, float effect, int men) { - curse *c; - attrib *a; + curse *c; + attrib *a; - a = a_new(&at_curse); - a_add(ap, a); - c = (curse *) a->data.v; + a = a_new(&at_curse); + a_add(ap, a); + c = (curse *)a->data.v; - c->type = ct; - c->flags = 0; - c->vigour = vigour; - c->duration = duration; - c->effect = effect; - c->magician = mage; + c->type = ct; + c->flags = 0; + c->vigour = vigour; + c->duration = duration; + c->effect = effect; + c->magician = mage; - c->no = newunitid(); - chash(c); + c->no = newunitid(); + chash(c); - switch (c->type->typ) { + switch (c->type->typ) { case CURSETYP_NORM: - break; + break; case CURSETYP_UNIT: { - c->data.i = men; - break; + c->data.i = men; + break; } - } - return c; + } + 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, - float vigour, int duration, float effect, int men) + float vigour, int duration, float effect, int men) { - curse *c; + curse *c; - /* die Kraft eines Spruchs darf nicht 0 sein */ - assert(vigour > 0); + /* die Kraft eines Spruchs darf nicht 0 sein */ + assert(vigour > 0); - c = get_curse(*ap, ct); + c = get_curse(*ap, ct); - if (c && (c_flags(c) & CURSE_ONLYONE)) { - return NULL; - } - assert(c == NULL || ct == c->type); + if (c && (c_flags(c) & 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: - { - c->data.i += men; + /* 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: + { + c->data.i += men; + } + } + } + set_curseingmagician(magician, *ap, ct); } - set_curseingmagician(magician, *ap, ct); - } else { - c = make_curse(magician, ap, ct, vigour, duration, effect, men); - } - return c; + else { + c = make_curse(magician, ap, ct, vigour, duration, effect, men); + } + return c; } /* ------------------------------------------------------------- */ @@ -588,99 +573,99 @@ curse *create_curse(unit * magician, attrib ** ap, const curse_type * ct, static void do_transfer_curse(curse * c, unit * u, unit * u2, int n) { - int cursedmen = 0; - int men = get_cursedmen(u, c); - bool dogive = false; - const curse_type *ct = c->type; + int cursedmen = 0; + int men = get_cursedmen(u, c); + bool dogive = false; + const curse_type *ct = c->type; - switch ((ct->flags | c->flags) & CURSE_SPREADMASK) { + switch ((ct->flags | c->flags) & CURSE_SPREADMASK) { case CURSE_SPREADALWAYS: - dogive = true; - men = u2->number + n; - break; + 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 (rng_int() % u_number < cursedmen) { - ++men; - --cursedmen; - dogive = true; + int i; + int u_number = u->number; + for (i = 0; i < n + 1 && u_number > 0; i++) { + if (rng_int() % u_number < cursedmen) { + ++men; + --cursedmen; + dogive = true; + } + --u_number; } - --u_number; - } - break; + break; } case CURSE_SPREADCHANCE: - if (chance(u2->number / (double)(u2->number + n))) { - men = u2->number + n; - dogive = true; - } - break; + if (chance(u2->number / (double)(u2->number + n))) { + men = u2->number + n; + dogive = true; + } + break; case CURSE_SPREADNEVER: - break; - } + break; + } - if (dogive) { - curse *cnew = make_curse(c->magician, &u2->attribs, c->type, c->vigour, - c->duration, c->effect, men); - cnew->flags = c->flags; + if (dogive) { + curse *cnew = make_curse(c->magician, &u2->attribs, c->type, c->vigour, + c->duration, c->effect, men); + cnew->flags = c->flags; - if (ct->typ == CURSETYP_UNIT) - set_cursedmen(cnew, men); - } + if (ct->typ == CURSETYP_UNIT) + set_cursedmen(cnew, men); + } } void transfer_curse(unit * u, unit * u2, int n) { - attrib *a; + attrib *a; - a = a_find(u->attribs, &at_curse); - while (a && a->type == &at_curse) { - curse *c = (curse *) a->data.v; - do_transfer_curse(c, u, u2, n); - a = a->next; - } + a = a_find(u->attribs, &at_curse); + while (a && a->type == &at_curse) { + curse *c = (curse *)a->data.v; + do_transfer_curse(c, u, u2, n); + a = a->next; + } } /* ------------------------------------------------------------- */ bool curse_active(const curse * c) { - if (!c) - return false; - if (c_flags(c) & CURSE_ISNEW) - return false; - if (c->vigour <= 0) - return false; + if (!c) + return false; + if (c_flags(c) & CURSE_ISNEW) + return false; + if (c->vigour <= 0) + return false; - return true; + return true; } bool is_cursed_internal(attrib * ap, const curse_type * ct) { - curse *c = get_curse(ap, ct); + curse *c = get_curse(ap, ct); - if (!c) - return false; + if (!c) + return false; - return true; + return true; } bool is_cursed_with(const attrib * ap, const curse * c) { - const attrib *a = ap; + const attrib *a = ap; - while (a) { - if ((a->type->flags & ATF_CURSE) && (c == (const curse *)a->data.v)) { - return true; + while (a) { + if ((a->type->flags & ATF_CURSE) && (c == (const curse *)a->data.v)) { + return true; + } + a = a->next; } - a = a->next; - } - return false; + return false; } /* ------------------------------------------------------------- */ @@ -701,81 +686,81 @@ bool is_cursed_with(const attrib * ap, const curse * c) int resolve_curse(variant id, void *address) { - int result = 0; - curse *c = NULL; - if (id.i != 0) { - c = cfindhash(id.i); - if (c == NULL) { - result = -1; + int result = 0; + curse *c = NULL; + if (id.i != 0) { + c = cfindhash(id.i); + if (c == NULL) { + result = -1; + } } - } - *(curse **) address = c; - return result; + *(curse **)address = c; + return result; } static const char *oldnames[MAXCURSE] = { - /* OBS: when removing curses, remember to update read_ccompat() */ - "fogtrap", - "antimagiczone", - "farvision", - "gbdream", - "auraboost", - "maelstrom", - "blessedharvest", - "drought", - "badlearn", - "stormwind", - "flyingship", - "nodrift", - "depression", - "magicwalls", - "strongwall", - "astralblock", - "generous", - "peacezone", - "magicstreet", - "magicrunes", - "badmagicresistancezone", - "goodmagicresistancezone", - "slavery", - "calmmonster", - "oldrace", - "fumble", - "riotzone", - "nocostbuilding", - "godcursezone", - "speed", - "orcish", - "magicboost", - "insectfur", - "strength", - "worse", - "magicresistance", - "itemcloak", - "sparkle", - "skillmod" + /* OBS: when removing curses, remember to update read_ccompat() */ + "fogtrap", + "antimagiczone", + "farvision", + "gbdream", + "auraboost", + "maelstrom", + "blessedharvest", + "drought", + "badlearn", + "stormwind", + "flyingship", + "nodrift", + "depression", + "magicwalls", + "strongwall", + "astralblock", + "generous", + "peacezone", + "magicstreet", + "magicrunes", + "badmagicresistancezone", + "goodmagicresistancezone", + "slavery", + "calmmonster", + "oldrace", + "fumble", + "riotzone", + "nocostbuilding", + "godcursezone", + "speed", + "orcish", + "magicboost", + "insectfur", + "strength", + "worse", + "magicresistance", + "itemcloak", + "sparkle", + "skillmod" }; const char *oldcursename(int id) { - return oldnames[id]; + return oldnames[id]; } /* ------------------------------------------------------------- */ message *cinfo_simple(const void *obj, objtype_t typ, const struct curse * c, - int self) + int self) { - struct message *msg; + struct message *msg; - unused_arg(typ); - unused_arg(self); - unused_arg(obj); + unused_arg(typ); + unused_arg(self); + unused_arg(obj); - msg = msg_message(mkname("curseinfo", c->type->cname), "id", c->no); - if (msg == NULL) { - log_error("There is no curseinfo for %s.\n", c->type->cname); - } - return msg; + msg = msg_message(mkname("curseinfo", c->type->cname), "id", c->no); + if (msg == NULL) { + log_error("There is no curseinfo for %s.\n", c->type->cname); + } + return msg; } /* ------------------------------------------------------------- */ @@ -791,27 +776,30 @@ message *cinfo_simple(const void *obj, objtype_t typ, const struct curse * c, */ float destr_curse(curse * c, int cast_level, float force) { - if (cast_level < c->vigour) { /* Zauber ist nicht stark genug */ - double probability = 0.1 + (cast_level - c->vigour) * 0.2; - /* pro Stufe Unterschied -20% */ - if (chance(probability)) { - force -= c->vigour; - if (c->type->change_vigour) { - c->type->change_vigour(c, -((float)cast_level + 1) / 2); - } else { - c->vigour -= cast_level + 1 / 2; - } + if (cast_level < c->vigour) { /* Zauber ist nicht stark genug */ + double probability = 0.1 + (cast_level - c->vigour) * 0.2; + /* pro Stufe Unterschied -20% */ + if (chance(probability)) { + force -= c->vigour; + if (c->type->change_vigour) { + c->type->change_vigour(c, -((float)cast_level + 1) / 2); + } + else { + c->vigour -= cast_level + 1 / 2; + } + } } - } else { /* Zauber ist stärker als curse */ - if (force >= c->vigour) { /* reicht die Kraft noch aus? */ - force -= c->vigour; - if (c->type->change_vigour) { - c->type->change_vigour(c, -c->vigour); - } else { - c->vigour = 0; - } + else { /* Zauber ist stärker als curse */ + if (force >= c->vigour) { /* reicht die Kraft noch aus? */ + force -= c->vigour; + if (c->type->change_vigour) { + c->type->change_vigour(c, -c->vigour); + } + else { + c->vigour = 0; + } + } } - } - return force; + return force; } diff --git a/src/kernel/curse.h b/src/kernel/curse.h index 4ad472a96..7bc6f9652 100644 --- a/src/kernel/curse.h +++ b/src/kernel/curse.h @@ -1,5 +1,5 @@ /* -Copyright (c) 1998-2010, Enno Rehling +Copyright (c) 1998-2014, Enno Rehling Katja Zedel @@ -251,7 +251,7 @@ extern "C" { bool is_cursed_internal(struct attrib *ap, const curse_type * ctype); /* ignoriert CURSE_ISNEW */ - extern void remove_curse(struct attrib **ap, const struct curse *c); + bool remove_curse(struct attrib **ap, const struct curse *c); /* löscht einen konkreten Spruch auf einem Objekt. */ @@ -280,11 +280,6 @@ extern "C" { * unterschiedlich gewünscht sein * */ - extern struct curse *get_cursex(struct attrib *ap, const curse_type * ctype, - variant data, bool(*compare) (const struct curse *, variant)); - /* gibt pointer auf die erste curse-struct zurück, deren Typ ctype ist, - * und für die compare() true liefert, oder einen NULL-pointer. - * */ extern struct curse *get_curse(struct attrib *ap, const curse_type * ctype); /* gibt pointer auf die erste curse-struct zurück, deren Typ ctype ist, * oder einen NULL-pointer @@ -303,9 +298,6 @@ extern "C" { extern void curse_done(struct attrib *a); extern int curse_age(struct attrib *a); - extern bool cmp_curse(const struct attrib *a, const void *data); - extern bool cmp_cursetype(const struct attrib *a, const void *data); - extern float destr_curse(struct curse *c, int cast_level, float force); extern int resolve_curse(variant data, void *address); diff --git a/src/kernel/faction.test.c b/src/kernel/faction.test.c index 08c2df891..31747bd6c 100644 --- a/src/kernel/faction.test.c +++ b/src/kernel/faction.test.c @@ -1,5 +1,6 @@ #include +#include #include #include #include @@ -13,6 +14,21 @@ #include #include +static void test_remove_empty_factions_allies(CuTest *tc) { + faction *f1, *f2; + region *r; + + test_cleanup(); + r = test_create_region(0, 0, 0); + f1 = test_create_faction(0); + test_create_unit(f1, r); + f2 = test_create_faction(0); + ally_add(&f1->allies, f2); + remove_empty_factions(); + CuAssertPtrEquals(tc, 0, f1->allies); + test_cleanup(); +} + static void test_remove_empty_factions(CuTest *tc) { faction *f, *fm; int fno; @@ -95,6 +111,7 @@ CuSuite *get_faction_suite(void) CuSuite *suite = CuSuiteNew(); SUITE_ADD_TEST(suite, test_addfaction); SUITE_ADD_TEST(suite, test_remove_empty_factions); + SUITE_ADD_TEST(suite, test_remove_empty_factions_allies); SUITE_ADD_TEST(suite, test_remove_dead_factions); SUITE_ADD_TEST(suite, test_get_monsters); return suite; diff --git a/src/kernel/save.c b/src/kernel/save.c index 9ec7d2622..c52eae383 100644 --- a/src/kernel/save.c +++ b/src/kernel/save.c @@ -113,8 +113,6 @@ char *rns(FILE * f, char *c, size_t size) return c; } -extern unsigned int __at_hashkey(const char *s); - static unit *unitorders(FILE * F, int enc, struct faction *f) { @@ -1315,7 +1313,6 @@ faction *readfaction(struct gamedata * data) f->flags = FFL_NPC | FFL_NOIDLEOUT; } } - assert((f->flags&FFL_SAVEMASK) == f->flags); a_read(data->store, &f->attribs, f); if (data->version >= CLAIM_VERSION) { diff --git a/src/modules/gmcmd.c b/src/modules/gmcmd.c index 110e418cd..9a5085ecf 100644 --- a/src/modules/gmcmd.c +++ b/src/modules/gmcmd.c @@ -35,16 +35,6 @@ /* util includes */ #include -#include -#include -#include -#include -#include -#include -#include -#include -#include - #include /* libc includes */ @@ -56,18 +46,11 @@ static int read_permissions(attrib * a, void *owner, struct storage *store) { attrib *attr = NULL; - a_read(store, &attr, NULL); - a_free(attr); + a_read(store, &attr, owner); + a_remove(&attr, a); return AT_READ_OK; } -struct attrib_type at_permissions = { - "GM:permissions", - NULL, NULL, NULL, - NULL, read_permissions, - ATF_UNIQUE -}; - static int read_gmcreate(attrib * a, void *owner, struct storage *store) { char zText[32]; @@ -75,15 +58,8 @@ static int read_gmcreate(attrib * a, void *owner, struct storage *store) return AT_READ_OK; } -/* at_gmcreate specifies that the owner can create items of a particular type */ -attrib_type at_gmcreate = { - "GM:create", - NULL, NULL, NULL, - NULL, read_gmcreate -}; - void register_gmcmd(void) { - at_register(&at_gmcreate); - at_register(&at_permissions); + at_deprecate("GM:create", read_gmcreate); + at_deprecate("GM:permissions", read_permissions); } diff --git a/src/test_eressea.c b/src/test_eressea.c index ca9b298cd..94f8d6c67 100644 --- a/src/test_eressea.c +++ b/src/test_eressea.c @@ -30,6 +30,7 @@ int RunAllTests(void) ADD_TESTS(suite, race); /* util */ ADD_TESTS(suite, config); + ADD_TESTS(suite, attrib); ADD_TESTS(suite, base36); ADD_TESTS(suite, bsdstring); ADD_TESTS(suite, functions); diff --git a/src/tests.h b/src/tests.h index 9cbcbcac1..a35b5acf3 100644 --- a/src/tests.h +++ b/src/tests.h @@ -1,25 +1,38 @@ #ifndef ERESSEA_TESTS_H #define ERESSEA_TESTS_H + +#include + #ifdef __cplusplus extern "C" { #endif - void test_cleanup(void); + struct region; + struct unit; + struct faction; + struct building; + struct ship; + struct item_type; + struct building_type; + struct ship_type; + struct terrain_type; - struct terrain_type * test_create_terrain(const char * name, unsigned int flags); - struct race *test_create_race(const char *name); - struct region *test_create_region(int x, int y, - const struct terrain_type *terrain); - struct faction *test_create_faction(const struct race *rc); - struct unit *test_create_unit(struct faction *f, struct region *r); - void test_create_world(void); - struct building * test_create_building(struct region * r, const struct building_type * btype); - struct ship * test_create_ship(struct region * r, const struct ship_type * stype); - struct item_type * test_create_itemtype(const char * name); - struct ship_type *test_create_shiptype(const char * name); - struct building_type *test_create_buildingtype(const char *name); + void test_cleanup(void); - int RunAllTests(void); + struct terrain_type * test_create_terrain(const char * name, unsigned int flags); + struct race *test_create_race(const char *name); + struct region *test_create_region(int x, int y, + const struct terrain_type *terrain); + struct faction *test_create_faction(const struct race *rc); + struct unit *test_create_unit(struct faction *f, struct region *r); + void test_create_world(void); + struct building * test_create_building(struct region * r, const struct building_type * btype); + struct ship * test_create_ship(struct region * r, const struct ship_type * stype); + struct item_type * test_create_itemtype(const char * name); + struct ship_type *test_create_shiptype(const char * name); + struct building_type *test_create_buildingtype(const char *name); + + int RunAllTests(void); #ifdef __cplusplus } diff --git a/src/triggers/removecurse.c b/src/triggers/removecurse.c index f6fcbc659..38cdbc989 100644 --- a/src/triggers/removecurse.c +++ b/src/triggers/removecurse.c @@ -1,7 +1,7 @@ /* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel +Copyright (c) 1998-2014, Enno Rehling +Katja Zedel Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above @@ -41,68 +41,66 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include typedef struct removecurse_data { - curse *curse; - unit *target; + curse *curse; + unit *target; } removecurse_data; static void removecurse_init(trigger * t) { - t->data.v = calloc(sizeof(removecurse_data), 1); + t->data.v = calloc(sizeof(removecurse_data), 1); } static void removecurse_free(trigger * t) { - free(t->data.v); + free(t->data.v); } static int removecurse_handle(trigger * t, void *data) { - /* call an event handler on removecurse. - * data.v -> ( variant event, int timer ) - */ - removecurse_data *td = (removecurse_data *) t->data.v; - if (td->curse && td->target) { - attrib *a = a_select(td->target->attribs, td->curse, cmp_curse); - if (a) { - a_remove(&td->target->attribs, a); - } else - log_error("could not perform removecurse::handle()\n"); - } - unused_arg(data); - return 0; + /* call an event handler on removecurse. + * data.v -> ( variant event, int timer ) + */ + removecurse_data *td = (removecurse_data *)t->data.v; + if (td->curse && td->target) { + if (!remove_curse(&td->target->attribs, td->curse)) { + log_error("could not perform removecurse::handle()\n"); + } + } + unused_arg(data); + return 0; } static void removecurse_write(const trigger * t, struct storage *store) { - removecurse_data *td = (removecurse_data *) t->data.v; - WRITE_TOK(store, td->target ? itoa36(td->target->no) : 0); - WRITE_INT(store, td->curse ? td->curse->no : 0); + removecurse_data *td = (removecurse_data *)t->data.v; + WRITE_TOK(store, td->target ? itoa36(td->target->no) : 0); + WRITE_INT(store, td->curse ? td->curse->no : 0); } static int removecurse_read(trigger * t, struct storage *store) { - removecurse_data *td = (removecurse_data *) t->data.v; + removecurse_data *td = (removecurse_data *)t->data.v; - read_reference(&td->target, store, read_unit_reference, resolve_unit); - read_reference(&td->curse, store, read_int, resolve_curse); + read_reference(&td->target, store, read_unit_reference, resolve_unit); + read_reference(&td->curse, store, read_int, resolve_curse); - return AT_READ_OK; + return AT_READ_OK; } trigger_type tt_removecurse = { - "removecurse", - removecurse_init, - removecurse_free, - removecurse_handle, - removecurse_write, - removecurse_read + "removecurse", + removecurse_init, + removecurse_free, + removecurse_handle, + removecurse_write, + removecurse_read }; trigger *trigger_removecurse(curse * c, unit * target) { - trigger *t = t_new(&tt_removecurse); - removecurse_data *td = (removecurse_data *) t->data.v; - td->curse = c; - td->target = target; - return t; + trigger *t = t_new(&tt_removecurse); + removecurse_data *td = (removecurse_data *)t->data.v; + td->curse = c; + td->target = target; + return t; } diff --git a/src/util/CMakeLists.txt b/src/util/CMakeLists.txt index c4b51250c..51ceadac7 100644 --- a/src/util/CMakeLists.txt +++ b/src/util/CMakeLists.txt @@ -2,6 +2,7 @@ project(util C) SET(_TEST_FILES base36.test.c +attrib.test.c strings.test.c bsdstring.test.c functions.test.c diff --git a/src/util/attrib.c b/src/util/attrib.c index 8c8bf9d35..7dc067cc4 100644 --- a/src/util/attrib.c +++ b/src/util/attrib.c @@ -1,7 +1,7 @@ /* Copyright (c) 1998-2010, Enno Rehling - Katja Zedel +Katja Zedel Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above @@ -29,322 +29,329 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #define MAXATHASH 61 -attrib_type *at_hash[MAXATHASH]; +static attrib_type *at_hash[MAXATHASH]; static unsigned int __at_hashkey(const char *s) { - int key = 0; - size_t i = strlen(s); + int key = 0; + size_t i = strlen(s); - while (i > 0) { - key = (s[--i] + key * 37); - } - return key & 0x7fffffff; + while (i > 0) { + key = (s[--i] + key * 37); + } + return key & 0x7fffffff; } void at_register(attrib_type * at) { - attrib_type *find; + attrib_type *find; - if (at->read == NULL) { - log_warning("registering non-persistent attribute %s.\n", at->name); - } - at->hashkey = __at_hashkey(at->name); - find = at_hash[at->hashkey % MAXATHASH]; - while (find && at->hashkey != find->hashkey) - find = find->nexthash; - if (find && find == at) { - log_warning("attribute '%s' was registered more than once\n", at->name); - return; - } else { - assert(!find || !"hashkey is already in use"); - } - at->nexthash = at_hash[at->hashkey % MAXATHASH]; - at_hash[at->hashkey % MAXATHASH] = at; + if (at->read == NULL) { + log_warning("registering non-persistent attribute %s.\n", at->name); + } + at->hashkey = __at_hashkey(at->name); + find = at_hash[at->hashkey % MAXATHASH]; + while (find && at->hashkey != find->hashkey) { + find = find->nexthash; + } + if (find && find == at) { + log_warning("attribute '%s' was registered more than once\n", at->name); + return; + } + else { + assert(!find || !"hashkey is already in use"); + } + at->nexthash = at_hash[at->hashkey % MAXATHASH]; + at_hash[at->hashkey % MAXATHASH] = at; } static attrib_type *at_find(unsigned int hk) { - const char *translate[3][2] = { - {"zielregion", "targetregion"}, /* remapping: from 'zielregion, heute targetregion */ - {"verzaubert", "curse"}, /* remapping: früher verzaubert, jetzt curse */ - {NULL, NULL} - }; - attrib_type *find = at_hash[hk % MAXATHASH]; - while (find && hk != find->hashkey) - find = find->nexthash; - if (!find) { - int i = 0; - while (translate[i][0]) { - if (__at_hashkey(translate[i][0]) == hk) - return at_find(__at_hashkey(translate[i][1])); - ++i; + const char *translate[3][2] = { + { "zielregion", "targetregion" }, /* remapping: from 'zielregion, heute targetregion */ + { "verzaubert", "curse" }, /* remapping: früher verzaubert, jetzt curse */ + { NULL, NULL } + }; + attrib_type *find = at_hash[hk % MAXATHASH]; + while (find && hk != find->hashkey) + find = find->nexthash; + if (!find) { + int i = 0; + while (translate[i][0]) { + if (__at_hashkey(translate[i][0]) == hk) + return at_find(__at_hashkey(translate[i][1])); + ++i; + } } - } - return find; + return find; } attrib *a_select(attrib * a, const void *data, - bool(*compare) (const attrib *, const void *)) + bool(*compare) (const attrib *, const void *)) { - while (a && !compare(a, data)) - a = a->next; - return a; + while (a && !compare(a, data)) + a = a->next; + return a; } attrib *a_find(attrib * a, const attrib_type * at) { - while (a && a->type != at) - a = a->nexttype; - return a; + while (a && a->type != at) + a = a->nexttype; + return a; } const attrib *a_findc(const attrib * a, const attrib_type * at) { - while (a && a->type != at) - a = a->nexttype; - return a; + while (a && a->type != at) + a = a->nexttype; + return a; } static attrib *a_insert(attrib * head, attrib * a) { - attrib **pa = &head->next; + attrib **pa = &head->next; - assert(!(a->type->flags & ATF_UNIQUE)); - assert(head && head->type == a->type); + assert(!(a->type->flags & ATF_UNIQUE)); + assert(head && head->type == a->type); - while (*pa && (*pa)->type == a->type) { - pa = &(*pa)->next; - } - a->next = *pa; - return *pa = a; + while (*pa && (*pa)->type == a->type) { + pa = &(*pa)->next; + } + a->next = *pa; + return *pa = a; } attrib *a_add(attrib ** pa, attrib * a) { - attrib *first = *pa; - assert(a->next == NULL && a->nexttype == NULL); + attrib *first = *pa; + assert(a->next == NULL && a->nexttype == NULL); - if (first == NULL) - return *pa = a; - if (first->type == a->type) { - return a_insert(first, a); - } - for (;;) { - attrib *next = first->nexttype; - if (next == NULL) { - /* the type is not in the list, append it behind the last type */ - attrib **insert = &first->next; - first->nexttype = a; - while (*insert) - insert = &(*insert)->next; - *insert = a; - break; + if (first == NULL) + return *pa = a; + if (first->type == a->type) { + return a_insert(first, a); } - if (next->type == a->type) { - return a_insert(next, a); + for (;;) { + attrib *next = first->nexttype; + if (next == NULL) { + /* the type is not in the list, append it behind the last type */ + attrib **insert = &first->next; + first->nexttype = a; + while (*insert) + insert = &(*insert)->next; + *insert = a; + break; + } + if (next->type == a->type) { + return a_insert(next, a); + } + first = next; } - first = next; - } - return a; -} - -void a_free(attrib * a) -{ - const attrib_type *at = a->type; - if (at->finalize) - at->finalize(a); - free(a); + return a; } static int a_unlink(attrib ** pa, attrib * a) { - attrib **pnexttype = pa; - attrib **pnext = NULL; + attrib **pnexttype = pa; + attrib **pnext = NULL; - assert(a != NULL); - while (*pnexttype) { - attrib *next = *pnexttype; - if (next->type == a->type) - break; - pnexttype = &next->nexttype; - pnext = &next->next; - } - if (*pnexttype && (*pnexttype)->type == a->type) { - if (*pnexttype == a) { - *pnexttype = a->next; - if (a->next != a->nexttype) { - a->next->nexttype = a->nexttype; - } - if (pnext == NULL) - return 1; - while (*pnext && (*pnext)->type != a->type) - pnext = &(*pnext)->next; - } else { - pnext = &(*pnexttype)->next; + assert(a != NULL); + while (*pnexttype) { + attrib *next = *pnexttype; + if (next->type == a->type) + break; + pnexttype = &next->nexttype; + pnext = &next->next; } - while (*pnext && (*pnext)->type == a->type) { - if (*pnext == a) { - *pnext = a->next; - return 1; - } - pnext = &(*pnext)->next; + if (*pnexttype && (*pnexttype)->type == a->type) { + if (*pnexttype == a) { + *pnexttype = a->next; + if (a->next != a->nexttype) { + a->next->nexttype = a->nexttype; + } + if (pnext == NULL) + return 1; + while (*pnext && (*pnext)->type != a->type) + pnext = &(*pnext)->next; + } + else { + pnext = &(*pnexttype)->next; + } + while (*pnext && (*pnext)->type == a->type) { + if (*pnext == a) { + *pnext = a->next; + return 1; + } + pnext = &(*pnext)->next; + } } - } - return 0; + return 0; +} + +static void a_free(attrib * a) +{ + const attrib_type *at = a->type; + if (at->finalize) + at->finalize(a); + free(a); } int a_remove(attrib ** pa, attrib * a) { - int ok; - assert(a != NULL); - ok = a_unlink(pa, a); - if (ok) - a_free(a); - return ok; + int ok; + assert(a != NULL); + ok = a_unlink(pa, a); + if (ok) + a_free(a); + return ok; } void a_removeall(attrib ** pa, const attrib_type * at) { - attrib **pnexttype = pa; - attrib **pnext = NULL; + attrib **pnexttype = pa; + attrib **pnext = NULL; - while (*pnexttype) { - attrib *next = *pnexttype; - if (next->type == at) - break; - pnexttype = &next->nexttype; - pnext = &next->next; - } - if (*pnexttype && (*pnexttype)->type == at) { - attrib *a = *pnexttype; + while (*pnexttype) { + attrib *next = *pnexttype; + if (next->type == at) + break; + pnexttype = &next->nexttype; + pnext = &next->next; + } + if (*pnexttype && (*pnexttype)->type == at) { + attrib *a = *pnexttype; - *pnexttype = a->nexttype; - if (pnext) { - while (*pnext && (*pnext)->type != at) - pnext = &(*pnext)->next; - *pnext = a->nexttype; + *pnexttype = a->nexttype; + if (pnext) { + while (*pnext && (*pnext)->type != at) + pnext = &(*pnext)->next; + *pnext = a->nexttype; + } + while (a && a->type == at) { + attrib *ra = a; + a = a->next; + a_free(ra); + } } - while (a && a->type == at) { - attrib *ra = a; - a = a->next; - a_free(ra); - } - } } attrib *a_new(const attrib_type * at) { - attrib *a = (attrib *) calloc(1, sizeof(attrib)); - assert(at != NULL); - a->type = at; - if (at->initialize) - at->initialize(a); - return a; + attrib *a = (attrib *)calloc(1, sizeof(attrib)); + assert(at != NULL); + a->type = at; + if (at->initialize) + at->initialize(a); + return a; } int a_age(attrib ** p) { - attrib **ap = p; - /* Attribute altern, und die Entfernung (age()==0) eines Attributs - * hat Einfluß auf den Besitzer */ - while (*ap) { - attrib *a = *ap; - if (a->type->age) { - int result = a->type->age(a); - assert(result >= 0 || !"age() returned a negative value"); - if (result == 0) { - a_remove(p, a); - continue; - } + attrib **ap = p; + /* Attribute altern, und die Entfernung (age()==0) eines Attributs + * hat Einfluß auf den Besitzer */ + while (*ap) { + attrib *a = *ap; + if (a->type->age) { + int result = a->type->age(a); + assert(result >= 0 || !"age() returned a negative value"); + if (result == 0) { + a_remove(p, a); + continue; + } + } + ap = &a->next; } - ap = &a->next; - } - return (*p != NULL); + return (*p != NULL); } static critbit_tree cb_deprecated = { 0 }; -void at_deprecate(const char * name, int (*reader)(attrib *, void *, struct storage *)) +void at_deprecate(const char * name, int(*reader)(attrib *, void *, struct storage *)) { - char buffer[64]; - size_t len = strlen(name); - len = cb_new_kv(name, len, &reader, sizeof(reader), buffer); - cb_insert(&cb_deprecated, buffer, len); + char buffer[64]; + size_t len = strlen(name); + len = cb_new_kv(name, len, &reader, sizeof(reader), buffer); + cb_insert(&cb_deprecated, buffer, len); } int a_read(struct storage *store, attrib ** attribs, void *owner) { - int key, retval = AT_READ_OK; - char zText[128]; - - zText[0] = 0; - key = -1; - READ_TOK(store, zText, sizeof(zText)); - if (strcmp(zText, "end") == 0) - return retval; - else - key = __at_hashkey(zText); - - while (key != -1) { - int (*reader)(attrib *, void *, struct storage *) = 0; - attrib_type *at = at_find(key); - attrib * na = 0; - - if (at) { - reader = at->read; - na = a_new(at); - } else { - const void * kv; - cb_find_prefix(&cb_deprecated, zText, strlen(zText)+1, &kv, 1, 0); - if (kv) { - cb_get_kv(kv, &reader, sizeof(reader)); - } else { - fprintf(stderr, "attribute hash: %d (%s)\n", key, zText); - assert(at || !"attribute not registered"); - } - } - if (reader) { - int i = reader(na, owner, store); - if (na) { - switch (i) { - case AT_READ_OK: - a_add(attribs, na); - break; - case AT_READ_FAIL: - retval = AT_READ_FAIL; - a_free(na); - break; - default: - assert(!"invalid return value"); - break; - } - } - } else { - assert(!"error: no registered callback can read attribute"); - } + int key, retval = AT_READ_OK; + char zText[128]; + zText[0] = 0; + key = -1; READ_TOK(store, zText, sizeof(zText)); - if (!strcmp(zText, "end")) - break; - key = __at_hashkey(zText); - } - return retval; + if (strcmp(zText, "end") == 0) + return retval; + else + key = __at_hashkey(zText); + + while (key != -1) { + int(*reader)(attrib *, void *, struct storage *) = 0; + attrib_type *at = at_find(key); + attrib * na = 0; + + if (at) { + reader = at->read; + na = a_new(at); + } + else { + const void * kv; + cb_find_prefix(&cb_deprecated, zText, strlen(zText) + 1, &kv, 1, 0); + if (kv) { + cb_get_kv(kv, &reader, sizeof(reader)); + } + else { + fprintf(stderr, "attribute hash: %d (%s)\n", key, zText); + assert(at || !"attribute not registered"); + } + } + if (reader) { + int i = reader(na, owner, store); + if (na) { + switch (i) { + case AT_READ_OK: + a_add(attribs, na); + break; + case AT_READ_FAIL: + retval = AT_READ_FAIL; + a_free(na); + break; + default: + assert(!"invalid return value"); + break; + } + } + } + else { + assert(!"error: no registered callback can read attribute"); + } + + READ_TOK(store, zText, sizeof(zText)); + if (!strcmp(zText, "end")) + break; + key = __at_hashkey(zText); + } + return retval; } void a_write(struct storage *store, const attrib * attribs, const void *owner) { - const attrib *na = attribs; + const attrib *na = attribs; - while (na) { - if (na->type->write) { - assert(na->type->hashkey || !"attribute not registered"); - WRITE_TOK(store, na->type->name); - na->type->write(na, owner, store); - na = na->next; - } else { - na = na->nexttype; + while (na) { + if (na->type->write) { + assert(na->type->hashkey || !"attribute not registered"); + WRITE_TOK(store, na->type->name); + na->type->write(na, owner, store); + na = na->next; + } + else { + na = na->nexttype; + } } - } - WRITE_TOK(store, "end"); + WRITE_TOK(store, "end"); } diff --git a/src/util/attrib.h b/src/util/attrib.h index 8a8650467..7dc3e1a3d 100644 --- a/src/util/attrib.h +++ b/src/util/attrib.h @@ -1,7 +1,7 @@ /* Copyright (c) 1998-2010, Enno Rehling - Katja Zedel +Katja Zedel Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above @@ -18,66 +18,66 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #ifndef ATTRIB_H #define ATTRIB_H + #ifdef __cplusplus extern "C" { #endif - struct gamedata; - struct storage; - typedef void (*afun) (void); + struct gamedata; + struct storage; + typedef void(*afun) (void); - typedef struct attrib { - const struct attrib_type *type; - union { - afun f; - void *v; - int i; - float flt; - char c; - short s; - short sa[2]; - char ca[4]; - } data; - /* internal data, do not modify: */ - struct attrib *next; /* next attribute in the list */ - struct attrib *nexttype; /* skip to attribute of a different type */ - } attrib; + typedef struct attrib { + const struct attrib_type *type; + union { + afun f; + void *v; + int i; + float flt; + char c; + short s; + short sa[2]; + char ca[4]; + } data; + /* internal data, do not modify: */ + struct attrib *next; /* next attribute in the list */ + struct attrib *nexttype; /* skip to attribute of a different type */ + } attrib; #define ATF_UNIQUE (1<<0) /* only one per attribute-list */ #define ATF_PRESERVE (1<<1) /* preserve order in list. append to back */ #define ATF_USER_DEFINED (1<<2) /* use this to make udf */ - typedef struct attrib_type { - const char *name; - void (*initialize) (struct attrib *); - void (*finalize) (struct attrib *); - int (*age) (struct attrib *); - /* age returns 0 if the attribute needs to be removed, !=0 otherwise */ - void(*write) (const struct attrib *, const void *owner, struct storage *); - int(*read) (struct attrib *, void *owner, struct storage *); /* return AT_READ_OK on success, AT_READ_FAIL if attrib needs removal */ - unsigned int flags; - /* ---- internal data, do not modify: ---- */ - struct attrib_type *nexthash; - unsigned int hashkey; - } attrib_type; + typedef struct attrib_type { + const char *name; + void(*initialize) (struct attrib *); + void(*finalize) (struct attrib *); + int(*age) (struct attrib *); + /* age returns 0 if the attribute needs to be removed, !=0 otherwise */ + void(*write) (const struct attrib *, const void *owner, struct storage *); + int(*read) (struct attrib *, void *owner, struct storage *); /* return AT_READ_OK on success, AT_READ_FAIL if attrib needs removal */ + unsigned int flags; + /* ---- internal data, do not modify: ---- */ + struct attrib_type *nexthash; + unsigned int hashkey; + } attrib_type; - extern void at_register(attrib_type * at); - extern void at_deprecate(const char * name, int (*reader)(attrib *, void *, struct storage *)); + extern void at_register(attrib_type * at); + extern void at_deprecate(const char * name, int(*reader)(attrib *, void *, struct storage *)); - extern attrib *a_select(attrib * a, const void *data, - bool(*compare) (const attrib *, const void *)); - extern attrib *a_find(attrib * a, const attrib_type * at); - extern const attrib *a_findc(const attrib * a, const attrib_type * at); - extern attrib *a_add(attrib ** pa, attrib * at); - extern int a_remove(attrib ** pa, attrib * at); - extern void a_removeall(attrib ** a, const attrib_type * at); - extern attrib *a_new(const attrib_type * at); - extern void a_free(attrib * a); + extern attrib *a_select(attrib * a, const void *data, + bool(*compare) (const attrib *, const void *)); + extern attrib *a_find(attrib * a, const attrib_type * at); + extern const attrib *a_findc(const attrib * a, const attrib_type * at); + extern attrib *a_add(attrib ** pa, attrib * at); + extern int a_remove(attrib ** pa, attrib * at); + extern void a_removeall(attrib ** a, const attrib_type * at); + extern attrib *a_new(const attrib_type * at); - extern int a_age(attrib ** attribs); - extern int a_read(struct storage *store, attrib ** attribs, void *owner); - extern void a_write(struct storage *store, const attrib * attribs, - const void *owner); + extern int a_age(attrib ** attribs); + extern int a_read(struct storage *store, attrib ** attribs, void *owner); + extern void a_write(struct storage *store, const attrib * attribs, + const void *owner); #define DEFAULT_AGE NULL #define DEFAULT_INIT NULL diff --git a/src/util/attrib.test.c b/src/util/attrib.test.c new file mode 100644 index 000000000..2e15c8321 --- /dev/null +++ b/src/util/attrib.test.c @@ -0,0 +1,84 @@ +#include +#include "attrib.h" + +#include +#include + +static void test_attrib_new(CuTest * tc) +{ + attrib_type at_test = { "test" }; + attrib * a; + CuAssertPtrNotNull(tc, (a = a_new(&at_test))); + CuAssertPtrEquals(tc, 0, a->next); + CuAssertPtrEquals(tc, 0, a->nexttype); + CuAssertPtrEquals(tc, (void *)a->type, (void *)&at_test); + a_remove(&a, a); + CuAssertPtrEquals(tc, 0, a); +} + + +static void test_attrib_add(CuTest * tc) +{ + attrib_type at_foo = { "foo" }; + attrib_type at_bar = { "bar" }; + attrib *a, *alist = 0; + + CuAssertPtrNotNull(tc, (a = a_new(&at_foo))); + CuAssertPtrEquals(tc, a, a_add(&alist, a)); + CuAssertPtrEquals(tc, a, alist); + + CuAssertPtrNotNull(tc, (a = a_add(&alist, a_new(&at_foo)))); + CuAssertPtrEquals_Msg(tc, "new attribute not added after existing", alist->next, a); + + CuAssertPtrNotNull(tc, (a = a_add(&alist, a_new(&at_bar)))); + CuAssertPtrEquals_Msg(tc, "new atribute not added at end of list", alist->next->next, a); + + CuAssertPtrNotNull(tc, (a = a_add(&alist, a_new(&at_foo)))); + CuAssertPtrEquals_Msg(tc, "messages not sorted by type", alist->next->next, a); + a_removeall(&alist, &at_foo); + a_removeall(&alist, &at_bar); +} + +static void test_attrib_remove(CuTest * tc) +{ + attrib_type at_foo = { "foo" }; + attrib *a, *alist = 0; + + CuAssertPtrNotNull(tc, a_add(&alist, a_new(&at_foo))); + CuAssertPtrNotNull(tc, a = a_add(&alist, a_new(&at_foo))); + CuAssertIntEquals(tc, 1, a_remove(&alist, a)); + CuAssertPtrNotNull(tc, alist); + CuAssertIntEquals(tc, 1, a_remove(&alist, alist)); + CuAssertPtrEquals(tc, 0, alist); +} + +static void test_attrib_nexttype(CuTest * tc) +{ + attrib_type at_foo = { "foo" }; + attrib_type at_bar = { "bar" }; + attrib *a, *alist = 0; + CuAssertPtrNotNull(tc, (a = a_new(&at_foo))); + CuAssertPtrEquals(tc, 0, a->nexttype); + CuAssertPtrEquals(tc, a, a_add(&alist, a)); + CuAssertPtrEquals(tc, 0, alist->nexttype); + + CuAssertPtrNotNull(tc, a_add(&alist, a_new(&at_foo))); + CuAssertPtrEquals(tc, 0, alist->nexttype); + + CuAssertPtrNotNull(tc, (a = a_add(&alist, a_new(&at_bar)))); + CuAssertPtrEquals(tc, a, alist->nexttype); + CuAssertPtrEquals(tc, 0, a->nexttype); + + a_removeall(&alist, &at_foo); + a_removeall(&alist, &at_bar); +} + +CuSuite *get_attrib_suite(void) +{ + CuSuite *suite = CuSuiteNew(); + SUITE_ADD_TEST(suite, test_attrib_new); + SUITE_ADD_TEST(suite, test_attrib_add); + SUITE_ADD_TEST(suite, test_attrib_remove); + SUITE_ADD_TEST(suite, test_attrib_nexttype); + return suite; +}