BUG 2462: Leuchtturm meldet keine Landregionen, beschützt Schiffe erst ab Größe 10.

This commit is contained in:
Enno Rehling 2018-07-17 20:53:34 +02:00
parent 820264aa82
commit fc80e4b83e
9 changed files with 125 additions and 86 deletions

View File

@ -93,11 +93,11 @@ end
function test_lighthouse() function test_lighthouse()
eressea.free_game() eressea.free_game()
local r = region.create(0, 0, "mountain") 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(1, 0, "mountain")
region.create(2, 0, "ocean") region.create(2, 0, "ocean")
region.create(0, 1, "firewall") region.create(0, 1, "firewall")
region.create(3, 0, "mountain") region.create(3, 0, "ocean")
region.create(4, 0, "plain") region.create(4, 0, "plain")
local u = unit.create(f, r, 1) local u = unit.create(f, r, 1)
local b = building.create(r, "lighthouse") local b = building.create(r, "lighthouse")
@ -110,7 +110,7 @@ function test_lighthouse()
init_reports() init_reports()
write_report(f) 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, " %(2,0%) %(vom Turm erblickt%)"))
assert_true(find_in_report(f, " %(3,0%) %(vom Turm erblickt%)")) assert_true(find_in_report(f, " %(3,0%) %(vom Turm erblickt%)"))

View File

@ -895,7 +895,9 @@ build_building(unit * u, const building_type * btype, int id, int want, order *
} }
fset(b, BLD_EXPANDED); fset(b, BLD_EXPANDED);
update_lighthouse(b); if (is_lighthouse(btype)) {
update_lighthouse(b);
}
return built; return built;
} }

View File

@ -377,7 +377,9 @@ building *new_building(const struct building_type * btype, region * r,
bptr = &(*bptr)->next; bptr = &(*bptr)->next;
*bptr = b; *bptr = b;
update_lighthouse(b); if (is_lighthouse(b->type)) {
update_lighthouse(b);
}
bname = LOC(lang, btype->_name); bname = LOC(lang, btype->_name);
if (!bname) { if (!bname) {
bname = LOC(lang, parameters[P_GEBAEUDE]); bname = LOC(lang, parameters[P_GEBAEUDE]);
@ -399,6 +401,7 @@ static building *deleted_buildings;
void remove_building(building ** blist, building * b) void remove_building(building ** blist, building * b)
{ {
unit *u; unit *u;
region *r = b->region;
static const struct building_type *bt_caravan, *bt_dam, *bt_tunnel; static const struct building_type *bt_caravan, *bt_dam, *bt_tunnel;
static int btypes; static int btypes;
@ -410,18 +413,19 @@ void remove_building(building ** blist, building * b)
bt_tunnel = bt_find("tunnel"); bt_tunnel = bt_find("tunnel");
} }
handle_event(b->attribs, "destroy", b); 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 (u->building == b) leave(u, true);
} }
if (is_lighthouse(b->type)) {
remove_lighthouse(b);
}
b->size = 0; b->size = 0;
update_lighthouse(b);
bunhash(b); bunhash(b);
/* Falls Karawanserei, Damm oder Tunnel einst<73>rzen, wird die schon /* Falls Karawanserei, Damm oder Tunnel einst<73>rzen, wird die schon
* gebaute Strasse zur Haelfte vernichtet */ * gebaute Strasse zur Haelfte vernichtet */
if (b->type == bt_caravan || b->type == bt_dam || b->type == bt_tunnel) { if (b->type == bt_caravan || b->type == bt_dam || b->type == bt_tunnel) {
region *r = b->region;
int d; int d;
for (d = 0; d != MAXDIRECTIONS; ++d) { for (d = 0; d != MAXDIRECTIONS; ++d) {
direction_t dir = (direction_t)d; direction_t dir = (direction_t)d;

View File

@ -19,6 +19,11 @@ attrib_type at_lighthouse = {
/* Rest ist NULL; tempor<6F>res, nicht alterndes Attribut */ /* Rest ist NULL; tempor<6F>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 /* update_lighthouse: call this function whenever the size of a lighthouse changes
* it adds temporary markers to the surrounding regions. * it adds temporary markers to the surrounding regions.
* The existence of markers says nothing about the quality of the observer in * 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) 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; r->flags |= RF_LIGHTHOUSE;
if (lh->size > 0) { if (lh->size >= 10) {
int d = (int)log10(lh->size) + 1; int d = lighthouse_range(lh, NULL, NULL);
int x; int x;
for (x = -d; x <= d; ++x) { for (x = -d; x <= d; ++x) {
int y; int y;
for (y = -d; y <= d; ++y) { for (y = -d; y <= d; ++y) {
attrib *a; attrib *a;
region *r2; region *r2;
int px = r->x + x, py = r->y + y; int px = r->x + x, py = r->y + y;
pnormalize(&px, &py, rplane(r)); pnormalize(&px, &py, rplane(r));
r2 = findregion(px, py); r2 = findregion(px, py);
if (!r2 || !fval(r2->terrain, SEA_REGION)) if (!r2 || !fval(r2->terrain, SEA_REGION))
continue; continue;
if (distance(r, r2) > d) if (distance(r, r2) > d)
continue; continue;
a = a_find(r2->attribs, &at_lighthouse); a = a_find(r2->attribs, &at_lighthouse);
while (a && a->type == &at_lighthouse) { while (a && a->type == &at_lighthouse) {
building *b = (building *)a->data.v; building *b = (building *)a->data.v;
if (b == lh) if (b == lh)
break; break;
a = a->next; a = a->next;
} }
if (!a) { if (!a) {
a = a_add(&r2->attribs, a_new(&at_lighthouse)); a = a_add(&r2->attribs, a_new(&at_lighthouse));
a->data.v = (void *)lh; 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) 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; int maxd = (int)log10(b->size) + 1;
if (u && skill_enabled(SK_PERCEPTION)) { if (u && skill_enabled(SK_PERCEPTION)) {
@ -80,11 +96,11 @@ int lighthouse_range(const building * b, const faction * f, const unit *u)
return 0; return 0;
} }
bool check_leuchtturm(region * r, faction * f) bool lighthouse_guarded(const region * r)
{ {
attrib *a; attrib *a;
if (!fval(r->terrain, SEA_REGION)) { if (!r->attribs || !(r->terrain->flags & SEA_REGION)) {
return false; return false;
} }
for (a = a_find(r->attribs, &at_lighthouse); a && a->type == &at_lighthouse; 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; building *b = (building *)a->data.v;
assert(is_building_type(b->type, "lighthouse")); 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; int maxd = (int)log10(b->size) + 1;
int d = distance(r, b->region);
if (skill_enabled(SK_PERCEPTION) && f) { assert(maxd >= d);
region *r2 = b->region; return true;
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;
}
} }
} }

View File

@ -29,13 +29,16 @@ extern "C" {
struct faction; struct faction;
struct region; struct region;
struct building; struct building;
struct building_type;
struct unit; struct unit;
struct attrib; struct attrib;
extern struct attrib_type at_lighthouse; extern struct attrib_type at_lighthouse;
/* leuchtturm */ /* 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 update_lighthouse(struct building *b);
void remove_lighthouse(const struct building *lh);
int lighthouse_range(const struct building *b, const struct faction *f, int lighthouse_range(const struct building *b, const struct faction *f,
const struct unit *u); const struct unit *u);

View File

@ -36,6 +36,7 @@ static void test_lighthouse_range(CuTest * tc)
set_level(u1, SK_PERCEPTION, 3); set_level(u1, SK_PERCEPTION, 3);
set_level(u2, SK_PERCEPTION, 3); set_level(u2, SK_PERCEPTION, 3);
CuAssertIntEquals(tc, 0, lighthouse_range(b, NULL, NULL)); CuAssertIntEquals(tc, 0, lighthouse_range(b, NULL, NULL));
b->flags |= BLD_MAINTAINED; b->flags |= BLD_MAINTAINED;
CuAssertIntEquals(tc, 1, lighthouse_range(b, u1->faction, u1)); CuAssertIntEquals(tc, 1, lighthouse_range(b, u1->faction, u1));
set_level(u1, SK_PERCEPTION, 6); set_level(u1, SK_PERCEPTION, 6);
@ -54,7 +55,7 @@ static void test_lighthouse_range(CuTest * tc)
static void test_lighthouse_update(CuTest * tc) static void test_lighthouse_update(CuTest * tc)
{ {
region *r1, *r2, *r3; region *r1, *r2, *r3, *r4;
building *b; building *b;
const struct terrain_type *t_ocean, *t_plain; 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); r1 = test_create_region(0, 0, t_plain);
r2 = test_create_region(1, 0, t_ocean); r2 = test_create_region(1, 0, t_ocean);
r3 = test_create_region(2, 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 = test_create_building(r1, test_create_buildingtype("lighthouse"));
b->flags |= BLD_MAINTAINED;
CuAssertIntEquals(tc, RF_LIGHTHOUSE, r1->flags&RF_LIGHTHOUSE); CuAssertIntEquals(tc, RF_LIGHTHOUSE, r1->flags&RF_LIGHTHOUSE);
CuAssertPtrEquals(tc, NULL, r1->attribs); CuAssertPtrEquals(tc, NULL, r1->attribs);
CuAssertPtrEquals(tc, NULL, r2->attribs); CuAssertPtrEquals(tc, NULL, r2->attribs);
CuAssertPtrEquals(tc, NULL, r3->attribs); CuAssertPtrEquals(tc, NULL, r3->attribs);
CuAssertPtrEquals(tc, NULL, r4->attribs);
r1->flags = 0; r1->flags = 0;
b->size = 1; b->size = 9; /* minimum size for any effect is 10 */
update_lighthouse(b); update_lighthouse(b);
CuAssertIntEquals(tc, RF_LIGHTHOUSE, r1->flags&RF_LIGHTHOUSE); 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, r1->attribs);
CuAssertPtrEquals(tc, NULL, r2->attribs);
CuAssertPtrEquals(tc, NULL, r3->attribs); CuAssertPtrEquals(tc, NULL, r3->attribs);
CuAssertPtrEquals(tc, NULL, r4->attribs);
a_removeall(&r2->attribs, NULL); a_removeall(&r2->attribs, NULL);
r1->flags = 0; r1->flags = 0;
@ -88,6 +92,36 @@ static void test_lighthouse_update(CuTest * tc)
CuAssertPtrEquals(tc, (void *)&at_lighthouse, (void *)r2->attribs->type); CuAssertPtrEquals(tc, (void *)&at_lighthouse, (void *)r2->attribs->type);
CuAssertPtrNotNull(tc, r3->attribs); CuAssertPtrNotNull(tc, r3->attribs);
CuAssertPtrEquals(tc, (void *)&at_lighthouse, (void *)r3->attribs->type); 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(); test_teardown();
} }
@ -96,5 +130,6 @@ CuSuite *get_lighthouse_suite(void)
CuSuite *suite = CuSuiteNew(); CuSuite *suite = CuSuiteNew();
SUITE_ADD_TEST(suite, test_lighthouse_range); SUITE_ADD_TEST(suite, test_lighthouse_range);
SUITE_ADD_TEST(suite, test_lighthouse_update); SUITE_ADD_TEST(suite, test_lighthouse_update);
SUITE_ADD_TEST(suite, test_lighthouse_guard);
return suite; return suite;
} }

View File

@ -1779,7 +1779,7 @@ static void sail(unit * u, order * ord, region_list ** routep, bool drifting)
/* storms should be the first thing we do. */ /* storms should be the first thing we do. */
stormchance = stormyness / shipspeed(sh, u); stormchance = stormyness / shipspeed(sh, u);
if (check_leuchtturm(next_point, NULL)) { if (lighthouse_guarded(next_point)) {
if (lighthouse_div > 0) { if (lighthouse_div > 0) {
stormchance /= lighthouse_div; stormchance /= lighthouse_div;
} }
@ -1867,7 +1867,7 @@ static void sail(unit * u, order * ord, region_list ** routep, bool drifting)
if (reason == SA_NO_INSECT) { if (reason == SA_NO_INSECT) {
ADDMSG(&f->msgs, msg_message("detectforbidden", "unit region", u, sh->region)); 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)); ADDMSG(&f->msgs, msg_message("sailnolandingstorm", "ship region", sh, next_point));
} }
else { else {

View File

@ -1353,6 +1353,13 @@ static void add_seen_nb(faction *f, region *r, seen_mode mode) {
update_interval(f, last); 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. /** mark all regions seen by the lighthouse.
*/ */
static void prepare_lighthouse_ql(faction *f, selist *rlist) { 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)) { for (ql = rlist, qi = 0; ql; selist_advance(&ql, &qi, 1)) {
region *rl = (region *)selist_get(ql, qi); region *rl = (region *)selist_get(ql, qi);
if (!fval(rl->terrain, FORBIDDEN_REGION)) { add_seen_lighthouse(rl, f);
add_seen_nb(f, rl, seen_lighthouse);
}
} }
} }
@ -1382,9 +1387,7 @@ static void prepare_lighthouse(faction *f, region *r, int range)
assert(n > 0 && n <= 64); assert(n > 0 && n <= 64);
for (i = 0; i != n; ++i) { for (i = 0; i != n; ++i) {
region *rl = result[i]; region *rl = result[i];
if (!fval(rl->terrain, FORBIDDEN_REGION)) { add_seen_lighthouse(rl, f);
add_seen_nb(f, rl, seen_lighthouse);
}
} }
} }
} }
@ -1592,7 +1595,7 @@ void prepare_report(report_context *ctx, faction *f)
if (rule_region_owners && f == region_get_owner(r)) { if (rule_region_owners && f == region_get_owner(r)) {
for (b = rbuildings(r); b; b = b->next) { for (b = rbuildings(r); b; b = b->next) {
if (b && b->type == bt_lighthouse) { if (b && b->type == bt_lighthouse) {
/* region owners get maximm range */ /* region owners get maximum range */
int lhr = lighthouse_range(b, NULL, NULL); int lhr = lighthouse_range(b, NULL, NULL);
if (lhr > range) range = lhr; 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 */ /* unit is one of ours, and inside the current lighthouse */
if (br == 0) { if (br == 0) {
/* lazy-calculate the range */ /* lazy-calculate the range */
br = lighthouse_range(u->building, f, u); br = lighthouse_range(b, f, u);
} }
if (br > range) { if (br > range) {
range = br; range = br;

View File

@ -530,7 +530,7 @@ void test_prepare_lighthouse_capacity(CuTest *tc) {
static void test_prepare_lighthouse(CuTest *tc) { static void test_prepare_lighthouse(CuTest *tc) {
report_context ctx; report_context ctx;
faction *f; faction *f;
region *r1, *r2, *r3; region *r1, *r2, *r3, *r4;
unit *u; unit *u;
building *b; building *b;
building_type *btype; building_type *btype;
@ -543,6 +543,7 @@ static void test_prepare_lighthouse(CuTest *tc) {
r1 = test_create_region(0, 0, t_plain); r1 = test_create_region(0, 0, t_plain);
r2 = test_create_region(1, 0, t_ocean); r2 = test_create_region(1, 0, t_ocean);
r3 = test_create_region(2, 0, t_ocean); r3 = test_create_region(2, 0, t_ocean);
r4 = test_create_region(0, 1, t_plain);
btype = test_create_buildingtype("lighthouse"); btype = test_create_buildingtype("lighthouse");
b = test_create_building(r1, btype); b = test_create_building(r1, btype);
b->flags |= BLD_MAINTAINED; 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_unit, r1->seen.mode);
CuAssertIntEquals(tc, seen_lighthouse, r2->seen.mode); CuAssertIntEquals(tc, seen_lighthouse, r2->seen.mode);
CuAssertIntEquals(tc, seen_neighbour, r3->seen.mode); CuAssertIntEquals(tc, seen_neighbour, r3->seen.mode);
CuAssertIntEquals(tc, seen_neighbour, r4->seen.mode);
finish_reports(&ctx); finish_reports(&ctx);
test_teardown(); test_teardown();
} }