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()
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%)"))

View File

@ -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;
}

View File

@ -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<73>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;

View File

@ -19,6 +19,11 @@ attrib_type at_lighthouse = {
/* 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
* 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;
}
}

View File

@ -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);

View File

@ -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;
}

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. */
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 {

View File

@ -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;

View File

@ -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();
}