fix the academy
make academy, curses and potions work for LERNE AUTO
remove E3 study.speedup
This commit is contained in:
Enno Rehling 2020-09-11 21:28:29 +02:00
parent 940e56b6ef
commit f78aa507f8
10 changed files with 200 additions and 215 deletions

View File

@ -67,7 +67,6 @@
"init_spells": 0, "init_spells": 0,
"recruit.allow_merge": true, "recruit.allow_merge": true,
"study.expensivemigrants": true, "study.expensivemigrants": true,
"study.speedup": 2,
"game.era": 3, "game.era": 3,
"game.start": 1, "game.start": 1,
"rules.reserve.twophase": true, "rules.reserve.twophase": true,

View File

@ -11,7 +11,7 @@
void academy_teaching_bonus(struct unit *u, skill_t sk, int students) { void academy_teaching_bonus(struct unit *u, skill_t sk, int students) {
if (students > 0 && sk != NOSKILL) { if (students > 0 && sk != NOSKILL) {
/* actually students * EXPERIENCEDAYS / MAX_STUDENTS */ /* actually students * EXPERIENCEDAYS / MAX_STUDENTS */
learn_skill(u, sk, students); change_skill_days(u, sk, students);
} }
} }

View File

@ -6,6 +6,8 @@
#include "kernel/order.h" #include "kernel/order.h"
#include "kernel/region.h" #include "kernel/region.h"
#include "kernel/unit.h" #include "kernel/unit.h"
#include "kernel/pool.h"
#include "kernel/item.h"
#include "util/keyword.h" #include "util/keyword.h"
#include "util/log.h" #include "util/log.h"
@ -210,7 +212,12 @@ void do_autostudy(region *r)
autostudy_run(scholars, nscholars); autostudy_run(scholars, nscholars);
for (i = 0; i != nscholars; ++i) { for (i = 0; i != nscholars; ++i) {
int days = STUDYDAYS * scholars[i].learn; int days = STUDYDAYS * scholars[i].learn;
learn_skill(scholars[i].u, skill, days); int money = learn_skill(scholars[i].u, skill, days, 0);
if (money > 0) {
use_pooled(u, get_resourcetype(R_SILVER), GET_DEFAULT, money);
ADDMSG(&u->faction->msgs, msg_message("studycost",
"unit region cost skill", u, u->region, money, skill));
}
} }
} }
} }

View File

@ -899,7 +899,7 @@ void drain_exp(struct unit *u, int n)
} }
} }
if (sk != NOSKILL) { if (sk != NOSKILL) {
reduce_skill_days(u, sk, n); change_skill_days(u, sk, -n);
} }
} }

View File

@ -310,18 +310,6 @@ static int tolua_create_curse(lua_State * L)
return 1; return 1;
} }
static int tolua_learn_skill(lua_State * L)
{
unit *u = (unit *)tolua_tousertype(L, 1, 0);
const char *skname = tolua_tostring(L, 2, 0);
int days = (int)tolua_tonumber(L, 3, 0);
skill_t sk = findskill(skname);
if (sk != NOSKILL) {
learn_skill(u, sk, days);
}
return 0;
}
static int tolua_update_scores(lua_State * L) static int tolua_update_scores(lua_State * L)
{ {
UNUSED_ARG(L); UNUSED_ARG(L);
@ -973,7 +961,6 @@ int tolua_bindings_open(lua_State * L, const dictionary *inifile)
tolua_function(L, TOLUA_CAST "remove_empty_units", tolua_remove_empty_units); tolua_function(L, TOLUA_CAST "remove_empty_units", tolua_remove_empty_units);
tolua_function(L, TOLUA_CAST "update_scores", tolua_update_scores); tolua_function(L, TOLUA_CAST "update_scores", tolua_update_scores);
tolua_function(L, TOLUA_CAST "update_owners", tolua_update_owners); tolua_function(L, TOLUA_CAST "update_owners", tolua_update_owners);
tolua_function(L, TOLUA_CAST "learn_skill", tolua_learn_skill);
tolua_function(L, TOLUA_CAST "create_curse", tolua_create_curse); tolua_function(L, TOLUA_CAST "create_curse", tolua_create_curse);
tolua_function(L, TOLUA_CAST "translate", &tolua_translate); tolua_function(L, TOLUA_CAST "translate", &tolua_translate);
tolua_function(L, TOLUA_CAST "spells", tolua_get_spells); tolua_function(L, TOLUA_CAST "spells", tolua_get_spells);

View File

@ -37,7 +37,7 @@ struct order *ord)
skill *sv = u->skills; skill *sv = u->skills;
while (sv != u->skills + u->skill_size) { while (sv != u->skills + u->skill_size) {
/* only one person learns for 3 weeks */ /* only one person learns for 3 weeks */
learn_skill(u, (skill_t)sv->id, STUDYDAYS * 3); change_skill_days(u, (skill_t)sv->id, STUDYDAYS * 3);
++sv; ++sv;
} }
} }

View File

@ -52,17 +52,17 @@ static void test_skillpotion(CuTest *tc) {
itype = test_create_itemtype("skillpotion"); itype = test_create_itemtype("skillpotion");
change_resource(u, itype->rtype, 2); change_resource(u, itype->rtype, 2);
learn_skill(u, SK_ENTERTAINMENT, STUDYDAYS * u->number); change_skill_days(u, SK_ENTERTAINMENT, STUDYDAYS * u->number);
pSkill = unit_skill(u, SK_ENTERTAINMENT); pSkill = unit_skill(u, SK_ENTERTAINMENT);
sk_set(pSkill, 5); sk_set(pSkill, 5);
initialWeeks_Entertainment = pSkill->weeks = 4; initialWeeks_Entertainment = pSkill->weeks = 4;
learn_skill(u, SK_STAMINA, STUDYDAYS * u->number); change_skill_days(u, SK_STAMINA, STUDYDAYS * u->number);
pSkill = unit_skill(u, SK_STAMINA); pSkill = unit_skill(u, SK_STAMINA);
sk_set(pSkill, 5); sk_set(pSkill, 5);
initialWeeks_Stamina = pSkill->weeks = 4; initialWeeks_Stamina = pSkill->weeks = 4;
learn_skill(u, SK_MAGIC, STUDYDAYS * u->number); change_skill_days(u, SK_MAGIC, STUDYDAYS * u->number);
pSkill = unit_skill(u, SK_MAGIC); pSkill = unit_skill(u, SK_MAGIC);
sk_set(pSkill, 5); sk_set(pSkill, 5);
initialWeeks_Magic = pSkill->weeks = 4; initialWeeks_Magic = pSkill->weeks = 4;

View File

@ -154,37 +154,37 @@ const attrib_type at_learning = {
#define EXPERIENCEDAYS 10 #define EXPERIENCEDAYS 10
static int study_days(unit * scholar, skill_t sk) static int study_days(unit * u, skill_t sk)
{ {
int speed = STUDYDAYS; int speed = STUDYDAYS;
if (u_race(scholar)->study_speed) { if (u_race(u)->study_speed) {
speed += u_race(scholar)->study_speed[sk]; speed += u_race(u)->study_speed[sk];
if (speed < STUDYDAYS) { if (speed < STUDYDAYS) {
skill *sv = unit_skill(scholar, sk); skill *sv = unit_skill(u, sk);
if (sv == 0) { if (sv == 0) {
speed = STUDYDAYS; speed = STUDYDAYS;
} }
} }
} }
return scholar->number * speed; return u->number * speed;
} }
static int static int
teach_unit(unit * teacher, unit * scholar, int nteaching, skill_t sk, teach_unit(unit * teacher, unit * student, int nteaching, skill_t sk,
bool report, int *academy_students) bool report, int *academy_students)
{ {
teaching_info *teach = NULL; teaching_info *teach = NULL;
attrib *a; attrib *a;
int students; int students;
if (magic_lowskill(scholar)) { if (magic_lowskill(student)) {
cmistake(teacher, teacher->thisorder, 292, MSG_EVENT); cmistake(teacher, teacher->thisorder, 292, MSG_EVENT);
return 0; return 0;
} }
students = scholar->number; students = student->number;
/* subtract already taught students */ /* subtract already taught students */
a = a_find(scholar->attribs, &at_learning); a = a_find(student->attribs, &at_learning);
if (a != NULL) { if (a != NULL) {
teach = (teaching_info *)a->data.v; teach = (teaching_info *)a->data.v;
students -= teach->students; students -= teach->students;
@ -194,18 +194,18 @@ teach_unit(unit * teacher, unit * scholar, int nteaching, skill_t sk,
if (students > 0) { if (students > 0) {
if (teach == NULL) { if (teach == NULL) {
a = a_add(&scholar->attribs, a_new(&at_learning)); a = a_add(&student->attribs, a_new(&at_learning));
teach = (teaching_info *)a->data.v; teach = (teaching_info *)a->data.v;
} }
selist_push(&teach->teachers, teacher); selist_push(&teach->teachers, teacher);
teach->days += students * STUDYDAYS; teach->days += students * STUDYDAYS;
teach->students += students; teach->students += students;
if (scholar->building) { if (student->building) {
/* Solange Akademien groessenbeschraenkt sind, sollte Lehrer und /* Solange Akademien groessenbeschraenkt sind, sollte Lehrer und
* Student auch in unterschiedlichen Gebaeuden stehen duerfen */ * Student auch in unterschiedlichen Gebaeuden stehen duerfen */
/* FIXME comment contradicts implementation */ /* FIXME comment contradicts implementation */
if (academy_can_teach(teacher, scholar, sk)) { if (academy_can_teach(teacher, student, sk)) {
/* Jeder Schueler zusaetzlich +10 Tage wenn in Uni. */ /* Jeder Schueler zusaetzlich +10 Tage wenn in Uni. */
teach->days += students * EXPERIENCEDAYS; /* learning erhoehen */ teach->days += students * EXPERIENCEDAYS; /* learning erhoehen */
/* Lehrer zusaetzlich +1 Tag pro Schueler. */ /* Lehrer zusaetzlich +1 Tag pro Schueler. */
@ -258,12 +258,12 @@ int teach_cmd(unit * teacher, struct order *ord)
count = 0; count = 0;
#if TEACH_ALL
init_order(ord, NULL); init_order(ord, NULL);
#if TEACH_ALL
if (getparam(teacher->faction->locale) == P_ANY) { if (getparam(teacher->faction->locale) == P_ANY) {
skill_t sk; skill_t sk;
unit *scholar; unit *student;
skill_t teachskill[MAXSKILLS]; skill_t teachskill[MAXSKILLS];
int t = 0; int t = 0;
@ -272,15 +272,15 @@ int teach_cmd(unit * teacher, struct order *ord)
teachskill[t] = getskill(teacher->faction->locale); teachskill[t] = getskill(teacher->faction->locale);
} while (sk != NOSKILL); } while (sk != NOSKILL);
for (scholar = r->units; teaching > 0 && scholar; scholar = scholar->next) { for (student = r->units; teaching > 0 && student; student = student->next) {
if (LongHunger(scholar)) { if (LongHunger(student)) {
continue; continue;
} }
else if (scholar->faction == teacher->faction) { else if (student->faction == teacher->faction) {
if (getkeyword(scholar->thisorder) == K_STUDY) { if (getkeyword(student->thisorder) == K_STUDY) {
/* Input ist nun von student->thisorder !! */ /* Input ist nun von student->thisorder !! */
init_order(scholar->thisorder, scholar->faction->locale); init_order(student->thisorder, student->faction->locale);
sk = getskill(scholar->faction->locale); sk = getskill(student->faction->locale);
if (sk != NOSKILL && teachskill[0] != NOSKILL) { if (sk != NOSKILL && teachskill[0] != NOSKILL) {
for (t = 0; teachskill[t] != NOSKILL; ++t) { for (t = 0; teachskill[t] != NOSKILL; ++t) {
if (sk == teachskill[t]) { if (sk == teachskill[t]) {
@ -290,20 +290,20 @@ int teach_cmd(unit * teacher, struct order *ord)
sk = teachskill[t]; sk = teachskill[t];
} }
if (sk != NOSKILL if (sk != NOSKILL
&& effskill_study(teacher, sk) - TEACHDIFFERENCE > effskill_study(scholar, sk)) { && effskill_study(teacher, sk) - TEACHDIFFERENCE > effskill_study(student, sk)) {
teaching -= teach_unit(teacher, scholar, teaching, sk, true, &academy_students); teaching -= teach_unit(teacher, student, teaching, sk, true, &academy_students);
} }
} }
} }
#ifdef TEACH_FRIENDS #ifdef TEACH_FRIENDS
else if (alliedunit(teacher, scholar->faction, HELP_GUARD)) { else if (alliedunit(teacher, student->faction, HELP_GUARD)) {
if (getkeyword(scholar->thisorder) == K_STUDY) { if (getkeyword(student->thisorder) == K_STUDY) {
/* Input ist nun von student->thisorder !! */ /* Input ist nun von student->thisorder !! */
init_order(scholar->thisorder, scholar->faction->locale); init_order(student->thisorder, student->faction->locale);
sk = getskill(scholar->faction->locale); sk = getskill(student->faction->locale);
if (sk != NOSKILL if (sk != NOSKILL
&& effskill_study(teacher, sk) - TEACHDIFFERENCE >= effskill(scholar, sk, NULL)) { && effskill_study(teacher, sk) - TEACHDIFFERENCE >= effskill(student, sk, NULL)) {
teaching -= teach_unit(teacher, scholar, teaching, sk, true, &academy_students); teaching -= teach_unit(teacher, student, teaching, sk, true, &academy_students);
} }
} }
} }
@ -322,15 +322,15 @@ int teach_cmd(unit * teacher, struct order *ord)
while (!parser_end()) { while (!parser_end()) {
skill_t sk; skill_t sk;
unit *scholar; unit *student;
bool feedback; bool feedback;
getunit(r, teacher->faction, &scholar); getunit(r, teacher->faction, &student);
++count; ++count;
/* Falls die Unit nicht gefunden wird, Fehler melden */ /* Falls die Unit nicht gefunden wird, Fehler melden */
if (!scholar) { if (!student) {
char tbuf[20]; char tbuf[20];
const char *uid; const char *uid;
const char *token; const char *token;
@ -362,8 +362,8 @@ int teach_cmd(unit * teacher, struct order *ord)
continue; continue;
} }
feedback = teacher->faction == scholar->faction feedback = teacher->faction == student->faction
|| alliedunit(scholar, teacher->faction, HELP_GUARD); || alliedunit(student, teacher->faction, HELP_GUARD);
/* Neuen Befehl zusammenbauen. TEMP-Einheiten werden automatisch in /* Neuen Befehl zusammenbauen. TEMP-Einheiten werden automatisch in
* ihre neuen Nummern uebersetzt. */ * ihre neuen Nummern uebersetzt. */
@ -371,51 +371,51 @@ int teach_cmd(unit * teacher, struct order *ord)
strncat(zOrder, " ", sz - 1); strncat(zOrder, " ", sz - 1);
--sz; --sz;
} }
sz -= str_strlcpy(zOrder + 4096 - sz, itoa36(scholar->no), sz); sz -= str_strlcpy(zOrder + 4096 - sz, itoa36(student->no), sz);
if (getkeyword(scholar->thisorder) != K_STUDY) { if (getkeyword(student->thisorder) != K_STUDY) {
ADDMSG(&teacher->faction->msgs, ADDMSG(&teacher->faction->msgs,
msg_feedback(teacher, ord, "teach_nolearn", "student", scholar)); msg_feedback(teacher, ord, "teach_nolearn", "student", student));
continue; continue;
} }
/* Input ist nun von student->thisorder !! */ /* Input ist nun von student->thisorder !! */
parser_pushstate(); parser_pushstate();
init_order(scholar->thisorder, scholar->faction->locale); init_order(student->thisorder, student->faction->locale);
sk = getskill(scholar->faction->locale); sk = getskill(student->faction->locale);
parser_popstate(); parser_popstate();
if (sk == NOSKILL) { if (sk == NOSKILL) {
ADDMSG(&teacher->faction->msgs, ADDMSG(&teacher->faction->msgs,
msg_feedback(teacher, ord, "teach_nolearn", "student", scholar)); msg_feedback(teacher, ord, "teach_nolearn", "student", student));
continue; continue;
} }
if (effskill_study(scholar, sk) > effskill_study(teacher, sk) if (effskill_study(student, sk) > effskill_study(teacher, sk)
- TEACHDIFFERENCE) { - TEACHDIFFERENCE) {
if (feedback) { if (feedback) {
ADDMSG(&teacher->faction->msgs, msg_feedback(teacher, ord, "teach_asgood", ADDMSG(&teacher->faction->msgs, msg_feedback(teacher, ord, "teach_asgood",
"student", scholar)); "student", student));
} }
continue; continue;
} }
if (sk == SK_MAGIC) { if (sk == SK_MAGIC) {
/* ist der Magier schon spezialisiert, so versteht er nur noch /* ist der Magier schon spezialisiert, so versteht er nur noch
* Lehrer seines Gebietes */ * Lehrer seines Gebietes */
magic_t mage2 = unit_get_magic(scholar); magic_t mage2 = unit_get_magic(student);
if (mage2 != M_GRAY) { if (mage2 != M_GRAY) {
magic_t mage1 = unit_get_magic(teacher); magic_t mage1 = unit_get_magic(teacher);
if (mage1 != mage2) { if (mage1 != mage2) {
if (feedback) { if (feedback) {
ADDMSG(&teacher->faction->msgs, msg_feedback(teacher, ord, ADDMSG(&teacher->faction->msgs, msg_feedback(teacher, ord,
"error_different_magic", "target", scholar)); "error_different_magic", "target", student));
} }
continue; continue;
} }
} }
} }
sk_academy = sk; sk_academy = sk;
teaching -= teach_unit(teacher, scholar, teaching, sk, false, &academy_students); teaching -= teach_unit(teacher, student, teaching, sk, false, &academy_students);
} }
new_order = create_order(K_TEACH, teacher->faction->locale, "%s", zOrder); new_order = create_order(K_TEACH, teacher->faction->locale, "%s", zOrder);
replace_order(&teacher->orders, ord, new_order); replace_order(&teacher->orders, ord, new_order);
@ -428,45 +428,6 @@ int teach_cmd(unit * teacher, struct order *ord)
return 0; return 0;
} }
typedef enum study_rule_t {
STUDY_DEFAULT = 0,
STUDY_FASTER = 1,
STUDY_AUTOTEACH = 2
} study_rule_t;
static double study_speedup(unit * u, skill_t s, study_rule_t rule)
{
#define MINTURN 16
if (turn > MINTURN) {
if (rule == STUDY_FASTER) {
double learnweeks = 0;
int i;
for (i = 0; i != u->skill_size; ++i) {
skill *sv = u->skills + i;
if (sv->id == s) {
learnweeks = sv->level * (sv->level + 1) / 2.0;
if (learnweeks < turn / 3.0) {
return 2.0;
}
}
}
return 2.0; /* If the skill was not found it is the first study. */
}
if (rule == STUDY_AUTOTEACH) {
double learnweeks = 0;
int i;
for (i = 0; i != u->skill_size; ++i) {
skill *sv = u->skills + i;
learnweeks += (sv->level * (sv->level + 1) / 2.0);
}
if (learnweeks < turn / 2.0) {
return 2.0;
}
}
}
return 1.0;
}
static bool ExpensiveMigrants(void) static bool ExpensiveMigrants(void)
{ {
static bool rule; static bool rule;
@ -552,17 +513,12 @@ bool check_student(const struct unit *u, struct order *ord, skill_t sk) {
int study_cmd(unit * u, order * ord) int study_cmd(unit * u, order * ord)
{ {
region *r = u->region;
int p;
int l;
int studycost, days; int studycost, days;
double multi = 1.0;
attrib *a = NULL; attrib *a = NULL;
teaching_info *teach = NULL; teaching_info *teach = NULL;
int money = 0; int money = 0;
skill_t sk; skill_t sk;
int maxalchemy = 0; int maxalchemy = 0;
int speed_rule = (study_rule_t)config_get_int("study.speedup", 0);
static const race *rc_snotling; static const race *rc_snotling;
static int rc_cache; static int rc_cache;
@ -585,7 +541,6 @@ int study_cmd(unit * u, order * ord)
} }
} }
p = studycost = study_cost(u, sk);
a = a_find(u->attribs, &at_learning); a = a_find(u->attribs, &at_learning);
if (a != NULL) { if (a != NULL) {
teach = (teaching_info *)a->data.v; teach = (teaching_info *)a->data.v;
@ -594,16 +549,13 @@ int study_cmd(unit * u, order * ord)
/* keine kostenpflichtigen Talente fuer Migranten. Vertraute sind /* keine kostenpflichtigen Talente fuer Migranten. Vertraute sind
* keine Migranten, wird in is_migrant abgefangen. Vorsicht, * keine Migranten, wird in is_migrant abgefangen. Vorsicht,
* studycost darf hier noch nicht durch Akademie erhoeht sein */ * studycost darf hier noch nicht durch Akademie erhoeht sein */
studycost = study_cost(u, sk);
if (studycost > 0 && !ExpensiveMigrants() && is_migrant(u)) { if (studycost > 0 && !ExpensiveMigrants() && is_migrant(u)) {
ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error_migrants_nolearn", ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error_migrants_nolearn",
"")); ""));
return -1; return -1;
} }
/* Akademie: */
if (active_building(u, bt_find("academy"))) {
studycost = studycost * 2;
if (studycost < 50) studycost = 50;
}
if (sk == SK_MAGIC) { if (sk == SK_MAGIC) {
magic_t mtype; magic_t mtype;
@ -684,71 +636,31 @@ int study_cmd(unit * u, order * ord)
} }
} }
} }
days = teach ? teach->days : 0;
days += study_days(u, sk);
if (studycost) { if (studycost) {
int cost = studycost * u->number; int cost = studycost * u->number;
money = get_pooled(u, get_resourcetype(R_SILVER), GET_DEFAULT, cost); money = get_pooled(u, get_resourcetype(R_SILVER), GET_DEFAULT, cost);
if (money > cost) money = cost; if (money > cost) money = cost;
} if (money < studycost * u->number) {
if (money < studycost * u->number) { int cost = studycost * u->number;
studycost = p; /* Ohne Univertreurung */ if (money > studycost) money = studycost;
if (money > studycost) money = studycost; if (money < cost) {
if (p > 0 && money < studycost * u->number) { /* we cannot afford everyone, but use as much as we have */
cmistake(u, ord, 65, MSG_EVENT); cmistake(u, ord, 65, MSG_EVENT);
multi = money / (double)(studycost * u->number); days = days * money / cost;
}
} }
} }
money += learn_skill(u, sk, days, studycost);
if (teach == NULL) {
a = a_add(&u->attribs, a_new(&at_learning));
teach = (teaching_info *)a->data.v;
assert(teach);
teach->teachers = NULL;
}
if (money > 0) { if (money > 0) {
use_pooled(u, get_resourcetype(R_SILVER), GET_DEFAULT, money); use_pooled(u, get_resourcetype(R_SILVER), GET_DEFAULT, money);
ADDMSG(&u->faction->msgs, msg_message("studycost", ADDMSG(&u->faction->msgs, msg_message("studycost",
"unit region cost skill", u, u->region, money, sk)); "unit region cost skill", u, u->region, money, sk));
} }
if (get_effect(u, oldpotiontype[P_WISE])) {
l = get_effect(u, oldpotiontype[P_WISE]);
if (l > u->number) l = u->number;
teach->days += l * EXPERIENCEDAYS;
change_effect(u, oldpotiontype[P_WISE], -l);
}
if (get_effect(u, oldpotiontype[P_FOOL])) {
l = get_effect(u, oldpotiontype[P_FOOL]);
if (l > u->number) l = u->number;
teach->days -= l * STUDYDAYS;
change_effect(u, oldpotiontype[P_FOOL], -l);
}
if (p != studycost) {
/* ist_in_gebaeude(r, u, BT_UNIVERSITAET) == 1) { */
/* p ist Kosten ohne Uni, studycost mit; wenn
* p!=studycost, ist die Einheit zwangsweise
* in einer Uni */
teach->days += u->number * EXPERIENCEDAYS;
}
if (is_cursed(r->attribs, &ct_badlearn)) {
teach->days -= u->number * EXPERIENCEDAYS;
}
multi *= study_speedup(u, sk, speed_rule);
days = study_days(u, sk);
days = (int)((days + teach->days) * multi);
/* the artacademy currently improves the learning of entertainment
of all units in the region, to be able to make it cumulative with
with an academy */
if (sk == SK_ENTERTAINMENT
&& buildingtype_exists(r, bt_find("artacademy"), false)) {
days *= 2;
}
learn_skill(u, sk, days);
if (a != NULL) { if (a != NULL) {
if (teach->teachers) { if (teach->teachers) {
msg_teachers(teach->teachers, u, sk); msg_teachers(teach->teachers, u, sk);
@ -789,56 +701,136 @@ void produceexp_ex(struct unit *u, skill_t sk, int n, learn_fun learn)
} }
} }
void produceexp(struct unit *u, skill_t sk, int n)
{
produceexp_ex(u, sk, n, learn_skill);
}
static learn_fun inject_learn_fun = 0; static learn_fun inject_learn_fun = 0;
void inject_learn(learn_fun fun) { void inject_learn(learn_fun fun) {
inject_learn_fun = fun; inject_learn_fun = fun;
} }
/** days should be scaled by u->number; STUDYDAYS * u->number is one week worth of learning */ static void increase_skill_days(unit *u, skill_t sk, int days) {
void learn_skill(unit *u, skill_t sk, int days) { assert(sk >= 0 && sk < MAXSKILLS && days >= 0);
int leveldays = STUDYDAYS * u->number; if (days > 0) {
int weeks = 0; int leveldays = STUDYDAYS * u->number;
int weeks = 0;
if (inject_learn_fun) {
inject_learn_fun(u, sk, days);
return;
}
while (days >= leveldays) {
++weeks;
days -= leveldays;
}
if (days > 0 && rng_int() % leveldays < days) {
++weeks;
}
if (weeks > 0) {
increase_skill(u, sk, weeks);
}
}
}
static void reduce_skill_days(unit *u, skill_t sk, int days) {
if (days > 0) {
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;
}
}
}
}
}
void produceexp(struct unit *u, skill_t sk, int n)
{
produceexp_ex(u, sk, n, increase_skill_days);
}
static int speed_rule;
/**
* days should be scaled by u->number; STUDYDAYS * u->number is one week worth of learning
* @return int
* The additional spend, i.e. from an academy.
*/
int learn_skill(unit *u, skill_t sk, int days, int studycost) {
region *r = u->region;
int cost = 0;
if (r->buildings) {
static const building_type *bt_artacademy;
static const building_type *bt_academy;
static int config;
if (bt_changed(&config)) {
bt_artacademy = bt_find("artacademy");
bt_academy = bt_find("academy");
}
/* Akademie: */
if (bt_academy && active_building(u, bt_academy)) {
int avail, n = u->number;
if (studycost < 50) studycost = 50;
cost = studycost * u->number;
avail = get_pooled(u, get_resourcetype(R_SILVER), GET_DEFAULT, studycost * u->number);
if (avail < cost) {
/* not all students can afford the academy */
cost = avail;
n = n * avail / cost;
cost = n * studycost;
}
days += EXPERIENCEDAYS * n;
}
/* the artacademy currently improves the learning of entertainment
of all units in the region, to be able to make it cumulative with
with an academy */
if (bt_artacademy && sk == SK_ENTERTAINMENT
&& buildingtype_exists(r, bt_artacademy, false)) {
days *= 2;
}
}
if (u->attribs) {
if (get_effect(u, oldpotiontype[P_WISE])) {
int effect = get_effect(u, oldpotiontype[P_WISE]);
if (effect > u->number) effect = u->number;
days += effect * EXPERIENCEDAYS;
change_effect(u, oldpotiontype[P_WISE], -effect);
}
if (get_effect(u, oldpotiontype[P_FOOL])) {
int effect = get_effect(u, oldpotiontype[P_FOOL]);
if (effect > u->number) effect = u->number;
days -= effect * STUDYDAYS;
change_effect(u, oldpotiontype[P_FOOL], -effect);
}
}
if (is_cursed(r->attribs, &ct_badlearn)) {
days -= EXPERIENCEDAYS * u->number;
}
if (fval(u, UFL_HUNGER)) { if (fval(u, UFL_HUNGER)) {
days /= 2; days /= 2;
} }
assert(sk >= 0 && sk < MAXSKILLS); increase_skill_days(u, sk, days);
if (inject_learn_fun) { return cost;
inject_learn_fun(u, sk, days);
return;
}
while (days >= leveldays) {
++weeks;
days -= leveldays;
}
if (days > 0 && rng_int() % leveldays < days) {
++weeks;
}
if (weeks > 0) {
increase_skill(u, sk, weeks);
}
} }
void reduce_skill_days(unit *u, skill_t sk, int days) { void change_skill_days(unit *u, skill_t sk, int days) {
skill *sv = unit_skill(u, sk); if (days < 0) {
if (sv) { reduce_skill_days(u, sk, -days);
while (days > 0) { }
if (days >= STUDYDAYS * u->number) { else {
reduce_skill(u, sv, 1); increase_skill_days(u, sk, days);
days -= STUDYDAYS;
}
else {
if (chance (days / ((double) STUDYDAYS * u->number))) /* (rng_int() % (30 * u->number) < days)*/
reduce_skill(u, sv, 1);
days = 0;
}
}
} }
} }
@ -885,7 +877,7 @@ void demon_skillchange(unit *u)
} }
} }
else { else {
learn_skill(u, sv->id, STUDYDAYS * u->number * weeks); change_skill_days(u, sv->id, STUDYDAYS * u->number * weeks);
} }
} }
++sv; ++sv;

View File

@ -34,8 +34,8 @@ extern "C" {
typedef void(*learn_fun)(struct unit *u, skill_t sk, int days); typedef void(*learn_fun)(struct unit *u, skill_t sk, int days);
void learn_skill(struct unit *u, skill_t sk, int days); int learn_skill(struct unit *u, skill_t sk, int days, int studycost);
void reduce_skill_days(struct unit *u, skill_t sk, int days); void change_skill_days(struct unit *u, skill_t sk, int days);
void produceexp(struct unit *u, skill_t sk, int n); 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 produceexp_ex(struct unit *u, skill_t sk, int n, learn_fun learn);

View File

@ -364,14 +364,14 @@ void test_learn_skill_single(CuTest *tc) {
setup_study(); setup_study();
config_set("study.random_progress", "0"); config_set("study.random_progress", "0");
u = test_create_unit(test_create_faction(NULL), test_create_region(0, 0, NULL)); u = test_create_unit(test_create_faction(NULL), test_create_region(0, 0, NULL));
learn_skill(u, SK_ALCHEMY, STUDYDAYS); CuAssertIntEquals(tc, 0, learn_skill(u, SK_ALCHEMY, STUDYDAYS, 0));
CuAssertPtrNotNull(tc, sv = u->skills); CuAssertPtrNotNull(tc, sv = u->skills);
CuAssertIntEquals(tc, SK_ALCHEMY, sv->id); CuAssertIntEquals(tc, SK_ALCHEMY, sv->id);
CuAssertIntEquals(tc, 1, sv->level); CuAssertIntEquals(tc, 1, sv->level);
CuAssertIntEquals(tc, 2, sv->weeks); CuAssertIntEquals(tc, 2, sv->weeks);
learn_skill(u, SK_ALCHEMY, STUDYDAYS); CuAssertIntEquals(tc, 0, learn_skill(u, SK_ALCHEMY, STUDYDAYS, 0));
CuAssertIntEquals(tc, 1, sv->weeks); CuAssertIntEquals(tc, 1, sv->weeks);
learn_skill(u, SK_ALCHEMY, STUDYDAYS * 2); CuAssertIntEquals(tc, 0, learn_skill(u, SK_ALCHEMY, STUDYDAYS * 2, 0));
CuAssertIntEquals(tc, 2, sv->level); CuAssertIntEquals(tc, 2, sv->level);
CuAssertIntEquals(tc, 2, sv->weeks); CuAssertIntEquals(tc, 2, sv->weeks);
test_teardown(); test_teardown();
@ -385,14 +385,14 @@ void test_learn_skill_multi(CuTest *tc) {
config_set("study.random_progress", "0"); config_set("study.random_progress", "0");
u = test_create_unit(test_create_faction(NULL), test_create_region(0, 0, NULL)); u = test_create_unit(test_create_faction(NULL), test_create_region(0, 0, NULL));
scale_number(u, 10); scale_number(u, 10);
learn_skill(u, SK_ALCHEMY, STUDYDAYS * u->number); CuAssertIntEquals(tc, 0, learn_skill(u, SK_ALCHEMY, STUDYDAYS * u->number, 0));
CuAssertPtrNotNull(tc, sv = u->skills); CuAssertPtrNotNull(tc, sv = u->skills);
CuAssertIntEquals(tc, SK_ALCHEMY, sv->id); CuAssertIntEquals(tc, SK_ALCHEMY, sv->id);
CuAssertIntEquals(tc, 1, sv->level); CuAssertIntEquals(tc, 1, sv->level);
CuAssertIntEquals(tc, 2, sv->weeks); CuAssertIntEquals(tc, 2, sv->weeks);
learn_skill(u, SK_ALCHEMY, STUDYDAYS * u->number); CuAssertIntEquals(tc, 0, learn_skill(u, SK_ALCHEMY, STUDYDAYS * u->number, 0));
CuAssertIntEquals(tc, 1, sv->weeks); CuAssertIntEquals(tc, 1, sv->weeks);
learn_skill(u, SK_ALCHEMY, STUDYDAYS * u->number * 2); CuAssertIntEquals(tc, 0, learn_skill(u, SK_ALCHEMY, STUDYDAYS * u->number * 2, 0));
CuAssertIntEquals(tc, 2, sv->level); CuAssertIntEquals(tc, 2, sv->level);
CuAssertIntEquals(tc, 2, sv->weeks); CuAssertIntEquals(tc, 2, sv->weeks);
test_teardown(); test_teardown();