From fc80e4b83eb4015de12546240667836ac4f7fc43 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Tue, 17 Jul 2018 20:53:34 +0200 Subject: [PATCH] =?UTF-8?q?BUG=202462:=20Leuchtturm=20meldet=20keine=20Lan?= =?UTF-8?q?dregionen,=20besch=C3=BCtzt=20Schiffe=20erst=20ab=20Gr=C3=B6?= =?UTF-8?q?=C3=9Fe=2010.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- scripts/tests/report.lua | 6 +-- src/kernel/build.c | 4 +- src/kernel/building.c | 12 +++-- src/lighthouse.c | 114 ++++++++++++++++++--------------------- src/lighthouse.h | 5 +- src/lighthouse.test.c | 43 +++++++++++++-- src/move.c | 4 +- src/reports.c | 19 ++++--- src/reports.test.c | 4 +- 9 files changed, 125 insertions(+), 86 deletions(-) diff --git a/scripts/tests/report.lua b/scripts/tests/report.lua index 12d1538c3..b65bcc279 100644 --- a/scripts/tests/report.lua +++ b/scripts/tests/report.lua @@ -93,11 +93,11 @@ end function test_lighthouse() eressea.free_game() local r = region.create(0, 0, "mountain") - local f = faction.create("human", "noreply@eressea.de", "de") + local f = faction.create("human", "human@example.com") region.create(1, 0, "mountain") region.create(2, 0, "ocean") region.create(0, 1, "firewall") - region.create(3, 0, "mountain") + region.create(3, 0, "ocean") region.create(4, 0, "plain") local u = unit.create(f, r, 1) local b = building.create(r, "lighthouse") @@ -110,7 +110,7 @@ function test_lighthouse() init_reports() write_report(f) - assert_true(find_in_report(f, " %(1,0%) %(vom Turm erblickt%)")) + assert_false(find_in_report(f, " %(1,0%) %(vom Turm erblickt%)")) assert_true(find_in_report(f, " %(2,0%) %(vom Turm erblickt%)")) assert_true(find_in_report(f, " %(3,0%) %(vom Turm erblickt%)")) diff --git a/src/kernel/build.c b/src/kernel/build.c index 310e4bd43..11324f752 100644 --- a/src/kernel/build.c +++ b/src/kernel/build.c @@ -895,7 +895,9 @@ build_building(unit * u, const building_type * btype, int id, int want, order * } fset(b, BLD_EXPANDED); - update_lighthouse(b); + if (is_lighthouse(btype)) { + update_lighthouse(b); + } return built; } diff --git a/src/kernel/building.c b/src/kernel/building.c index f3f01905f..75cad30f7 100644 --- a/src/kernel/building.c +++ b/src/kernel/building.c @@ -377,7 +377,9 @@ building *new_building(const struct building_type * btype, region * r, bptr = &(*bptr)->next; *bptr = b; - update_lighthouse(b); + if (is_lighthouse(b->type)) { + update_lighthouse(b); + } bname = LOC(lang, btype->_name); if (!bname) { bname = LOC(lang, parameters[P_GEBAEUDE]); @@ -399,6 +401,7 @@ static building *deleted_buildings; void remove_building(building ** blist, building * b) { unit *u; + region *r = b->region; static const struct building_type *bt_caravan, *bt_dam, *bt_tunnel; static int btypes; @@ -410,18 +413,19 @@ void remove_building(building ** blist, building * b) bt_tunnel = bt_find("tunnel"); } handle_event(b->attribs, "destroy", b); - for (u = b->region->units; u; u = u->next) { + for (u = r->units; u; u = u->next) { if (u->building == b) leave(u, true); } + if (is_lighthouse(b->type)) { + remove_lighthouse(b); + } b->size = 0; - update_lighthouse(b); bunhash(b); /* Falls Karawanserei, Damm oder Tunnel einst�rzen, wird die schon * gebaute Strasse zur Haelfte vernichtet */ if (b->type == bt_caravan || b->type == bt_dam || b->type == bt_tunnel) { - region *r = b->region; int d; for (d = 0; d != MAXDIRECTIONS; ++d) { direction_t dir = (direction_t)d; diff --git a/src/lighthouse.c b/src/lighthouse.c index fbf950fb1..2ff1c6191 100644 --- a/src/lighthouse.c +++ b/src/lighthouse.c @@ -19,6 +19,11 @@ attrib_type at_lighthouse = { /* Rest ist NULL; tempor�res, nicht alterndes Attribut */ }; +bool is_lighthouse(const building_type *btype) +{ + return is_building_type(btype, "lighthouse"); +} + /* update_lighthouse: call this function whenever the size of a lighthouse changes * it adds temporary markers to the surrounding regions. * The existence of markers says nothing about the quality of the observer in @@ -26,46 +31,57 @@ attrib_type at_lighthouse = { */ void update_lighthouse(building * lh) { - if (is_building_type(lh->type, "lighthouse")) { - region *r = lh->region; + region *r = lh->region; + assert(is_lighthouse(lh->type)); - r->flags |= RF_LIGHTHOUSE; - if (lh->size > 0) { - int d = (int)log10(lh->size) + 1; - int x; - for (x = -d; x <= d; ++x) { - int y; - for (y = -d; y <= d; ++y) { - attrib *a; - region *r2; - int px = r->x + x, py = r->y + y; + r->flags |= RF_LIGHTHOUSE; + if (lh->size >= 10) { + int d = lighthouse_range(lh, NULL, NULL); + int x; + for (x = -d; x <= d; ++x) { + int y; + for (y = -d; y <= d; ++y) { + attrib *a; + region *r2; + int px = r->x + x, py = r->y + y; - pnormalize(&px, &py, rplane(r)); - r2 = findregion(px, py); - if (!r2 || !fval(r2->terrain, SEA_REGION)) - continue; - if (distance(r, r2) > d) - continue; - a = a_find(r2->attribs, &at_lighthouse); - while (a && a->type == &at_lighthouse) { - building *b = (building *)a->data.v; - if (b == lh) - break; - a = a->next; - } - if (!a) { - a = a_add(&r2->attribs, a_new(&at_lighthouse)); - a->data.v = (void *)lh; - } + pnormalize(&px, &py, rplane(r)); + r2 = findregion(px, py); + if (!r2 || !fval(r2->terrain, SEA_REGION)) + continue; + if (distance(r, r2) > d) + continue; + a = a_find(r2->attribs, &at_lighthouse); + while (a && a->type == &at_lighthouse) { + building *b = (building *)a->data.v; + if (b == lh) + break; + a = a->next; + } + if (!a) { + a = a_add(&r2->attribs, a_new(&at_lighthouse)); + a->data.v = (void *)lh; } } } } } +void remove_lighthouse(const building *lh) { + building *b; + region * r = lh->region; + + r->flags &= ~RF_LIGHTHOUSE; + for (b = r->buildings; b; b = b->next) { + if (b != lh && is_lighthouse(b->type)) { + update_lighthouse(b); + } + } +} + int lighthouse_range(const building * b, const faction * f, const unit *u) { - if (fval(b, BLD_MAINTAINED) && b->size >= 10) { + if (b->size >= 10 && (b->flags & BLD_MAINTAINED)) { int maxd = (int)log10(b->size) + 1; if (u && skill_enabled(SK_PERCEPTION)) { @@ -80,11 +96,11 @@ int lighthouse_range(const building * b, const faction * f, const unit *u) return 0; } -bool check_leuchtturm(region * r, faction * f) +bool lighthouse_guarded(const region * r) { attrib *a; - if (!fval(r->terrain, SEA_REGION)) { + if (!r->attribs || !(r->terrain->flags & SEA_REGION)) { return false; } for (a = a_find(r->attribs, &at_lighthouse); a && a->type == &at_lighthouse; @@ -92,37 +108,11 @@ bool check_leuchtturm(region * r, faction * f) building *b = (building *)a->data.v; assert(is_building_type(b->type, "lighthouse")); - if (fval(b, BLD_MAINTAINED) && b->size >= 10) { + if ((b->flags & BLD_MAINTAINED) && b->size >= 10) { int maxd = (int)log10(b->size) + 1; - - if (skill_enabled(SK_PERCEPTION) && f) { - region *r2 = b->region; - unit *u; - int c = 0; - int d = 0; - - for (u = r2->units; u; u = u->next) { - if (u->building == b) { - c += u->number; - if (c > buildingcapacity(b)) - break; - if (u->faction == f) { - if (!d) - d = distance(r, r2); - if (maxd < d) - break; - if (effskill(u, SK_PERCEPTION, 0) >= d * 3) - return true; - } - } - else if (c) - break; /* first unit that's no longer in the house ends the search */ - } - } - else { - /* E3A rule: no perception req'd */ - return true; - } + int d = distance(r, b->region); + assert(maxd >= d); + return true; } } diff --git a/src/lighthouse.h b/src/lighthouse.h index 2eacfb7d8..cd5a02d04 100644 --- a/src/lighthouse.h +++ b/src/lighthouse.h @@ -29,13 +29,16 @@ extern "C" { struct faction; struct region; struct building; + struct building_type; struct unit; struct attrib; extern struct attrib_type at_lighthouse; /* leuchtturm */ - bool check_leuchtturm(struct region *r, struct faction *f); + bool is_lighthouse(const struct building_type *btype); + bool lighthouse_guarded(const struct region *r); void update_lighthouse(struct building *b); + void remove_lighthouse(const struct building *lh); int lighthouse_range(const struct building *b, const struct faction *f, const struct unit *u); diff --git a/src/lighthouse.test.c b/src/lighthouse.test.c index e0c57ec1a..bcc7c0ab7 100644 --- a/src/lighthouse.test.c +++ b/src/lighthouse.test.c @@ -36,6 +36,7 @@ static void test_lighthouse_range(CuTest * tc) set_level(u1, SK_PERCEPTION, 3); set_level(u2, SK_PERCEPTION, 3); CuAssertIntEquals(tc, 0, lighthouse_range(b, NULL, NULL)); + b->flags |= BLD_MAINTAINED; CuAssertIntEquals(tc, 1, lighthouse_range(b, u1->faction, u1)); set_level(u1, SK_PERCEPTION, 6); @@ -54,7 +55,7 @@ static void test_lighthouse_range(CuTest * tc) static void test_lighthouse_update(CuTest * tc) { - region *r1, *r2, *r3; + region *r1, *r2, *r3, *r4; building *b; const struct terrain_type *t_ocean, *t_plain; @@ -64,20 +65,23 @@ static void test_lighthouse_update(CuTest * tc) r1 = test_create_region(0, 0, t_plain); r2 = test_create_region(1, 0, t_ocean); r3 = test_create_region(2, 0, t_ocean); + r4 = test_create_region(0, 1, t_plain); b = test_create_building(r1, test_create_buildingtype("lighthouse")); + b->flags |= BLD_MAINTAINED; CuAssertIntEquals(tc, RF_LIGHTHOUSE, r1->flags&RF_LIGHTHOUSE); CuAssertPtrEquals(tc, NULL, r1->attribs); CuAssertPtrEquals(tc, NULL, r2->attribs); CuAssertPtrEquals(tc, NULL, r3->attribs); + CuAssertPtrEquals(tc, NULL, r4->attribs); r1->flags = 0; - b->size = 1; + b->size = 9; /* minimum size for any effect is 10 */ update_lighthouse(b); CuAssertIntEquals(tc, RF_LIGHTHOUSE, r1->flags&RF_LIGHTHOUSE); - CuAssertPtrNotNull(tc, r2->attribs); - CuAssertPtrEquals(tc, (void *)&at_lighthouse, (void *)r2->attribs->type); CuAssertPtrEquals(tc, NULL, r1->attribs); + CuAssertPtrEquals(tc, NULL, r2->attribs); CuAssertPtrEquals(tc, NULL, r3->attribs); + CuAssertPtrEquals(tc, NULL, r4->attribs); a_removeall(&r2->attribs, NULL); r1->flags = 0; @@ -88,6 +92,36 @@ static void test_lighthouse_update(CuTest * tc) CuAssertPtrEquals(tc, (void *)&at_lighthouse, (void *)r2->attribs->type); CuAssertPtrNotNull(tc, r3->attribs); CuAssertPtrEquals(tc, (void *)&at_lighthouse, (void *)r3->attribs->type); + CuAssertPtrEquals(tc, NULL, r4->attribs); + test_teardown(); +} + +static void test_lighthouse_guard(CuTest * tc) { + region *r1, *r2, *r3, *r4; + building *b; + 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); + r1 = test_create_region(0, 0, t_plain); + r2 = test_create_region(1, 0, t_ocean); + r3 = test_create_region(2, 0, t_ocean); + r4 = test_create_region(0, 1, t_plain); + b = test_create_building(r1, test_create_buildingtype("lighthouse")); + b->flags |= BLD_MAINTAINED; + b->size = 10; + CuAssertIntEquals(tc, 2, lighthouse_range(b, NULL, NULL)); + update_lighthouse(b); + CuAssertIntEquals(tc, RF_LIGHTHOUSE, r1->flags&RF_LIGHTHOUSE); + CuAssertPtrEquals(tc, NULL, r1->attribs); + CuAssertPtrEquals(tc, (void *)&at_lighthouse, (void *)r2->attribs->type); + CuAssertPtrEquals(tc, (void *)&at_lighthouse, (void *)r3->attribs->type); + CuAssertPtrEquals(tc, NULL, r4->attribs); + CuAssertIntEquals(tc, false, lighthouse_guarded(r1)); + CuAssertIntEquals(tc, true, lighthouse_guarded(r2)); + CuAssertIntEquals(tc, true, lighthouse_guarded(r3)); + CuAssertIntEquals(tc, false, lighthouse_guarded(r4)); test_teardown(); } @@ -96,5 +130,6 @@ CuSuite *get_lighthouse_suite(void) CuSuite *suite = CuSuiteNew(); SUITE_ADD_TEST(suite, test_lighthouse_range); SUITE_ADD_TEST(suite, test_lighthouse_update); + SUITE_ADD_TEST(suite, test_lighthouse_guard); return suite; } diff --git a/src/move.c b/src/move.c index 990d6fc14..205b52416 100644 --- a/src/move.c +++ b/src/move.c @@ -1779,7 +1779,7 @@ static void sail(unit * u, order * ord, region_list ** routep, bool drifting) /* storms should be the first thing we do. */ stormchance = stormyness / shipspeed(sh, u); - if (check_leuchtturm(next_point, NULL)) { + if (lighthouse_guarded(next_point)) { if (lighthouse_div > 0) { stormchance /= lighthouse_div; } @@ -1867,7 +1867,7 @@ static void sail(unit * u, order * ord, region_list ** routep, bool drifting) if (reason == SA_NO_INSECT) { ADDMSG(&f->msgs, msg_message("detectforbidden", "unit region", u, sh->region)); } - else if (check_leuchtturm(current_point, NULL)) { + else if (lighthouse_guarded(current_point)) { ADDMSG(&f->msgs, msg_message("sailnolandingstorm", "ship region", sh, next_point)); } else { diff --git a/src/reports.c b/src/reports.c index 5355a1db9..5d22636e8 100644 --- a/src/reports.c +++ b/src/reports.c @@ -1353,6 +1353,13 @@ static void add_seen_nb(faction *f, region *r, seen_mode mode) { update_interval(f, last); } +static void add_seen_lighthouse(region *r, faction *f) +{ + if (r->terrain->flags & SEA_REGION) { + add_seen_nb(f, r, seen_lighthouse); + } +} + /** mark all regions seen by the lighthouse. */ static void prepare_lighthouse_ql(faction *f, selist *rlist) { @@ -1361,9 +1368,7 @@ static void prepare_lighthouse_ql(faction *f, selist *rlist) { for (ql = rlist, qi = 0; ql; selist_advance(&ql, &qi, 1)) { region *rl = (region *)selist_get(ql, qi); - if (!fval(rl->terrain, FORBIDDEN_REGION)) { - add_seen_nb(f, rl, seen_lighthouse); - } + add_seen_lighthouse(rl, f); } } @@ -1382,9 +1387,7 @@ static void prepare_lighthouse(faction *f, region *r, int range) assert(n > 0 && n <= 64); for (i = 0; i != n; ++i) { region *rl = result[i]; - if (!fval(rl->terrain, FORBIDDEN_REGION)) { - add_seen_nb(f, rl, seen_lighthouse); - } + add_seen_lighthouse(rl, f); } } } @@ -1592,7 +1595,7 @@ void prepare_report(report_context *ctx, faction *f) if (rule_region_owners && f == region_get_owner(r)) { for (b = rbuildings(r); b; b = b->next) { if (b && b->type == bt_lighthouse) { - /* region owners get maximm range */ + /* region owners get maximum range */ int lhr = lighthouse_range(b, NULL, NULL); if (lhr > range) range = lhr; } @@ -1630,7 +1633,7 @@ void prepare_report(report_context *ctx, faction *f) /* unit is one of ours, and inside the current lighthouse */ if (br == 0) { /* lazy-calculate the range */ - br = lighthouse_range(u->building, f, u); + br = lighthouse_range(b, f, u); } if (br > range) { range = br; diff --git a/src/reports.test.c b/src/reports.test.c index 2b22782ae..6d7a7961f 100644 --- a/src/reports.test.c +++ b/src/reports.test.c @@ -530,7 +530,7 @@ void test_prepare_lighthouse_capacity(CuTest *tc) { static void test_prepare_lighthouse(CuTest *tc) { report_context ctx; faction *f; - region *r1, *r2, *r3; + region *r1, *r2, *r3, *r4; unit *u; building *b; building_type *btype; @@ -543,6 +543,7 @@ static void test_prepare_lighthouse(CuTest *tc) { r1 = test_create_region(0, 0, t_plain); r2 = test_create_region(1, 0, t_ocean); r3 = test_create_region(2, 0, t_ocean); + r4 = test_create_region(0, 1, t_plain); btype = test_create_buildingtype("lighthouse"); b = test_create_building(r1, btype); b->flags |= BLD_MAINTAINED; @@ -557,6 +558,7 @@ static void test_prepare_lighthouse(CuTest *tc) { CuAssertIntEquals(tc, seen_unit, r1->seen.mode); CuAssertIntEquals(tc, seen_lighthouse, r2->seen.mode); CuAssertIntEquals(tc, seen_neighbour, r3->seen.mode); + CuAssertIntEquals(tc, seen_neighbour, r4->seen.mode); finish_reports(&ctx); test_teardown(); }