diff --git a/src/creport.c b/src/creport.c index d6cc403cd..881edc870 100644 --- a/src/creport.c +++ b/src/creport.c @@ -1047,7 +1047,7 @@ static void show_allies_cr(FILE * F, const faction * f, const group *g) data.F = F; data.f = f; struct ally *sf = g ? g->allies : f->allies; - allies_walk(sf, print_ally_cb, &data); + ally_walk(sf, print_ally_cb, &data); } /* prints allies */ diff --git a/src/kernel/ally.c b/src/kernel/ally.c index 1d83c331f..636985410 100644 --- a/src/kernel/ally.c +++ b/src/kernel/ally.c @@ -19,6 +19,105 @@ #include #include +#define BLOCKSIZE 15 +typedef struct allies { + struct allies *next; + int num; + const struct faction *factions[BLOCKSIZE]; + int status[BLOCKSIZE]; +} allies; + +static void block_insert(allies *al, const struct faction *f, int status) { + int i = al->num++; + al->status[i] = status; + al->factions[i] = f; + /* TODO: heapify */ +} + +static int block_search(allies *al, const struct faction *f) { + int i; + /* TODO: binary search */ + for (i = 0; i != al->num; ++i) { + if (al->factions[i] == f) { + return i; + } + } + return BLOCKSIZE; +} + +int allies_get(allies *al, const struct faction *f) +{ + for (; al; al = al->next) { + int i = block_search(al, f); + if (i != BLOCKSIZE) { + return al->status[i]; + } + } + return 0; +} + +void allies_set(allies **p_al, const struct faction *f, int status) +{ + while (*p_al) { + allies *al = *p_al; + int i = block_search(al, f); + if (i != BLOCKSIZE) { + if (status == 0) { + if (--al->num != i) { + al->factions[i] = al->factions[al->num]; + al->status[i] = al->status[al->num]; + /* TODO: repair heap up or down */ + } + else if (al->num == 0) { + *p_al = al->next; + free(al); + return; + } + } + else { + al->status[i] = status; + } + return; + } + if (al->num < BLOCKSIZE) { + block_insert(al, f, status); + return; + } + p_al = &al->next; + } + *p_al = calloc(1, sizeof(allies)); + block_insert(*p_al, f, status); +} + +void allies_write(gamedata * data, const allies *alist) +{ + const allies *al; + for (al = alist; al; al = al->next) { + int i; + for (i = 0; i != al->num; ++i) { + const faction * f = al->factions[i]; + if (f && f->_alive) { + write_faction_reference(f, data->store); + WRITE_INT(data->store, al->status[i]); + } + } + } + write_faction_reference(NULL, data->store); +} + +void allies_read(gamedata * data, allies **sfp) +{ + for (;;) { + int aid, state; + READ_INT(data->store, &aid); + /* TODO: deal with unresolved factions, somehow */ + if (aid >=0) { + break; + } + READ_INT(data->store, &state); + } +} + typedef struct ally { struct ally *next; struct faction *faction; @@ -47,7 +146,7 @@ void allies_free(ally *al) } } -ally *allies_clone(const ally *al) { +ally *ally_clone(const ally *al) { ally *al_clone = NULL, **al_end = &al_clone; for (; al; al = al->next) { @@ -60,7 +159,7 @@ ally *allies_clone(const ally *al) { return al_clone; } -int allies_walk(ally *allies, cb_allies_walk callback, void *udata) +int ally_walk(ally *allies, cb_ally_walk callback, void *udata) { ally *al; for (al = allies; al; al = al->next) { diff --git a/src/kernel/ally.h b/src/kernel/ally.h index 19fc0915c..25b488dac 100644 --- a/src/kernel/ally.h +++ b/src/kernel/ally.h @@ -29,14 +29,20 @@ extern "C" { struct gamedata; struct unit; struct ally; + struct allies; extern struct attrib_type at_npcfaction; + int allies_get(struct allies *al, const struct faction *f); + void allies_set(struct allies **p_al, const struct faction *f, int status); + void allies_write(struct gamedata * data, const struct allies *alist); + void allies_read(struct gamedata * data, struct allies **sfp); + void read_allies(struct gamedata * data, struct ally **alist); void write_allies(struct gamedata * data, const struct ally *alist); - typedef int (*cb_allies_walk)(struct ally *, struct faction *, int, void *); - int allies_walk(struct ally *allies, cb_allies_walk callback, void *udata); - struct ally *allies_clone(const struct ally *al); + typedef int (*cb_ally_walk)(struct ally *, struct faction *, int, void *); + int ally_walk(struct ally *allies, cb_ally_walk callback, void *udata); + struct ally *ally_clone(const struct ally *al); void allies_free(struct ally *al); struct ally* ally_find(struct ally*al, const struct faction *f); diff --git a/src/kernel/ally.test.c b/src/kernel/ally.test.c index 7aaf50fa7..92011c566 100644 --- a/src/kernel/ally.test.c +++ b/src/kernel/ally.test.c @@ -30,10 +30,10 @@ static void test_allies_clone(CuTest * tc) test_setup(); f = test_create_faction(NULL); - CuAssertPtrEquals(tc, NULL, allies_clone(NULL)); + CuAssertPtrEquals(tc, NULL, ally_clone(NULL)); ally_set(&al, f, HELP_GUARD); - ac = allies_clone(al); + ac = ally_clone(al); CuAssertPtrNotNull(tc, ac); CuAssertTrue(tc, al != ac); CuAssertIntEquals(tc, HELP_GUARD, ally_get(ac, f)); @@ -43,10 +43,27 @@ static void test_allies_clone(CuTest * tc) test_teardown(); } +static void test_allies(CuTest *tc) { + struct allies * al = NULL; + struct faction * f; + + test_setup(); + f = test_create_faction(NULL); + + CuAssertIntEquals(tc, 0, allies_get(al, f)); + allies_set(&al, f, 42); + CuAssertIntEquals(tc, 42, allies_get(al, f)); + allies_set(&al, f, 0); + CuAssertIntEquals(tc, 0, allies_get(al, f)); + CuAssertPtrEquals(tc, NULL, al); + test_teardown(); +} + CuSuite *get_ally_suite(void) { CuSuite *suite = CuSuiteNew(); SUITE_ADD_TEST(suite, test_ally); + SUITE_ADD_TEST(suite, test_allies); SUITE_ADD_TEST(suite, test_allies_clone); return suite; } diff --git a/src/kernel/group.c b/src/kernel/group.c index 210f6e0f2..9e91d17a1 100755 --- a/src/kernel/group.c +++ b/src/kernel/group.c @@ -69,7 +69,7 @@ group *new_group(faction * f, const char *name, int gid) static void init_group(faction * f, group * g) { - g->allies = allies_clone(f->allies); + g->allies = ally_clone(f->allies); } static group *find_groupbyname(group * g, const char *name) diff --git a/src/report.c b/src/report.c index ffe9d072d..1bba84307 100644 --- a/src/report.c +++ b/src/report.c @@ -1587,7 +1587,7 @@ static void show_allies(const faction * f, struct ally * allies, char *buf, size_t size) { int num_allies = 0; - allies_walk(allies, count_allies_cb, &num_allies); + ally_walk(allies, count_allies_cb, &num_allies); if (num_allies > 0) { struct show_s show; @@ -1595,7 +1595,7 @@ show_allies(const faction * f, struct ally * allies, char *buf, size_t size) show.num_allies = num_allies; sbs_init(&show.sbs, buf, size); - allies_walk(allies, show_allies_cb, &show); + ally_walk(allies, show_allies_cb, &show); sbs_strcat(&show.sbs, "."); } }