Bug 2684 Astraler Blick

Old implementation was bad, using set_observer is better. Still missing a test, but improved the one for sp_viewreality, which is almost doing the same thing - adaptation should be easy.

Fixes https://bugs.eressea.de/view.php?id=2684
This commit is contained in:
Enno Rehling 2020-07-25 20:31:15 +02:00
parent 9a4bc1ede1
commit b06f3cf0e2
7 changed files with 56 additions and 91 deletions

View file

@ -79,7 +79,7 @@ static void free_nodes(node * root)
}
}
struct selist *regions_in_range(struct region *handle_start, int maxdist,
struct selist *path_regions_in_range(struct region *handle_start, int maxdist,
bool(*allowed) (const struct region *, const struct region *))
{
selist * rlist = NULL;

View file

@ -8,15 +8,10 @@ extern "C" {
const struct region *target, int maxlen,
bool(*allowed) (const struct region *, const struct region *));
extern bool path_exists(struct region *handle_start, const struct region *target,
int maxlen, bool(*allowed) (const struct region *,
const struct region *));
extern bool allowed_swim(const struct region *src,
const struct region *target);
extern bool allowed_fly(const struct region *src,
const struct region *target);
extern bool allowed_walk(const struct region *src,
const struct region *target);
extern struct selist *regions_in_range(struct region *src, int maxdist,
int maxlen, bool(*allowed) (const struct region *, const struct region *));
extern bool allowed_fly(const struct region *src, const struct region *target);
extern bool allowed_walk(const struct region *src, const struct region *target);
extern struct selist *path_regions_in_range(struct region *src, int maxdist,
bool(*allowed) (const struct region *, const struct region *));
extern void pathfinder_cleanup(void);

View file

@ -497,7 +497,7 @@ static attrib *set_new_dragon_target(unit * u, region * r, int range)
{
int max_affinity = 0;
region *max_region = NULL;
selist *ql, *rlist = regions_in_range(r, range, allowed_dragon);
selist *ql, *rlist = path_regions_in_range(r, range, allowed_dragon);
int qi;
for (qi = 0, ql = rlist; ql; selist_advance(&ql, &qi, 1)) {

View file

@ -5423,19 +5423,22 @@ int sp_fetchastral(castorder * co)
return cast_level;
}
#define SHOWASTRAL_IS_BORKED
static bool cb_not_astral_blocked(const struct region *rt) {
return !is_cursed(rt->attribs, &ct_astralblock);
}
#undef SHOWASTRAL_IS_BORKED
#ifndef SHOWASTRAL_IS_BORKED
#define SHOWASTRAL_MAX_RADIUS 5
int sp_showastral(castorder * co)
{
unit *u;
region *rt;
int n = 0;
int c = 0;
region_list *rl, *rl2;
region *r = co_get_region(co);
unit *mage = co_get_caster(co);
int cast_level = co->level;
double power = co->force;
int force = (int) co->force;
int radius = (force < SHOWASTRAL_MAX_RADIUS) ? force : SHOWASTRAL_MAX_RADIUS;
region *targets[4 * SHOWASTRAL_MAX_RADIUS * SHOWASTRAL_MAX_RADIUS];
switch (getplaneid(r)) {
case 0:
@ -5455,62 +5458,21 @@ int sp_showastral(castorder * co)
return 0;
}
rl = all_in_range(rt, power / 5);
/* Erst Einheiten zaehlen, fuer die Grammatik. */
for (rl2 = rl; rl2; rl2 = rl2->next) {
region *r2 = rl2->data;
if (!is_cursed(r2->attribs, &ct_astralblock)) {
for (u = r2->units; u; u = u->next) {
n++;
}
}
}
n = regions_in_range(rt, radius, cb_not_astral_blocked, targets);
if (n == 0) {
/* sprintf(buf, "%s kann niemanden im astralen Nebel entdecken.",
unitname(mage)); */
cmistake(mage, co->order, 220, MSG_MAGIC);
}
else {
/* Ausgeben */
sprintf(buf, "%s hat eine Vision der astralen Ebene. Im astralen "
"Nebel zu erkennen sind ", unitname(mage));
for (rl2 = rl; rl2; rl2 = rl2->next) {
if (!is_cursed(rl2->data->attribs, &ct_astralblock)) {
for (u = rl2->data->units; u; u = u->next) {
c++;
scat(unitname(u));
scat(" (");
if (!fval(u, UFL_ANON_FACTION)) {
scat(factionname(u->faction));
scat(", ");
}
icat(u->number);
scat(" ");
scat(LOC(mage->faction->locale, rc_name_s(u_race(u), (u->number == 1) ? NAME_SINGULAR : NAME_PLURAL)));
scat(", Entfernung ");
icat(distance(rl2->data, rt));
scat(")");
if (c == n - 1) {
scat(" und ");
}
else if (c < n - 1) {
scat(", ");
}
}
}
int i;
for (i = 0; i != n; ++i) {
region *rt = targets[i];
set_observer(rt, mage->faction, (int)(co->force / 2), 2);
}
scat(".");
addmessage(r, mage->faction, buf, MSG_MAGIC, ML_INFO);
}
free_regionlist(rl);
return cast_level;
return co->level;
}
#endif
@ -5519,7 +5481,7 @@ int sp_viewreality(castorder * co)
{
region *r = co_get_region(co);
unit *mage = co_get_caster(co);
int cast_level = co->level;
int force = (int)co->force;
message *m;
region *rl[MAX_SCHEMES];
int num;
@ -5537,7 +5499,7 @@ int sp_viewreality(castorder * co)
for (i = 0; i != num; ++i) {
region *rt = rl[i];
if (!is_cursed(rt->attribs, &ct_astralblock)) {
set_observer(rt, mage->faction, co->level / 2, 2);
set_observer(rt, mage->faction, force / 2, 2);
}
}
}
@ -5546,7 +5508,7 @@ int sp_viewreality(castorder * co)
r_addmessage(r, mage->faction, m);
msg_release(m);
return cast_level;
return co->level;
}
static void cb_disrupt_astral(region *r2, void *cbdata) {

View file

@ -116,7 +116,7 @@ static void test_bad_dreams(CuTest *tc) {
}
static void test_view_reality(CuTest *tc) {
region *r, *ra;
region *r, *ra, *rx;
faction *f;
unit *u;
castorder co;
@ -127,12 +127,13 @@ static void test_view_reality(CuTest *tc) {
mt_create_va(mt_new("viewreality_effect", NULL),
"unit:unit", MT_NEW_END);
r = test_create_region(0, 0, NULL);
rx = test_create_region(0, TP_RADIUS+1, NULL);
ra = test_create_region(real2tp(r->x), real2tp(r->y), NULL);
ra->_plane = get_astralplane();
f = test_create_faction(NULL);
u = test_create_unit(f, r);
test_create_castorder(&co, u, 10, 10., 0, NULL);
test_create_castorder(&co, u, 10, 10.0, 0, NULL);
CuAssertIntEquals(tc, -1, get_observer(r, f));
CuAssertIntEquals(tc, 0, sp_viewreality(&co));
CuAssertPtrNotNull(tc, test_find_messagetype(f->msgs, "spell_astral_only"));
@ -141,11 +142,12 @@ static void test_view_reality(CuTest *tc) {
test_clear_messagelist(&f->msgs);
move_unit(u, ra, NULL);
test_create_castorder(&co, u, 9, 10., 0, NULL);
test_create_castorder(&co, u, 9, 10.0, 0, NULL);
CuAssertIntEquals(tc, -1, get_observer(r, f));
CuAssertIntEquals(tc, 9, sp_viewreality(&co));
CuAssertPtrEquals(tc, NULL, test_find_messagetype(f->msgs, "spell_astral_only"));
CuAssertIntEquals(tc, 4, get_observer(r, f));
CuAssertIntEquals(tc, 5, get_observer(r, f));
CuAssertIntEquals(tc, -1, get_observer(rx, f));
CuAssertPtrEquals(tc, f, (void *)ra->individual_messages->viewer);
CuAssertPtrNotNull(tc, test_find_messagetype(ra->individual_messages->msgs, "viewreality_effect"));
free_castorder(&co);

View file

@ -43,32 +43,37 @@ static region *tpregion(const region * r)
return rt;
}
int regions_in_range(const region * r, int radius, bool(*valid) (const region *), region *result[])
{
int x, y, num = 0;
const struct plane *pl = rplane(r);
for (x = -radius; x <= +radius; ++x) {
for (y = -radius; y <= radius; ++y) {
int dist = koor_distance(0, 0, x, y);
if (dist <= radius) {
region *rn;
int nx = r->x + x, ny = r->y + y;
pnormalize(&nx, &ny, pl);
rn = findregion(nx, ny);
if (rn != NULL && (valid == NULL || valid(rn))) {
if (result) {
result[num] = rn;
}
++num;
}
}
}
}
return num;
}
int get_astralregions(const region * r, bool(*valid) (const region *), region *result[])
{
assert(is_astral(r));
r = r_astral_to_standard(r);
if (r) {
int x, y, num = 0;
for (x = -TP_RADIUS; x <= +TP_RADIUS; ++x) {
for (y = -TP_RADIUS; y <= +TP_RADIUS; ++y) {
region *rn;
int dist = koor_distance(0, 0, x, y);
if (dist <= TP_RADIUS) {
int nx = r->x + x, ny = r->y + y;
pnormalize(&nx, &ny, rplane(r));
rn = findregion(nx, ny);
if (rn != NULL && (valid == NULL || valid(rn))) {
if (result) {
result[num] = rn;
}
++num;
}
}
}
}
return num;
return regions_in_range(r, TP_RADIUS, valid, result);
}
return 0;
}

View file

@ -20,6 +20,7 @@ extern "C" {
bool is_astral(const struct region *r);
struct plane *get_astralplane(void);
int get_astralregions(const struct region * r, bool(*valid) (const struct region *), struct region *result[]);
int regions_in_range(const struct region * r, int radius, bool(*valid) (const struct region *), struct region *result[]);
void create_teleport_plane(void);
void spawn_braineaters(float chance);