diff --git a/res/core/messages.xml b/res/core/messages.xml
index 7028ab6b9..4de8b0299 100644
--- a/res/core/messages.xml
+++ b/res/core/messages.xml
@@ -2937,13 +2937,6 @@
-
-
-
-
-
-
-
@@ -3244,13 +3237,6 @@
-
-
-
-
-
-
-
diff --git a/res/translations/messages.de.po b/res/translations/messages.de.po
index 57b4426ef..c24966d6a 100644
--- a/res/translations/messages.de.po
+++ b/res/translations/messages.de.po
@@ -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.\""
diff --git a/res/translations/messages.en.po b/res/translations/messages.en.po
index 060fe09c2..1f1db551c 100644
--- a/res/translations/messages.en.po
+++ b/res/translations/messages.en.po
@@ -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.\""
diff --git a/scripts/eressea/embassy.lua b/scripts/eressea/embassy.lua
index 00b50b482..ef81d34cc 100644
--- a/scripts/eressea/embassy.lua
+++ b/scripts/eressea/embassy.lua
@@ -31,12 +31,12 @@ function embassy.update()
if home==nil then
return
end
- eressea.log.debug("updating embassies in " .. tostring(home))
+ eressea.log.info("updating embassies in " .. tostring(home))
local u
for u in home.units do
- if u.faction:get_key('mupL')==0 then
- if (u.faction:add_item('seashell', 1)>0) then
- eressea.log.debug("new seashell for " .. tostring(u.faction))
+ if not u.faction:get_key('mupL') then
+ if u.faction:add_item('seashell', 1) > 0 then
+ eressea.log.info("new seashell for " .. tostring(u.faction))
u.faction:set_key('mupL', get_turn())
end
end
diff --git a/src/economy.c b/src/economy.c
index ec6986dd6..efca9ce5c 100644
--- a/src/economy.c
+++ b/src/economy.c
@@ -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;
}
diff --git a/src/give.c b/src/give.c
index c6e77aa68..64fa39504 100644
--- a/src/give.c
+++ b/src/give.c
@@ -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;
}
diff --git a/src/give.h b/src/give.h
index 94eee729c..4d44790a7 100644
--- a/src/give.h
+++ b/src/give.h
@@ -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
}
diff --git a/src/kernel/build.c b/src/kernel/build.c
index 0475c607e..a5eb0a6db 100644
--- a/src/kernel/build.c
+++ b/src/kernel/build.c
@@ -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;
diff --git a/src/kernel/faction.c b/src/kernel/faction.c
index 238ba834b..beec40e0a 100755
--- a/src/kernel/faction.c
+++ b/src/kernel/faction.c
@@ -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);
diff --git a/src/kernel/faction.h b/src/kernel/faction.h
index cbe4c7008..d22e9ee22 100644
--- a/src/kernel/faction.h
+++ b/src/kernel/faction.h
@@ -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
diff --git a/src/kernel/faction.test.c b/src/kernel/faction.test.c
index 65310ee3a..e572cf312 100644
--- a/src/kernel/faction.test.c
+++ b/src/kernel/faction.test.c
@@ -25,6 +25,7 @@
#include
#include
+#include
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);
diff --git a/src/kernel/unit.c b/src/kernel/unit.c
index c1e9264b9..23bcc9982 100644
--- a/src/kernel/unit.c
+++ b/src/kernel/unit.c
@@ -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;
diff --git a/src/kernel/unit.h b/src/kernel/unit.h
index 46746e3a1..fc5602694 100644
--- a/src/kernel/unit.h
+++ b/src/kernel/unit.h
@@ -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
}
diff --git a/src/laws.c b/src/laws.c
index fda3f434f..e8200c262 100644
--- a/src/laws.c
+++ b/src/laws.c
@@ -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;
}
diff --git a/src/laws.test.c b/src/laws.test.c
index cead8605a..33742f427 100644
--- a/src/laws.test.c
+++ b/src/laws.test.c
@@ -1,6 +1,7 @@
#include
#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;
}
diff --git a/src/randenc.c b/src/randenc.c
index b0e5dd13a..9c3fd4739 100644
--- a/src/randenc.c
+++ b/src/randenc.c
@@ -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);
}
diff --git a/src/spells.c b/src/spells.c
index 5e2474861..335bcef3c 100644
--- a/src/spells.c
+++ b/src/spells.c
@@ -3110,8 +3110,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;
}
@@ -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) {
diff --git a/src/study.c b/src/study.c
index 7e5ca9812..8d39e5d5f 100644
--- a/src/study.c
+++ b/src/study.c
@@ -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;