FOLGE SCHIFF repariert.

https://bugs.eressea.de/view.php?id=2698
FOLGE generell verbessert, so daß man mehrere FOLGE Befehle setzen kann.
Bugfix: findship findet auch "leere" Schiffe, der Caller muss jetzt auf sh->number testen.
Schiffe und Burgen können ab sofort die selben IDs benutzen.
Befehlsreihenfolge: FOLGE erst nach VERLASSE/GIB
This commit is contained in:
Enno Rehling 2020-09-03 21:37:16 +02:00
parent d9a0bc7016
commit 712e1c3052
11 changed files with 138 additions and 84 deletions

View File

@ -232,7 +232,7 @@ void process_follow(void) {
for (r = regions; r; r = r->next) { for (r = regions; r; r = r->next) {
unit *u; unit *u;
for (u = r->units; u; u = u->next) { for (u = r->units; u; u = u->next) {
follow_unit(u); follow_cmds(u);
} }
} }
} }

View File

@ -56,16 +56,16 @@
struct building *getbuilding(const struct region *r) struct building *getbuilding(const struct region *r)
{ {
building *b = findbuilding(getid()); building *b = findbuilding(getid());
if (b == NULL || r != b->region) if (b != NULL && r == b->region) {
return NULL;
return b; return b;
}
return NULL;
} }
ship *getship(const struct region * r) ship *getship(const struct region * r)
{ {
ship *sh, *sx = findship(getid()); ship *sh = findship(getid());
for (sh = r->ships; sh; sh = sh->next) { if (sh != NULL && sh->number > 0 && sh->region == r) {
if (sh == sx)
return sh; return sh;
} }
return NULL; return NULL;

View File

@ -29,6 +29,7 @@
#include <util/log.h> #include <util/log.h>
#include <util/param.h> #include <util/param.h>
#include <util/resolve.h> #include <util/resolve.h>
#include <util/rng.h>
#include <util/strings.h> #include <util/strings.h>
#include <util/umlaut.h> #include <util/umlaut.h>
@ -368,11 +369,30 @@ building *building_create(int id)
return b; return b;
} }
static int newbuildingid(void) {
int random_no;
int start_random_no;
random_no = 1 + (rng_int() % MAX_CONTAINER_NR);
start_random_no = random_no;
while (findbuilding(random_no)) {
random_no++;
if (random_no == MAX_CONTAINER_NR + 1) {
random_no = 1;
}
if (random_no == start_random_no) {
random_no = (int)MAX_CONTAINER_NR + 1;
}
}
return random_no;
}
building *new_building(const struct building_type * btype, region * r, building *new_building(const struct building_type * btype, region * r,
const struct locale * lang, int size) const struct locale * lang, int size)
{ {
building **bptr = &r->buildings; building **bptr = &r->buildings;
int id = newcontainerid(); int id = newbuildingid();
building *b = building_create(id); building *b = building_create(id);
const char *bname; const char *bname;
char buffer[32]; char buffer[32];

View File

@ -466,7 +466,7 @@ unit *read_unit(gamedata *data)
if (sn > 0) { if (sn > 0) {
ship * sh = findship(sn); ship * sh = findship(sn);
if (sh) { if (sh && sh->number > 0) {
u_set_ship(u, sh); u_set_ship(u, sh);
if (fval(u, UFL_OWNER)) { if (fval(u, UFL_OWNER)) {
ship_set_owner(u); ship_set_owner(u);

View File

@ -25,6 +25,7 @@
#include <util/lists.h> #include <util/lists.h>
#include <util/log.h> #include <util/log.h>
#include <util/param.h> #include <util/param.h>
#include <util/rng.h>
#include <util/strings.h> #include <util/strings.h>
#include <util/umlaut.h> #include <util/umlaut.h>
@ -150,7 +151,7 @@ static ship *sfindhash(int i)
for (sh = shiphash[i % MAXSHIPHASH]; sh; sh = sh->nexthash) { for (sh = shiphash[i % MAXSHIPHASH]; sh; sh = sh->nexthash) {
if (sh->no == i) { if (sh->no == i) {
return sh->number > 0 ? sh : NULL; return sh;
} }
} }
return NULL; return NULL;
@ -171,6 +172,25 @@ void damage_ship(ship * sh, double percent)
/* Alte Schiffstypen: */ /* Alte Schiffstypen: */
static ship *deleted_ships; static ship *deleted_ships;
static int newshipid(void) {
int random_no;
int start_random_no;
random_no = 1 + (rng_int() % MAX_CONTAINER_NR);
start_random_no = random_no;
while (findship(random_no)) {
random_no++;
if (random_no == MAX_CONTAINER_NR + 1) {
random_no = 1;
}
if (random_no == start_random_no) {
random_no = (int)MAX_CONTAINER_NR + 1;
}
}
return random_no;
}
ship *new_ship(const ship_type * stype, region * r, const struct locale *lang) ship *new_ship(const ship_type * stype, region * r, const struct locale *lang)
{ {
static char buffer[32]; static char buffer[32];
@ -179,7 +199,7 @@ ship *new_ship(const ship_type * stype, region * r, const struct locale *lang)
if (!sh) abort(); if (!sh) abort();
assert(stype); assert(stype);
sh->no = newcontainerid(); sh->no = newshipid();
sh->coast = NODIRECTION; sh->coast = NODIRECTION;
sh->type = stype; sh->type = stype;
sh->region = r; sh->region = r;

View File

@ -1066,7 +1066,7 @@ int enter_ship(unit * u, struct order *ord, int id, bool report)
} }
sh = findship(id); sh = findship(id);
if (sh == NULL || sh->region != r) { if (sh == NULL || sh->number < 1 || sh->region != r) {
if (report) { if (report) {
cmistake(u, ord, 20, MSG_MOVE); cmistake(u, ord, 20, MSG_MOVE);
} }
@ -3914,7 +3914,6 @@ void init_processor(void)
} }
add_proc_order(p, K_RESERVE, reserve_cmd, 0, "RESERVE (all)"); add_proc_order(p, K_RESERVE, reserve_cmd, 0, "RESERVE (all)");
add_proc_order(p, K_CLAIM, claim_cmd, 0, NULL); add_proc_order(p, K_CLAIM, claim_cmd, 0, NULL);
add_proc_unit(p, follow_unit, "Folge auf Einheiten setzen");
p += 10; /* rest rng again before economics */ p += 10; /* rest rng again before economics */
if (rule_force_leave(FORCE_LEAVE_ALL)) { if (rule_force_leave(FORCE_LEAVE_ALL)) {
@ -3923,6 +3922,7 @@ void init_processor(void)
add_proc_region(p, economics, "Geben, Vergessen"); add_proc_region(p, economics, "Geben, Vergessen");
add_proc_region(p+1, recruit, "Rekrutieren"); add_proc_region(p+1, recruit, "Rekrutieren");
add_proc_region(p+2, destroy, "Zerstoeren"); add_proc_region(p+2, destroy, "Zerstoeren");
add_proc_unit(p, follow_cmds, "Folge auf Einheiten setzen");
add_proc_order(p, K_QUIT, quit_cmd, 0, "Stirb"); add_proc_order(p, K_QUIT, quit_cmd, 0, "Stirb");
/* all recruitment must be finished before we can calculate /* all recruitment must be finished before we can calculate

View File

@ -1499,12 +1499,12 @@ verify_ship(region * r, unit * mage, const spell * sp, spllprm * spobj,
ship *sh = findship(spobj->data.i); ship *sh = findship(spobj->data.i);
if (sh != NULL && sh->region != r && (sp->sptyp & GLOBALTARGET) == 0) { if (sh != NULL && sh->region != r && (sp->sptyp & GLOBALTARGET) == 0) {
/* Burg muss in gleicher Region sein */ /* Schiff muss in gleicher Region sein */
sh = NULL; sh = NULL;
} }
if (sh == NULL) { if (sh == NULL || sh->number < 1) {
/* Burg nicht gefunden */ /* Schiff nicht gefunden */
spobj->flag = TARGET_NOTFOUND; spobj->flag = TARGET_NOTFOUND;
ADDMSG(&mage->faction->msgs, msg_message("spellshipnotfound", ADDMSG(&mage->faction->msgs, msg_message("spellshipnotfound",
"unit region command id", mage, mage->region, ord, spobj->data.i)); "unit region command id", mage, mage->region, ord, spobj->data.i));

View File

@ -102,21 +102,28 @@ typedef struct follower {
} follower; } follower;
static void static void
get_followers(unit * target, region * r, const region_list * route_end, get_followers(unit * u, region * r, const region_list * route_end,
follower ** followers) follower ** followers)
{ {
unit *uf; unit *uf;
for (uf = r->units; uf; uf = uf->next) { for (uf = r->units; uf; uf = uf->next) {
if (fval(uf, UFL_FOLLOWING) && !fval(uf, UFL_NOTMOVING)) { if (fval(uf, UFL_FOLLOWING) && !fval(uf, UFL_NOTMOVING)) {
const attrib *a = a_find(uf->attribs, &at_follow); const attrib *a = a_find(uf->attribs, &at_follow);
if (a && a->data.v == target) { while (a) {
if (a->data.v == u) {
follower *fnew = (follower *)malloc(sizeof(follower)); follower *fnew = (follower *)malloc(sizeof(follower));
assert_alloc(fnew); assert_alloc(fnew);
fnew->uf = uf; fnew->uf = uf;
fnew->ut = target; fnew->ut = u;
fnew->route_end = route_end; fnew->route_end = route_end;
fnew->next = *followers; fnew->next = *followers;
*followers = fnew; *followers = fnew;
break;
}
a = a->next;
if (a && a->type != &at_follow) {
break;
}
} }
} }
} }
@ -2270,7 +2277,7 @@ int follow_ship(unit * u, order * ord)
dir = hunted_dir(rc->attribs, id); dir = hunted_dir(rc->attribs, id);
if (dir == NODIRECTION) { if (dir == NODIRECTION) {
if (sh == NULL || sh->region != rc) { if (sh == NULL || sh->number < 1 || sh->region != rc) {
cmistake(u, ord, 20, MSG_MOVE); cmistake(u, ord, 20, MSG_MOVE);
} }
return 0; return 0;
@ -2493,59 +2500,68 @@ void movement(void)
move_pirates(); move_pirates();
} }
/** Overrides long orders with a FOLLOW order if the target is moving. /**
* BUGS: http://bugs.eressea.de/view.php?id=1444 (A folgt B folgt C) * Override long orders with a FOLLOW order if target seems to be moving.
*/ */
void follow_unit(unit * u) void follow_cmds(unit * u)
{ {
region *r = u->region; region *r = u->region;
attrib *a = NULL; order *ord, *o;
order *ord;
if (fval(u, UFL_NOTMOVING) || LongHunger(u)) if (fval(u, UFL_MOVED | UFL_NOTMOVING) || LongHunger(u)) {
return; return;
}
for (ord = u->orders; ord; ord = ord->next) { for (ord = u->orders; ord; ord = ord->next) {
const struct locale *lang = u->faction->locale; const struct locale *lang = u->faction->locale;
if (getkeyword(ord) == K_FOLLOW) { if (getkeyword(ord) == K_FOLLOW) {
int id; unit *u2 = NULL;
param_t p; param_t p;
init_order(ord, NULL); init_order(ord, NULL);
p = getparam(lang); p = getparam(lang);
if (p == P_UNIT) { if (p == P_UNIT) {
id = read_unitid(u->faction, r); int id = read_unitid(u->faction, r);
if (id == u->no) { if (id == u->no) {
ADDMSG(&u->faction->msgs, msg_message("followfail", "unit follower", ADDMSG(&u->faction->msgs, msg_message("followfail", "unit follower",
u, u)); u, u));
continue; continue;
} }
if (a != NULL) {
a = a_find(u->attribs, &at_follow);
}
if (id > 0) { if (id > 0) {
unit *uf = findunit(id); u2 = findunit(id);
if (!a) { }
a = a_add(&u->attribs, make_follow(uf)); }
else if (p == P_SHIP) {
int id = getid();
if (id <= 0) {
cmistake(u, ord, 20, MSG_MOVE);
} }
else { else {
a->data.v = uf; ship *sh = findship(id);
if (sh == NULL || sh->number < 1 || (sh->region != r && hunted_dir(r->attribs, id) == NODIRECTION)) {
cmistake(u, ord, 20, MSG_MOVE);
} }
else if (!u->ship && !fval(u_race(u), RCF_FLY|RCF_SWIM)) {
cmistake(u, ord, 144, MSG_MOVE);
} }
else if (a) { else if (u->ship && u != ship_owner(u->ship)) {
a_remove(&u->attribs, a); cmistake(u, ord, 146, MSG_MOVE);
a = NULL; }
else if (!can_move(u)) {
cmistake(u, ord, 55, MSG_MOVE);
}
else {
u2 = ship_owner(sh);
} }
} }
} }
} if (u2) {
bool moving = false;
if (a && !fval(u, UFL_MOVED | UFL_NOTMOVING)) { if (u2->region != r || !cansee(u->faction, r, u2, 0)) {
bool follow = false; /* FIXME: u2 sollte hier keine TEMP Einheit sein. */
unit *u2 = a->data.v; ADDMSG(&u->faction->msgs, msg_message("unitnotfound_id",
"unit region command id", u, r, ord, itoa36(u2->no)));
if (!u2 || u2->region != r || !cansee(u->faction, r, u2, 0)) {
return; return;
} }
@ -2553,29 +2569,25 @@ void follow_unit(unit * u)
case K_MOVE: case K_MOVE:
case K_ROUTE: case K_ROUTE:
case K_DRIVE: case K_DRIVE:
follow = true; moving = true;
break; break;
default: default:
for (ord = u2->orders; ord; ord = ord->next) { for (o = u2->orders; o; o = o->next) {
if (K_FOLLOW == getkeyword(ord)) { if (K_FOLLOW == getkeyword(o)) {
follow = true; moving = true;
break; break;
} }
} }
break; break;
} }
if (!follow) { if (moving) {
attrib *a2 = a_find(u2->attribs, &at_follow); a_add(&u->attribs, make_follow(u2));
if (a2 != NULL) {
unit *u3 = a2->data.v;
follow = (u3 && u2->region == u3->region);
}
}
if (follow) {
fset(u2, UFL_FOLLOWED); fset(u2, UFL_FOLLOWED);
/* FOLLOW unit on a (potentially) moving unit prevents long orders */ /* FOLLOW unit on a (potentially) moving unit prevents long orders */
fset(u, UFL_FOLLOWING | UFL_LONGACTION); fset(u, UFL_FOLLOWING | UFL_LONGACTION);
set_order(&u->thisorder, NULL); set_order(&u->thisorder, NULL);
} }
} }
}
}
} }

View File

@ -62,7 +62,7 @@ extern "C" {
struct region *to, struct region_list *route); struct region *to, struct region_list *route);
int walkingcapacity(const struct unit *u); int walkingcapacity(const struct unit *u);
int movement_speed(const struct unit * u); int movement_speed(const struct unit * u);
void follow_unit(struct unit *u); void follow_cmds(struct unit *u);
struct unit *owner_buildingtyp(const struct region *r, struct unit *owner_buildingtyp(const struct region *r,
const struct building_type *bt); const struct building_type *bt);
bool move_blocked(const struct unit *u, const struct region *src, bool move_blocked(const struct unit *u, const struct region *src,

View File

@ -467,7 +467,7 @@ static void test_follow_unit(CuTest *tc) {
u->thisorder = copy_order(ord); u->thisorder = copy_order(ord);
/* Verfolger müssen ihre Ziele finden, ehe diese sich bewegen */ /* Verfolger müssen ihre Ziele finden, ehe diese sich bewegen */
follow_unit(u); follow_cmds(u);
CuAssertPtrEquals(tc, &at_follow, (void *)u->attribs->type); CuAssertPtrEquals(tc, &at_follow, (void *)u->attribs->type);
CuAssertPtrEquals(tc, u2, u->attribs->data.v); CuAssertPtrEquals(tc, u2, u->attribs->data.v);
CuAssertPtrEquals(tc, NULL, u->thisorder); CuAssertPtrEquals(tc, NULL, u->thisorder);
@ -496,7 +496,7 @@ static void test_follow_unit_self(CuTest *tc) {
u = test_create_unit(f, test_create_plain(0, 0)); u = test_create_unit(f, test_create_plain(0, 0));
ord = create_order(K_FOLLOW, f->locale, "EINHEIT %s", itoa36(u->no)); ord = create_order(K_FOLLOW, f->locale, "EINHEIT %s", itoa36(u->no));
unit_addorder(u, ord); unit_addorder(u, ord);
follow_unit(u); follow_cmds(u);
CuAssertPtrNotNull(tc, test_find_messagetype(u->faction->msgs, "followfail")); CuAssertPtrNotNull(tc, test_find_messagetype(u->faction->msgs, "followfail"));
CuAssertIntEquals(tc, 0, fval(u, UFL_FOLLOWING | UFL_LONGACTION)); CuAssertIntEquals(tc, 0, fval(u, UFL_FOLLOWING | UFL_LONGACTION));
test_teardown(); test_teardown();

View File

@ -143,12 +143,14 @@ int renumber_cmd(unit * u, order * ord)
i = newcontainerid(); i = newcontainerid();
} }
else { else {
ship *sh;
i = atoi36((const char *)s); i = atoi36((const char *)s);
if (i <= 0 || i > MAX_CONTAINER_NR) { if (i <= 0 || i > MAX_CONTAINER_NR) {
cmistake(u, ord, 114, MSG_EVENT); cmistake(u, ord, 114, MSG_EVENT);
break; break;
} }
if (findship(i)) { sh = findship(i);
if (sh && sh->number > 0) {
cmistake(u, ord, 115, MSG_EVENT); cmistake(u, ord, 115, MSG_EVENT);
break; break;
} }