From 2a61dc4d1187d9c9ad229ec4a8be2da9ab97f7ad Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Wed, 10 Dec 2014 20:44:33 +0100 Subject: [PATCH 1/9] prepare for give_men refactoring by writing some basic tests. --- src/give.test.c | 28 ++++++++++++++++++++++++++++ src/kernel/race.c | 1 + 2 files changed, 29 insertions(+) diff --git a/src/give.test.c b/src/give.test.c index ea5237e65..fa5918fb5 100644 --- a/src/give.test.c +++ b/src/give.test.c @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -35,6 +36,31 @@ static void setup_give(struct give *env) { env->itype->flags |= ITF_HERB; } +static void test_give_men(CuTest * tc) { + struct give env; + test_cleanup(); + env.f2 = env.f1 = test_create_faction(0); + setup_give(&env); + give_men(1, env.src, env.dst, NULL); + CuAssertIntEquals(tc, 2, env.dst->number); + CuAssertIntEquals(tc, 0, env.src->number); + test_cleanup(); +} + +static void test_give_peasants(CuTest * tc) { + struct give env; + int peasants; + test_cleanup(); + env.f2 = env.f1 = test_create_faction(0); + setup_give(&env); + peasants = env.r->land->peasants; + getunitpeasants = 1; + give_men(1, env.src, NULL, NULL); + CuAssertIntEquals(tc, 0, env.src->number); + CuAssertIntEquals(tc, peasants+1, env.r->land->peasants); + test_cleanup(); +} + static void test_give(CuTest * tc) { struct give env; @@ -110,6 +136,8 @@ CuSuite *get_give_suite(void) { CuSuite *suite = CuSuiteNew(); SUITE_ADD_TEST(suite, test_give); + SUITE_ADD_TEST(suite, test_give_men); + SUITE_ADD_TEST(suite, test_give_peasants); SUITE_ADD_TEST(suite, test_give_herbs); SUITE_ADD_TEST(suite, test_give_okay); SUITE_ADD_TEST(suite, test_give_denied_by_rules); diff --git a/src/kernel/race.c b/src/kernel/race.c index e83183564..7452fe79d 100644 --- a/src/kernel/race.c +++ b/src/kernel/race.c @@ -172,6 +172,7 @@ race *rc_get_or_create(const char *zName) rc = (race *)calloc(sizeof(race), 1); rc->hitpoints = 1; + rc->recruit_multi = 1.0F; if (strchr(zName, ' ') != NULL) { log_error("race '%s' has an invalid name. remove spaces\n", zName); assert(strchr(zName, ' ') == NULL); From 33a5e0aa9d64e2dbd907932cce11c7406b286144 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Wed, 10 Dec 2014 21:17:00 +0100 Subject: [PATCH 2/9] test giving men to other faction. refactor give_men to return a message. major milestone reached: 200 unit tests. --- src/give.c | 44 ++++++++++++++++++++++-------------- src/give.h | 3 ++- src/give.test.c | 52 +++++++++++++++++++++++++++++++++++++++++-- src/kernel/messages.c | 24 +++++++++++--------- src/kernel/messages.h | 4 ++-- 5 files changed, 95 insertions(+), 32 deletions(-) diff --git a/src/give.c b/src/give.c index ac928ab9b..8de3d1376 100644 --- a/src/give.c +++ b/src/give.c @@ -210,16 +210,15 @@ struct order *ord) return 0; } -void give_men(int n, unit * u, unit * u2, struct order *ord) +message * give_men(int n, unit * u, unit * u2, struct order *ord) { ship *sh; int k = 0; int error = 0; if (u2 && u->faction != u2->faction && u->faction->age < GiveRestriction()) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "giverestriction", - "turns", GiveRestriction())); - return; + return msg_feedback(u, ord, "giverestriction", + "turns", GiveRestriction()); } else if (u == u2) { error = 10; @@ -246,9 +245,8 @@ void give_men(int n, unit * u, unit * u2, struct order *ord) error = 75; } else if (u2 && !ucontact(u2, u)) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_no_contact", - "target", u2)); - error = -1; + return msg_feedback(u, ord, "feedback_no_contact", + "target", u2); } else if (u2 && (has_skill(u, SK_MAGIC) || has_skill(u2, SK_MAGIC))) { /* cannot give units to and from magicians */ @@ -367,18 +365,17 @@ void give_men(int n, unit * u, unit * u2, struct order *ord) } } if (error > 0) { - cmistake(u, ord, error, MSG_COMMERCE); + return msg_error(u, ord, error); } else if (!u2) { - ADDMSG(&u->faction->msgs, - msg_message("give_person_peasants", "unit amount", u, n)); + return msg_message("give_person_peasants", "unit amount", u, n); } else if (u2->faction != u->faction) { message *msg = msg_message("give_person", "unit target amount", u, u2, n); - add_message(&u->faction->msgs, msg); add_message(&u2->faction->msgs, msg); - msg_release(msg); + return msg; } + return NULL; } void give_unit(unit * u, unit * u2, order * ord) @@ -411,6 +408,7 @@ void give_unit(unit * u, unit * u2, order * ord) } else if (getunitpeasants) { unit *u3; + message *msg; for (u3 = r->units; u3; u3 = u3->next) if (u3->faction == u->faction && u != u3) @@ -428,8 +426,13 @@ void give_unit(unit * u, unit * u2, order * ord) } } } - give_men(u->number, u, NULL, ord); - cmistake(u, ord, 153, MSG_COMMERCE); + msg = give_men(u->number, u, NULL, ord); + if (msg) { + ADDMSG(&u->faction->msgs, msg); + } + else { + cmistake(u, ord, 153, MSG_COMMERCE); + } } else { ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", @@ -669,8 +672,11 @@ void give_cmd(unit * u, order * ord) msg_feedback(u, ord, "race_noregroup", "race", u_race(u))); } else { - n = u->number; - give_men(n, u, u2, ord); + message * msg; + msg = give_men(u->number, u, u2, ord); + if (msg) { + ADDMSG(&u->faction->msgs, msg); + } } } else if (!(u_race(u)->ec_flags & GIVEITEM) && u2 != NULL) { @@ -717,12 +723,16 @@ void give_cmd(unit * u, order * ord) } if (isparam(s, u->faction->locale, P_PERSON)) { + message * msg; if (!(u_race(u)->ec_flags & GIVEPERSON)) { ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "race_noregroup", "race", u_race(u))); return; } - give_men(n, u, u2, ord); + msg = give_men(u->number, u, u2, ord); + if (msg) { + ADDMSG(&u->faction->msgs, msg); + } return; } diff --git a/src/give.h b/src/give.h index c392ecde8..90c0b2702 100644 --- a/src/give.h +++ b/src/give.h @@ -19,10 +19,11 @@ extern "C" { struct item_type; struct order; struct unit; + struct message; int give_item(int want, const struct item_type *itype, struct unit *src, struct unit *dest, struct order *ord); - void give_men(int n, struct unit *u, struct unit *u2, + struct message * give_men(int n, struct unit *u, struct unit *u2, struct order *ord); void give_unit(struct unit *u, struct unit *u2, struct order *ord); void give_cmd(struct unit * u, struct order * ord); diff --git a/src/give.test.c b/src/give.test.c index fa5918fb5..d76ab7e35 100644 --- a/src/give.test.c +++ b/src/give.test.c @@ -41,21 +41,66 @@ static void test_give_men(CuTest * tc) { test_cleanup(); env.f2 = env.f1 = test_create_faction(0); setup_give(&env); - give_men(1, env.src, env.dst, NULL); + CuAssertPtrEquals(tc, 0, give_men(1, env.src, env.dst, NULL)); CuAssertIntEquals(tc, 2, env.dst->number); CuAssertIntEquals(tc, 0, env.src->number); test_cleanup(); } +static void test_give_men_other_faction(CuTest * tc) { + struct give env; + message * msg; + + test_cleanup(); + env.f1 = test_create_faction(0); + env.f2 = test_create_faction(0); + setup_give(&env); + usetcontact(env.dst, env.src); + msg = give_men(1, env.src, env.dst, NULL); + CuAssertStrEquals(tc, "give_person", (const char *)msg->parameters[0].v); + CuAssertIntEquals(tc, 2, env.dst->number); + CuAssertIntEquals(tc, 0, env.src->number); + test_cleanup(); +} + +static void test_give_men_requires_contact(CuTest * tc) { + struct give env; + message * msg; + + test_cleanup(); + env.f1 = test_create_faction(0); + env.f2 = test_create_faction(0); + setup_give(&env); + msg = give_men(1, env.src, env.dst, NULL); + CuAssertStrEquals(tc, "feedback_no_contact", (const char *)msg->parameters[3].v); + CuAssertIntEquals(tc, 1, env.dst->number); + CuAssertIntEquals(tc, 1, env.src->number); + test_cleanup(); +} + +static void test_give_men_not_to_self(CuTest * tc) { + struct give env; + message * msg; + test_cleanup(); + env.f2 = env.f1 = test_create_faction(0); + setup_give(&env); + msg = give_men(1, env.src, NULL, NULL); + CuAssertStrEquals(tc, "error159", (const char *)msg->parameters[3].v); + CuAssertIntEquals(tc, 1, env.src->number); + test_cleanup(); +} + static void test_give_peasants(CuTest * tc) { struct give env; + message * msg; int peasants; test_cleanup(); env.f2 = env.f1 = test_create_faction(0); setup_give(&env); peasants = env.r->land->peasants; getunitpeasants = 1; - give_men(1, env.src, NULL, NULL); + msg = give_men(1, env.src, NULL, NULL); + CuAssertStrEquals(tc, "give_person_peasants", (const char*)msg->parameters[0].v); CuAssertIntEquals(tc, 0, env.src->number); CuAssertIntEquals(tc, peasants+1, env.r->land->peasants); test_cleanup(); @@ -137,6 +182,9 @@ CuSuite *get_give_suite(void) CuSuite *suite = CuSuiteNew(); SUITE_ADD_TEST(suite, test_give); SUITE_ADD_TEST(suite, test_give_men); + SUITE_ADD_TEST(suite, test_give_men_other_faction); + SUITE_ADD_TEST(suite, test_give_men_requires_contact); + SUITE_ADD_TEST(suite, test_give_men_not_to_self); SUITE_ADD_TEST(suite, test_give_peasants); SUITE_ADD_TEST(suite, test_give_herbs); SUITE_ADD_TEST(suite, test_give_okay); diff --git a/src/kernel/messages.c b/src/kernel/messages.c index d70423251..f7297f832 100644 --- a/src/kernel/messages.c +++ b/src/kernel/messages.c @@ -251,18 +251,22 @@ void addmessage(region * r, faction * f, const char *s, msg_t mtype, int level) caddmessage(r, f, s, mtype, level); } +message * msg_error(const unit * u, struct order *ord, int mno) { + static char msgname[20]; + + if (fval(u->faction, FFL_NPC)) + return 0; + sprintf(msgname, "error%d", mno); + return msg_feedback(u, ord, msgname, ""); +} + message * cmistake(const unit * u, struct order *ord, int mno, int mtype) { - message * result; - static char msgname[20]; - unused_arg(mtype); - - if (fval(u->faction, FFL_NPC)) - return 0; - sprintf(msgname, "error%d", mno); - result = msg_feedback(u, ord, msgname, ""); - ADDMSG(&u->faction->msgs, result); - return result; + message * result; + unused_arg(mtype); + result = msg_error(u, ord, mno); + ADDMSG(&u->faction->msgs, result); + return result; } extern unsigned int new_hashstring(const char *s); diff --git a/src/kernel/messages.h b/src/kernel/messages.h index 5be1a88fb..83c0f2613 100644 --- a/src/kernel/messages.h +++ b/src/kernel/messages.h @@ -55,8 +55,8 @@ extern "C" { #define ADDMSG(msgs, mcreate) { message * m = mcreate; if (m) { assert(m->refcount>=1); add_message(msgs, m); msg_release(m); } } - extern struct message * cmistake(const struct unit *u, struct order *ord, int mno, - int mtype); + struct message * cmistake(const struct unit *u, struct order *ord, int mno, int mtype); + struct message * msg_error(const struct unit * u, struct order *ord, int mno); #ifdef __cplusplus } #endif From f1662077c3bfe1d0f94153c11d2bc93e62604683 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Wed, 10 Dec 2014 22:14:25 +0100 Subject: [PATCH 3/9] test giving too many and too few units. start moving give-to-peasants logic into its own function. --- src/give.c | 7 ++++++- src/give.h | 1 + src/give.test.c | 40 ++++++++++++++++++++++++++++++++++------ 3 files changed, 41 insertions(+), 7 deletions(-) diff --git a/src/give.c b/src/give.c index 8de3d1376..94ce97949 100644 --- a/src/give.c +++ b/src/give.c @@ -378,6 +378,11 @@ message * give_men(int n, unit * u, unit * u2, struct order *ord) return NULL; } +message * disband_men(int n, unit * u, struct order *ord) { + getunitpeasants = true; + return give_men(n, u, NULL, ord); +} + void give_unit(unit * u, unit * u2, order * ord) { region *r = u->region; @@ -426,7 +431,7 @@ void give_unit(unit * u, unit * u2, order * ord) } } } - msg = give_men(u->number, u, NULL, ord); + msg = disband_men(u->number, u, ord); if (msg) { ADDMSG(&u->faction->msgs, msg); } diff --git a/src/give.h b/src/give.h index 90c0b2702..dfd53cddc 100644 --- a/src/give.h +++ b/src/give.h @@ -23,6 +23,7 @@ extern "C" { int give_item(int want, const struct item_type *itype, struct unit *src, struct unit *dest, struct order *ord); + 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); void give_unit(struct unit *u, struct unit *u2, struct order *ord); diff --git a/src/give.test.c b/src/give.test.c index d76ab7e35..039663872 100644 --- a/src/give.test.c +++ b/src/give.test.c @@ -30,8 +30,8 @@ struct give { static void setup_give(struct give *env) { struct terrain_type *ter = test_create_terrain("plain", LAND_REGION); env->r = test_create_region(0, 0, ter); - env->src = test_create_unit(env->f1, env->r); - env->dst = test_create_unit(env->f2, env->r); + env->src = env->f1 ? test_create_unit(env->f1, env->r) : 0; + env->dst = env->f2 ? test_create_unit(env->f2, env->r) : 0; env->itype = it_get_or_create(rt_get_or_create("money")); env->itype->flags |= ITF_HERB; } @@ -47,6 +47,31 @@ static void test_give_men(CuTest * tc) { test_cleanup(); } +static void test_give_men_too_many(CuTest * tc) { + struct give env; + test_cleanup(); + env.f2 = env.f1 = test_create_faction(0); + setup_give(&env); + CuAssertPtrEquals(tc, 0, give_men(2, env.src, env.dst, NULL)); + CuAssertIntEquals(tc, 2, env.dst->number); + CuAssertIntEquals(tc, 0, env.src->number); + test_cleanup(); +} + +static void test_give_men_none(CuTest * tc) { + struct give env; + message * msg; + + test_cleanup(); + env.f2 = env.f1 = test_create_faction(0); + setup_give(&env); + msg = give_men(0, env.src, env.dst, NULL); + CuAssertStrEquals(tc, "error96", (const char *)msg->parameters[3].v); + CuAssertIntEquals(tc, 1, env.dst->number); + CuAssertIntEquals(tc, 1, env.src->number); + test_cleanup(); +} + static void test_give_men_other_faction(CuTest * tc) { struct give env; message * msg; @@ -84,8 +109,8 @@ static void test_give_men_not_to_self(CuTest * tc) { test_cleanup(); env.f2 = env.f1 = test_create_faction(0); setup_give(&env); - msg = give_men(1, env.src, NULL, NULL); - CuAssertStrEquals(tc, "error159", (const char *)msg->parameters[3].v); + msg = give_men(1, env.src, env.src, NULL); + CuAssertStrEquals(tc, "error10", (const char *)msg->parameters[3].v); CuAssertIntEquals(tc, 1, env.src->number); test_cleanup(); } @@ -95,11 +120,12 @@ static void test_give_peasants(CuTest * tc) { message * msg; int peasants; test_cleanup(); - env.f2 = env.f1 = test_create_faction(0); + env.f1 = test_create_faction(0); + env.f2 = 0; setup_give(&env); peasants = env.r->land->peasants; getunitpeasants = 1; - msg = give_men(1, env.src, NULL, NULL); + msg = disband_men(1, env.src, NULL); CuAssertStrEquals(tc, "give_person_peasants", (const char*)msg->parameters[0].v); CuAssertIntEquals(tc, 0, env.src->number); CuAssertIntEquals(tc, peasants+1, env.r->land->peasants); @@ -182,6 +208,8 @@ CuSuite *get_give_suite(void) CuSuite *suite = CuSuiteNew(); SUITE_ADD_TEST(suite, test_give); SUITE_ADD_TEST(suite, test_give_men); + SUITE_ADD_TEST(suite, test_give_men_none); + SUITE_ADD_TEST(suite, test_give_men_too_many); SUITE_ADD_TEST(suite, test_give_men_other_faction); SUITE_ADD_TEST(suite, test_give_men_requires_contact); SUITE_ADD_TEST(suite, test_give_men_not_to_self); From 215136465bfaf193adc0db5dc61aea147f0afd47 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Wed, 10 Dec 2014 23:04:54 +0100 Subject: [PATCH 4/9] refactoring: getunitpeasants is an awful global hack, and I am pushing it out of give_men so I can eliminate it more easily. --- src/give.c | 129 ++++++++++++++++++++++++-------------------- src/give.test.c | 1 - src/kernel/config.c | 2 +- src/kernel/config.h | 2 +- 4 files changed, 73 insertions(+), 61 deletions(-) diff --git a/src/give.c b/src/give.c index 94ce97949..ecbbe949c 100644 --- a/src/give.c +++ b/src/give.c @@ -210,61 +210,81 @@ struct order *ord) return 0; } +static bool can_give_men(const unit *u, order *ord, message **msg) { + if (u_race(u) == get_race(RC_SNOTLING)) { + /* snotlings may not be given to the peasants. */ + if (msg) *msg = msg_error(u, ord, 307); + } + else if (unit_has_cursed_item(u)) { + if (msg) *msg = msg_error(u, ord, 78); + } + else if (has_skill(u, SK_MAGIC)) { + /* cannot give units to and from magicians */ + if (msg) *msg = msg_error(u, ord, 158); + } + else if (fval(u, UFL_HUNGER)) { + /* hungry people cannot be given away */ + if (msg) *msg = msg_error(u, ord, 73); + } + else if (fval(u, UFL_LOCKED) || is_cursed(u->attribs, C_SLAVE, 0)) { + if (msg) *msg = msg_error(u, ord, 74); + } + else { + return true; + } + return false; +} + message * give_men(int n, unit * u, unit * u2, struct order *ord) { ship *sh; int k = 0; int error = 0; + message * msg; - if (u2 && u->faction != u2->faction && u->faction->age < GiveRestriction()) { + assert(u2); + + if (!can_give_men(u, ord, &msg)) { + return msg; + } + + if (u->faction != u2->faction && u->faction->age < GiveRestriction()) { return msg_feedback(u, ord, "giverestriction", "turns", GiveRestriction()); } else if (u == u2) { error = 10; } - else if (!u2 && u_race(u) == get_race(RC_SNOTLING)) { - /* snotlings may not be given to the peasants. */ - error = 307; - } - else if (u2 && u2->number && (fval(u, UFL_HERO) != fval(u2, UFL_HERO))) { + else if (u2->number && (fval(u, UFL_HERO) != fval(u2, UFL_HERO))) { /* heroes may not be given to non-heroes and vice versa */ error = 75; } - else if (unit_has_cursed_item(u) || (u2 && unit_has_cursed_item(u2))) { + else if (unit_has_cursed_item(u2)) { error = 78; } - else if (fval(u, UFL_LOCKED) || is_cursed(u->attribs, C_SLAVE, 0)) { - error = 74; - } - else if (u2 && fval(u, UFL_HUNGER)) { - /* hungry people cannot be given away */ - error = 73; - } - else if (u2 && (fval(u2, UFL_LOCKED) || is_cursed(u2->attribs, C_SLAVE, 0))) { + else if (fval(u2, UFL_LOCKED) || is_cursed(u2->attribs, C_SLAVE, 0)) { error = 75; } - else if (u2 && !ucontact(u2, u)) { + else if (!ucontact(u2, u)) { return msg_feedback(u, ord, "feedback_no_contact", "target", u2); } - else if (u2 && (has_skill(u, SK_MAGIC) || has_skill(u2, SK_MAGIC))) { + else if (has_skill(u2, SK_MAGIC)) { /* cannot give units to and from magicians */ error = 158; } - else if (u2 && (fval(u, UFL_WERE) != fval(u2, UFL_WERE))) { + else if (fval(u, UFL_WERE) != fval(u2, UFL_WERE)) { /* werewolves can't be given to non-werewolves and vice-versa */ error = 312; } - else if (u2 && u2->number != 0 && u_race(u2) != u_race(u)) { + else if (u2->number != 0 && u_race(u2) != u_race(u)) { log_debug("faction %s attempts to give %s to %s.\n", itoa36(u->faction->no), u_race(u)->_name, u_race(u2)->_name); error = 139; } - else if (u2 != NULL && (get_racename(u2->attribs) - || get_racename(u->attribs))) { + else if (get_racename(u2->attribs) || get_racename(u->attribs)) { error = 139; } - else if (u2 && u2->faction != u->faction && !rule_transfermen()) { + else if (u2->faction != u->faction && !rule_transfermen()) { error = 74; } else { @@ -279,7 +299,7 @@ message * give_men(int n, unit * u, unit * u2, struct order *ord) if (n == 0) { error = 96; } - else if (u2 && u->faction != u2->faction) { + else if (u->faction != u2->faction) { if (u2->faction->newbies + n > MAXNEWBIES) { error = 129; } @@ -301,7 +321,7 @@ message * give_men(int n, unit * u, unit * u2, struct order *ord) } } - if (u2 && (has_skill(u, SK_ALCHEMY) || has_skill(u2, SK_ALCHEMY))) { + if (has_skill(u, SK_ALCHEMY) || has_skill(u2, SK_ALCHEMY)) { k = count_skill(u2->faction, SK_ALCHEMY); /* Falls die Zieleinheit keine Alchemisten sind, werden sie nun @@ -325,7 +345,7 @@ message * give_men(int n, unit * u, unit * u2, struct order *ord) } if (error == 0) { - if (u2 && u2->number == 0) { + if (u2->number == 0) { set_racename(&u2->attribs, get_racename(u->attribs)); u_setrace(u2, u_race(u)); u2->irace = u->irace; @@ -335,41 +355,20 @@ message * give_men(int n, unit * u, unit * u2, struct order *ord) freset(u2, UFL_HERO); } - if (u2) { - /* Einheiten von Schiffen können nicht NACH in von - * Nicht-alliierten bewachten Regionen ausführen */ - sh = leftship(u); - if (sh) { - set_leftship(u2, sh); - } - transfermen(u, u2, n); - if (u->faction != u2->faction) { - u2->faction->newbies += n; - } + /* Einheiten von Schiffen können nicht NACH in von + * Nicht-alliierten bewachten Regionen ausführen */ + sh = leftship(u); + if (sh) { + set_leftship(u2, sh); } - else { - if (getunitpeasants) { -#ifdef ORCIFICATION - if (u_race(u) == get_race(RC_SNOTLING) && !fval(u->region, RF_ORCIFIED)) { - attrib *a = a_find(u->region->attribs, &at_orcification); - if (!a) - a = a_add(&u->region->attribs, a_new(&at_orcification)); - a->data.i += n; - } -#endif - transfermen(u, NULL, n); - } - else { - error = 159; - } + transfermen(u, u2, n); + if (u->faction != u2->faction) { + u2->faction->newbies += n; } } if (error > 0) { return msg_error(u, ord, error); } - else if (!u2) { - return msg_message("give_person_peasants", "unit amount", u, n); - } else if (u2->faction != u->faction) { message *msg = msg_message("give_person", "unit target amount", u, u2, n); add_message(&u2->faction->msgs, msg); @@ -379,8 +378,22 @@ message * give_men(int n, unit * u, unit * u2, struct order *ord) } message * disband_men(int n, unit * u, struct order *ord) { - getunitpeasants = true; - return give_men(n, u, NULL, ord); + message * msg; + + if (!can_give_men(u, ord, &msg)) { + return msg; + } + transfermen(u, NULL, n); +#ifdef ORCIFICATION + if (u_race(u) == get_race(RC_SNOTLING) && !fval(u->region, RF_ORCIFIED)) { + attrib *a = a_find(u->region->attribs, &at_orcification); + if (!a) { + a = a_add(&u->region->attribs, a_new(&at_orcification)); + } + a->data.i += n; + } +#endif + return msg_message("give_person_peasants", "unit amount", u, n); } void give_unit(unit * u, unit * u2, order * ord) @@ -678,7 +691,7 @@ void give_cmd(unit * u, order * ord) } else { message * msg; - msg = give_men(u->number, u, u2, ord); + msg = getunitpeasants ? disband_men(u->number, u, ord) : give_men(u->number, u, u2, ord); if (msg) { ADDMSG(&u->faction->msgs, msg); } @@ -734,7 +747,7 @@ void give_cmd(unit * u, order * ord) msg_feedback(u, ord, "race_noregroup", "race", u_race(u))); return; } - msg = give_men(u->number, u, u2, ord); + msg = getunitpeasants ? disband_men(u->number, u, ord) : give_men(u->number, u, u2, ord); if (msg) { ADDMSG(&u->faction->msgs, msg); } diff --git a/src/give.test.c b/src/give.test.c index 039663872..f376c4577 100644 --- a/src/give.test.c +++ b/src/give.test.c @@ -124,7 +124,6 @@ static void test_give_peasants(CuTest * tc) { env.f2 = 0; setup_give(&env); peasants = env.r->land->peasants; - getunitpeasants = 1; msg = disband_men(1, env.src, NULL); CuAssertStrEquals(tc, "give_person_peasants", (const char*)msg->parameters[0].v); CuAssertIntEquals(tc, 0, env.src->number); diff --git a/src/kernel/config.c b/src/kernel/config.c index 83cb2f7cc..3dd22b159 100644 --- a/src/kernel/config.c +++ b/src/kernel/config.c @@ -604,7 +604,7 @@ unsigned int atoip(const char *s) return n; } -bool unit_has_cursed_item(unit * u) +bool unit_has_cursed_item(const unit * u) { item *itm = u->items; while (itm) { diff --git a/src/kernel/config.h b/src/kernel/config.h index ab8916820..0a1f5b242 100644 --- a/src/kernel/config.h +++ b/src/kernel/config.h @@ -234,7 +234,7 @@ extern "C" { struct region *lastregion(struct faction *f); bool idle(struct faction *f); - bool unit_has_cursed_item(struct unit *u); + bool unit_has_cursed_item(const struct unit *u); /* simple garbage collection: */ void *gc_add(void *p); From ef415c66d0625bc52872b9151751110ecfaf1584 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Thu, 11 Dec 2014 08:35:05 +0100 Subject: [PATCH 5/9] Fix GIVE 0 behavior on oceans. --- res/core/messages.xml | 9 ++++++++ src/give.c | 28 +++++++++++++++--------- src/give.test.c | 51 ++++++++++++++++++++++++++++++++++++++++--- 3 files changed, 75 insertions(+), 13 deletions(-) diff --git a/res/core/messages.xml b/res/core/messages.xml index dfbeecd07..e65d89d1e 100644 --- a/res/core/messages.xml +++ b/res/core/messages.xml @@ -7112,6 +7112,15 @@ "$unit($target) receives $int($amount) $resource($resource,$amount) from $unit($unit)." + + + + + + "$unit($unit) ertränkt $int($amount) Person$if($eq($amount,1),"","en")." + "$unit($unit) drowns $int($amount)." + + diff --git a/src/give.c b/src/give.c index ecbbe949c..8887018ba 100644 --- a/src/give.c +++ b/src/give.c @@ -393,6 +393,9 @@ message * disband_men(int n, unit * u, struct order *ord) { a->data.i += n; } #endif + if (fval(u->region->terrain, SEA_REGION)) { + return msg_message("give_person_ocean", "unit amount", u, n); + } return msg_message("give_person_peasants", "unit amount", u, n); } @@ -421,12 +424,19 @@ void give_unit(unit * u, unit * u2, order * ord) } if (u2 == NULL) { + message *msg; if (fval(r->terrain, SEA_REGION)) { - cmistake(u, ord, 152, MSG_COMMERCE); + /* TODO: why is this here, but the unit does not actually seem to lose any men? */ + msg = disband_men(u->number, u, ord); + if (msg) { + ADDMSG(&u->faction->msgs, msg); + } + else { + cmistake(u, ord, 152, MSG_COMMERCE); + } } else if (getunitpeasants) { unit *u3; - message *msg; for (u3 = r->units; u3; u3 = u3->next) if (u3->faction == u->faction && u != u3) @@ -596,12 +606,10 @@ void give_cmd(unit * u, order * ord) msg_feedback(u, ord, "race_notake", "race", u_race(u2))); return; } - if (!u2) { - if (!getunitpeasants) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, - "feedback_unit_not_found", "")); - return; - } + if (!u2 && !getunitpeasants) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, + "feedback_unit_not_found", "")); + return; } if (u->items) { item **itmp = &u->items; @@ -691,7 +699,7 @@ void give_cmd(unit * u, order * ord) } else { message * msg; - msg = getunitpeasants ? disband_men(u->number, u, ord) : give_men(u->number, u, u2, ord); + msg = u2 ? give_men(u->number, u, u2, ord) : disband_men(u->number, u, ord); if (msg) { ADDMSG(&u->faction->msgs, msg); } @@ -747,7 +755,7 @@ void give_cmd(unit * u, order * ord) msg_feedback(u, ord, "race_noregroup", "race", u_race(u))); return; } - msg = getunitpeasants ? disband_men(u->number, u, ord) : give_men(u->number, u, u2, ord); + msg = u2 ? give_men(u->number, u, u2, ord) : disband_men(u->number, u, ord); if (msg) { ADDMSG(&u->faction->msgs, msg); } diff --git a/src/give.test.c b/src/give.test.c index f376c4577..517675e4a 100644 --- a/src/give.test.c +++ b/src/give.test.c @@ -36,6 +36,33 @@ static void setup_give(struct give *env) { env->itype->flags |= ITF_HERB; } +static void test_give_unit_to_peasants(CuTest * tc) { + struct give env; + test_cleanup(); + env.f1 = test_create_faction(0); + env.f2 = 0; + setup_give(&env); + rsetpeasants(env.r, 0); + getunitpeasants = true; + give_unit(env.src, NULL, NULL); + CuAssertIntEquals(tc, 0, env.src->number); + CuAssertIntEquals(tc, 1, env.r->land->peasants); + test_cleanup(); +} + +static void test_give_unit_in_ocean(CuTest * tc) { + struct give env; + test_cleanup(); + env.f1 = test_create_faction(0); + env.f2 = 0; + setup_give(&env); + env.r->terrain = test_create_terrain("ocean", SEA_REGION); + getunitpeasants = true; + give_unit(env.src, NULL, NULL); + CuAssertIntEquals(tc, 0, env.src->number); + test_cleanup(); +} + static void test_give_men(CuTest * tc) { struct give env; test_cleanup(); @@ -47,6 +74,21 @@ static void test_give_men(CuTest * tc) { test_cleanup(); } +static void test_give_men_in_ocean(CuTest * tc) { + struct give env; + message * msg; + + test_cleanup(); + env.f1 = test_create_faction(0); + env.f2 = 0; + setup_give(&env); + env.r->terrain = test_create_terrain("ocean", SEA_REGION); + msg = disband_men(1, env.src, NULL); + CuAssertStrEquals(tc, "give_person_ocean", (const char *)msg->parameters[0].v); + CuAssertIntEquals(tc, 0, env.src->number); + test_cleanup(); +} + static void test_give_men_too_many(CuTest * tc) { struct give env; test_cleanup(); @@ -118,16 +160,16 @@ static void test_give_men_not_to_self(CuTest * tc) { static void test_give_peasants(CuTest * tc) { struct give env; message * msg; - int peasants; + test_cleanup(); env.f1 = test_create_faction(0); env.f2 = 0; setup_give(&env); - peasants = env.r->land->peasants; + rsetpeasants(env.r, 0); msg = disband_men(1, env.src, NULL); CuAssertStrEquals(tc, "give_person_peasants", (const char*)msg->parameters[0].v); CuAssertIntEquals(tc, 0, env.src->number); - CuAssertIntEquals(tc, peasants+1, env.r->land->peasants); + CuAssertIntEquals(tc, 1, env.r->land->peasants); test_cleanup(); } @@ -207,11 +249,14 @@ CuSuite *get_give_suite(void) CuSuite *suite = CuSuiteNew(); SUITE_ADD_TEST(suite, test_give); SUITE_ADD_TEST(suite, test_give_men); + SUITE_ADD_TEST(suite, test_give_men_in_ocean); SUITE_ADD_TEST(suite, test_give_men_none); SUITE_ADD_TEST(suite, test_give_men_too_many); SUITE_ADD_TEST(suite, test_give_men_other_faction); SUITE_ADD_TEST(suite, test_give_men_requires_contact); SUITE_ADD_TEST(suite, test_give_men_not_to_self); + SUITE_ADD_TEST(suite, test_give_unit_in_ocean); + SUITE_ADD_TEST(suite, test_give_unit_to_peasants); SUITE_ADD_TEST(suite, test_give_peasants); SUITE_ADD_TEST(suite, test_give_herbs); SUITE_ADD_TEST(suite, test_give_okay); From 9c6b7af27ff2bc8079261b40fada3d4e05a6baa0 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Thu, 11 Dec 2014 09:15:19 +0100 Subject: [PATCH 6/9] fix a bug in the eternath quest gates (re-running old turn sometimes needs this). --- scripts/eressea/eternath.lua | 1 + scripts/eressea/gates.lua | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/scripts/eressea/eternath.lua b/scripts/eressea/eternath.lua index 1a93ad352..4c230e733 100644 --- a/scripts/eressea/eternath.lua +++ b/scripts/eressea/eternath.lua @@ -23,6 +23,7 @@ local eternath = {} function eternath.update() if b1 and b2 then + local size = 5 local units1 = gates.units(b1, size) local units2 = gates.units(b2, size) diff --git a/scripts/eressea/gates.lua b/scripts/eressea/gates.lua index 2fb6736ba..c6ce0d7bc 100644 --- a/scripts/eressea/gates.lua +++ b/scripts/eressea/gates.lua @@ -13,7 +13,7 @@ function gates.travel(b, units) end function gates.units(b, maxsize) - local size = maxsize + local size = maxsize or 1 local units = {} local u From eca081e0936c0c78a04823928bf6b9f513831cc4 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Thu, 11 Dec 2014 09:24:59 +0100 Subject: [PATCH 7/9] fix reading old data files that had the backup password in them (storage submodule update). --- storage | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/storage b/storage index 6acf2b4fe..bcc2874cf 160000 --- a/storage +++ b/storage @@ -1 +1 @@ -Subproject commit 6acf2b4fec360d7f681275ea3be77002fd2573c7 +Subproject commit bcc2874cf289a1d0fc9cc79ff3ed271403b2e24c From a16f63fc06586917458c71049d309bdf5e629b99 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Thu, 11 Dec 2014 09:58:23 +0100 Subject: [PATCH 8/9] PROMOTE earlier in the turn, after GIVE and before PAY. https://bugs.eressea.de/view.php?id=1659 --- src/laws.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/laws.c b/src/laws.c index b4f00f91f..6420ab366 100755 --- a/src/laws.c +++ b/src/laws.c @@ -4385,6 +4385,7 @@ void init_processor(void) p += 10; /* rest rng again before economics */ add_proc_region(p, &economics, "Zerstoeren, Geben, Rekrutieren, Vergessen"); + add_proc_order(p, K_PROMOTION, &promotion_cmd, 0, "Heldenbefoerderung"); p += 10; if (!keyword_disabled(K_PAY)) { @@ -4456,7 +4457,6 @@ void init_processor(void) p += 10; add_proc_global(p, restack_units, "Einheiten sortieren"); } - add_proc_order(p, K_PROMOTION, &promotion_cmd, 0, "Heldenbefoerderung"); if (!keyword_disabled(K_NUMBER)) { add_proc_order(p, K_NUMBER, &renumber_cmd, 0, "Neue Nummern (Einheiten)"); p += 10; From 237f05523772e7c3c0d5e07b97894b002aa8856a Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Thu, 11 Dec 2014 10:05:50 +0100 Subject: [PATCH 9/9] Print the full version number in the CR. --- src/creport.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/creport.c b/src/creport.c index 5f9700533..9829f7e7c 100644 --- a/src/creport.c +++ b/src/creport.c @@ -1523,7 +1523,7 @@ report_computer(const char *filename, report_context * ctx, const char *charset) fprintf(F, "%d;Basis\n", 36); fprintf(F, "%d;Runde\n", turn); fprintf(F, "%d;Zeitalter\n", era); - fprintf(F, "%d;Build\n", VERSION_BUILD); + fprintf(F, "%d.%d.%d;Build\n", VERSION_MAJOR, VERSION_MINOR, VERSION_BUILD); if (mailto != NULL) { fprintf(F, "\"%s\";mailto\n", mailto); fprintf(F, "\"%s\";mailcmd\n", locale_string(f->locale, "mailcmd"));