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) {
unit *u;
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)
{
building *b = findbuilding(getid());
if (b == NULL || r != b->region)
return NULL;
if (b != NULL && r == b->region) {
return b;
}
return NULL;
}
ship *getship(const struct region * r)
{
ship *sh, *sx = findship(getid());
for (sh = r->ships; sh; sh = sh->next) {
if (sh == sx)
ship *sh = findship(getid());
if (sh != NULL && sh->number > 0 && sh->region == r) {
return sh;
}
return NULL;

View File

@ -29,6 +29,7 @@
#include <util/log.h>
#include <util/param.h>
#include <util/resolve.h>
#include <util/rng.h>
#include <util/strings.h>
#include <util/umlaut.h>
@ -368,11 +369,30 @@ building *building_create(int id)
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,
const struct locale * lang, int size)
{
building **bptr = &r->buildings;
int id = newcontainerid();
int id = newbuildingid();
building *b = building_create(id);
const char *bname;
char buffer[32];

View File

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

View File

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

View File

@ -1066,7 +1066,7 @@ int enter_ship(unit * u, struct order *ord, int id, bool report)
}
sh = findship(id);
if (sh == NULL || sh->region != r) {
if (sh == NULL || sh->number < 1 || sh->region != r) {
if (report) {
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_CLAIM, claim_cmd, 0, NULL);
add_proc_unit(p, follow_unit, "Folge auf Einheiten setzen");
p += 10; /* rest rng again before economics */
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+1, recruit, "Rekrutieren");
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");
/* 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);
if (sh != NULL && sh->region != r && (sp->sptyp & GLOBALTARGET) == 0) {
/* Burg muss in gleicher Region sein */
/* Schiff muss in gleicher Region sein */
sh = NULL;
}
if (sh == NULL) {
/* Burg nicht gefunden */
if (sh == NULL || sh->number < 1) {
/* Schiff nicht gefunden */
spobj->flag = TARGET_NOTFOUND;
ADDMSG(&mage->faction->msgs, msg_message("spellshipnotfound",
"unit region command id", mage, mage->region, ord, spobj->data.i));

View File

@ -102,21 +102,28 @@ typedef struct follower {
} follower;
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)
{
unit *uf;
for (uf = r->units; uf; uf = uf->next) {
if (fval(uf, UFL_FOLLOWING) && !fval(uf, UFL_NOTMOVING)) {
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));
assert_alloc(fnew);
fnew->uf = uf;
fnew->ut = target;
fnew->ut = u;
fnew->route_end = route_end;
fnew->next = *followers;
*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);
if (dir == NODIRECTION) {
if (sh == NULL || sh->region != rc) {
if (sh == NULL || sh->number < 1 || sh->region != rc) {
cmistake(u, ord, 20, MSG_MOVE);
}
return 0;
@ -2493,59 +2500,68 @@ void movement(void)
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;
attrib *a = NULL;
order *ord;
order *ord, *o;
if (fval(u, UFL_NOTMOVING) || LongHunger(u))
if (fval(u, UFL_MOVED | UFL_NOTMOVING) || LongHunger(u)) {
return;
}
for (ord = u->orders; ord; ord = ord->next) {
const struct locale *lang = u->faction->locale;
if (getkeyword(ord) == K_FOLLOW) {
int id;
unit *u2 = NULL;
param_t p;
init_order(ord, NULL);
p = getparam(lang);
if (p == P_UNIT) {
id = read_unitid(u->faction, r);
int id = read_unitid(u->faction, r);
if (id == u->no) {
ADDMSG(&u->faction->msgs, msg_message("followfail", "unit follower",
u, u));
continue;
}
if (a != NULL) {
a = a_find(u->attribs, &at_follow);
}
if (id > 0) {
unit *uf = findunit(id);
if (!a) {
a = a_add(&u->attribs, make_follow(uf));
u2 = findunit(id);
}
}
else if (p == P_SHIP) {
int id = getid();
if (id <= 0) {
cmistake(u, ord, 20, MSG_MOVE);
}
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) {
a_remove(&u->attribs, a);
a = NULL;
else if (u->ship && u != ship_owner(u->ship)) {
cmistake(u, ord, 146, MSG_MOVE);
}
else if (!can_move(u)) {
cmistake(u, ord, 55, MSG_MOVE);
}
else {
u2 = ship_owner(sh);
}
}
}
}
if (a && !fval(u, UFL_MOVED | UFL_NOTMOVING)) {
bool follow = false;
unit *u2 = a->data.v;
if (!u2 || u2->region != r || !cansee(u->faction, r, u2, 0)) {
if (u2) {
bool moving = false;
if (u2->region != r || !cansee(u->faction, r, u2, 0)) {
/* FIXME: u2 sollte hier keine TEMP Einheit sein. */
ADDMSG(&u->faction->msgs, msg_message("unitnotfound_id",
"unit region command id", u, r, ord, itoa36(u2->no)));
return;
}
@ -2553,25 +2569,19 @@ void follow_unit(unit * u)
case K_MOVE:
case K_ROUTE:
case K_DRIVE:
follow = true;
moving = true;
break;
default:
for (ord = u2->orders; ord; ord = ord->next) {
if (K_FOLLOW == getkeyword(ord)) {
follow = true;
for (o = u2->orders; o; o = o->next) {
if (K_FOLLOW == getkeyword(o)) {
moving = true;
break;
}
}
break;
}
if (!follow) {
attrib *a2 = a_find(u2->attribs, &at_follow);
if (a2 != NULL) {
unit *u3 = a2->data.v;
follow = (u3 && u2->region == u3->region);
}
}
if (follow) {
if (moving) {
a_add(&u->attribs, make_follow(u2));
fset(u2, UFL_FOLLOWED);
/* FOLLOW unit on a (potentially) moving unit prevents long orders */
fset(u, UFL_FOLLOWING | UFL_LONGACTION);
@ -2579,3 +2589,5 @@ void follow_unit(unit * u)
}
}
}
}
}

View File

@ -62,7 +62,7 @@ extern "C" {
struct region *to, struct region_list *route);
int walkingcapacity(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,
const struct building_type *bt);
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);
/* 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, u2, u->attribs->data.v);
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));
ord = create_order(K_FOLLOW, f->locale, "EINHEIT %s", itoa36(u->no));
unit_addorder(u, ord);
follow_unit(u);
follow_cmds(u);
CuAssertPtrNotNull(tc, test_find_messagetype(u->faction->msgs, "followfail"));
CuAssertIntEquals(tc, 0, fval(u, UFL_FOLLOWING | UFL_LONGACTION));
test_teardown();

View File

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