Merge pull request #803 from ennorehling/master

Fixing LERNE AUTO
This commit is contained in:
Enno Rehling 2018-09-09 15:49:47 +02:00 committed by GitHub
commit 90f854f5b7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 171 additions and 74 deletions

2
clibs

@ -1 +1 @@
Subproject commit 66a891b383f1a51bb0d4e5cf002530f7f70bf7f4 Subproject commit d86c8525489d7f11b7ba13e101bb59ecf160b871

View File

@ -2864,6 +2864,9 @@ msgstr "der Schatten"
msgid "ALLES" msgid "ALLES"
msgstr "ALLES" msgstr "ALLES"
msgid "AUTO"
msgstr "AUTO"
msgid "undead_postfix_2" msgid "undead_postfix_2"
msgstr "der Finsternis" msgstr "der Finsternis"
@ -5958,6 +5961,10 @@ msgctxt "keyword"
msgid "maketemp" msgid "maketemp"
msgstr "MACHE TEMP" msgstr "MACHE TEMP"
msgctxt "keyword"
msgid "autostudy"
msgstr "LERNE AUTO"
msgctxt "spell" msgctxt "spell"
msgid "reanimate" msgid "reanimate"
msgstr "Wiederbelebung" msgstr "Wiederbelebung"

View File

@ -2510,6 +2510,9 @@ msgstr "halfling foot"
msgid "ALLES" msgid "ALLES"
msgstr "ALL" msgstr "ALL"
msgid "AUTO"
msgstr "AUTO"
msgctxt "race" msgctxt "race"
msgid "songdragon_d" msgid "songdragon_d"
msgstr "song dragons" msgstr "song dragons"
@ -5268,7 +5271,11 @@ msgstr "berserkers blood potions"
msgctxt "keyword" msgctxt "keyword"
msgid "maketemp" msgid "maketemp"
msgstr "MAKETEMP" msgstr "MAKE TEMP"
msgctxt "keyword"
msgid "autostudy"
msgstr "LEARN AUTO"
msgctxt "spell" msgctxt "spell"
msgid "reanimate" msgid "reanimate"

View File

@ -12,6 +12,30 @@ function setup()
eressea.settings.set("rules.peasants.growth.factor", "0") eressea.settings.set("rules.peasants.growth.factor", "0")
end end
function test_study_auto()
local r = region.create(0, 0, "plain")
local f = faction.create("human")
local u = unit.create(f, r, 1)
u:add_order("LERN AUT Waffenbau")
assert_equal("LERNE AUTO Waffenbau", u:get_order(0))
process_orders()
assert_equal(1, u:get_skill("weaponsmithing"))
end
function test_study_auto_expensive()
local r = region.create(0, 0, "plain")
local f = faction.create("human")
local u = unit.create(f, r, 1)
u:add_order("LERNE AUTO Magie")
assert_equal("LERNE Magie", u:get_order(0))
u:clear_orders()
u:add_order("LERN AUT Taktik")
assert_equal("LERNE Taktik", u:get_order(0))
u:clear_orders()
u:add_order("LERN AUT Waffenbau")
assert_equal("LERNE AUTO Waffenbau", u:get_order(0))
end
function test_calendar() function test_calendar()
assert_equal("winter", get_season(1011)) assert_equal("winter", get_season(1011))
assert_equal("spring", get_season(1012)) assert_equal("spring", get_season(1012))

View File

@ -42,7 +42,8 @@ function test_build_watch()
process_orders() process_orders()
assert_not_nil(u.building) assert_not_nil(u.building)
if 5 ~= u.building.size then if 5 ~= u.building.size then
for k,v in f.messages do -- debug logging to find intermittent errors
for k,v in ipairs(f.messages) do
print(v) print(v)
end end
end end

View File

@ -24,7 +24,7 @@ end
function test_study() function test_study()
local r = region.create(0, 0, "plain") local r = region.create(0, 0, "plain")
local f = faction.create("human", "test@example.com", "de") local f = faction.create("human")
local u = unit.create(f, r, 1) local u = unit.create(f, r, 1)
u:add_order("LERNEN Armbrust") u:add_order("LERNEN Armbrust")
process_orders() process_orders()
@ -33,7 +33,7 @@ end
function test_study_expensive() function test_study_expensive()
local r = region.create(0, 0, "plain") local r = region.create(0, 0, "plain")
local f = faction.create("human", "test@example.com", "de") local f = faction.create("human")
local u = unit.create(f, r, 1) local u = unit.create(f, r, 1)
eressea.settings.set("skills.cost.alchemy", "50") eressea.settings.set("skills.cost.alchemy", "50")
u:add_order("LERNEN Alchemie") u:add_order("LERNEN Alchemie")
@ -45,7 +45,7 @@ end
function test_unit_spells() function test_unit_spells()
local r = region.create(0, 0, "plain") local r = region.create(0, 0, "plain")
local f = faction.create("human", "test@example.com", "de") local f = faction.create("human")
local u = unit.create(f, r, 1) local u = unit.create(f, r, 1)
u.magic = "gray" u.magic = "gray"
u:set_skill("magic", 1) u:set_skill("magic", 1)
@ -75,7 +75,7 @@ end
function test_study_no_teacher() function test_study_no_teacher()
local r = region.create(0, 0, "plain") local r = region.create(0, 0, "plain")
local f = faction.create("human", "test@example.com", "de") local f = faction.create("human")
local u1 = make_student(f, r, 1) local u1 = make_student(f, r, 1)
u1:set_skill("crossbow", 1) u1:set_skill("crossbow", 1)
process_orders() process_orders()
@ -84,7 +84,7 @@ end
function test_study_with_teacher() function test_study_with_teacher()
local r = region.create(0, 0, "plain") local r = region.create(0, 0, "plain")
local f = faction.create("human", "test@example.com", "de") local f = faction.create("human")
local u1 = make_student(f, r, 1) local u1 = make_student(f, r, 1)
make_teacher(u1) make_teacher(u1)
@ -95,7 +95,7 @@ end
function test_study_too_many_students() function test_study_too_many_students()
local r = region.create(0, 0, "plain") local r = region.create(0, 0, "plain")
local f = faction.create("human", "test@example.com", "de") local f = faction.create("human")
local u1 = make_student(f, r, 20, "Taktik") local u1 = make_student(f, r, 20, "Taktik")
u1.name = "Student" u1.name = "Student"
u1:add_item("money", 201*u1.number) u1:add_item("money", 201*u1.number)
@ -106,7 +106,7 @@ end
function test_study_multiple_teachers() function test_study_multiple_teachers()
local r = region.create(0, 0, "plain") local r = region.create(0, 0, "plain")
local f = faction.create("human", "test@example.com", "de") local f = faction.create("human")
local u1 = make_student(f, r, 20, "Taktik") local u1 = make_student(f, r, 20, "Taktik")
u1.name = "Student" u1.name = "Student"
u1:add_item("money", 201*u1.number) u1:add_item("money", 201*u1.number)

View File

@ -38,14 +38,14 @@ int autostudy_init(scholar scholars[], int max_scholars, region *r)
if (kwd == K_AUTOSTUDY) { if (kwd == K_AUTOSTUDY) {
if (long_order_allowed(u) && unit_can_study(u)) { if (long_order_allowed(u) && unit_can_study(u)) {
scholar * st = scholars + nscholars; scholar * st = scholars + nscholars;
if (++nscholars == max_scholars) {
log_fatal("you must increase MAXSCHOLARS");
}
st->u = u;
init_order(u->thisorder, u->faction->locale); init_order(u->thisorder, u->faction->locale);
st->sk = getskill(u->faction->locale); st->sk = getskill(u->faction->locale);
st->level = effskill_study(u, st->sk); st->level = effskill_study(u, st->sk);
st->learn = 0; st->learn = 0;
st->u = u;
if (++nscholars == max_scholars) {
log_fatal("you must increase MAXSCHOLARS");
}
} }
else { else {
ADDMSG(&u->faction->msgs, msg_feedback(u, u->thisorder, "error_race_nolearn", "race", ADDMSG(&u->faction->msgs, msg_feedback(u, u->thisorder, "error_race_nolearn", "race",

View File

@ -141,7 +141,8 @@ int stream_order(struct stream *out, const struct order *ord, const struct local
if (ord->id < 0) { if (ord->id < 0) {
skill_t sk = (skill_t)(100 + ord->id); skill_t sk = (skill_t)(100 + ord->id);
assert(kwd == K_STUDY && sk != SK_MAGIC && sk < MAXSKILLS); assert(kwd == K_AUTOSTUDY || kwd == K_STUDY);
assert(sk != SK_MAGIC && sk < MAXSKILLS);
text = skillname(sk, lang); text = skillname(sk, lang);
if (strchr(text, ' ') != NULL) { if (strchr(text, ' ') != NULL) {
swrite(" '", 1, 2, out); swrite(" '", 1, 2, out);
@ -310,12 +311,13 @@ order *parse_order(const char *s, const struct locale * lang)
assert(lang); assert(lang);
assert(s); assert(s);
if (*s != 0) { if (*s != 0) {
char token[32];
keyword_t kwd = NOKEYWORD; keyword_t kwd = NOKEYWORD;
const char *sptr = s; const char *sptr = s;
bool persistent = false, noerror = false; bool persistent = false, noerror = false;
const char * p; char * p;
p = *sptr ? parse_token_depr(&sptr) : 0; p = parse_token(&sptr, token, sizeof(token));
if (p) { if (p) {
while (*p == '!' || *p == '@') { while (*p == '!' || *p == '@') {
if (*p == '!') noerror = true; if (*p == '!') noerror = true;
@ -326,7 +328,7 @@ order *parse_order(const char *s, const struct locale * lang)
} }
if (kwd == K_MAKE) { if (kwd == K_MAKE) {
const char *sp = sptr; const char *sp = sptr;
p = parse_token_depr(&sp); p = parse_token(&sp, token, sizeof(token));
if (p && isparam(p, lang, P_TEMP)) { if (p && isparam(p, lang, P_TEMP)) {
kwd = K_MAKETEMP; kwd = K_MAKETEMP;
sptr = sp; sptr = sp;
@ -334,10 +336,15 @@ order *parse_order(const char *s, const struct locale * lang)
} }
else if (kwd == K_STUDY) { else if (kwd == K_STUDY) {
const char *sp = sptr; const char *sp = sptr;
p = parse_token_depr(&sp); p = parse_token(&sp, token, sizeof(token));
if (p && isparam(p, lang, P_AUTO)) { if (p && isparam(p, lang, P_AUTO)) {
kwd = K_AUTOSTUDY; skill_t sk;
sptr = sp; sptr = sp;
p = parse_token(&sp, token, sizeof(token));
sk = get_skill(p, lang);
if (!expensive_skill(sk)) {
kwd = K_AUTOSTUDY;
}
} }
} }
if (kwd != NOKEYWORD) { if (kwd != NOKEYWORD) {

View File

@ -121,6 +121,8 @@ static void test_parse_autostudy(CuTest *tc) {
test_setup(); test_setup();
lang = get_or_create_locale("en"); lang = get_or_create_locale("en");
locale_setstring(lang, mkname("skill", skillnames[SK_ENTERTAINMENT]), "Entertainment"); locale_setstring(lang, mkname("skill", skillnames[SK_ENTERTAINMENT]), "Entertainment");
locale_setstring(lang, mkname("skill", skillnames[SK_MAGIC]), "Magic");
locale_setstring(lang, mkname("skill", skillnames[SK_TACTICS]), "Tactics");
locale_setstring(lang, keyword(K_STUDY), "STUDY"); locale_setstring(lang, keyword(K_STUDY), "STUDY");
locale_setstring(lang, keyword(K_AUTOSTUDY), "AUTOSTUDY"); locale_setstring(lang, keyword(K_AUTOSTUDY), "AUTOSTUDY");
locale_setstring(lang, parameters[P_AUTO], "AUTO"); locale_setstring(lang, parameters[P_AUTO], "AUTO");
@ -134,6 +136,17 @@ static void test_parse_autostudy(CuTest *tc) {
CuAssertIntEquals(tc, K_AUTOSTUDY, init_order(ord, lang)); CuAssertIntEquals(tc, K_AUTOSTUDY, init_order(ord, lang));
CuAssertStrEquals(tc, "Entertainment", getstrtoken()); CuAssertStrEquals(tc, "Entertainment", getstrtoken());
free_order(ord); free_order(ord);
ord = parse_order("STUDY AUTO Magic", lang);
CuAssertIntEquals(tc, K_STUDY, getkeyword(ord));
CuAssertStrEquals(tc, "STUDY Magic", get_command(ord, lang, cmd, sizeof(cmd)));
free_order(ord);
ord = parse_order("STUDY AUTO Tactics", lang);
CuAssertIntEquals(tc, K_STUDY, getkeyword(ord));
CuAssertStrEquals(tc, "STUDY Tactics", get_command(ord, lang, cmd, sizeof(cmd)));
free_order(ord);
test_teardown(); test_teardown();
} }

View File

@ -113,3 +113,38 @@ skill_t get_skill(const char *s, const struct locale * lang)
return result; return result;
} }
int skill_cost(skill_t sk) {
static int config;
static int costs[MAXSKILLS];
int cost;
switch (sk) {
case SK_SPY:
cost = 100;
break;
case SK_TACTICS:
case SK_HERBALISM:
case SK_ALCHEMY:
cost = 200;
break;
default:
cost = -1;
}
if (config_changed(&config)) {
memset(costs, 0, sizeof(costs));
}
if (costs[sk] == 0) {
char buffer[256];
sprintf(buffer, "skills.cost.%s", skillnames[sk]);
costs[sk] = config_get_int(buffer, cost);
}
if (costs[sk] >= 0) {
return costs[sk];
}
return (cost > 0) ? cost : 0;
}
bool expensive_skill(skill_t sk) {
return (sk == SK_MAGIC) || skill_cost(sk) > 0;
}

View File

@ -49,5 +49,7 @@ void init_skills(const struct locale *lang);
void init_skill(const struct locale *lang, skill_t kwd, const char *str); void init_skill(const struct locale *lang, skill_t kwd, const char *str);
void enable_skill(skill_t sk, bool enabled); void enable_skill(skill_t sk, bool enabled);
bool skill_enabled(skill_t sk); bool skill_enabled(skill_t sk);
int skill_cost(skill_t sk);
bool expensive_skill(skill_t sk);
#endif #endif

View File

@ -1,6 +1,8 @@
#include <platform.h> #include <platform.h>
#include "skill.h"
#include "kernel/config.h"
#include "util/language.h" #include "util/language.h"
#include "skill.h"
#include "tests.h" #include "tests.h"
#include <CuTest.h> #include <CuTest.h>
@ -38,12 +40,34 @@ static void test_get_skill(CuTest *tc) {
test_teardown(); test_teardown();
} }
static void test_skill_cost(CuTest *tc) {
test_setup();
CuAssertTrue(tc, expensive_skill(SK_MAGIC));
CuAssertTrue(tc, expensive_skill(SK_TACTICS));
CuAssertTrue(tc, expensive_skill(SK_SPY));
CuAssertTrue(tc, expensive_skill(SK_ALCHEMY));
CuAssertTrue(tc, expensive_skill(SK_HERBALISM));
CuAssertTrue(tc, !expensive_skill(SK_CROSSBOW));
CuAssertIntEquals(tc, 100, skill_cost(SK_SPY));
CuAssertIntEquals(tc, 200, skill_cost(SK_TACTICS));
CuAssertIntEquals(tc, 200, skill_cost(SK_ALCHEMY));
CuAssertIntEquals(tc, 200, skill_cost(SK_HERBALISM));
CuAssertIntEquals(tc, 0, skill_cost(SK_CROSSBOW));
config_set_int("skills.cost.crossbow", 300);
CuAssertIntEquals(tc, 300, skill_cost(SK_CROSSBOW));
CuAssertTrue(tc, expensive_skill(SK_CROSSBOW));
test_teardown();
}
CuSuite *get_skill_suite(void) CuSuite *get_skill_suite(void)
{ {
CuSuite *suite = CuSuiteNew(); CuSuite *suite = CuSuiteNew();
SUITE_ADD_TEST(suite, test_init_skill); SUITE_ADD_TEST(suite, test_init_skill);
SUITE_ADD_TEST(suite, test_init_skills); SUITE_ADD_TEST(suite, test_init_skills);
SUITE_ADD_TEST(suite, test_get_skill); SUITE_ADD_TEST(suite, test_get_skill);
SUITE_ADD_TEST(suite, test_skill_cost);
return suite; return suite;
} }

View File

@ -130,47 +130,23 @@ bool magic_lowskill(unit * u)
return u_race(u) == toad_rc; return u_race(u) == toad_rc;
} }
/* ------------------------------------------------------------- */
int study_cost(struct unit *u, skill_t sk) int study_cost(struct unit *u, skill_t sk)
{ {
static int config;
static int costs[MAXSKILLS];
int cost = -1;
if (sk == SK_MAGIC) { if (sk == SK_MAGIC) {
int next_level = 1 + (u ? get_level(u, sk) : 0); static int config;
static int cost;
/* Die Magiekosten betragen 50+Summe(50*Stufe) */ /* Die Magiekosten betragen 50+Summe(50*Stufe) */
/* 'Stufe' ist dabei die naechste zu erreichende Stufe */ /* 'Stufe' ist dabei die naechste zu erreichende Stufe */
cost = config_get_int("skills.cost.magic", 50); if (config_changed(&config)) {
return cost * (1 + ((next_level + next_level * next_level) / 2)); cost = config_get_int("skills.cost.magic", 50);
}
if (cost > 0) {
int next_level = 1 + (u ? get_level(u, sk) : 0);
return cost * (1 + ((next_level + next_level * next_level) / 2));
}
return cost;
} }
else switch (sk) { return skill_cost(sk);
case SK_SPY:
cost = 100;
break;
case SK_TACTICS:
case SK_HERBALISM:
case SK_ALCHEMY:
cost = 200;
break;
default:
cost = -1;
}
if (config_changed(&config)) {
memset(costs, 0, sizeof(costs));
}
if (costs[sk] == 0) {
char buffer[256];
sprintf(buffer, "skills.cost.%s", skillnames[sk]);
costs[sk] = config_get_int(buffer, cost);
}
if (costs[sk] >= 0) {
return costs[sk];
}
return (cost > 0) ? cost : 0;
} }
/* ------------------------------------------------------------- */ /* ------------------------------------------------------------- */

View File

@ -29,26 +29,9 @@ extern "C" {
struct unit; struct unit;
struct selist; struct selist;
int teach_cmd(struct unit *u, struct order *ord);
int study_cmd(struct unit *u, struct order *ord);
magic_t getmagicskill(const struct locale *lang);
skill_t getskill(const struct locale *lang);
bool is_migrant(struct unit *u);
int study_cost(struct unit *u, skill_t talent);
typedef void(*learn_fun)(struct unit *u, skill_t sk, int days);
#define STUDYDAYS 30 #define STUDYDAYS 30
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);
void demon_skillchange(struct unit *u);
#define TEACHNUMBER 10 #define TEACHNUMBER 10
typedef struct teaching_info { typedef struct teaching_info {
struct selist *teachers; struct selist *teachers;
int students; int students;
@ -57,6 +40,24 @@ extern "C" {
extern const struct attrib_type at_learning; extern const struct attrib_type at_learning;
int teach_cmd(struct unit *u, struct order *ord);
int study_cmd(struct unit *u, struct order *ord);
magic_t getmagicskill(const struct locale *lang);
skill_t getskill(const struct locale *lang);
bool is_migrant(struct unit *u);
int study_cost(struct unit *u, skill_t sk);
typedef void(*learn_fun)(struct unit *u, skill_t sk, int days);
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);
void demon_skillchange(struct unit *u);
void inject_learn(learn_fun fun); void inject_learn(learn_fun fun);
#ifdef __cplusplus #ifdef __cplusplus