http://eressea.upb.de/mantis/view.php?id=285
 Insekten können Gletscher betreten.

 Kompletter Umbau der movement-Routinen, wesentlich sauberer getrennt. Konstrukte wie A wird von B verfolgt, welcher C transportiert, und C wird von D verfolgt klappen, und kommend amit klar, das Einheiten zwishendurch stehenbleiben wegen fehlender Reichweite oder Gletscherproblemen.

 Wenn hier nicht mindestens ein Bug drin ist, wäre ich überrascht, obwohl ich es mit diversen konstruierten Testfällen in LUA ausprobiert habe. Ich teste das gleich mal mit Datenfiles.
This commit is contained in:
Enno Rehling 2004-12-19 16:39:51 +00:00
parent 3bb2bc4ab8
commit 1ead3ebe08
17 changed files with 756 additions and 567 deletions

View File

@ -915,29 +915,38 @@ void
plan_monsters(void)
{
region *r;
unit *u;
attrib *ta;
faction *f = findfaction(MONSTER_FACTION);
if (!f)
return;
if (!f) return;
f->lastorders = turn;
for (r = regions; r; r = r->next) {
unit *u;
for (u = r->units; u; u = u->next) {
region * tr = NULL;
boolean is_moving = false;
attrib * ta;
/* Ab hier nur noch Befehle für NPC-Einheiten. */
if (u->faction->no != MONSTER_FACTION) continue;
/* Monster bekommen jede Runde ein paar Tage Wahrnehmung dazu */
produceexp(u, SK_OBSERVATION, u->number);
/* Haben Drachen ihr Ziel erreicht? */
ta = a_find(u->attribs, &at_targetregion);
if (ta) {
if (u->region == (region*)ta->data.v) {
a_remove(&u->attribs, ta);
set_order(&u->lastorder, parse_order(keywords[K_WAIT], u->faction->locale));
free_order(u->lastorder); /* parse_order & set_order have each increased the refcount */
}
else {
is_moving = true;
}
}
ta = a_find(u->attribs, &at_hate);
if (ta && is_waiting(u)) {
if (ta && !is_waiting(u)) {
unit * tu = (unit *)ta->data.v;
if (tu && tu->region==r) {
sprintf(buf, "%s %s", locale_string(u->faction->locale, keywords[K_ATTACK]), itoa36(tu->no));
@ -948,11 +957,6 @@ plan_monsters(void)
}
else a_remove(&u->attribs, ta);
}
ta = a_find(u->attribs, &at_targetregion);
if (ta!=NULL) {
tr = (region *) ta->data.v;
if (tr != r) is_moving = true;
}
if (!(fval(u, UFL_ISNEW)) && r->terrain != T_OCEAN) { /* Monster bewachen immer */
const char * cmd = locale_string(u->faction->locale, keywords[K_GUARD]);

View File

@ -2500,7 +2500,7 @@ aftermath(battle * b)
fset(du, UFL_LONGACTION);
leave(du->region, du);
if (df->run.region) {
travel(du, df->run.region, 1, NULL);
run_to(du, df->run.region);
df->run.region = du->region;
}
} else

View File

@ -78,7 +78,7 @@ extern "C" {
/* is the border in a valid state,
* or should it be erased at the end of this turn to save space?
*/
void (*move)(const border *, struct unit * u, const struct region * from, const struct region * to);
struct region * (*move)(const border *, struct unit * u, struct region * from, struct region * to);
/* executed when the units traverses this border */
struct border_type * next; /* for internal use only */
} border_type;

View File

@ -1366,9 +1366,7 @@ sp_denyattack(fighter * fi, int level, double power, spell * sp)
case K_ROUTE:
init_tokens(mage->thisorder);
skip_token();
fi->run.region = movewhere(r, mage);
if (!fi->run.region) {
cmistake(mage, mage->thisorder, 71, MSG_MOVE);
if (movewhere(mage, getstrtoken(), mage->region, &fi->run.region)!=E_MOVE_OK) {
fi->run.region = fleeregion(mage);
}
break;

View File

@ -1039,7 +1039,7 @@ cansee(const faction * f, const region * r, const unit * u, int modifier)
#endif
o = eff_skill(u2, SK_OBSERVATION, r);
#if NIGHTEYES
#ifdef NIGHTEYES
if (u2->enchanted == SP_NIGHT_EYES && o < NIGHT_EYE_TALENT)
o = NIGHT_EYE_TALENT;
#endif
@ -1102,7 +1102,7 @@ cansee(faction * f, region * r, unit * u, int modifier)
#endif
o = eff_skill(u2, SK_OBSERVATION, r);
#if NIGHTEYES
#ifdef NIGHTEYES
if (u2->enchanted == SP_NIGHT_EYES && o < NIGHT_EYE_TALENT)
o = NIGHT_EYE_TALENT;
#endif
@ -1133,17 +1133,19 @@ cansee_durchgezogen(const faction * f, const region * r, const unit * u, int mod
else if (u->faction == f) cansee = true;
else {
n = eff_stealth(u, r) - modifier;
if (getguard(u) || usiege(u) || u->building || u->ship) {
cansee = true;
}
for (u2 = r->units; u2; u2 = u2->next){
n = eff_stealth(u, r) - modifier;
if (n<=0) {
cansee = true;
}
for (u2 = r->units; !cansee && u2; u2 = u2->next){
if (u2->faction == f) {
int o;
if (getguard(u) || usiege(u) || u->building || u->ship) {
cansee = true;
break;
}
#if NEWATSROI == 0
if (invisible(u) >= u->number
&& !get_item(u2, I_AMULET_OF_TRUE_SEEING))
@ -1152,13 +1154,12 @@ cansee_durchgezogen(const faction * f, const region * r, const unit * u, int mod
o = eff_skill(u2, SK_OBSERVATION, r);
#if NIGHTEYES
#ifdef NIGHTEYES
if (u2->enchanted == SP_NIGHT_EYES && o < NIGHT_EYE_TALENT)
o = NIGHT_EYE_TALENT;
#endif
if (o >= n) {
cansee = true;
break;
}
}
}
@ -2924,79 +2925,48 @@ findspecialdirection(const region *r, const char *token)
return NULL;
}
region *
movewhere(region * r, const unit *u)
message *
movement_error(unit * u, const char * token, order * ord, int error_code)
{
direction_t d;
const char *token;
region * r2;
direction_t d;
switch (error_code) {
case E_MOVE_BLOCKED:
d = finddirection(token, u->faction->locale);
return msg_message("moveblocked", "unit direction", u, d);
case E_MOVE_NOREGION:
return msg_feedback(u, ord, "unknowndirection", "direction", token);
}
return NULL;
}
token = getstrtoken();
int
movewhere(const unit *u, const char * token, region * r, region** resultp)
{
direction_t d = finddirection(token, u->faction->locale);
region * r2;
d = finddirection(token, u->faction->locale);
if (d == D_PAUSE)
return r;
switch (d) {
if (d == NODIRECTION)
return findspecialdirection(r, token);
case D_PAUSE:
*resultp = r;
break;
#if 0 /* NOT here! make a temporary attribute for this and move it into travel() */
if (is_cursed(r->attribs, C_REGCONF, 0)) {
if (rand()%100 < get_curseeffect(r->attribs, C_REGCONF, 0)) {
if(u->wants < 0) u->wants--;
else if(u->wants > 0) u->wants++;
else u->wants = rand()%2==0?1:-1;
}
case NODIRECTION:
r2 = findspecialdirection(r, token);
if (r2!=NULL) {
return E_MOVE_NOREGION;
}
*resultp = r2;
break;
default:
r2 = rconnect(r, d);
if (r2==NULL || move_blocked(u, r, r2)) {
return E_MOVE_BLOCKED;
}
*resultp = r2;
}
if (u->ship && is_cursed(u->ship->attribs, C_DISORIENTATION, 0)) {
if (rand()%100 < get_curseeffect(r->attribs, C_DISORIENTATION, 0)) {
if(u->wants < 0) u->wants--;
else if(u->wants > 0) u->wants++;
else u->wants = rand()%20?1:-1;
}
}
d = (direction_t)((d + u->wants + MAXDIRECTIONS) % MAXDIRECTIONS);
#endif
if (!rconnect(r, d)) {
#ifdef USE_CREATION
makeblock(r->x + delta_x[d], r->y + delta_y[d], 1);
log_error((("Region (%d,%d) hatte seine Nachbarn "
"(%d,%d) noch nicht generiert!\n", r->x, r->y,
r->x + delta_x[d], r->y + delta_y[d]));
#else
add_message(&u->faction->msgs,
msg_message("moveblocked", "unit direction", u, d));
return NULL;
#endif
}
r2 = rconnect(r, d);
if (!r2) {
log_error(("Region (%d,%d) hatte seine Nachbarn "
"(%d,%d) nicht gefunden!", r->x, r->y,
r->x + delta_x[d], r->y + delta_y[d]));
return 0;
}
if (move_blocked(u, r, r2)) {
add_message(&u->faction->msgs,
msg_message("moveblocked", "unit direction", u, d));
return NULL;
}
/* r2 enthält nun die existierende Zielregion - ihre Nachbarn sollen
* auch schon alle existieren. Dies erleichtert das Umherschauen bei
* den Reports! */
#ifdef USE_CREATION
for (d = 0; d != MAXDIRECTIONS; d++)
if (!rconnect(r2, d))
makeblock(r2->x + delta_x[d], r2->y + delta_y[d], 1);
#endif
return r2;
return E_MOVE_OK;
}
boolean

View File

@ -709,8 +709,12 @@ enum {
NORACE = (race_t) - 1
};
/* ---------- Regionen ----------------------------------------- */
/* movewhere error codes */
enum {
E_MOVE_OK = 0, /* possible to move */
E_MOVE_NOREGION, /* no region exists in this direction */
E_MOVE_BLOCKED /* cannot see this region, there is a blocking border. */
};
/* Richtungen */
enum {
@ -1120,7 +1124,8 @@ extern int maxworkingpeasants(const struct region * r);
extern int wage(const struct region *r, const struct unit *u, boolean img);
extern int fwage(const struct region *r, const struct faction *f, boolean img);
extern struct region * movewhere(struct region * r, const struct unit *u);
extern int movewhere(const struct unit *u, const char * token, struct region * r, struct region** resultp);
extern struct message * movement_error(struct unit * u, const char * token, struct order * ord, int error_code);
extern boolean move_blocked(const struct unit * u, const struct region *src, const struct region *dest);
extern void add_income(struct unit * u, int type, int want, int qty);

View File

@ -399,6 +399,7 @@ void
cmistake(const unit * u, struct order *ord, int mno, int mtype)
{
static char ebuf[20];
unused(mtype);
if (u->faction->no == MONSTER_FACTION) return;
sprintf(ebuf, "error%d", mno);

File diff suppressed because it is too large Load Diff

View File

@ -51,7 +51,7 @@ extern int personcapacity(const struct unit *u);
extern direction_t getdirection(const struct locale *);
extern void movement(void);
extern int travel(struct unit * u, struct region * r2, int flucht, struct region_list** routep);
extern void run_to(struct unit * u, struct region * to);
extern struct unit *is_guarded(struct region * r, struct unit * u, unsigned int mask);
extern int enoughsailors(const struct ship * sh, const struct region * r);
extern boolean canswim(struct unit *u);

View File

@ -92,7 +92,7 @@ extern char **seasonnames;
extern char **weeknames;
extern char **monthnames;
extern int *month_season;
extern int *storms;
extern int *storms; /* in movement.c */
extern char *agename;
extern int seasons;
extern int weeks_per_month;

View File

@ -2980,8 +2980,8 @@ wall_write(const border * b, FILE * f)
fprintf(f, "%d %d ", fd->mage?fd->mage->no:0, fd->force);
}
static void
wall_move(const border * b, struct unit * u, const struct region * from, const struct region * to)
static region *
wall_move(const border * b, struct unit * u, struct region * from, struct region * to)
{
wall_data * fd = (wall_data*)b->data;
int hp = dice(3, fd->force) * u->number;
@ -2999,7 +2999,7 @@ wall_move(const border * b, struct unit * u, const struct region * from, const s
}
}
unused(from);
unused(to);
return to;
}
border_type bt_firewall = {
@ -3093,6 +3093,24 @@ wisps_name(const border * b, const region * r, const faction * f, int gflags)
return "Irrlichter";
}
static region *
wisps_move(const border * b, struct unit * u, struct region * from, struct region * next)
{
direction_t reldir = reldirection(from, next);
wall_data * wd = (wall_data*)b->data;
assert(reldir!=D_SPECIAL);
if (wd->active) {
/* pick left and right region: */
region * rl = rconnect(from, (direction_t)((reldir+MAXDIRECTIONS-1)%MAXDIRECTIONS));
region * rr = rconnect(from, (direction_t)((reldir+1)%MAXDIRECTIONS));
int j = rand() % 3;
if (j==1 && rl && landregion(rterrain(rl))==landregion(rterrain(next))) return rl;
if (j==2 && rr && landregion(rterrain(rr))==landregion(rterrain(next))) return rr;
}
return next;
}
border_type bt_wisps = {
"wisps",
b_transparent, /* transparent */
@ -3105,6 +3123,8 @@ border_type bt_wisps = {
b_rvisible, /* rvisible */
b_fvisible, /* fvisible */
b_uvisible, /* uvisible */
NULL, /* visible */
wisps_move
};
static int

View File

@ -151,6 +151,15 @@ error_callback(lua_State * L)
}
#endif
static int
get_direction(const char * name)
{
for (int i=0;i!=MAXDIRECTIONS;++i) {
if (strcasecmp(directions[i], name)==0) return i;
}
return NODIRECTION;
}
void
bind_eressea(lua_State * L)
{
@ -171,6 +180,9 @@ bind_eressea(lua_State * L)
def("plan_monsters", &lua_planmonsters),
def("set_brain", &race_setscript),
/* string to enum */
def("direction", &get_direction),
/* localization: */
def("set_string", &lua_setstring),
def("get_string", &lua_getstring),

View File

@ -106,6 +106,19 @@ region_setflag(region& r, int bit, bool set)
else r.flags &= ~(1<<bit);
}
static void
region_setroad(region& r, int dir, lua_Number size)
{
rsetroad(&r, (direction_t)dir, (int)(terrain[rterrain(&r)].roadreq * size));
}
static lua_Number
region_getroad(region& r, int dir)
{
lua_Number result = rroad(&r, (direction_t)dir);
return terrain[rterrain(&r)].roadreq / result;
}
static region *
terraform_region(int x, int y, const char * tname)
{
@ -159,8 +172,13 @@ bind_region(lua_State * L)
.property("info", &region_getinfo, &region_setinfo)
.property("terrain", &region_getterrain)
.def("add_notice", &region_addnotice)
.def("get_flag", &region_getflag)
.def("set_flag", &region_setflag)
.def("get_road", &region_getroad)
.def("set_road", &region_setroad)
.def("next", &region_next)
.def_readonly("x", &region::x)
.def_readonly("y", &region::y)

View File

@ -4483,9 +4483,9 @@
<arg name="region" type="region"/>
<arg name="command" type="order"/>
</type>
<text locale="de">"$unit($unit) in $region($region): '$order($command)' - Kann die zu transportierende Einheit nicht finden."</text>
<text locale="fr">"$unit($unit) in $region($region): '$order($command)' - Could not find the unit to be transported."</text>
<text locale="en">"$unit($unit) in $region($region): '$order($command)' - Could not find the unit to be transported."</text>
<text locale="de">"$unit($unit) in $region($region): '$order($command)' - Die Einheit will nicht transportiert werden."</text>
<text locale="fr">"$unit($unit) in $region($region): '$order($command)' - The unit doen not want to be transported."</text>
<text locale="en">"$unit($unit) in $region($region): '$order($command)' - The unit doen not want to be transported."</text>
</message>
<message name="error98" section="errors">
<type>
@ -4755,15 +4755,16 @@
<text locale="fr">"$unit($unit) in $region($region): '$order($command)' - The target-unit did not contact us."</text>
<text locale="en">"$unit($unit) in $region($region): '$order($command)' - The target-unit did not contact us."</text>
</message>
<message name="error71" section="errors">
<message name="unknowndirection" section="errors">
<type>
<arg name="unit" type="unit"/>
<arg name="region" type="region"/>
<arg name="command" type="order"/>
<arg name="dirname" type="string"/>
</type>
<text locale="de">"$unit($unit) in $region($region): '$order($command)' - Die Richtung wurde nicht erkannt."</text>
<text locale="fr">"$unit($unit) in $region($region): '$order($command)' - Direction could not be recognized."</text>
<text locale="en">"$unit($unit) in $region($region): '$order($command)' - Direction could not be recognized."</text>
<text locale="de">"$unit($unit) in $region($region): '$order($command)' - Die Richtung '$dirname' wurde nicht erkannt."</text>
<text locale="fr">"$unit($unit) in $region($region): '$order($command)' - Direction '$dirname' was not recognized."</text>
<text locale="en">"$unit($unit) in $region($region): '$order($command)' - Direction '$dirname' was not recognized."</text>
</message>
<message name="error70" section="errors">
<type>

View File

@ -3,7 +3,6 @@
<xi:include href="messages.xml"/>
<!-- Localization -->
<!-- Strings MUST always be read first -->
<xi:include href="de/strings.xml"/>
<xi:include href="en/strings.xml"/>

View File

@ -1,3 +1,84 @@
function test_movement()
west = direction("west")
east = direction("east")
r0 = terraform(0, 0, "plain")
r1 = terraform(1, 0, "desert")
r2 = terraform(2, 0, "glacier")
r3 = terraform(3, 0, "plain")
r4 = terraform(4, 0, "glacier")
r0:set_road(east, 1.0)
r1:set_road(west, 1.0)
r1:set_road(east, 1.0)
r2:set_road(west, 1.0)
r2:set_road(east, 1.0)
r3:set_road(west, 1.0)
r3:set_road(east, 1.0)
r4:set_road(west, 1.0)
orcs = add_faction("enno@eressea.de", "orc", "de")
orcs.age = 20
orc = add_unit(orcs, r0)
orc.number = 10
orc:add_item("money", orc.number*10)
orc:add_item("horse", orc.number*3)
orc:set_skill("sk_riding", 10)
bugs = add_faction("enno@eressea.de", "insect", "de")
bugs.age = 20
bug = add_unit(bugs, r0)
bug.number = 1
bug:add_item("money", bug.number*10)
orc:clear_orders()
orc:add_order("NUMMER PARTEI orcs")
orc:add_order("NUMMER EINHEIT orc")
orc:add_order("BENENNE EINHEIT Orks")
orc:add_order("ROUTE O O O P P O W W W W")
orc:add_order("GIB 0 ALLES Steine")
orc:add_order("GIB 0 ALLES Holz")
orc:add_order("TRANSPORTIEREN " .. itoa36(bug.id))
bug:clear_orders()
bug:add_order("NUMMER PARTEI bugs")
bug:add_order("NUMMER EINHEIT bug")
bug:add_order("BENENNE EINHEIT Käfer")
bug:add_order("GIB 0 ALLES Steine")
bug:add_order("GIB 0 ALLES Holz")
bug:add_order("FAHREN " .. itoa36(orc.id))
u = add_unit(orcs, r0)
u.number = 1
u:add_item("horse", u.number*3)
u:add_item("money", u.number*10)
u:set_skill("sk_riding", 10)
u:set_skill("sk_stealth", 2)
u:clear_orders()
u:add_order("FOLGEN EINHEIT " .. itoa36(bug.id))
u:add_order("NACH W")
u:add_order("NUMMER EINHEIT foLg")
u:add_order("BENENNE EINHEIT Verfolger")
u2 = add_unit(orcs, r0)
u2.number = 1
u2:add_item("horse", u2.number*3)
u2:add_item("money", u.number*10)
u2:set_skill("sk_riding", 10)
u2:set_skill("sk_stealth", 2)
u2:clear_orders()
u2:add_order("FOLGEN EINHEIT nix")
u2:add_order("NUMMER EINHEIT Last")
u2:add_order("BENENNE EINHEIT Verfolger-Verfolger")
process_orders()
write_reports()
end
function test_handler()
local function msg_handler(u, evt)
@ -221,7 +302,8 @@ function test_fail()
print(f)
end
test_fail()
test_movement()
-- test_fail()
-- test_handler()
-- test_parser()
-- test_monsters()

View File

@ -1,3 +1,7 @@
parteien- oder gruppenweises aftermath-markieren.
XUL for Eressea
weights in item descriptions
[11:01] <Enno`> am besten wäre, wenn mailit nur die optionen, nicht das ganze script enthielte