From 407de0db2002feec22bcf378268de95b67d1c5ce Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Tue, 22 Jun 2021 00:30:06 +0200 Subject: [PATCH] resolve cansee and cansee_unit code-duplication --- src/laws.c | 190 ++++++++++++++++++++++------------------------- src/laws.h | 4 +- src/reports.c | 4 +- src/travelthru.c | 2 +- 4 files changed, 91 insertions(+), 109 deletions(-) diff --git a/src/laws.c b/src/laws.c index 6adcf5f02..8f30b3416 100644 --- a/src/laws.c +++ b/src/laws.c @@ -4021,10 +4021,79 @@ void turn_end(void) update_spells(); } +typedef enum cansee_t { + CANSEE_DETECTED, + CANSEE_HIDDEN, + CANSEE_INVISIBLE +} cansee_t; + +static enum cansee_t cansee_ex(const unit *u, const region *r, const unit *target, int stealth, int rings) +{ + enum cansee_t result = CANSEE_HIDDEN; + if (rings >= target->number) { + const resource_type *rtype = get_resourcetype(R_AMULET_OF_TRUE_SEEING); + int amulet = i_get(u->items, rtype->itype); + if (amulet <= 0) { + return CANSEE_INVISIBLE; + } + } + if (skill_enabled(SK_PERCEPTION)) { + int watch = effskill(u, SK_PERCEPTION, r); + if (stealth > watch) { + return result; + } + } + return CANSEE_DETECTED; +} + +static bool is_exposed(const unit *u) { + return u->building || u->ship || is_guard(u) || leftship(u); +} + +static bool big_sea_monster(const unit *u, const region *r) { + return ((r->terrain->flags & SEA_REGION) && (u_race(u)->weight >= 5000)); +} + +bool +cansee_unit(const unit * u, const region *r, const unit * target, int modifier) +/* r kann != u->region sein, wenn es um durchreisen geht */ +{ + int stealth, rings; + enum cansee_t see; + if (target->number == 0) { + return false; + } + else if (target->faction == u->faction || omniscient(u->faction)) { + return true; + } + else if (is_exposed(target)) { + return true; + } + else if (target->number == 0) { + attrib *a = a_find(target->attribs, &at_creator); + if (a) { + /* u is an empty temporary unit. In this special case we look at the creating unit. */ + target = (unit *)a->data.v; + } + else { + return false; + } + } + + stealth = eff_stealth(target, r) - modifier; + rings = invisible(target, NULL); + see = cansee_ex(u, r, target, stealth, rings); + if (CANSEE_HIDDEN == see) { + /* bug 2763 and 2754: can see sea serpents on oceans */ + return big_sea_monster(u, r); + } + return CANSEE_DETECTED == see; +} + /** * Determine if unit can be seen by faction. * - * @param f -- the observiong faction + * @param f -- the observing faction * @param u -- the unit that is observed * @param r -- the region that u is obesrved from (see below) * @param m -- terrain modifier to stealth @@ -4034,15 +4103,18 @@ void turn_end(void) * Es muss auch niemand aus f in der region sein, wenn sie vom Turm * erblickt wird. */ -bool cansee(const faction * f, const region * r, const unit * u, int modifier) +bool cansee(const faction *f, const region *r, const unit *u, int modifier) { unit *u2; - int stealth, rings; + int rings, stealth; + bool bsm, result; + /* quick exits: */ if (u->faction == f || omniscient(f)) { return true; } else if (u->number == 0) { + /* no need to do this in each cansee_unit: */ attrib *a = a_find(u->attribs, &at_creator); if (a) { /* u is an empty temporary unit. In this special case we look at the creating unit. */ @@ -4052,9 +4124,8 @@ bool cansee(const faction * f, const region * r, const unit * u, int modifier) return false; } } - - /* simple visibility, just gotta have a viewer in the region to see 'em */ - if (leftship(u) || is_guard(u) || u->building || u->ship) { + if (is_exposed(u)) { + /* obviosuly visibile, we only need a viewer in the region */ return true; } @@ -4065,117 +4136,30 @@ bool cansee(const faction * f, const region * r, const unit * u, int modifier) return true; } + result = bsm = big_sea_monster(u, r); for (u2 = r->units; u2; u2 = u2->next) { if (u2->faction == f) { - if (rings < u->number || invisible(u, u2) < u->number) { - if (skill_enabled(SK_PERCEPTION)) { - int observation = effskill(u2, SK_PERCEPTION, NULL); - - if (observation >= stealth) { - return true; - } - } - else { - return true; - } - } - } - } - - /* bug 2763 and 2754: sea serpents are visible on oceans */ - if ((u->region->terrain->flags & SEA_REGION) && (u_race(u)->weight >= 5000)) { - return true; - } - return false; -} - -bool cansee_unit(const unit * u, const unit * target, int modifier) -/* target->region kann != u->region sein, wenn es um durchreisen geht */ -{ - if (target->number == 0) - return false; - else if (target->faction == u->faction) - return true; - else { - int n, rings; - - if (is_guard(target) || target->building - || target->ship) { - return true; - } - - n = eff_stealth(target, target->region) - modifier; - rings = invisible(target, NULL); - if (rings == 0 && n <= 0) { - return true; - } - - if (rings && invisible(target, u) >= target->number) { - return false; - } - if (skill_enabled(SK_PERCEPTION)) { - int o = effskill(u, SK_PERCEPTION, target->region); - if (o >= n) { + enum cansee_t see = cansee_ex(u2, r, u, stealth, rings); + if (see == CANSEE_DETECTED) { return true; } - } - else { - return true; - } - } - return false; -} - -bool -cansee_durchgezogen(const faction * f, const region * r, const unit * u, - int modifier) - /* r kann != u->region sein, wenn es um durchreisen geht */ - /* und es muss niemand aus f in der region sein, wenn sie vom Turm - * erblickt wird */ -{ - unit *u2; - - if (u->number == 0) - return false; - else if (u->faction == f) - return true; - else { - int rings, n; - - if (is_guard(u) || u->building || u->ship) { - return true; - } - - n = eff_stealth(u, r) - modifier; - rings = invisible(u, NULL); - if (rings == 0 && n <= 0) { - return true; - } - - for (u2 = r->units; u2; u2 = u2->next) { - if (u2->faction == f) { - int o; - - if (rings && invisible(u, u2) >= u->number) - continue; - - o = effskill(u2, SK_PERCEPTION, NULL); - - if (o >= n) { - return true; - } + else if (see == CANSEE_HIDDEN && bsm) { + return true; } + /* still invisible to all: */ + result = false; } } - return false; + return result; } bool seefaction(const faction * f, const region * r, const unit * u, int modifier) { if (((f == u->faction) || !fval(u, UFL_ANON_FACTION)) - && cansee(f, r, u, modifier)) + && cansee(f, r, u, modifier)) { return true; + } return false; } diff --git a/src/laws.h b/src/laws.h index 7fdd03863..0b7eb6e34 100755 --- a/src/laws.h +++ b/src/laws.h @@ -86,9 +86,7 @@ extern "C" { bool cansee(const struct faction * f, const struct region * r, const struct unit *u, int modifier); - bool cansee_durchgezogen(const struct faction *f, const struct region *r, - const struct unit *u, int modifier); - bool cansee_unit(const struct unit *u, const struct unit *target, + bool cansee_unit(const struct unit *u, const struct region *r, const struct unit *who, int modifier); bool seefaction(const struct faction *f, const struct region *r, const struct unit *u, int modifier); diff --git a/src/reports.c b/src/reports.c index 40066b08f..22fe9ba33 100644 --- a/src/reports.c +++ b/src/reports.c @@ -1045,7 +1045,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(ut, u, data->stealthmod)) { + if (data->lastf != sf && cansee_unit(ut, r, u, data->stealthmod)) { add_seen_faction_i(data->flist, sf); data->lastf = sf; } @@ -2361,7 +2361,7 @@ static void count_cb(region *r, unit *u, void *cbdata) { count_data *data = (count_data *)cbdata; const struct faction *f = data->f; if (r != u->region && (!u->ship || ship_owner(u->ship) == u)) { - if (cansee_durchgezogen(f, r, u, 0)) { + if (cansee(f, r, u, 0)) { ++data->n; } } diff --git a/src/travelthru.c b/src/travelthru.c index 9d984a16e..207fae8a3 100644 --- a/src/travelthru.c +++ b/src/travelthru.c @@ -74,7 +74,7 @@ void travelthru_add(region * r, unit * u) bool travelthru_cansee(const struct region *r, const struct faction *f, const struct unit *u) { if (r != u->region && (!u->ship || ship_owner(u->ship) == u)) { - return cansee_durchgezogen(f, r, u, 0); + return cansee(f, r, u, 0); } return false; }