diff --git a/res/core/calendar.xml b/res/core/calendar.xml index 42f83d58b..d96037698 100644 --- a/res/core/calendar.xml +++ b/res/core/calendar.xml @@ -1,5 +1,5 @@ - + diff --git a/scripts/tests/e2/e2features.lua b/scripts/tests/e2/e2features.lua index da2a98d55..f0e597770 100644 --- a/scripts/tests/e2/e2features.lua +++ b/scripts/tests/e2/e2features.lua @@ -10,6 +10,11 @@ function setup() eressea.settings.set("rules.encounters", "0") end +function test_calendar() + assert_equal(get_season(1011), "calendar::winter") + assert_equal(get_season(1012), "calendar::spring") +end + function test_herbalism() -- OBS: herbalism is currently an E2-only skill local r = region.create(0, 0, "plain") diff --git a/scripts/tests/e2/init.lua b/scripts/tests/e2/init.lua index 5f81933d7..2f87b83fc 100644 --- a/scripts/tests/e2/init.lua +++ b/scripts/tests/e2/init.lua @@ -1,5 +1,3 @@ -require 'tests.economy' - require 'tests.e2.undead' require 'tests.e2.shiplanding' require 'tests.e2.e2features' @@ -10,6 +8,7 @@ require 'tests.e2.spells' require 'tests.e2.stealth' require 'tests.e2.items' require 'tests.items' +require 'tests.economy' require 'tests.orders' require 'tests.common' require 'tests.report' diff --git a/scripts/tests/e3/init.lua b/scripts/tests/e3/init.lua index 28a2cf6e5..412da5544 100644 --- a/scripts/tests/e3/init.lua +++ b/scripts/tests/e3/init.lua @@ -5,6 +5,7 @@ require 'tests.e3.rules' require 'tests.e3.parser' require 'tests.e3.morale' require 'tests.e3.items' +require 'tests.economy' require 'tests.orders' require 'tests.common' require 'tests.items' diff --git a/scripts/tests/e3/rules.lua b/scripts/tests/e3/rules.lua index 2ecdf1ff7..150ad3ae0 100644 --- a/scripts/tests/e3/rules.lua +++ b/scripts/tests/e3/rules.lua @@ -37,6 +37,10 @@ function teardown() set_rule("rules.ship.storms") end +function test_calendar() + assert_equal(get_season(396), "calendar::winter") +end + function disable_test_bug_1738_build_castle_e3() local r = region.create(0, 0, "plain") local f = faction.create("bug_1738@eressea.de", "human", "de") diff --git a/scripts/tests/economy.lua b/scripts/tests/economy.lua index b628dd47b..fe1574887 100644 --- a/scripts/tests/economy.lua +++ b/scripts/tests/economy.lua @@ -127,6 +127,20 @@ function test_ironkeeper_guards_iron() assert_equal(level, u:get_item("iron")) end +function test_sawmill() + local r = region.create(0, 0, "plain") + r:set_resource("tree", 100) + local u = unit.create(faction.create("human"), r) + u:add_item("money", 250) -- sawmill maintenance + u:set_skill("forestry", 6) + u.building = building.create(r, "sawmill") + u.building.size = 1 + u:add_order("MACHE 6 HOLZ") + process_orders() + assert_equal(6, u:get_item("log")) + assert_equal(97, r:get_resource("tree")) +end + function test_ent_guards_trees() local r = region.create(0, 0, "plain") r:set_resource("tree", 100) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 7be3dd3b1..ebe914dfe 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -21,7 +21,7 @@ COMPILE_DEFINITIONS ERESSEA_BUILDNO="${ERESSEA_BUILDNO}") ENDIF() IF (CMAKE_COMPILER_IS_GNUCC) - SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-error=unused-but-set-variable") +# SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-error=unused-but-set-variable") ENDIF() IF (CMAKE_COMPILER_IS_GNUCC OR CMAKE_C_COMPILER_ID MATCHES "Clang") # SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wconversion -Wno-sign-conversion") diff --git a/src/calendar.c b/src/calendar.c index 2099b6631..d2a70c974 100644 --- a/src/calendar.c +++ b/src/calendar.c @@ -18,7 +18,7 @@ int seasons = 0; int first_turn(void) { - return config_get_int("game.start", 1); + return config_get_int("game.start", 0); } const gamedate *get_gamedate(int turn, gamedate * gd) diff --git a/src/creport.c b/src/creport.c index c2d10d1c0..99a9ede97 100644 --- a/src/creport.c +++ b/src/creport.c @@ -763,12 +763,8 @@ void cr_output_unit(stream *out, const region * r, const faction * f, stream_printf(out, "\"%s\";Beschr\n", str); } /* print faction information */ - sf = visible_faction(f, u); - prefix = raceprefix(u); + sf = visible_faction(NULL, u); if (u->faction == f || omniscient(f)) { - const attrib *a_otherfaction = a_find(u->attribs, &at_otherfaction); - const faction *otherfaction = - a_otherfaction ? get_otherfaction(a_otherfaction) : NULL; /* my own faction, full info */ const attrib *a = NULL; unit *mage; @@ -780,12 +776,12 @@ void cr_output_unit(stream *out, const region * r, const faction * f, stream_printf(out, "%d;gruppe\n", g->gid); } stream_printf(out, "%d;Partei\n", u->faction->no); - if (sf != u->faction) + if (sf && sf != u->faction) { stream_printf(out, "%d;Verkleidung\n", sf->no); - if (fval(u, UFL_ANON_FACTION)) - stream_printf(out, "%d;Parteitarnung\n", (u->flags & UFL_ANON_FACTION)!=0); - if (otherfaction && otherfaction != u->faction) { - stream_printf(out, "%d;Anderepartei\n", otherfaction->no); + stream_printf(out, "%d;Anderepartei\n", sf->no); + } + if (fval(u, UFL_ANON_FACTION)) { + stream_printf(out, "%d;Parteitarnung\n", (u->flags & UFL_ANON_FACTION) != 0); } mage = get_familiar_mage(u); if (mage) { @@ -798,21 +794,19 @@ void cr_output_unit(stream *out, const region * r, const faction * f, stream_printf(out, "%d;Parteitarnung\n", (u->flags & UFL_ANON_FACTION) != 0); } else { - const attrib *a_otherfaction = a_find(u->attribs, &at_otherfaction); - const faction *otherfaction = - a_otherfaction ? get_otherfaction(a_otherfaction) : NULL; /* other unit. show visible faction, not u->faction */ - stream_printf(out, "%d;Partei\n", sf->no); + stream_printf(out, "%d;Partei\n", sf ? sf->no : f->no); if (sf == f) { stream_printf(out, "1;Verraeter\n"); } - if (otherfaction && otherfaction != u->faction) { + if (sf && sf != u->faction) { if (alliedunit(u, f, HELP_FSTEALTH)) { - stream_printf(out, "%d;Anderepartei\n", otherfaction->no); + stream_printf(out, "%d;Anderepartei\n", sf->no); } } } } + prefix = raceprefix(u); if (prefix) { prefix = mkname("prefix", prefix); stream_printf(out, "\"%s\";typprefix\n", translate(prefix, LOC(f->locale, diff --git a/src/creport.test.c b/src/creport.test.c index 21a6c09b7..14f40268c 100644 --- a/src/creport.test.c +++ b/src/creport.test.c @@ -1,9 +1,11 @@ #include #include "creport.h" #include "move.h" +#include "spy.h" #include "travelthru.h" #include "keyword.h" +#include #include #include #include @@ -48,9 +50,67 @@ static void test_cr_unit(CuTest *tc) { test_cleanup(); } +static int cr_get_int(stream *strm, const char *match, int def) +{ + char line[1024]; + + strm->api->rewind(strm->handle); + while (strm->api->readln(strm->handle, line, sizeof(line))==0) { + if (strstr(line, match)) { + return atoi(line); + } + } + return def; +} + +static void test_cr_factionstealth(CuTest *tc) { + stream strm; + faction *f1, *f2; + region *r; + unit *u; + ally *al; + + test_setup(); + mstream_init(&strm); + f1 = test_create_faction(0); + f2 = test_create_faction(0); + r = test_create_region(0, 0, 0); + u = test_create_unit(f1, r); + + cr_output_unit(&strm, u->region, f1, u, seen_unit); + CuAssertIntEquals(tc, f1->no, cr_get_int(&strm, ";Partei", -1)); + CuAssertIntEquals(tc, -1, cr_get_int(&strm, ";Anderepartei", -1)); + CuAssertIntEquals(tc, -1, cr_get_int(&strm, ";Verraeter", -1)); + + set_factionstealth(u, f2); + CuAssertPtrNotNull(tc, u->attribs); + + cr_output_unit(&strm, u->region, f1, u, seen_unit); + CuAssertIntEquals(tc, f1->no, cr_get_int(&strm, ";Partei", -1)); + CuAssertIntEquals(tc, f2->no, cr_get_int(&strm, ";Anderepartei", -1)); + CuAssertIntEquals(tc, -1, cr_get_int(&strm, ";Verraeter", -1)); + + cr_output_unit(&strm, u->region, f2, u, seen_unit); + CuAssertIntEquals(tc, f1->no, cr_get_int(&strm, ";Partei", -1)); + CuAssertIntEquals(tc, f2->no, cr_get_int(&strm, ";Anderepartei", -1)); + CuAssertIntEquals(tc, 1, cr_get_int(&strm, ";Verraeter", -1)); + + al = ally_add(&f1->allies, f2); + al->status = HELP_FSTEALTH; + + cr_output_unit(&strm, u->region, f2, u, seen_unit); + CuAssertIntEquals(tc, f1->no, cr_get_int(&strm, ";Partei", -1)); + CuAssertIntEquals(tc, f2->no, cr_get_int(&strm, ";Anderepartei", -1)); + CuAssertIntEquals(tc, 1, cr_get_int(&strm, ";Verraeter", -1)); + + mstream_done(&strm); + test_cleanup(); +} + CuSuite *get_creport_suite(void) { CuSuite *suite = CuSuiteNew(); SUITE_ADD_TEST(suite, test_cr_unit); + SUITE_ADD_TEST(suite, test_cr_factionstealth); return suite; } diff --git a/src/economy.c b/src/economy.c index ab6862aa4..2a6fea671 100644 --- a/src/economy.c +++ b/src/economy.c @@ -1116,7 +1116,7 @@ attrib_allocation(const resource_type * rtype, region * r, allocation * alist) { allocation *al; int nreq = 0; - int avail = 0; + int avail = INT_MAX; for (al = alist; al; al = al->next) { nreq += required(al->want, al->save); @@ -1139,7 +1139,7 @@ attrib_allocation(const resource_type * rtype, region * r, allocation * alist) if (rx>0 && rng_int() % nreq < rx) ++x; avail -= x; nreq -= want; - al->get = x * al->save.sa[0] / al->save.sa[1]; + al->get = x * al->save.sa[1] / al->save.sa[0]; al->get = MIN(al->want, al->get); if (!rtype->raw) { int use = required(al->get, al->save); diff --git a/src/economy.test.c b/src/economy.test.c index 8b1b0b0fa..72bf3d294 100644 --- a/src/economy.test.c +++ b/src/economy.test.c @@ -405,9 +405,16 @@ static void test_make_item(CuTest *tc) { CuAssertIntEquals(tc, 22, get_item(u, itype)); CuAssertIntEquals(tc, 283, u->region->resources->amount); /* no free lunches */ + rtype->modifiers[0].value = frac_make(1, 2); + make_item(u, itype, 6); + split_allocations(u->region); + CuAssertIntEquals(tc, 28, get_item(u, itype)); + CuAssertIntEquals(tc, 280, u->region->resources->amount); /* 50% saving = 3 stones make 6 stones */ + rtype->modifiers[0].flags = RMF_REQUIREDBUILDING; rtype->modifiers[0].race = NULL; rtype->modifiers[0].btype = bt_get_or_create("mine"); + make_item(u, itype, 10); CuAssertPtrNotNull(tc, test_find_messagetype(u->faction->msgs, "error104")); diff --git a/src/guard.c b/src/guard.c index 07640452c..55f189b6c 100644 --- a/src/guard.c +++ b/src/guard.c @@ -24,16 +24,20 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include "monsters.h" #include -#include +#include #include #include #include -#include +#include +#include #include guard_t can_start_guarding(const unit * u) { + if (u->region->terrain->flags & SEA_REGION) { + 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..8302bcc9a 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("packice", ARCTIC_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); + 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, test_create_terrain("packice", ARCTIC_REGION)); + + 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")); + + 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/kernel/config.c b/src/kernel/config.c index 3f04b03b3..b605fddd4 100644 --- a/src/kernel/config.c +++ b/src/kernel/config.c @@ -833,17 +833,21 @@ const char * game_name(void) return param ? param : global.gamename; } -const char * game_name_upper(void) +const char * game_mailcmd(void) { - static char result[32]; /* FIXME: static result */ - char *r = result; - const char *param = game_name(); - const char *c = param; - while (*c && (result+sizeof(result))>r) { - *r++ = (char)toupper(*c++); + const char *param = config_get("game.mailcmd"); + if (!param) { + static char result[32]; /* FIXME: static result */ + char *r = result; + const char *c; + param = game_name(); + for (c = param; *c && (result + sizeof(result)) > r; ++c) { + *r++ = (char)toupper(*c); + } + *r = '\0'; + return result; } - *r = '\0'; - return result; + return param; } int game_id(void) { diff --git a/src/kernel/config.h b/src/kernel/config.h index e38d1dd56..3b307bbdd 100644 --- a/src/kernel/config.h +++ b/src/kernel/config.h @@ -51,7 +51,7 @@ extern "C" { param_t getparam(const struct locale *lang); const char * game_name(void); - const char * game_name_upper(void); + const char * game_mailcmd(void); int game_id(void); /* returns a value between [0..xpct_2], generated with two dice */ diff --git a/src/kernel/config.test.c b/src/kernel/config.test.c index 9a10a4c56..7acf8e948 100644 --- a/src/kernel/config.test.c +++ b/src/kernel/config.test.c @@ -245,7 +245,6 @@ static void test_config_inifile(CuTest *tc) { config_set_from(ini); CuAssertStrEquals(tc, "Eressea", config_get("game.name")); CuAssertStrEquals(tc, "Eressea", game_name()); - CuAssertStrEquals(tc, "ERESSEA", game_name_upper()); CuAssertIntEquals(tc, 42, game_id()); iniparser_freedict(ini); test_cleanup(); @@ -274,6 +273,18 @@ static void test_findparam(CuTest *tc) { test_cleanup(); } +static void test_game_mailcmd(CuTest *tc) { + test_setup(); + CuAssertStrEquals(tc, "Eressea", game_name()); + CuAssertStrEquals(tc, "ERESSEA", game_mailcmd()); + config_set("game.name", "Hodor"); + CuAssertStrEquals(tc, "Hodor", game_name()); + CuAssertStrEquals(tc, "HODOR", game_mailcmd()); + config_set("game.mailcmd", "ERESSEA"); + CuAssertStrEquals(tc, "ERESSEA", game_mailcmd()); + test_cleanup(); +} + CuSuite *get_config_suite(void) { CuSuite *suite = CuSuiteNew(); @@ -287,6 +298,7 @@ CuSuite *get_config_suite(void) SUITE_ADD_TEST(suite, test_getunit); SUITE_ADD_TEST(suite, test_read_unitid); SUITE_ADD_TEST(suite, test_default_order); + SUITE_ADD_TEST(suite, test_game_mailcmd); SUITE_ADD_TEST(suite, test_rules); return suite; } diff --git a/src/kernel/jsonconf.c b/src/kernel/jsonconf.c index 287aa61db..0f5642c42 100644 --- a/src/kernel/jsonconf.c +++ b/src/kernel/jsonconf.c @@ -797,18 +797,18 @@ static void json_settings(cJSON *json) { return; } for (child = json->child; child; child = child->next) { - if (child->valuestring) { - config_set(child->string, child->valuestring); - } - else { - char value[32]; - if (child->type == cJSON_Number && child->valuedouble && child->valueintvaluedouble) { - sprintf(value, "%f", child->valuedouble); + if (config_get(child->string) == NULL) { + if (child->valuestring) { + config_set(child->string, child->valuestring); } else { - sprintf(value, "%d", child->valueint); - } - if (config_get(child->string) == NULL) { + char value[32]; + if (child->type == cJSON_Number && child->valuedouble && child->valueint < child->valuedouble) { + sprintf(value, "%f", child->valuedouble); + } + else { + sprintf(value, "%d", child->valueint); + } config_set(child->string, value); } } diff --git a/src/kernel/jsonconf.test.c b/src/kernel/jsonconf.test.c index 8b8ac8c14..456a27d22 100644 --- a/src/kernel/jsonconf.test.c +++ b/src/kernel/jsonconf.test.c @@ -70,14 +70,17 @@ static void test_settings(CuTest * tc) "\"integer\" : 14," "\"true\": true," "\"game.id\": 4," + "\"game.name\": \"E3\"," "\"false\": false," "\"float\" : 1.5 }}"; cJSON *json = cJSON_Parse(data); test_cleanup(); config_set("game.id", "42"); /* should not be replaced */ + config_set("game.name", "Eressea"); /* should not be replaced */ json_config(json); CuAssertStrEquals(tc, "42", config_get("game.id")); + CuAssertStrEquals(tc, "Eressea", config_get("game.name")); CuAssertStrEquals(tc, "1", config_get("true")); CuAssertStrEquals(tc, "0", config_get("false")); CuAssertStrEquals(tc, "1d4", config_get("string")); diff --git a/src/laws.c b/src/laws.c index b8291440f..5b4c5971b 100644 --- a/src/laws.c +++ b/src/laws.c @@ -2691,31 +2691,29 @@ 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) { + cmistake(u, ord, 2, MSG_EVENT); } - 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; diff --git a/src/reports.c b/src/reports.c index a70219b0b..a07b60f4b 100644 --- a/src/reports.c +++ b/src/reports.c @@ -1006,7 +1006,7 @@ static void cb_add_address(region *r, unit *ut, void *cbdata) { for (u = r->units; u; u = u->next) { faction *sf = visible_faction(f, u); assert(u->faction != f); /* if this is see_travel only, then I shouldn't be here. */ - if (data->lastf != sf && cansee_unit(u, ut, data->stealthmod)) { + if (data->lastf != sf && cansee_unit(ut, u, data->stealthmod)) { add_seen_faction_i(data->flist, sf); data->lastf = sf; break; @@ -1024,7 +1024,7 @@ static void add_travelthru_addresses(region *r, faction *f, selist **flist, int travelthru_map(r, cb_add_address, &cbdata); } -static void get_addresses(report_context * ctx) +void get_addresses(report_context * ctx) { /* "TODO: travelthru" */ region *r; @@ -1945,7 +1945,7 @@ static void eval_regions(struct opstack **stack, const void *userdata) const char *get_mailcmd(const struct locale *loc) { static char result[64]; /* FIXME: static return buffer */ - snprintf(result, sizeof(result), "%s %d %s", game_name_upper(), game_id(), LOC(loc, "mailcmd")); + snprintf(result, sizeof(result), "%s %d %s", game_mailcmd(), game_id(), LOC(loc, "mailcmd")); return result; } diff --git a/src/reports.h b/src/reports.h index 4fab104ef..855234376 100644 --- a/src/reports.h +++ b/src/reports.h @@ -81,6 +81,7 @@ extern "C" { void prepare_report(report_context *ctx, struct faction *f); void finish_reports(report_context *ctx); + void get_addresses(report_context * ctx); typedef int(*report_fun) (const char *filename, report_context * ctx, const char *charset); diff --git a/src/reports.test.c b/src/reports.test.c index e3ca5c89b..c026041a9 100644 --- a/src/reports.test.c +++ b/src/reports.test.c @@ -2,6 +2,7 @@ #include "reports.h" #include "move.h" +#include "spy.h" #include "lighthouse.h" #include "travelthru.h" #include "keyword.h" @@ -279,6 +280,88 @@ static void test_prepare_travelthru(CuTest *tc) { test_cleanup(); } +static void test_get_addresses(CuTest *tc) { + report_context ctx; + faction *f, *f2, *f1; + region *r; + + test_setup(); + f = test_create_faction(0); + f1 = test_create_faction(0); + f2 = test_create_faction(0); + r = test_create_region(0, 0, 0); + test_create_unit(f, r); + test_create_unit(f1, r); + test_create_unit(f2, r); + prepare_report(&ctx, f); + CuAssertPtrEquals(tc, r, ctx.first); + CuAssertPtrEquals(tc, NULL, ctx.last); + get_addresses(&ctx); + CuAssertPtrNotNull(tc, ctx.addresses); + CuAssertTrue(tc, selist_contains(ctx.addresses, f, NULL)); + CuAssertTrue(tc, selist_contains(ctx.addresses, f1, NULL)); + CuAssertTrue(tc, selist_contains(ctx.addresses, f2, NULL)); + CuAssertIntEquals(tc, 3, selist_length(ctx.addresses)); + test_cleanup(); +} + +static void test_get_addresses_fstealth(CuTest *tc) { + report_context ctx; + faction *f, *f2, *f1; + region *r; + unit *u; + + test_setup(); + f = test_create_faction(0); + f1 = test_create_faction(0); + f2 = test_create_faction(0); + r = test_create_region(0, 0, 0); + test_create_unit(f, r); + u = test_create_unit(f1, r); + set_factionstealth(u, f2); + + prepare_report(&ctx, f); + CuAssertPtrEquals(tc, r, ctx.first); + CuAssertPtrEquals(tc, NULL, ctx.last); + get_addresses(&ctx); + CuAssertPtrNotNull(tc, ctx.addresses); + CuAssertTrue(tc, selist_contains(ctx.addresses, f, NULL)); + CuAssertTrue(tc, !selist_contains(ctx.addresses, f1, NULL)); + CuAssertTrue(tc, selist_contains(ctx.addresses, f2, NULL)); + CuAssertIntEquals(tc, 2, selist_length(ctx.addresses)); + test_cleanup(); +} + +static void test_get_addresses_travelthru(CuTest *tc) { + report_context ctx; + faction *f, *f2, *f1; + region *r1, *r2; + unit *u; + + test_setup(); + f = test_create_faction(0); + f1 = test_create_faction(0); + f2 = test_create_faction(0); + r1 = test_create_region(0, 0, 0); + r2 = test_create_region(1, 0, 0); + u = test_create_unit(f, r2); + travelthru_add(r1, u); + u = test_create_unit(f1, r1); + set_factionstealth(u, f2); + u->building = test_create_building(u->region, test_create_buildingtype("tower")); + + prepare_report(&ctx, f); + CuAssertPtrEquals(tc, r1, ctx.first); + CuAssertPtrEquals(tc, NULL, ctx.last); + get_addresses(&ctx); + CuAssertPtrNotNull(tc, ctx.addresses); + CuAssertTrue(tc, selist_contains(ctx.addresses, f, NULL)); + CuAssertTrue(tc, !selist_contains(ctx.addresses, f1, NULL)); + CuAssertTrue(tc, selist_contains(ctx.addresses, f2, NULL)); + CuAssertIntEquals(tc, 2, selist_length(ctx.addresses)); + test_cleanup(); +} + void test_prepare_lighthouse_capacity(CuTest *tc) { building *b; building_type *btype; @@ -490,6 +573,9 @@ CuSuite *get_reports_suite(void) SUITE_ADD_TEST(suite, test_prepare_lighthouse_owners); SUITE_ADD_TEST(suite, test_prepare_lighthouse_capacity); SUITE_ADD_TEST(suite, test_prepare_travelthru); + SUITE_ADD_TEST(suite, test_get_addresses); + SUITE_ADD_TEST(suite, test_get_addresses_fstealth); + SUITE_ADD_TEST(suite, test_get_addresses_travelthru); SUITE_ADD_TEST(suite, test_reorder_units); SUITE_ADD_TEST(suite, test_seen_faction); SUITE_ADD_TEST(suite, test_regionid); diff --git a/src/spy.c b/src/spy.c index d4082cad7..c9667f7ee 100644 --- a/src/spy.c +++ b/src/spy.c @@ -178,7 +178,7 @@ int spy_cmd(unit * u, struct order *ord) return 0; } -void set_factionstealth(unit * u, faction * f) +static bool can_set_factionstealth(const unit * u, const faction * f) { region *lastr = NULL; /* for all units mu of our faction, check all the units in the region @@ -194,7 +194,7 @@ void set_factionstealth(unit * u, faction * f) faction *fv = visible_faction(f, ru); if (fv == f) { if (cansee(f, lastr, ru, 0)) - break; + return true; } } ru = ru->next; @@ -204,13 +204,15 @@ void set_factionstealth(unit * u, faction * f) } mu = mu->nextF; } - if (mu != NULL) { - attrib *a = a_find(u->attribs, &at_otherfaction); - if (!a) - a = a_add(&u->attribs, make_otherfaction(f)); - else - a->data.v = f; - } + return true; +} + +void set_factionstealth(unit *u, faction *f) { + attrib *a = a_find(u->attribs, &at_otherfaction); + if (!a) + a = a_add(&u->attribs, make_otherfaction(f)); + else + a->data.v = f; } int setstealth_cmd(unit * u, struct order *ord) @@ -315,7 +317,7 @@ int setstealth_cmd(unit * u, struct order *ord) } else { struct faction *f = findfaction(nr); - if (f == NULL) { + if (f == NULL || !can_set_factionstealth(u, f)) { cmistake(u, ord, 66, MSG_EVENT); break; } diff --git a/src/spy.h b/src/spy.h index d3ee0c728..665595ef4 100644 --- a/src/spy.h +++ b/src/spy.h @@ -26,12 +26,15 @@ extern "C" { struct region; struct strlist; struct order; + struct faction; - extern int setstealth_cmd(struct unit *u, struct order *ord); - extern int spy_cmd(struct unit *u, struct order *ord); - extern int sabotage_cmd(struct unit *u, struct order *ord); - extern void spy_message(int spy, const struct unit *u, + int setstealth_cmd(struct unit *u, struct order *ord); + int spy_cmd(struct unit *u, struct order *ord); + int sabotage_cmd(struct unit *u, struct order *ord); + void spy_message(int spy, const struct unit *u, const struct unit *target); + void set_factionstealth(struct unit * u, struct faction * f); + #define OCEAN_SWIMMER_CHANCE 0.1 #define CANAL_SWIMMER_CHANCE 0.9 diff --git a/src/spy.test.c b/src/spy.test.c index ae1550689..0dfaada7a 100644 --- a/src/spy.test.c +++ b/src/spy.test.c @@ -50,14 +50,6 @@ static void test_simple_spy_message(CuTest *tc) { test_cleanup(); } -static void set_factionstealth(unit *u, faction *f) { - attrib *a = a_find(u->attribs, &at_otherfaction); - if (!a) - a = a_add(&u->attribs, make_otherfaction(f)); - else - a->data.v = f; -} - static void test_all_spy_message(CuTest *tc) { spy_fixture fix; item_type *itype; diff --git a/src/util/variant.c b/src/util/variant.c index c1d42808d..af5d690f4 100644 --- a/src/util/variant.c +++ b/src/util/variant.c @@ -2,6 +2,7 @@ #include "variant.h" #include +#include #include const variant frac_zero = { .sa = { 0, 1 } }; @@ -41,8 +42,13 @@ variant frac_make(int num, int den) int g = gcd(num, den); num /= g; den /= g; - assert(num >= SHRT_MIN && num <= SHRT_MAX); - assert(den >= SHRT_MIN && den <= SHRT_MAX); + if (num < SHRT_MIN || num > SHRT_MAX || den < SHRT_MIN || den > SHRT_MAX) { + int a = abs(num/SHRT_MIN) + 1; + int b = abs(den/SHRT_MIN) + 1; + if (b>a) a = b; + num /= a; + den /= a; + } v.sa[0] = (short)num; v.sa[1] = (short)den; return v;