diff --git a/src/bind_process.c b/src/bind_process.c index f9f99284e..8626a2820 100755 --- a/src/bind_process.c +++ b/src/bind_process.c @@ -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); } } } diff --git a/src/kernel/build.c b/src/kernel/build.c index 14f922f57..f5debccb8 100644 --- a/src/kernel/build.c +++ b/src/kernel/build.c @@ -56,17 +56,17 @@ struct building *getbuilding(const struct region *r) { building *b = findbuilding(getid()); - if (b == NULL || r != b->region) - return NULL; - return b; + 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) - return sh; + ship *sh = findship(getid()); + if (sh != NULL && sh->number > 0 && sh->region == r) { + return sh; } return NULL; } diff --git a/src/kernel/building.c b/src/kernel/building.c index c8c19cc9d..a2283c1cc 100644 --- a/src/kernel/building.c +++ b/src/kernel/building.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include @@ -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]; diff --git a/src/kernel/save.c b/src/kernel/save.c index c720441c0..c1bf3eaa3 100644 --- a/src/kernel/save.c +++ b/src/kernel/save.c @@ -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); diff --git a/src/kernel/ship.c b/src/kernel/ship.c index 1458953cb..47983df69 100644 --- a/src/kernel/ship.c +++ b/src/kernel/ship.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include @@ -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; diff --git a/src/laws.c b/src/laws.c index db7c60a8b..1cea122d5 100644 --- a/src/laws.c +++ b/src/laws.c @@ -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 diff --git a/src/magic.c b/src/magic.c index 16fb401c4..9fe1ed6aa 100644 --- a/src/magic.c +++ b/src/magic.c @@ -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)); diff --git a/src/move.c b/src/move.c index 1e8d893ae..38cc0d8bb 100644 --- a/src/move.c +++ b/src/move.c @@ -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) { - follower *fnew = (follower *)malloc(sizeof(follower)); - assert_alloc(fnew); - fnew->uf = uf; - fnew->ut = target; - fnew->route_end = route_end; - fnew->next = *followers; - *followers = fnew; + while (a) { + if (a->data.v == u) { + follower *fnew = (follower *)malloc(sizeof(follower)); + assert_alloc(fnew); + fnew->uf = uf; + 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,89 +2500,94 @@ 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 { + 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 (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 { - a->data.v = uf; + u2 = ship_owner(sh); } } - else if (a) { - a_remove(&u->attribs, a); - a = NULL; - } } - } - } + 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; + } - 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)) { - return; - } - - switch (getkeyword(u2->thisorder)) { - case K_MOVE: - case K_ROUTE: - case K_DRIVE: - follow = true; - break; - default: - for (ord = u2->orders; ord; ord = ord->next) { - if (K_FOLLOW == getkeyword(ord)) { - follow = true; + switch (getkeyword(u2->thisorder)) { + case K_MOVE: + case K_ROUTE: + case K_DRIVE: + moving = true; + break; + default: + for (o = u2->orders; o; o = o->next) { + if (K_FOLLOW == getkeyword(o)) { + moving = true; + break; + } + } break; } + 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); + set_order(&u->thisorder, NULL); + } } - 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) { - fset(u2, UFL_FOLLOWED); - /* FOLLOW unit on a (potentially) moving unit prevents long orders */ - fset(u, UFL_FOLLOWING | UFL_LONGACTION); - set_order(&u->thisorder, NULL); } } } diff --git a/src/move.h b/src/move.h index 333514862..6866cf233 100644 --- a/src/move.h +++ b/src/move.h @@ -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, diff --git a/src/move.test.c b/src/move.test.c index 17a7ed4cc..cdff2e60d 100644 --- a/src/move.test.c +++ b/src/move.test.c @@ -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(); diff --git a/src/renumber.c b/src/renumber.c index ca39af93a..5fb5310e9 100644 --- a/src/renumber.c +++ b/src/renumber.c @@ -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; }