bug 2684: update sp_showastral and sp_viewreality.

add more messages
add unit tests
closes https://bugs.eressea.de/view.php?id=2684
This commit is contained in:
Enno Rehling 2020-07-26 16:58:57 +02:00
parent cf1c06ad29
commit 9e3dc18daa
10 changed files with 178 additions and 70 deletions

View File

@ -247,14 +247,14 @@
<arg name="id" type="int"/>
</type>
</message>
<message name="curseinfo::skill_2" section="events">
<message name="curseinfo_skill_2" section="events">
<type>
<arg name="unit" type="unit"/>
<arg name="skill" type="skill"/>
<arg name="id" type="int"/>
</type>
</message>
<message name="curseinfo::skill_1" section="events">
<message name="curseinfo_skill_1" section="events">
<type>
<arg name="unit" type="unit"/>
<arg name="skill" type="skill"/>
@ -1124,6 +1124,12 @@
</type>
</message>
<message name="showastral_effect" section="magic">
<type>
<arg name="unit" type="unit"/>
</type>
</message>
<message name="recruit_effect" section="magic">
<type>
<arg name="mage" type="unit"/>
@ -5798,13 +5804,6 @@
<arg name="command" type="order"/>
</type>
</message>
<message name="spellfail::noway" section="magic">
<type>
<arg name="unit" type="unit"/>
<arg name="region" type="region"/>
<arg name="command" type="order"/>
</type>
</message>
<message name="spellfail::nocontact" section="magic">
<type>
<arg name="unit" type="unit"/>

View File

@ -656,7 +656,7 @@ msgstr "\"$unit($unit) ertrinkt in $region($region).\""
msgid "travel"
msgstr "\"$unit($unit) $if($eq($mode,1),\"reitet\", \"wandert\") von $region($start) nach $region($end).$if($isnull($regions),\"\",\" Dabei wurde $trail($regions) durchquert.\")\""
msgid "curseinfo::skill_1"
msgid "curseinfo_skill_1"
msgstr "\"$unit($unit) ist ungewöhnlich geschickt in $skill($skill). ($int36($id))\""
msgid "error11"
@ -1487,12 +1487,9 @@ msgstr "\"Ein magischer Schimmer liegt auf diesen Mauern. ($int36($id))\""
msgid "changebanner"
msgstr "\"Das Banner wurde auf '$value' geändert.\""
msgid "curseinfo::skill_2"
msgid "curseinfo_skill_2"
msgstr "\"$unit($unit) ist ungewöhnlich ungeschickt in $skill($skill). ($int36($id))\""
msgid "spellfail::noway"
msgstr "\"$unit($unit) in $region($region): '$order($command)' - Dorthin führt kein Weg.\""
msgid "spellbuildingresists"
msgstr "\"$unit($unit) in $region($region): '$order($command)' - Gebäude $int36($id) konnte nicht verzaubert werden.\""
@ -2522,6 +2519,9 @@ msgstr "\"$unit($mage) meint, dass auf $region($region) ein Zauber liegt, konnte
msgid "viewreality_effect"
msgstr "\"$unit($unit) gelingt es, durch die Nebel auf die Realität zu blicken.\""
msgid "showastral_effect"
msgstr "\"$unit($unit) gelingt es, in die Nebel des Astralraums zu blicken.\""
msgid "use_speedsail"
msgstr "\"$unit($unit) setzt ein Sonnensegel. Die Geschwindigkeit des Schiffes erhöht um $int($speed).\""

View File

@ -656,7 +656,7 @@ msgstr "\"$unit($unit) drowns in $region($region).\""
msgid "travel"
msgstr "\"$unit($unit) $if($eq($mode,1),\"rides\", \"walks\") from $region($start) to $region($end)$if($isnull($regions),\"\",\" by way of $trail($regions)\").\""
msgid "curseinfo::skill_1"
msgid "curseinfo_skill_1"
msgstr "\"$unit($unit) is incredibly skilled at $skill($skill). ($int36($id))\""
msgid "error11"
@ -1487,12 +1487,9 @@ msgstr "\"A magical shimmer lies on these walls. ($int36($id))\""
msgid "changebanner"
msgstr "\"Banner has been changed to '$value'.\""
msgid "curseinfo::skill_2"
msgid "curseinfo_skill_2"
msgstr "\"$unit($unit) has some troubles with $skill($skill). ($int36($id))\""
msgid "spellfail::noway"
msgstr "\"$unit($unit) in $region($region): '$order($command)' - There is no route leading there.\""
msgid "spellbuildingresists"
msgstr "\"$unit($unit) in $region($region): '$order($command)' - Building $int36($id) could not be charmed.\""
@ -2519,6 +2516,9 @@ msgstr "\"$unit($unit) in $region($region): '$order($command)' - The magician de
msgid "analyse_region_fail"
msgstr "\"It appears to $unit($mage) that $region($region) is charmed, but no details have been revealed.\""
msgid "showastral_effect"
msgstr "\"$unit($unit) has a vision of the astral plane.\""
msgid "viewreality_effect"
msgstr "\"$unit($unit) manages to catch a glimpse of reality through the fog.\""

View File

@ -121,7 +121,7 @@ void set_observer(region *r, faction *f, int skill, int turns)
attrib *a = a_find(r->attribs, &at_observer);
while (a && a->type == &at_observer) {
obs_data *od = (obs_data *)a->data.v;
if (od->f == f && od->skill < skill) {
if (od->f == f) {
od->skill = skill;
od->timer = turns;
return;

View File

@ -5203,22 +5203,21 @@ int sp_leaveastral(castorder * co)
case 1:
rt = pa->param[0]->data.r;
if (!rt || r_standard_to_astral(rt) != r || !inhabitable(rt)) {
ADDMSG(&mage->faction->msgs, msg_feedback(mage, co->order,
"spellfail::noway", ""));
cmistake(mage, co->order, 216, MSG_MAGIC);
return 0;
}
ro = r;
break;
default:
ADDMSG(&mage->faction->msgs, msg_feedback(mage, co->order,
"spell_astral_only", ""));
"spell_astral_only", NULL));
return 0;
}
if (ro == NULL || is_cursed(ro->attribs, &ct_astralblock)
|| is_cursed(rt->attribs, &ct_astralblock)) {
ADDMSG(&mage->faction->msgs, msg_feedback(mage, co->order,
"spellfail_astralblock", ""));
"spellfail_astralblock", NULL));
return 0;
}
@ -5423,13 +5422,10 @@ int sp_fetchastral(castorder * co)
return cast_level;
}
static bool cb_not_astral_blocked(const struct region *rt) {
return !is_cursed(rt->attribs, &ct_astralblock);
static bool cb_show_astral(const struct region *r) {
return r->units && !is_cursed(r->attribs, &ct_astralblock);
}
#undef SHOWASTRAL_IS_BORKED
#ifndef SHOWASTRAL_IS_BORKED
#define SHOWASTRAL_MAX_RADIUS 5
int sp_showastral(castorder * co)
{
region *rt;
@ -5440,29 +5436,24 @@ int sp_showastral(castorder * co)
int radius = (force < SHOWASTRAL_MAX_RADIUS) ? force : SHOWASTRAL_MAX_RADIUS;
region *targets[4 * SHOWASTRAL_MAX_RADIUS * SHOWASTRAL_MAX_RADIUS];
switch (getplaneid(r)) {
case 0:
rt = r_standard_to_astral(r);
if (!rt || fval(rt->terrain, FORBIDDEN_REGION)) {
/* Hier gibt es keine Verbindung zur astralen Welt */
cmistake(mage, co->order, 216, MSG_MAGIC);
if (getplaneid(r) == 1) {
ADDMSG(&mage->faction->msgs, msg_feedback(mage, co->order,
"spell_astral_forbidden", NULL));
return 0;
}
break;
case 1:
rt = r;
break;
default:
rt = r_standard_to_astral(r);
if (rt == NULL || fval(rt->terrain, FORBIDDEN_REGION) || is_cursed(r->attribs, &ct_astralblock)) {
/* Hier gibt es keine Verbindung zur astralen Welt */
cmistake(mage, co->order, 216, MSG_MAGIC);
return 0;
}
n = regions_in_range(rt, radius, cb_not_astral_blocked, targets);
n = regions_in_range(rt, radius, cb_show_astral, targets);
if (n == 0) {
/* sprintf(buf, "%s kann niemanden im astralen Nebel entdecken.",
unitname(mage)); */
cmistake(mage, co->order, 220, MSG_MAGIC);
return 0;
}
else {
int i;
@ -5470,43 +5461,52 @@ int sp_showastral(castorder * co)
region *rt = targets[i];
set_observer(rt, mage->faction, (int)(co->force / 2), 2);
}
ADDMSG(&mage->faction->msgs, msg_message("showastral_effect", "unit", mage));
}
return co->level;
}
#endif
/* ------------------------------------------------------------- */
static bool cb_view_reality(const struct region *r) {
return !is_cursed(r->attribs, &ct_astralblock);
}
int sp_viewreality(castorder * co)
{
region *r = co_get_region(co);
unit *mage = co_get_caster(co);
int force = (int)co->force;
message *m;
region *rl[MAX_SCHEMES];
int num;
if (getplaneid(r) != 1) {
/* sprintf(buf, "Dieser Zauber kann nur im Astralraum gezaubert werden."); */
ADDMSG(&mage->faction->msgs, msg_feedback(mage, co->order,
"spell_astral_only", ""));
"spell_astral_only", NULL));
return 0;
}
num = get_astralregions(r, NULL, rl);
if (is_cursed(r->attribs, &ct_astralblock)) {
cmistake(mage, co->order, 216, MSG_MAGIC);
return 0;
}
num = get_astralregions(r, cb_view_reality, rl);
if (num > 0) {
int i;
for (i = 0; i != num; ++i) {
region *rt = rl[i];
if (!is_cursed(rt->attribs, &ct_astralblock)) {
set_observer(rt, mage->faction, force / 2, 2);
}
}
else {
cmistake(mage, co->order, 216, MSG_MAGIC);
return 0;
}
m = msg_message("viewreality_effect", "unit", mage);
r_addmessage(r, mage->faction, m);
msg_release(m);
ADDMSG(&mage->faction->msgs, msg_message("viewreality_effect", "unit", mage));
return co->level;
}
@ -6421,9 +6421,7 @@ static spelldata spell_functions[] = {
{ "analyze_magic", sp_analysemagic, 0 },
{ "concealing_aura", sp_itemcloak, 0 },
{ "tybiedfumbleshield", sp_fumbleshield, 0 },
#ifndef SHOWASTRAL_IS_BORKED
{ "show_astral", sp_showastral, 0 },
#endif
{ "resist_magic", sp_resist_magic_bonus, 0 },
{ "keeploot", sp_keeploot, 0 },
{ "enterastral", sp_enterastral, 0 },

View File

@ -16,10 +16,11 @@ extern "C" {
void register_magicresistance(void);
void register_spells(void);
#define SHOWASTRAL_MAX_RADIUS 5
int sp_baddreams(struct castorder * co);
int sp_gooddreams(struct castorder * co);
int sp_viewreality(struct castorder * co);
int sp_showastral(struct castorder * co);
#define ACTION_RESET 0x01 /* reset the one-time-flag FFL_SELECT (on first pass) */
#define ACTION_CANSEE 0x02 /* to people who can see the actor */
#define ACTION_CANNOTSEE 0x04 /* to people who can not see the actor */

View File

@ -120,38 +120,147 @@ static void test_view_reality(CuTest *tc) {
faction *f;
unit *u;
castorder co;
curse *c;
test_setup();
mt_create_error(216);
mt_create_error(220);
mt_create_va(mt_new("spell_astral_only", NULL),
"unit:unit", "region:region", "command:order", MT_NEW_END);
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);
u = test_create_unit(f, rx);
/* can only cast in astral space */
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"));
free_castorder(&co);
test_clear_messagelist(&f->msgs);
ra = test_create_region(real2tp(0), real2tp(0), NULL);
ra->_plane = get_astralplane();
move_unit(u, ra, NULL);
/* there is no connection from ra to rx */
test_create_castorder(&co, u, 10, 10.0, 0, NULL);
CuAssertIntEquals(tc, 0, sp_viewreality(&co));
CuAssertPtrNotNull(tc, test_find_messagetype(f->msgs, "error216"));
CuAssertIntEquals(tc, -1, get_observer(rx, f));
free_castorder(&co);
test_clear_messagelist(&f->msgs);
r = test_create_region(0, 0, NULL);
test_clear_messagelist(&f->msgs);
/* units exist, r can be seen, but rx is out of range */
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"));
CuAssertPtrNotNull(tc, test_find_messagetype(f->msgs, "viewreality_effect"));
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);
set_observer(r, f, -1, -1);
CuAssertIntEquals(tc, -1, get_observer(r, f));
/* target region r exists, but astral space is blocked */
c = create_curse(NULL, &ra->attribs, &ct_astralblock, 50.0, 1, 50, 0);
test_create_castorder(&co, u, 10, 10.0, 0, NULL);
CuAssertIntEquals(tc, 0, sp_viewreality(&co));
CuAssertPtrNotNull(tc, test_find_messagetype(f->msgs, "error216"));
CuAssertIntEquals(tc, -1, get_observer(r, f));
free_castorder(&co);
remove_curse(&ra->attribs, c);
/* target region r exists, but astral interference is blocked */
c = create_curse(NULL, &r->attribs, &ct_astralblock, 50.0, 1, 50, 0);
test_create_castorder(&co, u, 10, 10.0, 0, NULL);
CuAssertIntEquals(tc, 0, sp_viewreality(&co));
CuAssertPtrNotNull(tc, test_find_messagetype(f->msgs, "error216"));
CuAssertIntEquals(tc, -1, get_observer(r, f));
free_castorder(&co);
test_teardown();
}
static void test_show_astral(CuTest *tc) {
region *r, *ra, *rx;
faction *f;
unit *u;
castorder co;
curse * c;
test_setup();
mt_create_error(216);
mt_create_error(220);
mt_create_va(mt_new("spell_astral_forbidden", NULL),
"unit:unit", "region:region", "command:order", MT_NEW_END);
mt_create_va(mt_new("showastral_effect", NULL),
"unit:unit", MT_NEW_END);
ra = test_create_region(real2tp(0), real2tp(0) + 1 + SHOWASTRAL_MAX_RADIUS, NULL);
ra->_plane = get_astralplane();
f = test_create_faction(NULL);
u = test_create_unit(f, ra);
/* error: unit is in astral space */
test_create_castorder(&co, u, 10, 10.0, 0, NULL);
CuAssertIntEquals(tc, 0, sp_showastral(&co));
CuAssertPtrNotNull(tc, test_find_messagetype(f->msgs, "spell_astral_forbidden"));
free_castorder(&co);
test_clear_messagelist(&f->msgs);
r = test_create_region(0, 0, NULL);
move_unit(u, r, NULL);
/* error: no target region */
test_create_castorder(&co, u, 9, 10.0, 0, NULL);
CuAssertIntEquals(tc, 0, sp_showastral(&co));
CuAssertPtrNotNull(tc, test_find_messagetype(f->msgs, "error216"));
CuAssertIntEquals(tc, -1, get_observer(ra, f));
free_castorder(&co);
rx = test_create_region(real2tp(r->x), real2tp(r->y), NULL);
rx->_plane = ra->_plane;
/* rx is in range, but empty */
test_create_castorder(&co, u, 9, 10.0, 0, NULL);
CuAssertIntEquals(tc, 0, sp_showastral(&co));
CuAssertIntEquals(tc, -1, get_observer(rx, f));
CuAssertIntEquals(tc, -1, get_observer(ra, f));
CuAssertPtrNotNull(tc, test_find_messagetype(f->msgs, "error220"));
CuAssertPtrEquals(tc, NULL, test_find_messagetype(f->msgs, "showastral_effect"));
free_castorder(&co);
test_create_unit(f, ra);
test_create_unit(f, rx);
/* rx is in range, but ra is not */
test_create_castorder(&co, u, 9, 10.0, 0, NULL);
CuAssertIntEquals(tc, 9, sp_showastral(&co));
CuAssertIntEquals(tc, 5, get_observer(rx, f));
CuAssertIntEquals(tc, -1, get_observer(ra, f));
CuAssertPtrNotNull(tc, test_find_messagetype(f->msgs, "showastral_effect"));
free_castorder(&co);
/* astral block on r */
c = create_curse(NULL, &r->attribs, &ct_astralblock, 50.0, 1, 50, 0);
test_create_castorder(&co, u, 9, 10.0, 0, NULL);
CuAssertIntEquals(tc, 0, sp_showastral(&co));
CuAssertPtrNotNull(tc, test_find_messagetype(f->msgs, "error216"));
free_castorder(&co);
remove_curse(&r->attribs, c);
/* astral block on rx */
c = create_curse(NULL, &rx->attribs, &ct_astralblock, 50.0, 1, 50, 0);
test_create_castorder(&co, u, 9, 10.0, 0, NULL);
CuAssertIntEquals(tc, 0, sp_showastral(&co));
CuAssertPtrNotNull(tc, test_find_messagetype(f->msgs, "error220"));
free_castorder(&co);
remove_curse(&rx->attribs, c);
test_teardown();
}
@ -176,6 +285,7 @@ CuSuite *get_spells_suite(void)
CuSuite *suite = CuSuiteNew();
SUITE_ADD_TEST(suite, test_watch_region);
SUITE_ADD_TEST(suite, test_view_reality);
SUITE_ADD_TEST(suite, test_show_astral);
SUITE_ADD_TEST(suite, test_good_dreams);
SUITE_ADD_TEST(suite, test_bad_dreams);
SUITE_ADD_TEST(suite, test_dreams);

View File

@ -318,10 +318,10 @@ static message *cinfo_skillmod(const void *obj, objtype_t typ, const curse * c,
unit *u = (unit *)obj;
int sk = c->data.i;
if (c->effect > 0) {
return msg_message("curseinfo::skill_1", "unit skill id", u, sk, c->no);
return msg_message("curseinfo_skill_1", "unit skill id", u, sk, c->no);
}
else if (c->effect < 0) {
return msg_message("curseinfo::skill_2", "unit skill id", u, sk, c->no);
return msg_message("curseinfo_skill_2", "unit skill id", u, sk, c->no);
}
}
return NULL;

View File

@ -22,7 +22,6 @@
#include <assert.h>
#define TE_CENTER 1000
#define TP_DISTANCE 4
int real2tp(int rk)
{

View File

@ -7,7 +7,8 @@
extern "C" {
#endif
#define TP_RADIUS 2 /* Radius von Schemen */
#define TP_DISTANCE 4
#define TP_RADIUS (TP_DISTANCE/2) /* Radius von Schemen */
#define MAX_SCHEMES ((TP_RADIUS * 2 + 1) * (TP_RADIUS * 2 + 1) - 4)
struct region;