Merge branch '2541-quit' into develop

This commit is contained in:
Enno Rehling 2019-05-04 12:01:55 +02:00
commit 5c7788ecdd
17 changed files with 312 additions and 73 deletions

View File

@ -2937,13 +2937,6 @@
<arg name="command" type="order"/>
</type>
</message>
<message name="error282" section="errors">
<type>
<arg name="unit" type="unit"/>
<arg name="region" type="region"/>
<arg name="command" type="order"/>
</type>
</message>
<message name="error281" section="errors">
<type>
<arg name="unit" type="unit"/>
@ -3244,13 +3237,6 @@
<arg name="target" type="region"/>
</type>
</message>
<message name="error241" section="errors">
<type>
<arg name="unit" type="unit"/>
<arg name="region" type="region"/>
<arg name="command" type="order"/>
</type>
</message>
<message name="error240" section="errors">
<type>
<arg name="unit" type="unit"/>

View File

@ -587,9 +587,6 @@ msgstr "\"$unit($unit) in $region($region): '$order($command)' - Unbekannte Opti
msgid "error131"
msgstr "\"$unit($unit) in $region($region): '$order($command)' - Um in Gletschern Straßen bauen zu können, muß zuerst ein Tunnel errichtet werden.\""
msgid "error241"
msgstr "\"$unit($unit) in $region($region): '$order($command)' - Die Partei muß mindestens 81 Wochen alt sein, um einen Neustart mit einer anderen Rasse zu versuchen.\""
msgid "feedback_unit_not_found"
msgstr "\"$unit($unit) in $region($region): '$order($command)' - Die Einheit wurde nicht gefunden.\""
@ -1119,7 +1116,7 @@ msgid "dissolve_units_4"
msgstr "\"$unit($unit) in $region($region): $int($number) $race($race,$number) $if($eq($number,1),\"zerfiel\", \"zerfielen\") zu Staub.\""
msgid "error281"
msgstr "\"$unit($unit) in $region($region): '$order($command)' - Gegen welche Rasse soll der Jihad ausgerufen werden?\""
msgstr "\"$unit($unit) in $region($region): '$order($command)' - Die Zielpartei muss die selbe Rasse haben.\""
msgid "error171"
msgstr "\"$unit($unit) in $region($region): '$order($command)' - Diesen Kampfzauber gibt es nicht.\""
@ -1784,9 +1781,6 @@ msgstr "\"$unit($unit) in $region($region): '$order($command)' - Es konnte kein
msgid "error50"
msgstr "\"$unit($unit) in $region($region): '$order($command)' - Die Einheit ist nicht erfahren genug dafür.\""
msgid "error282"
msgstr "\"$unit($unit) in $region($region): '$order($command)' - Gegen diese Rasse kann kein Jihad ausgerufen werden.\""
msgid "nmr_warning_final"
msgstr "\"Bitte sende die Befehle nächste Runde ein, wenn du weiterspielen möchtest.\""

View File

@ -587,9 +587,6 @@ msgstr "\"$unit($unit) in $region($region): '$order($command)' - Unknown option.
msgid "error131"
msgstr "\"$unit($unit) in $region($region): '$order($command)' - You must build a tunnel before building roads through glaciers.\""
msgid "error241"
msgstr "\"$unit($unit) in $region($region): '$order($command)' - The faction must be at least 81 weeks old to restart with a new race.\""
msgid "feedback_unit_not_found"
msgstr "\"$unit($unit) in $region($region): '$order($command)' - The unit could not be found.\""
@ -1119,7 +1116,7 @@ msgid "dissolve_units_4"
msgstr "\"$unit($unit) in $region($region): $int($number) $race($race,$number) turned to dust.\""
msgid "error281"
msgstr "\"$unit($unit) in $region($region): '$order($command)' - What race did you want the jihad to be against?\""
msgstr "\"$unit($unit) in $region($region): '$order($command)' - The target faction must have the same race as yours.\""
msgid "error171"
msgstr "\"$unit($unit) in $region($region): '$order($command)' - This combat spell does not exist.\""
@ -1784,9 +1781,6 @@ msgstr "\"$unit($unit) in $region($region): '$order($command)' - No peasant coul
msgid "error50"
msgstr "\"$unit($unit) in $region($region): '$order($command)' - The unit is not experienced enough to do this.\""
msgid "error282"
msgstr "\"$unit($unit) in $region($region): '$order($command)' - You cannot start a jihad against this race.\""
msgid "nmr_warning_final"
msgstr "\"Please send in orders for the next turn if you want to continue playing.\""

View File

@ -548,7 +548,7 @@ static void recruit(unit * u, struct order *ord, econ_request ** recruitorders)
return;
}
if (has_skill(u, SK_ALCHEMY)) {
if (count_skill(u->faction, SK_ALCHEMY) + n > skill_limit(u->faction, SK_ALCHEMY)) {
if (faction_count_skill(u->faction, SK_ALCHEMY) + n > faction_skill_limit(u->faction, SK_ALCHEMY)) {
cmistake(u, ord, 156, MSG_EVENT);
return;
}

View File

@ -299,7 +299,7 @@ static bool can_give_men(const unit *u, const unit *dst, order *ord, message **m
return false;
}
static bool rule_transfermen(void)
bool rule_transfermen(void)
{
int rule = config_get_int("rules.transfermen", 1);
return rule != 0;
@ -391,7 +391,7 @@ message * give_men(int n, unit * u, unit * u2, struct order *ord)
}
if (has_skill(u, SK_ALCHEMY) || has_skill(u2, SK_ALCHEMY)) {
int k = count_skill(u2->faction, SK_ALCHEMY);
int k = faction_count_skill(u2->faction, SK_ALCHEMY);
/* Falls die Zieleinheit keine Alchemisten sind, werden sie nun
* welche. */
@ -408,7 +408,7 @@ message * give_men(int n, unit * u, unit * u2, struct order *ord)
/* wird das Alchemistenmaximum ueberschritten ? */
if (k > skill_limit(u2->faction, SK_ALCHEMY)) {
if (k > faction_skill_limit(u2->faction, SK_ALCHEMY)) {
error = 156;
}
}
@ -472,9 +472,23 @@ message * disband_men(int n, unit * u, struct order *ord) {
return msg_message("give_person_peasants", "unit amount", u, n);
}
int give_unit_allowed(const unit * u)
{
if (unit_has_cursed_item(u)) {
return 78;
}
if (fval(u, UFL_HERO)) {
return 75;
}
if (fval(u, UFL_LOCKED) || fval(u, UFL_HUNGER)) {
return 74;
}
return 0;
}
void give_unit(unit * u, unit * u2, order * ord)
{
int maxt = max_transfers();
int err, maxt = max_transfers();
assert(u);
if (!rule_transfermen() && u2 && u->faction != u2->faction) {
@ -482,17 +496,9 @@ void give_unit(unit * u, unit * u2, order * ord)
return;
}
if (unit_has_cursed_item(u)) {
cmistake(u, ord, 78, MSG_COMMERCE);
return;
}
if (fval(u, UFL_HERO)) {
cmistake(u, ord, 75, MSG_COMMERCE);
return;
}
if (fval(u, UFL_LOCKED) || fval(u, UFL_HUNGER)) {
cmistake(u, ord, 74, MSG_COMMERCE);
err = give_unit_allowed(u);
if (err != 0) {
cmistake(u, ord, err, MSG_COMMERCE);
return;
}
@ -586,8 +592,8 @@ void give_unit(unit * u, unit * u2, order * ord)
}
}
if (has_skill(u, SK_MAGIC)) {
if (count_skill(u2->faction, SK_MAGIC) + u->number >
skill_limit(u2->faction, SK_MAGIC)) {
if (faction_count_skill(u2->faction, SK_MAGIC) + u->number >
faction_skill_limit(u2->faction, SK_MAGIC)) {
cmistake(u, ord, 155, MSG_COMMERCE);
return;
}
@ -597,8 +603,8 @@ void give_unit(unit * u, unit * u2, order * ord)
}
}
if (has_skill(u, SK_ALCHEMY)
&& count_skill(u2->faction, SK_ALCHEMY) + u->number >
skill_limit(u2->faction, SK_ALCHEMY)) {
&& faction_count_skill(u2->faction, SK_ALCHEMY) + u->number >
faction_skill_limit(u2->faction, SK_ALCHEMY)) {
cmistake(u, ord, 156, MSG_COMMERCE);
return;
}

View File

@ -29,10 +29,12 @@ extern "C" {
struct message * disband_men(int n, struct unit * u, struct order *ord);
struct message * give_men(int n, struct unit *u, struct unit *u2,
struct order *ord);
int give_unit_allowed(const struct unit * u);
void give_unit(struct unit *u, struct unit *u2, struct order *ord);
void give_cmd(struct unit * u, struct order * ord);
struct message * check_give(const struct unit * u, const struct unit * u2, struct order *ord);
bool can_give_to(struct unit *u, struct unit *u2);
bool rule_transfermen(void);
#ifdef __cplusplus
}

View File

@ -572,7 +572,7 @@ static int build_limited(unit * u, const construction * con, int completed, int
}
/* Flinkfingerring wirkt nicht auf Mengenbegrenzte (magische)
* Talente */
if (skill_limit(u->faction, con->skill) == INT_MAX) {
if (faction_skill_limit(u->faction, con->skill) == INT_MAX) {
const resource_type *ring = get_resourcetype(R_RING_OF_NIMBLEFINGER);
item *itm = ring ? *i_find(&u->items, ring->itype) : 0;
int i = itm ? itm->number : 0;

View File

@ -609,7 +609,7 @@ static int allied_skillcount(const faction * f, skill_t sk)
for (qi = 0; members; selist_advance(&members, &qi, 1)) {
faction *m = (faction *)selist_get(members, qi);
num += count_skill(m, sk);
num += faction_count_skill(m, sk);
}
return num;
}
@ -623,7 +623,7 @@ static int allied_skilllimit(const faction * f, skill_t sk)
return value;
}
int count_skill(faction * f, skill_t sk)
int faction_count_skill(faction * f, skill_t sk)
{
int n = 0;
unit *u;
@ -638,7 +638,7 @@ int count_skill(faction * f, skill_t sk)
return n;
}
int skill_limit(faction * f, skill_t sk)
int faction_skill_limit(const faction * f, skill_t sk)
{
int m = INT_MAX;
int al = allied_skilllimit(f, sk);

View File

@ -161,8 +161,8 @@ extern "C" {
struct spellbook * faction_get_spellbook(struct faction *f);
/* skills */
int skill_limit(struct faction *f, skill_t sk);
int count_skill(struct faction *f, skill_t sk);
int faction_skill_limit(const struct faction *f, skill_t sk);
int faction_count_skill(struct faction *f, skill_t sk);
bool faction_id_is_unused(int);
#define COUNT_MONSTERS 0x01

View File

@ -25,6 +25,7 @@
#include <assert.h>
#include <stdio.h>
#include <limits.h>
static void test_destroyfaction_allies(CuTest *tc) {
faction *f1, *f2;
@ -211,6 +212,26 @@ static void test_max_migrants(CuTest *tc) {
test_teardown();
}
static void test_skill_limit(CuTest *tc) {
faction *f;
test_setup();
f = test_create_faction(NULL);
CuAssertIntEquals(tc, INT_MAX, faction_skill_limit(f, SK_ENTERTAINMENT));
CuAssertIntEquals(tc, 3, faction_skill_limit(f, SK_ALCHEMY));
config_set_int("rules.maxskills.alchemy", 4);
CuAssertIntEquals(tc, 4, faction_skill_limit(f, SK_ALCHEMY));
CuAssertIntEquals(tc, 3, faction_skill_limit(f, SK_MAGIC));
CuAssertIntEquals(tc, 3, max_magicians(f));
config_set_int("rules.maxskills.magic", 4);
CuAssertIntEquals(tc, 4, faction_skill_limit(f, SK_MAGIC));
CuAssertIntEquals(tc, 4, max_magicians(f));
f->race = test_create_race(racenames[RC_ELF]);
CuAssertIntEquals(tc, 5, faction_skill_limit(f, SK_MAGIC));
CuAssertIntEquals(tc, 5, max_magicians(f));
test_teardown();
}
static void test_valid_race(CuTest *tc) {
race * rc1, *rc2;
faction *f;
@ -334,6 +355,7 @@ CuSuite *get_faction_suite(void)
CuSuite *suite = CuSuiteNew();
SUITE_ADD_TEST(suite, test_addplayer);
SUITE_ADD_TEST(suite, test_max_migrants);
SUITE_ADD_TEST(suite, test_skill_limit);
SUITE_ADD_TEST(suite, test_addfaction);
SUITE_ADD_TEST(suite, test_remove_empty_factions);
SUITE_ADD_TEST(suite, test_destroyfaction_allies);

View File

@ -1812,17 +1812,27 @@ int maintenance_cost(const struct unit *u)
return u_race(u)->maintenance * u->number;
}
static skill_t limited_skills[] = { SK_MAGIC, SK_ALCHEMY, SK_TACTICS, SK_SPY, SK_HERBALISM, NOSKILL };
static skill_t limited_skills[] = { SK_ALCHEMY, SK_HERBALISM, SK_MAGIC, SK_SPY, SK_TACTICS, NOSKILL };
bool is_limited_skill(skill_t sk)
{
int i;
for (i = 0; limited_skills[i] != NOSKILL; ++i) {
if (sk == limited_skills[i]) {
return true;
}
}
return false;
}
bool has_limited_skills(const struct unit * u)
{
int i, j;
int i;
for (i = 0; i != u->skill_size; ++i) {
skill *sv = u->skills + i;
for (j = 0; limited_skills[j] != NOSKILL; ++j) {
if (sv->id == limited_skills[j]) {
return true;
}
if (is_limited_skill(sv->id)) {
return true;
}
}
return false;

View File

@ -251,6 +251,7 @@ extern "C" {
bool has_horses(const struct unit *u);
int maintenance_cost(const struct unit *u);
bool has_limited_skills(const struct unit *u);
bool is_limited_skill(skill_t sk);
#ifdef __cplusplus
}

View File

@ -30,6 +30,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#include "battle.h"
#include "contact.h"
#include "economy.h"
#include "give.h"
#include "market.h"
#include "morale.h"
#include "monsters.h"
@ -395,8 +396,7 @@ static void peasants(region * r, int rule)
dead += (int)(0.5 + n * PEASANT_STARVATION_CHANCE);
if (dead > 0) {
message *msg = add_message(&r->msgs, msg_message("phunger", "dead", dead));
msg_release(msg);
ADDMSG(&r->msgs, msg_message("phunger", "dead", dead));
peasants -= dead;
}
@ -941,6 +941,52 @@ int leave_cmd(unit * u, struct order *ord)
return 0;
}
void transfer_faction(faction *fsrc, faction *fdst) {
unit *u;
skill_t sk;
int skill_count[MAXSKILLS];
int skill_limit[MAXSKILLS];
for (sk = 0; sk != MAXSKILLS; ++sk) {
skill_limit[sk] = faction_skill_limit(fdst, sk);
}
memset(skill_count, 0, sizeof(skill_count));
for (u = fdst->units; u != NULL; u = u->nextF) {
if (u->skills) {
int i;
for (i = 0; i != u->skill_size; ++i) {
const skill *sv = u->skills + i;
skill_t sk = (skill_t)sv->id;
skill_count[sk] += u->number;
}
}
}
for (u = fsrc->units; u != NULL; u = u->nextF) {
if (u_race(u) == fdst->race) {
u->flags &= ~UFL_HERO;
if (give_unit_allowed(u) == 0) {
if (u->skills) {
int i;
for (i = 0; i != u->skill_size; ++i) {
const skill *sv = u->skills + i;
skill_t sk = (skill_t)sv->id;
if (skill_count[sk] + u->number > skill_limit[sk]) {
break;
}
}
if (i != u->skill_size) {
continue;
}
}
u_setfaction(u, fdst);
}
}
}
}
int quit_cmd(unit * u, struct order *ord)
{
char token[128];
@ -952,7 +998,37 @@ int quit_cmd(unit * u, struct order *ord)
assert(kwd == K_QUIT);
passwd = gettoken(token, sizeof(token));
if (checkpasswd(f, (const char *)passwd)) {
fset(f, FFL_QUIT);
int flags = FFL_QUIT;
if (rule_transfermen()) {
param_t p;
p = getparam(f->locale);
if (p == P_FACTION) {
faction *f2 = getfaction();
if (f2 == NULL) {
cmistake(u, ord, 66, MSG_EVENT);
flags = 0;
}
else if (f->race != f2->race) {
cmistake(u, ord, 281, MSG_EVENT);
flags = 0;
}
else {
unit *u2;
for (u2 = u->region->units; u2; u2 = u2->next) {
if (u2->faction == f2 && ucontact(u2, u)) {
transfer_faction(u->faction, u2->faction);
break;
}
}
if (u2 == NULL) {
/* no target unit found */
cmistake(u, ord, 0, MSG_EVENT);
flags = 0;
}
}
}
}
f->flags |= flags;
}
else {
char buffer[64];
@ -2077,7 +2153,7 @@ int banner_cmd(unit * u, struct order *ord)
init_order_depr(ord);
s = getstrtoken();
faction_setbanner(u->faction, s);
add_message(&u->faction->msgs, msg_message("changebanner", "value", s));
ADDMSG(&u->faction->msgs, msg_message("changebanner", "value", s));
return 0;
}

View File

@ -1,6 +1,7 @@
#include <platform.h>
#include "laws.h"
#include "battle.h"
#include "contact.h"
#include "guard.h"
#include "monsters.h"
@ -1868,6 +1869,149 @@ static void test_long_order_on_ocean(CuTest *tc) {
test_teardown();
}
static void test_quit(CuTest *tc) {
faction *f;
unit *u;
region *r;
test_setup();
r = test_create_plain(0, 0);
f = test_create_faction(NULL);
u = test_create_unit(f, r);
u->thisorder = create_order(K_QUIT, f->locale, "password");
faction_setpassword(f, "passwort");
quit_cmd(u, u->thisorder);
CuAssertIntEquals(tc, 0, f->flags & FFL_QUIT);
faction_setpassword(f, "password");
quit_cmd(u, u->thisorder);
CuAssertIntEquals(tc, FFL_QUIT, f->flags & FFL_QUIT);
test_teardown();
}
/**
* Gifting units to another faction upon voluntary death (QUIT).
*/
static void test_quit_transfer(CuTest *tc) {
faction *f1, *f2;
unit *u1, *u2;
region *r;
test_setup();
r = test_create_plain(0, 0);
f1 = test_create_faction(NULL);
faction_setpassword(f1, "password");
u1 = test_create_unit(f1, r);
f2 = test_create_faction(NULL);
u2 = test_create_unit(f2, r);
contact_unit(u2, u1);
u1->thisorder = create_order(K_QUIT, f1->locale, "password %s %s",
LOC(f1->locale, parameters[P_FACTION]), itoa36(f2->no));
quit_cmd(u1, u1->thisorder);
CuAssertIntEquals(tc, FFL_QUIT, f1->flags & FFL_QUIT);
CuAssertPtrEquals(tc, f2, u1->faction);
test_teardown();
}
/**
* Gifting units with limited skills to another faction.
*
* This is allowed only up to the limit of the target faction.
* Units that would break the limit are not transferred.
*/
static void test_quit_transfer_limited(CuTest *tc) {
faction *f1, *f2;
unit *u1, *u2;
region *r;
test_setup();
r = test_create_plain(0, 0);
f1 = test_create_faction(NULL);
faction_setpassword(f1, "password");
u1 = test_create_unit(f1, r);
f2 = test_create_faction(NULL);
u2 = test_create_unit(f2, r);
contact_unit(u2, u1);
u1->thisorder = create_order(K_QUIT, f1->locale, "password %s %s",
LOC(f1->locale, parameters[P_FACTION]), itoa36(f2->no));
set_level(u1, SK_MAGIC, 1);
set_level(u2, SK_MAGIC, 1);
CuAssertIntEquals(tc, true, has_limited_skills(u1));
config_set_int("rules.maxskills.magic", 1);
quit_cmd(u1, u1->thisorder);
CuAssertIntEquals(tc, FFL_QUIT, f1->flags & FFL_QUIT);
CuAssertPtrEquals(tc, f1, u1->faction);
f1->flags -= FFL_QUIT;
config_set_int("rules.maxskills.magic", 2);
quit_cmd(u1, u1->thisorder);
CuAssertIntEquals(tc, FFL_QUIT, f1->flags & FFL_QUIT);
CuAssertPtrEquals(tc, f2, u1->faction);
test_teardown();
}
/**
* Only units of the same race can be gifted to another faction.
*/
static void test_quit_transfer_migrants(CuTest *tc) {
faction *f1, *f2;
unit *u1, *u2;
region *r;
test_setup();
r = test_create_plain(0, 0);
f1 = test_create_faction(NULL);
faction_setpassword(f1, "password");
u1 = test_create_unit(f1, r);
f2 = test_create_faction(NULL);
u2 = test_create_unit(f2, r);
contact_unit(u2, u1);
u1->thisorder = create_order(K_QUIT, f1->locale, "password %s %s",
LOC(f1->locale, parameters[P_FACTION]), itoa36(f2->no));
u_setrace(u1, test_create_race("smurf"));
quit_cmd(u1, u1->thisorder);
CuAssertIntEquals(tc, FFL_QUIT, f1->flags & FFL_QUIT);
CuAssertPtrEquals(tc, f1, u1->faction);
test_teardown();
}
/**
* A hero that is gifted to another faction loses their status.
*/
static void test_quit_transfer_hero(CuTest *tc) {
faction *f1, *f2;
unit *u1, *u2;
region *r;
test_setup();
r = test_create_plain(0, 0);
f1 = test_create_faction(NULL);
faction_setpassword(f1, "password");
u1 = test_create_unit(f1, r);
f2 = test_create_faction(NULL);
u2 = test_create_unit(f2, r);
contact_unit(u2, u1);
u1->thisorder = create_order(K_QUIT, f1->locale, "password %s %s",
LOC(f1->locale, parameters[P_FACTION]), itoa36(f2->no));
u1->flags |= UFL_HERO;
quit_cmd(u1, u1->thisorder);
CuAssertIntEquals(tc, FFL_QUIT, f1->flags & FFL_QUIT);
CuAssertPtrEquals(tc, f2, u1->faction);
CuAssertIntEquals(tc, 0, u1->flags & UFL_HERO);
test_teardown();
}
CuSuite *get_laws_suite(void)
{
CuSuite *suite = CuSuiteNew();
@ -1943,6 +2087,11 @@ CuSuite *get_laws_suite(void)
SUITE_ADD_TEST(suite, test_nmr_timeout);
SUITE_ADD_TEST(suite, test_long_orders);
SUITE_ADD_TEST(suite, test_long_order_on_ocean);
SUITE_ADD_TEST(suite, test_quit);
SUITE_ADD_TEST(suite, test_quit_transfer);
SUITE_ADD_TEST(suite, test_quit_transfer_limited);
SUITE_ADD_TEST(suite, test_quit_transfer_migrants);
SUITE_ADD_TEST(suite, test_quit_transfer_hero);
return suite;
}

View File

@ -603,8 +603,7 @@ void plagues(region * r)
}
if (dead > 0) {
message *msg = add_message(&r->msgs, msg_message("pest", "dead", dead));
msg_release(msg);
ADDMSG(&r->msgs, msg_message("pest", "dead", dead));
deathcounts(r, dead);
rsetpeasants(r, peasants - dead);
}

View File

@ -3109,8 +3109,8 @@ static int sp_chaossuction(castorder * co)
create_special_direction(rt, r, 2, "vortex_desc", "vortex", false);
new_border(&bt_chaosgate, r, rt);
add_message(&r->msgs, msg_message("chaosgate_effect_1", "mage", caster));
add_message(&rt->msgs, msg_message("chaosgate_effect_2", ""));
ADDMSG(&r->msgs, msg_message("chaosgate_effect_1", "mage", caster));
ADDMSG(&rt->msgs, msg_message("chaosgate_effect_2", ""));
return cast_level;
}
@ -3450,7 +3450,7 @@ static bool can_charm(const unit * u, int maxlevel)
while (l < h) {
int m = (l + h) / 2;
if (sk == expskills[m]) {
if (skill_limit(u->faction, sk) != INT_MAX) {
if (faction_skill_limit(u->faction, sk) != INT_MAX) {
return false;
}
else if ((int)sv->level > maxlevel) {

View File

@ -635,9 +635,9 @@ int study_cmd(unit * u, order * ord)
mtype = M_GRAY;
}
else if (!has_skill(u, SK_MAGIC)) {
int mmax = skill_limit(u->faction, SK_MAGIC);
int mmax = faction_skill_limit(u->faction, SK_MAGIC);
/* Die Einheit ist noch kein Magier */
if (count_skill(u->faction, SK_MAGIC) + u->number > mmax) {
if (faction_count_skill(u->faction, SK_MAGIC) + u->number > mmax) {
ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error_max_magicians",
"amount", mmax));
return -1;
@ -694,8 +694,8 @@ int study_cmd(unit * u, order * ord)
if (sk == SK_ALCHEMY) {
maxalchemy = effskill(u, SK_ALCHEMY, NULL);
if (!has_skill(u, SK_ALCHEMY)) {
int amax = skill_limit(u->faction, SK_ALCHEMY);
if (count_skill(u->faction, SK_ALCHEMY) + u->number > amax) {
int amax = faction_skill_limit(u->faction, SK_ALCHEMY);
if (faction_count_skill(u->faction, SK_ALCHEMY) + u->number > amax) {
ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error_max_alchemists",
"amount", amax));
return -1;