diff --git a/src/guard.c b/src/guard.c index 07640452c..1f2ee7f3f 100644 --- a/src/guard.c +++ b/src/guard.c @@ -34,6 +34,9 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. guard_t can_start_guarding(const unit * u) { + if (!u->region->land) { + return E_GUARD_TERRAIN; + } if (u->status >= ST_FLEE || fval(u, UFL_FLEEING)) return E_GUARD_FLEEING; /* Monster der Monsterpartei duerfen immer bewachen */ diff --git a/src/guard.h b/src/guard.h index 101369f40..5a717d92d 100644 --- a/src/guard.h +++ b/src/guard.h @@ -12,7 +12,7 @@ extern "C" { struct unit; struct region; - typedef enum { E_GUARD_OK, E_GUARD_UNARMED, E_GUARD_NEWBIE, E_GUARD_FLEEING } guard_t; + typedef enum { E_GUARD_OK, E_GUARD_UNARMED, E_GUARD_NEWBIE, E_GUARD_FLEEING, E_GUARD_TERRAIN } guard_t; guard_t can_start_guarding(const struct unit * u); void update_guards(void); diff --git a/src/guard.test.c b/src/guard.test.c index 17aa2891c..1ffd1b4da 100644 --- a/src/guard.test.c +++ b/src/guard.test.c @@ -7,7 +7,9 @@ #include #include #include +#include #include +#include #include #include @@ -128,14 +130,117 @@ static void test_guard_monsters(CuTest * tc) test_cleanup(); } +static void test_update_guard(CuTest * tc) +/* https://bugs.eressea.de/view.php?id=2292 */ +{ + unit *ug; + region *r; + item_type *itype; + const struct terrain_type *t_ocean, *t_plain; + + test_setup(); + t_ocean = test_create_terrain("ocean", SEA_REGION); + t_plain = test_create_terrain("plain", LAND_REGION); + itype = it_get_or_create(rt_get_or_create("sword")); + new_weapontype(itype, 0, frac_zero, NULL, 0, 0, 0, SK_MELEE, 2); + r = test_create_region(0, 0, t_ocean); + ug = test_create_unit(test_create_faction(0), r); + i_change(&ug->items, itype, 1); + set_level(ug, SK_MELEE, 2); + setguard(ug, true); + CuAssertIntEquals(tc, 1, armedmen(ug, false)); + CuAssertTrue(tc, is_guard(ug)); + + terraform_region(r, t_ocean); + update_guards(); + CuAssertTrue(tc, ! is_guard(ug)); + + test_cleanup(); +} + +static void test_guard_on(CuTest * tc) +{ + unit *ug; + region *r; + item_type *itype; + terrain_type *t_ocean, *t_plain; + + test_setup(); + t_ocean = test_create_terrain("ocean", SEA_REGION); + t_plain = test_create_terrain("plain", LAND_REGION); + itype = it_get_or_create(rt_get_or_create("sword")); + new_weapontype(itype, 0, frac_zero, NULL, 0, 0, 0, SK_MELEE, 2); + r = test_create_region(0, 0, t_plain); + ug = test_create_unit(test_create_faction(0), r); + i_change(&ug->items, itype, 1); + set_level(ug, SK_MELEE, 2); + ug->thisorder = create_order(K_GUARD, ug->faction->locale, NULL); + + setguard(ug, false); + CuAssertIntEquals(tc, E_GUARD_OK, can_start_guarding(ug)); + guard_on_cmd(ug, ug->thisorder); + CuAssertTrue(tc, is_guard(ug)); + + terraform_region(r, t_ocean); + + setguard(ug, false); + CuAssertIntEquals(tc, E_GUARD_TERRAIN, can_start_guarding(ug)); + guard_on_cmd(ug, ug->thisorder); + CuAssertTrue(tc, !is_guard(ug)); + CuAssertPtrNotNull(tc, test_find_messagetype(ug->faction->msgs, "error2")); + + setguard(ug, false); + t_ocean->flags &= ~ SEA_REGION; + CuAssertIntEquals(tc, E_GUARD_TERRAIN, can_start_guarding(ug)); + guard_on_cmd(ug, ug->thisorder); + CuAssertTrue(tc, !is_guard(ug)); + CuAssertPtrNotNull(tc, test_find_messagetype(ug->faction->msgs, "error_onlandonly")); + + terraform_region(r, t_plain); + + i_change(&ug->items, itype, -1); + CuAssertIntEquals(tc, E_GUARD_UNARMED, can_start_guarding(ug)); + guard_on_cmd(ug, ug->thisorder); + CuAssertTrue(tc, !is_guard(ug)); + CuAssertPtrNotNull(tc, test_find_messagetype(ug->faction->msgs, "unit_unarmed")); + i_change(&ug->items, itype, 1); + + test_clear_messages(ug->faction); + set_level(ug, SK_MELEE, 0); + CuAssertIntEquals(tc, E_GUARD_UNARMED, can_start_guarding(ug)); + guard_on_cmd(ug, ug->thisorder); + CuAssertTrue(tc, !is_guard(ug)); + CuAssertPtrNotNull(tc, test_find_messagetype(ug->faction->msgs, "unit_unarmed")); + set_level(ug, SK_MELEE, 2); + + ug->status = ST_FLEE; + CuAssertIntEquals(tc, E_GUARD_FLEEING, can_start_guarding(ug)); + guard_on_cmd(ug, ug->thisorder); + CuAssertTrue(tc, !is_guard(ug)); + CuAssertPtrNotNull(tc, test_find_messagetype(ug->faction->msgs, "error320")); + ug->status = ST_FIGHT; + + config_set("NewbieImmunity", "5"); + CuAssertIntEquals(tc, E_GUARD_NEWBIE, can_start_guarding(ug)); + guard_on_cmd(ug, ug->thisorder); + CuAssertTrue(tc, !is_guard(ug)); + CuAssertPtrNotNull(tc, test_find_messagetype(ug->faction->msgs, "error304")); + config_set("NewbieImmunity", NULL); + + test_clear_messages(ug->faction); + test_cleanup(); +} + CuSuite *get_guard_suite(void) { CuSuite *suite = CuSuiteNew(); SUITE_ADD_TEST(suite, test_is_guarded); SUITE_ADD_TEST(suite, test_is_guard); SUITE_ADD_TEST(suite, test_guard_unskilled); + SUITE_ADD_TEST(suite, test_guard_on); SUITE_ADD_TEST(suite, test_guard_armed); SUITE_ADD_TEST(suite, test_guard_unarmed); SUITE_ADD_TEST(suite, test_guard_monsters); + SUITE_ADD_TEST(suite, test_update_guard); return suite; } diff --git a/src/laws.c b/src/laws.c index 253b45b89..dfbd163cb 100644 --- a/src/laws.c +++ b/src/laws.c @@ -2686,31 +2686,34 @@ int guard_on_cmd(unit * u, struct order *ord) return 0; } - if (fval(u->region->terrain, SEA_REGION)) { - cmistake(u, ord, 2, MSG_EVENT); + if (fval(u, UFL_MOVED)) { + cmistake(u, ord, 187, MSG_EVENT); + } + else if (fval(u_race(u), RCF_ILLUSIONARY) + || u_race(u) == get_race(RC_SPELL)) { + cmistake(u, ord, 95, MSG_EVENT); } else { - if (fval(u, UFL_MOVED)) { - cmistake(u, ord, 187, MSG_EVENT); + int err = can_start_guarding(u); + if (err == E_GUARD_OK) { + setguard(u, true); } - else if (fval(u_race(u), RCF_ILLUSIONARY) - || u_race(u) == get_race(RC_SPELL)) { - cmistake(u, ord, 95, MSG_EVENT); + else if (err == E_GUARD_TERRAIN) { + if (fval(u->region->terrain, SEA_REGION)) { + cmistake(u, ord, 2, MSG_EVENT); + } + else { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error_onlandonly", "")); + } } - else { - int err = can_start_guarding(u); - if (err == E_GUARD_OK) { - setguard(u, true); - } - else if (err == E_GUARD_UNARMED) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "unit_unarmed", "")); - } - else if (err == E_GUARD_FLEEING) { - cmistake(u, ord, 320, MSG_EVENT); - } - else if (err == E_GUARD_NEWBIE) { - cmistake(u, ord, 304, MSG_EVENT); - } + else if (err == E_GUARD_UNARMED) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "unit_unarmed", "")); + } + else if (err == E_GUARD_FLEEING) { + cmistake(u, ord, 320, MSG_EVENT); + } + else if (err == E_GUARD_NEWBIE) { + cmistake(u, ord, 304, MSG_EVENT); } } return 0;