diff --git a/src/kernel/ally.c b/src/kernel/ally.c index 759d556f4..b4385088a 100644 --- a/src/kernel/ally.c +++ b/src/kernel/ally.c @@ -10,10 +10,33 @@ #include "plane.h" #include +#include + +#include + #include #include #include +void read_allies(gamedata * data, faction *f) +{ + ally **sfp = &f->allies; + for (;;) { + int aid; + ally * al = ally_add(sfp, NULL); + aid = read_faction_reference(data, &al->faction, NULL); + if (aid > 0) { + int state; + READ_INT(data->store, &state); + al->status = state & HELP_ALL; + sfp = &al->next; + } + else { + break; + } + } +} + ally * ally_find(ally *al, const struct faction *f) { for (; al; al = al->next) { if (al->faction == f) return al; diff --git a/src/kernel/ally.h b/src/kernel/ally.h index 58d6ff4a8..d4c41d36c 100644 --- a/src/kernel/ally.h +++ b/src/kernel/ally.h @@ -26,7 +26,9 @@ extern "C" { struct attrib_type; struct plane; struct faction; + struct gamedata; struct unit; + extern struct attrib_type at_npcfaction; typedef struct ally { @@ -35,6 +37,7 @@ extern "C" { int status; } ally; + void read_allies(struct gamedata * data, struct faction *f); ally * ally_find(ally *al, const struct faction *f); ally * ally_add(ally **al_p, struct faction *f); void ally_remove(ally **al_p, struct faction *f); diff --git a/src/kernel/save.c b/src/kernel/save.c index 064983127..d12c6cdaa 100644 --- a/src/kernel/save.c +++ b/src/kernel/save.c @@ -1152,31 +1152,6 @@ void write_region(gamedata *data, const region *r) writeregion(data, r); } -static ally **addally(const faction * f, ally ** sfp, int aid, int state) -{ - struct faction *af = findfaction(aid); - ally *sf; - - state &= ~HELP_OBSERVE; - state &= ~HELP_TRAVEL; - state &= HelpMask(); - - if (state == 0) - return sfp; - - while (*sfp) { - sfp = &(*sfp)->next; - } - - sf = ally_add(sfp, af); - if (!sf->faction) { - ur_add(aid, &sf->faction, NULL); - } - sf->status = state & HELP_ALL; - - return &sf->next; -} - int get_spell_level_faction(const spell * sp, void * cbdata) { static spellbook * common = 0; @@ -1385,18 +1360,7 @@ faction *read_faction(gamedata * data) f->options &= ~want(O_JSON); } sfp = &f->allies; - for (;;) { - int aid = 0; - READ_INT(data->store, &aid); - if (aid > 0) { - int state; - READ_INT(data->store, &state); - sfp = addally(f, sfp, aid, state); - } - else { - break; - } - } + read_allies(data, f); read_groups(data, f); f->spellbook = 0; if (data->version >= REGIONOWNER_VERSION) { diff --git a/src/spells.c b/src/spells.c index 52acc54ed..9d5481a60 100644 --- a/src/spells.c +++ b/src/spells.c @@ -2892,46 +2892,20 @@ static curse *mk_deathcloud(unit * mage, region * r, double force, int duration) return c; } -#define COMPAT_DEATHCLOUD -#ifdef COMPAT_DEATHCLOUD static int dc_read_compat(struct attrib *a, void *target, gamedata *data) /* return AT_READ_OK on success, AT_READ_FAIL if attrib needs removal */ { struct storage *store = data->store; - region *r = NULL; - unit *u; - int id; - int duration; - float strength; - int rx, ry; UNUSED_ARG(a); UNUSED_ARG(target); - READ_INT(store, &duration); - READ_FLT(store, &strength); - READ_INT(store, &id); - u = findunit(id); - - /* this only affects really old data. no need to change: */ - READ_INT(store, &rx); - READ_INT(store, &ry); - r = findregion(rx, ry); - - if (r != NULL) { - double effect; - curse *c; - - effect = strength; - c = create_curse(u, &r->attribs, &ct_deathcloud, strength * 2, duration, - effect, 0); - c->data.v = r; - if (u == NULL) { - ur_add(id, &c->magician, NULL); - } - } - return AT_READ_FAIL; /* we don't care for the attribute. */ + READ_INT(store, NULL); + READ_FLT(store, NULL); + READ_INT(store, NULL); + READ_INT(store, NULL); + READ_INT(store, NULL); + return AT_READ_DEPR; /* we don't care for the attribute. */ } -#endif /* ------------------------------------------------------------- */ /* Name: Todeswolke @@ -6704,9 +6678,7 @@ void register_spells(void) { register_borders(); -#ifdef COMPAT_DEATHCLOUD at_deprecate("zauber_todeswolke", dc_read_compat); -#endif /* init_firewall(); */ ct_register(&ct_firewall); diff --git a/src/util/resolve.c b/src/util/resolve.c index 577afb98f..5f1787056 100644 --- a/src/util/resolve.c +++ b/src/util/resolve.c @@ -17,69 +17,85 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. **/ #include + +#include + #include #include +#include + #include "resolve.h" #include "storage.h" #include "variant.h" typedef struct unresolved { - void **addr; - /* address to pass to the resolve-function */ - variant data; + int id; /* information on how to resolve the missing object */ resolve_fun resolve; /* function to resolve the unknown object */ + selist *addrs; + /* address to pass to the resolve-function */ } unresolved; -#define BLOCKSIZE 1024 -static unresolved *ur_list; -static unresolved *ur_begin; -static unresolved *ur_current; +#define HASHSIZE 1024 /* must be a power of 2 */ +static unresolved ur_hash[HASHSIZE]; + +int ur_key(int id) { + int h = id ^ (id >> 16); + return h & (HASHSIZE - 1); +} void ur_add(int id, void **addr, resolve_fun fun) { + int h, i; + + assert(id > 0); assert(addr); assert(!*addr); - if (ur_list == NULL) { - ur_list = malloc(BLOCKSIZE * sizeof(unresolved)); - ur_begin = ur_current = ur_list; + + h = ur_key(id); + for (i = 0; i != HASHSIZE; ++i) { + int k = h + i; + if (k >= HASHSIZE) k -= HASHSIZE; + if (ur_hash[k].id <= 0) { + ur_hash[k].id = id; + ur_hash[k].resolve = fun; + selist_push(&ur_hash[k].addrs, addr); + return; + } + if (ur_hash[k].id == id && ur_hash[k].resolve == fun) { + ur_hash[k].resolve = fun; + selist_push(&ur_hash[k].addrs, addr); + return; + } } - else if (ur_current - ur_begin == BLOCKSIZE - 1) { - ur_begin = malloc(BLOCKSIZE * sizeof(unresolved)); - ur_current->data.v = ur_begin; - ur_current = ur_begin; - } - ur_current->data.i = id; - ur_current->resolve = fun; - ur_current->addr = addr; + assert(!"hash table is full"); +} - ++ur_current; - ur_current->addr = NULL; - ur_current->data.v = NULL; +static bool addr_cb(void *data, void *more) { + void **addr = (void **)data; + *addr = more; + return true; } void resolve(int id, void *data) { - unresolved *ur = ur_list; - /* TODO: hella slow! hashing is better */ - while (ur) { - if (ur->addr == NULL) { - ur = ur->data.v; - free(ur_list); - ur_list = ur; - continue; - } - if (id == ur->data.i) { - if (ur->resolve) { - *ur->addr = ur->resolve(id, data); - } - else { - *ur->addr = data; + int h, i; + h = ur_key(id); + + for (i = 0; i != HASHSIZE; ++i) { + int k = h + i; + + if (k >= HASHSIZE) k -= HASHSIZE; + if (ur_hash[k].id == 0) break; + else if (ur_hash[k].id == id) { + if (ur_hash[k].resolve) { + data = ur_hash[k].resolve(id, data); } + selist_foreach_ex(ur_hash[k].addrs, addr_cb, data); + selist_free(ur_hash[k].addrs); + ur_hash[k].addrs = NULL; + ur_hash[k].id = -1; } - ++ur; } - free(ur_list); - ur_list = NULL; }