forked from github/server
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:
parent
d9a0bc7016
commit
712e1c3052
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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];
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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));
|
||||||
|
|
94
src/move.c
94
src/move.c
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue