diff --git a/src/kernel/config.c b/src/kernel/config.c index dc61e643b..4a20d962a 100644 --- a/src/kernel/config.c +++ b/src/kernel/config.c @@ -924,8 +924,12 @@ default_wage(const region * r, const faction * f, const race * rc, int in_turn) int esize = 0; double wage; attrib *a; - const struct curse_type *ctype; + static int ct_cache; + static const struct curse_type *drought_ct; + if (ct_changed(&ct_cache)) { + drought_ct = ct_find("drought"); + } if (b != NULL) { /* TODO: this reveals imaginary castles */ esize = buildingeffsize(b, false); @@ -970,9 +974,8 @@ default_wage(const region * r, const faction * f, const race * rc, int in_turn) } /* Bei einer Dürre verdient man nur noch ein Viertel */ - ctype = ct_find("drought"); - if (ctype) { - curse *c = get_curse(r->attribs, ctype); + if (drought_ct) { + curse *c = get_curse(r->attribs, drought_ct); if (curse_active(c)) wage /= curse_geteffect(c); } diff --git a/src/kernel/curse.c b/src/kernel/curse.c index 646c99687..ac2e917a7 100644 --- a/src/kernel/curse.c +++ b/src/kernel/curse.c @@ -291,6 +291,17 @@ attrib_type at_curse = { #define MAXCTHASH 128 static quicklist *cursetypes[MAXCTHASH]; +static int ct_changes = 1; + +bool ct_changed(int *cache) +{ + assert(cache); + if (*cache != ct_changes) { + *cache = ct_changes; + return true; + } + return false; +} void ct_register(const curse_type * ct) { @@ -298,6 +309,27 @@ void ct_register(const curse_type * ct) quicklist **ctlp = cursetypes + hash; ql_set_insert(ctlp, (void *)ct); + ++ct_changes; +} + +void ct_remove(const char *c) +{ + unsigned int hash = tolower(c[0]); + quicklist *ctl = cursetypes[hash]; + + if (ctl) { + int 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) { + ql_delete(&ctl, qi); + ++ct_changes; + break; + } + } + } } const curse_type *ct_find(const char *c) @@ -798,5 +830,7 @@ void curses_done(void) { int i; for (i = 0; i != MAXCTHASH; ++i) { ql_free(cursetypes[i]); + cursetypes[i] = 0; } + ++ct_changes; } diff --git a/src/kernel/curse.h b/src/kernel/curse.h index 9013a1df5..a1518bbdd 100644 --- a/src/kernel/curse.h +++ b/src/kernel/curse.h @@ -282,7 +282,9 @@ extern "C" { int find_cursebyname(const char *c); const curse_type *ct_find(const char *c); + bool ct_changed(int *cache); void ct_register(const curse_type *); + void ct_remove(const char *c); void ct_checknames(void); curse *findcurse(int curseid); diff --git a/src/kernel/curse.test.c b/src/kernel/curse.test.c index 6514b2f3e..d7c86b9b0 100644 --- a/src/kernel/curse.test.c +++ b/src/kernel/curse.test.c @@ -157,10 +157,29 @@ static void test_write_flag(CuTest *tc) { cleanup_curse(&fix); } +static void test_curse_cache(CuTest *tc) +{ + int cache = 0; + const curse_type ct_dummy = { "dummy", CURSETYP_NORM, 0, M_SUMEFFECT, NULL }; + test_setup(); + CuAssertIntEquals(tc, true, ct_changed(&cache)); + CuAssertIntEquals(tc, false, ct_changed(&cache)); + CuAssertPtrEquals(tc, NULL, (void *)ct_find(ct_dummy.cname)); + ct_register(&ct_dummy); + CuAssertIntEquals(tc, true, ct_changed(&cache)); + CuAssertPtrEquals(tc, (void *)&ct_dummy, (void *)ct_find(ct_dummy.cname)); + ct_remove(ct_dummy.cname); + CuAssertIntEquals(tc, true, ct_changed(&cache)); + CuAssertIntEquals(tc, false, ct_changed(&cache)); + CuAssertPtrEquals(tc, NULL, (void *)ct_find(ct_dummy.cname)); + test_cleanup(); +} + CuSuite *get_curse_suite(void) { CuSuite *suite = CuSuiteNew(); SUITE_ADD_TEST(suite, test_curse); + SUITE_ADD_TEST(suite, test_curse_cache); SUITE_ADD_TEST(suite, test_magicstreet); SUITE_ADD_TEST(suite, test_magicstreet_warning); SUITE_ADD_TEST(suite, test_good_dreams); diff --git a/src/kernel/unit.c b/src/kernel/unit.c index f0636b681..246f59cb7 100644 --- a/src/kernel/unit.c +++ b/src/kernel/unit.c @@ -1279,8 +1279,12 @@ static int att_modification(const unit * u, skill_t sk) if (u->attribs) { curse *c; - const curse_type *skillmod_ct = ct_find("skillmod"); - const curse_type *worse_ct = ct_find("worse"); + static int cache; + static const curse_type *skillmod_ct, *worse_ct; + if (ct_changed(&cache)) { + skillmod_ct = ct_find("skillmod"); + worse_ct = ct_find("worse"); + } c = get_curse(u->attribs, worse_ct); if (c != NULL) result += curse_geteffect(c); @@ -1729,7 +1733,11 @@ int unit_max_hp(const unit * u) /* der healing curse veraendert die maximalen hp */ if (u->region && u->region->attribs) { - const curse_type *heal_ct = ct_find("healingzone"); + static int cache; + static const curse_type *heal_ct; + if (ct_changed(&cache)) { + heal_ct = ct_find("healingzone"); + } if (heal_ct) { curse *c = get_curse(u->region->attribs, heal_ct); if (c) {