From f89721ebec96342734b9d8fc79fafe9f2a224446 Mon Sep 17 00:00:00 2001 From: CTD Date: Tue, 16 Sep 2014 09:21:33 +0200 Subject: [PATCH 01/21] Monster Email MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit kann jetzt über die config.xml eingestellt werden --- src/kernel/faction.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/kernel/faction.c b/src/kernel/faction.c index b46848e3c..fd1faf459 100755 --- a/src/kernel/faction.c +++ b/src/kernel/faction.c @@ -126,7 +126,15 @@ faction *get_or_create_monsters(void) if (!f) { const race *rc = rc_find("dragon"); - f = addfaction("noreply@eressea.de", NULL, rc, NULL, 0); + const char *email = get_param(global.parameters, "monster.email"); + if (email) + { + f = addfaction(email, NULL, rc, NULL, 0); + } + else + { + f = addfaction("noreply@eressea.de", NULL, rc, NULL, 0); + } renumber_faction(f, 666); faction_setname(f, "Monster"); f->options = 0; From 3484acfa430c2f4177c5b675845fcf692190d5a6 Mon Sep 17 00:00:00 2001 From: CTD Date: Thu, 18 Sep 2014 12:10:42 +0200 Subject: [PATCH 02/21] =?UTF-8?q?Arbeitspl=C3=A4tze?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Regionen haben jetzt immer mindestens 10% ihrer size als freie Freie Arbeitsplätzt, höchstens jedoch 200. Das sorgt dafür das die Bäume nicht alle Bauern umbringen. Diese ernähren sich quasi durch Jagt statt Ackerbau. Sinnlose Variable MAXPEASANTS_PER_AREA entfernt. --- src/kernel/config.c | 6 +++--- src/kernel/config.h | 3 +-- src/kernel/region.c | 2 +- src/laws.c | 4 ++-- 4 files changed, 7 insertions(+), 8 deletions(-) diff --git a/src/kernel/config.c b/src/kernel/config.c index 10ab406b9..9e4a42c0f 100644 --- a/src/kernel/config.c +++ b/src/kernel/config.c @@ -1508,9 +1508,9 @@ bool idle(faction * f) int maxworkingpeasants(const struct region *r) { - int i = production(r) * MAXPEASANTS_PER_AREA - - ((rtrees(r, 2) + rtrees(r, 1) / 2) * TREESIZE); - return _max(i, 0); + int size = production(r); + int treespace = (rtrees(r, 2) + rtrees(r, 1) / 2) * TREESIZE; + return _max(size-treespace, _min(size / 10 , 200)); } int lighthouse_range(const building * b, const faction * f) diff --git a/src/kernel/config.h b/src/kernel/config.h index 02cf6e8f0..4e195c4d8 100644 --- a/src/kernel/config.h +++ b/src/kernel/config.h @@ -46,8 +46,7 @@ extern "C" { # define MAXUNITS 1048573 /* must be prime for hashing. 524287 was >90% full */ #endif -#define MAXPEASANTS_PER_AREA 10 /* number of peasants per region-size */ -#define TREESIZE (MAXPEASANTS_PER_AREA-2) /* space used by trees (in #peasants) */ +#define TREESIZE (8) /* space used by trees (in #peasants) */ #define PEASANTFORCE 0.75 /* Chance einer Vermehrung trotz 90% Auslastung */ #define HERBROTCHANCE 5 /* Verrottchance für Kräuter (ifdef HERBS_ROT) */ diff --git a/src/kernel/region.c b/src/kernel/region.c index 8c57a220f..0736d7ba9 100644 --- a/src/kernel/region.c +++ b/src/kernel/region.c @@ -1187,7 +1187,7 @@ void terraform_region(region * r, const terrain_type * terrain) int production(const region * r) { /* muß rterrain(r) sein, nicht rterrain() wegen rekursion */ - int p = r->terrain->size / MAXPEASANTS_PER_AREA; + int p = r->terrain->size; if (curse_active(get_curse(r->attribs, ct_find("drought")))) p /= 2; diff --git a/src/laws.c b/src/laws.c index 406c37c77..9f9f4ed3e 100755 --- a/src/laws.c +++ b/src/laws.c @@ -490,7 +490,7 @@ static void peasants(region * r) { int peasants = rpeasants(r); int money = rmoney(r); - int maxp = production(r) * MAXPEASANTS_PER_AREA; + int maxp = production(r); int n, satiated; int dead = 0; @@ -781,7 +781,7 @@ growing_trees(region * r, const int current_season, const int last_weeks_season) /* Grundchance 1.0% */ /* Jeder Elf in der Region erhöht die Chance marginal */ - elves = _min(elves, (production(r) * MAXPEASANTS_PER_AREA) / 8); + elves = _min(elves, production(r) / 8); if (elves) { seedchance += 1.0 - pow(0.99999, elves * RESOURCE_QUANTITY); } From 911b93e343437dbed2e16610c363d23b8934cecd Mon Sep 17 00:00:00 2001 From: CTD1 Date: Thu, 25 Sep 2014 08:59:29 +0200 Subject: [PATCH 03/21] Update faction.c --- src/kernel/faction.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/kernel/faction.c b/src/kernel/faction.c index fd1faf459..2522f6968 100755 --- a/src/kernel/faction.c +++ b/src/kernel/faction.c @@ -127,12 +127,10 @@ faction *get_or_create_monsters(void) const race *rc = rc_find("dragon"); const char *email = get_param(global.parameters, "monster.email"); - if (email) - { + if (email) { f = addfaction(email, NULL, rc, NULL, 0); - } - else - { + } + else { f = addfaction("noreply@eressea.de", NULL, rc, NULL, 0); } renumber_faction(f, 666); @@ -348,7 +346,7 @@ void destroyfaction(faction * f) if (rc->ec_flags & ECF_REC_HORSES) { /* Zentauren an die Pferde */ h += u->number; } - else { /* Orks zählen nur zur Hälfte */ + else { /* Orks zählen nur zur Hälfte */ p += (int)(u->number * rc->recruit_multi); } for (itm = u->items; itm; itm = itm->next) { @@ -373,7 +371,7 @@ void destroyfaction(faction * f) group *g; ally *sf, *sfn; - /* Alle HELFE für die Partei löschen */ + /* Alle HELFE für die Partei löschen */ for (sf = ff->allies; sf; sf = sf->next) { if (sf->faction == f) { removelist(&ff->allies, sf); From 1c19a6948c59f375ee65771a97743f19143c395b Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Wed, 15 Oct 2014 18:19:16 +0200 Subject: [PATCH 04/21] kill some dead code. --- src/laws.c | 1 - src/laws.h | 2 -- 2 files changed, 3 deletions(-) diff --git a/src/laws.c b/src/laws.c index d329959cd..cf0d98e50 100755 --- a/src/laws.c +++ b/src/laws.c @@ -693,7 +693,6 @@ void demographics(void) for (r = regions; r; r = r->next) { ++r->age; /* also oceans. no idea why we didn't always do that */ live(r); - /* check_split_dragons(); */ if (!fval(r->terrain, SEA_REGION)) { /* die Nachfrage nach Produkten steigt. */ diff --git a/src/laws.h b/src/laws.h index 63ad86e0b..3ffc35f08 100755 --- a/src/laws.h +++ b/src/laws.h @@ -23,8 +23,6 @@ extern "C" { #endif extern int writepasswd(void); - int getoption(void); - int wanderoff(struct region *r, int p); void demographics(void); void last_orders(void); void find_address(void); From 7df47fd25c3b44096a08f429a3a4a9e0449a67d4 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Thu, 16 Oct 2014 07:34:09 +0200 Subject: [PATCH 05/21] remove bad configuration caching (TODO: cache inside get_param). move remove_empty_* functions out of config.c add basic tests for remove_empty_units (no special units yet). --- src/bind_eressea.c | 1 + src/economy.c | 2 +- src/kernel/config.c | 118 +---------------------------------------- src/kernel/config.h | 4 -- src/kernel/faction.c | 54 +++++++++++++++++++ src/kernel/faction.h | 2 + src/kernel/unit.c | 47 ++++++++++++++++ src/kernel/unit.h | 2 + src/kernel/unit.test.c | 38 +++++++++++++ 9 files changed, 147 insertions(+), 121 deletions(-) diff --git a/src/bind_eressea.c b/src/bind_eressea.c index d6f1d1eb5..664808b17 100755 --- a/src/bind_eressea.c +++ b/src/bind_eressea.c @@ -4,6 +4,7 @@ #include "json.h" +#include #include #include #include diff --git a/src/economy.c b/src/economy.c index 965df6478..bb24fd5e5 100644 --- a/src/economy.c +++ b/src/economy.c @@ -57,9 +57,9 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include #include -#include #include #include +#include #include #include diff --git a/src/kernel/config.c b/src/kernel/config.c index 7bffa0bbf..6f0004708 100644 --- a/src/kernel/config.c +++ b/src/kernel/config.c @@ -102,7 +102,6 @@ struct settings global = { bool lomem = false; FILE *logfile; -FILE *updatelog; bool battledebug = false; int turn = -1; @@ -122,17 +121,6 @@ bool IsImmune(const faction * f) return !fval(f, FFL_NPC) && f->age < NewbieImmunity(); } -static int MaxAge(void) -{ - static int value = -1; - static int gamecookie = -1; - if (value < 0 || gamecookie != global.cookie) { - gamecookie = global.cookie; - value = get_param_int(global.parameters, "MaxAge", 0); - } - return value; -} - static int ally_flag(const char *s, int help_mask) { if ((help_mask & HELP_MONEY) && strcmp(s, "money") == 0) @@ -2069,100 +2057,6 @@ char *_strdup(const char *s) } #endif -void remove_empty_factions(void) -{ - faction **fp, *f3; - - for (fp = &factions; *fp;) { - faction *f = *fp; - /* monster (0) werden nicht entfernt. alive kann beim readgame - * () auf 0 gesetzt werden, wenn monsters keine einheiten mehr - * haben. */ - if ((f->units == NULL || f->alive == 0) && !is_monsters(f)) { - ursprung *ur = f->ursprung; - while (ur && ur->id != 0) - ur = ur->next; - if (verbosity >= 2) - log_printf(stdout, "\t%s\n", factionname(f)); - - /* Einfach in eine Datei schreiben und später vermailen */ - - if (updatelog) - fprintf(updatelog, "dropout %s\n", itoa36(f->no)); - - for (f3 = factions; f3; f3 = f3->next) { - ally *sf; - group *g; - ally **sfp = &f3->allies; - while (*sfp) { - sf = *sfp; - if (sf->faction == f || sf->faction == NULL) { - *sfp = sf->next; - free(sf); - } - else - sfp = &(*sfp)->next; - } - for (g = f3->groups; g; g = g->next) { - sfp = &g->allies; - while (*sfp) { - sf = *sfp; - if (sf->faction == f || sf->faction == NULL) { - *sfp = sf->next; - free(sf); - } - else - sfp = &(*sfp)->next; - } - } - } - - *fp = f->next; - funhash(f); - free_faction(f); - free(f); - } - else - fp = &(*fp)->next; - } -} - -void remove_empty_units_in_region(region * r) -{ - unit **up = &r->units; - - while (*up) { - unit *u = *up; - - if (u->number) { - faction *f = u->faction; - if (f == NULL || !f->alive) { - set_number(u, 0); - } - if (MaxAge() > 0) { - if ((!fval(f, FFL_NOTIMEOUT) && f->age > MaxAge())) { - set_number(u, 0); - } - } - } - if ((u->number == 0 && u_race(u) != get_race(RC_SPELL)) || (u->age <= 0 - && u_race(u) == get_race(RC_SPELL))) { - remove_unit(up, u); - } - if (*up == u) - up = &u->next; - } -} - -void remove_empty_units(void) -{ - region *r; - - for (r = regions; r; r = r->next) { - remove_empty_units_in_region(r); - } -} - bool faction_id_is_unused(int id) { return findfaction(id) == NULL; @@ -2715,20 +2609,12 @@ int entertainmoney(const region * r) int rule_give(void) { - static int value = -1; - if (value < 0) { - value = get_param_int(global.parameters, "rules.give", GIVE_DEFAULT); - } - return value; + return get_param_int(global.parameters, "rules.give", GIVE_DEFAULT); } int markets_module(void) { - static int value = -1; - if (value < 0) { - value = get_param_int(global.parameters, "modules.markets", 0); - } - return value; + return get_param_int(global.parameters, "modules.markets", 0); } /** releases all memory associated with the game state. diff --git a/src/kernel/config.h b/src/kernel/config.h index 06474dd65..5f3513a72 100644 --- a/src/kernel/config.h +++ b/src/kernel/config.h @@ -107,10 +107,6 @@ extern "C" { #define i2b(i) ((bool)((i)?(true):(false))) - void remove_empty_units_in_region(struct region *r); - void remove_empty_units(void); - void remove_empty_factions(void); - typedef struct strlist { struct strlist *next; char *s; diff --git a/src/kernel/faction.c b/src/kernel/faction.c index b46848e3c..d3e3bc014 100755 --- a/src/kernel/faction.c +++ b/src/kernel/faction.c @@ -601,3 +601,57 @@ int skill_limit(faction * f, skill_t sk) return m; } +void remove_empty_factions(void) +{ + faction **fp, *f3; + + for (fp = &factions; *fp;) { + faction *f = *fp; + /* monster (0) werden nicht entfernt. alive kann beim readgame + * () auf 0 gesetzt werden, wenn monsters keine einheiten mehr + * haben. */ + if ((f->units == NULL || f->alive == 0) && !is_monsters(f)) { + ursprung *ur = f->ursprung; + while (ur && ur->id != 0) + ur = ur->next; + if (verbosity >= 2) + log_printf(stdout, "\t%s\n", factionname(f)); + + /* Einfach in eine Datei schreiben und später vermailen */ + + for (f3 = factions; f3; f3 = f3->next) { + ally *sf; + group *g; + ally **sfp = &f3->allies; + while (*sfp) { + sf = *sfp; + if (sf->faction == f || sf->faction == NULL) { + *sfp = sf->next; + free(sf); + } + else + sfp = &(*sfp)->next; + } + for (g = f3->groups; g; g = g->next) { + sfp = &g->allies; + while (*sfp) { + sf = *sfp; + if (sf->faction == f || sf->faction == NULL) { + *sfp = sf->next; + free(sf); + } + else + sfp = &(*sfp)->next; + } + } + } + + *fp = f->next; + funhash(f); + free_faction(f); + free(f); + } + else + fp = &(*fp)->next; + } +} diff --git a/src/kernel/faction.h b/src/kernel/faction.h index 52f3c271a..f1db53b87 100644 --- a/src/kernel/faction.h +++ b/src/kernel/faction.h @@ -20,6 +20,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #define H_KRNL_FACTION #include "skill.h" +#include "types.h" #ifdef __cplusplus extern "C" { @@ -136,6 +137,7 @@ void destroyfaction(faction * f); extern void renumber_faction(faction * f, int no); void free_faction(struct faction *f); + void remove_empty_factions(void); #ifdef SMART_INTERVALS extern void update_interval(struct faction *f, struct region *r); diff --git a/src/kernel/unit.c b/src/kernel/unit.c index 09c821b70..dca02aabf 100644 --- a/src/kernel/unit.c +++ b/src/kernel/unit.c @@ -1786,3 +1786,50 @@ int effskill(const unit * u, skill_t sk) return eff_skill(u, sk, u->region); } +static int MaxAge(void) +{ + static int value = -1; + static int gamecookie = -1; + if (value < 0 || gamecookie != global.cookie) { + gamecookie = global.cookie; + value = get_param_int(global.parameters, "MaxAge", 0); + } + return value; +} + +void remove_empty_units_in_region(region * r) +{ + unit **up = &r->units; + int max_age = MaxAge(); + + while (*up) { + unit *u = *up; + + if (u->number) { + faction *f = u->faction; + if (f == NULL || !f->alive) { + set_number(u, 0); + } + if (max_age > 0) { + if ((!fval(f, FFL_NOTIMEOUT) && f->age > max_age)) { + set_number(u, 0); + } + } + } + if ((u->number == 0 && u_race(u) != get_race(RC_SPELL)) || (u->age <= 0 + && u_race(u) == get_race(RC_SPELL))) { + remove_unit(up, u); + } + if (*up == u) + up = &u->next; + } +} + +void remove_empty_units(void) +{ + region *r; + + for (r = regions; r; r = r->next) { + remove_empty_units_in_region(r); + } +} diff --git a/src/kernel/unit.h b/src/kernel/unit.h index de90db3b2..a3db732dd 100644 --- a/src/kernel/unit.h +++ b/src/kernel/unit.h @@ -238,6 +238,8 @@ extern "C" { struct spellbook * unit_get_spellbook(const struct unit * u); void unit_add_spell(struct unit * u, struct sc_mage * m, struct spell * sp, int level); + void remove_empty_units_in_region(struct region * r); + void remove_empty_units(void); extern struct attrib_type at_creator; #ifdef __cplusplus diff --git a/src/kernel/unit.test.c b/src/kernel/unit.test.c index 6f3618e73..3a341cce2 100644 --- a/src/kernel/unit.test.c +++ b/src/kernel/unit.test.c @@ -11,6 +11,42 @@ #include #include +static void test_remove_empty_units(CuTest *tc) { + unit *u; + int uid; + + test_cleanup(); + test_create_world(); + + u = test_create_unit(test_create_faction(test_create_race("human")), findregion(0, 0)); + uid = u->no; + remove_empty_units(); + CuAssertPtrNotNull(tc, findunit(uid)); + u->number = 0; + remove_empty_units(); + CuAssertPtrEquals(tc, 0, findunit(uid)); + test_cleanup(); +} + +static void test_remove_empty_units_in_region(CuTest *tc) { + unit *u; + int uid; + + test_cleanup(); + test_create_world(); + + u = test_create_unit(test_create_faction(test_create_race("human")), findregion(0, 0)); + uid = u->no; + remove_empty_units_in_region(u->region); + CuAssertPtrNotNull(tc, findunit(uid)); + u->number = 0; + remove_empty_units_in_region(u->region); + CuAssertPtrEquals(tc, 0, findunit(uid)); + CuAssertPtrEquals(tc, 0, u->region); + CuAssertPtrEquals(tc, 0, u->faction); + test_cleanup(); +} + static void test_scale_number(CuTest *tc) { unit *u; const struct potion_type *ptype; @@ -37,5 +73,7 @@ CuSuite *get_unit_suite(void) { CuSuite *suite = CuSuiteNew(); SUITE_ADD_TEST(suite, test_scale_number); + SUITE_ADD_TEST(suite, test_remove_empty_units); + SUITE_ADD_TEST(suite, test_remove_empty_units_in_region); return suite; } From 559f1f905afacbb28a22e8d15f0d7ccb0119fa4e Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Thu, 16 Oct 2014 07:46:08 +0200 Subject: [PATCH 06/21] Eliminate dead code: FFL_NOTIMEOUT. old feature for time-limited factions, not used anywhere. --- src/kernel/faction.h | 4 ++-- src/kernel/save.c | 2 +- src/kernel/unit.c | 17 ----------------- 3 files changed, 3 insertions(+), 20 deletions(-) diff --git a/src/kernel/faction.h b/src/kernel/faction.h index f1db53b87..92878ceef 100644 --- a/src/kernel/faction.h +++ b/src/kernel/faction.h @@ -49,10 +49,10 @@ extern "C" { #define FFL_NOIDLEOUT (1<<24) /* Partei stirbt nicht an NMRs */ #define FFL_NPC (1<<25) /* eine Partei mit Monstern */ #define FFL_DBENTRY (1<<28) /* Partei ist in Datenbank eingetragen */ -#define FFL_NOTIMEOUT (1<<29) /* ignore MaxAge() */ + #define FFL_GM (1<<30) /* eine Partei mit Sonderrechten */ -#define FFL_SAVEMASK (FFL_DEFENDER|FFL_NEWID|FFL_GM|FFL_NPC|FFL_NOTIMEOUT|FFL_DBENTRY|FFL_NOIDLEOUT) +#define FFL_SAVEMASK (FFL_DEFENDER|FFL_NEWID|FFL_GM|FFL_NPC|FFL_DBENTRY|FFL_NOIDLEOUT) #define is_monsters(f) ((f)->flags&FFL_NPC) diff --git a/src/kernel/save.c b/src/kernel/save.c index 52661ff24..9ec7d2622 100644 --- a/src/kernel/save.c +++ b/src/kernel/save.c @@ -1312,7 +1312,7 @@ faction *readfaction(struct gamedata * data) READ_INT(data->store, &f->flags); if (data->version < INTFLAGS_VERSION) { if (f->no == 0 || f->no == 666) { - f->flags = FFL_NPC | FFL_NOTIMEOUT | FFL_NOIDLEOUT; + f->flags = FFL_NPC | FFL_NOIDLEOUT; } } assert((f->flags&FFL_SAVEMASK) == f->flags); diff --git a/src/kernel/unit.c b/src/kernel/unit.c index dca02aabf..b956465e2 100644 --- a/src/kernel/unit.c +++ b/src/kernel/unit.c @@ -1786,21 +1786,9 @@ int effskill(const unit * u, skill_t sk) return eff_skill(u, sk, u->region); } -static int MaxAge(void) -{ - static int value = -1; - static int gamecookie = -1; - if (value < 0 || gamecookie != global.cookie) { - gamecookie = global.cookie; - value = get_param_int(global.parameters, "MaxAge", 0); - } - return value; -} - void remove_empty_units_in_region(region * r) { unit **up = &r->units; - int max_age = MaxAge(); while (*up) { unit *u = *up; @@ -1810,11 +1798,6 @@ void remove_empty_units_in_region(region * r) if (f == NULL || !f->alive) { set_number(u, 0); } - if (max_age > 0) { - if ((!fval(f, FFL_NOTIMEOUT) && f->age > max_age)) { - set_number(u, 0); - } - } } if ((u->number == 0 && u_race(u) != get_race(RC_SPELL)) || (u->age <= 0 && u_race(u) == get_race(RC_SPELL))) { From 440aca34ea40f06a609da6790dea6031cd836a47 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Thu, 16 Oct 2014 08:06:44 +0200 Subject: [PATCH 07/21] test special treatment for spells in remove_empty_units. --- src/kernel/unit.c | 3 +-- src/kernel/unit.test.c | 57 ++++++++++++++++++++++++++++++++++++++++++ src/tests.c | 4 +-- 3 files changed, 60 insertions(+), 4 deletions(-) diff --git a/src/kernel/unit.c b/src/kernel/unit.c index b956465e2..27dff7f0c 100644 --- a/src/kernel/unit.c +++ b/src/kernel/unit.c @@ -232,9 +232,8 @@ int gift_items(unit * u, int flags) int rule = rule_give(); assert(u->region); - assert(u->faction); - if ((u->faction->flags & FFL_QUIT) == 0 || (rule & GIVE_ONDEATH) == 0) { + if ((rule & GIVE_ONDEATH) == 0 || !u->faction || (u->faction->flags & FFL_QUIT) == 0) { if ((rule & GIVE_ALLITEMS) == 0 && (flags & GIFT_FRIENDS)) flags -= GIFT_FRIENDS; if ((rule & GIVE_PEASANTS) == 0 && (flags & GIFT_PEASANTS)) diff --git a/src/kernel/unit.test.c b/src/kernel/unit.test.c index 3a341cce2..12a83d3ad 100644 --- a/src/kernel/unit.test.c +++ b/src/kernel/unit.test.c @@ -1,8 +1,10 @@ #include #include #include "alchemy.h" +#include "faction.h" #include "unit.h" #include "item.h" +#include "race.h" #include "region.h" #include @@ -47,6 +49,58 @@ static void test_remove_empty_units_in_region(CuTest *tc) { test_cleanup(); } +static void test_remove_units_without_faction(CuTest *tc) { + unit *u; + int uid; + + test_cleanup(); + test_create_world(); + + u = test_create_unit(test_create_faction(test_create_race("human")), findregion(0, 0)); + uid = u->no; + u_setfaction(u, 0); + remove_empty_units_in_region(u->region); + CuAssertPtrEquals(tc, 0, findunit(uid)); + CuAssertIntEquals(tc, 0, u->number); + test_cleanup(); +} + +static void test_remove_units_with_dead_faction(CuTest *tc) { + unit *u; + int uid; + + test_cleanup(); + test_create_world(); + + u = test_create_unit(test_create_faction(test_create_race("human")), findregion(0, 0)); + uid = u->no; + u->faction->alive = false; + remove_empty_units_in_region(u->region); + CuAssertPtrEquals(tc, 0, findunit(uid)); + CuAssertIntEquals(tc, 0, u->number); + test_cleanup(); +} + +static void test_remove_units_ignores_spells(CuTest *tc) { + unit *u; + int uid; + + test_cleanup(); + test_create_world(); + + u = create_unit(findregion(0, 0), test_create_faction(test_create_race("human")), 1, get_race(RC_SPELL), 0, 0, 0); + uid = u->no; + u->number = 0; + u->age = 1; + remove_empty_units_in_region(u->region); + CuAssertPtrNotNull(tc, findunit(uid)); + CuAssertPtrNotNull(tc, u->region); + u->age = 0; + remove_empty_units_in_region(u->region); + CuAssertPtrEquals(tc, 0, findunit(uid)); + test_cleanup(); +} + static void test_scale_number(CuTest *tc) { unit *u; const struct potion_type *ptype; @@ -74,6 +128,9 @@ CuSuite *get_unit_suite(void) CuSuite *suite = CuSuiteNew(); SUITE_ADD_TEST(suite, test_scale_number); SUITE_ADD_TEST(suite, test_remove_empty_units); + SUITE_ADD_TEST(suite, test_remove_units_ignores_spells); + SUITE_ADD_TEST(suite, test_remove_units_without_faction); + SUITE_ADD_TEST(suite, test_remove_units_with_dead_faction); SUITE_ADD_TEST(suite, test_remove_empty_units_in_region); return suite; } diff --git a/src/tests.c b/src/tests.c index e5017b5ad..066b93262 100644 --- a/src/tests.c +++ b/src/tests.c @@ -51,8 +51,8 @@ struct faction *test_create_faction(const struct race *rc) struct unit *test_create_unit(struct faction *f, struct region *r) { - unit *u = create_unit(r, f, 1, f?f->race:rc_find("human"), 0, 0, 0); - return u; + assert(f || !r); + return create_unit(r, f, 1, f ? f->race : rc_find("human"), 0, 0, 0); } void test_cleanup(void) From ac65d83ba24e02ceb2e581824f85fca943f6a28e Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Thu, 16 Oct 2014 08:13:56 +0200 Subject: [PATCH 08/21] test that empty factions are removed, but not monsters. --- src/kernel/faction.test.c | 47 ++++++++++++++++++++++++++++++++++++++- src/tests.c | 9 ++++---- 2 files changed, 51 insertions(+), 5 deletions(-) diff --git a/src/kernel/faction.test.c b/src/kernel/faction.test.c index a0b82f5b9..08c2df891 100644 --- a/src/kernel/faction.test.c +++ b/src/kernel/faction.test.c @@ -1,12 +1,55 @@ #include + +#include #include #include +#include #include #include -#include "faction.h" + #include +#include + +#include #include +static void test_remove_empty_factions(CuTest *tc) { + faction *f, *fm; + int fno; + + test_cleanup(); + fm = get_or_create_monsters(); + assert(fm); + f = test_create_faction(0); + fno = f->no; + remove_empty_factions(); + CuAssertPtrEquals(tc, 0, findfaction(fno)); + CuAssertPtrEquals(tc, fm, get_monsters()); + test_cleanup(); +} + +static void test_remove_dead_factions(CuTest *tc) { + faction *f, *fm; + region *r; + + test_cleanup(); + r = test_create_region(0, 0, 0); + fm = get_or_create_monsters(); + f = test_create_faction(0); + assert(fm && r && f); + test_create_unit(f, r); + test_create_unit(fm, r); + remove_empty_factions(); + CuAssertPtrEquals(tc, f, findfaction(f->no)); + CuAssertPtrNotNull(tc, get_monsters()); + fm->alive = 0; + f->alive = 0; + remove_empty_factions(); + CuAssertPtrEquals(tc, 0, findfaction(f->no)); + CuAssertPtrEquals(tc, fm, get_monsters()); + test_cleanup(); +} + static void test_addfaction(CuTest *tc) { faction *f = 0; const struct race *rc = rc_get_or_create("human"); @@ -51,6 +94,8 @@ 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_dead_factions); SUITE_ADD_TEST(suite, test_get_monsters); return suite; } diff --git a/src/tests.c b/src/tests.c index 066b93262..ebd8c7bf4 100644 --- a/src/tests.c +++ b/src/tests.c @@ -34,25 +34,26 @@ struct race *test_create_race(const char *name) struct region *test_create_region(int x, int y, const terrain_type *terrain) { region *r = new_region(x, y, NULL, 0); - terraform_region(r, terrain); + terraform_region(r, terrain ? terrain : get_or_create_terrain("plain")); rsettrees(r, 0, 0); rsettrees(r, 1, 0); rsettrees(r, 2, 0); rsethorses(r, 0); - rsetpeasants(r, terrain->size); + rsetpeasants(r, r->terrain->size); return r; } struct faction *test_create_faction(const struct race *rc) { - faction *f = addfaction("nobody@eressea.de", NULL, rc?rc:rc_find("human"), default_locale, 0); + faction *f = addfaction("nobody@eressea.de", NULL, rc?rc:rc_get_or_create("human"), default_locale, 0); return f; } struct unit *test_create_unit(struct faction *f, struct region *r) { + const struct race * rc = f ? f->race : 0; assert(f || !r); - return create_unit(r, f, 1, f ? f->race : rc_find("human"), 0, 0, 0); + return create_unit(r, f, 1, rc ? rc : rc_get_or_create("human"), 0, 0, 0); } void test_cleanup(void) From cd470d5e277a4a6a40e2625ee7865992aa4491b8 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Thu, 16 Oct 2014 14:33:20 +0200 Subject: [PATCH 09/21] fix string concatenation operator --- scripts/reports.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/reports.lua b/scripts/reports.lua index 6a7c4aedd..1cd0302b9 100644 --- a/scripts/reports.lua +++ b/scripts/reports.lua @@ -1,4 +1,4 @@ dofile('config.lua') -eressea.read_game(get_turn() + '.dat') +eressea.read_game(get_turn() .. '.dat') init_reports() write_reports() From 88b9d3c583a8bfba3dd2d037b17546aae2f5be1b Mon Sep 17 00:00:00 2001 From: CTD Date: Thu, 16 Oct 2014 14:40:22 +0200 Subject: [PATCH 10/21] =?UTF-8?q?Fix=20f=C3=BCr=20Leere=20Geb=C3=A4ude?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Der check war sinnlos, denn u->building wobei u der Besitzer ist, gibt ja im Fall das er der "Besitzer der größten Burg in der Region" ist eben diese Burg zurück. So geht das dann auch in E2. --- src/economy.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/economy.c b/src/economy.c index bb24fd5e5..bf7e4f288 100644 --- a/src/economy.c +++ b/src/economy.c @@ -1039,12 +1039,10 @@ static bool maintain(building * b, bool first) u = building_owner(b); if (u == NULL) return false; - /* If the owner is the region owner, check if biggest castle has the dontpay flag */ + /* If the owner is the region owner, check if dontpay flag is set for the building where he is in */ if (check_param(global.parameters, "rules.region_owner_pay_building", b->type->_name)) { - if (u == building_owner(largestbuilding(r, &cmp_taxes, false))) { - if (fval(u->building, BLD_DONTPAY)) { - return false; - } + if (fval(u->building, BLD_DONTPAY)) { + return false; } } for (c = 0; b->type->maintenance[c].number; ++c) { From aa07c550abf8dd7f60c6e3122733db48dbeef28b Mon Sep 17 00:00:00 2001 From: CTD Date: Thu, 14 Aug 2014 02:20:09 +0200 Subject: [PATCH 11/21] Auto Lehrer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Config via study.speedup (sollte in E2 und E3 schon mit dem Wert 0 in der XML stehen) Wert 1: Wenn das gerade gelernte Talent wenig Lerntage hat als 1/3 der max. möglichen (ohne Bonus wie Akademie) hat, dann gibt es die doppelten Lerntage. Entspricht etwa dem alten Lehrer Schema. Wert 2: Es werden die Lerntage aller Talente der Einheit als Vergleichswert genommen, dann aber gegen den halben maximalen Lerntagewert. Es werden niemals die Lerntage der aktuellen Stufe mit eingerechnet, sondern nur die durchschnittlichen Lerntage der bereits fertig gelernten Stufen. In E2 sollte der Lehre Befehl deaktiviert werden wenn diese Option aktiviert wird. --- src/study.c | 38 ++++++++++++++++++++++---------------- 1 file changed, 22 insertions(+), 16 deletions(-) diff --git a/src/study.c b/src/study.c index 6adae692c..be408b601 100644 --- a/src/study.c +++ b/src/study.c @@ -493,25 +493,31 @@ int teach_cmd(unit * u, struct order *ord) return 0; } -static double study_speedup(unit * u) +static double study_speedup(unit * u, skill_t s, int rule_type) { -#define MINTURN 5 /* 5 */ -#define OFSTURN 2 /* 2 */ +#define MINTURN 16 + double learnweeks = 0; + int i; if (turn > MINTURN) { - static int speed_rule = -1; - if (speed_rule < 0) { - speed_rule = get_param_int(global.parameters, "study.speedup", 0); - } - if (speed_rule == 1) { - double learn_age = OFSTURN; - int i; + if (rule_type == 1) { for (i = 0; i != u->skill_size; ++i) { skill *sv = u->skills + i; - double learn_time = sv->level * (sv->level + 1) / 2.0; - learn_age += learn_time; + if (sv->id == s){ + learnweeks = sv->level * (sv->level + 1) / 2.0; + if (learnweeks < turn / 3) { + return 2.0; + } + } } - if (learn_age < turn) { - return 2.0 - learn_age / turn; + return 2.0; /* If the skill was not found it is the first study. */ + } + if (rule_type == 2) { + for (i = 0; i != u->skill_size; ++i) { + skill *sv = u->skills + i; + learnweeks = +(sv->level * (sv->level + 1) / 2.0); + } + if (learnweeks < turn / 3) { + return 2.0; } } } @@ -531,6 +537,7 @@ int learn_cmd(unit * u, order * ord) int money = 0; skill_t sk; int maxalchemy = 0; + int speed_rule = get_param_int(global.parameters, "study.speedup", 0); static int learn_newskills = -1; if (learn_newskills < 0) { const char *str = get_param(global.parameters, "study.newskills"); @@ -539,7 +546,6 @@ int learn_cmd(unit * u, order * ord) else learn_newskills = 1; } - if ((u_race(u)->flags & RCF_NOLEARN) || fval(u, UFL_WERE)) { ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error_race_nolearn", "race", u_race(u))); @@ -732,7 +738,7 @@ int learn_cmd(unit * u, order * ord) teach->value -= u->number * 10; } - multi *= study_speedup(u); + multi *= study_speedup(u, sk, speed_rule); days = study_days(u, sk); days = (int)((days + teach->value) * multi); From 1c8488f2b4ca2b358538501e0a10e40183284ef0 Mon Sep 17 00:00:00 2001 From: CTD Date: Thu, 14 Aug 2014 02:21:43 +0200 Subject: [PATCH 12/21] Wenn man 1/2 schreibt sollte auch 1/2 im Code stehen. --- src/study.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/study.c b/src/study.c index be408b601..44abd2329 100644 --- a/src/study.c +++ b/src/study.c @@ -516,7 +516,7 @@ static double study_speedup(unit * u, skill_t s, int rule_type) skill *sv = u->skills + i; learnweeks = +(sv->level * (sv->level + 1) / 2.0); } - if (learnweeks < turn / 3) { + if (learnweeks < turn / 2) { return 2.0; } } From a86c2d88ab3495e74d47a9b3706ef0c307ab76ec Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Fri, 17 Oct 2014 19:56:26 +0200 Subject: [PATCH 13/21] Test: After a faction is eliminated, nobody should have it as an ally. --- src/kernel/faction.test.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) 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; From 74a6bd72c24fad6c43ef84198c1367223a8a0b43 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sat, 18 Oct 2014 14:16:26 +0200 Subject: [PATCH 14/21] additional testing. --- src/kernel/save.c | 2 - src/test_eressea.c | 1 + src/tests.h | 31 +-- src/util/CMakeLists.txt | 1 + src/util/attrib.c | 473 ++++++++++++++++++++-------------------- src/util/attrib.h | 99 ++++----- src/util/attrib.test.c | 36 +++ 7 files changed, 345 insertions(+), 298 deletions(-) create mode 100644 src/util/attrib.test.c diff --git a/src/kernel/save.c b/src/kernel/save.c index 9ec7d2622..7febc0d23 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) { 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..fca8353fb 100644 --- a/src/tests.h +++ b/src/tests.h @@ -1,25 +1,28 @@ #ifndef ERESSEA_TESTS_H #define ERESSEA_TESTS_H + +#include + #ifdef __cplusplus extern "C" { #endif - void test_cleanup(void); + void test_cleanup(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); + 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); + int RunAllTests(void); #ifdef __cplusplus } 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..2b83b60ec 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; + return a; } void a_free(attrib * a) { - const attrib_type *at = a->type; - if (at->finalize) - at->finalize(a); - free(a); + const attrib_type *at = a->type; + if (at->finalize) + at->finalize(a); + free(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; } 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..2bea8d2b8 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,67 @@ 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 void a_free(attrib * a); - 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..aba7b25db --- /dev/null +++ b/src/util/attrib.test.c @@ -0,0 +1,36 @@ +#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); +} + + +static void test_attrib_add(CuTest * tc) +{ + attrib_type at_test = { "test" }; + attrib *a, *alist = 0; + CuAssertPtrNotNull(tc, (a = a_new(&at_test))); + CuAssertPtrEquals(tc, a, a_add(&alist, a)); + CuAssertPtrEquals(tc, a, alist); + + CuAssertPtrNotNull(tc, (a = a_add(&alist, a_new(&at_test)))); + CuAssertPtrEquals(tc, alist->next, a); + CuAssertPtrEquals(tc, alist->nexttype, a); +} + +CuSuite *get_attrib_suite(void) +{ + CuSuite *suite = CuSuiteNew(); + SUITE_ADD_TEST(suite, test_attrib_new); + return suite; +} From 8f57adaf5b65de33ca8d3699d16d6b3f8af0bec1 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sat, 18 Oct 2014 14:30:07 +0200 Subject: [PATCH 15/21] declare types (gcc failure). --- src/tests.h | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/tests.h b/src/tests.h index fca8353fb..ce6edda06 100644 --- a/src/tests.h +++ b/src/tests.h @@ -7,6 +7,15 @@ extern "C" { #endif + struct region; + struct unit; + struct faction; + struct building; + struct ship; + struct item_type; + struct building_type; + struct terrain_type; + void test_cleanup(void); struct terrain_type * test_create_terrain(const char * name, unsigned int flags); From b37e8ac13862e64ae737545c2b2757f36e094c47 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sat, 18 Oct 2014 17:12:43 +0200 Subject: [PATCH 16/21] add a test for attrib->nexttype. fix gcc build. --- src/tests.h | 1 + src/util/attrib.test.c | 15 +++++++++++---- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/tests.h b/src/tests.h index ce6edda06..a35b5acf3 100644 --- a/src/tests.h +++ b/src/tests.h @@ -14,6 +14,7 @@ extern "C" { struct ship; struct item_type; struct building_type; + struct ship_type; struct terrain_type; void test_cleanup(void); diff --git a/src/util/attrib.test.c b/src/util/attrib.test.c index aba7b25db..be3987bfe 100644 --- a/src/util/attrib.test.c +++ b/src/util/attrib.test.c @@ -17,20 +17,27 @@ static void test_attrib_new(CuTest * tc) static void test_attrib_add(CuTest * tc) { - attrib_type at_test = { "test" }; + attrib_type at_foo = { "foo" }; + attrib_type at_bar = { "bar" }; attrib *a, *alist = 0; - CuAssertPtrNotNull(tc, (a = a_new(&at_test))); + CuAssertPtrNotNull(tc, (a = a_new(&at_foo))); CuAssertPtrEquals(tc, a, a_add(&alist, a)); CuAssertPtrEquals(tc, a, alist); + CuAssertPtrEquals(tc, 0, alist->nexttype); - CuAssertPtrNotNull(tc, (a = a_add(&alist, a_new(&at_test)))); + CuAssertPtrNotNull(tc, (a = a_add(&alist, a_new(&at_foo)))); CuAssertPtrEquals(tc, alist->next, a); - CuAssertPtrEquals(tc, alist->nexttype, a); + CuAssertPtrEquals(tc, 0, alist->nexttype); + + CuAssertPtrNotNull(tc, (a = a_add(&alist, a_new(&at_bar)))); + CuAssertPtrEquals(tc, alist->next->next, a); + CuAssertPtrEquals(tc, a, alist->nexttype); } CuSuite *get_attrib_suite(void) { CuSuite *suite = CuSuiteNew(); SUITE_ADD_TEST(suite, test_attrib_new); + SUITE_ADD_TEST(suite, test_attrib_add); return suite; } From a58afb9d15f809d586d19491a3be07976d8de576 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sat, 18 Oct 2014 17:51:07 +0200 Subject: [PATCH 17/21] added test for removal of atributes. refactor existing tests a bit, free up memory. --- src/util/attrib.test.c | 46 +++++++++++++++++++++++++++++++++++++++--- 1 file changed, 43 insertions(+), 3 deletions(-) diff --git a/src/util/attrib.test.c b/src/util/attrib.test.c index be3987bfe..2790f3edb 100644 --- a/src/util/attrib.test.c +++ b/src/util/attrib.test.c @@ -12,6 +12,7 @@ static void test_attrib_new(CuTest * tc) CuAssertPtrEquals(tc, 0, a->next); CuAssertPtrEquals(tc, 0, a->nexttype); CuAssertPtrEquals(tc, (void *)a->type, (void *)&at_test); + a_free(a); } @@ -20,18 +21,55 @@ 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); - CuAssertPtrEquals(tc, 0, alist->nexttype); CuAssertPtrNotNull(tc, (a = a_add(&alist, a_new(&at_foo)))); - CuAssertPtrEquals(tc, alist->next, a); + 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, alist->next->next, a); 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) @@ -39,5 +77,7 @@ 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; } From 5626abd8dc0dfdf4efd0f22b452b357cde85d7d3 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sat, 18 Oct 2014 18:37:44 +0200 Subject: [PATCH 18/21] refactor and kill dead code. indentation normalization, copyright update. --- src/kernel/curse.c | 922 ++++++++++++++++++------------------- src/kernel/curse.h | 12 +- src/triggers/removecurse.c | 74 ++- 3 files changed, 493 insertions(+), 515 deletions(-) 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/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; } From 539d2673f7c6bdf9dad2a2b9f7c68901fcd757e8 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sat, 18 Oct 2014 19:19:21 +0200 Subject: [PATCH 19/21] fix a crash in E2 caused by the recent removal of FFL_TIMEOUT. --- src/kernel/save.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/kernel/save.c b/src/kernel/save.c index 7febc0d23..c52eae383 100644 --- a/src/kernel/save.c +++ b/src/kernel/save.c @@ -1313,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) { From 7e1cec33a266ae85f50346ae6900715f918ecd33 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sat, 18 Oct 2014 19:23:36 +0200 Subject: [PATCH 20/21] Remove unused gmcmd attributes. use the at_deprecated feature that was built for this purpose. remove final external dependency on a_free in the code. --- src/modules/gmcmd.c | 32 ++++---------------------------- src/util/attrib.c | 16 ++++++++-------- src/util/attrib.h | 1 - src/util/attrib.test.c | 3 ++- 4 files changed, 14 insertions(+), 38 deletions(-) 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/util/attrib.c b/src/util/attrib.c index 2b83b60ec..7dc067cc4 100644 --- a/src/util/attrib.c +++ b/src/util/attrib.c @@ -151,14 +151,6 @@ attrib *a_add(attrib ** pa, attrib * a) return a; } -void a_free(attrib * a) -{ - const attrib_type *at = a->type; - if (at->finalize) - at->finalize(a); - free(a); -} - static int a_unlink(attrib ** pa, attrib * a) { attrib **pnexttype = pa; @@ -197,6 +189,14 @@ static int a_unlink(attrib ** pa, attrib * a) 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; diff --git a/src/util/attrib.h b/src/util/attrib.h index 2bea8d2b8..7dc3e1a3d 100644 --- a/src/util/attrib.h +++ b/src/util/attrib.h @@ -73,7 +73,6 @@ extern "C" { 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 int a_age(attrib ** attribs); extern int a_read(struct storage *store, attrib ** attribs, void *owner); diff --git a/src/util/attrib.test.c b/src/util/attrib.test.c index 2790f3edb..2e15c8321 100644 --- a/src/util/attrib.test.c +++ b/src/util/attrib.test.c @@ -12,7 +12,8 @@ static void test_attrib_new(CuTest * tc) CuAssertPtrEquals(tc, 0, a->next); CuAssertPtrEquals(tc, 0, a->nexttype); CuAssertPtrEquals(tc, (void *)a->type, (void *)&at_test); - a_free(a); + a_remove(&a, a); + CuAssertPtrEquals(tc, 0, a); } From 837227f69c8b107814fd369acd367186b98e2483 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sat, 18 Oct 2014 19:53:13 +0200 Subject: [PATCH 21/21] PR code review comments. - make study rule an enum, for easier debugging - change parameter name (it's not a type) --- src/study.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/study.c b/src/study.c index 44abd2329..f0686c766 100644 --- a/src/study.c +++ b/src/study.c @@ -493,13 +493,19 @@ int teach_cmd(unit * u, struct order *ord) return 0; } -static double study_speedup(unit * u, skill_t s, int rule_type) +typedef enum study_rule_t { + STUDY_DEFAULT = 0, + STUDY_FASTER = 1, + STUDY_AUTOTEACH = 2 +} study_rule_t; + +static double study_speedup(unit * u, skill_t s, study_rule_t rule) { #define MINTURN 16 double learnweeks = 0; int i; if (turn > MINTURN) { - if (rule_type == 1) { + if (rule == STUDY_FASTER) { for (i = 0; i != u->skill_size; ++i) { skill *sv = u->skills + i; if (sv->id == s){ @@ -511,7 +517,7 @@ static double study_speedup(unit * u, skill_t s, int rule_type) } return 2.0; /* If the skill was not found it is the first study. */ } - if (rule_type == 2) { + if (rule == STUDY_AUTOTEACH) { for (i = 0; i != u->skill_size; ++i) { skill *sv = u->skills + i; learnweeks = +(sv->level * (sv->level + 1) / 2.0); @@ -537,7 +543,7 @@ int learn_cmd(unit * u, order * ord) int money = 0; skill_t sk; int maxalchemy = 0; - int speed_rule = get_param_int(global.parameters, "study.speedup", 0); + int speed_rule = (study_rule_t)get_param_int(global.parameters, "study.speedup", 0); static int learn_newskills = -1; if (learn_newskills < 0) { const char *str = get_param(global.parameters, "study.newskills");