Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion src/kernel/skills.c
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ void sk_set_level(const struct unit *u, skill *sv, unsigned int level)
}

static void increase_skill(unit *u, skill *sv, unsigned int days) {
days /= u->number;
if (days > 0) {
unsigned int leveldays = sv->days;
while (leveldays <= days) {
Expand All @@ -130,7 +131,8 @@ static void increase_skill(unit *u, skill *sv, unsigned int days) {

void reduce_skill(unit *u, skill *sv, unsigned int days)
{
if (sv) {
days /= u->number;
if (sv && days > 0) {
// first, strip full levels off the skill:
// max_days = maximum days I can have "to do" at current level
unsigned int max_days = MAX_DAYS_TO_NEXT_LEVEL(sv->level);
Expand Down
71 changes: 51 additions & 20 deletions src/kernel/skills.test.c
Original file line number Diff line number Diff line change
Expand Up @@ -38,38 +38,38 @@ static void test_skill_change(CuTest *tc)
test_setup();
config_set_int("study.random_progress", 0);
u = test_create_unit(test_create_faction(), test_create_plain(0, 0));
set_number(u, 2); // number should have no effect on skill values
change_skill_days(u, SK_CROSSBOW, SKILL_DAYS_PER_WEEK);
set_number(u, 2);
change_skill_days(u, SK_CROSSBOW, 2 * SKILL_DAYS_PER_WEEK);
CuAssertPtrNotNull(tc, sv = unit_skill(u, SK_CROSSBOW));
CuAssertIntEquals(tc, 1 * SKILL_DAYS_PER_WEEK, days_effort(sv));
CuAssertIntEquals(tc, 1, skill_level(u, SK_CROSSBOW));
/* no random progress, so it will take 2 weeks of learning to next level: */
CuAssertIntEquals(tc, 2 * SKILL_DAYS_PER_WEEK, skill_days(u, SK_CROSSBOW));
change_skill_days(u, SK_CROSSBOW, SKILL_DAYS_PER_WEEK);
change_skill_days(u, SK_CROSSBOW, 2 * SKILL_DAYS_PER_WEEK);
CuAssertIntEquals(tc, 2 * SKILL_DAYS_PER_WEEK, days_effort(sv));
CuAssertIntEquals(tc, 1, skill_level(u, SK_CROSSBOW));
CuAssertIntEquals(tc, 1 * SKILL_DAYS_PER_WEEK, skill_days(u, SK_CROSSBOW));
change_skill_days(u, SK_CROSSBOW, SKILL_DAYS_PER_WEEK);
change_skill_days(u, SK_CROSSBOW, 2 * SKILL_DAYS_PER_WEEK);
CuAssertIntEquals(tc, 3 * SKILL_DAYS_PER_WEEK, days_effort(sv));
CuAssertIntEquals(tc, 2, skill_level(u, SK_CROSSBOW));
CuAssertIntEquals(tc, 3 * SKILL_DAYS_PER_WEEK, skill_days(u, SK_CROSSBOW));
change_skill_days(u, SK_CROSSBOW, 4 * SKILL_DAYS_PER_WEEK);
change_skill_days(u, SK_CROSSBOW, 8 * SKILL_DAYS_PER_WEEK);
CuAssertIntEquals(tc, 7 * SKILL_DAYS_PER_WEEK, days_effort(sv));
CuAssertIntEquals(tc, 3, skill_level(u, SK_CROSSBOW));
CuAssertIntEquals(tc, 3 * SKILL_DAYS_PER_WEEK, skill_days(u, SK_CROSSBOW));
change_skill_days(u, SK_CROSSBOW, -SKILL_DAYS_PER_WEEK);
change_skill_days(u, SK_CROSSBOW, -2 * SKILL_DAYS_PER_WEEK);
CuAssertIntEquals(tc, 6 * SKILL_DAYS_PER_WEEK, days_effort(sv));
CuAssertIntEquals(tc, 3, skill_level(u, SK_CROSSBOW));
CuAssertIntEquals(tc, 4 * SKILL_DAYS_PER_WEEK, skill_days(u, SK_CROSSBOW));
change_skill_days(u, SK_CROSSBOW, -SKILL_DAYS_PER_WEEK);
change_skill_days(u, SK_CROSSBOW, -2 * SKILL_DAYS_PER_WEEK);
CuAssertIntEquals(tc, 5 * SKILL_DAYS_PER_WEEK, days_effort(sv));
CuAssertIntEquals(tc, 3, skill_level(u, SK_CROSSBOW));
CuAssertIntEquals(tc, 5 * SKILL_DAYS_PER_WEEK, skill_days(u, SK_CROSSBOW));
change_skill_days(u, SK_CROSSBOW, -SKILL_DAYS_PER_WEEK * 2);
change_skill_days(u, SK_CROSSBOW, -4 * SKILL_DAYS_PER_WEEK);
CuAssertIntEquals(tc, 3 * SKILL_DAYS_PER_WEEK, days_effort(sv));
CuAssertIntEquals(tc, 3, skill_level(u, SK_CROSSBOW));
CuAssertIntEquals(tc, 7 * SKILL_DAYS_PER_WEEK, skill_days(u, SK_CROSSBOW));
change_skill_days(u, SK_CROSSBOW, -SKILL_DAYS_PER_WEEK);
change_skill_days(u, SK_CROSSBOW, -2 * SKILL_DAYS_PER_WEEK);
CuAssertIntEquals(tc, 2 * SKILL_DAYS_PER_WEEK, days_effort(sv));
CuAssertIntEquals(tc, 2, skill_level(u, SK_CROSSBOW));
CuAssertIntEquals(tc, 4 * SKILL_DAYS_PER_WEEK, skill_days(u, SK_CROSSBOW));
Expand All @@ -78,11 +78,41 @@ static void test_skill_change(CuTest *tc)
sv->days = SKILL_DAYS_PER_WEEK;
CuAssertIntEquals(tc, 65 * SKILL_DAYS_PER_WEEK, days_effort(sv));

change_skill_days(u, SK_CROSSBOW, -25 * SKILL_DAYS_PER_WEEK);
change_skill_days(u, SK_CROSSBOW, -50 * SKILL_DAYS_PER_WEEK);
CuAssertIntEquals(tc, 40 * SKILL_DAYS_PER_WEEK, days_effort(sv));
// 40 = (8 * 9) / 2 + 4
CuAssertIntEquals(tc, 9, skill_level(u, SK_CROSSBOW));
CuAssertIntEquals(tc, 15 * SKILL_DAYS_PER_WEEK, skill_days(u, SK_CROSSBOW));
test_teardown();
}

static void test_change_skill(CuTest *tc)
{
unit *u;
skill *sv;

test_setup();
config_set_int("study.random_progress", 0);
u = test_create_unit(test_create_faction(), test_create_plain(0, 0));
sv = test_set_skill(u, SK_CROSSBOW, 1, 1);
CuAssertIntEquals(tc, SKILL_DAYS_PER_WEEK, sv->days);
CuAssertIntEquals(tc, 1, sv->level);
change_skill(u, sv, -SKILL_DAYS_PER_WEEK);
CuAssertIntEquals(tc, SKILL_DAYS_PER_WEEK * 2, sv->days);
CuAssertIntEquals(tc, 1, sv->level);

set_number(u, 2);
sv = test_set_skill(u, SK_ARMORER, 1, 1);
CuAssertIntEquals(tc, SKILL_DAYS_PER_WEEK, sv->days);
CuAssertIntEquals(tc, 1, sv->level);
change_skill(u, sv, -2 * SKILL_DAYS_PER_WEEK);
CuAssertIntEquals(tc, SKILL_DAYS_PER_WEEK * 2, sv->days);
CuAssertIntEquals(tc, 1, sv->level);
change_skill(u, sv, 2 * SKILL_DAYS_PER_WEEK);
CuAssertIntEquals(tc, SKILL_DAYS_PER_WEEK, sv->days);
CuAssertIntEquals(tc, 1, sv->level);

test_teardown();
}

static void test_reduce_skill(CuTest *tc)
Expand All @@ -92,33 +122,33 @@ static void test_reduce_skill(CuTest *tc)
test_setup();
config_set_int("study.random_progress", 0);
u = test_create_unit(test_create_faction(), test_create_plain(0, 0));
set_number(u, 2); // number should have no effect on skill values
change_skill_days(u, SK_CROSSBOW, SKILL_DAYS_PER_WEEK);
set_number(u, 2);
change_skill_days(u, SK_CROSSBOW, 2 * SKILL_DAYS_PER_WEEK);
CuAssertIntEquals(tc, 1, skill_level(u, SK_CROSSBOW));
CuAssertIntEquals(tc, 2 * SKILL_DAYS_PER_WEEK, skill_days(u, SK_CROSSBOW));
change_skill_days(u, SK_CROSSBOW, -SKILL_DAYS_PER_WEEK);
change_skill_days(u, SK_CROSSBOW, -2 * SKILL_DAYS_PER_WEEK);
CuAssertIntEquals(tc, 1, skill_level(u, SK_CROSSBOW));
CuAssertIntEquals(tc, 3 * SKILL_DAYS_PER_WEEK, skill_days(u, SK_CROSSBOW));
change_skill_days(u, SK_CROSSBOW, -1);
change_skill_days(u, SK_CROSSBOW, -2);
CuAssertPtrEquals(tc, NULL, u->skills);

change_skill_days(u, SK_CROSSBOW, 3 * SKILL_DAYS_PER_WEEK);
change_skill_days(u, SK_CROSSBOW, 6 * SKILL_DAYS_PER_WEEK);
CuAssertIntEquals(tc, 2, skill_level(u, SK_CROSSBOW));
CuAssertIntEquals(tc, 3 * SKILL_DAYS_PER_WEEK, skill_days(u, SK_CROSSBOW));
change_skill_days(u, SK_CROSSBOW, - 2 * SKILL_DAYS_PER_WEEK);
change_skill_days(u, SK_CROSSBOW, -4 * SKILL_DAYS_PER_WEEK);
CuAssertIntEquals(tc, SKILL_DAYS_PER_WEEK, days_effort(u->skills));
CuAssertIntEquals(tc, 2, skill_level(u, SK_CROSSBOW));
CuAssertIntEquals(tc, 5 * SKILL_DAYS_PER_WEEK, skill_days(u, SK_CROSSBOW));
change_skill_days(u, SK_CROSSBOW, -1);
change_skill_days(u, SK_CROSSBOW, -2);
CuAssertIntEquals(tc, SKILL_DAYS_PER_WEEK - 1, days_effort(u->skills));
CuAssertIntEquals(tc, 1, skill_level(u, SK_CROSSBOW));
CuAssertIntEquals(tc, 2 * SKILL_DAYS_PER_WEEK + 1, skill_days(u, SK_CROSSBOW));
change_skill_days(u, SK_CROSSBOW, 2 - SKILL_DAYS_PER_WEEK);
change_skill_days(u, SK_CROSSBOW, 4 - 2 * SKILL_DAYS_PER_WEEK);
CuAssertIntEquals(tc, 1, days_effort(u->skills));
change_skill_days(u, SK_CROSSBOW, -1);
change_skill_days(u, SK_CROSSBOW, -2);
CuAssertIntEquals(tc, 1, skill_level(u, SK_CROSSBOW));
CuAssertIntEquals(tc, 3 * SKILL_DAYS_PER_WEEK, skill_days(u, SK_CROSSBOW));
change_skill_days(u, SK_CROSSBOW, -1);
change_skill_days(u, SK_CROSSBOW, -2);
CuAssertPtrEquals(tc, NULL, u->skills);
}

Expand Down Expand Up @@ -255,6 +285,7 @@ CuSuite *get_skills_suite(void)
SUITE_ADD_TEST(suite, test_reduce_skill);
SUITE_ADD_TEST(suite, test_skill_set);
SUITE_ADD_TEST(suite, test_skill_change);
SUITE_ADD_TEST(suite, test_change_skill);
SUITE_ADD_TEST(suite, test_set_level);
SUITE_ADD_TEST(suite, test_skills_merge);
return suite;
Expand Down
10 changes: 5 additions & 5 deletions src/study.c
Original file line number Diff line number Diff line change
Expand Up @@ -414,8 +414,8 @@ int teach_cmd(unit * teacher, struct order *ord)
free_order(new_order); /* parse_order & set_order have each increased the refcount */
}
if (academy_students > 0 && sk_academy != NOSKILL) {
// TODO: rounding errors here.
change_skill_days(teacher, sk_academy, academy_students / teacher->number);
// TODO: rounding errors, because increase_skill int-divides by teacher->number again.
change_skill_days(teacher, sk_academy, SKILL_DAYS_PER_WEEK / 3 * academy_students / 10);
}
reset_order();
return 0;
Expand Down Expand Up @@ -679,7 +679,7 @@ void produceexp(struct unit *u, enum skill_t sk)
if (u->number > 0) {
const struct race *rc = u_race(u);
if ((rc->flags & RCF_NOLEARN) == 0 && rc_can_learn(rc, sk)) {
change_skill_days(u, sk, produceexp_days());
change_skill_days(u, sk, u->number * produceexp_days());
}
}
}
Expand Down Expand Up @@ -749,7 +749,7 @@ int learn_skill(unit *u, enum skill_t sk, int days, int studycost) {
if (fval(u, UFL_HUNGER)) {
days /= 2;
}
change_skill_days(u, sk, days / u->number);
change_skill_days(u, sk, days);
return cost;
}

Expand Down Expand Up @@ -789,7 +789,7 @@ void demon_skillchange(unit *u)
skill* sv = u->skills + s;
int roll = rng_int() % 100;
if (sv->level > 0 && roll < upchance + downchance) {
int weeks = 1;
int weeks = u->number;
if (max_change > 1) {
weeks += rng_int() % max_change;
}
Expand Down
1 change: 1 addition & 0 deletions src/study.test.c
Original file line number Diff line number Diff line change
Expand Up @@ -487,6 +487,7 @@ static void test_demon_skillchange(CuTest *tc) {
CuAssertPtrEquals(tc, (void *)rc, (void *)get_race(RC_DAEMON));
u = test_create_unit(test_create_faction_ex(rc, NULL), test_create_plain(0, 0));
CuAssertPtrNotNull(tc, u);
scale_number(u, 2);
test_set_skill(u, SK_CROSSBOW, 2, 1);
test_set_skill(u, SK_MELEE, 2, 1);
CuAssertIntEquals(tc, 1 * SKILL_DAYS_PER_WEEK, skill_days(u, SK_CROSSBOW));
Expand Down
2 changes: 1 addition & 1 deletion src/triggers/shock.c
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ static void do_shock(unit * u, const char *reason)
skill* sv = u->skills + s;
int weeks = (sv->level * sv->level - sv->level) / 2;
int change = (weeks + 9) / 10;
change_skill(u, sv, -SKILL_DAYS_PER_WEEK * change);
change_skill(u, sv, -SKILL_DAYS_PER_WEEK * u->number * change);
}
}
/* Dies ist ein Hack, um das skillmod und familiar-Attribut beim Mage
Expand Down
18 changes: 14 additions & 4 deletions src/triggers/shock.test.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,12 @@
#include <kernel/event.h>
#include <kernel/faction.h>
#include <kernel/unit.h>
#include "kernel/skill.h" // for SK_MAGIC
#include "kernel/types.h" // for M_GWYRRD
#include "kernel/skill.h"
#include "kernel/skills.h"
#include "kernel/types.h"

#include <util/message.h>
#include "util/message.h"
#include "util/rand.h"

#include <tests.h>
#include <CuTest.h>
Expand All @@ -23,19 +25,27 @@ static void shock_setup(void) {
static void test_shock(CuTest *tc) {
unit *u;
trigger *tt;
skill *sv;

test_setup();
shock_setup();
random_source_inject_constants(0.f, 0);
u = test_create_unit(test_create_faction(), test_create_plain(0, 0));
create_mage(u, M_GWYRRD);
set_level(u, SK_MAGIC, 5);
test_set_skill(u, SK_CROSSBOW, 1, MAX_WEEKS_TO_NEXT_LEVEL(1));
sv = test_set_skill(u, SK_MAGIC, 5, MAX_WEEKS_TO_NEXT_LEVEL(5));
CuAssertIntEquals(tc, 5, sv->level);
CuAssertIntEquals(tc, 330, sv->days);
set_spellpoints(u, 10);
u->hp = 10;
tt = trigger_shock(u);
tt->type->handle(tt, u);
CuAssertIntEquals(tc, 2, u->hp);
CuAssertIntEquals(tc, 2, get_spellpoints(u));
CuAssertPtrNotNull(tc, test_find_messagetype(u->faction->msgs, "shock"));
// TODO: Talenttageverlust testen
CuAssertIntEquals(tc, 4, sv->level);
CuAssertIntEquals(tc, 180, sv->days);
t_free(tt);
free(tt);
test_teardown();
Expand Down
Loading