From 7038b021de72d49ec9879a321794ed785178df32 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sat, 24 May 2014 20:25:06 -0700 Subject: [PATCH] fix counting of units, making it slower but more correct --- src/bind_unit.c | 23 ++++++------ src/kernel/config.c | 64 ++++++++++++---------------------- src/kernel/config.h | 28 ++++++++------- src/kernel/save.c | 85 +++++++++++++++++++++++++-------------------- src/kernel/unit.c | 8 ++--- src/laws.c | 45 ++++++++++++------------ src/summary.c | 4 +-- 7 files changed, 122 insertions(+), 135 deletions(-) diff --git a/src/bind_unit.c b/src/bind_unit.c index 2d2c71dca..3b65a7190 100755 --- a/src/bind_unit.c +++ b/src/bind_unit.c @@ -847,19 +847,16 @@ static int tolua_unit_get_race(lua_State * L) static int tolua_unit_set_race(lua_State * L) { - unit *self = (unit *) tolua_tousertype(L, 1, 0); - const char *rcname = tolua_tostring(L, 2, 0); - race *rc = rc_find(rcname); - if (rc != NULL) { - if (count_unit(self)) - --self->faction->no_units; - if (self->irace == u_race(self)) - self->irace = NULL; - u_setrace(self, rc); - if (count_unit(self)) - --self->faction->no_units; - } - return 0; + unit *self = (unit *) tolua_tousertype(L, 1, 0); + const char *rcname = tolua_tostring(L, 2, 0); + race *rc = rc_find(rcname); + if (rc != NULL) { + if (self->irace == u_race(self)) { + self->irace = NULL; + } + u_setrace(self, rc); + } + return 0; } static int tolua_unit_destroy(lua_State * L) diff --git a/src/kernel/config.c b/src/kernel/config.c index 6822d42d0..cffbb381e 100644 --- a/src/kernel/config.c +++ b/src/kernel/config.c @@ -1194,59 +1194,41 @@ void update_lighthouse(building * lh) } } -int count_all(const faction * f) +int count_faction(const faction * f, int flags) { -#ifndef NDEBUG unit *u; - int np = 0, n = 0; + int n = 0; for (u = f->units; u; u = u->nextF) { - assert(f == u->faction); - n += u->number; - if (playerrace(u_race(u))) { - np += u->number; + const race *rc = u_race(u); + int x = (flags&COUNT_UNITS) ? 1 : u->number; + if (f->race!=rc) { + if (!playerrace(rc)) { + if (flags&COUNT_MONSTERS) { + n+=x; + } + } else if (flags&COUNT_MIGRANTS) { + if (!is_cursed(u->attribs, C_SLAVE, 0)) { + n+=x; + } + } + } else if (flags&COUNT_DEFAULT) { + n+=x; } } - if (f->num_people != np) { - log_error("# of people in %s is != num_people: %d should be %d.\n", factionid(f), f->num_people, np); - } - if (f->num_total != n) { - log_error("# of men in %s is != num_total: %d should be %d.\n", factionid(f), f->num_total, n); - } -#endif - return (f->flags & FFL_NPC) ? f->num_total : f->num_people; + return n; } int count_units(const faction * f) { -#ifndef NDEBUG - unit *u; - int n = 0, np = 0; - for (u = f->units; u; u = u->nextF) { - ++n; - if (playerrace(u_race(u))) ++np; - } - n = (f->flags & FFL_NPC) ? n : np; - if (f->no_units && n != f->no_units) { - log_warning("# of units in %s is != no_units: %d should be %d.\n", factionid(f), f->no_units, n); - } -#endif - return n; + return count_faction(f, COUNT_ALL|COUNT_UNITS); +} +int count_all(const faction * f) +{ + return count_faction(f, COUNT_ALL); } - int count_migrants(const faction * f) { - unit *u = f->units; - int n = 0; - while (u) { - assert(u->faction == f); - if (u_race(u) != f->race && u_race(u) != new_race[RC_ILLUSION] - && u_race(u) != new_race[RC_SPELL] - && !!playerrace(u_race(u)) && !(is_cursed(u->attribs, C_SLAVE, 0))) { - n += u->number; - } - u = u->nextF; - } - return n; + return count_faction(f, COUNT_MIGRANTS); } int count_maxmigrants(const faction * f) diff --git a/src/kernel/config.h b/src/kernel/config.h index 885684d99..8ee6f7aa6 100644 --- a/src/kernel/config.h +++ b/src/kernel/config.h @@ -256,16 +256,23 @@ extern "C" { extern int rule_alliance_limit(void); extern int rule_faction_limit(void); - int count_units(const struct faction * f); - int count_all(const struct faction *f); - int count_migrants(const struct faction *f); - int count_maxmigrants(const struct faction *f); +#define COUNT_MONSTERS 0x01 +#define COUNT_MIGRANTS 0x02 +#define COUNT_DEFAULT 0x04 +#define COUNT_ALL 0x07 +#define COUNT_UNITS 0x10 + + int count_faction(const struct faction * f, int flags); + int count_migrants(const struct faction * f); + int count_maxmigrants(const struct faction * f); + int count_all(const struct faction * f); + int count_units(const struct faction * f); - extern bool has_limited_skills(const struct unit *u); - extern const struct race *findrace(const char *, const struct locale *); + bool has_limited_skills(const struct unit *u); + const struct race *findrace(const char *, const struct locale *); - int eff_stealth(const struct unit *u, const struct region *r); - int ispresent(const struct faction *f, const struct region *r); + int eff_stealth(const struct unit *u, const struct region *r); + int ispresent(const struct faction *f, const struct region *r); int check_option(struct faction *f, int option); extern void parse_kwd(keyword_t kword, int (*dofun) (struct unit *, @@ -450,11 +457,6 @@ extern "C" { extern struct attrib_type at_guard; extern void free_gamedata(void); -#if 1 /* disable to count all units */ -# define count_unit(u) (u->number>0 && playerrace(u_race(u))) -#else -# define count_unit(u) 1 -#endif #ifdef __cplusplus } diff --git a/src/kernel/save.c b/src/kernel/save.c index aa15dbc24..570b3f16f 100644 --- a/src/kernel/save.c +++ b/src/kernel/save.c @@ -574,36 +574,50 @@ writeorder(struct gamedata *data, const struct order *ord, unit *read_unit(struct gamedata *data) { - unit *u; - int number, n, p; - order **orderp; - char obuf[DISPLAYSIZE]; - faction *f; - char rname[32]; + unit *u; + int number, n, p; + order **orderp; + char obuf[DISPLAYSIZE]; + faction *f; + char rname[32]; - READ_INT(data->store, &n); - if (n <= 0) - return NULL; - u = findunit(n); - if (u == NULL) { - u = calloc(sizeof(unit), 1); - u->no = n; - uhash(u); - } else { - while (u->attribs) - a_remove(&u->attribs, u->attribs); - while (u->items) - i_free(i_remove(&u->items, u->items)); - free(u->skills); - u->skills = 0; - u->skill_size = 0; - u_setfaction(u, NULL); - } + READ_INT(data->store, &n); + if (n <= 0) { + log_error("data contains invalid unit %d.\n", n); + assert(n>0); + return 0; + } + u = findunit(n); + if (u) { + log_error("reading unit %s that already exists.\n", unitname(u)); + while (u->attribs) { + a_remove(&u->attribs, u->attribs); + } + while (u->items) { + i_free(i_remove(&u->items, u->items)); + } + free(u->skills); + u->skills = 0; + u->skill_size = 0; + u_setfaction(u, NULL); + } else { + u = calloc(sizeof(unit), 1); + u->no = n; + uhash(u); + } - READ_INT(data->store, &n); - f = findfaction(n); - if (f != u->faction) - u_setfaction(u, f); + READ_INT(data->store, &n); + f = findfaction(n); + if (f != u->faction) { + u_setfaction(u, f); + } + if (u->faction) { + ++u->faction->no_units; + } else { + log_error("unit %s has faction == NULL\n", unitname(u)); + assert(u->faction); + return 0; + } READ_STR(data->store, obuf, sizeof(obuf)); u->name = _strdup(obuf); @@ -614,6 +628,11 @@ unit *read_unit(struct gamedata *data) u->display = _strdup(obuf); } READ_INT(data->store, &number); + set_number(u, number); + + + + READ_INT(data->store, &n); u->age = (short)n; @@ -660,16 +679,6 @@ unit *read_unit(struct gamedata *data) } } } - if (u->faction == NULL) { - log_error("unit %s has faction == NULL\n", unitname(u)); - u_setfaction(u, get_monsters()); - set_number(u, 0); - } - - if (count_unit(u) && u->faction) - u->faction->no_units++; - - set_number(u, number); READ_INT(data->store, &n); if (n > 0) { diff --git a/src/kernel/unit.c b/src/kernel/unit.c index 568d8161f..8f7f20262 100644 --- a/src/kernel/unit.c +++ b/src/kernel/unit.c @@ -1074,9 +1074,7 @@ void u_setfaction(unit * u, faction * f) if (u->faction == f) return; if (u->faction) { - if (count_unit(u)) { - --u->faction->no_units; - } + --u->faction->no_units; set_number(u, 0); join_group(u, NULL); free_orders(&u->orders); @@ -1112,7 +1110,7 @@ void u_setfaction(unit * u, faction * f) if (cnt) { set_number(u, cnt); } - if (f && count_unit(u)) { + if (f) { ++f->no_units; } } @@ -1126,7 +1124,7 @@ void set_number(unit * u, int count) if (count == 0) { u->flags &= ~(UFL_HERO); } - if (u->faction && playerrace(u_race(u))) { + if (u->faction) { u->faction->num_people += count - u->number; } u->number = (unsigned short)count; diff --git a/src/laws.c b/src/laws.c index 040d212b0..764afa511 100755 --- a/src/laws.c +++ b/src/laws.c @@ -3482,33 +3482,32 @@ static int maxunits(const faction * f) int checkunitnumber(const faction * f, int add) { - int alimit, flimit; - - alimit = rule_alliance_limit(); - if (alimit) { - /* if unitsperalliance is true, maxunits returns the - number of units allowed in an alliance */ - faction *f2; - int unitsinalliance = add; - - for (f2 = factions; f2; f2 = f2->next) { - if (f->alliance == f2->alliance) { - unitsinalliance += f2->no_units; - } - if (unitsinalliance > alimit) { - return 1; - } + int alimit, flimit; + int flags = COUNT_DEFAULT|COUNT_MIGRANTS|COUNT_UNITS; + int fno = count_faction(f, flags) + add; + flimit = rule_faction_limit(); + if (flimit && fno > flimit) { + return 2; } - } - flimit = rule_faction_limit(); - if (flimit) { - if (f->no_units + add > flimit) { - return 2; + alimit = rule_alliance_limit(); + if (alimit) { + /* if unitsperalliance is true, maxunits returns the + number of units allowed in an alliance */ + faction *f2; + int unitsinalliance = fno; + + for (f2 = factions; f2; f2 = f2->next) { + if (f != f2 && f->alliance == f2->alliance) { + unitsinalliance += count_faction(f2, flags); + if (unitsinalliance > alimit) { + return 1; + } + } + } } - } - return 0; + return 0; } void new_units(void) diff --git a/src/summary.c b/src/summary.c index ad62181a6..f7a33444b 100644 --- a/src/summary.c +++ b/src/summary.c @@ -93,11 +93,11 @@ static void out_faction(FILE * file, const struct faction *f) fprintf(file, "%s (%s/%d) (%.3s/%.3s), %d Einh., %d Pers., $%d, %d NMR\n", f->name, itoa36(f->no), f_get_alliance(f) ? f->alliance->id : 0, LOC(default_locale, rc_name(f->race, 0)), magic_school[f->magiegebiet], - f->no_units, f->num_total, f->money, turn - f->lastorders); + count_units(f), f->num_total, f->money, turn - f->lastorders); } else { fprintf(file, "%s (%.3s/%.3s), %d Einh., %d Pers., $%d, %d NMR\n", factionname(f), LOC(default_locale, rc_name(f->race, 0)), - magic_school[f->magiegebiet], f->no_units, f->num_total, f->money, + magic_school[f->magiegebiet], count_units(f), f->num_total, f->money, turn - f->lastorders); } }