limited-skill units are only transferred up to the limit.

This commit is contained in:
Enno Rehling 2019-05-04 10:45:51 +02:00
parent 6637c94852
commit 8605409ed3
12 changed files with 126 additions and 24 deletions

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

@ -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;
}
}
@ -592,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;
}
@ -603,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

@ -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

@ -943,8 +943,42 @@ int leave_cmd(unit * u, struct order *ord)
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 (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);
}
}

View File

@ -1912,6 +1912,40 @@ static void test_quit_transfer(CuTest *tc) {
test_teardown();
}
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();
}
CuSuite *get_laws_suite(void)
{
CuSuite *suite = CuSuiteNew();
@ -1989,6 +2023,7 @@ CuSuite *get_laws_suite(void)
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);
return suite;
}

View File

@ -3451,7 +3451,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;