From eb8376ef7084bd6f33ef5311647da0d4d44d2e02 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Mon, 19 Sep 2016 03:52:10 +0200 Subject: [PATCH 01/22] allow caching of ct_find results --- src/kernel/curse.c | 34 ++++++++++++++++++++++++++++++++++ src/kernel/curse.h | 2 ++ src/kernel/curse.test.c | 19 +++++++++++++++++++ 3 files changed, 55 insertions(+) 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); From e7739867df82c8c598d6d66b632a51e33364b2fa Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Mon, 19 Sep 2016 03:55:12 +0200 Subject: [PATCH 02/22] use curse_type caching in att_modification --- src/kernel/unit.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/kernel/unit.c b/src/kernel/unit.c index f0636b681..08f9314f3 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); From 640ba05876b44ca5fbe566c58538376ce815acef Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Mon, 19 Sep 2016 04:04:02 +0200 Subject: [PATCH 03/22] allow local caching of bt_find results --- src/kernel/building.c | 16 +++++++++++++++- src/kernel/building.h | 1 + src/kernel/building.test.c | 8 ++++++-- 3 files changed, 22 insertions(+), 3 deletions(-) diff --git a/src/kernel/building.c b/src/kernel/building.c index 60b588912..0056fba1e 100644 --- a/src/kernel/building.c +++ b/src/kernel/building.c @@ -83,15 +83,28 @@ const building_type *bt_find(const char *name) return bt_find_i(name); } +static int bt_changes = 1; + +bool bt_changed(int *cache) +{ + assert(cache); + if (*cache != bt_changes) { + *cache = bt_changes; + return true; + } + return false; +} + void bt_register(building_type * type) { if (type->init) { type->init(type); } ql_push(&buildingtypes, (void *)type); + ++bt_changes; } -void free_buildingtype(void *ptr) { +static void free_buildingtype(void *ptr) { building_type *btype = (building_type *)ptr; free_construction(btype->construction); free(btype->maintenance); @@ -103,6 +116,7 @@ void free_buildingtypes(void) { ql_foreach(buildingtypes, free_buildingtype); ql_free(buildingtypes); buildingtypes = 0; + ++bt_changes; } building_type *bt_get_or_create(const char *name) diff --git a/src/kernel/building.h b/src/kernel/building.h index 587197276..dad9ffdde 100644 --- a/src/kernel/building.h +++ b/src/kernel/building.h @@ -84,6 +84,7 @@ extern "C" { extern struct attrib_type at_building_action; building_type *bt_get_or_create(const char *name); + bool bt_changed(int *cache); const building_type *bt_find(const char *name); void free_buildingtypes(void); void register_buildings(void); diff --git a/src/kernel/building.test.c b/src/kernel/building.test.c index 2f6fa6e34..755e9319f 100644 --- a/src/kernel/building.test.c +++ b/src/kernel/building.test.c @@ -17,16 +17,20 @@ static void test_register_building(CuTest * tc) { building_type *btype; + int cache = 0; test_cleanup(); btype = (building_type *)calloc(sizeof(building_type), 1); btype->_name = _strdup("herp"); + CuAssertIntEquals(tc, true, bt_changed(&cache)); + CuAssertIntEquals(tc, false, bt_changed(&cache)); bt_register(btype); + CuAssertIntEquals(tc, true, bt_changed(&cache)); CuAssertPtrNotNull(tc, bt_find("herp")); - // free(btype->_name); - // free(btype); + free_buildingtypes(); + CuAssertIntEquals(tc, true, bt_changed(&cache)); test_cleanup(); } From d139ee08d1012044531996d6f364a29cd382ff30 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Mon, 19 Sep 2016 04:15:12 +0200 Subject: [PATCH 04/22] caching building_type in economy code --- src/economy.c | 48 ++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 38 insertions(+), 10 deletions(-) diff --git a/src/economy.c b/src/economy.c index 1eda7bf61..75071b608 100644 --- a/src/economy.c +++ b/src/economy.c @@ -1709,7 +1709,11 @@ static void buy(unit * u, request ** buyorders, struct order *ord) /* ...oder in der Region muß es eine Burg geben. */ building *b = 0; if (r->buildings) { - const struct building_type *bt_castle = bt_find("castle"); + static int cache; + static const struct building_type *bt_castle; + if (bt_changed(&cache)) { + bt_castle = bt_find("castle"); + } for (b = r->buildings; b; b = b->next) { if (b->type == bt_castle && b->size >= 2) { @@ -1795,8 +1799,14 @@ static void expandselling(region * r, request * sellorders, int limit) unit *hafenowner; static int counter[MAXLUXURIES]; static int ncounter = 0; - const struct building_type *castle_bt; + static int bt_cache; + static const struct building_type *castle_bt, *harbour_bt, *caravan_bt; + if (bt_changed(&bt_cache)) { + castle_bt = bt_find("castle"); + harbour_bt = bt_find("harbour"); + caravan_bt = bt_find("caravan"); + } if (ncounter == 0) { const luxury_type *ltype; for (ltype = luxurytypes; ltype; ltype = ltype->next) { @@ -1811,7 +1821,6 @@ static void expandselling(region * r, request * sellorders, int limit) } /* Stelle Eigentümer der größten Burg fest. Bekommt Steuern aus jedem * Verkauf. Wenn zwei Burgen gleicher Größe bekommt gar keiner etwas. */ - castle_bt = bt_find("castle"); for (b = rbuildings(r); b; b = b->next) { if (b->size > maxsize && building_owner(b) != NULL && b->type == castle_bt) { @@ -1825,7 +1834,7 @@ static void expandselling(region * r, request * sellorders, int limit) } } - hafenowner = owner_buildingtyp(r, bt_find("harbour")); + hafenowner = owner_buildingtyp(r, harbour_bt); if (maxb != (building *)NULL && maxowner != (unit *)NULL) { maxeffsize = buildingeffsize(maxb, false); @@ -1847,7 +1856,7 @@ static void expandselling(region * r, request * sellorders, int limit) return; if (r->terrain == newterrain(T_DESERT) - && buildingtype_exists(r, bt_find("caravan"), true)) { + && buildingtype_exists(r, caravan_bt, true)) { max_products = rpeasants(r) * 2 / TRADE_FRACTION; } /* Verkauf: so programmiert, dass er leicht auf mehrere Gueter pro @@ -1974,6 +1983,13 @@ static bool sell(unit * u, request ** sellorders, struct order *ord) region *r = u->region; const char *s; keyword_t kwd; + static int bt_cache; + static const struct building_type *castle_bt, *caravan_bt; + + if (bt_changed(&bt_cache)) { + castle_bt = bt_find("castle"); + caravan_bt = bt_find("caravan"); + } if (u->ship && is_guarded(r, u, GUARD_CREWS)) { cmistake(u, ord, 69, MSG_INCOME); @@ -1990,7 +2006,7 @@ static bool sell(unit * u, request ** sellorders, struct order *ord) unlimited = false; n = rpeasants(r) / TRADE_FRACTION; if (r->terrain == newterrain(T_DESERT) - && buildingtype_exists(r, bt_find("caravan"), true)) + && buildingtype_exists(r, caravan_bt, true)) n *= 2; if (n == 0) { cmistake(u, ord, 303, MSG_COMMERCE); @@ -2023,9 +2039,8 @@ static bool sell(unit * u, request ** sellorders, struct order *ord) /* ...oder in der Region muß es eine Burg geben. */ building *b = 0; if (r->buildings) { - const struct building_type *bt_castle = bt_find("castle"); for (b = r->buildings; b; b = b->next) { - if (b->type == bt_castle && b->size >= 2) break; + if (b->type == castle_bt && b->size >= 2) break; } } if (!b) { @@ -2340,9 +2355,15 @@ static void breedhorses(unit * u) int n, c, breed = 0; const struct resource_type *rhorse = get_resourcetype(R_HORSE); int horses, effsk; + static int bt_cache; + static const struct building_type *stables_bt; + + if (bt_changed(&bt_cache)) { + stables_bt = bt_find("stables"); + } assert(rhorse && rhorse->itype); - if (!active_building(u, bt_find("stables"))) { + if (!active_building(u, stables_bt)) { cmistake(u, u->thisorder, 122, MSG_PRODUCE); return; } @@ -3079,6 +3100,13 @@ void produce(struct region *r) unit *u; bool limited = true; request *nextworker = workers; + static int bt_cache; + static const struct building_type *caravan_bt; + + if (bt_changed(&bt_cache)) { + caravan_bt = bt_find("caravan"); + } + assert(r); /* das sind alles befehle, die 30 tage brauchen, und die in thisorder @@ -3228,7 +3256,7 @@ void produce(struct region *r) if (sellorders) { int limit = rpeasants(r) / TRADE_FRACTION; if (r->terrain == newterrain(T_DESERT) - && buildingtype_exists(r, bt_find("caravan"), true)) + && buildingtype_exists(r, caravan_bt, true)) limit *= 2; expandselling(r, sellorders, limited ? limit : INT_MAX); } From 9af5fb032674790449f42118d979ea7bae72c8c4 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Mon, 19 Sep 2016 04:23:49 +0200 Subject: [PATCH 05/22] cache some of the highest-ranking ct_find callers --- src/kernel/config.c | 11 +++++++---- src/kernel/unit.c | 6 +++++- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/src/kernel/config.c b/src/kernel/config.c index d78362f3c..5b51950e0 100644 --- a/src/kernel/config.c +++ b/src/kernel/config.c @@ -923,8 +923,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); @@ -969,9 +973,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/unit.c b/src/kernel/unit.c index 08f9314f3..246f59cb7 100644 --- a/src/kernel/unit.c +++ b/src/kernel/unit.c @@ -1733,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) { From fbd596fbfa068bc9d66fedc8685b663cafc5ac6a Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Mon, 19 Sep 2016 06:43:56 +0200 Subject: [PATCH 06/22] remove bad caching in get_race --- src/kernel/race.c | 19 ++----------------- 1 file changed, 2 insertions(+), 17 deletions(-) diff --git a/src/kernel/race.c b/src/kernel/race.c index 57f443ea5..bb91898db 100644 --- a/src/kernel/race.c +++ b/src/kernel/race.c @@ -75,30 +75,15 @@ static const char *racenames[MAXRACES] = { "clone" }; -static race * race_cache[MAXRACES]; - struct race *get_race(race_t rt) { - static int cache = -1; const char * name; - race * result = 0; assert(rt < MAXRACES); name = racenames[rt]; if (!name) { - return 0; + return NULL; } - if (cache_breaker != cache) { - cache = cache_breaker; - memset(race_cache, 0, sizeof(race_cache)); - return race_cache[rt] = rc_get_or_create(name); - } - else { - result = race_cache[rt]; - if (!result) { - result = race_cache[rt] = rc_get_or_create(name); - } - } - return result; + return rc_get_or_create(name); } race_list *get_familiarraces(void) From f8167ed62caab84b93c523982800f429e85b339b Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Mon, 19 Sep 2016 06:47:46 +0200 Subject: [PATCH 07/22] test get_race and others --- src/kernel/race.test.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/kernel/race.test.c b/src/kernel/race.test.c index e8bbfcf29..25bd3e912 100644 --- a/src/kernel/race.test.c +++ b/src/kernel/race.test.c @@ -9,7 +9,7 @@ static void test_rc_name(CuTest *tc) { struct race *rc; - test_cleanup(); + test_setup(); rc = test_create_race("human"); CuAssertStrEquals(tc, "race::human", rc_name_s(rc, NAME_SINGULAR)); CuAssertStrEquals(tc, "race::human_p", rc_name_s(rc, NAME_PLURAL)); @@ -20,7 +20,7 @@ static void test_rc_name(CuTest *tc) { static void test_rc_defaults(CuTest *tc) { struct race *rc; - test_cleanup(); + test_setup(); rc = rc_get_or_create("human"); CuAssertStrEquals(tc, "human", rc->_name); CuAssertDblEquals(tc, 0.0, rc->magres, 0.0); @@ -43,15 +43,25 @@ static void test_rc_defaults(CuTest *tc) { static void test_rc_find(CuTest *tc) { race *rc; - test_cleanup(); + test_setup(); rc = test_create_race("hungryhippos"); CuAssertPtrEquals(tc, rc, (void *)rc_find("hungryhippos")); test_cleanup(); } +static void test_race_get(CuTest *tc) { + race *rc; + test_setup(); + rc = get_race(RC_ELF); + CuAssertPtrEquals(tc, rc, (void *)rc_find("elf")); + CuAssertPtrEquals(tc, rc, (void *)rc_get_or_create("elf")); + test_cleanup(); +} + CuSuite *get_race_suite(void) { CuSuite *suite = CuSuiteNew(); + SUITE_ADD_TEST(suite, test_race_get); SUITE_ADD_TEST(suite, test_rc_name); SUITE_ADD_TEST(suite, test_rc_defaults); SUITE_ADD_TEST(suite, test_rc_find); From 96d6abdc5a802e335fadd15e2a06c991249be4d0 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Mon, 19 Sep 2016 06:55:32 +0200 Subject: [PATCH 08/22] add caching API for rc_find --- src/kernel/race.c | 14 ++++++++++++-- src/kernel/race.h | 1 + src/kernel/race.test.c | 9 ++++++++- 3 files changed, 21 insertions(+), 3 deletions(-) diff --git a/src/kernel/race.c b/src/kernel/race.c index bb91898db..1088681d2 100644 --- a/src/kernel/race.c +++ b/src/kernel/race.c @@ -59,7 +59,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. /** external variables **/ race *races; int num_races = 0; -static int cache_breaker; +static int rc_changes = 1; static const char *racenames[MAXRACES] = { "dwarf", "elf", NULL, "goblin", "human", "troll", "demon", "insect", @@ -132,6 +132,7 @@ void free_races(void) { races = rc; } num_races = 0; + ++rc_changes; } static race *rc_find_i(const char *name) @@ -153,6 +154,15 @@ const race * rc_find(const char *name) { return rc_find_i(name); } +bool rc_changed(int *cache) { + assert(cache); + if (*cache != rc_changes) { + *cache = rc_changes; + return true; + } + return false; +} + race *rc_get_or_create(const char *zName) { race *rc; @@ -180,7 +190,7 @@ race *rc_get_or_create(const char *zName) for (i = 1; i < RACE_ATTACKS; ++i) rc->attack[i].type = AT_NONE; rc->index = num_races++; - ++cache_breaker; + ++rc_changes; rc->next = races; return races = rc; } diff --git a/src/kernel/race.h b/src/kernel/race.h index b1632f62d..6e8e4bd36 100644 --- a/src/kernel/race.h +++ b/src/kernel/race.h @@ -180,6 +180,7 @@ extern "C" { race_t old_race(const struct race *); race *rc_get_or_create(const char *name); + bool rc_changed(int *cache); const race *rc_find(const char *); void free_races(void); diff --git a/src/kernel/race.test.c b/src/kernel/race.test.c index 25bd3e912..0a14c3ca6 100644 --- a/src/kernel/race.test.c +++ b/src/kernel/race.test.c @@ -50,11 +50,18 @@ static void test_rc_find(CuTest *tc) { } static void test_race_get(CuTest *tc) { + int cache; race *rc; test_setup(); + CuAssertTrue(tc, rc_changed(&cache)); + CuAssertTrue(tc, !rc_changed(&cache)); rc = get_race(RC_ELF); - CuAssertPtrEquals(tc, rc, (void *)rc_find("elf")); CuAssertPtrEquals(tc, rc, (void *)rc_get_or_create("elf")); + CuAssertTrue(tc, rc_changed(&cache)); + CuAssertTrue(tc, !rc_changed(&cache)); + CuAssertPtrEquals(tc, rc, (void *)rc_find("elf")); + free_races(); + CuAssertTrue(tc, rc_changed(&cache)); test_cleanup(); } From fe383af5f2cb032fc31d1e82bccf9f38c4f3b9f6 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Mon, 19 Sep 2016 06:58:24 +0200 Subject: [PATCH 09/22] sample usage of race caching --- src/spells.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/spells.c b/src/spells.c index ab4d6dd6d..015d56067 100644 --- a/src/spells.c +++ b/src/spells.c @@ -1501,16 +1501,23 @@ static int sp_create_irongolem(castorder * co) int cast_level = co->level; double force = co->force; int number = lovar(force * 8 * RESOURCE_QUANTITY); - if (number < 1) + static int cache; + race * golem_rc; + + if (rc_changed(&cache)) { + golem_rc = rc_find("irongolem"); + } + + if (number < 1) { number = 1; + } if (r->terrain == newterrain(T_SWAMP)) { cmistake(mage, co->order, 188, MSG_MAGIC); return 0; } - u2 = - create_unit(r, mage->faction, number, rc_find("irongolem"), 0, NULL, mage); + u2 = create_unit(r, mage->faction, number, golem_rc, 0, NULL, mage); set_level(u2, SK_ARMORER, 1); set_level(u2, SK_WEAPONSMITH, 1); @@ -1523,7 +1530,7 @@ static int sp_create_irongolem(castorder * co) ADDMSG(&mage->faction->msgs, msg_message("magiccreate_effect", "region command unit amount object", mage->region, co->order, mage, number, - LOC(mage->faction->locale, rc_name_s(rc_find("irongolem"), (u2->number == 1) ? NAME_SINGULAR : NAME_PLURAL)))); + LOC(mage->faction->locale, rc_name_s(golem_rc, (u2->number == 1) ? NAME_SINGULAR : NAME_PLURAL)))); return cast_level; } From 025c0b91d9110911695f204ef08ce0e024b76ca7 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Mon, 19 Sep 2016 07:02:45 +0200 Subject: [PATCH 10/22] cache the toad race --- src/study.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/src/study.c b/src/study.c index 58cbde94a..70c016dfc 100644 --- a/src/study.c +++ b/src/study.c @@ -94,6 +94,9 @@ magic_t getmagicskill(const struct locale * lang) /* familiars and toads are not migrants */ bool is_migrant(unit * u) { + static int cache; + static race *toad_rc; + if (u_race(u) == u->faction->race) return false; @@ -101,16 +104,21 @@ bool is_migrant(unit * u) return false; if (is_familiar(u)) return false; - if (u_race(u) == get_race(RC_TOAD)) - return false; - - return true; + if (rc_changed(&cache)) { + toad_rc = get_race(RC_TOAD); + } + return u_race(u) != toad_rc; } /* ------------------------------------------------------------- */ bool magic_lowskill(unit * u) { - return (u_race(u) == get_race(RC_TOAD)) ? true : false; + static race *toad_rc; + static int cache; + if (rc_changed(&cache)) { + toad_rc = get_race(RC_TOAD); + } + return u_race(u) == toad_rc; } /* ------------------------------------------------------------- */ From ee77075cb6fd777079e0cc4fea6d6bb6f08b6e77 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Mon, 19 Sep 2016 08:25:39 +0200 Subject: [PATCH 11/22] cache get_race calls --- src/kernel/config.c | 1 + src/kernel/skills.c | 28 ++++++++++++++++++++-------- 2 files changed, 21 insertions(+), 8 deletions(-) diff --git a/src/kernel/config.c b/src/kernel/config.c index d78362f3c..dc61e643b 100644 --- a/src/kernel/config.c +++ b/src/kernel/config.c @@ -140,6 +140,7 @@ int NMRTimeout(void) race_t old_race(const struct race * rc) { race_t i; + // TODO: this sucks so bad! for (i = 0; i != MAXRACES; ++i) { if (get_race(i) == rc) return i; } diff --git a/src/kernel/skills.c b/src/kernel/skills.c index caae7b836..e773424ab 100644 --- a/src/kernel/skills.c +++ b/src/kernel/skills.c @@ -104,16 +104,22 @@ int value, int flags) int skill_mod(const race * rc, skill_t sk, const struct terrain_type *terrain) { int result = 0; + static int rc_cache; + static race *rc_dwarf, *rc_insect; + if (rc_changed(&rc_cache)) { + rc_dwarf = get_race(RC_DWARF); + rc_insect = get_race(RC_INSECT); + } result = rc->bonus[sk]; - if (rc == get_race(RC_DWARF)) { + if (rc == rc_dwarf) { if (sk == SK_TACTICS) { if (terrain == newterrain(T_MOUNTAIN) || fval(terrain, ARCTIC_REGION)) ++result; } } - else if (rc == get_race(RC_INSECT)) { + else if (rc == rc_insect) { if (terrain == newterrain(T_MOUNTAIN) || fval(terrain, ARCTIC_REGION)) --result; else if (terrain == newterrain(T_DESERT) || terrain == newterrain(T_SWAMP)) @@ -126,19 +132,25 @@ int skill_mod(const race * rc, skill_t sk, const struct terrain_type *terrain) int rc_skillmod(const struct race *rc, const region * r, skill_t sk) { int mods = 0; - if (!skill_enabled(sk)) { return 0; } if (r) { mods = skill_mod(rc, sk, r->terrain); } - if (rc == get_race(RC_ELF) && r && r_isforest(r)) { - if (sk == SK_PERCEPTION || sk == SK_STEALTH) { - ++mods; + if (r && r_isforest(r)) { + static int rc_cache; + static race * rc_elf; + if (rc_changed(&rc_cache)) { + rc_elf = get_race(RC_ELF); } - else if (sk == SK_TACTICS) { - mods += 2; + if (rc == rc_elf) { + if (sk == SK_PERCEPTION || sk == SK_STEALTH) { + ++mods; + } + else if (sk == SK_TACTICS) { + mods += 2; + } } } return mods; From be5f15e18a58b36c8bcd4bb9f82a024e38c4ed48 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Mon, 19 Sep 2016 08:32:09 +0200 Subject: [PATCH 12/22] fix const-conversion warning --- src/spells.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/spells.c b/src/spells.c index 015d56067..63f3af6a3 100644 --- a/src/spells.c +++ b/src/spells.c @@ -1502,7 +1502,7 @@ static int sp_create_irongolem(castorder * co) double force = co->force; int number = lovar(force * 8 * RESOURCE_QUANTITY); static int cache; - race * golem_rc; + const race * golem_rc; if (rc_changed(&cache)) { golem_rc = rc_find("irongolem"); @@ -1570,6 +1570,11 @@ static int sp_create_stonegolem(castorder * co) unit *mage = co->magician.u; int cast_level = co->level; int number = lovar(co->force * 5 * RESOURCE_QUANTITY); + const race * golem_rc; + + if (rc_changed(&cache)) { + golem_rc = rc_find("stonegolem"); + } if (number < 1) number = 1; @@ -1579,7 +1584,7 @@ static int sp_create_stonegolem(castorder * co) } u2 = - create_unit(r, mage->faction, number, rc_find("stonegolem"), 0, NULL, mage); + create_unit(r, mage->faction, number, golem_rc, 0, NULL, mage); set_level(u2, SK_ROAD_BUILDING, 1); set_level(u2, SK_BUILDING, 1); @@ -1591,7 +1596,7 @@ static int sp_create_stonegolem(castorder * co) ADDMSG(&mage->faction->msgs, msg_message("magiccreate_effect", "region command unit amount object", mage->region, co->order, mage, number, - LOC(mage->faction->locale, rc_name_s(rc_find("stonegolem"), (u2->number == 1) ? NAME_SINGULAR : NAME_PLURAL)))); + LOC(mage->faction->locale, rc_name_s(golem_rc, (u2->number == 1) ? NAME_SINGULAR : NAME_PLURAL)))); return cast_level; } From 6964267c3764ba6d74e2d186926ccc03e65a3016 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Mon, 19 Sep 2016 08:35:54 +0200 Subject: [PATCH 13/22] static variables, duh --- src/spells.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/spells.c b/src/spells.c index 63f3af6a3..380d41b54 100644 --- a/src/spells.c +++ b/src/spells.c @@ -1502,7 +1502,7 @@ static int sp_create_irongolem(castorder * co) double force = co->force; int number = lovar(force * 8 * RESOURCE_QUANTITY); static int cache; - const race * golem_rc; + static const race * golem_rc; if (rc_changed(&cache)) { golem_rc = rc_find("irongolem"); @@ -1570,7 +1570,8 @@ static int sp_create_stonegolem(castorder * co) unit *mage = co->magician.u; int cast_level = co->level; int number = lovar(co->force * 5 * RESOURCE_QUANTITY); - const race * golem_rc; + static int cache; + static const race * golem_rc; if (rc_changed(&cache)) { golem_rc = rc_find("stonegolem"); From 115e13d513d6fd93e04cf14c58e81a0f01faf262 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Mon, 19 Sep 2016 08:42:07 +0200 Subject: [PATCH 14/22] initialize variable --- src/kernel/race.test.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/kernel/race.test.c b/src/kernel/race.test.c index 0a14c3ca6..7c464e4da 100644 --- a/src/kernel/race.test.c +++ b/src/kernel/race.test.c @@ -50,7 +50,7 @@ static void test_rc_find(CuTest *tc) { } static void test_race_get(CuTest *tc) { - int cache; + int cache = 0; race *rc; test_setup(); CuAssertTrue(tc, rc_changed(&cache)); From b958fa1c2e724de73db5d04d4746752487eac718 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Mon, 19 Sep 2016 08:56:33 +0200 Subject: [PATCH 15/22] get_race is better than old_race --- src/volcano.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/volcano.c b/src/volcano.c index 910bd8775..bd8c56b30 100644 --- a/src/volcano.c +++ b/src/volcano.c @@ -118,7 +118,7 @@ damage_unit(unit * u, const char *dam, bool physical, bool magic) heiltrank = 0; /* Sieben Leben */ - if (old_race(u_race(u)) == RC_CAT && (chance(1.0 / 7))) { + if (u_race(u) == get_race(RC_CAT) && (chance(1.0 / 7))) { hp[i] = u->hp / u->number; hp_rem += hp[i]; continue; From 6ec99af4d6d84276f437dc3b6a11ace1bac3dec7 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Mon, 19 Sep 2016 15:53:31 +0200 Subject: [PATCH 16/22] mark all three major dragon types as RCF_DRAGON. use RCF_DRGON flag to detemine BP_DRAGON speed. --- res/eressea/races.xml | 2 +- res/races/dragon.xml | 2 +- res/races/wyrm.xml | 2 +- res/races/youngdragon.xml | 2 +- src/move.c | 11 +++++------ 5 files changed, 9 insertions(+), 10 deletions(-) diff --git a/res/eressea/races.xml b/res/eressea/races.xml index 201a6a797..b29b84ede 100644 --- a/res/eressea/races.xml +++ b/res/eressea/races.xml @@ -742,7 +742,7 @@ - + diff --git a/res/races/dragon.xml b/res/races/dragon.xml index 7a6dee3a7..a1f347105 100644 --- a/res/races/dragon.xml +++ b/res/races/dragon.xml @@ -1,5 +1,5 @@ +"6" damage="2d30" unarmedattack="0" unarmeddefense="0" attackmodifier="7" defensemodifier="7" scarepeasants="yes" fly="yes" walk="yes" teach="no" getitem="yes" resistbash="yes" dragon="yes"> diff --git a/res/races/wyrm.xml b/res/races/wyrm.xml index 8569f4c19..5c63b0fb6 100644 --- a/res/races/wyrm.xml +++ b/res/races/wyrm.xml @@ -1,4 +1,4 @@ - + diff --git a/res/races/youngdragon.xml b/res/races/youngdragon.xml index 541f68142..fe29bbfde 100644 --- a/res/races/youngdragon.xml +++ b/res/races/youngdragon.xml @@ -1,4 +1,4 @@ - + diff --git a/src/move.c b/src/move.c index c95775b5a..a97bc5425 100644 --- a/src/move.c +++ b/src/move.c @@ -1465,15 +1465,14 @@ static void make_route(unit * u, order * ord, region_list ** routep) static int movement_speed(unit * u) { int mp = BP_WALKING; - double dk = u_race(u)->speed; - + const race *rc = u_race(u); + double dk = rc->speed; assert(u->number); /* dragons have a fixed speed, and no other effects work on them: */ - switch (old_race(u_race(u))) { - case RC_DRAGON: - case RC_WYRM: - case RC_FIREDRAGON: + if (fval(rc, RCF_DRAGON)) { return BP_DRAGON; + } + switch (old_race(u_race(u))) { case RC_BIRTHDAYDRAGON: case RC_SONGDRAGON: mp = BP_DRAGON; From e6677806b615d9b65d26a273853c2f576f56f353 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Mon, 19 Sep 2016 16:03:02 +0200 Subject: [PATCH 17/22] refactor unholy power, extract function --- src/spells.c | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/src/spells.c b/src/spells.c index 380d41b54..589b062da 100644 --- a/src/spells.c +++ b/src/spells.c @@ -2730,6 +2730,22 @@ static int sp_firewall(castorder * co) * (SPELLLEVEL | TESTCANSEE) */ +static race *unholy_race(const race *rc) { + race *target_race = NULL; + switch (old_race(rc)) { + case RC_SKELETON: + target_race = get_race(RC_SKELETON_LORD); + break; + case RC_ZOMBIE: + target_race = get_race(RC_ZOMBIE_LORD); + break; + case RC_GHOUL: + target_race = get_race(RC_GHOUL_LORD); + break; + } + return target_race; +} + static int sp_unholypower(castorder * co) { region * r = co_get_region(co); @@ -2752,17 +2768,8 @@ static int sp_unholypower(castorder * co) u = pa->param[i]->data.u; - switch (old_race(u_race(u))) { - case RC_SKELETON: - target_race = get_race(RC_SKELETON_LORD); - break; - case RC_ZOMBIE: - target_race = get_race(RC_ZOMBIE_LORD); - break; - case RC_GHOUL: - target_race = get_race(RC_GHOUL_LORD); - break; - default: + target_race = unholy_race(u_race(u)); + if (!target_race) { cmistake(mage, co->order, 284, MSG_MAGIC); continue; } From 1f100a1b6ceea63f5a1eaac15bbee7bf2f54fe8f Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Mon, 19 Sep 2016 16:10:10 +0200 Subject: [PATCH 18/22] replace old_race calls with get_race. --- src/monsters.c | 19 +++++++------------ src/spells.c | 2 ++ 2 files changed, 9 insertions(+), 12 deletions(-) diff --git a/src/monsters.c b/src/monsters.c index 0da4947f2..f5d38a446 100644 --- a/src/monsters.c +++ b/src/monsters.c @@ -380,20 +380,15 @@ static order *monster_move(region * r, unit * u) if (monster_is_waiting(u)) { return NULL; } - switch (old_race(u_race(u))) { - case RC_FIREDRAGON: - case RC_DRAGON: - case RC_WYRM: + if (fval(u_race(u), RCF_DRAGON)) { d = richest_neighbour(r, u->faction, 1); - break; - case RC_TREEMAN: - d = treeman_neighbour(r); - break; - default: - d = random_neighbour(r, u); - break; } - + else if (get_race(RC_TREEMAN)==u_race(u)) { + d = treeman_neighbour(r); + } + else { + d = random_neighbour(r, u); + } /* falls kein geld gefunden wird, zufaellig verreisen, aber nicht in * den ozean */ diff --git a/src/spells.c b/src/spells.c index 589b062da..37fa9af55 100644 --- a/src/spells.c +++ b/src/spells.c @@ -2742,6 +2742,8 @@ static race *unholy_race(const race *rc) { case RC_GHOUL: target_race = get_race(RC_GHOUL_LORD); break; + default: + target_race = NULL; } return target_race; } From 043ff40d0255c680b504afb37c602fbaad24816b Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Mon, 19 Sep 2016 18:28:44 +0200 Subject: [PATCH 19/22] eliminate another call to old_race. --- src/spells.c | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/src/spells.c b/src/spells.c index 37fa9af55..a860abe3c 100644 --- a/src/spells.c +++ b/src/spells.c @@ -2731,21 +2731,23 @@ static int sp_firewall(castorder * co) */ static race *unholy_race(const race *rc) { - race *target_race = NULL; - switch (old_race(rc)) { - case RC_SKELETON: - target_race = get_race(RC_SKELETON_LORD); - break; - case RC_ZOMBIE: - target_race = get_race(RC_ZOMBIE_LORD); - break; - case RC_GHOUL: - target_race = get_race(RC_GHOUL_LORD); - break; - default: - target_race = NULL; + static int cache; + static race * rc_skeleton, *rc_zombie, *rc_ghoul; + if (rc_changed(&cache)) { + rc_skeleton = get_race(RC_SKELETON); + rc_zombie = get_race(RC_ZOMBIE); + rc_ghoul = get_race(RC_GHOUL); } - return target_race; + if (rc == rc_skeleton) { + return get_race(RC_SKELETON_LORD); + } + if (rc == rc_zombie) { + return get_race(RC_ZOMBIE_LORD); + } + if (rc == rc_ghoul) { + return get_race(RC_GHOUL_LORD); + } + return NULL; } static int sp_unholypower(castorder * co) From a7fbe4901b920ffda74558fafeaef66ffb7b2c74 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Mon, 19 Sep 2016 18:42:14 +0200 Subject: [PATCH 20/22] eliminate old_race. make the catdragon act like a dragon. --- res/eressea/races.xml | 2 +- src/battle.c | 46 ++++++++++++++++++---------------- src/economy.c | 58 +++++++++++++++++++++++-------------------- src/guard.c | 30 +++++++++++++--------- src/kernel/race.h | 2 +- 5 files changed, 75 insertions(+), 63 deletions(-) diff --git a/res/eressea/races.xml b/res/eressea/races.xml index b29b84ede..513797d8d 100644 --- a/res/eressea/races.xml +++ b/res/eressea/races.xml @@ -717,7 +717,7 @@ - + diff --git a/src/battle.c b/src/battle.c index 392b24441..534984fb1 100644 --- a/src/battle.c +++ b/src/battle.c @@ -1037,31 +1037,33 @@ static int rc_specialdamage(const unit *au, const unit *du, const struct weapon_ { const race *ar = u_race(au); int m, modifier = 0; - - switch (old_race(ar)) { - case RC_HALFLING: - if (wtype != NULL && dragonrace(u_race(du))) { - modifier += 5; + if (wtype != NULL) { + if (fval(u_race(du), RCF_DRAGON)) { + static int cache; + static race *rc_halfling; + if (rc_changed(&cache)) { + rc_halfling = get_race(RC_HALFLING); + } + if (ar == rc_halfling) { + modifier += 5; + } } - break; - default: - break; - } - if (wtype != NULL && wtype->modifiers != NULL) { - for (m = 0; wtype->modifiers[m].value; ++m) { - /* weapon damage for this weapon, possibly by race */ - if (wtype->modifiers[m].flags & WMF_DAMAGE) { - race_list *rlist = wtype->modifiers[m].races; - if (rlist != NULL) { - while (rlist) { - if (rlist->data == ar) - break; - rlist = rlist->next; + if (wtype->modifiers != NULL) { + for (m = 0; wtype->modifiers[m].value; ++m) { + /* weapon damage for this weapon, possibly by race */ + if (wtype->modifiers[m].flags & WMF_DAMAGE) { + race_list *rlist = wtype->modifiers[m].races; + if (rlist != NULL) { + while (rlist) { + if (rlist->data == ar) + break; + rlist = rlist->next; + } + if (rlist == NULL) + continue; } - if (rlist == NULL) - continue; + modifier += wtype->modifiers[m].value; } - modifier += wtype->modifiers[m].value; } } } diff --git a/src/economy.c b/src/economy.c index 1eda7bf61..ae13d5ecc 100644 --- a/src/economy.c +++ b/src/economy.c @@ -114,16 +114,20 @@ static void recruit_init(void) int income(const unit * u) { - switch (old_race(u_race(u))) { - case RC_FIREDRAGON: - return 150 * u->number; - case RC_DRAGON: - return 1000 * u->number; - case RC_WYRM: - return 5000 * u->number; - default: - return 20 * u->number; + // TODO: make this a property, like race.income, no hard-coding of values + if (fval(u_race(u), RCF_DRAGON)) { + switch (old_race(u_race(u))) { + case RC_FIREDRAGON: + return 150 * u->number; + case RC_DRAGON: + return 1000 * u->number; + case RC_WYRM: + return 5000 * u->number; + default: + break; + } } + return 20 * u->number; } static void scramble(void *data, unsigned int n, size_t width) @@ -478,7 +482,7 @@ static void recruit(unit * u, struct order *ord, request ** recruitorders) init_order(ord); n = getint(); - if (n<=0) { + if (n <= 0) { syntax_error(u, ord); return; } @@ -796,7 +800,7 @@ static int maintain(building * b) cost -= use_pooled(u, m->rtype, GET_SLACK | GET_RESERVE | GET_POOLED_SLACK, - cost); + cost); assert(cost == 0); } if (work) { @@ -815,7 +819,7 @@ void maintain_buildings(region * r) while (*bp) { building *b = *bp; int flags = BLD_MAINTAINED; - + if (!curse_active(get_curse(b->attribs, nocost_ct))) { flags = maintain(b); } @@ -929,12 +933,12 @@ static void manufacture(unit * u, const item_type * itype, int want) case EBUILDINGREQ: ADDMSG(&u->faction->msgs, msg_feedback(u, u->thisorder, "building_needed", "building", - itype->construction->btype->_name)); + itype->construction->btype->_name)); return; case ELOWSKILL: ADDMSG(&u->faction->msgs, msg_feedback(u, u->thisorder, "manufacture_skills", - "skill minskill product", sk, minskill, itype->rtype, 1)); + "skill minskill product", sk, minskill, itype->rtype, 1)); return; case ENOMATERIALS: ADDMSG(&u->faction->msgs, msg_materials_required(u, u->thisorder, @@ -1077,8 +1081,8 @@ static void allocate_resource(unit * u, const resource_type * rtype, int want) skill_t sk = itype->construction->skill; add_message(&u->faction->msgs, msg_feedback(u, u->thisorder, "manufacture_skills", - "skill minskill product", sk, itype->construction->minskill, - itype->rtype)); + "skill minskill product", sk, itype->construction->minskill, + itype->rtype)); return; } else { @@ -1276,7 +1280,7 @@ attrib_allocation(const resource_type * rtype, region * r, allocation * alist) } typedef void(*allocate_function) (const resource_type *, struct region *, -struct allocation *); + struct allocation *); static allocate_function get_allocator(const struct resource_type *rtype) { @@ -1345,7 +1349,7 @@ static void create_potion(unit * u, const potion_type * ptype, int want) case EBUILDINGREQ: ADDMSG(&u->faction->msgs, msg_feedback(u, u->thisorder, "building_needed", "building", - ptype->itype->construction->btype->_name)); + ptype->itype->construction->btype->_name)); break; case ECOMPLETE: assert(0); @@ -1687,7 +1691,7 @@ static void buy(unit * u, request ** buyorders, struct order *ord) kwd = init_order(ord); assert(kwd == K_BUY); n = getint(); - if (n<=0) { + if (n <= 0) { cmistake(u, ord, 26, MSG_COMMERCE); return; } @@ -2082,7 +2086,7 @@ static bool sell(unit * u, request ** sellorders, struct order *ord) * produktion, wo für jedes produkt einzeln eine obere limite * existiert, so dass man arrays von orders machen kann. */ - /* Ein Händler kann nur 10 Güter pro Talentpunkt handeln. */ + /* Ein Händler kann nur 10 Güter pro Talentpunkt handeln. */ k = u->number * 10 * effskill(u, SK_TRADE, 0); /* hat der Händler bereits gehandelt, muss die Menge der bereits @@ -2188,7 +2192,7 @@ static void plant(unit * u, int raw) if (skill < 6) { ADDMSG(&u->faction->msgs, msg_feedback(u, u->thisorder, "plant_skills", - "skill minskill product", SK_HERBALISM, 6, itype->rtype, 1)); + "skill minskill product", SK_HERBALISM, 6, itype->rtype, 1)); return; } /* Wasser des Lebens prüfen */ @@ -2202,7 +2206,7 @@ static void plant(unit * u, int raw) if (n == 0) { ADDMSG(&u->faction->msgs, msg_feedback(u, u->thisorder, "resource_missing", "missing", - itype->rtype)); + itype->rtype)); return; } @@ -2218,7 +2222,7 @@ static void plant(unit * u, int raw) /* Alles ok. Abziehen. */ use_pooled(u, rt_water, GET_DEFAULT, 1); use_pooled(u, itype->rtype, GET_DEFAULT, n); - rsetherbs(r, (short) (rherbs(r) + planted)); + rsetherbs(r, (short)(rherbs(r) + planted)); ADDMSG(&u->faction->msgs, msg_message("plant", "unit region amount herb", u, r, planted, itype->rtype)); } @@ -2241,13 +2245,13 @@ static void planttrees(unit * u, int raw) if (skill < 6) { ADDMSG(&u->faction->msgs, msg_feedback(u, u->thisorder, "plant_skills", - "skill minskill product", SK_HERBALISM, 6, rtype, 1)); + "skill minskill product", SK_HERBALISM, 6, rtype, 1)); return; } if (fval(r, RF_MALLORN) && skill < 7) { ADDMSG(&u->faction->msgs, msg_feedback(u, u->thisorder, "plant_skills", - "skill minskill product", SK_HERBALISM, 7, rtype, 1)); + "skill minskill product", SK_HERBALISM, 7, rtype, 1)); return; } @@ -2284,7 +2288,7 @@ static void breedtrees(unit * u, int raw) int current_season; region *r = u->region; gamedate date; - + get_gamedate(turn, &date); current_season = date.season; @@ -2536,7 +2540,7 @@ static void steal_cmd(unit * u, struct order *ord, request ** stealorders) return; } id = read_unitid(u->faction, r); - if (id>0) { + if (id > 0) { u2 = findunitr(r, id); } if (u2 && u2->region == u->region) { diff --git a/src/guard.c b/src/guard.c index f779e7e2e..326b89bee 100644 --- a/src/guard.c +++ b/src/guard.c @@ -67,28 +67,34 @@ void update_guards(void) unsigned int guard_flags(const unit * u) { + // TODO: this should be a property of the race, like race.guard_flags + static int rc_cache; + static race *rc_elf, *rc_ent, *rc_ironkeeper; + const race *rc = u_race(u); unsigned int flags = GUARD_CREWS | GUARD_LANDING | GUARD_TRAVELTHRU | GUARD_TAX; + // TODO: configuration, not define #if GUARD_DISABLES_PRODUCTION == 1 flags |= GUARD_PRODUCE; #endif #if GUARD_DISABLES_RECRUIT == 1 flags |= GUARD_RECRUIT; #endif - switch (old_race(u_race(u))) { - case RC_ELF: - if (u->faction->race != u_race(u)) - break; - /* else fallthrough */ - case RC_TREEMAN: + if (rc_changed(&rc_cache)) { + rc_elf = get_race(RC_ELF); + rc_ent = get_race(RC_TREEMAN); + rc_ironkeeper = get_race(RC_IRONKEEPER); + } + if (rc == rc_elf) { + if (u->faction->race == u_race(u)) { + flags |= GUARD_TREES; + } + } + else if (rc == rc_ent) { flags |= GUARD_TREES; - break; - case RC_IRONKEEPER: + } + else if (rc == rc_ironkeeper) { flags = GUARD_MINING; - break; - default: - /* TODO: This should be configuration variables, all of it */ - break; } return flags; } diff --git a/src/kernel/race.h b/src/kernel/race.h index 6e8e4bd36..d11dc5fd1 100644 --- a/src/kernel/race.h +++ b/src/kernel/race.h @@ -244,7 +244,7 @@ extern "C" { #define omniscient(f) ((f)->race==get_race(RC_ILLUSION) || (f)->race==get_race(RC_TEMPLATE)) #define playerrace(rc) (!fval((rc), RCF_NPC)) -#define dragonrace(rc) ((rc) == get_race(RC_FIREDRAGON) || (rc) == get_race(RC_DRAGON) || (rc) == get_race(RC_WYRM) || (rc) == get_race(RC_BIRTHDAYDRAGON)) +#define dragonrace(rc) (fval(rc, RCF_DRAGON)) #define humanoidrace(rc) (fval((rc), RCF_UNDEAD) || (rc)==get_race(RC_DRACOID) || playerrace(rc)) #define illusionaryrace(rc) (fval(rc, RCF_ILLUSIONARY)) From aceb8808268611c6445a3896778c51b455089819 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Mon, 19 Sep 2016 18:45:16 +0200 Subject: [PATCH 21/22] add some TODO and reduce old_race usage. --- src/laws.c | 2 +- src/monster.c | 8 ++------ 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/src/laws.c b/src/laws.c index 19078353e..199d9e0a0 100755 --- a/src/laws.c +++ b/src/laws.c @@ -3464,7 +3464,7 @@ static int use_item(unit * u, const item_type * itype, int amount, struct order static double heal_factor(const unit * u) { double elf_regen; - + // TODO: do not hard-code, make this a property, race.healing switch (old_race(u_race(u))) { case RC_TROLL: case RC_DAEMON: diff --git a/src/monster.c b/src/monster.c index 5eafba1ea..37c48f8b5 100644 --- a/src/monster.c +++ b/src/monster.c @@ -83,6 +83,7 @@ static void eaten_by_monster(unit * u) multi = RESOURCE_QUANTITY * newterrain(T_PLAIN)->size / 10000.0; } + // TODO: do not hard-code, make it a race property or callback? it's already RCF_KILLPEASANTS switch (old_race(u_race(u))) { case RC_FIREDRAGON: n = rng_int() % 80 * u->number; @@ -118,12 +119,7 @@ static void eaten_by_monster(unit * u) static void absorbed_by_monster(unit * u) { - int n; - - switch (old_race(u_race(u))) { - default: - n = rng_int() % (u->number / 20 + 1); - } + int n = rng_int() % (u->number / 20 + 1); if (n > 0) { n = lovar(n); From 12239178c6b567fa291e18725bc84568836117e1 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Mon, 19 Sep 2016 20:10:01 +0200 Subject: [PATCH 22/22] rc_find optimizations in monster AI. remove dead alp code. --- src/monsters.c | 125 +++++++++++++------------------------------- src/monsters.test.c | 3 +- src/move.c | 2 +- 3 files changed, 37 insertions(+), 93 deletions(-) diff --git a/src/monsters.c b/src/monsters.c index f5d38a446..78999e015 100644 --- a/src/monsters.c +++ b/src/monsters.c @@ -485,65 +485,6 @@ static order *make_movement_order(unit * u, const region * target, int moves, return parse_order(zOrder, u->faction->locale); } -#ifdef TODO_ALP -static order *monster_seeks_target(region * r, unit * u) -{ - direction_t d; - unit *target = NULL; - int dist, dist2; - direction_t i; - region *nr; - - /* Das Monster sucht ein bestimmtes Opfer. Welches, steht - * in einer Referenz/attribut - * derzeit gibt es nur den alp - */ - - switch (old_race(u_race(u))) { - case RC_ALP: - target = alp_target(u); - break; - default: - assert(!"Seeker-Monster gibt kein Ziel an"); - } - - /* TODO: prüfen, ob target überhaupt noch existiert... */ - if (!target) { - log_error("Monster '%s' hat kein Ziel!\n", unitname(u)); - return NULL; /* this is a bug workaround! remove!! */ - } - - if (r == target->region) { /* Wir haben ihn! */ - if (u_race(u) == get_race(RC_ALP)) { - alp_findet_opfer(u, r); - } else { - assert(!"Seeker-Monster hat keine Aktion fuer Ziel"); - } - return NULL; - } - - /* Simpler Ansatz: Nachbarregion mit gerinster Distanz suchen. - * Sinnvoll momentan nur bei Monstern, die sich nicht um das - * Terrain kümmern. Nebelwände & Co machen derzeit auch nix... - */ - dist2 = distance(r, target->region); - d = NODIRECTION; - for (i = 0; i < MAXDIRECTIONS; i++) { - nr = rconnect(r, i); - assert(nr); - dist = distance(nr, target->region); - if (dist < dist2) { - dist2 = dist; - d = i; - } - } - assert(d != NODIRECTION); - - return create_order(K_MOVE, u->faction->locale, "%s", - LOC(u->faction->locale, directions[d])); -} -#endif - void random_growl(const unit *u, region *target, int rand) { const struct locale *lang = u->faction->locale; @@ -652,6 +593,13 @@ static order *plan_dragon(unit * u) region *tr = NULL; bool move = false; order *long_order = NULL; + static int rc_cache; + static const race *rc_wyrm; + const race * rc = u_race(u); + + if (rc_changed(&rc_cache)) { + rc_wyrm = get_race(RC_WYRM); + } if (ta == NULL) { move |= (rpeasants(r) == 0); /* when no peasants, move */ @@ -659,7 +607,7 @@ static order *plan_dragon(unit * u) } move |= chance(0.04); /* 4% chance to change your mind */ - if (u_race(u) == get_race(RC_WYRM) && !move) { + if (rc == rc_wyrm && !move) { unit *u2; for (u2 = r->units; u2; u2 = u2->next) { /* wyrme sind einzelgänger */ @@ -689,18 +637,21 @@ static order *plan_dragon(unit * u) } if (tr != NULL) { assert(long_order == NULL); - switch (old_race(u_race(u))) { - case RC_FIREDRAGON: - long_order = make_movement_order(u, tr, 4, allowed_dragon); - break; - case RC_DRAGON: - long_order = make_movement_order(u, tr, 3, allowed_dragon); - break; - case RC_WYRM: + // TODO: per-race planning functions? + if (rc == rc_wyrm) { long_order = make_movement_order(u, tr, 1, allowed_dragon); - break; - default: - break; + } + else { + switch (old_race(rc)) { + case RC_FIREDRAGON: + long_order = make_movement_order(u, tr, 4, allowed_dragon); + break; + case RC_DRAGON: + long_order = make_movement_order(u, tr, 3, allowed_dragon); + break; + default: + break; + } } if (long_order) { reduce_weight(u); @@ -752,6 +703,7 @@ void plan_monsters(faction * f) bool attacking = chance(attack_chance); for (u = r->units; u; u = u->next) { + const race *rc = u_race(u); attrib *ta; order *long_order = NULL; @@ -807,7 +759,7 @@ void plan_monsters(faction * f) a_remove(&u->attribs, ta); } } - else if (u_race(u)->flags & RCF_MOVERANDOM) { + else if (rc->flags & RCF_MOVERANDOM) { if (chance(random_move_chance()) || check_overpopulated(u)) { long_order = monster_move(r, u); } @@ -821,31 +773,24 @@ void plan_monsters(faction * f) handle_event(u->attribs, "ai_move", u); } - switch (old_race(u_race(u))) { - case RC_SEASERPENT: - long_order = create_order(K_PIRACY, f->locale, NULL); - break; -#ifdef TODO_ALP - case RC_ALP: - long_order = monster_seeks_target(r, u); - break; -#endif - case RC_FIREDRAGON: - case RC_DRAGON: - case RC_WYRM: + if (fval(rc, RCF_DRAGON)) { long_order = plan_dragon(u); - break; - default: - if (u_race(u)->flags & RCF_LEARN) { - long_order = monster_learn(u); + } + else { + if (rc == get_race(RC_SEASERPENT)) { + long_order = create_order(K_PIRACY, f->locale, NULL); + } + else { + if (rc->flags & RCF_LEARN) { + long_order = monster_learn(u); + } } - break; } } if (long_order == NULL && unit_can_study(u)) { /* Einheiten, die Waffenlosen Kampf lernen könnten, lernen es um * zu bewachen: */ - if (u_race(u)->bonus[SK_WEAPONLESS] != -99) { + if (rc->bonus[SK_WEAPONLESS] != -99) { if (effskill(u, SK_WEAPONLESS, 0) < 1) { long_order = create_order(K_STUDY, f->locale, "'%s'", diff --git a/src/monsters.test.c b/src/monsters.test.c index a44a354d9..6797a9ce0 100644 --- a/src/monsters.test.c +++ b/src/monsters.test.c @@ -54,8 +54,7 @@ static void create_monsters(faction **player, faction **monsters, unit **u, unit *monsters = get_or_create_monsters(); assert(rc_find((*monsters)->race->_name)); rc = rc_get_or_create((*monsters)->race->_name); - fset(rc, RCF_UNARMEDGUARD); - fset(rc, RCF_NPC); + fset(rc, RCF_UNARMEDGUARD|RCF_NPC|RCF_DRAGON); fset(*monsters, FFL_NOIDLEOUT); assert(fval(*monsters, FFL_NPC) && fval((*monsters)->race, RCF_UNARMEDGUARD) && fval((*monsters)->race, RCF_NPC) && fval(*monsters, FFL_NOIDLEOUT)); diff --git a/src/move.c b/src/move.c index a97bc5425..63c79dd6b 100644 --- a/src/move.c +++ b/src/move.c @@ -1473,7 +1473,7 @@ static int movement_speed(unit * u) return BP_DRAGON; } switch (old_race(u_race(u))) { - case RC_BIRTHDAYDRAGON: + case RC_BIRTHDAYDRAGON: // FIXME: catdragon has RCF_DRAGON, so this cannot happen case RC_SONGDRAGON: mp = BP_DRAGON; break;