Add a new attribute and RF_OBSERVER flag.

This commit is contained in:
Enno Rehling 2016-09-25 13:01:51 +02:00
parent 4353773c3b
commit 15702daf99
9 changed files with 226 additions and 124 deletions

View File

@ -1404,7 +1404,7 @@ static void cr_output_region(FILE * F, report_context * ctx, region * r)
}
cr_output_curses_compat(F, f, r, TYP_REGION);
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)) {
/* Sonderbehandlung Teleport-Ebene */
region_list *rl = astralregions(r, inhabitable);
@ -1427,7 +1427,7 @@ static void cr_output_region(FILE * F, report_context * ctx, region * r)
}
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);
cr_output_messages(F, r->msgs, f);
if (mlist) {

View File

@ -34,7 +34,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#define RF_MALLORN (1<<1) /* 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_5 (1<<5)
#define RF_UNUSED_6 (1<<6)

View File

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

View File

@ -992,7 +992,7 @@ static void describe(stream *out, const region * r, faction * f)
}
/* iron & stone */
if (r->seen.mode == seen_unit) {
if (r->seen.mode >= seen_unit) {
resource_report result[MAX_RAWMATERIALS];
int n, numresults = report_resources(r, result, MAX_RAWMATERIALS, f, true);
@ -1190,7 +1190,7 @@ static void describe(stream *out, const region * r, faction * f)
*bufp = 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)) {
/* Sonderbehandlung Teleport-Ebene */
region_list *rl = astralregions(r, inhabitable);
@ -2285,7 +2285,7 @@ report_plaintext(const char *filename, report_context * ctx,
continue;
/* Beschreibung */
if (r->seen.mode == seen_unit) {
if (r->seen.mode >= seen_unit) {
anyunits = 1;
describe(out, r, f);
if (markets_module() && r->land) {
@ -2316,28 +2316,19 @@ report_plaintext(const char *filename, report_context * ctx,
newline(out);
write_travelthru(out, r, f);
}
else {
if (r->seen.mode == seen_far) {
describe(out, r, f);
newline(out);
guards(out, r, f);
newline(out);
write_travelthru(out, r, f);
}
else {
describe(out, r, f);
newline(out);
write_travelthru(out, r, f);
}
}
/* Statistik */
if (wants_stats && r->seen.mode == seen_unit)
if (wants_stats && r->seen.mode >= seen_unit)
statistics(out, r, f);
/* Nachrichten an REGION in der Region */
if (r->seen.mode == seen_unit || r->seen.mode == seen_travel) {
if (r->seen.mode >= seen_travel) {
// TODO: Bug 2073
message_list *mlist = r_getmessages(r, f);
if (mlist) {

View File

@ -20,6 +20,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#include <kernel/config.h>
#include "reports.h"
#include "laws.h"
#include "spells.h"
#include "travelthru.h"
#include "lighthouse.h"
#include "donations.h"
@ -92,6 +93,7 @@ const char *visibility[] = {
"travel",
"far",
"unit",
"spell",
"battle"
};
@ -943,9 +945,9 @@ const struct unit *ucansee(const struct faction *f, const struct unit *u,
int stealth_modifier(seen_mode mode)
{
switch (mode) {
case seen_spell:
case seen_unit:
return 0;
case seen_far:
case seen_lighthouse:
return -2;
case seen_travel:
@ -1336,6 +1338,12 @@ void prepare_report(report_context *ctx, faction *f)
for (r = ctx->first; r!=ctx->last; r = r->next) {
unit *u;
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 && bt_lighthouse) {

View File

@ -437,7 +437,7 @@ static void test_report_far_vision(CuTest *tc) {
u1 = test_create_unit(f, r1);
r2 = test_create_region(10, 0, 0);
rc = test_create_race("spell");
watch_region(r2, f, 10);
set_observer(r2, f, 10);
CuAssertPtrEquals(tc, r1, f->first);
CuAssertPtrEquals(tc, r2, f->last);
report_context ctx;
@ -445,7 +445,7 @@ static void test_report_far_vision(CuTest *tc) {
CuAssertPtrEquals(tc, r1, ctx.first);
CuAssertPtrEquals(tc, 0, ctx.last);
CuAssertIntEquals(tc, seen_unit, r1->seen.mode);
CuAssertIntEquals(tc, seen_unit, r2->seen.mode);
CuAssertIntEquals(tc, seen_spell, r2->seen.mode);
finish_reports(&ctx);
test_cleanup();
}

View File

@ -32,7 +32,7 @@
#include <spells/combatspells.h>
#include <spells/flyingship.h>
/* kernel includes */
/* kernel includes */
#include <kernel/curse.h>
#include <kernel/connection.h>
#include <kernel/building.h>
@ -440,8 +440,8 @@ report_effect(region * r, unit * mage, message * seen, message * unseen)
*
*/
/* ------------------------------------------------------------- */
/* Name: Vertrauter
/* ------------------------------------------------------------- */
/* Name: Vertrauter
* Stufe: 10
*
* Wirkung:
@ -1246,7 +1246,7 @@ static void fumble_ents(const castorder * co)
* Flag:
* (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 {
const struct item_type *type;
@ -1259,7 +1259,7 @@ static iron_weapon *ironweapons = NULL;
void
add_ironweapon(const struct item_type *type, const struct item_type *rusty,
float chance)
float chance)
{
iron_weapon *iweapon = malloc(sizeof(iron_weapon));
assert_alloc(iweapon);
@ -1366,7 +1366,7 @@ static int sp_rosthauch(castorder * co)
* Flag:
* (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)
{
@ -1430,7 +1430,7 @@ static int sp_kaelteschutz(castorder * co)
* Flag:
* (UNITSPELL | TESTCANSEE | SPELLLEVEL)
*/
/* Syntax: ZAUBER "Funkenregen" eh1 */
/* Syntax: ZAUBER "Funkenregen" eh1 */
static int sp_sparkle(castorder * co)
{
@ -2861,7 +2861,7 @@ static int dc_age(struct curse *c)
damage *= (1.0 - magic_resistance(u));
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)
up = &u->next;
}
@ -3123,7 +3123,7 @@ static bool chaosgate_valid(const connection * b)
}
static struct region *chaosgate_move(const connection * b, struct unit *u,
struct region *from, struct region *to, bool routing)
struct region *from, struct region *to, bool routing)
{
if (!routing) {
int maxhp = u->hp / 4;
@ -4111,13 +4111,92 @@ static int sp_bigrecruit(castorder * co)
return cast_level;
}
void watch_region(region *r, faction *f, int perception)
{
unit *u;
typedef struct obs_data {
faction *f;
int skill;
int timer;
} obs_data;
u = create_unit(r, f, 1, get_race(RC_SPELL), 0, NULL, NULL);
u->age = 2;
set_level(u, SK_PERCEPTION, perception);
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));
}
/* ------------------------------------------------------------- */
@ -4133,7 +4212,7 @@ void watch_region(region *r, faction *f, int perception)
* (UNITSPELL | TESTCANSEE)
*/
/* restistenz der einheit pruefen */
/* restistenz der einheit pruefen */
static int sp_pump(castorder * co)
{
unit *u, *target;
@ -4176,7 +4255,7 @@ static int sp_pump(castorder * co)
return cast_level / 2;
}
watch_region(rt, mage->faction, effskill(target, SK_PERCEPTION, 0));
set_observer(rt, mage->faction, effskill(target, SK_PERCEPTION, 0));
return cast_level;
}
@ -4527,7 +4606,7 @@ int sp_icastle(castorder * co)
if (type == bt_illusion) {
b->size = (rng_int() % (int)((power * power) + 1) * 10);
}
else if (type->maxsize >0) {
else if (type->maxsize > 0) {
b->size = type->maxsize;
}
else {
@ -4815,7 +4894,7 @@ int sp_dreamreading(castorder * co)
return 0;
}
watch_region(u->region, mage->faction, effskill(u, SK_PERCEPTION, u->region));
set_observer(u->region, mage->faction, effskill(u, SK_PERCEPTION, u->region));
msg =
msg_message("sp_dreamreading_effect", "mage unit region", mage, u,
@ -5622,7 +5701,8 @@ int sp_showastral(castorder * co)
/* sprintf(buf, "%s kann niemanden im astralen Nebel entdecken.",
unitname(mage)); */
cmistake(mage, co->order, 220, MSG_MAGIC);
} else {
}
else {
/* Ausgeben */
@ -5642,13 +5722,14 @@ int sp_showastral(castorder * co)
}
icat(u->number);
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 ");
icat(distance(rl2->data, rt));
scat(")");
if (c == n - 1) {
scat(" und ");
} else if (c < n - 1) {
}
else if (c < n - 1) {
scat(", ");
}
}
@ -5688,7 +5769,7 @@ int sp_viewreality(castorder * co)
for (rl2 = rl; rl2; rl2 = rl2->next) {
region *rt = rl2->data;
if (!is_cursed(rt->attribs, C_ASTRALBLOCK, 0)) {
watch_region(rt, mage->faction, co->level / 2);
set_observer(rt, mage->faction, co->level / 2);
}
}
@ -6262,7 +6343,7 @@ int sp_speed2(castorder * co)
* Flags:
* (FARCASTING | SPELLLEVEL | ONSHIPCAST | TESTCANSEE)
*/
/* Jeder gebrochene Zauber verbraucht c->vigour an Zauberkraft
/* Jeder gebrochene Zauber verbraucht c->vigour an Zauberkraft
* (force) */
int sp_q_antimagie(castorder * co)
{
@ -6718,6 +6799,7 @@ void register_spells(void)
register_borders();
at_register(&at_wdwpyramid);
at_register(&at_observer);
at_register(&at_deathcloud_compat);
/* init_firewall(); */

View File

@ -31,7 +31,8 @@ extern "C" {
void register_spells(void);
void watch_region(struct region *r, struct faction *f, int perception);
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_gooddreams(castorder * co);

View File

@ -3,6 +3,7 @@
#include <kernel/curse.h>
#include <kernel/faction.h>
#include <kernel/order.h>
#include <kernel/race.h>
#include <kernel/region.h>
#include <kernel/spell.h>
#include <kernel/unit.h>
@ -106,9 +107,28 @@ static void test_bad_dreams(CuTest *tc) {
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 *suite = CuSuiteNew();
SUITE_ADD_TEST(suite, test_watch_region);
SUITE_ADD_TEST(suite, test_good_dreams);
SUITE_ADD_TEST(suite, test_bad_dreams);
SUITE_ADD_TEST(suite, test_dreams);