Merge pull request #502 from ennorehling/feature/refactor-study

refactor study.c
This commit is contained in:
Enno Rehling 2016-03-26 14:53:26 +01:00
commit 108b4404d2
27 changed files with 571 additions and 334 deletions

View File

@ -49,7 +49,7 @@
"recruit.allow_merge": true,
"study.expensivemigrants": true,
"study.speedup": 2,
"study.from_use": 0.4,
"study.produceexp": 12,
"world.era": 3,
"rules.reserve.twophase": true,
"rules.owners.force_leave": false,

@ -1 +1 @@
Subproject commit 934c2dd94d41da19637a76a1a8b3dfeb7aa8524d
Subproject commit ee7a32b9b8986bf2ea6b287975f9ef0ec997b7a3

View File

@ -27,8 +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) {
academy = academy / 30; /* anzahl gelehrter wochen, max. 10 */
learn_skill(u, sk, academy / 30.0 / TEACHNUMBER);
learn_skill(u, sk, academy / STUDYDAYS);
}
}

View File

@ -394,10 +394,10 @@ static int tolua_learn_skill(lua_State * L)
{
unit *u = (unit *)tolua_tousertype(L, 1, 0);
const char *skname = tolua_tostring(L, 2, 0);
float chances = (float)tolua_tonumber(L, 3, 0);
int days = (int)tolua_tonumber(L, 3, 0);
skill_t sk = findskill(skname);
if (sk != NOSKILL) {
learn_skill(u, sk, chances);
learn_skill(u, sk, days);
}
return 0;
}

View File

@ -11,7 +11,7 @@ static void test_init_directions(CuTest *tc) {
struct locale *lang;
test_cleanup();
lang = get_or_create_locale("en");
lang = get_or_create_locale("de");
locale_setstring(lang, "dir_nw", "NW");
init_directions(lang);
CuAssertIntEquals(tc, D_NORTHWEST, get_direction("nw", lang));

View File

@ -31,18 +31,11 @@ struct give {
static void setup_give(struct give *env) {
struct terrain_type *ter = test_create_terrain("plain", LAND_REGION);
struct locale *lang;
race *rc;
assert(env->f1);
rc = test_create_race(env->f1->race ? env->f1->race->_name : "humon");
rc->ec_flags |= GIVEPERSON;
lang = get_or_create_locale(env->f1->locale ? locale_name(env->f1->locale) : "test");
env->f1->locale = lang;
locale_setstring(lang, "ALLES", "ALLES");
locale_setstring(lang, "PERSONEN", "PERSONEN");
locale_setstring(lang, "KRAEUTER", "KRAUT");
init_locale(lang);
env->r = test_create_region(0, 0, ter);
env->src = test_create_unit(env->f1, env->r);
@ -277,7 +270,6 @@ static void test_give(CuTest * tc) {
static void test_give_herbs(CuTest * tc) {
struct give env;
struct order *ord;
struct locale * lang;
char cmd[32];
test_cleanup();
@ -286,12 +278,8 @@ static void test_give_herbs(CuTest * tc) {
setup_give(&env);
i_change(&env.src->items, env.itype, 10);
lang = get_or_create_locale("test");
env.f1->locale = lang;
locale_setstring(lang, "KRAEUTER", "KRAUT");
init_locale(lang);
_snprintf(cmd, sizeof(cmd), "%s KRAUT", itoa36(env.dst->no));
ord = create_order(K_GIVE, lang, cmd);
_snprintf(cmd, sizeof(cmd), "%s %s", itoa36(env.dst->no), LOC(env.f1->locale, parameters[P_HERBS]));
ord = create_order(K_GIVE, env.f1->locale, cmd);
assert(ord);
give_cmd(env.src, ord);
@ -332,7 +320,6 @@ static void test_give_invalid_target(CuTest *tc) {
// bug https://bugs.eressea.de/view.php?id=1685
struct give env;
order *ord;
struct locale * lang;
test_cleanup();
env.f1 = test_create_faction(0);
@ -340,11 +327,7 @@ static void test_give_invalid_target(CuTest *tc) {
setup_give(&env);
i_change(&env.src->items, env.itype, 10);
lang = get_or_create_locale("de");
env.f1->locale = lang;
locale_setstring(lang, "KRAEUTER", "KRAUT");
init_locale(lang);
ord = create_order(K_GIVE, lang, "## KRAUT");
ord = create_order(K_GIVE, env.f1->locale, "## KRAUT");
assert(ord);
give_cmd(env.src, ord);

View File

@ -53,9 +53,7 @@ struct order *ord)
for (n = 0; n != amount; ++n) {
skill *sv = u->skills;
while (sv != u->skills + u->skill_size) {
int i;
for (i = 0; i != 3; ++i)
learn_skill(u, (skill_t)sv->id, 1.0);
learn_skill(u, (skill_t)sv->id, STUDYDAYS * 3);
++sv;
}
}

View File

@ -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, 1.0);
learn_skill(u, SK_ENTERTAINMENT, STUDYDAYS);
pSkill = unit_skill(u, SK_ENTERTAINMENT);
sk_set(pSkill, 5);
initialWeeks_Entertainment = pSkill->weeks = 4;
learn_skill(u, SK_STAMINA, 1.0);
learn_skill(u, SK_STAMINA, STUDYDAYS);
pSkill = unit_skill(u, SK_STAMINA);
sk_set(pSkill, 5);
initialWeeks_Stamina = pSkill->weeks = 4;
learn_skill(u, SK_MAGIC, 1.0);
learn_skill(u, SK_MAGIC, STUDYDAYS);
pSkill = unit_skill(u, SK_MAGIC);
sk_set(pSkill, 5);
initialWeeks_Magic = pSkill->weeks = 4;

View File

@ -34,7 +34,6 @@ static unit * setup_build(build_fixture *bf) {
bf->rc = test_create_race("human");
bf->r = test_create_region(0, 0, 0);
bf->f = test_create_faction(bf->rc);
bf->f->locale = get_or_create_locale("de");
assert(bf->rc && bf->f && bf->r);
bf->u = test_create_unit(bf->f, bf->r);
assert(bf->u);

View File

@ -22,8 +22,7 @@ static void test_read_unitid(CuTest *tc) {
struct terrain_type *t_plain;
test_cleanup();
lang = get_or_create_locale("de");
test_translate_param(lang, P_TEMP, "TEMP");
lang = test_create_locale();
/* note that the english order is FIGHT, not COMBAT, so this is a poor example */
t_plain = test_create_terrain("plain", LAND_REGION);
u = test_create_unit(test_create_faction(0), test_create_region(0, 0, t_plain));
@ -68,8 +67,7 @@ static void test_getunit(CuTest *tc) {
struct terrain_type *t_plain;
test_cleanup();
lang = get_or_create_locale("de");
test_translate_param(lang, P_TEMP, "TEMP");
lang = test_create_locale();
/* note that the english order is FIGHT, not COMBAT, so this is a poor example */
t_plain = test_create_terrain("plain", LAND_REGION);
u = test_create_unit(test_create_faction(0), test_create_region(0, 0, t_plain));

View File

@ -36,7 +36,7 @@ void test_equipment(CuTest * tc)
equipment_setskill(eq, SK_MAGIC, "5");
equipment_addspell(eq, sp, 1);
u = test_create_unit(0, 0);
u = test_create_unit(test_create_faction(0), 0);
equip_unit_mask(u, eq, EQUIP_ALL);
CuAssertIntEquals(tc, 1, i_get(u->items, it_horses));
CuAssertIntEquals(tc, 5, get_level(u, SK_MAGIC));

View File

@ -97,7 +97,7 @@ static void test_addfaction(CuTest *tc) {
test_cleanup();
rc = rc_get_or_create("human");
lang = get_or_create_locale("en");
lang = test_create_locale();
f = addfaction("test@eressea.de", "hurrdurr", rc, lang, 1234);
CuAssertPtrNotNull(tc, f);
CuAssertPtrNotNull(tc, f->name);

View File

@ -64,7 +64,7 @@ void test_change_item(CuTest * tc)
test_create_itemtype("iron");
init_resources();
u = test_create_unit(0, 0);
u = test_create_unit(test_create_faction(0), 0);
test_uchange(tc, u, get_resourcetype(R_IRON));
}

View File

@ -638,7 +638,7 @@ int rhorses(const region * r)
void rsetmoney(region * r, int value)
{
assert(r->land || value==0);
assert(r && (r->land || value==0));
assert(value >= 0);
if (r->land) {
r->land->money = value;

View File

@ -206,7 +206,7 @@ int level(int days)
void sk_set(skill * sv, int level)
{
assert(level != 0);
assert(sv && level != 0);
sv->weeks = skill_weeks(level);
sv->level = level;
}

View File

@ -45,9 +45,6 @@ extern "C" {
fumble_f fumble;
} spell;
int use_item_power(struct region *r, struct unit *u);
int use_item_regeneration(struct region *r, struct unit *u);
void showspells(struct region *r, struct unit *u);
int sp_antimagiczone(struct castorder *co);
struct spell * create_spell(const char * name, unsigned int id);

View File

@ -213,18 +213,16 @@ static void test_display_cmd(CuTest *tc) {
test_cleanup();
r = test_create_region(0, 0, test_create_terrain("plain", LAND_REGION));
f = test_create_faction(0);
f->locale = get_or_create_locale("de");
assert(r && f);
test_translate_param(f->locale, P_UNIT, "EINHEIT");
u = test_create_unit(f, r);
assert(u);
ord = create_order(K_DISPLAY, f->locale, "EINHEIT Hodor");
ord = create_order(K_DISPLAY, f->locale, "%s Hodor", LOC(f->locale, parameters[P_UNIT]));
CuAssertIntEquals(tc, 0, display_cmd(u, ord));
CuAssertStrEquals(tc, "Hodor", u->display);
free_order(ord);
ord = create_order(K_DISPLAY, f->locale, "EINHEIT");
ord = create_order(K_DISPLAY, f->locale, LOC(f->locale, parameters[P_UNIT]));
CuAssertIntEquals(tc, 0, display_cmd(u, ord));
CuAssertPtrEquals(tc, NULL, u->display);
free_order(ord);
@ -779,34 +777,27 @@ static void test_luck_message(CuTest *tc) {
static unit * setup_name_cmd(void) {
faction *f;
struct locale *lang;
test_cleanup();
f = test_create_faction(0);
f->locale = lang = get_or_create_locale("en");
locale_setstring(lang, parameters[P_UNIT], "UNIT");
locale_setstring(lang, parameters[P_REGION], "REGION");
locale_setstring(lang, parameters[P_FACTION], "FACTION");
locale_setstring(lang, parameters[P_BUILDING], "BUILDING");
locale_setstring(lang, parameters[P_SHIP], "SHIP");
init_parameters(lang);
return test_create_unit(f, test_create_region(0, 0, 0));
}
static void test_name_unit(CuTest *tc) {
unit *u;
faction *f;
order *ord;
u = setup_name_cmd();
ord = create_order(K_NAME, u->faction->locale, "UNIT Hodor");
f = u->faction;
ord = create_order(K_NAME, f->locale, "%s Hodor", LOC(f->locale, parameters[P_UNIT]));
name_cmd(u, ord);
CuAssertStrEquals(tc, "Hodor", u->_name);
free_order(ord);
ord = create_order(K_NAME, u->faction->locale, "UNIT");
ord = create_order(K_NAME, f->locale, LOC(f->locale, parameters[P_UNIT]));
name_cmd(u, ord);
CuAssertPtrNotNull(tc, test_find_messagetype(u->faction->msgs, "error84"));
CuAssertPtrNotNull(tc, test_find_messagetype(f->msgs, "error84"));
CuAssertStrEquals(tc, "Hodor", u->_name);
free_order(ord);
@ -815,22 +806,24 @@ static void test_name_unit(CuTest *tc) {
static void test_name_region(CuTest *tc) {
unit *u;
faction *f;
order *ord;
u = setup_name_cmd();
f = u->faction;
ord = create_order(K_NAME, u->faction->locale, "REGION Hodor");
ord = create_order(K_NAME, f->locale, "%s Hodor", LOC(f->locale, parameters[P_REGION]));
name_cmd(u, ord);
CuAssertPtrNotNull(tc, test_find_messagetype(u->faction->msgs, "error145"));
CuAssertPtrNotNull(tc, test_find_messagetype(f->msgs, "error145"));
u->building = test_create_building(u->region, 0);
name_cmd(u, ord);
CuAssertStrEquals(tc, "Hodor", u->region->land->name);
free_order(ord);
ord = create_order(K_NAME, u->faction->locale, "REGION");
ord = create_order(K_NAME, f->locale, LOC(f->locale, parameters[P_REGION]));
name_cmd(u, ord);
CuAssertPtrNotNull(tc, test_find_messagetype(u->faction->msgs, "error84"));
CuAssertPtrNotNull(tc, test_find_messagetype(f->msgs, "error84"));
CuAssertStrEquals(tc, "Hodor", u->region->land->name);
free_order(ord);
@ -839,22 +832,24 @@ static void test_name_region(CuTest *tc) {
static void test_name_building(CuTest *tc) {
unit *u;
faction *f;
order *ord;
u = setup_name_cmd();
f = u->faction;
ord = create_order(K_NAME, u->faction->locale, "BUILDING Hodor");
ord = create_order(K_NAME, f->locale, "%s Hodor", LOC(f->locale, parameters[P_BUILDING]));
name_cmd(u, ord);
CuAssertPtrNotNull(tc, test_find_messagetype(u->faction->msgs, "error145"));
CuAssertPtrNotNull(tc, test_find_messagetype(f->msgs, "error145"));
u->building = test_create_building(u->region, 0);
name_cmd(u, ord);
CuAssertStrEquals(tc, "Hodor", u->building->name);
free_order(ord);
ord = create_order(K_NAME, u->faction->locale, "BUILDING");
ord = create_order(K_NAME, f->locale, LOC(f->locale, parameters[P_BUILDING]));
name_cmd(u, ord);
CuAssertPtrNotNull(tc, test_find_messagetype(u->faction->msgs, "error84"));
CuAssertPtrNotNull(tc, test_find_messagetype(f->msgs, "error84"));
CuAssertStrEquals(tc, "Hodor", u->building->name);
free_order(ord);
@ -868,19 +863,21 @@ static void test_name_building(CuTest *tc) {
static void test_name_ship(CuTest *tc) {
unit *u;
faction *f;
order *ord;
u = setup_name_cmd();
f = u->faction;
u->ship = test_create_ship(u->region, 0);
ord = create_order(K_NAME, u->faction->locale, "SHIP Hodor");
ord = create_order(K_NAME, f->locale, "%s Hodor", LOC(f->locale, parameters[P_SHIP]));
name_cmd(u, ord);
CuAssertStrEquals(tc, "Hodor", u->ship->name);
free_order(ord);
ord = create_order(K_NAME, u->faction->locale, "SHIP");
ord = create_order(K_NAME, f->locale, LOC(f->locale, parameters[P_SHIP]));
name_cmd(u, ord);
CuAssertPtrNotNull(tc, test_find_messagetype(u->faction->msgs, "error84"));
CuAssertPtrNotNull(tc, test_find_messagetype(f->msgs, "error84"));
CuAssertStrEquals(tc, "Hodor", u->ship->name);
free_order(ord);
@ -896,7 +893,6 @@ static void test_long_order_normal(CuTest *tc) {
u = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0));
fset(u, UFL_MOVED);
fset(u, UFL_LONGACTION);
u->faction->locale = get_or_create_locale("de");
unit_addorder(u, ord = create_order(K_MOVE, u->faction->locale, 0));
update_long_order(u);
CuAssertPtrEquals(tc, ord->data, u->thisorder->data);
@ -913,7 +909,6 @@ static void test_long_order_none(CuTest *tc) {
unit *u;
test_cleanup();
u = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0));
u->faction->locale = get_or_create_locale("de");
update_long_order(u);
CuAssertPtrEquals(tc, 0, u->thisorder);
CuAssertPtrEquals(tc, 0, u->orders);
@ -926,7 +921,6 @@ static void test_long_order_cast(CuTest *tc) {
unit *u;
test_cleanup();
u = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0));
u->faction->locale = get_or_create_locale("de");
unit_addorder(u, create_order(K_CAST, u->faction->locale, 0));
unit_addorder(u, create_order(K_CAST, u->faction->locale, 0));
update_long_order(u);
@ -941,7 +935,6 @@ static void test_long_order_buy_sell(CuTest *tc) {
unit *u;
test_cleanup();
u = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0));
u->faction->locale = get_or_create_locale("de");
unit_addorder(u, create_order(K_BUY, u->faction->locale, 0));
unit_addorder(u, create_order(K_SELL, u->faction->locale, 0));
unit_addorder(u, create_order(K_SELL, u->faction->locale, 0));
@ -957,7 +950,6 @@ static void test_long_order_multi_long(CuTest *tc) {
unit *u;
test_cleanup();
u = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0));
u->faction->locale = get_or_create_locale("de");
unit_addorder(u, create_order(K_MOVE, u->faction->locale, 0));
unit_addorder(u, create_order(K_DESTROY, u->faction->locale, 0));
update_long_order(u);
@ -972,7 +964,6 @@ static void test_long_order_multi_buy(CuTest *tc) {
unit *u;
test_cleanup();
u = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0));
u->faction->locale = get_or_create_locale("de");
unit_addorder(u, create_order(K_BUY, u->faction->locale, 0));
unit_addorder(u, create_order(K_BUY, u->faction->locale, 0));
update_long_order(u);
@ -987,7 +978,6 @@ static void test_long_order_multi_sell(CuTest *tc) {
unit *u;
test_cleanup();
u = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0));
u->faction->locale = get_or_create_locale("de");
unit_addorder(u, create_order(K_SELL, u->faction->locale, 0));
unit_addorder(u, create_order(K_BUY, u->faction->locale, 0));
unit_addorder(u, create_order(K_SELL, u->faction->locale, 0));
@ -1003,7 +993,6 @@ static void test_long_order_buy_cast(CuTest *tc) {
unit *u;
test_cleanup();
u = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0));
u->faction->locale = get_or_create_locale("de");
unit_addorder(u, create_order(K_BUY, u->faction->locale, 0));
unit_addorder(u, create_order(K_CAST, u->faction->locale, 0));
update_long_order(u);
@ -1021,7 +1010,6 @@ static void test_long_order_hungry(CuTest *tc) {
config_set("hunger.long", "1");
u = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0));
fset(u, UFL_HUNGER);
u->faction->locale = get_or_create_locale("de");
unit_addorder(u, create_order(K_MOVE, u->faction->locale, 0));
unit_addorder(u, create_order(K_DESTROY, u->faction->locale, 0));
set_default_order(K_WORK);
@ -1040,7 +1028,6 @@ static void test_ally_cmd_errors(CuTest *tc) {
test_cleanup();
u = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0));
u->faction->locale = get_or_create_locale("de");
fid = u->faction->no + 1;
CuAssertPtrEquals(tc, 0, findfaction(fid));
@ -1056,36 +1043,30 @@ static void test_ally_cmd(CuTest *tc) {
unit *u;
faction * f;
order *ord;
struct locale *lang;
test_cleanup();
u = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0));
f = test_create_faction(0);
u->faction->locale = lang = get_or_create_locale("de");
locale_setstring(lang, parameters[P_NOT], "NICHT");
locale_setstring(lang, parameters[P_GUARD], "BEWACHE");
init_parameters(lang);
ord = create_order(K_ALLY, lang, "%s", itoa36(f->no));
ord = create_order(K_ALLY, f->locale, "%s", itoa36(f->no));
ally_cmd(u, ord);
CuAssertPtrEquals(tc, 0, u->faction->msgs);
CuAssertIntEquals(tc, HELP_ALL, alliedfaction(0, u->faction, f, HELP_ALL));
free_order(ord);
ord = create_order(K_ALLY, lang, "%s NICHT", itoa36(f->no));
ord = create_order(K_ALLY, f->locale, "%s %s", itoa36(f->no), LOC(f->locale, parameters[P_NOT]));
ally_cmd(u, ord);
CuAssertPtrEquals(tc, 0, u->faction->msgs);
CuAssertIntEquals(tc, 0, alliedfaction(0, u->faction, f, HELP_ALL));
free_order(ord);
ord = create_order(K_ALLY, lang, "%s BEWACHE", itoa36(f->no));
ord = create_order(K_ALLY, f->locale, "%s %s", itoa36(f->no), LOC(f->locale, parameters[P_GUARD]));
ally_cmd(u, ord);
CuAssertPtrEquals(tc, 0, u->faction->msgs);
CuAssertIntEquals(tc, HELP_GUARD, alliedfaction(0, u->faction, f, HELP_ALL));
free_order(ord);
ord = create_order(K_ALLY, lang, "%s BEWACHE NICHT", itoa36(f->no));
ord = create_order(K_ALLY, f->locale, "%s %s %s", itoa36(f->no), LOC(f->locale, parameters[P_GUARD]), LOC(f->locale, parameters[P_NOT]));
ally_cmd(u, ord);
CuAssertPtrEquals(tc, 0, u->faction->msgs);
CuAssertIntEquals(tc, 0, alliedfaction(0, u->faction, f, HELP_ALL));
@ -1116,26 +1097,22 @@ static void test_nmr_warnings(CuTest *tc) {
static unit * setup_mail_cmd(void) {
faction *f;
struct locale *lang;
test_cleanup();
f = test_create_faction(0);
f->locale = lang = get_or_create_locale("de");
locale_setstring(lang, parameters[P_UNIT], "EINHEIT");
locale_setstring(lang, parameters[P_REGION], "REGION");
locale_setstring(lang, parameters[P_FACTION], "PARTEI");
init_parameters(lang);
return test_create_unit(f, test_create_region(0, 0, 0));
}
static void test_mail_unit(CuTest *tc) {
order *ord;
unit *u;
faction *f;
u = setup_mail_cmd();
ord = create_order(K_MAIL, u->faction->locale, "EINHEIT %s 'Hodor!'", itoa36(u->no));
f = u->faction;
ord = create_order(K_MAIL, f->locale, "%s %s 'Hodor!'", LOC(f->locale, parameters[P_UNIT]), itoa36(u->no));
mail_cmd(u, ord);
CuAssertPtrNotNull(tc, test_find_messagetype(u->faction->msgs, "unitmessage"));
CuAssertPtrNotNull(tc, test_find_messagetype(f->msgs, "unitmessage"));
free_order(ord);
test_cleanup();
}
@ -1143,11 +1120,13 @@ static void test_mail_unit(CuTest *tc) {
static void test_mail_faction(CuTest *tc) {
order *ord;
unit *u;
faction *f;
u = setup_mail_cmd();
ord = create_order(K_MAIL, u->faction->locale, "PARTEI %s 'Hodor!'", itoa36(u->faction->no));
f = u->faction;
ord = create_order(K_MAIL, f->locale, "%s %s 'Hodor!'", LOC(f->locale, parameters[P_FACTION]), itoa36(u->faction->no));
mail_cmd(u, ord);
CuAssertPtrNotNull(tc, test_find_messagetype(u->faction->msgs, "regionmessage"));
CuAssertPtrNotNull(tc, test_find_messagetype(f->msgs, "regionmessage"));
free_order(ord);
test_cleanup();
}
@ -1155,9 +1134,11 @@ static void test_mail_faction(CuTest *tc) {
static void test_mail_region(CuTest *tc) {
order *ord;
unit *u;
faction *f;
u = setup_mail_cmd();
ord = create_order(K_MAIL, u->faction->locale, "REGION 'Hodor!'", itoa36(u->no));
f = u->faction;
ord = create_order(K_MAIL, f->locale, "%s 'Hodor!'", LOC(f->locale, parameters[P_REGION]), itoa36(u->no));
mail_cmd(u, ord);
CuAssertPtrNotNull(tc, test_find_messagetype(u->region->msgs, "mail_result"));
free_order(ord);
@ -1166,52 +1147,60 @@ static void test_mail_region(CuTest *tc) {
static void test_mail_unit_no_msg(CuTest *tc) {
unit *u;
faction *f;
order *ord;
u = setup_mail_cmd();
ord = create_order(K_MAIL, u->faction->locale, "EINHEIT %s", itoa36(u->no));
f = u->faction;
ord = create_order(K_MAIL, f->locale, "%s %s", LOC(f->locale, parameters[P_UNIT]), itoa36(u->no));
mail_cmd(u, ord);
CuAssertPtrEquals(tc, 0, test_find_messagetype(u->faction->msgs, "unitmessage"));
CuAssertPtrNotNull(tc, test_find_messagetype(u->faction->msgs, "error30"));
CuAssertPtrEquals(tc, 0, test_find_messagetype(f->msgs, "unitmessage"));
CuAssertPtrNotNull(tc, test_find_messagetype(f->msgs, "error30"));
free_order(ord);
test_cleanup();
}
static void test_mail_faction_no_msg(CuTest *tc) {
unit *u;
faction *f;
order *ord;
u = setup_mail_cmd();
ord = create_order(K_MAIL, u->faction->locale, "PARTEI %s", itoa36(u->faction->no));
f = u->faction;
ord = create_order(K_MAIL, f->locale, "%s %s", LOC(f->locale, parameters[P_FACTION]), itoa36(f->no));
mail_cmd(u, ord);
CuAssertPtrEquals(tc, 0, test_find_messagetype(u->faction->msgs, "regionmessage"));
CuAssertPtrNotNull(tc, test_find_messagetype(u->faction->msgs, "error30"));
CuAssertPtrEquals(tc, 0, test_find_messagetype(f->msgs, "regionmessage"));
CuAssertPtrNotNull(tc, test_find_messagetype(f->msgs, "error30"));
free_order(ord);
test_cleanup();
}
static void test_mail_faction_no_target(CuTest *tc) {
unit *u;
faction *f;
order *ord;
u = setup_mail_cmd();
ord = create_order(K_MAIL, u->faction->locale, "PARTEI %s", itoa36(u->faction->no+1));
f = u->faction;
ord = create_order(K_MAIL, f->locale, "%s %s", LOC(f->locale, parameters[P_FACTION]), itoa36(f->no+1));
mail_cmd(u, ord);
CuAssertPtrEquals(tc, 0, test_find_messagetype(u->faction->msgs, "regionmessage"));
CuAssertPtrNotNull(tc, test_find_messagetype(u->faction->msgs, "error66"));
CuAssertPtrEquals(tc, 0, test_find_messagetype(f->msgs, "regionmessage"));
CuAssertPtrNotNull(tc, test_find_messagetype(f->msgs, "error66"));
free_order(ord);
test_cleanup();
}
static void test_mail_region_no_msg(CuTest *tc) {
unit *u;
faction *f;
order *ord;
u = setup_mail_cmd();
ord = create_order(K_MAIL, u->faction->locale, "REGION");
f = u->faction;
ord = create_order(K_MAIL, f->locale, LOC(f->locale, parameters[P_REGION]));
mail_cmd(u, ord);
CuAssertPtrEquals(tc, 0, test_find_messagetype(u->region->msgs, "mail_result"));
CuAssertPtrNotNull(tc, test_find_messagetype(u->faction->msgs, "error30"));
CuAssertPtrNotNull(tc, test_find_messagetype(f->msgs, "error30"));
free_order(ord);
test_cleanup();
}
@ -1236,27 +1225,27 @@ static void test_show_without_item(CuTest *tc)
f = test_create_faction(test_create_race("human"));
u = test_create_unit(f, r);
ord = create_order(K_RESHOW, u->faction->locale, "testname");
ord = create_order(K_RESHOW, f->locale, "testname");
itype = it_get_or_create(rt_get_or_create("testitem"));
i = i_new(itype, 1);
reshow_cmd(u, ord);
CuAssertTrue(tc, test_find_messagetype(u->faction->msgs, "error21") != NULL);
test_clear_messages(u->faction);
CuAssertTrue(tc, test_find_messagetype(f->msgs, "error21") != NULL);
test_clear_messages(f);
locale_setstring(loc, "testitem", "testname");
locale_setstring(loc, "iteminfo::testitem", "testdescription");
reshow_cmd(u, ord);
CuAssertTrue(tc, test_find_messagetype(u->faction->msgs, "error21") == NULL);
CuAssertTrue(tc, test_find_messagetype(u->faction->msgs, "error36") != NULL);
test_clear_messages(u->faction);
CuAssertTrue(tc, test_find_messagetype(f->msgs, "error21") == NULL);
CuAssertTrue(tc, test_find_messagetype(f->msgs, "error36") != NULL);
test_clear_messages(f);
i_add(&(u->items), i);
reshow_cmd(u, ord);
CuAssertTrue(tc, test_find_messagetype(u->faction->msgs, "error21") == NULL);
CuAssertTrue(tc, test_find_messagetype(u->faction->msgs, "error36") == NULL);
test_clear_messages(u->faction);
CuAssertTrue(tc, test_find_messagetype(f->msgs, "error21") == NULL);
CuAssertTrue(tc, test_find_messagetype(f->msgs, "error36") == NULL);
test_clear_messages(f);
free_order(ord);
test_cleanup();

View File

@ -387,12 +387,11 @@ void test_multi_cast(CuTest *tc) {
sp->cast = cast_fireball;
CuAssertPtrEquals(tc, sp, find_spell("fireball"));
u = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0));
u->faction->locale = lang = get_or_create_locale("de");
locale_setstring(lang, parameters[P_ANY], "ALLE");
init_parameters(lang);
lang = test_create_locale();
locale_setstring(lang, mkname("spell", sp->sname), "Feuerball");
CuAssertStrEquals(tc, "Feuerball", spell_name(sp, lang));
u = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0));
set_level(u, SK_MAGIC, 10);
unit_add_spell(u, 0, sp, 1);
CuAssertPtrEquals(tc, sp, unit_getspell(u, "Feuerball", lang));

View File

@ -26,56 +26,26 @@
extern void plan_monsters(struct faction *f);
extern int monster_attacks(unit * monster, bool respect_buildings, bool rich_only);
static void init_language(void)
{
struct locale* lang;
int i;
lang = get_or_create_locale("de");
locale_setstring(lang, "skill::unarmed", "Waffenloser Kampf");
locale_setstring(lang, "keyword::attack", "ATTACKIERE");
locale_setstring(lang, "keyword::study", "LERNE");
locale_setstring(lang, "keyword::tax", "TREIBE");
locale_setstring(lang, "keyword::loot", "PLUENDERE");
locale_setstring(lang, "keyword::piracy", "PIRATERIE");
locale_setstring(lang, "keyword::guard", "BEWACHE");
locale_setstring(lang, "keyword::move", "NACH");
locale_setstring(lang, "keyword::message", "BOTSCHAFT");
locale_setstring(lang, "REGION", "REGION");
locale_setstring(lang, "east", "O");
for (i = 0; i < MAXKEYWORDS; ++i) {
if (!locale_getstring(lang, mkname("keyword", keywords[i])))
locale_setstring(lang, mkname("keyword", keywords[i]), keywords[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_keywords(lang);
init_skills(lang);
}
static order *find_order(const char *expected, const unit *unit)
{
char cmd[32];
order *order;
for (order = unit->orders; order; order = order->next) {
if (strcmp(expected, get_command(order, cmd, sizeof(cmd))) == 0) {
return order;
order *ord;
for (ord = unit->orders; ord; ord = ord->next) {
if (strcmp(expected, get_command(ord, cmd, sizeof(cmd))) == 0) {
return ord;
}
}
return NULL;
}
static void create_monsters(faction **player, faction **monsters, region **r, unit **u, unit **m) {
static void create_monsters(faction **player, faction **monsters, unit **u, unit **m) {
race* rc;
region *r;
test_cleanup();
init_language();
test_create_world();
test_create_horse();
default_locale = test_create_locale();
*player = test_create_faction(NULL);
*monsters = get_or_create_monsters();
assert(rc_find((*monsters)->race->_name));
@ -84,22 +54,22 @@ static void create_monsters(faction **player, faction **monsters, region **r, un
fset(rc, RCF_NPC);
fset(*monsters, FFL_NOIDLEOUT);
assert(fval(*monsters, FFL_NPC) && fval((*monsters)->race, RCF_UNARMEDGUARD) && fval((*monsters)->race, RCF_NPC) && fval(*monsters, FFL_NOIDLEOUT));
(*monsters)->locale = default_locale;
*r = findregion(0, 0);
test_create_region(-1, 0, test_create_terrain("ocean", SEA_REGION | SAIL_INTO | SWIM_INTO | FLY_INTO));
test_create_region(1, 0, 0);
r = test_create_region(0, 0, 0);
*u = test_create_unit(*player, *r);
*u = test_create_unit(*player, r);
unit_setid(*u, 1);
*m = test_create_unit(*monsters, *r);
*m = test_create_unit(*monsters, r);
}
static void test_monsters_attack(CuTest * tc)
{
faction *f, *f2;
region *r;
unit *u, *m;
create_monsters(&f, &f2, &r, &u, &m);
create_monsters(&f, &f2, &u, &m);
guard(m, GUARD_TAX);
@ -107,7 +77,7 @@ static void test_monsters_attack(CuTest * tc)
plan_monsters(f2);
CuAssertPtrNotNull(tc, find_order("ATTACKIERE 1", m));
CuAssertPtrNotNull(tc, find_order("attack 1", m));
test_cleanup();
}
@ -117,8 +87,8 @@ static void test_monsters_attack_ocean(CuTest * tc)
region *r;
unit *u, *m;
create_monsters(&f, &f2, &r, &u, &m);
r = findregion(-1, 0);
create_monsters(&f, &f2, &u, &m);
r = findregion(-1, 0); // ocean
u = test_create_unit(u->faction, r);
unit_setid(u, 2);
m = test_create_unit(m->faction, r);
@ -128,21 +98,20 @@ static void test_monsters_attack_ocean(CuTest * tc)
plan_monsters(f2);
CuAssertPtrNotNull(tc, find_order("ATTACKIERE 2", m));
CuAssertPtrNotNull(tc, find_order("attack 2", m));
test_cleanup();
}
static void test_monsters_waiting(CuTest * tc)
{
faction *f, *f2;
region *r;
unit *u, *m;
create_monsters(&f, &f2, &r, &u, &m);
create_monsters(&f, &f2, &u, &m);
guard(m, GUARD_TAX);
fset(m, UFL_ISNEW);
monster_attacks(m, false, false);
CuAssertPtrEquals(tc, 0, find_order("ATTACKIERE 1", m));
CuAssertPtrEquals(tc, 0, find_order("attack 1", m));
test_cleanup();
}
@ -153,8 +122,8 @@ static void test_seaserpent_piracy(CuTest * tc)
unit *u, *m;
race *rc;
create_monsters(&f, &f2, &r, &u, &m);
r = findregion(-1, 0);
create_monsters(&f, &f2, &u, &m);
r = findregion(-1, 0); // ocean
u = test_create_unit(u->faction, r);
unit_setid(u, 2);
m = test_create_unit(m->faction, r);
@ -166,18 +135,17 @@ static void test_seaserpent_piracy(CuTest * tc)
config_set("rules.monsters.attack_chance", "1");
plan_monsters(f2);
CuAssertPtrNotNull(tc, find_order("PIRATERIE", m));
CuAssertPtrNotNull(tc, find_order("ATTACKIERE 2", m));
CuAssertPtrNotNull(tc, find_order("piracy", m));
CuAssertPtrNotNull(tc, find_order("attack 2", m));
test_cleanup();
}
static void test_monsters_attack_not(CuTest * tc)
{
faction *f, *f2;
region *r;
unit *u, *m;
create_monsters(&f, &f2, &r, &u, &m);
create_monsters(&f, &f2, &u, &m);
guard(m, GUARD_TAX);
guard(u, GUARD_TAX);
@ -186,24 +154,23 @@ static void test_monsters_attack_not(CuTest * tc)
plan_monsters(f2);
CuAssertPtrEquals(tc, 0, find_order("ATTACKIERE 1", m));
CuAssertPtrEquals(tc, 0, find_order("attack 1", m));
test_cleanup();
}
static void test_dragon_attacks_the_rich(CuTest * tc)
{
faction *f, *f2;
region *r;
unit *u, *m;
const item_type *i_silver;
init_language();
create_monsters(&f, &f2, &r, &u, &m);
create_monsters(&f, &f2, &u, &m);
init_resources();
guard(m, GUARD_TAX);
set_level(m, SK_WEAPONLESS, 10);
rsetmoney(r, 1);
rsetmoney(findregion(0, 0), 1);
rsetmoney(findregion(1, 0), 0);
i_silver = it_find("money");
assert(i_silver);
@ -213,8 +180,8 @@ static void test_dragon_attacks_the_rich(CuTest * tc)
plan_monsters(f2);
CuAssertPtrNotNull(tc, find_order("ATTACKIERE 1", m));
CuAssertPtrNotNull(tc, find_order("PLUENDERE", m));
CuAssertPtrNotNull(tc, find_order("attack 1", m));
CuAssertPtrNotNull(tc, find_order("loot", m));
test_cleanup();
}
@ -224,28 +191,28 @@ static void test_dragon_moves(CuTest * tc)
region *r;
unit *u, *m;
create_monsters(&f, &f2, &r, &u, &m);
create_monsters(&f, &f2, &u, &m);
rsetmoney(findregion(1, 0), 1000);
r = findregion(0, 0); // plain
rsetpeasants(r, 0);
rsetmoney(r, 0);
rsetmoney(findregion(1, 0), 1000);
set_level(m, SK_WEAPONLESS, 10);
config_set("rules.monsters.attack_chance", ".0");
plan_monsters(f2);
CuAssertPtrNotNull(tc, find_order("NACH O", m));
CuAssertPtrNotNull(tc, find_order("move east", m));
test_cleanup();
}
static void test_monsters_learn_exp(CuTest * tc)
{
faction *f, *f2;
region *r;
unit *u, *m;
skill* sk;
create_monsters(&f, &f2, &r, &u, &m);
config_set("study.from_use", "1");
create_monsters(&f, &f2, &u, &m);
config_set("study.produceexp", "30");
u_setrace(u, u_race(m));
produceexp(u, SK_MELEE, u->number);

View File

@ -284,7 +284,6 @@ struct drift_fixture {
unit *u;
terrain_type *t_ocean;
ship_type *st_boat;
struct locale *lang;
ship *sh;
};
@ -292,7 +291,6 @@ struct drift_fixture {
void setup_drift (struct drift_fixture *fix) {
test_cleanup();
config_set("rules.ship.storms", "0");
fix->lang = get_or_create_locale("de");
test_create_world();
test_create_shiptype("drifter");
@ -304,8 +302,6 @@ void setup_drift (struct drift_fixture *fix) {
set_level(fix->u, SK_SAILING, fix->st_boat->sumskill);
u_set_ship(fix->u, fix->sh = test_create_ship(fix->u->region, fix->st_boat));
assert(fix->f && fix->u && fix->sh);
fix->f->locale = get_or_create_locale("de");
}
static void test_ship_no_overload(CuTest *tc) {
@ -460,7 +456,6 @@ static void test_follow_ship_msg(CuTest * tc) {
const ship_type *stype;
message *msg;
order *ord;
traveldir *td = NULL;
attrib *a;
@ -488,10 +483,6 @@ static void test_follow_ship_msg(CuTest * tc) {
td->dir = D_NORTHWEST;
td->age = 2;
locale_setstring(default_locale, "northwest", "Nordwesten");
locale_setstring(default_locale, "keyword::move", "NACH");
init_locale(default_locale);
mt_register(mt_new_va("error18", "unit:unit", "region:region", "command:order", 0));
init_order(ord);

View File

@ -151,22 +151,17 @@ static void dissolve_units(void)
remove_empty_units();
}
static int improve_all(faction * f, skill_t sk, int by_weeks)
static bool improve_all(faction * f, skill_t sk, int by_weeks)
{
unit *u;
bool ret = by_weeks;
bool result = false;
for (u = f->units; u; u = u->nextF) {
if (has_skill(u, sk)) {
int weeks = 0;
for (; weeks != by_weeks; ++weeks) {
learn_skill(u, sk, 1.0);
ret = 0;
learn_skill(u, sk, by_weeks * STUDYDAYS);
result = true;
}
}
}
return ret;
return result;
}
void find_manual(region * r, unit * u)
@ -247,10 +242,8 @@ void find_manual(region * r, unit * u)
msg_release(msg);
}
if (improve_all(u->faction, skill, 3) == 3) {
int i;
for (i = 0; i != 9; ++i)
learn_skill(u, skill, 1.0);
if (!improve_all(u->faction, skill, 3)) {
learn_skill(u, skill, 9 * STUDYDAYS);
}
}
@ -958,38 +951,7 @@ static void demon_skillchanges(void)
unit *u;
for (u = r->units; u; u = u->next) {
if (u_race(u) == get_race(RC_DAEMON)) {
skill *sv = u->skills;
int upchance = 15;
int downchance = 10;
if (fval(u, UFL_HUNGER)) {
/* hungry demons only go down, never up in skill */
int rule_hunger = config_get_int("hunger.demons.skill", 0) != 0;
if (rule_hunger) {
upchance = 0;
downchance = 15;
}
}
while (sv != u->skills + u->skill_size) {
int roll = rng_int() % 100;
if (sv->level > 0 && roll < upchance + downchance) {
int weeks = 1 + rng_int() % 3;
if (roll < downchance) {
reduce_skill(u, sv, weeks);
if (sv->level < 1) {
/* demons should never forget below 1 */
set_level(u, sv->id, 1);
}
}
else {
while (weeks--) {
learn_skill(u, sv->id, 1.0);
}
}
}
++sv;
}
demon_skillchange(u);
}
}
}

View File

@ -280,7 +280,7 @@ int teach_cmd(unit * u, struct order *ord)
static const curse_type *gbdream_ct = NULL;
plane *pl;
region *r = u->region;
skill_t sk = NOSKILL;
skill_t sk_academy = NOSKILL;
int teaching, i, j, count, academy = 0;
if (gbdream_ct == 0)
@ -322,6 +322,7 @@ int teach_cmd(unit * u, struct order *ord)
#if TEACH_ALL
if (getparam(u->faction->locale) == P_ANY) {
skill_t sk;
unit *student;
skill_t teachskill[MAXSKILLS];
int t = 0;
@ -380,6 +381,7 @@ int teach_cmd(unit * u, struct order *ord)
init_order(ord);
while (!parser_end()) {
skill_t sk;
unit *u2;
bool feedback;
@ -472,15 +474,15 @@ int teach_cmd(unit * u, struct order *ord)
continue;
}
}
sk_academy = sk;
teaching -= teach_unit(u, u2, teaching, sk, false, &academy);
}
new_order = create_order(K_TEACH, u->faction->locale, "%s", zOrder);
replace_order(&u->orders, ord, new_order);
free_order(new_order); /* parse_order & set_order have each increased the refcount */
}
if (academy) {
academy_teaching_bonus(u, sk, academy);
if (academy && sk_academy!=NOSKILL) {
academy_teaching_bonus(u, sk_academy, academy);
}
return 0;
}
@ -738,17 +740,7 @@ int study_cmd(unit * u, order * ord)
if (fval(u, UFL_HUNGER))
days /= 2;
while (days) {
if (days >= u->number * 30) {
learn_skill(u, sk, 1.0);
days -= u->number * 30;
}
else {
double chance = (double)days / u->number / 30;
learn_skill(u, sk, chance);
days = 0;
}
}
learn_skill(u, sk, days);
if (a != NULL) {
int index = 0;
while (teach->teachers[index] && index != MAXTEACHERS) {
@ -800,17 +792,16 @@ int study_cmd(unit * u, order * ord)
return 0;
}
static double produceexp_chance(void) {
return config_get_flt("study.from_use", 1.0 / 3);
static int produceexp_days(void) {
return config_get_int("study.produceexp", 10);
}
void produceexp_ex(struct unit *u, skill_t sk, int n, bool(*learn)(unit *, skill_t, double))
void produceexp_ex(struct unit *u, skill_t sk, int n, learn_fun learn)
{
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);
}
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);
}
}
@ -826,32 +817,67 @@ 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;
void learn_skill(unit *u, skill_t sk, int days) {
int leveldays = STUDYDAYS * u->number;
int weeks = 0;
#ifndef NO_TESTS
if (inject_learn_fun) {
return inject_learn_fun(u, sk, learn_chance);
inject_learn_fun(u, sk, days);
return;
}
#endif
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) {
while (days >= leveldays) {
++weeks;
days -= leveldays;
}
if (days > 0 && rng_int() % leveldays < days) {
++weeks;
}
if (weeks > 0) {
skill *sv = unit_skill(u, sk);
if (!sv) {
sv = add_skill(u, sk);
}
while (sv->weeks <= weeks) {
weeks -= sv->weeks;
sk_set(sv, sv->level + 1);
}
else {
sv->weeks--;
sv->weeks -= weeks;
}
}
/** Talente von Dämonen verschieben sich.
*/
void demon_skillchange(unit *u)
{
skill *sv = u->skills;
int upchance = 15;
int downchance = 10;
if (fval(u, UFL_HUNGER)) {
/* hungry demons only go down, never up in skill */
int rule_hunger = config_get_int("hunger.demon.skill", 0) != 0;
if (rule_hunger) {
upchance = 0;
downchance = 15;
}
}
while (sv != u->skills + u->skill_size) {
int roll = rng_int() % 100;
if (sv->level > 0 && roll < upchance + downchance) {
int weeks = 1 + rng_int() % 3;
if (roll < downchance) {
reduce_skill(u, sv, weeks);
if (sv->level < 1) {
/* demons should never forget below 1 */
set_level(u, sv->id, 1);
}
}
else {
learn_skill(u, sv->id, STUDYDAYS*weeks);
}
return true;
}
++sv;
}
sv = add_skill(u, sk);
sk_set(sv, 1);
return true;
}

View File

@ -35,14 +35,16 @@ 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);
typedef void(*learn_fun)(struct unit *u, skill_t sk, int days);
#define STUDYDAYS 30
void learn_skill(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, bool(*learn)(struct unit *, skill_t, double));
void produceexp_ex(struct unit *u, skill_t sk, int n, learn_fun learn);
void demon_skillchange(struct unit *u);
#define MAXTEACHERS 20
#define TEACHNUMBER 10
typedef struct teaching_info {
@ -52,6 +54,9 @@ extern "C" {
extern const struct attrib_type at_learning;
#ifndef NO_TESTS
void inject_learn(learn_fun fun);
#endif
#ifdef __cplusplus
}

View File

@ -3,12 +3,13 @@
#include "study.h"
#include <kernel/config.h>
#include <kernel/unit.h>
#include <kernel/building.h>
#include <kernel/faction.h>
#include <kernel/item.h>
#include <kernel/order.h>
#include <kernel/race.h>
#include <kernel/region.h>
#include <kernel/building.h>
#include <kernel/unit.h>
#include <util/rand.h>
#include <util/message.h>
#include <util/language.h>
@ -19,6 +20,34 @@
#include <CuTest.h>
#define MAXLOG 4
typedef struct log_entry {
unit *u;
skill_t sk;
int days;
} log_entry;
static log_entry log_learners[MAXLOG];
static int log_size;
static void log_learn(unit *u, skill_t sk, int days) {
if (log_size < MAXLOG) {
log_entry * entry = &log_learners[log_size++];
entry->u = u;
entry->sk = sk;
entry->days = days;
}
}
void learn_inject(void) {
log_size = 0;
inject_learn(log_learn);
}
void learn_reset(void) {
inject_learn(0);
}
typedef struct {
unit *u;
unit *teachers[2];
@ -133,23 +162,33 @@ static void test_study_bug_2194(CuTest *tc) {
i_change(&u1->items, get_resourcetype(R_SILVER)->itype, 50);
i_change(&u2->items, get_resourcetype(R_SILVER)->itype, 50);
b->flags = BLD_WORKING;
learn_inject();
teach_cmd(u, u->thisorder);
learn_reset();
CuAssertPtrEquals(tc, u, log_learners[0].u);
CuAssertIntEquals(tc, SK_CROSSBOW, log_learners[0].sk);
CuAssertIntEquals(tc, 1, log_size);
CuAssertPtrNotNull(tc, test_find_messagetype(u->faction->msgs, "teach_asgood"));
free_order(u->thisorder);
u->thisorder = create_order(K_TEACH, loc, itoa36(u2->no));
learn_inject();
teach_cmd(u, u->thisorder);
learn_reset();
CuAssertIntEquals(tc, 0, log_size);
test_cleanup();
}
static CuTest *g_tc;
static bool cb_learn_one(unit *u, skill_t sk, double chance) {
static void cb_learn_one(unit *u, skill_t sk, int days) {
CuAssertIntEquals(g_tc, SK_ALCHEMY, sk);
CuAssertDblEquals(g_tc, 0.5 / u->number, chance, 0.01);
return false;
CuAssertIntEquals(g_tc, 10, days);
}
static bool cb_learn_two(unit *u, skill_t sk, double chance) {
static void cb_learn_two(unit *u, skill_t sk, int days) {
CuAssertIntEquals(g_tc, SK_ALCHEMY, sk);
CuAssertDblEquals(g_tc, 2 * 0.5 / u->number, chance, 0.01);
return false;
CuAssertIntEquals(g_tc, 20, days);
}
static void test_produceexp(CuTest *tc) {
@ -158,32 +197,13 @@ static void test_produceexp(CuTest *tc) {
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");
scale_number(u, 2);
config_set("study.produceexp", "20");
produceexp_ex(u, SK_ALCHEMY, 1, cb_learn_one);
produceexp_ex(u, SK_ALCHEMY, 2, cb_learn_two);
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;
@ -217,26 +237,288 @@ static void test_academy_building(CuTest *tc) {
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);
learn_inject();
teach_cmd(u, u->thisorder);
inject_learn(0);
learn_reset();
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);
CuAssertIntEquals(tc, 15, log_learners[0].days);
test_cleanup();
}
void test_learn_skill_single(CuTest *tc) {
unit *u;
skill *sv;
test_cleanup();
config_set("study.random_progress", "0");
u = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0));
learn_skill(u, SK_ALCHEMY, STUDYDAYS);
CuAssertPtrNotNull(tc, sv = u->skills);
CuAssertIntEquals(tc, SK_ALCHEMY, sv->id);
CuAssertIntEquals(tc, 1, sv->level);
CuAssertIntEquals(tc, 2, sv->weeks);
learn_skill(u, SK_ALCHEMY, STUDYDAYS);
CuAssertIntEquals(tc, 1, sv->weeks);
learn_skill(u, SK_ALCHEMY, STUDYDAYS * 2);
CuAssertIntEquals(tc, 2, sv->level);
CuAssertIntEquals(tc, 2, sv->weeks);
test_cleanup();
}
void test_learn_skill_multi(CuTest *tc) {
unit *u;
skill *sv;
test_cleanup();
config_set("study.random_progress", "0");
u = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0));
scale_number(u, 10);
learn_skill(u, SK_ALCHEMY, STUDYDAYS * u->number);
CuAssertPtrNotNull(tc, sv = u->skills);
CuAssertIntEquals(tc, SK_ALCHEMY, sv->id);
CuAssertIntEquals(tc, 1, sv->level);
CuAssertIntEquals(tc, 2, sv->weeks);
learn_skill(u, SK_ALCHEMY, STUDYDAYS * u->number);
CuAssertIntEquals(tc, 1, sv->weeks);
learn_skill(u, SK_ALCHEMY, STUDYDAYS * u->number * 2);
CuAssertIntEquals(tc, 2, sv->level);
CuAssertIntEquals(tc, 2, sv->weeks);
test_cleanup();
}
static void test_demon_skillchanges(CuTest *tc) {
unit * u;
race * rc;
test_cleanup();
rc = test_create_race("demon");
CuAssertPtrEquals(tc, rc, get_race(RC_DAEMON));
u = test_create_unit(test_create_faction(rc), 0);
CuAssertPtrNotNull(tc, u);
set_level(u, SK_CROSSBOW, 1);
demon_skillchange(u);
// TODO: sensing here
test_cleanup();
}
static void test_study_cmd(CuTest *tc) {
unit *u;
test_cleanup();
init_resources();
u = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0));
u->thisorder = create_order(K_STUDY, u->faction->locale, "CROSSBOW");
learn_inject();
study_cmd(u, u->thisorder);
learn_reset();
CuAssertPtrEquals(tc, u, log_learners[0].u);
CuAssertIntEquals(tc, SK_CROSSBOW, log_learners[0].sk);
CuAssertIntEquals(tc, STUDYDAYS, log_learners[0].days);
test_cleanup();
}
static void test_study_cost(CuTest *tc) {
unit *u;
const struct item_type *itype;
test_cleanup();
init_resources();
itype = get_resourcetype(R_SILVER)->itype;
u = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0));
scale_number(u, 2);
u->thisorder = create_order(K_STUDY, u->faction->locale, "ALCHEMY");
i_change(&u->items, itype, u->number * study_cost(u, SK_ALCHEMY));
learn_inject();
study_cmd(u, u->thisorder);
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, 0, i_get(u->items, itype));
test_cleanup();
}
static void test_teach_cmd(CuTest *tc) {
unit *u, *ut;
test_cleanup();
init_resources();
u = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0));
scale_number(u, 10);
u->thisorder = create_order(K_STUDY, u->faction->locale, "CROSSBOW");
ut = test_create_unit(u->faction, u->region);
set_level(ut, SK_CROSSBOW, TEACHDIFFERENCE);
ut->thisorder = create_order(K_TEACH, u->faction->locale, itoa36(u->no));
learn_inject();
teach_cmd(ut, ut->thisorder);
study_cmd(u, u->thisorder);
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);
test_cleanup();
}
static void test_teach_two(CuTest *tc) {
unit *u1, *u2, *ut;
test_cleanup();
init_resources();
u1 = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0));
scale_number(u1, 5);
u1->thisorder = create_order(K_STUDY, u1->faction->locale, "CROSSBOW");
u2 = test_create_unit(u1->faction, u1->region);
scale_number(u2, 5);
u2->thisorder = create_order(K_STUDY, u2->faction->locale, "CROSSBOW");
ut = test_create_unit(u1->faction, u1->region);
set_level(ut, SK_CROSSBOW, TEACHDIFFERENCE);
ut->thisorder = create_order(K_TEACH, ut->faction->locale, "%s %s", itoa36(u1->no), itoa36(u2->no));
learn_inject();
teach_cmd(ut, ut->thisorder);
study_cmd(u1, u1->thisorder);
study_cmd(u2, u2->thisorder);
learn_reset();
CuAssertPtrEquals(tc, u1, log_learners[0].u);
CuAssertIntEquals(tc, SK_CROSSBOW, log_learners[0].sk);
CuAssertIntEquals(tc, STUDYDAYS * 2 * u1->number, log_learners[0].days);
CuAssertPtrEquals(tc, u2, log_learners[1].u);
CuAssertIntEquals(tc, SK_CROSSBOW, log_learners[1].sk);
CuAssertIntEquals(tc, STUDYDAYS * 2 * u2->number, log_learners[1].days);
test_cleanup();
}
static void test_teach_two_skills(CuTest *tc) {
unit *u1, *u2, *ut;
faction *f;
region *r;
test_cleanup();
init_resources();
f = test_create_faction(0);
r = test_create_region(0, 0, 0);
u1 = test_create_unit(f, r);
scale_number(u1, 5);
u1->thisorder = create_order(K_STUDY, f->locale, "CROSSBOW");
u2 = test_create_unit(f, r);
scale_number(u2, 5);
u2->thisorder = create_order(K_STUDY, f->locale, "ENTERTAINMENT");
ut = test_create_unit(f, r);
set_level(ut, SK_ENTERTAINMENT, TEACHDIFFERENCE);
set_level(ut, SK_CROSSBOW, TEACHDIFFERENCE);
ut->thisorder = create_order(K_TEACH, f->locale, "%s %s", itoa36(u1->no), itoa36(u2->no));
learn_inject();
teach_cmd(ut, ut->thisorder);
study_cmd(u1, u1->thisorder);
study_cmd(u2, u2->thisorder);
learn_reset();
CuAssertPtrEquals(tc, u1, log_learners[0].u);
CuAssertIntEquals(tc, SK_CROSSBOW, log_learners[0].sk);
CuAssertIntEquals(tc, STUDYDAYS * 2 * u1->number, log_learners[0].days);
CuAssertPtrEquals(tc, u2, log_learners[1].u);
CuAssertIntEquals(tc, SK_ENTERTAINMENT, log_learners[1].sk);
CuAssertIntEquals(tc, STUDYDAYS * 2 * u2->number, log_learners[1].days);
test_cleanup();
}
static void test_teach_one_to_many(CuTest *tc) {
unit *u, *ut;
test_cleanup();
init_resources();
u = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0));
scale_number(u, 20);
u->thisorder = create_order(K_STUDY, u->faction->locale, "CROSSBOW");
ut = test_create_unit(u->faction, u->region);
set_level(ut, SK_CROSSBOW, TEACHDIFFERENCE);
ut->thisorder = create_order(K_TEACH, u->faction->locale, itoa36(u->no));
learn_inject();
teach_cmd(ut, ut->thisorder);
study_cmd(u, u->thisorder);
learn_reset();
CuAssertPtrEquals(tc, u, log_learners[0].u);
CuAssertIntEquals(tc, SK_CROSSBOW, log_learners[0].sk);
CuAssertIntEquals(tc, STUDYDAYS * 10 + STUDYDAYS * u->number, log_learners[0].days);
test_cleanup();
}
static void test_teach_many_to_one(CuTest *tc) {
unit *u, *u1, *u2;
test_cleanup();
init_resources();
u = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0));
scale_number(u, 20);
u->thisorder = create_order(K_STUDY, u->faction->locale, "CROSSBOW");
u1 = test_create_unit(u->faction, u->region);
set_level(u1, SK_CROSSBOW, TEACHDIFFERENCE);
u1->thisorder = create_order(K_TEACH, u->faction->locale, itoa36(u->no));
u2 = test_create_unit(u->faction, u->region);
set_level(u2, SK_CROSSBOW, TEACHDIFFERENCE);
u2->thisorder = create_order(K_TEACH, u->faction->locale, itoa36(u->no));
learn_inject();
teach_cmd(u1, u1->thisorder);
teach_cmd(u2, u2->thisorder);
study_cmd(u, u->thisorder);
learn_reset();
CuAssertPtrEquals(tc, u, log_learners[0].u);
CuAssertIntEquals(tc, SK_CROSSBOW, log_learners[0].sk);
CuAssertIntEquals(tc, 2 * STUDYDAYS * u->number, log_learners[0].days);
test_cleanup();
}
static void test_teach_many_to_many(CuTest *tc) {
unit *s1, *s2, *t1, *t2;
region *r;
faction *f;
test_cleanup();
init_resources();
f = test_create_faction(0);
r = test_create_region(0, 0, 0);
s1 = test_create_unit(f, r);
scale_number(s1, 20);
s1->thisorder = create_order(K_STUDY, f->locale, "CROSSBOW");
s2 = test_create_unit(f, r);
scale_number(s2, 10);
s2->thisorder = create_order(K_STUDY, f->locale, "CROSSBOW");
t1 = test_create_unit(f, r);
set_level(t1, SK_CROSSBOW, TEACHDIFFERENCE);
t1->thisorder = create_order(K_TEACH, f->locale, "%s %s", itoa36(s1->no), itoa36(s2->no));
t2 = test_create_unit(f, r);
scale_number(t2, 2);
set_level(t2, SK_CROSSBOW, TEACHDIFFERENCE);
t2->thisorder = create_order(K_TEACH, f->locale, "%s %s", itoa36(s1->no), itoa36(s2->no));
learn_inject();
teach_cmd(t1, t1->thisorder);
teach_cmd(t2, t2->thisorder);
study_cmd(s1, s1->thisorder);
study_cmd(s2, s2->thisorder);
learn_reset();
CuAssertPtrEquals(tc, s1, log_learners[0].u);
CuAssertIntEquals(tc, SK_CROSSBOW, log_learners[0].sk);
CuAssertIntEquals(tc, 2 * STUDYDAYS * s1->number, log_learners[0].days);
CuAssertPtrEquals(tc, s2, log_learners[1].u);
CuAssertIntEquals(tc, SK_CROSSBOW, log_learners[1].sk);
CuAssertIntEquals(tc, 2 * STUDYDAYS * s2->number, log_learners[1].days);
test_cleanup();
}
CuSuite *get_study_suite(void)
{
CuSuite *suite = CuSuiteNew();
SUITE_ADD_TEST(suite, test_study_cmd);
SUITE_ADD_TEST(suite, test_study_cost);
SUITE_ADD_TEST(suite, test_teach_cmd);
SUITE_ADD_TEST(suite, test_teach_two);
SUITE_ADD_TEST(suite, test_teach_one_to_many);
SUITE_ADD_TEST(suite, test_teach_many_to_one);
SUITE_ADD_TEST(suite, test_teach_many_to_many);
SUITE_ADD_TEST(suite, test_teach_two_skills);
SUITE_ADD_TEST(suite, test_learn_skill_single);
SUITE_ADD_TEST(suite, test_learn_skill_multi);
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);
SUITE_ADD_TEST(suite, test_academy_building);
DISABLE_TEST(suite, test_study_bug_2194);
SUITE_ADD_TEST(suite, test_demon_skillchanges);
SUITE_ADD_TEST(suite, test_study_bug_2194);
return suite;
}

View File

@ -3,6 +3,7 @@
#include "keyword.h"
#include "seen.h"
#include "prefix.h"
#include "reports.h"
#include <kernel/config.h>
#include <kernel/plane.h>
@ -53,7 +54,7 @@ struct region *test_create_region(int x, int y, const terrain_type *terrain)
if (!terrain) {
terrain_type *t = get_or_create_terrain("plain");
t->size = 1000;
fset(t, LAND_REGION|CAVALRY_REGION|FOREST_REGION);
fset(t, LAND_REGION|CAVALRY_REGION|FOREST_REGION|FLY_INTO|WALK_INTO|SAIL_INTO);
terraform_region(r, t);
}
else {
@ -67,9 +68,44 @@ struct region *test_create_region(int x, int y, const terrain_type *terrain)
return r;
}
struct locale * test_create_locale(void) {
struct locale *loc = get_locale("test");
if (!loc) {
int i;
loc = get_or_create_locale("test");
locale_setstring(loc, "factiondefault", parameters[P_FACTION]);
for (i = 0; i < MAXSKILLS; ++i) {
if (!locale_getstring(loc, mkname("skill", skillnames[i])))
locale_setstring(loc, mkname("skill", skillnames[i]), skillnames[i]);
}
for (i = 0; i != MAXDIRECTIONS; ++i) {
locale_setstring(loc, directions[i], directions[i]);
init_direction(loc, i, directions[i]);
init_direction(loc, i, coasts[i]+7);
}
for (i = 0; i <= ST_FLEE; ++i) {
locale_setstring(loc, combatstatus[i], combatstatus[i]+7);
}
for (i = 0; i != MAXKEYWORDS; ++i) {
locale_setstring(loc, mkname("keyword", keywords[i]), keywords[i]);
}
for (i = 0; i != MAXSKILLS; ++i) {
locale_setstring(loc, mkname("skill", skillnames[i]), skillnames[i]);
}
for (i = 0; i != MAXPARAMS; ++i) {
locale_setstring(loc, parameters[i], parameters[i]);
test_translate_param(loc, i, parameters[i]);
}
init_parameters(loc);
init_skills(loc);
}
return loc;
}
struct faction *test_create_faction(const struct race *rc)
{
faction *f = addfaction("nobody@eressea.de", NULL, rc ? rc : test_create_race("human"), default_locale, 0);
struct locale * loc = test_create_locale();
faction *f = addfaction("nobody@eressea.de", NULL, rc ? rc : test_create_race("human"), loc, 0);
test_clear_messages(f);
return f;
}
@ -78,6 +114,7 @@ struct unit *test_create_unit(struct faction *f, struct region *r)
{
const struct race * rc = f ? f->race : 0;
assert(f || !r);
if (!rc) rc = rc_get_or_create("human");
return create_unit(r, f, 1, rc ? rc : rc_get_or_create("human"), 0, 0, 0);
}
@ -85,6 +122,7 @@ void test_cleanup(void)
{
int i;
default_locale = 0;
free_gamedata();
free_terrains();
free_resources();

View File

@ -25,11 +25,13 @@ extern "C" {
struct castorder;
struct spellparameter;
struct spell;
struct locale;
struct CuTest;
void test_cleanup(void);
struct locale * test_create_locale(void);
struct terrain_type * test_create_terrain(const char * name, unsigned int flags);
struct race *test_create_race(const char *name);
struct region *test_create_region(int x, int y,

View File

@ -9,6 +9,7 @@
#include <kernel/region.h>
#include <kernel/terrain.h>
#include <kernel/unit.h>
#include <kernel/faction.h>
#include <kernel/race.h>
#include <util/language.h>
@ -30,6 +31,7 @@ static void test_move_to_vortex(CuTest *tc) {
r2 = test_create_region(5, 0, t_plain);
CuAssertPtrNotNull(tc, create_special_direction(r1, r2, 10, "", "vortex", true));
u = test_create_unit(test_create_faction(rc_get_or_create("hodor")), r1);
u->faction->locale = lang;
CuAssertIntEquals(tc, E_MOVE_NOREGION, movewhere(u, "barf", r1, &r));
CuAssertIntEquals(tc, E_MOVE_OK, movewhere(u, "wirbel", r1, &r));
CuAssertPtrEquals(tc, r2, r);