diff --git a/src/academy.c b/src/academy.c index 496c1ef8e..9f42c0e4c 100644 --- a/src/academy.c +++ b/src/academy.c @@ -27,7 +27,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. void academy_teaching_bonus(struct unit *u, skill_t sk, int academy) { if (academy && sk != NOSKILL) { - learn_skill(u, sk, academy / STUDYDAYS); + learn_skill(u, sk, academy); } } diff --git a/src/battle.c b/src/battle.c index c89753049..84d61091a 100644 --- a/src/battle.c +++ b/src/battle.c @@ -26,6 +26,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include "monsters.h" #include "move.h" #include "skill.h" +#include "study.h" #include #include @@ -955,21 +956,7 @@ void drain_exp(struct unit *u, int n) } } if (sk != NOSKILL) { - skill *sv = unit_skill(u, sk); - if (sv) { - while (n > 0) { - /* FIXME STUDYDAYS */ - if (n >= 30 * u->number) { - reduce_skill(u, sv, 1); - n -= 30; - } - else { - if (rng_int() % (30 * u->number) < n) - reduce_skill(u, sv, 1); - n = 0; - } - } - } + reduce_skill_days(u, sk, n); } } diff --git a/src/battle.test.c b/src/battle.test.c index b00d06a98..a869b4ca4 100644 --- a/src/battle.test.c +++ b/src/battle.test.c @@ -12,8 +12,13 @@ #include #include #include +#include +#include #include + +#include + #include "tests.h" static void test_make_fighter(CuTest * tc) @@ -494,6 +499,82 @@ static void test_battle_skilldiff_building(CuTest *tc) test_cleanup(); } +static void assert_skill(CuTest *tc, char *msg, unit *u, skill_t sk, int level, int week, int weekmax) +{ + skill *sv = unit_skill(u, sk); + char buf[256]; + if (sv) { + sprintf(buf, "%s level %d != %d", msg, sv->level, level); + CuAssertIntEquals_Msg(tc, (const char *)&buf, level, sv->level); + sprintf(buf, "%s week %d !<= %d !<= %d", msg, week, sv->weeks, weekmax); + CuAssert(tc, (const char *)&buf, sv->weeks >= week && sv->weeks <=weekmax); + } else { + CuAssertIntEquals_Msg(tc, msg, level, 0); + CuAssertIntEquals_Msg(tc, msg, week, 0); + } +} + +static void test_drain_exp(CuTest *tc) +{ + unit *u; + char *msg; + int i; + double rand; + + test_setup(); + config_set("study.random_progress", "0"); + u = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0)); + set_level(u, SK_STAMINA, 3); + + CuAssertIntEquals(tc, 3, unit_skill(u, SK_STAMINA)->level); + CuAssertIntEquals(tc, 4, unit_skill(u, SK_STAMINA)->weeks); + + assert_skill(tc, msg = "base", u, SK_STAMINA, 3, 4, 4); + assert_skill(tc, msg, u, SK_STAMINA, 3, 4, 4); + assert_skill(tc, msg, u, SK_MINING, 0, 0, 0); + + for (i=0; i<10; ++i) { + set_level(u, SK_STAMINA, 3); + drain_exp(u, 0); + assert_skill(tc, msg = "0 change", u, SK_STAMINA, 3, 4, 4); + assert_skill(tc, msg, u, SK_MINING, 0, 0, 0); + + for (rand = 0.0; rand < 2.0; rand += 1) { + random_source_inject_constant(rand); + + set_level(u, SK_STAMINA, 3); + drain_exp(u, 29); + + assert_skill(tc, msg = "no change yet", u, SK_STAMINA, 3, 4, rand == 0.0?4:5); + assert_skill(tc, msg, u, SK_MINING, 0, 0, 0); + + set_level(u, SK_STAMINA, 3); + drain_exp(u, 1); + + assert_skill(tc, msg = "random change", u, SK_STAMINA, 3, 4, rand == 0.0?4:5); + assert_skill(tc, msg, u, SK_MINING, 0, 0, 0); + + set_level(u, SK_STAMINA, 3); + drain_exp(u, 30); + + assert_skill(tc, msg = "plus one", u, SK_STAMINA, 3, 5, 5); + assert_skill(tc, msg, u, SK_MINING, 0, 0, 0); + } + + set_level(u, SK_STAMINA, 3); + drain_exp(u, 90); + + assert_skill(tc, msg = "plus three", u, SK_STAMINA, 3, 7, 7); + assert_skill(tc, msg, u, SK_MINING, 0, 0, 0); + + set_level(u, SK_STAMINA, 3); + drain_exp(u, 120); + + assert_skill(tc, msg = "plus four", u, SK_STAMINA, 2, 5, 5); + assert_skill(tc, msg, u, SK_MINING, 0, 0, 0); + } +} + CuSuite *get_battle_suite(void) { CuSuite *suite = CuSuiteNew(); @@ -508,5 +589,6 @@ CuSuite *get_battle_suite(void) SUITE_ADD_TEST(suite, test_natural_armor); SUITE_ADD_TEST(suite, test_magic_resistance); SUITE_ADD_TEST(suite, test_projectile_armor); + SUITE_ADD_TEST(suite, test_drain_exp); return suite; } diff --git a/src/items/xerewards.c b/src/items/xerewards.c index a6d1ad2ea..e39608a16 100644 --- a/src/items/xerewards.c +++ b/src/items/xerewards.c @@ -34,6 +34,8 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. /* util includes */ #include +#include + /* libc includes */ #include #include diff --git a/src/kernel/skills.c b/src/kernel/skills.c index 9dad73f2f..3bcbd0f66 100644 --- a/src/kernel/skills.c +++ b/src/kernel/skills.c @@ -203,6 +203,19 @@ int skill_weeks(int level) return level + 1; } +void increase_skill(unit * u, skill_t sk, unsigned int weeks) +{ + skill *sv = unit_skill(u, sk); + if (!sv) { + sv = add_skill(u, sk); + } + while (sv->weeks <= (int) weeks) { + weeks -= sv->weeks; + sk_set(sv, sv->level + 1); + } + sv->weeks -= weeks; +} + void reduce_skill(unit * u, skill * sv, unsigned int weeks) { sv->weeks += weeks; diff --git a/src/kernel/skills.h b/src/kernel/skills.h index 1261a7ea9..4c41109d7 100644 --- a/src/kernel/skills.h +++ b/src/kernel/skills.h @@ -52,7 +52,8 @@ extern "C" { int level(int days); #define skill_level(level) (level) - void reduce_skill(struct unit *u, skill * sv, unsigned int change); + void increase_skill(struct unit * u, skill_t sk, unsigned int weeks); + void reduce_skill(struct unit *u, skill * sv, unsigned int weeks); int skill_weeks(int level); int skill_compare(const skill * sk, const skill * sc); diff --git a/src/randenc.c b/src/randenc.c index e46d5fa24..d2099e49c 100644 --- a/src/randenc.c +++ b/src/randenc.c @@ -156,7 +156,7 @@ static bool improve_all(faction * f, skill_t sk, int by_weeks) bool result = false; for (u = f->units; u; u = u->nextF) { if (has_skill(u, sk)) { - learn_skill(u, sk, by_weeks * STUDYDAYS); + increase_skill(u, sk, by_weeks); result = true; } } @@ -242,7 +242,7 @@ void find_manual(region * r, unit * u) } if (!improve_all(u->faction, skill, 3)) { - learn_skill(u, skill, 9 * STUDYDAYS); + increase_skill(u, skill, 9); } } diff --git a/src/study.c b/src/study.c index f05e1a914..9e1668483 100644 --- a/src/study.c +++ b/src/study.c @@ -163,8 +163,8 @@ static void init_learning(struct attrib *a) static void done_learning(struct attrib *a) { - teaching_info *teach = (teaching_info *)a->data.v; - selist_free(teach->teachers); + teaching_info *teach = (teaching_info *)a->data.v; + selist_free(teach->teachers); free(a->data.v); } @@ -174,6 +174,8 @@ const attrib_type at_learning = { ATF_UNIQUE }; +#define EXPERIENCEDAYS 10 + static int study_days(unit * student, skill_t sk) { int speed = STUDYDAYS; @@ -260,14 +262,16 @@ teach_unit(unit * teacher, unit * student, int nteaching, skill_t sk, * * Ist C aber vor B dran, lehrt C 300 tage an A, und 0 tage an D, * und B lehrt auch 0 tage an A. + * (Na und? -stm) * - * Deswegen darf C D nie lehren duerfen. + * Deswegen darf C D nie lehren duerfen. (Warum? -stm) * * -> Das ist wirr. wer hat das entworfen? * Besser waere, man macht erst vorab alle zuordnungen, und dann * die Talentaenderung (enno). */ + /* FIXME: this code no effect; check if the refactoring done in 1e51d0e9e238e1e6e073cab2060777038e1acfa1 fucked this up */ nteaching = MAX(0, nteaching - student->number * STUDYDAYS); } @@ -449,7 +453,6 @@ int teach_cmd(unit * u, struct order *ord) continue; } - /* u is teacher, u2 is student */ if (effskill_study(u2, sk, 0) > effskill_study(u, sk, 0) - TEACHDIFFERENCE) { if (feedback) { @@ -480,7 +483,8 @@ int teach_cmd(unit * u, struct order *ord) free_order(new_order); /* parse_order & set_order have each increased the refcount */ } if (academy && sk_academy!=NOSKILL) { - academy_teaching_bonus(u, sk_academy, academy); + assert(academy % STUDYDAYS == 0); + academy_teaching_bonus(u, sk_academy, academy / STUDYDAYS); } return 0; } @@ -871,15 +875,24 @@ void learn_skill(unit *u, skill_t sk, int days) { ++weeks; } if (weeks > 0) { - skill *sv = unit_skill(u, sk); - if (!sv) { - sv = add_skill(u, sk); + increase_skill(u, sk, weeks); + } +} + +void reduce_skill_days(unit *u, skill_t sk, int days) { + skill *sv = unit_skill(u, sk); + if (sv) { + while (days > 0) { + if (days >= STUDYDAYS * u->number) { + reduce_skill(u, sv, 1); + days -= STUDYDAYS; + } + else { + if (chance (days / ((double) STUDYDAYS * u->number))) /* (rng_int() % (30 * u->number) < days)*/ + reduce_skill(u, sv, 1); + days = 0; + } } - while (sv->weeks <= weeks) { - weeks -= sv->weeks; - sk_set(sv, sv->level + 1); - } - sv->weeks -= weeks; } } diff --git a/src/study.h b/src/study.h index 8362f7c55..83bd65a40 100644 --- a/src/study.h +++ b/src/study.h @@ -39,8 +39,8 @@ extern "C" { typedef void(*learn_fun)(struct unit *u, skill_t sk, int days); #define STUDYDAYS 30 -#define EXPERIENCEDAYS 10 void learn_skill(struct unit *u, skill_t sk, int days); + void reduce_skill_days(struct unit *u, skill_t sk, int days); void produceexp(struct unit *u, skill_t sk, int n); void produceexp_ex(struct unit *u, skill_t sk, int n, learn_fun learn);