From 4fe72b5d2823aed46a9b70d8f40233a37d6240c9 Mon Sep 17 00:00:00 2001 From: Steffen Mecke Date: Fri, 28 Jul 2017 09:51:28 +0200 Subject: [PATCH 1/5] BUG 2350: read studyspeed correctly and fix orcs --- res/eressea/races.xml | 2 +- res/races/orc.xml | 2 +- src/kernel/xmlreader.c | 17 +++++++++++++---- 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/res/eressea/races.xml b/res/eressea/races.xml index 3ece1b325..04f621526 100644 --- a/res/eressea/races.xml +++ b/res/eressea/races.xml @@ -1172,7 +1172,7 @@ - + diff --git a/res/races/orc.xml b/res/races/orc.xml index 4f4d96ed5..a0033759a 100644 --- a/res/races/orc.xml +++ b/res/races/orc.xml @@ -1,5 +1,5 @@ - + diff --git a/src/kernel/xmlreader.c b/src/kernel/xmlreader.c index a9d38798a..2ef54b005 100644 --- a/src/kernel/xmlreader.c +++ b/src/kernel/xmlreader.c @@ -1320,6 +1320,12 @@ static void parse_ai(race * rc, xmlNodePtr node) rc->flags |= RCF_ATTACK_MOVED; } +static void set_study_speed(race *rc, skill_t sk, int modifier){ + if (!rc->study_speed) + rc->study_speed = calloc(1, MAXSKILLS); + rc->study_speed[sk] = (char)modifier; +} + static int parse_races(xmlDocPtr doc) { xmlXPathContextPtr xpath = xmlXPathNewContext(doc); @@ -1338,6 +1344,7 @@ static int parse_races(xmlDocPtr doc) xmlXPathObjectPtr result; int k, study_speed_base, attacks; struct att *attack; + skill_t sk; propValue = xmlGetProp(node, BAD_CAST "name"); assert(propValue != NULL); @@ -1362,6 +1369,11 @@ static int parse_races(xmlDocPtr doc) rc->hitpoints = xml_ivalue(node, "hp", rc->hitpoints); rc->armor = (char)xml_ivalue(node, "ac", rc->armor); study_speed_base = xml_ivalue(node, "studyspeed", 0); + if (study_speed_base != 0) { + for (sk = 0; sk < MAXSKILLS; ++sk) { + set_study_speed(rc, sk, study_speed_base); + } + } rc->at_default = (char)xml_ivalue(node, "unarmedattack", -2); rc->df_default = (char)xml_ivalue(node, "unarmeddefense", -2); @@ -1471,7 +1483,6 @@ static int parse_races(xmlDocPtr doc) xmlNodePtr node = result->nodesetval->nodeTab[k]; int mod = xml_ivalue(node, "modifier", 0); int speed = xml_ivalue(node, "speed", study_speed_base); - skill_t sk; propValue = xmlGetProp(node, BAD_CAST "name"); assert(propValue != NULL); @@ -1479,9 +1490,7 @@ static int parse_races(xmlDocPtr doc) if (sk != NOSKILL) { rc->bonus[sk] = (char)mod; if (speed) { - if (!rc->study_speed) - rc->study_speed = calloc(1, MAXSKILLS); - rc->study_speed[sk] = (char)speed; + set_study_speed(rc, sk, speed); } } else { From 1edfb7ae8ee9a45f96b4d317051857b01e03b220 Mon Sep 17 00:00:00 2001 From: Steffen Mecke Date: Fri, 28 Jul 2017 09:55:39 +0200 Subject: [PATCH 2/5] use STUDYDAYS consequently --- src/battle.c | 1 + src/kernel/skills.c | 1 + src/study.c | 28 ++++++++++++++-------------- src/study.h | 1 + 4 files changed, 17 insertions(+), 14 deletions(-) diff --git a/src/battle.c b/src/battle.c index 343bd754a..c89753049 100644 --- a/src/battle.c +++ b/src/battle.c @@ -958,6 +958,7 @@ void drain_exp(struct unit *u, int n) 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; diff --git a/src/kernel/skills.c b/src/kernel/skills.c index b951b77ba..9dad73f2f 100644 --- a/src/kernel/skills.c +++ b/src/kernel/skills.c @@ -153,6 +153,7 @@ int rc_skillmod(const struct race *rc, const region * r, skill_t sk) int level_days(int level) { + /* FIXME STUDYDAYS * ((level + 1) * level / 2); */ return 30 * ((level + 1) * level / 2); } diff --git a/src/study.c b/src/study.c index 9ea0a860e..f05e1a914 100644 --- a/src/study.c +++ b/src/study.c @@ -176,13 +176,13 @@ const attrib_type at_learning = { static int study_days(unit * student, skill_t sk) { - int speed = 30; + int speed = STUDYDAYS; if (u_race(student)->study_speed) { speed += u_race(student)->study_speed[sk]; - if (speed < 30) { + if (speed < STUDYDAYS) { skill *sv = unit_skill(student, sk); if (sv == 0) { - speed = 30; + speed = STUDYDAYS; } } } @@ -209,7 +209,7 @@ teach_unit(unit * teacher, unit * student, int nteaching, skill_t sk, return 0; } - n = 30 * student->number; + n = STUDYDAYS * student->number; a = a_find(student->attribs, &at_learning); if (a != NULL) { teach = (teaching_info *)a->data.v; @@ -231,7 +231,7 @@ teach_unit(unit * teacher, unit * student, int nteaching, skill_t sk, * Student auch in unterschiedlichen Gebaeuden stehen duerfen */ if (academy_can_teach(teacher, student, sk)) { /* Jeder Schueler zusaetzlich +10 Tage wenn in Uni. */ - teach->value += (n / 30) * 10; /* learning erhoehen */ + teach->value += (n / STUDYDAYS) * EXPERIENCEDAYS; /* learning erhoehen */ /* Lehrer zusaetzlich +1 Tag pro Schueler. */ if (academy) { *academy += n; @@ -268,7 +268,7 @@ teach_unit(unit * teacher, unit * student, int nteaching, skill_t sk, * die Talentaenderung (enno). */ - nteaching = MAX(0, nteaching - student->number * 30); + nteaching = MAX(0, nteaching - student->number * STUDYDAYS); } return n; @@ -301,14 +301,14 @@ int teach_cmd(unit * u, struct order *ord) return 0; } - teaching = u->number * 30 * TEACHNUMBER; + teaching = u->number * STUDYDAYS * TEACHNUMBER; if ((i = get_effect(u, oldpotiontype[P_FOOL])) > 0) { /* Trank "Dumpfbackenbrot" */ i = MIN(i, u->number * TEACHNUMBER); /* Trank wirkt pro Schueler, nicht pro Lehrer */ - teaching -= i * 30; + teaching -= i * STUDYDAYS; change_effect(u, oldpotiontype[P_FOOL], -i); - j = teaching / 30; + j = teaching / STUDYDAYS; ADDMSG(&u->faction->msgs, msg_message("teachdumb", "teacher amount", u, j)); } if (teaching == 0) @@ -747,12 +747,12 @@ int study_cmd(unit * u, order * ord) if (get_effect(u, oldpotiontype[P_WISE])) { l = MIN(u->number, get_effect(u, oldpotiontype[P_WISE])); - teach->value += l * 10; + teach->value += l * EXPERIENCEDAYS; change_effect(u, oldpotiontype[P_WISE], -l); } if (get_effect(u, oldpotiontype[P_FOOL])) { l = MIN(u->number, get_effect(u, oldpotiontype[P_FOOL])); - teach->value -= l * 30; + teach->value -= l * STUDYDAYS; change_effect(u, oldpotiontype[P_FOOL], -l); } @@ -761,11 +761,11 @@ int study_cmd(unit * u, order * ord) /* p ist Kosten ohne Uni, studycost mit; wenn * p!=studycost, ist die Einheit zwangsweise * in einer Uni */ - teach->value += u->number * 10; + teach->value += u->number * EXPERIENCEDAYS; } if (is_cursed(r->attribs, C_BADLEARN, 0)) { - teach->value -= u->number * 10; + teach->value -= u->number * EXPERIENCEDAYS; } multi *= study_speedup(u, sk, speed_rule); @@ -828,7 +828,7 @@ int study_cmd(unit * u, order * ord) static int produceexp_days(void) { static int config, rule; if (config_changed(&config)) { - rule = config_get_int("study.produceexp", 10); + rule = config_get_int("study.produceexp", EXPERIENCEDAYS); } return rule; } diff --git a/src/study.h b/src/study.h index 0f8ae70f5..8362f7c55 100644 --- a/src/study.h +++ b/src/study.h @@ -39,6 +39,7 @@ 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 produceexp(struct unit *u, skill_t sk, int n); From 160ef71d402eea5c509ec3bb45e119cfa33f7cef Mon Sep 17 00:00:00 2001 From: Steffen Mecke Date: Mon, 31 Jul 2017 12:55:05 +0200 Subject: [PATCH 3/5] refactor for STUDYDAYS --- src/academy.c | 2 +- src/battle.c | 17 ++------- src/battle.test.c | 82 +++++++++++++++++++++++++++++++++++++++++++ src/items/xerewards.c | 2 ++ src/kernel/skills.c | 13 +++++++ src/kernel/skills.h | 3 +- src/randenc.c | 4 +-- src/study.c | 39 +++++++++++++------- src/study.h | 2 +- 9 files changed, 131 insertions(+), 33 deletions(-) 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); From 80bfb5dbc6a4d510a23b66bf0d4b1097dbc367d5 Mon Sep 17 00:00:00 2001 From: Steffen Mecke Date: Mon, 31 Jul 2017 12:56:12 +0200 Subject: [PATCH 4/5] rename teacher variable --- src/study.c | 102 ++++++++++++++++++++++++++-------------------------- 1 file changed, 51 insertions(+), 51 deletions(-) diff --git a/src/study.c b/src/study.c index 9e1668483..56a9bf913 100644 --- a/src/study.c +++ b/src/study.c @@ -278,42 +278,42 @@ teach_unit(unit * teacher, unit * student, int nteaching, skill_t sk, return n; } -int teach_cmd(unit * u, struct order *ord) +int teach_cmd(unit * teacher, struct order *ord) { plane *pl; - region *r = u->region; + region *r = teacher->region; skill_t sk_academy = NOSKILL; int teaching, i, j, count, academy = 0; - if (u->region->attribs) { + if (teacher->region->attribs) { const curse_type *gbdream_ct = ct_find("gbdream"); if (gbdream_ct) { - if (get_curse(u->region->attribs, gbdream_ct)) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "gbdream_noteach", "")); + if (get_curse(teacher->region->attribs, gbdream_ct)) { + ADDMSG(&teacher->faction->msgs, msg_feedback(teacher, ord, "gbdream_noteach", "")); return 0; } } } - if ((u_race(u)->flags & RCF_NOTEACH) || fval(u, UFL_WERE)) { - cmistake(u, ord, 274, MSG_EVENT); + if ((u_race(teacher)->flags & RCF_NOTEACH) || fval(teacher, UFL_WERE)) { + cmistake(teacher, ord, 274, MSG_EVENT); return 0; } pl = rplane(r); if (pl && fval(pl, PFL_NOTEACH)) { - cmistake(u, ord, 273, MSG_EVENT); + cmistake(teacher, ord, 273, MSG_EVENT); return 0; } - teaching = u->number * STUDYDAYS * TEACHNUMBER; + teaching = teacher->number * STUDYDAYS * TEACHNUMBER; - if ((i = get_effect(u, oldpotiontype[P_FOOL])) > 0) { /* Trank "Dumpfbackenbrot" */ - i = MIN(i, u->number * TEACHNUMBER); + if ((i = get_effect(teacher, oldpotiontype[P_FOOL])) > 0) { /* Trank "Dumpfbackenbrot" */ + i = MIN(i, teacher->number * TEACHNUMBER); /* Trank wirkt pro Schueler, nicht pro Lehrer */ teaching -= i * STUDYDAYS; - change_effect(u, oldpotiontype[P_FOOL], -i); + change_effect(teacher, oldpotiontype[P_FOOL], -i); j = teaching / STUDYDAYS; - ADDMSG(&u->faction->msgs, msg_message("teachdumb", "teacher amount", u, j)); + ADDMSG(&teacher->faction->msgs, msg_message("teachdumb", "teacher amount", teacher, j)); } if (teaching == 0) return 0; @@ -323,22 +323,22 @@ int teach_cmd(unit * u, struct order *ord) init_order(ord); #if TEACH_ALL - if (getparam(u->faction->locale) == P_ANY) { + if (getparam(teacher->faction->locale) == P_ANY) { skill_t sk; unit *student; skill_t teachskill[MAXSKILLS]; int t = 0; do { - sk = getskill(u->faction->locale); - teachskill[t] = getskill(u->faction->locale); + sk = getskill(teacher->faction->locale); + teachskill[t] = getskill(teacher->faction->locale); } while (sk != NOSKILL); for (student = r->units; teaching && student; student = student->next) { if (LongHunger(student)) { continue; } - else if (student->faction == u->faction) { + else if (student->faction == teacher->faction) { if (getkeyword(student->thisorder) == K_STUDY) { /* Input ist nun von student->thisorder !! */ init_order(student->thisorder); @@ -352,20 +352,20 @@ int teach_cmd(unit * u, struct order *ord) sk = teachskill[t]; } if (sk != NOSKILL - && effskill_study(u, sk, 0) - TEACHDIFFERENCE > effskill_study(student, sk, 0)) { - teaching -= teach_unit(u, student, teaching, sk, true, &academy); + && effskill_study(teacher, sk, 0) - TEACHDIFFERENCE > effskill_study(student, sk, 0)) { + teaching -= teach_unit(teacher, student, teaching, sk, true, &academy); } } } #ifdef TEACH_FRIENDS - else if (alliedunit(u, student->faction, HELP_GUARD)) { + else if (alliedunit(teacher, student->faction, HELP_GUARD)) { if (getkeyword(student->thisorder) == K_STUDY) { /* Input ist nun von student->thisorder !! */ init_order(student->thisorder); sk = getskill(student->faction->locale); if (sk != NOSKILL - && effskill_study(u, sk, 0) - TEACHDIFFERENCE >= effskill(student, sk, 0)) { - teaching -= teach_unit(u, student, teaching, sk, true, &academy); + && effskill_study(teacher, sk, 0) - TEACHDIFFERENCE >= effskill(student, sk, 0)) { + teaching -= teach_unit(teacher, student, teaching, sk, true, &academy); } } } @@ -384,15 +384,15 @@ int teach_cmd(unit * u, struct order *ord) while (!parser_end()) { skill_t sk; - unit *u2; + unit *student; bool feedback; - getunit(r, u->faction, &u2); + getunit(r, teacher->faction, &student); ++count; /* Falls die Unit nicht gefunden wird, Fehler melden */ - if (!u2) { + if (!student) { char tbuf[20]; const char *uid; const char *token; @@ -402,30 +402,30 @@ int teach_cmd(unit * u, struct order *ord) for (j = 0; j != count - 1; ++j) { /* skip over the first 'count' units */ - getunit(r, u->faction, NULL); + getunit(r, teacher->faction, NULL); } token = getstrtoken(); /* Beginne die Fehlermeldung */ - if (isparam(token, u->faction->locale, P_TEMP)) { + if (isparam(token, teacher->faction->locale, P_TEMP)) { token = getstrtoken(); - sprintf(tbuf, "%s %s", LOC(u->faction->locale, + sprintf(tbuf, "%s %s", LOC(teacher->faction->locale, parameters[P_TEMP]), token); uid = tbuf; } else { uid = token; } - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "unitnotfound_id", + ADDMSG(&teacher->faction->msgs, msg_feedback(teacher, ord, "unitnotfound_id", "id", uid)); parser_popstate(); continue; } - feedback = u->faction == u2->faction - || alliedunit(u2, u->faction, HELP_GUARD); + feedback = teacher->faction == student->faction + || alliedunit(student, teacher->faction, HELP_GUARD); /* Neuen Befehl zusammenbauen. TEMP-Einheiten werden automatisch in * ihre neuen Nummern uebersetzt. */ @@ -433,58 +433,58 @@ int teach_cmd(unit * u, struct order *ord) strncat(zOrder, " ", sz - 1); --sz; } - sz -= strlcpy(zOrder + 4096 - sz, itoa36(u2->no), sz); + sz -= strlcpy(zOrder + 4096 - sz, itoa36(student->no), sz); - if (getkeyword(u2->thisorder) != K_STUDY) { - ADDMSG(&u->faction->msgs, - msg_feedback(u, ord, "teach_nolearn", "student", u2)); + if (getkeyword(student->thisorder) != K_STUDY) { + ADDMSG(&teacher->faction->msgs, + msg_feedback(teacher, ord, "teach_nolearn", "student", student)); continue; } - /* Input ist nun von u2->thisorder !! */ + /* Input ist nun von student->thisorder !! */ parser_pushstate(); - init_order(u2->thisorder); - sk = getskill(u2->faction->locale); + init_order(student->thisorder); + sk = getskill(student->faction->locale); parser_popstate(); if (sk == NOSKILL) { - ADDMSG(&u->faction->msgs, - msg_feedback(u, ord, "teach_nolearn", "student", u2)); + ADDMSG(&teacher->faction->msgs, + msg_feedback(teacher, ord, "teach_nolearn", "student", student)); continue; } - if (effskill_study(u2, sk, 0) > effskill_study(u, sk, 0) + if (effskill_study(student, sk, 0) > effskill_study(teacher, sk, 0) - TEACHDIFFERENCE) { if (feedback) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "teach_asgood", - "student", u2)); + ADDMSG(&teacher->faction->msgs, msg_feedback(teacher, ord, "teach_asgood", + "student", student)); } continue; } if (sk == SK_MAGIC) { /* ist der Magier schon spezialisiert, so versteht er nur noch * Lehrer seines Gebietes */ - sc_mage *mage1 = get_mage(u); - sc_mage *mage2 = get_mage(u2); + sc_mage *mage1 = get_mage(teacher); + sc_mage *mage2 = get_mage(student); if (mage2 && mage1 && mage2->magietyp != M_GRAY && mage1->magietyp != mage2->magietyp) { if (feedback) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, - "error_different_magic", "target", u2)); + ADDMSG(&teacher->faction->msgs, msg_feedback(teacher, ord, + "error_different_magic", "target", student)); } continue; } } sk_academy = sk; - teaching -= teach_unit(u, u2, teaching, sk, false, &academy); + teaching -= teach_unit(teacher, student, teaching, sk, false, &academy); } - new_order = create_order(K_TEACH, u->faction->locale, "%s", zOrder); - replace_order(&u->orders, ord, new_order); + new_order = create_order(K_TEACH, teacher->faction->locale, "%s", zOrder); + replace_order(&teacher->orders, ord, new_order); free_order(new_order); /* parse_order & set_order have each increased the refcount */ } if (academy && sk_academy!=NOSKILL) { assert(academy % STUDYDAYS == 0); - academy_teaching_bonus(u, sk_academy, academy / STUDYDAYS); + academy_teaching_bonus(teacher, sk_academy, academy / STUDYDAYS); } return 0; } From f0c17b01afbbbbb4487871d500770c2136bb9da7 Mon Sep 17 00:00:00 2001 From: Steffen Mecke Date: Fri, 4 Aug 2017 15:17:18 +0200 Subject: [PATCH 5/5] fixed demon_skillchange and produceexp learn_skill's argument is the number of person days, not the number of unit days as assumed! --- src/academy.c | 7 ++++--- src/items/xerewards.c | 1 + src/items/xerewards.test.c | 6 +++--- src/study.c | 7 ++++--- src/study.test.c | 12 ++++++------ 5 files changed, 18 insertions(+), 15 deletions(-) diff --git a/src/academy.c b/src/academy.c index 9f42c0e4c..c25ea2476 100644 --- a/src/academy.c +++ b/src/academy.c @@ -25,9 +25,10 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include "academy.h" #include "study.h" -void academy_teaching_bonus(struct unit *u, skill_t sk, int academy) { - if (academy && sk != NOSKILL) { - learn_skill(u, sk, academy); +void academy_teaching_bonus(struct unit *u, skill_t sk, int student_days) { + if (student_days && sk != NOSKILL) { + /* actually days / STUDYDAYS * EXPERIENCEDAYS / MAX_STUDENTS */ + learn_skill(u, sk, student_days / STUDYDAYS); } } diff --git a/src/items/xerewards.c b/src/items/xerewards.c index e39608a16..e9a11d00d 100644 --- a/src/items/xerewards.c +++ b/src/items/xerewards.c @@ -54,6 +54,7 @@ struct order *ord) for (n = 0; n != amount; ++n) { skill *sv = u->skills; while (sv != u->skills + u->skill_size) { + /* only one person learns for 3 weeks */ learn_skill(u, (skill_t)sv->id, STUDYDAYS * 3); ++sv; } diff --git a/src/items/xerewards.test.c b/src/items/xerewards.test.c index ea9f53fde..5739141c0 100644 --- a/src/items/xerewards.test.c +++ b/src/items/xerewards.test.c @@ -31,17 +31,17 @@ static void test_skillpotion(CuTest *tc) { itype = test_create_itemtype("skillpotion"); change_resource(u, itype->rtype, 2); - learn_skill(u, SK_ENTERTAINMENT, STUDYDAYS); + learn_skill(u, SK_ENTERTAINMENT, STUDYDAYS * u->number); pSkill = unit_skill(u, SK_ENTERTAINMENT); sk_set(pSkill, 5); initialWeeks_Entertainment = pSkill->weeks = 4; - learn_skill(u, SK_STAMINA, STUDYDAYS); + learn_skill(u, SK_STAMINA, STUDYDAYS * u->number); pSkill = unit_skill(u, SK_STAMINA); sk_set(pSkill, 5); initialWeeks_Stamina = pSkill->weeks = 4; - learn_skill(u, SK_MAGIC, STUDYDAYS); + learn_skill(u, SK_MAGIC, STUDYDAYS * u->number); pSkill = unit_skill(u, SK_MAGIC); sk_set(pSkill, 5); initialWeeks_Magic = pSkill->weeks = 4; diff --git a/src/study.c b/src/study.c index 56a9bf913..ddded23cc 100644 --- a/src/study.c +++ b/src/study.c @@ -484,7 +484,7 @@ int teach_cmd(unit * teacher, struct order *ord) } if (academy && sk_academy!=NOSKILL) { assert(academy % STUDYDAYS == 0); - academy_teaching_bonus(teacher, sk_academy, academy / STUDYDAYS); + academy_teaching_bonus(teacher, sk_academy, academy); } return 0; } @@ -842,7 +842,7 @@ void produceexp_ex(struct unit *u, skill_t sk, int n, learn_fun learn) assert(u && n <= u->number); if (n > 0 && (is_monsters(u->faction) || playerrace(u_race(u)))) { int days = produceexp_days(); - learn(u, sk, days * n / u->number); + learn(u, sk, days * n); } } @@ -858,6 +858,7 @@ void inject_learn(learn_fun fun) { inject_learn_fun = fun; } #endif +/** days should be scaled by u->number; STUDYDAYS * u->number is one week worth of learning */ void learn_skill(unit *u, skill_t sk, int days) { int leveldays = STUDYDAYS * u->number; int weeks = 0; @@ -929,7 +930,7 @@ void demon_skillchange(unit *u) } } else { - learn_skill(u, sv->id, STUDYDAYS*weeks); + learn_skill(u, sv->id, STUDYDAYS * u->number * weeks); } } ++sv; diff --git a/src/study.test.c b/src/study.test.c index 74104704b..c0b58b493 100644 --- a/src/study.test.c +++ b/src/study.test.c @@ -184,12 +184,12 @@ static CuTest *g_tc; static void cb_learn_one(unit *u, skill_t sk, int days) { CuAssertIntEquals(g_tc, SK_ALCHEMY, sk); - CuAssertIntEquals(g_tc, 10, days); + CuAssertIntEquals(g_tc, 20, days); } static void cb_learn_two(unit *u, skill_t sk, int days) { CuAssertIntEquals(g_tc, SK_ALCHEMY, sk); - CuAssertIntEquals(g_tc, 20, days); + CuAssertIntEquals(g_tc, 40, days); } static void test_produceexp(CuTest *tc) { @@ -247,7 +247,7 @@ static void test_academy_building(CuTest *tc) { CuAssertPtrEquals(tc, u, log_learners[0].u); CuAssertIntEquals(tc, SK_CROSSBOW, log_learners[0].sk); - CuAssertIntEquals(tc, 15, log_learners[0].days); + CuAssertIntEquals(tc, u1->number, log_learners[0].days); test_cleanup(); } @@ -377,7 +377,7 @@ static void test_study_cost(CuTest *tc) { learn_reset(); CuAssertPtrEquals(tc, u, log_learners[0].u); CuAssertIntEquals(tc, SK_ALCHEMY, log_learners[0].sk); - CuAssertIntEquals(tc, STUDYDAYS*u->number, log_learners[0].days); + CuAssertIntEquals(tc, STUDYDAYS * u->number, log_learners[0].days); CuAssertIntEquals(tc, 0, i_get(u->items, itype)); test_cleanup(); } @@ -405,7 +405,7 @@ static void test_teach_magic(CuTest *tc) { learn_reset(); CuAssertPtrEquals(tc, u, log_learners[0].u); CuAssertIntEquals(tc, SK_MAGIC, log_learners[0].sk); - CuAssertIntEquals(tc, STUDYDAYS*2, log_learners[0].days); + CuAssertIntEquals(tc, STUDYDAYS * 2, log_learners[0].days); CuAssertIntEquals(tc, 0, i_get(u->items, itype)); test_cleanup(); } @@ -426,7 +426,7 @@ static void test_teach_cmd(CuTest *tc) { learn_reset(); CuAssertPtrEquals(tc, u, log_learners[0].u); CuAssertIntEquals(tc, SK_CROSSBOW, log_learners[0].sk); - CuAssertIntEquals(tc, STUDYDAYS*2*u->number, log_learners[0].days); + CuAssertIntEquals(tc, STUDYDAYS * 2 * u->number, log_learners[0].days); test_cleanup(); }