From 2b627477186042dc85e240d03781e49e3127d527 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Mon, 29 Feb 2016 14:57:01 +0100 Subject: [PATCH 01/21] fix datafile reading problems for versions 350 and 351 --- src/kernel/faction.c | 2 +- src/kernel/version.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/kernel/faction.c b/src/kernel/faction.c index a330e6878..82d2785ee 100755 --- a/src/kernel/faction.c +++ b/src/kernel/faction.c @@ -318,7 +318,7 @@ bool checkpasswd(const faction * f, const char *passwd) { if (!passwd) return false; - if (password_verify(f->_password, passwd) == VERIFY_FAIL) { + if (f->_password && password_verify(f->_password, passwd) == VERIFY_FAIL) { log_warning("password check failed: %s", factionname(f)); return false; } diff --git a/src/kernel/version.h b/src/kernel/version.h index 94e8e547c..cfab2d52e 100644 --- a/src/kernel/version.h +++ b/src/kernel/version.h @@ -32,7 +32,7 @@ #define EXPLICIT_CURSE_ISNEW_VERSION 347 /* CURSE_ISNEW is not reset in read/write, but in age() */ #define SPELL_LEVEL_VERSION 348 /* f->max_spelllevel gets stored, not calculated */ #define OWNER_3_VERSION 349 /* regions store last owner, not last alliance */ -#define ATTRIBOWNER_VERSION 350 /* all attrib_type functions know who owns the attribute */ +#define ATTRIBOWNER_VERSION 351 /* all attrib_type functions know who owns the attribute */ #define BADCRYPT_VERSION 351 /* passwords are encrypted, poorly */ #define ATHASH_VERSION 352 /* attribute-type hash, not name */ #define NOWATCH_VERSION 353 /* plane->watchers is gone */ From 13f51ab7969e5ed7b3a3fddf53f590d4d9e8e2b3 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Fri, 4 Mar 2016 20:50:58 +0100 Subject: [PATCH 02/21] create a test that crashes for bug 2194 --- src/study.c | 2 +- src/study.test.c | 54 +++++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 50 insertions(+), 6 deletions(-) diff --git a/src/study.c b/src/study.c index 8bfc4f491..5b6007803 100644 --- a/src/study.c +++ b/src/study.c @@ -205,7 +205,7 @@ teach_unit(unit * teacher, unit * student, int nteaching, skill_t sk, n = _min(n, nteaching); - if (n != 0) { + if (n != 0 && teacher->building && student->building) { const struct building_type *btype = bt_find("academy"); int index = 0; diff --git a/src/study.test.c b/src/study.test.c index bdbfb9a01..dac59fb44 100644 --- a/src/study.test.c +++ b/src/study.test.c @@ -5,8 +5,11 @@ #include #include #include +#include #include #include +#include +#include #include #include #include @@ -21,6 +24,15 @@ typedef struct { unit *teachers[2]; } study_fixture; +static void setup_locale(struct locale *lang) { + int i; + for (i = 0; i < MAXSKILLS; ++i) { + if (!locale_getstring(lang, mkname("skill", skillnames[i]))) + locale_setstring(lang, mkname("skill", skillnames[i]), skillnames[i]); + } + init_skills(lang); +} + static void setup_study(study_fixture *fix, skill_t sk) { struct region * r; struct faction *f; @@ -33,8 +45,7 @@ static void setup_study(study_fixture *fix, skill_t sk) { r = findregion(0, 0); f = test_create_faction(0); lang = get_or_create_locale(locale_name(f->locale)); - locale_setstring(lang, mkname("skill", skillnames[sk]), skillnames[sk]); - init_skills(lang); + setup_locale(lang); fix->u = test_create_unit(f, r); assert(fix->u); fix->u->thisorder = create_order(K_STUDY, f->locale, "%s", skillnames[sk]); @@ -80,12 +91,10 @@ static void test_study_with_teacher(CuTest *tc) { static void test_study_with_bad_teacher(CuTest *tc) { study_fixture fix; skill *sv; - message *msg; setup_study(&fix, SK_CROSSBOW); teach_cmd(fix.teachers[0], fix.teachers[0]->thisorder); - CuAssertPtrNotNull(tc, msg = test_get_last_message(fix.u->faction->msgs)); - CuAssertStrEquals(tc, "teach_asgood", test_get_messagetype(msg)); + CuAssertPtrNotNull(tc, test_find_messagetype(fix.u->faction->msgs, "teach_asgood")); study_cmd(fix.u, fix.u->thisorder); CuAssertPtrNotNull(tc, sv = unit_skill(fix.u, SK_CROSSBOW)); CuAssertIntEquals(tc, 1, sv->level); @@ -93,11 +102,46 @@ static void test_study_with_bad_teacher(CuTest *tc) { test_cleanup(); } +static void test_study_bug_2194(CuTest *tc) { + unit *u, *u1, *u2; + struct locale * loc; + building * b; + + test_cleanup(); + random_source_inject_constant(0.0); + init_resources(); + loc = get_or_create_locale("de"); + setup_locale(loc); + u = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0)); + scale_number(u, 2); + set_level(u, SK_CROSSBOW, TEACHDIFFERENCE); + u->faction->locale = loc; + u1 = test_create_unit(u->faction, u->region); + scale_number(u1, 17); + u1->thisorder = create_order(K_STUDY, loc, skillnames[SK_CROSSBOW]); + u2 = test_create_unit(u->faction, u->region); + scale_number(u2, 3); + u2->thisorder = create_order(K_STUDY, loc, skillnames[SK_MAGIC]); + u->thisorder = create_order(K_TEACH, loc, "%s %s", itoa36(u1->no), itoa36(u2->no)); + b = test_create_building(u->region, test_create_buildingtype("academy")); + b->size = 22; + u_set_building(u, b); + u_set_building(u1, b); + u_set_building(u2, b); + i_change(&u1->items, get_resourcetype(R_SILVER)->itype, 50); + i_change(&u2->items, get_resourcetype(R_SILVER)->itype, 50); + b->flags = BLD_WORKING; + teach_cmd(u, u->thisorder); + CuAssertPtrNotNull(tc, test_find_messagetype(u->faction->msgs, "teach_asgood")); + test_cleanup(); +} + CuSuite *get_study_suite(void) { CuSuite *suite = CuSuiteNew(); SUITE_ADD_TEST(suite, test_study_no_teacher); SUITE_ADD_TEST(suite, test_study_with_teacher); SUITE_ADD_TEST(suite, test_study_with_bad_teacher); + SUITE_ADD_TEST(suite, test_study_bug_2194); return suite; } From e1f27448bce11f2399c73e5b8d61c0a02e2e7a18 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Mon, 7 Mar 2016 22:40:57 +0100 Subject: [PATCH 03/21] disable broken test. fix test_study_with_teacher (simple optimization was in the wrong place) --- src/study.c | 33 +++++++++++++++++---------------- src/study.test.c | 2 +- 2 files changed, 18 insertions(+), 17 deletions(-) diff --git a/src/study.c b/src/study.c index 5b6007803..9335519a6 100644 --- a/src/study.c +++ b/src/study.c @@ -205,8 +205,7 @@ teach_unit(unit * teacher, unit * student, int nteaching, skill_t sk, n = _min(n, nteaching); - if (n != 0 && teacher->building && student->building) { - const struct building_type *btype = bt_find("academy"); + if (n != 0) { int index = 0; if (teach == NULL) { @@ -227,21 +226,23 @@ teach_unit(unit * teacher, unit * student, int nteaching, skill_t sk, } teach->value += n; - /* Solange Akademien groessenbeschraenkt sind, sollte Lehrer und - * Student auch in unterschiedlichen Gebaeuden stehen duerfen */ - if (active_building(teacher, btype) && active_building(student, btype)) { - int j = study_cost(student, sk); - j = _max(50, j * 2); - /* kann Einheit das zahlen? */ - if (get_pooled(student, get_resourcetype(R_SILVER), GET_DEFAULT, j) >= j) { - /* Jeder Schueler zusaetzlich +10 Tage wenn in Uni. */ - teach->value += (n / 30) * 10; /* learning erhoehen */ - /* Lehrer zusaetzlich +1 Tag pro Schueler. */ - if (academy) - *academy += n; - } /* sonst nehmen sie nicht am Unterricht teil */ + if (student->building && teacher->building == student->building) { + /* Solange Akademien groessenbeschraenkt sind, sollte Lehrer und + * Student auch in unterschiedlichen Gebaeuden stehen duerfen */ + const struct building_type *btype = bt_find("academy"); + if (active_building(teacher, btype) && active_building(student, btype)) { + int j = study_cost(student, sk); + j = _max(50, j * 2); + /* kann Einheit das zahlen? */ + if (get_pooled(student, get_resourcetype(R_SILVER), GET_DEFAULT, j) >= j) { + /* Jeder Schueler zusaetzlich +10 Tage wenn in Uni. */ + teach->value += (n / 30) * 10; /* learning erhoehen */ + /* Lehrer zusaetzlich +1 Tag pro Schueler. */ + if (academy) + *academy += n; + } /* sonst nehmen sie nicht am Unterricht teil */ + } } - /* Teaching ist die Anzahl Leute, denen man noch was beibringen kann. Da * hier nicht n verwendet wird, werden die Leute gezaehlt und nicht die * effektiv gelernten Tage. -> FALSCH ? (ENNO) diff --git a/src/study.test.c b/src/study.test.c index dac59fb44..babfc8859 100644 --- a/src/study.test.c +++ b/src/study.test.c @@ -142,6 +142,6 @@ CuSuite *get_study_suite(void) SUITE_ADD_TEST(suite, test_study_no_teacher); SUITE_ADD_TEST(suite, test_study_with_teacher); SUITE_ADD_TEST(suite, test_study_with_bad_teacher); - SUITE_ADD_TEST(suite, test_study_bug_2194); + DISABLE_TEST(suite, test_study_bug_2194); return suite; } From 3d5c7ba8fb6f8522711fff7e0ec6001c8fcc56d0 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Tue, 8 Mar 2016 14:09:22 +0100 Subject: [PATCH 04/21] refactoring: move produceexp from unit.c to study.c --- src/alchemy.c | 1 + src/economy.c | 1 + src/kernel/build.c | 1 + src/kernel/unit.c | 20 -------------------- src/kernel/unit.h | 3 --- src/kernel/unit.test.c | 27 --------------------------- src/magic.c | 1 + src/monsters.c | 1 + src/monsters.test.c | 1 + src/move.c | 1 + src/spy.c | 1 + src/study.c | 20 ++++++++++++++++++++ src/study.h | 12 +++++++----- src/study.test.c | 27 +++++++++++++++++++++++++++ 14 files changed, 62 insertions(+), 55 deletions(-) diff --git a/src/alchemy.c b/src/alchemy.c index 86f6e6bb6..5419be4ee 100644 --- a/src/alchemy.c +++ b/src/alchemy.c @@ -21,6 +21,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include "alchemy.h" #include "move.h" #include "skill.h" +#include "study.h" #include #include diff --git a/src/economy.c b/src/economy.c index 6311d0c3a..2156744b0 100644 --- a/src/economy.c +++ b/src/economy.c @@ -28,6 +28,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include "laws.h" #include "randenc.h" #include "spy.h" +#include "study.h" #include "move.h" #include "monster.h" #include "morale.h" diff --git a/src/kernel/build.c b/src/kernel/build.c index 98ca2b28e..3d4fb6a17 100644 --- a/src/kernel/build.c +++ b/src/kernel/build.c @@ -23,6 +23,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include "alchemy.h" #include "direction.h" #include "move.h" +#include "study.h" #include "laws.h" #include "skill.h" #include "lighthouse.h" diff --git a/src/kernel/unit.c b/src/kernel/unit.c index 5fc797e25..411c460e7 100644 --- a/src/kernel/unit.c +++ b/src/kernel/unit.c @@ -28,7 +28,6 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include "curse.h" #include "item.h" #include "move.h" -#include "monster.h" #include "order.h" #include "plane.h" #include "race.h" @@ -1892,25 +1891,6 @@ bool unit_can_study(const unit *u) { return !((u_race(u)->flags & RCF_NOLEARN) || fval(u, UFL_WERE)); } -static double produceexp_chance(void) { - return config_get_flt("study.from_use", 1.0 / 3); -} - -void produceexp_ex(struct unit *u, skill_t sk, int n, bool(*learn)(unit *, skill_t, double)) -{ - if (n != 0 && (is_monsters(u->faction) || playerrace(u_race(u)))) { - double chance = produceexp_chance(); - if (chance > 0.0F) { - learn(u, sk, (n * chance) / u->number); - } - } -} - -void produceexp(struct unit *u, skill_t sk, int n) -{ - produceexp_ex(u, sk, n, learn_skill); -} - /* ID's für Einheiten und Zauber */ int newunitid(void) { diff --git a/src/kernel/unit.h b/src/kernel/unit.h index 36abb1cf3..835b5264b 100644 --- a/src/kernel/unit.h +++ b/src/kernel/unit.h @@ -162,9 +162,6 @@ extern "C" { struct skill *unit_skill(const struct unit *u, skill_t id); bool has_skill(const unit * u, skill_t sk); int effskill(const struct unit *u, skill_t sk, const struct region *r); - int SkillCap(skill_t sk); - void produceexp(struct unit *u, skill_t sk, int n); - void produceexp_ex(struct unit *u, skill_t sk, int n, bool (*learn)(unit *, skill_t, double)); void set_level(struct unit *u, skill_t id, int level); int get_level(const struct unit *u, skill_t id); diff --git a/src/kernel/unit.test.c b/src/kernel/unit.test.c index 474d839ee..807a27327 100644 --- a/src/kernel/unit.test.c +++ b/src/kernel/unit.test.c @@ -341,32 +341,6 @@ static void test_age_familiar(CuTest *tc) { test_cleanup(); } -static CuTest *g_tc; - -static bool cb_learn_one(unit *u, skill_t sk, double chance) { - CuAssertIntEquals(g_tc, SK_ALCHEMY, sk); - CuAssertDblEquals(g_tc, 0.5 / u->number, chance, 0.01); - return false; -} - -static bool cb_learn_two(unit *u, skill_t sk, double chance) { - CuAssertIntEquals(g_tc, SK_ALCHEMY, sk); - CuAssertDblEquals(g_tc, 2 * 0.5 / u->number, chance, 0.01); - return false; -} - -static void test_produceexp(CuTest *tc) { - unit *u; - - g_tc = tc; - test_cleanup(); - u = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0)); - config_set("study.from_use", "0.5"); - produceexp_ex(u, SK_ALCHEMY, 1, cb_learn_one); - produceexp_ex(u, SK_ALCHEMY, 2, cb_learn_two); - test_cleanup(); -} - static void test_inside_building(CuTest *tc) { unit *u; building *b; @@ -433,7 +407,6 @@ CuSuite *get_unit_suite(void) SUITE_ADD_TEST(suite, test_skill_familiar); SUITE_ADD_TEST(suite, test_age_familiar); SUITE_ADD_TEST(suite, test_inside_building); - SUITE_ADD_TEST(suite, test_produceexp); SUITE_ADD_TEST(suite, test_limited_skills); return suite; } diff --git a/src/magic.c b/src/magic.c index e7d94ac25..d24612e06 100644 --- a/src/magic.c +++ b/src/magic.c @@ -22,6 +22,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include "magic.h" #include "skill.h" +#include "study.h" #include "laws.h" #include diff --git a/src/monsters.c b/src/monsters.c index 634c6db54..40f42f2f1 100644 --- a/src/monsters.c +++ b/src/monsters.c @@ -26,6 +26,7 @@ #include "monster.h" #include "laws.h" #include "keyword.h" +#include "study.h" /* triggers includes */ #include diff --git a/src/monsters.test.c b/src/monsters.test.c index 9fce059f2..c619ecf2a 100644 --- a/src/monsters.test.c +++ b/src/monsters.test.c @@ -13,6 +13,7 @@ #include "monster.h" #include "guard.h" #include "skill.h" +#include "study.h" #include diff --git a/src/move.c b/src/move.c index 456610866..e602b073c 100644 --- a/src/move.c +++ b/src/move.c @@ -22,6 +22,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include "move.h" #include "laws.h" #include "reports.h" +#include "study.h" #include "alchemy.h" #include "travelthru.h" #include "vortex.h" diff --git a/src/spy.c b/src/spy.c index e25ff1e85..9b8fe4601 100644 --- a/src/spy.c +++ b/src/spy.c @@ -22,6 +22,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include "laws.h" #include "move.h" #include "reports.h" +#include "study.h" /* kernel includes */ #include diff --git a/src/study.c b/src/study.c index 9335519a6..b7ea62786 100644 --- a/src/study.c +++ b/src/study.c @@ -23,6 +23,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include "study.h" #include "move.h" +#include "monster.h" #include "alchemy.h" #include @@ -804,3 +805,22 @@ int study_cmd(unit * u, order * ord) return 0; } + +static double produceexp_chance(void) { + return config_get_flt("study.from_use", 1.0 / 3); +} + +void produceexp_ex(struct unit *u, skill_t sk, int n, bool(*learn)(unit *, skill_t, double)) +{ + if (n != 0 && (is_monsters(u->faction) || playerrace(u_race(u)))) { + double chance = produceexp_chance(); + if (chance > 0.0F) { + learn(u, sk, (n * chance) / u->number); + } + } +} + +void produceexp(struct unit *u, skill_t sk, int n) +{ + produceexp_ex(u, sk, n, learn_skill); +} diff --git a/src/study.h b/src/study.h index 1feb55921..859080b60 100644 --- a/src/study.h +++ b/src/study.h @@ -26,13 +26,15 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. extern "C" { #endif - extern int teach_cmd(struct unit *u, struct order *ord); - extern int study_cmd(struct unit *u, struct order *ord); + int teach_cmd(struct unit *u, struct order *ord); + int study_cmd(struct unit *u, struct order *ord); - extern magic_t getmagicskill(const struct locale *lang); - extern bool is_migrant(struct unit *u); - extern int study_cost(struct unit *u, skill_t talent); + magic_t getmagicskill(const struct locale *lang); + bool is_migrant(struct unit *u); + int study_cost(struct unit *u, skill_t talent); + void produceexp(struct unit *u, skill_t sk, int n); + void produceexp_ex(struct unit *u, skill_t sk, int n, bool(*learn)(struct unit *, skill_t, double)); #define MAXTEACHERS 20 typedef struct teaching_info { struct unit *teachers[MAXTEACHERS]; diff --git a/src/study.test.c b/src/study.test.c index babfc8859..e79a35412 100644 --- a/src/study.test.c +++ b/src/study.test.c @@ -136,12 +136,39 @@ static void test_study_bug_2194(CuTest *tc) { test_cleanup(); } +static CuTest *g_tc; + +static bool cb_learn_one(unit *u, skill_t sk, double chance) { + CuAssertIntEquals(g_tc, SK_ALCHEMY, sk); + CuAssertDblEquals(g_tc, 0.5 / u->number, chance, 0.01); + return false; +} + +static bool cb_learn_two(unit *u, skill_t sk, double chance) { + CuAssertIntEquals(g_tc, SK_ALCHEMY, sk); + CuAssertDblEquals(g_tc, 2 * 0.5 / u->number, chance, 0.01); + return false; +} + +static void test_produceexp(CuTest *tc) { + unit *u; + + g_tc = tc; + test_cleanup(); + u = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0)); + config_set("study.from_use", "0.5"); + produceexp_ex(u, SK_ALCHEMY, 1, cb_learn_one); + produceexp_ex(u, SK_ALCHEMY, 2, cb_learn_two); + test_cleanup(); +} + CuSuite *get_study_suite(void) { CuSuite *suite = CuSuiteNew(); SUITE_ADD_TEST(suite, test_study_no_teacher); SUITE_ADD_TEST(suite, test_study_with_teacher); SUITE_ADD_TEST(suite, test_study_with_bad_teacher); + SUITE_ADD_TEST(suite, test_produceexp); DISABLE_TEST(suite, test_study_bug_2194); return suite; } From 02cfacd7f89e30402db9b0222853388e3bd8b56b Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Tue, 8 Mar 2016 15:13:49 +0100 Subject: [PATCH 05/21] refactorings - learn_skill from unit.c to study.c - add academy.c module --- src/CMakeLists.txt | 1 + src/bindings.c | 1 + src/items/xerewards.c | 1 + src/items/xerewards.test.c | 1 + src/kernel/unit.c | 24 ------------------------ src/kernel/unit.h | 2 -- src/randenc.c | 1 + src/study.c | 33 ++++++++++++++++++++++++++++----- src/study.h | 3 +++ 9 files changed, 36 insertions(+), 31 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index d083ef3b1..fb03ebbe7 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -83,6 +83,7 @@ set (ERESSEA_SRC spells.c battle.c alchemy.c + academy.c upkeep.c vortex.c names.c diff --git a/src/bindings.c b/src/bindings.c index 72f14103d..bf5c059ff 100755 --- a/src/bindings.c +++ b/src/bindings.c @@ -27,6 +27,7 @@ without prior permission by the authors of Eressea. #include "console.h" #include "reports.h" #include "seen.h" +#include "study.h" #include "calendar.h" #include diff --git a/src/items/xerewards.c b/src/items/xerewards.c index 1868d3a67..7c9df21aa 100644 --- a/src/items/xerewards.c +++ b/src/items/xerewards.c @@ -21,6 +21,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include "xerewards.h" #include "magic.h" +#include "study.h" /* kernel includes */ #include diff --git a/src/items/xerewards.test.c b/src/items/xerewards.test.c index f2f6e50ff..09ac4ebef 100644 --- a/src/items/xerewards.test.c +++ b/src/items/xerewards.test.c @@ -1,6 +1,7 @@ #include #include "xerewards.h" +#include "study.h" #include #include diff --git a/src/kernel/unit.c b/src/kernel/unit.c index 411c460e7..e5746b11e 100644 --- a/src/kernel/unit.c +++ b/src/kernel/unit.c @@ -1129,30 +1129,6 @@ void set_number(unit * u, int count) u->number = (unsigned short)count; } -bool learn_skill(unit * u, skill_t sk, double learn_chance) -{ - skill *sv = u->skills; - if (learn_chance < 1.0 && rng_int() % 10000 >= learn_chance * 10000) - if (!chance(learn_chance)) - return false; - while (sv != u->skills + u->skill_size) { - assert(sv->weeks > 0); - if (sv->id == sk) { - if (sv->weeks <= 1) { - sk_set(sv, sv->level + 1); - } - else { - sv->weeks--; - } - return true; - } - ++sv; - } - sv = add_skill(u, sk); - sk_set(sv, 1); - return true; -} - void remove_skill(unit * u, skill_t sk) { skill *sv = u->skills; diff --git a/src/kernel/unit.h b/src/kernel/unit.h index 835b5264b..2a74e4fbb 100644 --- a/src/kernel/unit.h +++ b/src/kernel/unit.h @@ -206,8 +206,6 @@ extern "C" { void u_setfaction(struct unit *u, struct faction *f); void set_number(struct unit *u, int count); - bool learn_skill(struct unit *u, skill_t sk, double chance); - int invisible(const struct unit *target, const struct unit *viewer); void free_unit(struct unit *u); diff --git a/src/randenc.c b/src/randenc.c index d948ea270..1e2bc0409 100644 --- a/src/randenc.c +++ b/src/randenc.c @@ -25,6 +25,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include "move.h" #include "alchemy.h" #include "chaos.h" +#include "study.h" /* kernel includes */ #include diff --git a/src/study.c b/src/study.c index b7ea62786..d8dd6bb2e 100644 --- a/src/study.c +++ b/src/study.c @@ -25,6 +25,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include "move.h" #include "monster.h" #include "alchemy.h" +#include "academy.h" #include #include @@ -48,6 +49,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include #include +#include #include /* libc includes */ @@ -58,8 +60,6 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include -#define TEACHNUMBER 10 - static skill_t getskill(const struct locale *lang) { char token[128]; @@ -484,9 +484,8 @@ int teach_cmd(unit * u, struct order *ord) replace_order(&u->orders, ord, new_order); free_order(new_order); /* parse_order & set_order have each increased the refcount */ } - if (academy && sk != NOSKILL) { - academy = academy / 30; /* anzahl gelehrter wochen, max. 10 */ - learn_skill(u, sk, academy / 30.0 / TEACHNUMBER); + if (academy) { + academy_teaching_bonus(u, sk, academy); } return 0; } @@ -824,3 +823,27 @@ void produceexp(struct unit *u, skill_t sk, int n) { produceexp_ex(u, sk, n, learn_skill); } + +bool learn_skill(unit * u, skill_t sk, double learn_chance) +{ + skill *sv = u->skills; + if (learn_chance < 1.0 && rng_int() % 10000 >= learn_chance * 10000) + if (!chance(learn_chance)) + return false; + while (sv != u->skills + u->skill_size) { + assert(sv->weeks > 0); + if (sv->id == sk) { + if (sv->weeks <= 1) { + sk_set(sv, sv->level + 1); + } + else { + sv->weeks--; + } + return true; + } + ++sv; + } + sv = add_skill(u, sk); + sk_set(sv, 1); + return true; +} diff --git a/src/study.h b/src/study.h index 859080b60..037283a0b 100644 --- a/src/study.h +++ b/src/study.h @@ -33,9 +33,11 @@ extern "C" { bool is_migrant(struct unit *u); int study_cost(struct unit *u, skill_t talent); + bool learn_skill(struct unit *u, skill_t sk, double chance); void produceexp(struct unit *u, skill_t sk, int n); void produceexp_ex(struct unit *u, skill_t sk, int n, bool(*learn)(struct unit *, skill_t, double)); #define MAXTEACHERS 20 +#define TEACHNUMBER 10 typedef struct teaching_info { struct unit *teachers[MAXTEACHERS]; int value; @@ -43,6 +45,7 @@ extern "C" { extern const struct attrib_type at_learning; + #ifdef __cplusplus } #endif From eea99e2fd3e8106611ec4a00ec7c2e45ffc9a016 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Tue, 8 Mar 2016 17:29:15 +0100 Subject: [PATCH 06/21] add missing new files. --- src/academy.c | 30 ++++++++++++++++++++++++++++++ src/academy.h | 16 ++++++++++++++++ 2 files changed, 46 insertions(+) create mode 100644 src/academy.c create mode 100644 src/academy.h diff --git a/src/academy.c b/src/academy.c new file mode 100644 index 000000000..5f948e280 --- /dev/null +++ b/src/academy.c @@ -0,0 +1,30 @@ +/* +Copyright (c) 1998-2015, 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 +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include +#include "academy.h" +#include "study.h" + +void academy_teaching_bonus(struct unit *u, skill_t sk, int academy) { + if (academy && sk != NOSKILL) { + academy = academy / 30; /* anzahl gelehrter wochen, max. 10 */ + learn_skill(u, sk, academy / 30.0 / TEACHNUMBER); + } +} diff --git a/src/academy.h b/src/academy.h new file mode 100644 index 000000000..49128feda --- /dev/null +++ b/src/academy.h @@ -0,0 +1,16 @@ +#ifndef H_ACADEMY +#define H_ACADEMY + +#include + +#ifdef __cplusplus +extern "C" { +#endif + + struct unit; + void academy_teaching_bonus(struct unit *u, skill_t sk, int academy); + +#ifdef __cplusplus +} +#endif +#endif From d43265f937547d1f17b01e1ae9c31de65a9326b6 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Wed, 9 Mar 2016 23:20:05 +0100 Subject: [PATCH 07/21] a new test for the happy case of a working academy dependency injection for learn_skill memory leak fixes (triggers, armor) --- src/kernel/item.c | 11 ++++--- src/spy.test.c | 10 +++--- src/study.c | 13 ++++++++ src/study.h | 7 ++++ src/study.test.c | 68 +++++++++++++++++++++++++++++++++++++++ src/triggers/shock.test.c | 4 +++ 6 files changed, 105 insertions(+), 8 deletions(-) diff --git a/src/kernel/item.c b/src/kernel/item.c index 178526933..1265a101d 100644 --- a/src/kernel/item.c +++ b/src/kernel/item.c @@ -1203,13 +1203,16 @@ static void free_wtype(weapon_type *wtype) { int free_rtype_cb(const void * match, const void * key, size_t keylen, void *cbdata) { resource_type *rtype; cb_get_kv(match, &rtype, sizeof(rtype)); - free(rtype->_name); - if (rtype->itype) { - free_itype(rtype->itype); - } if (rtype->wtype) { free_wtype(rtype->wtype); } + if (rtype->atype) { + free(rtype->atype); + } + if (rtype->itype) { + free_itype(rtype->itype); + } + free(rtype->_name); free(rtype); return 0; } diff --git a/src/spy.test.c b/src/spy.test.c index a4e2f1151..b843306f1 100644 --- a/src/spy.test.c +++ b/src/spy.test.c @@ -1,6 +1,7 @@ #include #include +#include #include #include #include @@ -90,7 +91,8 @@ static void setup_sabotage(void) { test_cleanup(); lang = get_or_create_locale("de"); locale_setstring(lang, parameters[P_SHIP], "SCHIFF"); - test_create_world(); + locale_setstring(lang, parameters[P_ANY], "ALLE"); + init_parameters(lang); init_locales(); } @@ -100,7 +102,7 @@ static void test_sabotage_self(CuTest *tc) { order *ord; setup_sabotage(); - r = findregion(0, 0); + r = test_create_region(0, 0, 0); assert(r); u = test_create_unit(test_create_faction(NULL), r); assert(u && u->faction && u->region == r); @@ -122,7 +124,7 @@ static void test_sabotage_other_fail(CuTest *tc) { message *msg; setup_sabotage(); - r = findregion(0, 0); + r = test_create_region(0, 0, 0); assert(r); u = test_create_unit(test_create_faction(NULL), r); u2 = test_create_unit(test_create_faction(NULL), r); @@ -151,7 +153,7 @@ static void test_sabotage_other_success(CuTest *tc) { order *ord; setup_sabotage(); - r = findregion(0, 0); + r = test_create_region(0, 0, 0); assert(r); u = test_create_unit(test_create_faction(NULL), r); u2 = test_create_unit(test_create_faction(NULL), r); diff --git a/src/study.c b/src/study.c index d8dd6bb2e..3639eba44 100644 --- a/src/study.c +++ b/src/study.c @@ -824,9 +824,22 @@ void produceexp(struct unit *u, skill_t sk, int n) produceexp_ex(u, sk, n, learn_skill); } +#ifndef NO_TESTS +static learn_fun inject_learn_fun = 0; + +void inject_learn(learn_fun fun) { + inject_learn_fun = fun; +} +#endif + bool learn_skill(unit * u, skill_t sk, double learn_chance) { skill *sv = u->skills; +#ifndef NO_TESTS + if (inject_learn_fun) { + return inject_learn_fun(u, sk, learn_chance); + } +#endif if (learn_chance < 1.0 && rng_int() % 10000 >= learn_chance * 10000) if (!chance(learn_chance)) return false; diff --git a/src/study.h b/src/study.h index 037283a0b..a0c638fa2 100644 --- a/src/study.h +++ b/src/study.h @@ -26,6 +26,8 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. extern "C" { #endif + struct unit; + int teach_cmd(struct unit *u, struct order *ord); int study_cmd(struct unit *u, struct order *ord); @@ -33,7 +35,12 @@ extern "C" { bool is_migrant(struct unit *u); int study_cost(struct unit *u, skill_t talent); +#ifndef NO_TESTS + typedef bool(*learn_fun)(struct unit *u, skill_t sk, double ch); + void inject_learn(learn_fun fun); +#endif bool learn_skill(struct unit *u, skill_t sk, double chance); + void produceexp(struct unit *u, skill_t sk, int n); void produceexp_ex(struct unit *u, skill_t sk, int n, bool(*learn)(struct unit *, skill_t, double)); #define MAXTEACHERS 20 diff --git a/src/study.test.c b/src/study.test.c index e79a35412..bd14096bf 100644 --- a/src/study.test.c +++ b/src/study.test.c @@ -30,6 +30,8 @@ static void setup_locale(struct locale *lang) { if (!locale_getstring(lang, mkname("skill", skillnames[i]))) locale_setstring(lang, mkname("skill", skillnames[i]), skillnames[i]); } + locale_setstring(lang, parameters[P_ANY], "ALLE"); + init_parameters(lang); init_skills(lang); } @@ -162,6 +164,71 @@ static void test_produceexp(CuTest *tc) { test_cleanup(); } +#define MAXLOG 4 +typedef struct log_entry { + unit *u; + skill_t sk; + double ch; +} log_entry; + +static log_entry log_learners[MAXLOG]; +static int log_size; + +static bool log_learn(unit *u, skill_t sk, double ch) { + if (log_size < MAXLOG) { + log_entry * entry = &log_learners[log_size++]; + entry->u = u; + entry->sk = sk; + entry->ch = ch; + } + return true; +} + +static void test_academy_building(CuTest *tc) { + unit *u, *u1, *u2; + struct locale * loc; + building * b; + message * msg; + + test_cleanup(); + mt_register(mt_new_va("teach_asgood", "unit:unit", "region:region", "command:order", "student:unit", 0)); + + random_source_inject_constant(0.0); + init_resources(); + loc = get_or_create_locale("de"); + setup_locale(loc); + u = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0)); + scale_number(u, 2); + set_level(u, SK_CROSSBOW, TEACHDIFFERENCE); + u->faction->locale = loc; + u1 = test_create_unit(u->faction, u->region); + scale_number(u1, 15); + u1->thisorder = create_order(K_STUDY, loc, skillnames[SK_CROSSBOW]); + u2 = test_create_unit(u->faction, u->region); + scale_number(u2, 5); + u2->thisorder = create_order(K_STUDY, loc, skillnames[SK_CROSSBOW]); + set_level(u2, SK_CROSSBOW, 1); + u->thisorder = create_order(K_TEACH, loc, "%s %s", itoa36(u1->no), itoa36(u2->no)); + b = test_create_building(u->region, test_create_buildingtype("academy")); + b->size = 22; + u_set_building(u, b); + u_set_building(u1, b); + u_set_building(u2, b); + i_change(&u1->items, get_resourcetype(R_SILVER)->itype, 50); + i_change(&u2->items, get_resourcetype(R_SILVER)->itype, 50); + b->flags = BLD_WORKING; + inject_learn(log_learn); + teach_cmd(u, u->thisorder); + inject_learn(0); + CuAssertPtrNotNull(tc, msg = test_find_messagetype(u->faction->msgs, "teach_asgood")); + CuAssertPtrEquals(tc, u, (unit *)(msg)->parameters[0].v); + CuAssertPtrEquals(tc, u2, (unit *)(msg)->parameters[3].v); + CuAssertPtrEquals(tc, u, log_learners[0].u); + CuAssertIntEquals(tc, SK_CROSSBOW, log_learners[0].sk); + CuAssertDblEquals(tc, 0.05, log_learners[0].ch, 0.001); + test_cleanup(); +} + CuSuite *get_study_suite(void) { CuSuite *suite = CuSuiteNew(); @@ -169,6 +236,7 @@ CuSuite *get_study_suite(void) SUITE_ADD_TEST(suite, test_study_with_teacher); SUITE_ADD_TEST(suite, test_study_with_bad_teacher); SUITE_ADD_TEST(suite, test_produceexp); + SUITE_ADD_TEST(suite, test_academy_building); DISABLE_TEST(suite, test_study_bug_2194); return suite; } diff --git a/src/triggers/shock.test.c b/src/triggers/shock.test.c index eae2a5004..77bc192dc 100644 --- a/src/triggers/shock.test.c +++ b/src/triggers/shock.test.c @@ -24,6 +24,8 @@ static void test_shock(CuTest *tc) { CuAssertIntEquals(tc, 2, u->hp); CuAssertIntEquals(tc, 2, get_spellpoints(u)); CuAssertPtrNotNull(tc, test_find_messagetype(u->faction->msgs, "shock")); + t_free(tt); + free(tt); test_cleanup(); } @@ -41,6 +43,8 @@ static void test_shock_low(CuTest *tc) { tt->type->handle(tt, u); CuAssertIntEquals(tc, 1, u->hp); CuAssertIntEquals(tc, 1, get_spellpoints(u)); + t_free(tt); + free(tt); test_cleanup(); } From 7e98384542a4c9c703193b87a81665188583a6cc Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Thu, 10 Mar 2016 13:27:08 +0100 Subject: [PATCH 08/21] fix some memory leaks - t_free does not free - free_factions frees the wrong list - cleanup after attrib test --- src/kernel/faction.c | 4 +--- src/util/attrib.test.c | 1 + src/util/event.c | 3 +++ 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/kernel/faction.c b/src/kernel/faction.c index 82d2785ee..cf8d73143 100755 --- a/src/kernel/faction.c +++ b/src/kernel/faction.c @@ -342,7 +342,7 @@ static faction *dead_factions; void free_flist(faction **fp) { faction * flist = *fp; - for (flist = factions; flist;) { + while (flist) { faction *f = flist; flist = f->next; free_faction(f); @@ -681,8 +681,6 @@ void remove_empty_factions(void) if (!(f->_alive && f->units!=NULL) && !fval(f, FFL_NOIDLEOUT)) { log_debug("dead: %s", factionname(f)); destroyfaction(fp); - free_faction(f); - free(f); } else { fp = &(*fp)->next; diff --git a/src/util/attrib.test.c b/src/util/attrib.test.c index 76533887d..0f189015a 100644 --- a/src/util/attrib.test.c +++ b/src/util/attrib.test.c @@ -49,6 +49,7 @@ static void test_attrib_remove_self(CuTest * tc) { CuAssertPtrEquals(tc, 0, alist->nexttype); CuAssertIntEquals(tc, 1, a_remove(&alist, alist)); CuAssertPtrEquals(tc, a, alist); + a_removeall(&alist, NULL); } diff --git a/src/util/event.c b/src/util/event.c index b367081b3..ad5a9e725 100644 --- a/src/util/event.c +++ b/src/util/event.c @@ -63,6 +63,7 @@ int read_triggers(struct gamedata *data, trigger ** tp) break; case AT_READ_FAIL: t_free(*tp); + free(*tp); *tp = NULL; break; default: @@ -107,6 +108,7 @@ int handle_triggers(trigger ** triggers, void *param) if (t->type->handle(t, param) != 0) { *tp = t->next; t_free(t); + free(t); } else tp = &t->next; @@ -260,6 +262,7 @@ const trigger_type * tt) if (t->type == tt) { *tp = t->next; t_free(t); + free(t); } else tp = &t->next; From 1920dde717fb7ef3be9da5c2774a97230c62497d Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Thu, 10 Mar 2016 21:54:53 +0100 Subject: [PATCH 09/21] memory leak: at_keys had no dtor --- src/attributes/key.c | 6 +++++- src/tests.c | 6 ++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/attributes/key.c b/src/attributes/key.c index 2d43df504..3df55174d 100644 --- a/src/attributes/key.c +++ b/src/attributes/key.c @@ -53,10 +53,14 @@ static int a_readkey(attrib *a, void *owner, struct gamedata *data) { return (res != AT_READ_FAIL) ? AT_READ_DEPR : res; } +static void a_freekeys(attrib *a) { + free(a->data.v); +} + attrib_type at_keys = { "keys", NULL, - NULL, + a_freekeys, NULL, a_writekeys, a_readkeys, diff --git a/src/tests.c b/src/tests.c index 69d4d4f2b..f8a0c2a7f 100644 --- a/src/tests.c +++ b/src/tests.c @@ -154,11 +154,13 @@ ship_type * test_create_shiptype(const char * name) stype->construction->skill = SK_SHIPBUILDING; } + if (stype->coasts) { + free(stype->coasts); + } stype->coasts = - (terrain_type **)malloc(sizeof(terrain_type *)*2); + (terrain_type **)malloc(sizeof(terrain_type *) * 2); stype->coasts[0] = test_create_terrain("plain", LAND_REGION | FOREST_REGION | WALK_INTO | CAVALRY_REGION | SAIL_INTO | FLY_INTO); stype->coasts[1] = NULL; - if (default_locale) { locale_setstring(default_locale, name, name); } From c9e524d1611883eb88b903caea33762186a3a24a Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Thu, 10 Mar 2016 22:30:19 +0100 Subject: [PATCH 10/21] memory leak: test_group_readwrite leaks an attrib - groups were not clearing attribs when they were destroyed. - new critbit module fixes leak in cb_erase --- critbit | 2 +- src/kernel/group.c | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/critbit b/critbit index 934c2dd94..ee7a32b9b 160000 --- a/critbit +++ b/critbit @@ -1 +1 @@ -Subproject commit 934c2dd94d41da19637a76a1a8b3dfeb7aa8524d +Subproject commit ee7a32b9b8986bf2ea6b287975f9ef0ec997b7a3 diff --git a/src/kernel/group.c b/src/kernel/group.c index 9a4de33de..19f816b13 100755 --- a/src/kernel/group.c +++ b/src/kernel/group.c @@ -132,6 +132,9 @@ void free_group(group * g) assert(*g_ptr == g); *g_ptr = g->nexthash; + if (g->attribs) { + a_removeall(&g->attribs, NULL); + } while (g->allies) { ally *a = g->allies; g->allies = a->next; From c21d5290ef61799da0705e93859c2485b4575572 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Thu, 10 Mar 2016 22:33:53 +0100 Subject: [PATCH 11/21] memory leak: castorders when you test_create_castorder, you must free_castorder --- src/spells/flyingship.test.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/spells/flyingship.test.c b/src/spells/flyingship.test.c index b3d03f01b..1b88bd7fb 100644 --- a/src/spells/flyingship.test.c +++ b/src/spells/flyingship.test.c @@ -44,19 +44,21 @@ static void test_flyingship(CuTest * tc) sh1 = test_create_ship(r, shipType1); par_data.data.sh = sh1; - test_create_castorder(&co, u, 10, 10.0, 0, &par); + test_create_castorder(&co, u, 10, 10.0, 0, &par); CuAssertTrue(tc, !flying_ship(sh1)); CuAssertIntEquals(tc, 10, sp_flying_ship(&co)); CuAssertTrue(tc, flying_ship(sh1)); + free_castorder(&co); sh2 = test_create_ship(r, shipType2); par_data.data.sh = sh2; - test_create_castorder(&co, u, 10, 10.0, 0, &par); + test_create_castorder(&co, u, 10, 10.0, 0, &par); CuAssertTrue(tc, !flying_ship(sh2)); CuAssertIntEquals(tc, 0, sp_flying_ship(&co)); CuAssertTrue(tc, !flying_ship(sh2)); + free_castorder(&co); test_cleanup(); } From be0cc939176365dccb9d8587a8577ed8e7d330b4 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Thu, 10 Mar 2016 23:05:24 +0100 Subject: [PATCH 12/21] this test is poorly written, and a trap --- src/spells/flyingship.test.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/spells/flyingship.test.c b/src/spells/flyingship.test.c index 1b88bd7fb..98e524926 100644 --- a/src/spells/flyingship.test.c +++ b/src/spells/flyingship.test.c @@ -49,6 +49,7 @@ static void test_flyingship(CuTest * tc) CuAssertTrue(tc, !flying_ship(sh1)); CuAssertIntEquals(tc, 10, sp_flying_ship(&co)); CuAssertTrue(tc, flying_ship(sh1)); + co.par = 0; free_castorder(&co); sh2 = test_create_ship(r, shipType2); @@ -58,6 +59,7 @@ static void test_flyingship(CuTest * tc) CuAssertTrue(tc, !flying_ship(sh2)); CuAssertIntEquals(tc, 0, sp_flying_ship(&co)); CuAssertTrue(tc, !flying_ship(sh2)); + co.par = 0; free_castorder(&co); test_cleanup(); } From 0f792e038f6e241e7f583bfa65cb0bb4eee4d963 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Fri, 11 Mar 2016 09:43:16 +0100 Subject: [PATCH 13/21] memory leaks - must free gamedata after close - clear spellbook and free it --- src/reports.test.c | 3 ++- src/util/gamedata.test.c | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/reports.test.c b/src/reports.test.c index dd2c544eb..e00e50a8b 100644 --- a/src/reports.test.c +++ b/src/reports.test.c @@ -405,7 +405,8 @@ static void test_write_spell_syntax(CuTest *tc) { set_parameter(spell, "kc+"); check_spell_syntax(tc, "kc+", &spell, " ZAUBERE \"Testzauber\" ( REGION | EINHEIT [ ...] | SCHIFF \n [ ...] | BURG [ ...] )"); - + spellbook_clear(spell.spb); + free(spell.spb); test_cleanup(); } diff --git a/src/util/gamedata.test.c b/src/util/gamedata.test.c index b28066b97..630ebc773 100644 --- a/src/util/gamedata.test.c +++ b/src/util/gamedata.test.c @@ -14,6 +14,7 @@ static void test_gamedata(CuTest * tc) data = gamedata_open("test.dat", "rb", 0); CuAssertPtrNotNull(tc, data); gamedata_close(data); + free(data); CuAssertIntEquals(tc, 0, remove("test.dat")); } From 10e67e21076c2e2c99fdc255d069926cc9ef1a86 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Fri, 11 Mar 2016 09:45:39 +0100 Subject: [PATCH 14/21] always free gamedata (this test uses two) --- src/util/gamedata.test.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/util/gamedata.test.c b/src/util/gamedata.test.c index 630ebc773..c58a8ddd0 100644 --- a/src/util/gamedata.test.c +++ b/src/util/gamedata.test.c @@ -11,6 +11,7 @@ static void test_gamedata(CuTest * tc) data = gamedata_open("test.dat", "wb", 0); CuAssertPtrNotNull(tc, data); gamedata_close(data); + free(data); data = gamedata_open("test.dat", "rb", 0); CuAssertPtrNotNull(tc, data); gamedata_close(data); From 42849170f49534281f83a99359379aa50451c4de Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Fri, 11 Mar 2016 09:47:13 +0100 Subject: [PATCH 15/21] memory leak: free this test's local attrib list --- src/attributes/key.test.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/attributes/key.test.c b/src/attributes/key.test.c index 72b72a3b9..46343d19f 100644 --- a/src/attributes/key.test.c +++ b/src/attributes/key.test.c @@ -39,6 +39,7 @@ static void test_upgrade(CuTest *tc) { CuAssertTrue(tc, key_get(alist, 42)); CuAssertTrue(tc, key_get(alist, 43)); CuAssertTrue(tc, key_get(alist, 44)); + a_removeall(&alist, NULL); } CuSuite *get_key_suite(void) From 349a67ece37256cd26bda8f711f031f7a5c7896b Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Fri, 11 Mar 2016 09:50:18 +0100 Subject: [PATCH 16/21] memory leak: test_create_shiptype and coasts, again --- src/move.test.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/move.test.c b/src/move.test.c index 81398ec62..21c717137 100644 --- a/src/move.test.c +++ b/src/move.test.c @@ -38,6 +38,7 @@ static void test_ship_not_allowed_in_coast(CuTest * tc) ttype = test_create_terrain("glacier", LAND_REGION | ARCTIC_REGION | WALK_INTO | SAIL_INTO); otype = test_create_terrain("ocean", SEA_REGION | SAIL_INTO); stype = test_create_shiptype("derp"); + free(stype->coasts); stype->coasts = (struct terrain_type **)calloc(2, sizeof(struct terrain_type *)); r1 = test_create_region(0, 0, ttype); From cdf6d3992ee0993e6b323caec4bb62021b3d2cf2 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Fri, 11 Mar 2016 10:31:21 +0100 Subject: [PATCH 17/21] memory leak: gamedata store was not released --- src/util/gamedata.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/util/gamedata.c b/src/util/gamedata.c index 4dc334cc8..cd3fa01a7 100644 --- a/src/util/gamedata.c +++ b/src/util/gamedata.c @@ -23,11 +23,6 @@ void gamedata_init(gamedata *data, storage *store, int version) { binstore_init(data->store, &data->strm); } -void gamedata_close(gamedata *data) { - gamedata_done(data); - fstream_done(&data->strm); -} - int gamedata_openfile(gamedata *data, const char *filename, const char *mode, int version) { FILE *F = fopen(filename, mode); if (F) { @@ -70,3 +65,9 @@ gamedata *gamedata_open(const char *filename, const char *mode, int version) { } return data; } + +void gamedata_close(gamedata *data) { + gamedata_done(data); + fstream_done(&data->strm); + free(data->store); +} From b81f9db074229a58758cf190a02c4bcb2b55d343 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Fri, 11 Mar 2016 11:31:05 +0100 Subject: [PATCH 18/21] memory leak: free race->parameters --- src/kernel/race.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/kernel/race.c b/src/kernel/race.c index 92bdac19f..be9f2ab68 100644 --- a/src/kernel/race.c +++ b/src/kernel/race.c @@ -141,6 +141,7 @@ void racelist_insert(struct race_list **rl, const struct race *r) void free_races(void) { while (races) { race * rc = races->next; + free_params(&races->parameters); free(races->_name); free(races->def_damage); free(races); From 637054bc22d44f4d1b7457ca493cb9d576393de2 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Fri, 11 Mar 2016 11:33:45 +0100 Subject: [PATCH 19/21] memory leak: clean up mstream after test --- src/kernel/save.test.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/kernel/save.test.c b/src/kernel/save.test.c index 83866273b..53dcfe5d9 100644 --- a/src/kernel/save.test.c +++ b/src/kernel/save.test.c @@ -296,6 +296,7 @@ static void test_read_password_external(CuTest *tc) { fclose(F); _test_read_password(&data, f); CuAssertPtrNotNull(tc, f->_password); + mstream_done(&data.strm); gamedata_done(&data); CuAssertTrue(tc, checkpasswd(f, "secret")); CuAssertIntEquals(tc, 0, remove(pwfile)); From d83bd3bec5c415ae41f824767c970e7b70dd39c2 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Fri, 11 Mar 2016 11:52:36 +0100 Subject: [PATCH 20/21] memory leak: finally found that coast leak. bad test was overwriting coasts without free (setting custom coasts in a test is not easy). --- src/piracy.test.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/piracy.test.c b/src/piracy.test.c index dee326980..419f73073 100644 --- a/src/piracy.test.c +++ b/src/piracy.test.c @@ -47,6 +47,7 @@ static void setup_pirate(unit **pirate, int p_r_flags, int p_rc_flags, const cha if (v_shiptype) { st_boat = st_get_or_create(v_shiptype); u_set_ship(*victim, test_create_ship((*victim)->region, st_boat)); + free(st_boat->coasts); st_boat->coasts = (struct terrain_type **)calloc(2, sizeof(struct terrain_type *)); st_boat->coasts[0] = vterrain; st_boat->coasts[1] = 0; @@ -59,6 +60,7 @@ static void setup_pirate(unit **pirate, int p_r_flags, int p_rc_flags, const cha if (p_shiptype) { st_boat = st_get_or_create(p_shiptype); u_set_ship(*pirate, test_create_ship((*pirate)->region, st_boat)); + free(st_boat->coasts); st_boat->coasts = (struct terrain_type **)calloc(2, sizeof(struct terrain_type *)); st_boat->coasts[0] = vterrain; st_boat->coasts[1] = 0; From ae7d86dae02844a8fc4c771f6b09110d69f81cde Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Fri, 11 Mar 2016 21:36:10 +0100 Subject: [PATCH 21/21] just a little bit of refactoring --- src/academy.c | 15 +++++++++++++++ src/academy.h | 2 +- src/study.c | 19 +++++++------------ src/util/umlaut.c | 1 - 4 files changed, 23 insertions(+), 14 deletions(-) diff --git a/src/academy.c b/src/academy.c index 5f948e280..60af23246 100644 --- a/src/academy.c +++ b/src/academy.c @@ -19,6 +19,9 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include #include +#include +#include +#include #include "academy.h" #include "study.h" @@ -28,3 +31,15 @@ void academy_teaching_bonus(struct unit *u, skill_t sk, int academy) { learn_skill(u, sk, academy / 30.0 / TEACHNUMBER); } } + +bool academy_can_teach(unit *teacher, unit *student, skill_t sk) { + const struct building_type *btype = bt_find("academy"); + if (active_building(teacher, btype) && active_building(student, btype)) { + int j = study_cost(student, sk); + j = _max(50, j * 2); + /* kann Einheit das zahlen? */ + return get_pooled(student, get_resourcetype(R_SILVER), GET_DEFAULT, j) >= j; + /* sonst nehmen sie nicht am Unterricht teil */ + } + return false; +} diff --git a/src/academy.h b/src/academy.h index 49128feda..f6af93748 100644 --- a/src/academy.h +++ b/src/academy.h @@ -9,7 +9,7 @@ extern "C" { struct unit; void academy_teaching_bonus(struct unit *u, skill_t sk, int academy); - + bool academy_can_teach(struct unit *teacher, struct unit *student, skill_t sk); #ifdef __cplusplus } #endif diff --git a/src/study.c b/src/study.c index 3639eba44..a69dff705 100644 --- a/src/study.c +++ b/src/study.c @@ -230,18 +230,13 @@ teach_unit(unit * teacher, unit * student, int nteaching, skill_t sk, if (student->building && teacher->building == student->building) { /* Solange Akademien groessenbeschraenkt sind, sollte Lehrer und * Student auch in unterschiedlichen Gebaeuden stehen duerfen */ - const struct building_type *btype = bt_find("academy"); - if (active_building(teacher, btype) && active_building(student, btype)) { - int j = study_cost(student, sk); - j = _max(50, j * 2); - /* kann Einheit das zahlen? */ - if (get_pooled(student, get_resourcetype(R_SILVER), GET_DEFAULT, j) >= j) { - /* Jeder Schueler zusaetzlich +10 Tage wenn in Uni. */ - teach->value += (n / 30) * 10; /* learning erhoehen */ - /* Lehrer zusaetzlich +1 Tag pro Schueler. */ - if (academy) - *academy += n; - } /* sonst nehmen sie nicht am Unterricht teil */ + if (academy_can_teach(teacher, student, sk)) { + /* Jeder Schueler zusaetzlich +10 Tage wenn in Uni. */ + teach->value += (n / 30) * 10; /* learning erhoehen */ + /* Lehrer zusaetzlich +1 Tag pro Schueler. */ + if (academy) { + *academy += n; + } } } /* Teaching ist die Anzahl Leute, denen man noch was beibringen kann. Da diff --git a/src/util/umlaut.c b/src/util/umlaut.c index 872ad8ffd..abbd59372 100644 --- a/src/util/umlaut.c +++ b/src/util/umlaut.c @@ -171,7 +171,6 @@ void addtoken(void ** root, const char *str, variant id) ref = (tref *)malloc(sizeof(tref)); ref->ucs = ucs; - ref->node = 0; ref->node = node; ref->nexthash = tk->next[index]; tk->next[index] = ref;