Merge branch 'kill-rcspell' into feature/refactor-rcspell

Conflicts:
	src/kernel/config.h
	src/main.c
	src/report.c
	src/reports.c
	src/reports.test.c
	src/spells.c
This commit is contained in:
Enno Rehling 2017-05-21 21:33:29 +02:00
commit abb7c9fb17
13 changed files with 350 additions and 227 deletions

View File

@ -1636,11 +1636,51 @@ static castorder * create_castorder_combat(castorder *co, fighter *fig, const sp
return co; return co;
} }
#ifdef FFL_CURSED
static void summon_igjarjuk(battle *b, spellrank spellranks[]) {
side *s;
castorder *co;
for (s = b->sides; s != b->sides + b->nsides; ++s) {
fighter *fig = 0;
if (s->bf->attacker && fval(s->faction, FFL_CURSED)) {
spell *sp = find_spell("igjarjuk");
if (sp) {
int si;
for (si = 0; s->enemies[si]; ++si) {
side *se = s->enemies[si];
if (se && !fval(se->faction, FFL_NPC)) {
fighter *fi;
for (fi = se->fighters; fi; fi = fi->next) {
if (fi && (!fig || fig->unit->number > fi->unit->number)) {
fig = fi;
if (fig->unit->number == 1) {
break;
}
}
}
if (fig && fig->unit->number == 1) {
break;
}
}
}
if (fig) {
co = create_castorder_combat(0, fig, sp, 10, 10);
co->magician.fig = fig;
add_castorder(&spellranks[sp->rank], co);
break;
}
}
}
}
}
#endif
void do_combatmagic(battle * b, combatmagic_t was) void do_combatmagic(battle * b, combatmagic_t was)
{ {
side *s; side *s;
region *r = b->region;
castorder *co; castorder *co;
region *r = b->region;
int level, rank, sl; int level, rank, sl;
spellrank spellranks[MAX_SPELLRANK]; spellrank spellranks[MAX_SPELLRANK];
@ -1648,38 +1688,7 @@ void do_combatmagic(battle * b, combatmagic_t was)
#ifdef FFL_CURSED #ifdef FFL_CURSED
if (was == DO_PRECOMBATSPELL) { if (was == DO_PRECOMBATSPELL) {
for (s = b->sides; s != b->sides + b->nsides; ++s) { summon_igjarjuk(b, spellranks);
fighter *fig = 0;
if (s->bf->attacker && fval(s->faction, FFL_CURSED)) {
spell *sp = find_spell("igjarjuk");
if (sp) {
int si;
for (si = 0; s->enemies[si]; ++si) {
side *se = s->enemies[si];
if (se && !fval(se->faction, FFL_NPC)) {
fighter *fi;
for (fi = se->fighters; fi; fi = fi->next) {
if (fi && (!fig || fig->unit->number > fi->unit->number)) {
fig = fi;
if (fig->unit->number == 1) {
break;
}
}
}
if (fig && fig->unit->number == 1) {
break;
}
}
}
if (fig) {
co = create_castorder_combat(0, fig, sp, 10, 10);
co->magician.fig = fig;
add_castorder(&spellranks[sp->rank], co);
break;
}
}
}
}
} }
#endif #endif
for (s = b->sides; s != b->sides + b->nsides; ++s) { for (s = b->sides; s != b->sides + b->nsides; ++s) {

View File

@ -1418,7 +1418,7 @@ static void cr_output_region(FILE * F, report_context * ctx, region * r)
} }
cr_output_curses_compat(F, f, r, TYP_REGION); cr_output_curses_compat(F, f, r, TYP_REGION);
cr_borders(r, f, r->seen.mode, F); cr_borders(r, f, r->seen.mode, F);
if (r->seen.mode == seen_unit && is_astral(r) if (r->seen.mode >= seen_unit && is_astral(r)
&& !is_cursed(r->attribs, C_ASTRALBLOCK, 0)) { && !is_cursed(r->attribs, C_ASTRALBLOCK, 0)) {
/* Sonderbehandlung Teleport-Ebene */ /* Sonderbehandlung Teleport-Ebene */
region_list *rl = astralregions(r, inhabitable); region_list *rl = astralregions(r, inhabitable);
@ -1441,7 +1441,7 @@ static void cr_output_region(FILE * F, report_context * ctx, region * r)
} }
cr_output_travelthru(F, r, f); cr_output_travelthru(F, r, f);
if (r->seen.mode == seen_unit || r->seen.mode == seen_travel) { if (r->seen.mode >= seen_travel) {
message_list *mlist = r_getmessages(r, f); message_list *mlist = r_getmessages(r, f);
cr_output_messages(F, r->msgs, f); cr_output_messages(F, r->msgs, f);
if (mlist) { if (mlist) {

View File

@ -35,7 +35,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#define RF_MALLORN (1<<1) /* persistent */ #define RF_MALLORN (1<<1) /* persistent */
#define RF_BLOCKED (1<<2) /* persistent */ #define RF_BLOCKED (1<<2) /* persistent */
#define RF_UNUSED_3 (1<<3) #define RF_OBSERVER (1<<3) /* persistent */
#define RF_UNUSED_4 (1<<4) #define RF_UNUSED_4 (1<<4)
#define RF_UNUSED_5 (1<<5) #define RF_UNUSED_5 (1<<5)
#define RF_UNUSED_6 (1<<6) #define RF_UNUSED_6 (1<<6)

View File

@ -71,8 +71,8 @@ typedef enum {
seen_neighbour, seen_neighbour,
seen_lighthouse, seen_lighthouse,
seen_travel, seen_travel,
seen_far,
seen_unit, seen_unit,
seen_spell,
seen_battle seen_battle
} seen_mode; } seen_mode;

View File

@ -63,42 +63,21 @@ void update_lighthouse(building * lh)
} }
} }
int lighthouse_range(const building * b, const faction * f) int lighthouse_range(const building * b, const faction * f, const unit *u)
{ {
int d = 0;
if (fval(b, BLD_MAINTAINED) && b->size >= 10) { if (fval(b, BLD_MAINTAINED) && b->size >= 10) {
int maxd = (int)log10(b->size) + 1; int maxd = (int)log10(b->size) + 1;
if (skill_enabled(SK_PERCEPTION)) { if (u && skill_enabled(SK_PERCEPTION)) {
region *r = b->region; int sk = effskill(u, SK_PERCEPTION, 0) / 3;
int c = 0; assert(u->building == b);
int cap = buildingcapacity(b); assert(u->faction == f);
unit *u, *uown = building_owner(b); maxd = MIN(maxd, sk);
for (u = r->units; u; u = u->next) {
if (u->building == b || u == uown) {
c += u->number;
if (c > cap) {
break;
}
else if (f == NULL || u->faction == f) {
int sk = effskill(u, SK_PERCEPTION, 0) / 3;
d = MAX(d, sk);
d = MIN(maxd, d);
if (d == maxd)
break;
}
}
else if (c)
break; /* first unit that's no longer in the house ends the search */
}
}
else {
/* E3A rule: no perception req'd */
return maxd;
} }
/* E3A rule: no perception req'd */
return maxd;
} }
return d; return 0;
} }
bool check_leuchtturm(region * r, faction * f) bool check_leuchtturm(region * r, faction * f)

View File

@ -29,14 +29,15 @@ extern "C" {
struct faction; struct faction;
struct region; struct region;
struct building; struct building;
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 check_leuchtturm(struct region *r, struct faction *f);
void update_lighthouse(struct building *lh); void update_lighthouse(struct building *b);
int lighthouse_range(const struct building *b, int lighthouse_range(const struct building *b, const struct faction *f,
const struct faction *f); const struct unit *u);
#ifdef __cplusplus #ifdef __cplusplus

View File

@ -26,29 +26,29 @@ static void test_lighthouse_range(CuTest * tc)
u1 = test_create_unit(test_create_faction(0), r); u1 = test_create_unit(test_create_faction(0), r);
u2 = test_create_unit(test_create_faction(0), r); u2 = test_create_unit(test_create_faction(0), r);
b = test_create_building(r, test_create_buildingtype("lighthouse")); b = test_create_building(r, test_create_buildingtype("lighthouse"));
CuAssertIntEquals(tc, 0, lighthouse_range(b, NULL)); CuAssertIntEquals(tc, 0, lighthouse_range(b, NULL, NULL));
CuAssertIntEquals(tc, 0, lighthouse_range(b, u1->faction)); CuAssertIntEquals(tc, 0, lighthouse_range(b, u1->faction, NULL));
b->size = 10; b->size = 10;
CuAssertIntEquals(tc, 0, lighthouse_range(b, NULL)); CuAssertIntEquals(tc, 0, lighthouse_range(b, NULL, NULL));
u1->building = b; u1->building = b;
u2->building = b; u2->building = b;
u1->number = 10; u1->number = 10;
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)); CuAssertIntEquals(tc, 0, lighthouse_range(b, NULL, NULL));
b->flags |= BLD_MAINTAINED; b->flags |= BLD_MAINTAINED;
CuAssertIntEquals(tc, 1, lighthouse_range(b, NULL)); CuAssertIntEquals(tc, 1, lighthouse_range(b, u1->faction, u1));
set_level(u1, SK_PERCEPTION, 6); set_level(u1, SK_PERCEPTION, 6);
CuAssertIntEquals(tc, 2, lighthouse_range(b, u1->faction)); CuAssertIntEquals(tc, 2, lighthouse_range(b, u1->faction, u1));
CuAssertIntEquals(tc, 0, lighthouse_range(b, u2->faction)); /* lighthouse_range does not check inside_building */
CuAssertIntEquals(tc, 1, lighthouse_range(b, u2->faction, u2));
b->size = 100; b->size = 100;
update_lighthouse(b); update_lighthouse(b);
CuAssertIntEquals(tc, 2, lighthouse_range(b, NULL)); CuAssertIntEquals(tc, 3, lighthouse_range(b, NULL, NULL));
CuAssertIntEquals(tc, 2, lighthouse_range(b, u1->faction, u1));
set_level(u1, SK_PERCEPTION, 9); set_level(u1, SK_PERCEPTION, 9);
CuAssertIntEquals(tc, 3, lighthouse_range(b, NULL)); CuAssertIntEquals(tc, 3, lighthouse_range(b, u1->faction, u1));
CuAssertIntEquals(tc, 3, lighthouse_range(b, u1->faction)); CuAssertIntEquals(tc, 1, lighthouse_range(b, u2->faction, u2));
CuAssertIntEquals(tc, 1, lighthouse_range(b, u2->faction));
CuAssertIntEquals(tc, 0, lighthouse_range(b, test_create_faction(0)));
test_cleanup(); test_cleanup();
} }

View File

@ -997,7 +997,7 @@ void report_region(struct stream *out, const region * r, faction * f)
} }
/* iron & stone */ /* iron & stone */
if (r->seen.mode == seen_unit) { if (r->seen.mode >= seen_unit) {
resource_report result[MAX_RAWMATERIALS]; resource_report result[MAX_RAWMATERIALS];
int n, numresults = report_resources(r, result, MAX_RAWMATERIALS, f, true); int n, numresults = report_resources(r, result, MAX_RAWMATERIALS, f, true);
@ -1184,7 +1184,7 @@ void report_region(struct stream *out, const region * r, faction * f)
*bufp = 0; *bufp = 0;
paragraph(out, buf, 0, 0, 0); paragraph(out, buf, 0, 0, 0);
if (r->seen.mode == seen_unit && is_astral(r) && if (r->seen.mode >= seen_unit && is_astral(r) &&
!is_cursed(r->attribs, C_ASTRALBLOCK, 0)) { !is_cursed(r->attribs, C_ASTRALBLOCK, 0)) {
/* Sonderbehandlung Teleport-Ebene */ /* Sonderbehandlung Teleport-Ebene */
region_list *rl = astralregions(r, inhabitable); region_list *rl = astralregions(r, inhabitable);
@ -2272,7 +2272,7 @@ report_plaintext(const char *filename, report_context * ctx,
continue; continue;
/* Beschreibung */ /* Beschreibung */
if (r->seen.mode == seen_unit) { if (r->seen.mode >= seen_unit) {
anyunits = 1; anyunits = 1;
newline(out); newline(out);
report_region(out, r, f); report_region(out, r, f);
@ -2305,24 +2305,13 @@ report_plaintext(const char *filename, report_context * ctx,
report_travelthru(out, r, f); report_travelthru(out, r, f);
} }
else { else {
if (r->seen.mode == seen_far) { report_region(out, r, f);
newline(out); newline(out);
report_region(out, r, f); report_travelthru(out, r, f);
newline(out);
guards(out, r, f);
newline(out);
report_travelthru(out, r, f);
}
else {
newline(out);
report_region(out, r, f);
newline(out);
report_travelthru(out, r, f);
}
} }
/* Statistik */ /* Statistik */
if (wants_stats && r->seen.mode == seen_unit) if (wants_stats && r->seen.mode >= seen_unit)
statistics(out, r, f); statistics(out, r, f);
/* Nachrichten an REGION in der Region */ /* Nachrichten an REGION in der Region */

View File

@ -21,6 +21,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#include "reports.h" #include "reports.h"
#include "guard.h" #include "guard.h"
#include "laws.h" #include "laws.h"
#include "spells.h"
#include "travelthru.h" #include "travelthru.h"
#include "lighthouse.h" #include "lighthouse.h"
#include "donations.h" #include "donations.h"
@ -93,6 +94,7 @@ const char *visibility[] = {
"travel", "travel",
"far", "far",
"unit", "unit",
"spell",
"battle" "battle"
}; };
@ -966,9 +968,9 @@ const struct unit *ucansee(const struct faction *f, const struct unit *u,
int stealth_modifier(seen_mode mode) int stealth_modifier(seen_mode mode)
{ {
switch (mode) { switch (mode) {
case seen_spell:
case seen_unit: case seen_unit:
return 0; return 0;
case seen_far:
case seen_lighthouse: case seen_lighthouse:
return -2; return -2;
case seen_travel: case seen_travel:
@ -1422,29 +1424,42 @@ void prepare_report(report_context *ctx, faction *f)
ctx->last = lastregion(f); ctx->last = lastregion(f);
for (r = ctx->first; r!=ctx->last; r = r->next) { for (r = ctx->first; r!=ctx->last; r = r->next) {
int range = 0;
unit *u; unit *u;
if (fval(r, RF_LIGHTHOUSE) && bt_lighthouse) { int range = 0;
if (fval(r, RF_OBSERVER)) {
int skill = get_observer(r, f);
if (skill >= 0) {
add_seen_nb(f, r, seen_spell);
}
}
if (fval(r, RF_LIGHTHOUSE)) {
/* region owners get the report from lighthouses */
if (rule_region_owners && f == region_get_owner(r)) { if (rule_region_owners && f == region_get_owner(r)) {
/* region owners get the report from lighthouses */
building *b; building *b;
for (b = rbuildings(r); b; b = b->next) {
for (b = r->buildings; b; b = b->next) { if (b && b->type == bt_lighthouse) {
if (b->type == bt_lighthouse) { /* region owners get maximm range */
int br = lighthouse_range(b, NULL); int br = lighthouse_range(b, NULL, NULL);
if (br > range) range = br; if (br > range) range = br;
} }
} }
} }
} }
for (u = r->units; u; u = u->next) { for (u = r->units; u; u = u->next) {
/* if we have any unit in this region, then we get seen_unit access */
if (u->faction == f) { if (u->faction == f) {
add_seen_nb(f, r, seen_unit); add_seen_nb(f, r, seen_unit);
if (fval(r, RF_LIGHTHOUSE) && bt_lighthouse) { /* units inside the lighthouse get range based on their perception
if (u->building && u->building->type == bt_lighthouse && inside_building(u)) { * or the size, if perception is not a skill
int br = lighthouse_range(u->building, f); */
if (br > range) range = br; if (!fval(r, RF_LIGHTHOUSE)) {
} /* it's enough to mark the region once, and if there are
* no lighthouses, there is no need to look at more units */
break;
}
if (range == 0 && u->building && u->building->type == bt_lighthouse && inside_building(u)) {
int br = lighthouse_range(u->building, f, u);
if (br > range) range = br;
} }
} }
} }

View File

@ -6,6 +6,7 @@
#include "lighthouse.h" #include "lighthouse.h"
#include "travelthru.h" #include "travelthru.h"
#include "keyword.h" #include "keyword.h"
#include "spells.h"
#include <kernel/ally.h> #include <kernel/ally.h>
#include <kernel/config.h> #include <kernel/config.h>
@ -474,12 +475,11 @@ void test_prepare_lighthouse_capacity(CuTest *tc) {
u1->number = 4; u1->number = 4;
u1->building = b; u1->building = b;
set_level(u1, SK_PERCEPTION, 3); set_level(u1, SK_PERCEPTION, 3);
CuAssertIntEquals(tc, 1, lighthouse_range(b, u1->faction)); CuAssertIntEquals(tc, 1, lighthouse_range(b, u1->faction, u1));
CuAssertPtrEquals(tc, b, inside_building(u1)); CuAssertPtrEquals(tc, b, inside_building(u1));
u2 = test_create_unit(f, r1); u2 = test_create_unit(f, r1);
u2->building = b; u2->building = b;
set_level(u2, SK_PERCEPTION, 3); set_level(u2, SK_PERCEPTION, 3);
CuAssertIntEquals(tc, 0, lighthouse_range(b, u2->faction));
CuAssertPtrEquals(tc, NULL, inside_building(u2)); CuAssertPtrEquals(tc, NULL, inside_building(u2));
prepare_report(&ctx, u1->faction); prepare_report(&ctx, u1->faction);
CuAssertPtrEquals(tc, r1, ctx.first); CuAssertPtrEquals(tc, r1, ctx.first);
@ -532,7 +532,12 @@ static void test_prepare_lighthouse(CuTest *tc) {
test_cleanup(); test_cleanup();
} }
static void test_prepare_lighthouse_owners(CuTest *tc) { /**
* In E3, region owners get the view range benefit of
* any lighthouse in the region.
*/
static void test_prepare_lighthouse_owners(CuTest *tc)
{
report_context ctx; report_context ctx;
faction *f; faction *f;
region *r1, *r2, *r3; region *r1, *r2, *r3;
@ -558,8 +563,9 @@ static void test_prepare_lighthouse_owners(CuTest *tc) {
u = test_create_unit(f, r1); u = test_create_unit(f, r1);
u = test_create_unit(test_create_faction(0), r1); u = test_create_unit(test_create_faction(0), r1);
u->building = b; u->building = b;
set_level(u, SK_PERCEPTION, 3);
region_set_owner(b->region, f, 0); region_set_owner(b->region, f, 0);
set_level(u, SK_PERCEPTION, 3);
CuAssertIntEquals(tc, 2, lighthouse_range(b, f, NULL));
prepare_report(&ctx, f); prepare_report(&ctx, f);
CuAssertPtrEquals(tc, r1, ctx.first); CuAssertPtrEquals(tc, r1, ctx.first);
CuAssertPtrEquals(tc, NULL, ctx.last); CuAssertPtrEquals(tc, NULL, ctx.last);
@ -707,6 +713,30 @@ static void test_region_distance_ql(CuTest *tc) {
test_cleanup(); test_cleanup();
} }
static void test_report_far_vision(CuTest *tc) {
unit *u1;
faction *f;
region *r1, *r2;
const race *rc;
test_setup();
f = test_create_faction(0);
r1 = test_create_region(0, 0, 0);
u1 = test_create_unit(f, r1);
r2 = test_create_region(10, 0, 0);
rc = test_create_race("spell");
set_observer(r2, f, 10);
CuAssertPtrEquals(tc, r1, f->first);
CuAssertPtrEquals(tc, r2, f->last);
report_context ctx;
prepare_report(&ctx, f);
CuAssertPtrEquals(tc, r1, ctx.first);
CuAssertPtrEquals(tc, 0, ctx.last);
CuAssertIntEquals(tc, seen_unit, r1->seen.mode);
CuAssertIntEquals(tc, seen_spell, r2->seen.mode);
finish_reports(&ctx);
test_cleanup();
}
CuSuite *get_reports_suite(void) CuSuite *get_reports_suite(void)
{ {
CuSuite *suite = CuSuiteNew(); CuSuite *suite = CuSuiteNew();
@ -724,6 +754,7 @@ CuSuite *get_reports_suite(void)
SUITE_ADD_TEST(suite, test_get_addresses); SUITE_ADD_TEST(suite, test_get_addresses);
SUITE_ADD_TEST(suite, test_get_addresses_fstealth); SUITE_ADD_TEST(suite, test_get_addresses_fstealth);
SUITE_ADD_TEST(suite, test_get_addresses_travelthru); SUITE_ADD_TEST(suite, test_get_addresses_travelthru);
SUITE_ADD_TEST(suite, test_report_far_vision);
SUITE_ADD_TEST(suite, test_reorder_units); SUITE_ADD_TEST(suite, test_reorder_units);
SUITE_ADD_TEST(suite, test_seen_faction); SUITE_ADD_TEST(suite, test_seen_faction);
SUITE_ADD_TEST(suite, test_regionid); SUITE_ADD_TEST(suite, test_regionid);

View File

@ -437,40 +437,40 @@ report_effect(region * r, unit * mage, message * seen, message * unseen)
* *
*/ */
/* ------------------------------------------------------------- */ /* ------------------------------------------------------------- */
/* Name: Vertrauter /* Name: Vertrauter
* Stufe: 10 * Stufe: 10
* *
* Wirkung: * Wirkung:
* Der Magier beschwoert einen Vertrauten, ein kleines Tier, welches * Der Magier beschwoert einen Vertrauten, ein kleines Tier, welches
* dem Magier zu Diensten ist. Der Magier kann durch die Augen des * dem Magier zu Diensten ist. Der Magier kann durch die Augen des
* Vertrauten sehen, und durch den Vertrauten zaubern, allerdings nur * Vertrauten sehen, und durch den Vertrauten zaubern, allerdings nur
* mit seiner halben Stufe. Je nach Vertrautem erhaelt der Magier * mit seiner halben Stufe. Je nach Vertrautem erhaelt der Magier
* evtl diverse Skillmodifikationen. Der Typ des Vertrauten ist * evtl diverse Skillmodifikationen. Der Typ des Vertrauten ist
* zufaellig bestimmt, wird aber durch Magiegebiet und Rasse beeinflu<EFBFBD>t. * zufaellig bestimmt, wird aber durch Magiegebiet und Rasse beeinflußt.
* "Tierische" Vertraute brauchen keinen Unterhalt. * "Tierische" Vertraute brauchen keinen Unterhalt.
* *
* Ein paar Moeglichkeiten: * Ein paar Moeglichkeiten:
* Magieg. Rasse Besonderheiten * Magieg. Rasse Besonderheiten
* Eule Tybied -/- fliegt, Auraregeneration * Eule Tybied -/- fliegt, Auraregeneration
* Rabe Ilaun -/- fliegt * Rabe Ilaun -/- fliegt
* Imp Draig -/- Magieresistenz? * Imp Draig -/- Magieresistenz?
* Fuchs Gwyrrd -/- Wahrnehmung * Fuchs Gwyrrd -/- Wahrnehmung
* ???? Cerddor -/- ???? (Singvogel?, Papagei?) * ???? Cerddor -/- ???? (Singvogel?, Papagei?)
* Adler -/- -/- fliegt, +Wahrnehmung, =^=Adlerauge-Spruch? * Adler -/- -/- fliegt, +Wahrnehmung, =^=Adlerauge-Spruch?
* Kraehe -/- -/- fliegt, +Tarnung (weil unauffaellig) * Kraehe -/- -/- fliegt, +Tarnung (weil unauffaellig)
* Delphin -/- Meerm. schwimmt * Delphin -/- Meerm. schwimmt
* Wolf -/- Ork * Wolf -/- Ork
* Hund -/- Mensch kann evtl BEWACHE ausfuehren * Hund -/- Mensch kann evtl BEWACHE ausfuehren
* Ratte -/- Goblin * Ratte -/- Goblin
* Albatros -/- -/- fliegt, kann auf Ozean "landen" * Albatros -/- -/- fliegt, kann auf Ozean "landen"
* Affe -/- -/- kann evtl BEKLAUE ausfuehren * Affe -/- -/- kann evtl BEKLAUE ausfuehren
* Goblin -/- !Goblin normale Einheit * Goblin -/- !Goblin normale Einheit
* Katze -/- !Katze normale Einheit * Katze -/- !Katze normale Einheit
* Daemon -/- !Daemon normale Einheit * Daemon -/- !Daemon normale Einheit
* *
* Spezielle V. fuer Katzen, Trolle, Elfen, Daemonen, Insekten, Zwerge? * Spezielle V. fuer Katzen, Trolle, Elfen, Daemonen, Insekten, Zwerge?
*/ */
static const race *select_familiar(const race * magerace, magic_t magiegebiet) static const race *select_familiar(const race * magerace, magic_t magiegebiet)
{ {
@ -606,7 +606,7 @@ static int sp_summon_familiar(castorder * co)
if (dh == 0) { if (dh == 0) {
bytes = bytes =
strlcpy(bufp, (const char *)LOC(mage->faction->locale, strlcpy(bufp, (const char *)LOC(mage->faction->locale,
"list_and"), size); "list_and"), size);
} }
else { else {
bytes = strlcpy(bufp, (const char *)", ", size); bytes = strlcpy(bufp, (const char *)", ", size);
@ -617,7 +617,7 @@ static int sp_summon_familiar(castorder * co)
} }
bytes = bytes =
strlcpy(bufp, (const char *)skillname((skill_t)sk, mage->faction->locale), strlcpy(bufp, (const char *)skillname((skill_t)sk, mage->faction->locale),
size); size);
assert(bytes <= INT_MAX); assert(bytes <= INT_MAX);
if (wrptr(&bufp, &size, (int)bytes) != 0) if (wrptr(&bufp, &size, (int)bytes) != 0)
WARN_STATIC_BUFFER(); WARN_STATIC_BUFFER();
@ -1249,7 +1249,7 @@ static void fumble_ents(const castorder * co)
* Flag: * Flag:
* (FARCASTING | SPELLLEVEL | UNITSPELL | TESTCANSEE | TESTRESISTANCE) * (FARCASTING | SPELLLEVEL | UNITSPELL | TESTCANSEE | TESTRESISTANCE)
*/ */
/* Syntax: ZAUBER [REGION x y] [STUFE 2] "Rosthauch" 1111 2222 3333 */ /* Syntax: ZAUBER [REGION x y] [STUFE 2] "Rosthauch" 1111 2222 3333 */
typedef struct iron_weapon { typedef struct iron_weapon {
const struct item_type *type; const struct item_type *type;
@ -1262,7 +1262,7 @@ static iron_weapon *ironweapons = NULL;
void void
add_ironweapon(const struct item_type *type, const struct item_type *rusty, add_ironweapon(const struct item_type *type, const struct item_type *rusty,
float chance) float chance)
{ {
iron_weapon *iweapon = malloc(sizeof(iron_weapon)); iron_weapon *iweapon = malloc(sizeof(iron_weapon));
assert_alloc(iweapon); assert_alloc(iweapon);
@ -1369,7 +1369,7 @@ static int sp_rosthauch(castorder * co)
* Flag: * Flag:
* (UNITSPELL | SPELLLEVEL | ONSHIPCAST | TESTCANSEE) * (UNITSPELL | SPELLLEVEL | ONSHIPCAST | TESTCANSEE)
*/ */
/* Syntax: ZAUBER [STUFE n] "Kaelteschutz" eh1 [eh2 [eh3 [...]]] */ /* Syntax: ZAUBER [STUFE n] "Kaelteschutz" eh1 [eh2 [eh3 [...]]] */
static int sp_kaelteschutz(castorder * co) static int sp_kaelteschutz(castorder * co)
{ {
@ -1413,7 +1413,7 @@ static int sp_kaelteschutz(castorder * co)
u)); u));
if (u->faction != mage->faction) if (u->faction != mage->faction)
ADDMSG(&u->faction->msgs, msg_message("heat_effect", "mage target", ADDMSG(&u->faction->msgs, msg_message("heat_effect", "mage target",
cansee(u->faction, r, mage, 0) ? mage : NULL, u)); cansee(u->faction, r, mage, 0) ? mage : NULL, u));
i = cast_level; i = cast_level;
} }
/* Erstattung? */ /* Erstattung? */
@ -1433,7 +1433,7 @@ static int sp_kaelteschutz(castorder * co)
* Flag: * Flag:
* (UNITSPELL | TESTCANSEE | SPELLLEVEL) * (UNITSPELL | TESTCANSEE | SPELLLEVEL)
*/ */
/* Syntax: ZAUBER "Funkenregen" eh1 */ /* Syntax: ZAUBER "Funkenregen" eh1 */
static int sp_sparkle(castorder * co) static int sp_sparkle(castorder * co)
{ {
@ -1532,8 +1532,8 @@ static int sp_create_irongolem(castorder * co)
ADDMSG(&mage->faction->msgs, ADDMSG(&mage->faction->msgs,
msg_message("magiccreate_effect", "region command unit amount object", msg_message("magiccreate_effect", "region command unit amount object",
mage->region, co->order, mage, number, mage->region, co->order, mage, number,
LOC(mage->faction->locale, rc_name_s(golem_rc, (u2->number == 1) ? NAME_SINGULAR : NAME_PLURAL)))); LOC(mage->faction->locale, rc_name_s(golem_rc, (u2->number == 1) ? NAME_SINGULAR : NAME_PLURAL))));
return cast_level; return cast_level;
} }
@ -1599,8 +1599,8 @@ static int sp_create_stonegolem(castorder * co)
ADDMSG(&mage->faction->msgs, ADDMSG(&mage->faction->msgs,
msg_message("magiccreate_effect", "region command unit amount object", msg_message("magiccreate_effect", "region command unit amount object",
mage->region, co->order, mage, number, mage->region, co->order, mage, number,
LOC(mage->faction->locale, rc_name_s(golem_rc, (u2->number == 1) ? NAME_SINGULAR : NAME_PLURAL)))); LOC(mage->faction->locale, rc_name_s(golem_rc, (u2->number == 1) ? NAME_SINGULAR : NAME_PLURAL))));
return cast_level; return cast_level;
} }
@ -2206,17 +2206,17 @@ static int sp_ironkeeper(castorder * co)
fset(keeper, UFL_ANON_FACTION); fset(keeper, UFL_ANON_FACTION);
} }
{ {
trigger *tkill = trigger_killunit(keeper); trigger *tkill = trigger_killunit(keeper);
add_trigger(&keeper->attribs, "timer", trigger_timeout(cast_level + 2, add_trigger(&keeper->attribs, "timer", trigger_timeout(cast_level + 2,
tkill)); tkill));
} }
msg = msg_message("summon_effect", "mage amount race", mage, 1, u_race(keeper)); msg = msg_message("summon_effect", "mage amount race", mage, 1, u_race(keeper));
r_addmessage(r, NULL, msg); r_addmessage(r, NULL, msg);
msg_release(msg); msg_release(msg);
return cast_level; return cast_level;
} }
/* ------------------------------------------------------------- */ /* ------------------------------------------------------------- */
@ -2387,7 +2387,7 @@ void patzer_peasantmob(const castorder * co)
u = u =
create_unit(r, f, n, get_race(RC_PEASANT), 0, LOC(f->locale, "angry_mob"), create_unit(r, f, n, get_race(RC_PEASANT), 0, LOC(f->locale, "angry_mob"),
NULL); NULL);
fset(u, UFL_ISNEW); fset(u, UFL_ISNEW);
addlist(&u->orders, create_order(K_GUARD, lang, NULL)); addlist(&u->orders, create_order(K_GUARD, lang, NULL));
set_order(&u->thisorder, default_order(lang)); set_order(&u->thisorder, default_order(lang));
@ -2459,7 +2459,7 @@ static int sp_forest_fire(castorder * co)
freset(u->faction, FFL_SELECT); freset(u->faction, FFL_SELECT);
msg = msg =
msg_message("forestfire_effect", "mage region amount", mage, r, msg_message("forestfire_effect", "mage region amount", mage, r,
destroyed + vernichtet_schoesslinge); destroyed + vernichtet_schoesslinge);
r_addmessage(r, NULL, msg); r_addmessage(r, NULL, msg);
add_message(&mage->faction->msgs, msg); add_message(&mage->faction->msgs, msg);
msg_release(msg); msg_release(msg);
@ -2629,10 +2629,10 @@ static int sp_summondragon(castorder * co)
number = 6; number = 6;
break; break;
} }
{ {
trigger *tsummon = trigger_createunit(r, f, race, number); trigger *tsummon = trigger_createunit(r, f, race, number);
add_trigger(&r->attribs, "timer", trigger_timeout(time, tsummon)); add_trigger(&r->attribs, "timer", trigger_timeout(time, tsummon));
} }
} }
} }
@ -2707,15 +2707,15 @@ static int sp_firewall(castorder * co)
} }
/* melden, 1x pro Partei */ /* melden, 1x pro Partei */
{ {
message *seen = msg_message("firewall_effect", "mage region", mage, r); message *seen = msg_message("firewall_effect", "mage region", mage, r);
message *unseen = msg_message("firewall_effect", "mage region", NULL, r); message *unseen = msg_message("firewall_effect", "mage region", NULL, r);
report_effect(r, mage, seen, unseen); report_effect(r, mage, seen, unseen);
msg_release(seen); msg_release(seen);
msg_release(unseen); msg_release(unseen);
} }
return cast_level; return cast_level;
} }
/* ------------------------------------------------------------- */ /* ------------------------------------------------------------- */
@ -2866,7 +2866,7 @@ static int dc_age(struct curse *c)
damage /= dmg.sa[1]; damage /= dmg.sa[1];
hp = change_hitpoints(u, -(int)damage); hp = change_hitpoints(u, -(int)damage);
ADDMSG(&u->faction->msgs, msg_message((hp>0)?"poison_damage":"poison_death", "region unit", r, u)); ADDMSG(&u->faction->msgs, msg_message((hp > 0) ? "poison_damage" : "poison_death", "region unit", r, u));
if (*up == u) if (*up == u)
up = &u->next; up = &u->next;
} }
@ -2923,7 +2923,7 @@ static int dc_read_compat(struct attrib *a, void *target, gamedata *data)
effect = strength; effect = strength;
c = c =
create_curse(u, &r->attribs, &ct_deathcloud, strength * 2, duration, create_curse(u, &r->attribs, &ct_deathcloud, strength * 2, duration,
effect, 0); effect, 0);
c->data.v = r; c->data.v = r;
if (u == NULL) { if (u == NULL) {
ur_add(var, &c->magician, resolve_unit); ur_add(var, &c->magician, resolve_unit);
@ -3321,7 +3321,7 @@ static int sp_bloodsacrifice(castorder * co)
change_spellpoints(mage, aura); change_spellpoints(mage, aura);
ADDMSG(&mage->faction->msgs, ADDMSG(&mage->faction->msgs,
msg_message("sp_bloodsacrifice_effect", msg_message("sp_bloodsacrifice_effect",
"unit region command amount", mage, mage->region, co->order, aura)); "unit region command amount", mage, mage->region, co->order, aura));
return cast_level; return cast_level;
} }
@ -3815,7 +3815,7 @@ static int sp_raisepeasantmob(castorder * co)
u = u =
create_unit(r, monsters, n, get_race(RC_PEASANT), 0, LOC(monsters->locale, create_unit(r, monsters, n, get_race(RC_PEASANT), 0, LOC(monsters->locale,
"furious_mob"), NULL); "furious_mob"), NULL);
fset(u, UFL_ISNEW); fset(u, UFL_ISNEW);
setguard(u, true); setguard(u, true);
a = a_new(&at_unitdissolve); a = a_new(&at_unitdissolve);
@ -4115,6 +4115,94 @@ static int sp_bigrecruit(castorder * co)
return cast_level; return cast_level;
} }
typedef struct obs_data {
faction *f;
int skill;
int timer;
} obs_data;
static void obs_init(struct attrib *a)
{
a->data.v = malloc(sizeof(obs_data));
}
static void obs_done(struct attrib *a)
{
free(a->data.v);
}
static int obs_age(struct attrib *a, void *owner)
{
obs_data *od = (obs_data *)a->data.v;
update_interval(od->f, (region *)owner);
return --od->timer;
}
static void obs_write(const struct attrib *a, const void *owner, struct storage *store)
{
obs_data *od = (obs_data *)a->data.v;
write_faction_reference(od->f, store);
WRITE_INT(store, od->skill);
WRITE_INT(store, od->timer);
}
static int obs_read(struct attrib *a, void *owner, struct gamedata *data)
{
obs_data *od = (obs_data *)a->data.v;
read_reference(&od->f, data, read_faction_reference, resolve_faction);
READ_INT(data->store, &od->skill);
READ_INT(data->store, &od->timer);
return AT_READ_OK;
}
attrib_type at_observer = { "observer", obs_init, obs_done, obs_age, obs_write, obs_read };
static attrib *make_observer(faction *f, int perception)
{
attrib * a = a_new(&at_observer);
obs_data *od = (obs_data *)a->data.v;
od->f = f;
od->skill = perception;
od->timer = 2;
return a;
}
int get_observer(region *r, faction *f) {
if (fval(r, RF_OBSERVER)) {
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) {
return od->skill;
}
a = a->next;
}
}
return -1;
}
void set_observer(region *r, faction *f, int skill)
{
update_interval(f, r);
if (fval(r, RF_OBSERVER)) {
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) {
od->skill = skill;
od->timer = 2;
return;
}
a = a->nexttype;
}
}
else {
fset(r, RF_OBSERVER);
}
a_add(&r->attribs, make_observer(f, skill));
}
/* ------------------------------------------------------------- */ /* ------------------------------------------------------------- */
/* Name: Aushorchen /* Name: Aushorchen
* Stufe: 7 * Stufe: 7
@ -4128,7 +4216,7 @@ static int sp_bigrecruit(castorder * co)
* (UNITSPELL | TESTCANSEE) * (UNITSPELL | TESTCANSEE)
*/ */
/* restistenz der einheit pruefen */ /* restistenz der einheit pruefen */
static int sp_pump(castorder * co) static int sp_pump(castorder * co)
{ {
unit *u, *target; unit *u, *target;
@ -4171,12 +4259,7 @@ static int sp_pump(castorder * co)
return cast_level / 2; return cast_level / 2;
} }
u = set_observer(rt, mage->faction, effskill(target, SK_PERCEPTION, 0));
create_unit(rt, mage->faction, 1, get_race(RC_SPELL), 0,
"spell/pump", NULL);
u->age = 2;
set_level(u, SK_PERCEPTION, effskill(target, SK_PERCEPTION, 0));
return cast_level; return cast_level;
} }
@ -4400,7 +4483,7 @@ static int sp_raisepeasants(castorder * co)
u2 = u2 =
create_unit(r, mage->faction, bauern, get_race(RC_PEASANT), 0, create_unit(r, mage->faction, bauern, get_race(RC_PEASANT), 0,
LOC(mage->faction->locale, "furious_mob"), mage); LOC(mage->faction->locale, "furious_mob"), mage);
fset(u2, UFL_LOCKED); fset(u2, UFL_LOCKED);
if (rule_stealth_anon()) { if (rule_stealth_anon()) {
@ -4414,7 +4497,7 @@ static int sp_raisepeasants(castorder * co)
msg = msg =
msg_message("sp_raisepeasants_effect", "mage region amount", mage, r, msg_message("sp_raisepeasants_effect", "mage region amount", mage, r,
u2->number); u2->number);
r_addmessage(r, NULL, msg); r_addmessage(r, NULL, msg);
if (mage->region != r) { if (mage->region != r) {
add_message(&mage->faction->msgs, msg); add_message(&mage->faction->msgs, msg);
@ -4527,7 +4610,7 @@ int sp_icastle(castorder * co)
if (type == bt_illusion) { if (type == bt_illusion) {
b->size = (rng_int() % (int)((power * power) + 1) * 10); b->size = (rng_int() % (int)((power * power) + 1) * 10);
} }
else if (type->maxsize >0) { else if (type->maxsize > 0) {
b->size = type->maxsize; b->size = type->maxsize;
} }
else { else {
@ -4760,7 +4843,7 @@ int sp_clonecopy(castorder * co)
"clone_of"), unitname(mage)); "clone_of"), unitname(mage));
clone = clone =
create_unit(target_region, mage->faction, 1, get_race(RC_CLONE), 0, name, create_unit(target_region, mage->faction, 1, get_race(RC_CLONE), 0, name,
mage); mage);
setstatus(clone, ST_FLEE); setstatus(clone, ST_FLEE);
fset(clone, UFL_LOCKED); fset(clone, UFL_LOCKED);
@ -4776,7 +4859,7 @@ int sp_clonecopy(castorder * co)
/* ------------------------------------------------------------- */ /* ------------------------------------------------------------- */
int sp_dreamreading(castorder * co) int sp_dreamreading(castorder * co)
{ {
unit *u, *u2; unit *u;
region *r = co_get_region(co); region *r = co_get_region(co);
unit *mage = co->magician.u; unit *mage = co->magician.u;
int cast_level = co->level; int cast_level = co->level;
@ -4809,16 +4892,11 @@ int sp_dreamreading(castorder * co)
return 0; return 0;
} }
u2 = set_observer(u->region, mage->faction, effskill(u, SK_PERCEPTION, u->region));
create_unit(u->region, mage->faction, 1, get_race(RC_SPELL), 0,
"spell/dreamreading", NULL);
set_number(u2, 1);
u2->age = 2; /* Nur fuer diese Runde. */
set_level(u2, SK_PERCEPTION, effskill(u, SK_PERCEPTION, u2->region));
msg = msg =
msg_message("sp_dreamreading_effect", "mage unit region", mage, u, msg_message("sp_dreamreading_effect", "mage unit region", mage, u,
u->region); u->region);
r_addmessage(r, mage->faction, msg); r_addmessage(r, mage->faction, msg);
msg_release(msg); msg_release(msg);
return cast_level; return cast_level;
@ -5609,7 +5687,7 @@ int sp_showastral(castorder * co)
region *r2 = rl2->data; region *r2 = rl2->data;
if (!is_cursed(r2->attribs, C_ASTRALBLOCK, 0)) { if (!is_cursed(r2->attribs, C_ASTRALBLOCK, 0)) {
for (u = r2->units; u; u = u->next) { for (u = r2->units; u; u = u->next) {
if (u_race(u) != get_race(RC_SPECIAL) && u_race(u) != get_race(RC_SPELL)) if (u_race(u) != get_race(RC_SPELL))
n++; n++;
} }
} }
@ -5619,7 +5697,8 @@ int sp_showastral(castorder * co)
/* sprintf(buf, "%s kann niemanden im astralen Nebel entdecken.", /* sprintf(buf, "%s kann niemanden im astralen Nebel entdecken.",
unitname(mage)); */ unitname(mage)); */
cmistake(mage, co->order, 220, MSG_MAGIC); cmistake(mage, co->order, 220, MSG_MAGIC);
} else { }
else {
/* Ausgeben */ /* Ausgeben */
@ -5629,7 +5708,7 @@ int sp_showastral(castorder * co)
for (rl2 = rl; rl2; rl2 = rl2->next) { for (rl2 = rl; rl2; rl2 = rl2->next) {
if (!is_cursed(rl2->data->attribs, C_ASTRALBLOCK, 0)) { if (!is_cursed(rl2->data->attribs, C_ASTRALBLOCK, 0)) {
for (u = rl2->data->units; u; u = u->next) { for (u = rl2->data->units; u; u = u->next) {
if (u_race(u) != get_race(RC_SPECIAL) && u_race(u) != get_race(RC_SPELL)) { if (u_race(u) != get_race(RC_SPELL)) {
c++; c++;
scat(unitname(u)); scat(unitname(u));
scat(" ("); scat(" (");
@ -5639,13 +5718,14 @@ int sp_showastral(castorder * co)
} }
icat(u->number); icat(u->number);
scat(" "); scat(" ");
scat(LOC(mage->faction->locale, rc_name_s(u_race(u), (u->number==1) ? NAME_SINGULAR:NAME_PLURAL))); scat(LOC(mage->faction->locale, rc_name_s(u_race(u), (u->number == 1) ? NAME_SINGULAR : NAME_PLURAL)));
scat(", Entfernung "); scat(", Entfernung ");
icat(distance(rl2->data, rt)); icat(distance(rl2->data, rt));
scat(")"); scat(")");
if (c == n - 1) { if (c == n - 1) {
scat(" und "); scat(" und ");
} else if (c < n - 1) { }
else if (c < n - 1) {
scat(", "); scat(", ");
} }
} }
@ -5667,7 +5747,6 @@ int sp_showastral(castorder * co)
int sp_viewreality(castorder * co) int sp_viewreality(castorder * co)
{ {
region_list *rl, *rl2; region_list *rl, *rl2;
unit *u;
region *r = co_get_region(co); region *r = co_get_region(co);
unit *mage = co->magician.u; unit *mage = co->magician.u;
int cast_level = co->level; int cast_level = co->level;
@ -5686,11 +5765,7 @@ int sp_viewreality(castorder * co)
for (rl2 = rl; rl2; rl2 = rl2->next) { for (rl2 = rl; rl2; rl2 = rl2->next) {
region *rt = rl2->data; region *rt = rl2->data;
if (!is_cursed(rt->attribs, C_ASTRALBLOCK, 0)) { if (!is_cursed(rt->attribs, C_ASTRALBLOCK, 0)) {
u = set_observer(rt, mage->faction, co->level / 2);
create_unit(rt, mage->faction, 1, get_race(RC_SPELL), 0,
"spell/viewreality", NULL);
set_level(u, SK_PERCEPTION, co->level / 2);
u->age = 2;
} }
} }
@ -6264,8 +6339,8 @@ int sp_speed2(castorder * co)
* Flags: * Flags:
* (FARCASTING | SPELLLEVEL | ONSHIPCAST | TESTCANSEE) * (FARCASTING | SPELLLEVEL | ONSHIPCAST | TESTCANSEE)
*/ */
/* Jeder gebrochene Zauber verbraucht c->vigour an Zauberkraft /* Jeder gebrochene Zauber verbraucht c->vigour an Zauberkraft
* (force) */ * (force) */
int sp_q_antimagie(castorder * co) int sp_q_antimagie(castorder * co)
{ {
attrib **ap; attrib **ap;
@ -6413,7 +6488,7 @@ int sp_break_curse(castorder * co)
/* Es wurde kein Ziel gefunden */ /* Es wurde kein Ziel gefunden */
ADDMSG(&mage->faction->msgs, ADDMSG(&mage->faction->msgs,
msg_message("spelltargetnotfound", "unit region command", msg_message("spelltargetnotfound", "unit region command",
mage, mage->region, co->order)); mage, mage->region, co->order));
} }
/* curse aufloesen, wenn zauber staerker (force > vigour) */ /* curse aufloesen, wenn zauber staerker (force > vigour) */

View File

@ -25,11 +25,15 @@ extern "C" {
struct ship; struct ship;
struct curse; struct curse;
struct unit; struct unit;
struct faction;
struct region;
struct message; struct message;
void register_magicresistance(void); void register_magicresistance(void);
void register_spells(void); void register_spells(void);
void set_spelldata(struct spell *sp);
void set_observer(struct region *r, struct faction *f, int perception);
int get_observer(struct region *r, struct faction *f);
int sp_baddreams(castorder * co); int sp_baddreams(castorder * co);
int sp_gooddreams(castorder * co); int sp_gooddreams(castorder * co);

View File

@ -3,6 +3,7 @@
#include <kernel/curse.h> #include <kernel/curse.h>
#include <kernel/faction.h> #include <kernel/faction.h>
#include <kernel/order.h> #include <kernel/order.h>
#include <kernel/race.h>
#include <kernel/region.h> #include <kernel/region.h>
#include <kernel/spell.h> #include <kernel/spell.h>
#include <kernel/unit.h> #include <kernel/unit.h>
@ -108,9 +109,28 @@ static void test_bad_dreams(CuTest *tc) {
test_cleanup(); test_cleanup();
} }
static void test_watch_region(CuTest *tc) {
region *r;
faction *f;
test_setup();
test_create_race("spell");
CuAssertPtrNotNull(tc, get_race(RC_SPELL));
r = test_create_region(0, 0, 0);
f = test_create_faction(0);
CuAssertIntEquals(tc, -1, get_observer(r, f));
set_observer(r, f, 0);
CuAssertIntEquals(tc, 0, get_observer(r, f));
set_observer(r, f, 10);
CuAssertIntEquals(tc, 10, get_observer(r, f));
CuAssertIntEquals(tc, RF_OBSERVER, fval(r, RF_OBSERVER));
CuAssertPtrNotNull(tc, r->attribs);
test_cleanup();
}
CuSuite *get_spells_suite(void) CuSuite *get_spells_suite(void)
{ {
CuSuite *suite = CuSuiteNew(); CuSuite *suite = CuSuiteNew();
SUITE_ADD_TEST(suite, test_watch_region);
SUITE_ADD_TEST(suite, test_good_dreams); SUITE_ADD_TEST(suite, test_good_dreams);
SUITE_ADD_TEST(suite, test_bad_dreams); SUITE_ADD_TEST(suite, test_bad_dreams);
SUITE_ADD_TEST(suite, test_dreams); SUITE_ADD_TEST(suite, test_dreams);