diff --git a/clibs b/clibs index d286006a2..da2c0cc39 160000 --- a/clibs +++ b/clibs @@ -1 +1 @@ -Subproject commit d286006a28c8aa7cd70ed7fd4cd172b50ade9727 +Subproject commit da2c0cc39b27c98ed8d31b0503426788fc236bd8 diff --git a/conf/e2/rules.xml b/conf/e2/rules.xml index 45b9030d3..22ff8109f 100644 --- a/conf/e2/rules.xml +++ b/conf/e2/rules.xml @@ -25,7 +25,7 @@ - + @@ -38,7 +38,7 @@ - + diff --git a/res/e3a/equipment.xml b/res/e3a/equipment.xml index 9fe133f48..62123766a 100644 --- a/res/e3a/equipment.xml +++ b/res/e3a/equipment.xml @@ -1,7 +1,7 @@ - + diff --git a/res/e3a/familiars.xml b/res/e3a/familiars.xml index 775546099..4a9fad6c8 100644 --- a/res/e3a/familiars.xml +++ b/res/e3a/familiars.xml @@ -2,27 +2,27 @@ - + - + - + - + - + @@ -30,7 +30,7 @@ - + @@ -42,7 +42,7 @@ - + @@ -53,11 +53,11 @@ - + - + @@ -65,7 +65,7 @@ - + @@ -73,14 +73,14 @@ - + - + @@ -88,15 +88,15 @@ - + - + - + diff --git a/res/eressea/equipment.xml b/res/eressea/equipment.xml index efd4f2a3b..e4d48aefe 100644 --- a/res/eressea/equipment.xml +++ b/res/eressea/equipment.xml @@ -2,18 +2,18 @@ - + - + - + @@ -21,30 +21,30 @@ - + - + - + - + - + - + @@ -58,18 +58,18 @@ - + - + - + @@ -79,53 +79,53 @@ - + - + - + - + - + - + - + - + - + @@ -136,57 +136,57 @@ - + - - - - + + + + - + - + - + - + - + - + - + - + - - - + + + @@ -195,56 +195,52 @@ - + - + - + - + - + - + - - + + - - - - - + - + - + - + @@ -252,24 +248,24 @@ - + - + - + - + diff --git a/res/eressea/familiars.xml b/res/eressea/familiars.xml index 8503123cb..7e9bb75dc 100644 --- a/res/eressea/familiars.xml +++ b/res/eressea/familiars.xml @@ -2,26 +2,26 @@ - + - + - + - + @@ -29,7 +29,7 @@ - + @@ -37,7 +37,7 @@ - + @@ -54,7 +54,7 @@ - + @@ -67,12 +67,12 @@ - + - + @@ -80,7 +80,7 @@ - + @@ -92,7 +92,7 @@ - + @@ -103,7 +103,7 @@ - + @@ -111,19 +111,19 @@ - + - + - + diff --git a/scripts/eressea/autoseed.lua b/scripts/eressea/autoseed.lua index 10a33627f..fc658d1a1 100644 --- a/scripts/eressea/autoseed.lua +++ b/scripts/eressea/autoseed.lua @@ -65,9 +65,9 @@ local function seed(r, email, race, lang) assert(f) local u = unit.create(f, r) assert(u) - equip_unit(u, "autoseed_faction") - equip_unit(u, "autoseed_unit") - equip_unit(u, "autoseed_" .. race, 7) + equip_unit(u, "seed_faction") + equip_unit(u, "seed_unit") + equip_unit(u, "seed_" .. race, 7) unit.create(f, r, 5):set_skill("mining", 30) unit.create(f, r, 5):set_skill("quarrying", 30) f:set_origin(r) diff --git a/scripts/tests/process.lua b/scripts/tests/process.lua index c5515be0b..296b9d5ec 100644 --- a/scripts/tests/process.lua +++ b/scripts/tests/process.lua @@ -18,8 +18,9 @@ local function file_exists(name) if f~=nil then io.close(f) return true else return false end end -local function assert_file(filename) - assert_equal(true, file_exists(filename)) +local function assert_file(filename, exists) + if exists == nil then exists = true end + assert_equal(exists, file_exists(filename)) os.remove(filename) end @@ -30,9 +31,9 @@ function test_process_turn() assert_equal(0, write_reports()) assert_equal(0, eressea.write_game("test.dat")) assert_file("data/test.dat") - assert_file("reports/" .. get_turn() .. "-ii.nr") - assert_file("reports/" .. get_turn() .. "-ii.cr") - assert_file("reports/" .. get_turn() .. "-ii.txt") + assert_file("reports/" .. get_turn() .. "-ii.nr", false) + assert_file("reports/" .. get_turn() .. "-ii.cr", false) + assert_file("reports/" .. get_turn() .. "-ii.txt", false) assert_file("reports/" .. get_turn() .. "-777.nr") assert_file("reports/" .. get_turn() .. "-777.cr") assert_file("reports/" .. get_turn() .. "-777.txt") diff --git a/src/attributes/attributes.c b/src/attributes/attributes.c index 610bea684..f003c2cde 100644 --- a/src/attributes/attributes.c +++ b/src/attributes/attributes.c @@ -96,7 +96,7 @@ static int obs_read(struct attrib *a, void *owner, struct gamedata *data) { obs_data *od = (obs_data *)a->data.v; - read_reference(&od->f, data, read_faction_reference, resolve_faction); + read_faction_reference(data, &od->f, NULL); READ_INT(data->store, &od->skill); READ_INT(data->store, &od->timer); return AT_READ_OK; diff --git a/src/attributes/follow.c b/src/attributes/follow.c index d68fcaebd..e0741646b 100644 --- a/src/attributes/follow.c +++ b/src/attributes/follow.c @@ -30,7 +30,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. static int read_follow(attrib * a, void *owner, gamedata *data) { - read_unit_reference(data); /* skip it */ + READ_INT(data->store, NULL); /* skip it */ return AT_READ_FAIL; } diff --git a/src/attributes/hate.c b/src/attributes/hate.c index 17155fc71..7cba12514 100644 --- a/src/attributes/hate.c +++ b/src/attributes/hate.c @@ -45,9 +45,7 @@ write_hate(const attrib * a, const void *owner, struct storage *store) static int read_hate(attrib * a, void *owner, gamedata *data) { - int result = read_reference(&a->data.v, data, read_unit_reference, - resolve_unit); - if (result == 0 && !a->data.v) { + if (read_unit_reference(data, (unit **)&a->data.v, NULL) <= 0) { return AT_READ_FAIL; } return AT_READ_OK; diff --git a/src/attributes/key.c b/src/attributes/key.c index 6841bbd71..00f81a80e 100644 --- a/src/attributes/key.c +++ b/src/attributes/key.c @@ -67,8 +67,12 @@ static int keys_size(int n) { assert(n > 0 && n <= 4096); if (n <= 1) return 1; if (n <= 4) return 4; + if (n <= 8) return 8; if (n <= 16) return 16; if (n <= 256) return 256; + if (n <= 512) return 512; + if (n <= 1024) return 1024; + if (n <= 2048) return 2048; return 4096; } diff --git a/src/attributes/targetregion.c b/src/attributes/targetregion.c index f61214dfc..29e76f557 100644 --- a/src/attributes/targetregion.c +++ b/src/attributes/targetregion.c @@ -36,10 +36,9 @@ write_targetregion(const attrib * a, const void *owner, struct storage *store) static int read_targetregion(attrib * a, void *owner, gamedata *data) { - int result = read_reference(&a->data.v, data, read_region_reference, - RESOLVE_REGION(data->version)); - if (result == 0 && !a->data.v) + if (read_region_reference(data, (region **)&a->data.v, NULL) <= 0) { return AT_READ_FAIL; + } return AT_READ_OK; } diff --git a/src/battle.c b/src/battle.c index be513f288..ad1c0f8da 100644 --- a/src/battle.c +++ b/src/battle.c @@ -927,7 +927,7 @@ void kill_troop(troop dt) if (drops != NULL) { i_merge(&du->items, &drops); } - sprintf(eqname, "%s_spoils", rc->_name); + sprintf(eqname, "spo_%s", rc->_name); eq = get_equipment(eqname); if (eq != NULL) { equip_items(&du->items, eq); diff --git a/src/building_action.c b/src/building_action.c index f72af4412..28cd55a48 100644 --- a/src/building_action.c +++ b/src/building_action.c @@ -86,8 +86,7 @@ static void lc_done(struct attrib *a) free(data); } -static void -lc_write(const struct attrib *a, const void *owner, struct storage *store) +static void lc_write(const struct attrib *a, const void *owner, struct storage *store) { building_action *data = (building_action *)a->data.v; const char *fname = data->fname; @@ -106,8 +105,7 @@ static int lc_read(struct attrib *a, void *owner, gamedata *data) building *b = (building *)owner; int result = 0; if (data->version < ATTRIBOWNER_VERSION) { - result = read_reference(&b, data, read_building_reference, resolve_building); - assert(b == owner); + READ_INT(data->store, NULL); } READ_TOK(store, name, sizeof(name)); if (strcmp(name, "tunnel_action") == 0) { diff --git a/src/creport.c b/src/creport.c index 12cb4e5b5..b68f3e4fe 100644 --- a/src/creport.c +++ b/src/creport.c @@ -1365,8 +1365,8 @@ static void cr_output_region(FILE * F, report_context * ctx, region * r) unit *u; int stealthmod = stealth_modifier(r->seen.mode); - if (r->display && r->display[0]) - fprintf(F, "\"%s\";Beschr\n", r->display); + if (r->land && r->land->display && r->land->display[0]) + fprintf(F, "\"%s\";Beschr\n", r->land->display); if (fval(r->terrain, LAND_REGION)) { assert(r->land); fprintf(F, "%d;Bauern\n", rpeasants(r)); diff --git a/src/economy.c b/src/economy.c index 74595a335..7c4b0efd3 100644 --- a/src/economy.c +++ b/src/economy.c @@ -266,7 +266,6 @@ void add_recruits(unit * u, int number, int wanted) strlcpy(equipment, "new_", sizeof(equipment)); strlcat(equipment, u_race(u)->_name, sizeof(equipment)); - strlcat(equipment, "_unit", sizeof(equipment)); equip_unit(unew, get_equipment(equipment)); if (unew != u) { diff --git a/src/give.c b/src/give.c index b55e6687b..18d355031 100644 --- a/src/give.c +++ b/src/give.c @@ -418,10 +418,12 @@ message * give_men(int n, unit * u, unit * u2, struct order *ord) set_racename(&u2->attribs, get_racename(u->attribs)); u_setrace(u2, u_race(u)); u2->irace = u->irace; - if (fval(u, UFL_HERO)) + if (fval(u, UFL_HERO)) { fset(u2, UFL_HERO); - else + } + else { freset(u2, UFL_HERO); + } } /* Einheiten von Schiffen können nicht NACH in von diff --git a/src/helpers.c b/src/helpers.c index 7591dba9f..5f73ac542 100644 --- a/src/helpers.c +++ b/src/helpers.c @@ -20,6 +20,7 @@ without prior permission by the authors of Eressea. #include #include #include +#include #include #include #include @@ -290,10 +291,10 @@ use_item_lua(unit *u, const item_type *itype, int amount, struct order *ord) } /* compat code for old data files */ -static int caldera_read(trigger *t, struct gamedata *data) +static int caldera_read(trigger *t, gamedata *data) { UNUSED_ARG(t); - read_building_reference(data); + READ_INT(data->store, NULL); return AT_READ_FAIL; } diff --git a/src/kernel/ally.c b/src/kernel/ally.c index 759d556f4..73f198091 100644 --- a/src/kernel/ally.c +++ b/src/kernel/ally.c @@ -7,13 +7,40 @@ #include "region.h" #include "group.h" #include "faction.h" +#include "objtypes.h" #include "plane.h" #include +#include + +#include + #include #include #include +void read_allies(gamedata * data, faction *f) +{ + ally **sfp = &f->allies; + for (;;) { + int aid; + READ_INT(data->store, &aid); + if (aid > 0) { + ally * al = ally_add(sfp, NULL); + int state; + if ((al->faction = findfaction(aid)) == NULL) { + ur_add(RESOLVE_FACTION | aid, (void **)&al->faction, NULL); + } + 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/building.c b/src/kernel/building.c index 45faccdab..57b8a91e2 100644 --- a/src/kernel/building.c +++ b/src/kernel/building.c @@ -322,25 +322,26 @@ void write_building_reference(const struct building *b, struct storage *store) WRITE_INT(store, (b && b->region) ? b->no : 0); } -int resolve_building(variant id, void *address) +void resolve_building(building *b) { - int result = 0; - building *b = NULL; - if (id.i != 0) { - b = findbuilding(id.i); - if (b == NULL) { - result = -1; - } - } - *(building **)address = b; - return result; + resolve(RESOLVE_BUILDING | b->no, b); } -variant read_building_reference(gamedata * data) +int read_building_reference(gamedata * data, building **bp, resolve_fun fun) { - variant result; - READ_INT(data->store, &result.i); - return result; + int id; + READ_INT(data->store, &id); + if (id > 0) { + *bp = findbuilding(id); + if (*bp == NULL) { + *bp = NULL; + ur_add(RESOLVE_BUILDING | id, (void**)bp, fun); + } + } + else { + *bp = NULL; + } + return id; } building *new_building(const struct building_type * btype, region * r, diff --git a/src/kernel/building.h b/src/kernel/building.h index 04ad08262..af29c324b 100644 --- a/src/kernel/building.h +++ b/src/kernel/building.h @@ -20,7 +20,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #define H_KRNL_BUILDING #include -#include +#include #include #include @@ -152,10 +152,11 @@ extern "C" { #include "build.h" #define NOBUILDING NULL - int resolve_building(variant data, void *address); +#define RESOLVE_BUILDING (TYP_BUILDING << 24) + void resolve_building(building *b); void write_building_reference(const struct building *b, struct storage *store); - variant read_building_reference(struct gamedata *data); + int read_building_reference(struct gamedata * data, struct building **bp, resolve_fun fun); struct building *findbuilding(int n); diff --git a/src/kernel/connection.c b/src/kernel/connection.c index 43caee729..b630429fe 100644 --- a/src/kernel/connection.c +++ b/src/kernel/connection.c @@ -606,37 +606,26 @@ int read_borders(gamedata *data) { struct storage *store = data->store; for (;;) { - int bid = 0; + int fid, tid, bid; char zText[32]; region *from, *to; border_type *type; READ_TOK(store, zText, sizeof(zText)); - if (!strcmp(zText, "end")) + if (!strcmp(zText, "end")) { break; + } + READ_INT(store, &bid); type = find_bordertype(zText); if (type == NULL) { log_error("[read_borders] connection %d type %s is not registered", bid, zText); assert(type || !"connection type not registered"); } - READ_INT(store, &bid); - if (data->version < UIDHASH_VERSION) { - int fx, fy, tx, ty; - READ_INT(store, &fx); - READ_INT(store, &fy); - READ_INT(store, &tx); - READ_INT(store, &ty); - from = findregion(fx, fy); - to = findregion(tx, ty); - } - else { - int fid, tid; - READ_INT(store, &fid); - READ_INT(store, &tid); - from = findregionbyid(fid); - to = findregionbyid(tid); - } + READ_INT(store, &fid); + READ_INT(store, &tid); + from = findregionbyid(fid); + to = findregionbyid(tid); if (!to || !from) { log_error("%s connection %d has missing regions", zText, bid); if (type->read) { @@ -660,19 +649,6 @@ int read_borders(gamedata *data) b->id = bid; assert(bid <= nextborder); type->read(b, data); - if (data->version < NOBORDERATTRIBS_VERSION) { - attrib *a = NULL; - int result = read_attribs(data, &a, b); - if (border_convert_cb) { - border_convert_cb(b, a); - } - while (a) { - a_remove(&a, a); - } - if (result < 0) { - return result; - } - } if (!type->write) { log_warning("invalid border '%s' between '%s' and '%s'\n", zText, regionname(from, 0), regionname(to, 0)); } diff --git a/src/kernel/curse.c b/src/kernel/curse.c index 9702d7649..499db9e93 100644 --- a/src/kernel/curse.c +++ b/src/kernel/curse.c @@ -191,12 +191,7 @@ int curse_read(attrib * a, void *owner, gamedata *data) READ_INT(store, &c->duration); READ_FLT(store, &flt); c->vigour = flt; - if (data->version < INTPAK_VERSION) { - ur = resolve_unit(read_int(data->store), &c->magician); - } - else { - ur = read_reference(&c->magician, data, read_unit_reference, resolve_unit); - } + ur = read_unit_reference(data, &c->magician, NULL); if (data->version < CURSEFLOAT_VERSION) { READ_INT(store, &n); c->effect = (float)n; @@ -231,9 +226,7 @@ int curse_read(attrib * a, void *owner, gamedata *data) READ_INT(store, &c->data.i); } if (c->type->typ == CURSETYP_REGION) { - int rr = - read_reference(&c->data.v, data, read_region_reference, - RESOLVE_REGION(data->version)); + int rr = read_region_reference(data, (region **)&c->data.v, NULL); if (ur == 0 && rr == 0 && !c->data.v) { return AT_READ_FAIL; } diff --git a/src/kernel/equipment.c b/src/kernel/equipment.c index 11fe594f5..b87f401dd 100644 --- a/src/kernel/equipment.c +++ b/src/kernel/equipment.c @@ -30,6 +30,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. /* util includes */ #include #include +#include #include #include @@ -202,38 +203,85 @@ void free_ls(void *arg) { static critbit_tree cb_equipments = { 0 }; +#define EQNAMELEN 24 + +typedef struct eq_entry { + char key[EQNAMELEN]; + equipment *value; +} eq_entry; + +typedef struct name_cb_data { + const equipment *find; + const char *result; +} name_cb_data; + + +static int equipment_name_cb(const void * match, const void * key, size_t keylen, void *cbdata) { + const eq_entry *ent = (const eq_entry *)match; + name_cb_data *query = (name_cb_data *)cbdata; + if (ent->value == query->find) { + query->result = ent->key; + return 1; + } + return 0; +} + +const char *equipment_name(const struct equipment *eq) +{ + name_cb_data data; + + data.find = eq; + data.result = NULL; + cb_foreach(&cb_equipments, "", 0, equipment_name_cb, &data); + return data.result; +} + equipment *get_equipment(const char *eqname) { - const char *match; - equipment *eq = NULL; + const void *match; + + if (strlen(eqname) >= EQNAMELEN) { + log_warning("equipment name is longer than %d bytes: %s", EQNAMELEN - 1, eqname); + return NULL; + } match = cb_find_str(&cb_equipments, eqname); if (match) { - cb_get_kv(match, &eq, sizeof(eq)); + const eq_entry *ent = (const eq_entry *)match; + return ent->value; } - return eq; + return NULL; +} + +equipment *create_equipment(const char *eqname) +{ + size_t len = strlen(eqname); + eq_entry ent; + + if (len >= EQNAMELEN) { + log_error("equipment name is longer than %d bytes: %s", EQNAMELEN-1, eqname); + len = EQNAMELEN-1; + } + memset(ent.key, 0, EQNAMELEN); + memcpy(ent.key, eqname, len); + + ent.value = (equipment *)calloc(1, sizeof(equipment)); + + cb_insert(&cb_equipments, &ent, sizeof(ent)); + return ent.value; } equipment *get_or_create_equipment(const char *eqname) { equipment *eq = get_equipment(eqname); if (!eq) { - size_t len; - char data[64]; - - eq = (equipment *)calloc(1, sizeof(equipment)); - eq->name = strdup(eqname); - - len = cb_new_kv(eqname, strlen(eqname), &eq, sizeof(eq), data); - assert(len <= sizeof(data)); - cb_insert(&cb_equipments, data, len); + return create_equipment(eqname); } return eq; } static void free_equipment(equipment *eq) { int i; - free(eq->name); if (eq->spells) { selist_foreach(eq->spells, free_ls); selist_free(eq->spells); @@ -251,10 +299,9 @@ static void free_equipment(equipment *eq) { } static int free_equipment_cb(const void * match, const void * key, size_t keylen, void *cbdata) { - equipment *eq; - cb_get_kv(match, &eq, sizeof(eq)); - free_equipment(eq); - free(eq); + const eq_entry * ent = (const eq_entry *)match; + free_equipment(ent->value); + free(ent->value); return 0; } diff --git a/src/kernel/equipment.h b/src/kernel/equipment.h index 928182dfb..9fbffe67f 100644 --- a/src/kernel/equipment.h +++ b/src/kernel/equipment.h @@ -45,7 +45,6 @@ extern "C" { } subset; typedef struct equipment { - char *name; struct itemdata *items; char *skills[MAXSKILLS]; struct selist *spells; @@ -55,8 +54,10 @@ extern "C" { void equipment_done(void); + const char *equipment_name(const struct equipment *eq); struct equipment *get_or_create_equipment(const char *eqname); struct equipment *get_equipment(const char *eqname); + struct equipment *create_equipment(const char *eqname); void equipment_setitem(struct equipment *eq, const struct item_type *itype, const char *value); diff --git a/src/kernel/equipment.test.c b/src/kernel/equipment.test.c index 1e6bf1819..7952001fe 100644 --- a/src/kernel/equipment.test.c +++ b/src/kernel/equipment.test.c @@ -10,7 +10,7 @@ #include #include -void test_equipment(CuTest * tc) +static void test_equipment(CuTest * tc) { equipment * eq; unit * u; @@ -46,9 +46,33 @@ void test_equipment(CuTest * tc) test_cleanup(); } +static void test_get_equipment(CuTest * tc) +{ + equipment * eq; + + test_setup(); + eq = create_equipment("catapultammo123"); + CuAssertPtrNotNull(tc, eq); + CuAssertStrEquals(tc, "catapultammo123", equipment_name(eq)); + eq = get_equipment("catapultammo123"); + CuAssertPtrNotNull(tc, eq); + CuAssertStrEquals(tc, "catapultammo123", equipment_name(eq)); + eq = get_equipment("catapult"); + CuAssertPtrEquals(tc, NULL, eq); + eq = create_equipment("catapult"); + eq = get_equipment("catapult"); + CuAssertPtrNotNull(tc, eq); + CuAssertStrEquals(tc, "catapult", equipment_name(eq)); + eq = get_equipment("catapultammo123"); + CuAssertPtrNotNull(tc, eq); + CuAssertStrEquals(tc, "catapultammo123", equipment_name(eq)); + test_cleanup(); +} + CuSuite *get_equipment_suite(void) { CuSuite *suite = CuSuiteNew(); SUITE_ADD_TEST(suite, test_equipment); + SUITE_ADD_TEST(suite, test_get_equipment); return suite; } diff --git a/src/kernel/faction.c b/src/kernel/faction.c index 736c9f4e6..98e49bd84 100755 --- a/src/kernel/faction.c +++ b/src/kernel/faction.c @@ -203,21 +203,6 @@ const char *factionname(const faction * f) return ibuf; } -int resolve_faction(variant id, void *address) -{ - int result = 0; - faction *f = NULL; - if (id.i != 0) { - f = findfaction(id.i); - if (f == NULL) { - result = -1; - } - } - assert(address); - *(faction **)address = f; - return result; -} - bool faction_id_is_unused(int id) { return findfaction(id) == NULL; @@ -332,10 +317,25 @@ bool checkpasswd(const faction * f, const char *passwd) return true; } -variant read_faction_reference(gamedata * data) +void resolve_faction(faction *f) { - variant id; - READ_INT(data->store, &id.i); + resolve(RESOLVE_FACTION | f->no, f); +} + +int read_faction_reference(gamedata * data, faction **fp, resolve_fun fun) +{ + int id; + READ_INT(data->store, &id); + if (id > 0) { + *fp = findfaction(id); + if (*fp == NULL) { + *fp = NULL; + ur_add(RESOLVE_FACTION | id, (void **)fp, fun); + } + } + else { + *fp = NULL; + } return id; } diff --git a/src/kernel/faction.h b/src/kernel/faction.h index 64832053b..a04acabfa 100644 --- a/src/kernel/faction.h +++ b/src/kernel/faction.h @@ -21,7 +21,10 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include "skill.h" #include "types.h" + +#include #include + #include #ifdef __cplusplus @@ -126,8 +129,10 @@ extern "C" { void write_faction_reference(const struct faction *f, struct storage *store); - variant read_faction_reference(struct gamedata *data); - int resolve_faction(variant data, void *addr); + int read_faction_reference(struct gamedata *data, struct faction **fp, resolve_fun fun); + +#define RESOLVE_FACTION (TYP_FACTION << 24) + void resolve_faction(struct faction *f); void renumber_faction(faction * f, int no); void free_factions(void); diff --git a/src/kernel/group.c b/src/kernel/group.c index 06f2f9f49..2c6b28bec 100755 --- a/src/kernel/group.c +++ b/src/kernel/group.c @@ -24,6 +24,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include "ally.h" #include "faction.h" #include "unit.h" +#include "objtypes.h" /* attrib includes */ #include @@ -238,16 +239,16 @@ void read_groups(gamedata *data, faction * f) g = new_group(f, buf, gid); pa = &g->allies; for (;;) { - ally *a; - variant fid; - - fid = read_faction_reference(data); - if (fid.i <= 0) - break; - a = ally_add(pa, findfaction(fid.i)); - READ_INT(store, &a->status); - if (!a->faction) - ur_add(fid, &a->faction, resolve_faction); + ally *al; + int id; + READ_INT(store, &id); + if (id == 0) break; + al = ally_add(pa, NULL); + al->faction = findfaction(id); + if (!al->faction) { + ur_add(RESOLVE_FACTION | id, (void **)&al->faction, NULL); + } + READ_INT(store, &al->status); } read_attribs(data, &g->attribs, g); } diff --git a/src/kernel/item.c b/src/kernel/item.c index 8639ac5d1..89c532297 100644 --- a/src/kernel/item.c +++ b/src/kernel/item.c @@ -60,6 +60,12 @@ static critbit_tree cb_resources; luxury_type *luxurytypes; potion_type *potiontypes; +#define RTYPENAMELEN 24 +typedef struct rt_entry { + char key[RTYPENAMELEN]; + struct resource_type *value; +} rt_entry; + static int res_changeaura(unit * u, const resource_type * rtype, int delta) { assert(rtype != NULL); @@ -166,13 +172,19 @@ static int num_resources; static void rt_register(resource_type * rtype) { - char buffer[64]; const char * name = rtype->_name; size_t len = strlen(name); + rt_entry ent; - assert(len < sizeof(buffer) - sizeof(rtype)); - len = cb_new_kv(name, len, &rtype, sizeof(rtype), buffer); - cb_insert(&cb_resources, buffer, len); + if (len >= RTYPENAMELEN) { + log_error("resource name is longer than %d bytes: %s", + RTYPENAMELEN-1, name); + len = RTYPENAMELEN-1; + } + ent.value = rtype; + memset(ent.key, 0, RTYPENAMELEN); + memcpy(ent.key, name, len); + cb_insert(&cb_resources, &ent, sizeof(ent)); ++num_resources; } @@ -186,22 +198,11 @@ resource_type *rt_get_or_create(const char *name) { else { rtype->_name = strdup(name); rt_register(rtype); - return rt_find(name); } } return rtype; } -static void it_register(item_type * itype) -{ - char buffer[64]; - const char * name = itype->rtype->_name; - size_t len = strlen(name); - - assert(len < sizeof(buffer) - sizeof(itype)); - len = cb_new_kv(name, len, &itype, sizeof(itype), buffer); -} - static const char *it_aliases[][2] = { { "Runenschwert", "runesword" }, { "p12", "truthpotion" }, @@ -244,7 +245,6 @@ item_type *it_get_or_create(resource_type *rtype) { rtype->uchange = res_changeitem; rtype->itype = itype; rtype->flags |= RTF_ITEM; - it_register(itype); return itype; } @@ -389,13 +389,20 @@ const potion_type *resource2potion(const resource_type * rtype) resource_type *rt_find(const char *name) { - void * match; - resource_type *result = 0; + const void *match; + size_t len = strlen(name); - if (cb_find_prefix(&cb_resources, name, strlen(name) + 1, &match, 1, 0)) { - cb_get_kv(match, &result, sizeof(result)); + if (len >= RTYPENAMELEN) { + log_warning("resource name is longer than %d bytes: %s", + RTYPENAMELEN-1, name); + return NULL; } - return result; + match = cb_find_str(&cb_resources, name); + if (match) { + const rt_entry *ent = (const rt_entry *)match; + return ent->value; + } + return NULL; } item **i_find(item ** i, const item_type * it) @@ -792,14 +799,14 @@ int change_money(unit * u, int v) return 0; } -static int add_resourcename_cb(const void * match, const void * key, size_t keylen, void *data) +static int add_resourcename_cb(const void * match, const void * key, + size_t keylen, void *data) { struct locale * lang = (struct locale *)data; int i = locale_index(lang); critbit_tree * cb = rnames + i; - resource_type *rtype; + resource_type *rtype = ((rt_entry *)match)->value; - cb_get_kv(match, &rtype, sizeof(rtype)); for (i = 0; i != 2; ++i) { char buffer[128]; const char * name = LOC(lang, resourcename(rtype, (i == 0) ? 0 : NMF_PLURAL)); @@ -835,20 +842,20 @@ const resource_type *findresourcetype(const char *name, const struct locale *lan else { log_debug("findresourcetype: transliterate failed for '%s'\n", name); } - return 0; + return NULL; } attrib_type at_showitem = { "showitem" }; -static int add_itemname_cb(const void * match, const void * key, size_t keylen, void *data) +static int add_itemname_cb(const void * match, const void * key, + size_t keylen, void *data) { struct locale * lang = (struct locale *)data; critbit_tree * cb = inames + locale_index(lang); - resource_type *rtype; + resource_type *rtype = ((rt_entry *)match)->value; - cb_get_kv(match, &rtype, sizeof(rtype)); if (rtype->itype) { int i; for (i = 0; i != 2; ++i) { @@ -980,9 +987,10 @@ void free_rtype(resource_type *rtype) { free(rtype); } -int free_rtype_cb(const void * match, const void * key, size_t keylen, void *cbdata) { - resource_type *rtype; - cb_get_kv(match, &rtype, sizeof(rtype)); +static int free_rtype_cb(const void * match, const void * key, + size_t keylen, void *cbdata) +{ + resource_type *rtype = ((rt_entry *)match)->value;; free_rtype(rtype); return 0; } diff --git a/src/kernel/item.test.c b/src/kernel/item.test.c index c1c64bf62..89954c451 100644 --- a/src/kernel/item.test.c +++ b/src/kernel/item.test.c @@ -173,12 +173,31 @@ static void test_core_resources(CuTest *tc) { test_cleanup(); } +static void test_get_resource(CuTest *tc) { + resource_type *rtype; + + test_setup(); + + CuAssertPtrEquals(tc, NULL, rt_find("catapultammo123")); + rtype = rt_get_or_create("catapultammo123"); + CuAssertPtrNotNull(tc, rtype); + CuAssertPtrEquals(tc, rtype, rt_find("catapultammo123")); + CuAssertStrEquals(tc, "catapultammo123", rtype->_name); + + CuAssertPtrEquals(tc, NULL, rt_find("catapult")); + rtype = rt_get_or_create("catapult"); + CuAssertPtrEquals(tc, rtype, rt_find("catapult")); + CuAssertStrEquals(tc, "catapult", rtype->_name); + test_cleanup(); +} + CuSuite *get_item_suite(void) { CuSuite *suite = CuSuiteNew(); SUITE_ADD_TEST(suite, test_resourcename_no_appearance); SUITE_ADD_TEST(suite, test_resourcename_with_appearance); SUITE_ADD_TEST(suite, test_change_item); + SUITE_ADD_TEST(suite, test_get_resource); SUITE_ADD_TEST(suite, test_resource_type); SUITE_ADD_TEST(suite, test_finditemtype); SUITE_ADD_TEST(suite, test_findresourcetype); diff --git a/src/kernel/messages.h b/src/kernel/messages.h index 4eca65fc1..58558072d 100644 --- a/src/kernel/messages.h +++ b/src/kernel/messages.h @@ -46,10 +46,10 @@ extern "C" { int level; } msglevel; - extern struct message *msg_message(const char *name, const char *sig, ...); - extern struct message *msg_feedback(const struct unit *, struct order *cmd, + struct message *msg_message(const char *name, const char *sig, ...); + struct message *msg_feedback(const struct unit *, struct order *cmd, const char *name, const char *sig, ...); - extern struct message *add_message(struct message_list **pm, + struct message *add_message(struct message_list **pm, struct message *m); void addmessage(struct region *r, struct faction *f, const char *s, msg_t mtype, int level); diff --git a/src/kernel/plane.c b/src/kernel/plane.c index 0b2fdc0d3..0dd6793f4 100644 --- a/src/kernel/plane.c +++ b/src/kernel/plane.c @@ -258,39 +258,6 @@ unsigned char index) return (rel + ursprung_y(f, pl, NULL) + plane_center_y(pl)); } -static int resolve_plane(variant id, void *addr) -{ - int result = 0; - plane *pl = NULL; - if (id.i != 0) { - pl = getplanebyid(id.i); - if (pl == NULL) { - result = -1; - } - } - *(plane **)addr = pl; - return result; -} - -void write_plane_reference(const plane * u, struct storage *store) -{ - WRITE_INT(store, u ? (u->id) : 0); -} - -int read_plane_reference(plane ** pp, struct storage *store) -{ - variant id; - READ_INT(store, &id.i); - if (id.i == 0) { - *pp = NULL; - return AT_READ_FAIL; - } - *pp = getplanebyid(id.i); - if (*pp == NULL) - ur_add(id, pp, resolve_plane); - return AT_READ_OK; -} - void free_plane(plane *pl) { free(pl->name); free(pl); diff --git a/src/kernel/plane.h b/src/kernel/plane.h index d06495f34..5b1c71644 100644 --- a/src/kernel/plane.h +++ b/src/kernel/plane.h @@ -69,8 +69,6 @@ extern "C" { struct plane *get_homeplane(void); int rel_to_abs(const struct plane *pl, const struct faction *f, int rel, unsigned char index); - void write_plane_reference(const plane * p, struct storage *store); - int read_plane_reference(plane ** pp, struct storage *store); int plane_width(const plane * pl); int plane_height(const plane * pl); void adjust_coordinates(const struct faction *f, int *x, int *y, const struct plane *pl); diff --git a/src/kernel/race.c b/src/kernel/race.c index 14fb66331..a73c0e699 100644 --- a/src/kernel/race.c +++ b/src/kernel/race.c @@ -561,21 +561,15 @@ void write_race_reference(const race * rc, struct storage *store) WRITE_TOK(store, rc ? rc->_name : "none"); } -variant read_race_reference(struct storage *store) +struct race * read_race_reference(struct storage *store) { - variant result; char zName[20]; READ_TOK(store, zName, sizeof(zName)); if (strcmp(zName, "none") == 0) { - result.v = NULL; - return result; + return NULL; } - else { - result.v = rc_find_i(zName); - } - assert(result.v != NULL); - return result; + return rc_find_i(zName); } void register_race_function(race_func func, const char *name) { diff --git a/src/kernel/race.h b/src/kernel/race.h index 2dec5f06b..2990c2158 100644 --- a/src/kernel/race.h +++ b/src/kernel/race.h @@ -263,7 +263,7 @@ extern "C" { void write_race_reference(const struct race *rc, struct storage *store); - variant read_race_reference(struct storage *store); + struct race *read_race_reference(struct storage *store); const char *raceprefix(const struct unit *u); void register_race_function(race_func, const char *); diff --git a/src/kernel/region.c b/src/kernel/region.c index e8da83c50..c7e3841fb 100644 --- a/src/kernel/region.c +++ b/src/kernel/region.c @@ -825,8 +825,8 @@ void free_land(land_region * lr) lr->demands = d->next; free(d); } - if (lr->name) - free(lr->name); + free(lr->name); + free(lr->display); free(lr); } @@ -894,7 +894,6 @@ void free_region(region * r) { if (last == r) last = NULL; - free(r->display); if (r->land) free_land(r->land); @@ -1088,7 +1087,6 @@ void terraform_region(region * r, const terrain_type * terrain) terraform_resources(r); if (!fval(terrain, LAND_REGION)) { - region_setinfo(r, NULL); if (r->land) { free_land(r->land); r->land = NULL; @@ -1257,46 +1255,22 @@ int production(const region * r) return p; } -int resolve_region_coor(variant id, void *address) +void resolve_region(region *r) { - region *r = findregion(id.sa[0], id.sa[1]); - if (r) { - *(region **)address = r; - return 0; - } - *(region **)address = NULL; - return -1; + resolve(RESOLVE_REGION | r->uid, r); } -int resolve_region_id(variant id, void *address) -{ - region *r = NULL; - if (id.i != 0) { - r = findregionbyid(id.i); - if (r == NULL) { - *(region **)address = NULL; - return -1; - } - } - *(region **)address = r; - return 0; -} - -variant read_region_reference(gamedata *data) +int read_region_reference(gamedata * data, region **rp, resolve_fun fun) { struct storage * store = data->store; - variant result; - if (data->version < UIDHASH_VERSION) { - int n; - READ_INT(store, &n); - result.sa[0] = (short)n; - READ_INT(store, &n); - result.sa[1] = (short)n; + int id = 0; + + READ_INT(store, &id); + *rp = findregionbyid(id); + if (*rp == NULL) { + ur_add(RESOLVE_REGION | id, (void **)rp, fun); } - else { - READ_INT(store, &result.i); - } - return result; + return id; } void write_region_reference(const region * r, struct storage *store) @@ -1444,13 +1418,14 @@ faction *update_owners(region * r) void region_setinfo(struct region *r, const char *info) { - free(r->display); - r->display = info ? strdup(info) : 0; + assert(r->land); + free(r->land->display); + r->land->display = (info && info[0]) ? strdup(info) : 0; } const char *region_getinfo(const region * r) { - return r->display ? r->display : ""; + return (r->land && r->land->display) ? r->land->display : ""; } void region_setname(struct region *r, const char *name) diff --git a/src/kernel/region.h b/src/kernel/region.h index c81411468..7f86f397f 100644 --- a/src/kernel/region.h +++ b/src/kernel/region.h @@ -19,11 +19,14 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #ifndef H_KRNL_REGION #define H_KRNL_REGION -#include -#include +#include + #include "types.h" #include "direction.h" +#include +#include + #define MAXLUXURIES 16 /* there must be no more than MAXLUXURIES kinds of luxury goods in any game */ #define MAXREGIONS 524287 /* must be prime for hashing. 262139 was a little small */ #define MAXTREES 100 * 1000 * 1000 /* bug 2360: some players are crazy */ @@ -96,7 +99,7 @@ extern "C" { typedef struct land_region { char *name; - /* TODO: demand kann nach Konvertierung entfernt werden. */ + char *display; demand *demands; const struct item_type *herbtype; short herbs; @@ -122,7 +125,6 @@ extern "C" { int uid; /* a unique id */ int x, y; struct plane *_plane; /* to access, use rplane(r) */ - char *display; int flags; unsigned short age; struct message_list *msgs; @@ -257,11 +259,10 @@ extern "C" { int region_get_morale(const region * r); void region_set_morale(region * r, int morale, int turn); +#define RESOLVE_REGION (TYP_REGION << 24) + void resolve_region(region *r); void write_region_reference(const struct region *r, struct storage *store); - variant read_region_reference(struct gamedata *data); - int resolve_region_coor(variant id, void *address); - int resolve_region_id(variant id, void *address); -#define RESOLVE_REGION(version) ((versionstore; char pbuf[8]; @@ -399,8 +399,7 @@ static void read_alliances(struct gamedata *data) READ_INT(store, &al->flags); } if (data->version >= ALLIANCELEADER_VERSION) { - read_reference(&al->_leader, data, read_faction_reference, - resolve_faction); + read_faction_reference(data, &al->_leader, NULL); READ_INT(store, &id); } else { @@ -420,7 +419,6 @@ void read_planes(gamedata *data) { READ_INT(store, &nread); while (--nread >= 0) { int id; - variant fno; plane *pl; READ_INT(store, &id); @@ -459,9 +457,10 @@ void read_planes(gamedata *data) { else { /* WATCHERS - eliminated in February 2016, ca. turn 966 */ if (data->version < NOWATCH_VERSION) { - fno = read_faction_reference(data); - while (fno.i) { - fno = read_faction_reference(data); + int fno; + READ_INT(data->store, &fno); + while (fno) { + READ_INT(data->store, &fno); } } } @@ -492,7 +491,7 @@ void write_planes(storage *store) { } } -void write_alliances(struct gamedata *data) +void write_alliances(gamedata *data) { alliance *al = alliances; while (al) { @@ -509,22 +508,7 @@ void write_alliances(struct gamedata *data) WRITE_SECTION(data->store); } -static int resolve_owner(variant id, void *address) -{ - region_owner *owner = (region_owner *)address; - int result = 0; - faction *f = NULL; - if (id.i != 0) { - f = findfaction(id.i); - if (f == NULL) { - log_error("region has an invalid owner (%s)", itoa36(id.i)); - } - } - owner->owner = f; - return result; -} - -static void read_owner(struct gamedata *data, region_owner ** powner) +static void read_owner(gamedata *data, region_owner ** powner) { int since_turn; @@ -540,9 +524,7 @@ static void read_owner(struct gamedata *data, region_owner ** powner) owner->flags = 0; } if (data->version >= OWNER_3_VERSION) { - int id; - READ_INT(data->store, &id); - owner->last_owner = id ? findfaction(id) : NULL; + read_faction_reference(data, &owner->last_owner, NULL); } else if (data->version >= OWNER_2_VERSION) { int id; @@ -555,7 +537,7 @@ static void read_owner(struct gamedata *data, region_owner ** powner) else { owner->last_owner = NULL; } - read_reference(owner, data, &read_faction_reference, &resolve_owner); + read_faction_reference(data, &owner->owner, NULL); *powner = owner; } else { @@ -563,7 +545,7 @@ static void read_owner(struct gamedata *data, region_owner ** powner) } } -static void write_owner(struct gamedata *data, region_owner * owner) +static void write_owner(gamedata *data, region_owner * owner) { if (owner) { faction *f; @@ -603,8 +585,7 @@ int current_turn(void) return cturn; } -static void -writeorder(struct gamedata *data, const struct order *ord, +static void writeorder(gamedata *data, const struct order *ord, const struct locale *lang) { char obuf[1024]; @@ -613,7 +594,58 @@ writeorder(struct gamedata *data, const struct order *ord, WRITE_STR(data->store, obuf); } -unit *read_unit(struct gamedata *data) +static void read_skills(gamedata *data, unit *u) +{ + if (data->version < SKILLSORT_VERSION) { + for (;;) { + int n = NOSKILL, level, weeks; + skill_t sk; + READ_INT(data->store, &n); + sk = (skill_t)n; + if (sk == NOSKILL) break; + READ_INT(data->store, &level); + READ_INT(data->store, &weeks); + if (level) { + skill *sv = add_skill(u, sk); + sv->level = sv->old = (unsigned char)level; + sv->weeks = (unsigned char)weeks; + } + } + } + else { + int i; + READ_INT(data->store, &u->skill_size); + u->skills = malloc(sizeof(skill)*u->skill_size); + for (i = 0; i != u->skill_size; ++i) { + skill *sv = u->skills + i; + int val; + READ_INT(data->store, &val); + sv->id = (skill_t)val; + READ_INT(data->store, &sv->level); + sv->old = sv->level; + READ_INT(data->store, &sv->weeks); + } + } +} + +static void write_skills(gamedata *data, const unit *u) { + int i; + skill_t sk = NOSKILL; + WRITE_INT(data->store, u->skill_size); + for (i = 0; i != u->skill_size; ++i) { + skill *sv = u->skills + i; +#ifndef NDEBUG + assert(sv->id > sk); + sk = sv->id; + assert(sv->weeks <= sv->level * 2 + 1); +#endif + WRITE_INT(data->store, sv->id); + WRITE_INT(data->store, sv->level); + WRITE_INT(data->store, sv->weeks); + } +} + +unit *read_unit(gamedata *data) { unit *u; const race *rc; @@ -760,20 +792,7 @@ unit *read_unit(struct gamedata *data) set_order(&u->thisorder, NULL); assert(u_race(u)); - for (;;) { - int n = NOSKILL, level, weeks; - skill_t sk; - READ_INT(data->store, &n); - sk = (skill_t)n; - if (sk == NOSKILL) break; - READ_INT(data->store, &level); - READ_INT(data->store, &weeks); - if (level) { - skill *sv = add_skill(u, sk); - sv->level = sv->old = (unsigned char)level; - sv->weeks = (unsigned char)weeks; - } - } + read_skills(data, u); read_items(data->store, &u->items); READ_INT(data->store, &u->hp); if (u->hp < u->number) { @@ -781,13 +800,14 @@ unit *read_unit(struct gamedata *data) u->hp = u->number; } read_attribs(data, &u->attribs, u); + resolve_unit(u); return u; } -void write_unit(struct gamedata *data, const unit * u) +void write_unit(gamedata *data, const unit * u) { order *ord; - int i, p = 0; + int p = 0; unsigned int flags = u->flags & UFL_SAVEMASK; const race *irace = u_irace(u); @@ -835,18 +855,7 @@ void write_unit(struct gamedata *data, const unit * u) WRITE_SECTION(data->store); assert(u_race(u)); - - for (i = 0; i != u->skill_size; ++i) { - skill *sv = u->skills + i; - assert(sv->weeks <= sv->level * 2 + 1); - if (sv->level > 0) { - WRITE_INT(data->store, sv->id); - WRITE_INT(data->store, sv->level); - WRITE_INT(data->store, sv->weeks); - } - } - WRITE_INT(data->store, -1); - WRITE_SECTION(data->store); + write_skills(data, u); write_items(data->store, u->items); WRITE_SECTION(data->store); if (u->hp == 0 && data->version < NORCSPELL_VERSION) { @@ -859,11 +868,24 @@ void write_unit(struct gamedata *data, const unit * u) WRITE_SECTION(data->store); } -static region *readregion(struct gamedata *data, int x, int y) +static void read_regioninfo(gamedata *data, const region *r, char *info, size_t len) { + if (lomem) { + READ_STR(data->store, NULL, 0); + } + else { + READ_STR(data->store, info, len); + if (unicode_utf8_trim(info) != 0) { + log_warning("trim region %d info to '%s'", r->uid, info); + } + } +} + +static region *readregion(gamedata *data, int x, int y) { region *r = findregion(x, y); const terrain_type *terrain; char name[NAMESIZE]; + char info[DISPLAYSIZE]; int uid = 0; int n; @@ -889,16 +911,11 @@ static region *readregion(struct gamedata *data, int x, int y) } r->land = 0; } - if (lomem) { - READ_STR(data->store, NULL, 0); + if (data->version < LANDDISPLAY_VERSION) { + read_regioninfo(data, r, info, sizeof(info)); } else { - char info[DISPLAYSIZE]; - READ_STR(data->store, info, sizeof(info)); - if (unicode_utf8_trim(info)!=0) { - log_warning("trim region %d info to '%s'", uid, info); - }; - region_setinfo(r, info); + info[0] = '\0'; } READ_STR(data->store, name, sizeof(name)); @@ -915,15 +932,19 @@ static region *readregion(struct gamedata *data, int x, int y) if (fval(r->terrain, LAND_REGION)) { r->land = calloc(1, sizeof(land_region)); READ_STR(data->store, name, sizeof(name)); - if (unicode_utf8_trim(name)!=0) { - log_warning("trim region %d name to '%s'", uid, name); - }; + if (unicode_utf8_trim(name) != 0) { + log_warning("trim region %d name to '%s'", uid, name); + }; r->land->name = strdup(name); } if (r->land) { int i; rawmaterial **pres = &r->resources; + if (data->version >= LANDDISPLAY_VERSION) { + read_regioninfo(data, r, info, sizeof(info)); + } + region_setinfo(r, info); READ_INT(data->store, &i); if (i < 0) { log_error("number of trees in %s is %d.", regionname(r, NULL), i); @@ -1001,7 +1022,11 @@ static region *readregion(struct gamedata *data, int x, int y) READ_INT(data->store, &n); rsetmoney(r, n); } - + else { + if (info[0]) { + log_error("%s %d has a description: %s", r->terrain->_name, r->uid, info); + } + } assert(r->terrain != NULL); if (r->land) { @@ -1040,27 +1065,27 @@ region *read_region(gamedata *data) READ_INT(store, &x); READ_INT(store, &y); r = readregion(data, x, y); + resolve_region(r); return r; } -void writeregion(struct gamedata *data, const region * r) +void writeregion(gamedata *data, const region * r) { assert(r); assert(data); WRITE_INT(data->store, r->uid); - WRITE_STR(data->store, region_getinfo(r)); WRITE_TOK(data->store, r->terrain->_name); WRITE_INT(data->store, r->flags & RF_SAVEMASK); WRITE_INT(data->store, r->age); WRITE_SECTION(data->store); - if (fval(r->terrain, LAND_REGION)) { + if (r->land) { const item_type *rht; struct demand *demand; rawmaterial *res = r->resources; - assert(r->land); WRITE_STR(data->store, (const char *)r->land->name); + WRITE_STR(data->store, region_getinfo(r)); assert(rtrees(r, 0) >= 0); assert(rtrees(r, 1) >= 0); assert(rtrees(r, 2) >= 0); @@ -1096,11 +1121,9 @@ void writeregion(struct gamedata *data, const region * r) } WRITE_TOK(data->store, "end"); WRITE_SECTION(data->store); -#if RELEASE_VERSION>=REGIONOWNER_VERSION WRITE_INT(data->store, region_get_morale(r)); write_owner(data, r->land->ownership); WRITE_SECTION(data->store); -#endif } write_attribs(data->store, r->attribs, r); WRITE_SECTION(data->store); @@ -1114,33 +1137,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) { - variant id; - id.i = aid; - ur_add(id, &sf->faction, resolve_faction); - } - sf->status = state & HELP_ALL; - - return &sf->next; -} - int get_spell_level_faction(const spell * sp, void * cbdata) { static spellbook * common = 0; @@ -1217,9 +1213,8 @@ void _test_write_password(gamedata *data, const faction *f) { write_password(data, f); } -faction *read_faction(struct gamedata * data) +faction *read_faction(gamedata * data) { - ally **sfp; int planes, n; faction *f; char name[DISPLAYSIZE]; @@ -1348,28 +1343,17 @@ faction *read_faction(struct gamedata * data) /* mistakes were made in the past*/ 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) { read_spellbook(FactionSpells() ? &f->spellbook : 0, data, get_spell_level_faction, (void *)f); } + resolve_faction(f); return f; } -void write_faction(struct gamedata *data, const faction * f) +void write_faction(gamedata *data, const faction * f) { ally *sf; ursprung *ur; @@ -1450,7 +1434,7 @@ static int cb_sb_maxlevel(spellbook_entry *sbe, void *cbdata) { int readgame(const char *filename) { - int n; + int n, stream_version; char path[MAX_PATH]; gamedata gdata = { 0 }; storage store; @@ -1467,11 +1451,8 @@ int readgame(const char *filename) return -1; } sz = fread(&gdata.version, sizeof(int), 1, F); - if (sz != sizeof(int) || gdata.version >= INTPAK_VERSION) { - int stream_version; - size_t sz = fread(&stream_version, sizeof(int), 1, F); - assert((sz == 1 && stream_version == STREAM_VERSION) || !"unsupported data format"); - } + sz = fread(&stream_version, sizeof(int), 1, F); + assert((sz == 1 && stream_version == STREAM_VERSION) || !"unsupported data format"); assert(gdata.version >= MIN_VERSION || !"unsupported data format"); assert(gdata.version <= MAX_VERSION || !"unsupported data format"); @@ -1540,7 +1521,8 @@ struct building *read_building(gamedata *data) { log_error("building too big: %s (%s size %d of %d), fixing.", buildingname(b), b->type->_name, b->size, b->type->maxsize); b->size = b->type->maxsize; } - return b; + resolve_building(b); + return b; } void write_ship(gamedata *data, const ship *sh) @@ -1558,7 +1540,7 @@ void write_ship(gamedata *data, const ship *sh) write_attribs(store, sh->attribs, sh); } -ship *read_ship(struct gamedata *data) +ship *read_ship(gamedata *data) { char name[DISPLAYSIZE]; ship *sh; @@ -1725,6 +1707,9 @@ int read_game(gamedata *data) /* Burgen */ READ_INT(store, &p); + if (p > 0 && !r->land) { + log_error("%s, uid=%d has %d buildings", regionname(r, NULL), r->uid, p); + } bp = &r->buildings; while (--p >= 0) { @@ -1780,10 +1765,6 @@ int read_game(gamedata *data) } read_borders(data); - /* Unaufgeloeste Zeiger initialisieren */ - log_debug("fixing unresolved references."); - resolve(); - log_debug("updating area information for lighthouses."); for (r = regions; r; r = r->next) { if (r->flags & RF_LIGHTHOUSE) { diff --git a/src/kernel/save.test.c b/src/kernel/save.test.c index 9501df896..81d5a507d 100644 --- a/src/kernel/save.test.c +++ b/src/kernel/save.test.c @@ -116,12 +116,15 @@ static void test_readwrite_region(CuTest * tc) gamedata data; storage store; region *r; + const char * lipsum = "Lorem ipsum dolor sit amet"; test_setup(); r = test_create_region(0, 0, 0); free(r->land->name); r->land->name = strdup(" Hodor "); CuAssertStrEquals(tc, " Hodor ", r->land->name); + region_setinfo(r, lipsum); + CuAssertStrEquals(tc, lipsum, r->land->display); mstream_init(&data.strm); gamedata_init(&data, &store, RELEASE_VERSION); write_region(&data, r); @@ -132,6 +135,7 @@ static void test_readwrite_region(CuTest * tc) r = read_region(&data); CuAssertPtrNotNull(tc, r); CuAssertStrEquals(tc, "Hodor", r->land->name); + CuAssertStrEquals(tc, lipsum, r->land->display); regions = r; mstream_done(&data.strm); diff --git a/src/kernel/unit.c b/src/kernel/unit.c index 44e9445b7..2c6378ca1 100644 --- a/src/kernel/unit.c +++ b/src/kernel/unit.c @@ -277,6 +277,10 @@ int gift_items(unit * u, int flags) u->items = NULL; break; } + else if (!u3) { + /* pick a last-chance recipient: */ + u3 = u2; + } } } if (u->items && u3) { @@ -644,9 +648,7 @@ void a_writesiege(const attrib * a, const void *owner, struct storage *store) int a_readsiege(attrib * a, void *owner, gamedata *data) { - int result = read_reference(&a->data.v, data, read_building_reference, - resolve_building); - if (result == 0 && !a->data.v) { + if (read_building_reference(data, (building **)&a->data.v, NULL) <= 0) { return AT_READ_FAIL; } return AT_READ_OK; @@ -747,25 +749,26 @@ void write_unit_reference(const unit * u, struct storage *store) WRITE_INT(store, (u && u->region) ? u->no : 0); } -int resolve_unit(variant id, void *address) +void resolve_unit(unit *u) { - unit *u = NULL; - if (id.i != 0) { - u = findunit(id.i); - if (u == NULL) { - *(unit **)address = NULL; - return -1; - } - } - *(unit **)address = u; - return 0; + resolve(RESOLVE_UNIT | u->no, u); } -variant read_unit_reference(gamedata *data) +int read_unit_reference(gamedata * data, unit **up, resolve_fun fun) { - variant var; - READ_INT(data->store, &var.i); - return var; + int id; + READ_INT(data->store, &id); + if (id > 0) { + *up = findunit(id); + if (*up == NULL) { + *up = NULL; + ur_add(RESOLVE_UNIT | id, (void **)up, fun); + } + } + else { + *up = NULL; + } + return id; } int get_level(const unit * u, skill_t id) @@ -773,7 +776,7 @@ int get_level(const unit * u, skill_t id) assert(id != NOSKILL); if (skill_enabled(id)) { skill *sv = u->skills; - while (sv != u->skills + u->skill_size) { + while (sv != u->skills + u->skill_size && sv->id <= id) { if (sv->id == id) { return sv->level; } @@ -795,7 +798,7 @@ void set_level(unit * u, skill_t sk, int value) remove_skill(u, sk); return; } - while (sv != u->skills + u->skill_size) { + while (sv != u->skills + u->skill_size && sv->id <= sk) { if (sv->id == sk) { sk_set(sv, value); return; @@ -1186,35 +1189,39 @@ void set_number(unit * u, int count) void remove_skill(unit * u, skill_t sk) { - skill *sv = u->skills; - for (sv = u->skills; sv != u->skills + u->skill_size; ++sv) { + int i; + skill *sv; + for (i = 0; i != u->skill_size; ++i) { + sv = u->skills + i; if (sv->id == sk) { - skill *sl = u->skills + u->skill_size - 1; - if (sl != sv) { - *sv = *sl; - } + memmove(sv, sv + 1, (u->skill_size - i - 1) * sizeof(skill)); --u->skill_size; return; } } } -skill *add_skill(unit * u, skill_t id) +skill *add_skill(unit * u, skill_t sk) { - skill *sv = u->skills; -#ifndef NDEBUG - for (sv = u->skills; sv != u->skills + u->skill_size; ++sv) { - assert(sv->id != id); + skill *sv; + int i; + + for (i=0; i != u->skill_size; ++i) { + sv = u->skills+i; + if (sv->id >= sk) break; + } + u->skills = realloc(u->skills, (1 + u->skill_size) * sizeof(skill)); + sv = u->skills + i; + if (i < u->skill_size) { + assert(sv->id != sk); + memmove(sv + 1, sv, sizeof(skill) * (u->skill_size - i)); } -#endif ++u->skill_size; - u->skills = realloc(u->skills, u->skill_size * sizeof(skill)); - sv = (u->skills + u->skill_size - 1); sv->level = 0; sv->weeks = 1; sv->old = 0; - sv->id = id; - if (id == SK_MAGIC && u->faction && !fval(u->faction, FFL_NPC)) { + sv->id = sk; + if (sk == SK_MAGIC && u->faction && !fval(u->faction, FFL_NPC)) { assert(u->number <= 1); assert(max_magicians(u->faction) >= u->number); } @@ -1224,9 +1231,10 @@ skill *add_skill(unit * u, skill_t id) skill *unit_skill(const unit * u, skill_t sk) { skill *sv = u->skills; - while (sv != u->skills + u->skill_size) { - if (sv->id == sk) + while (sv != u->skills + u->skill_size && sv->id <= sk) { + if (sv->id == sk) { return sv; + } ++sv; } return NULL; @@ -1235,7 +1243,7 @@ skill *unit_skill(const unit * u, skill_t sk) bool has_skill(const unit * u, skill_t sk) { skill *sv = u->skills; - while (sv != u->skills + u->skill_size) { + while (sv != u->skills + u->skill_size && sv->id <= sk) { if (sv->id == sk) { return (sv->level > 0); } diff --git a/src/kernel/unit.h b/src/kernel/unit.h index dede956b5..d80c0ec79 100644 --- a/src/kernel/unit.h +++ b/src/kernel/unit.h @@ -19,7 +19,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #ifndef H_KRNL_UNIT_H #define H_KRNL_UNIT_H -#include +#include #include "types.h" #include "skills.h" #include @@ -182,12 +182,13 @@ extern "C" { #define GIFT_FRIENDS 1<<1 #define GIFT_PEASANTS 1<<2 int gift_items(struct unit *u, int flags); - void make_zombie(unit * u); + void make_zombie(struct unit * u); /* see resolve.h */ - int resolve_unit(variant data, void *address); +#define RESOLVE_UNIT (TYP_UNIT << 24) + void resolve_unit(struct unit *u); void write_unit_reference(const struct unit *u, struct storage *store); - variant read_unit_reference(struct gamedata *data); + int read_unit_reference(struct gamedata * data, struct unit **up, resolve_fun fun); bool leave(struct unit *u, bool force); bool can_leave(struct unit *u); diff --git a/src/kernel/unit.test.c b/src/kernel/unit.test.c index 2abb8c85c..2e4ce3568 100644 --- a/src/kernel/unit.test.c +++ b/src/kernel/unit.test.c @@ -31,7 +31,7 @@ static void test_remove_empty_units(CuTest *tc) { unit *u; int uid; - test_cleanup(); + test_setup(); test_create_world(); u = test_create_unit(test_create_faction(test_create_race("human")), findregion(0, 0)); @@ -48,7 +48,7 @@ static void test_remove_empty_units_in_region(CuTest *tc) { unit *u; int uid; - test_cleanup(); + test_setup(); test_create_world(); u = test_create_unit(test_create_faction(test_create_race("human")), findregion(0, 0)); @@ -69,7 +69,7 @@ static void test_remove_units_without_faction(CuTest *tc) { unit *u; int uid; - test_cleanup(); + test_setup(); test_create_world(); u = test_create_unit(test_create_faction(test_create_race("human")), findregion(0, 0)); @@ -85,7 +85,7 @@ static void test_remove_units_with_dead_faction(CuTest *tc) { unit *u; int uid; - test_cleanup(); + test_setup(); test_create_world(); u = test_create_unit(test_create_faction(test_create_race("human")), findregion(0, 0)); @@ -101,7 +101,7 @@ static void test_scale_number(CuTest *tc) { unit *u; const struct potion_type *ptype; - test_cleanup(); + test_setup(); test_create_world(); ptype = new_potiontype(it_get_or_create(rt_get_or_create("hodor")), 1); u = test_create_unit(test_create_faction(test_create_race("human")), findregion(0, 0)); @@ -122,7 +122,7 @@ static void test_scale_number(CuTest *tc) { static void test_unit_name(CuTest *tc) { unit *u; - test_cleanup(); + test_setup(); test_create_world(); u = test_create_unit(test_create_faction(test_create_race("human")), findregion(0, 0)); renumber_unit(u, 666); @@ -334,9 +334,50 @@ static void test_inside_building(CuTest *tc) { test_cleanup(); } +static void test_skills(CuTest *tc) { + unit *u; + skill *sv; + test_setup(); + u = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0)); + sv = add_skill(u, SK_ALCHEMY); + CuAssertPtrNotNull(tc, sv); + CuAssertPtrEquals(tc, sv, u->skills); + CuAssertIntEquals(tc, 1, u->skill_size); + CuAssertIntEquals(tc, SK_ALCHEMY, sv->id); + CuAssertIntEquals(tc, 0, sv->level); + CuAssertIntEquals(tc, 1, sv->weeks); + CuAssertIntEquals(tc, 0, sv->old); + sv = add_skill(u, SK_BUILDING); + CuAssertPtrNotNull(tc, sv); + CuAssertIntEquals(tc, 2, u->skill_size); + CuAssertIntEquals(tc, SK_ALCHEMY, u->skills[0].id); + CuAssertIntEquals(tc, SK_BUILDING, u->skills[1].id); + sv = add_skill(u, SK_LONGBOW); + CuAssertPtrNotNull(tc, sv); + CuAssertPtrEquals(tc, sv, unit_skill(u, SK_LONGBOW)); + CuAssertIntEquals(tc, 3, u->skill_size); + CuAssertIntEquals(tc, SK_ALCHEMY, u->skills[0].id); + CuAssertIntEquals(tc, SK_LONGBOW, u->skills[1].id); + CuAssertIntEquals(tc, SK_BUILDING, u->skills[2].id); + CuAssertTrue(tc, !has_skill(u, SK_LONGBOW)); + set_level(u, SK_LONGBOW, 1); + CuAssertTrue(tc, has_skill(u, SK_LONGBOW)); + remove_skill(u, SK_LONGBOW); + CuAssertIntEquals(tc, SK_BUILDING, u->skills[1].id); + CuAssertIntEquals(tc, 2, u->skill_size); + remove_skill(u, SK_LONGBOW); + CuAssertIntEquals(tc, SK_BUILDING, u->skills[1].id); + CuAssertIntEquals(tc, 2, u->skill_size); + remove_skill(u, SK_BUILDING); + CuAssertIntEquals(tc, SK_ALCHEMY, u->skills[0].id); + CuAssertIntEquals(tc, 1, u->skill_size); + CuAssertTrue(tc, !has_skill(u, SK_LONGBOW)); + test_cleanup(); +} + static void test_limited_skills(CuTest *tc) { unit *u; - test_cleanup(); + test_setup(); u = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0)); CuAssertIntEquals(tc, false, has_limited_skills(u)); set_level(u, SK_ENTERTAINMENT, 1); @@ -592,6 +633,7 @@ CuSuite *get_unit_suite(void) SUITE_ADD_TEST(suite, test_skill_familiar); SUITE_ADD_TEST(suite, test_age_familiar); SUITE_ADD_TEST(suite, test_inside_building); + SUITE_ADD_TEST(suite, test_skills); SUITE_ADD_TEST(suite, test_limited_skills); SUITE_ADD_TEST(suite, test_renumber_unit); SUITE_ADD_TEST(suite, test_name_unit); diff --git a/src/kernel/xmlreader.c b/src/kernel/xmlreader.c index 2ef54b005..18bdedebc 100644 --- a/src/kernel/xmlreader.c +++ b/src/kernel/xmlreader.c @@ -960,7 +960,7 @@ static void add_spells(equipment * eq, xmlNodeSetPtr nsetItems) equipment_addspell(eq, name, level); } else { - log_error("spell '%s' for equipment-set '%s' has no level\n", name, eq->name); + log_error("spell '%s' for equipment-set '%s' has no level\n", name, equipment_name(eq)); } xmlFree(propValue); } @@ -980,7 +980,7 @@ static void add_skills(equipment * eq, xmlNodeSetPtr nsetSkills) assert(propValue != NULL); sk = findskill((const char *)propValue); if (sk == NOSKILL) { - log_error("unknown skill '%s' in equipment-set %s\n", (const char *)propValue, eq->name); + log_error("unknown skill '%s' in equipment-set %s\n", (const char *)propValue, equipment_name(eq)); xmlFree(propValue); } else { @@ -1044,7 +1044,7 @@ add_subsets(xmlDocPtr doc, equipment * eq, xmlNodeSetPtr nsetSubsets) } } if (totalChance > 1.0f) { - log_error("total chance exceeds 1.0: %f in equipment set %s.\n", totalChance, eq->name); + log_error("total chance exceeds 1.0: %f in equipment set %s.\n", totalChance, equipment_name(eq)); } } xmlXPathFreeObject(xpathResult); @@ -1069,9 +1069,13 @@ static int parse_equipment(xmlDocPtr doc) xmlChar *propName = xmlGetProp(node, BAD_CAST "name"); if (propName != NULL) { - equipment *eq = get_or_create_equipment((const char *)propName); + equipment *eq = get_equipment((const char *)propName); xmlXPathObjectPtr xpathResult; + if (!eq) { + eq = create_equipment((const char *)propName); + } + xpath->node = node; xpathResult = xmlXPathEvalExpression(BAD_CAST "callback", xpath); diff --git a/src/keyword.c b/src/keyword.c index cb56fe940..a38c91e07 100644 --- a/src/keyword.c +++ b/src/keyword.c @@ -2,6 +2,7 @@ #include #include "keyword.h" +#include #include #include #include @@ -20,7 +21,7 @@ const char * keyword(keyword_t kwd) if (!result[0]) { strcpy(result, "keyword::"); } - strcpy(result + 9, keywords[kwd]); + strlcpy(result + 9, keywords[kwd], sizeof(result) - 9); return result; } diff --git a/src/laws.c b/src/laws.c index c3c7d968e..d7f73fa6c 100644 --- a/src/laws.c +++ b/src/laws.c @@ -1559,11 +1559,11 @@ int display_cmd(unit * u, struct order *ord) break; case P_REGION: - if (u->faction != region_get_owner(r)) { + if (!r->land || u->faction != region_get_owner(r)) { cmistake(u, ord, 147, MSG_EVENT); break; } - s = &r->display; + s = &r->land->display; break; default: diff --git a/src/laws.test.c b/src/laws.test.c index 4d6adbfe9..9f7884fc5 100644 --- a/src/laws.test.c +++ b/src/laws.test.c @@ -227,7 +227,7 @@ static void test_display_cmd(CuTest *tc) { ord = create_order(K_DISPLAY, f->locale, "%s Hodor", LOC(f->locale, parameters[P_REGION])); CuAssertIntEquals(tc, 0, display_cmd(u, ord)); - CuAssertPtrEquals(tc, NULL, r->display); + CuAssertPtrEquals(tc, NULL, r->land->display); free_order(ord); test_cleanup(); diff --git a/src/magic.c b/src/magic.c index f5e7810b4..d41ce71e4 100644 --- a/src/magic.c +++ b/src/magic.c @@ -356,9 +356,7 @@ static int read_seenspell(attrib * a, void *owner, struct gamedata *data) } sp = find_spell(token); if (!sp) { - log_warning("read_seenspell: could not find spell '%s'\n", token); - } - if (!sp) { + log_info("read_seenspell: could not find spell '%s'\n", token); return AT_READ_FAIL; } a->data.v = sp; @@ -2264,26 +2262,21 @@ bool create_newfamiliar(unit * mage, unit * familiar) return true; } -static int resolve_familiar(variant data, void *addr) -{ - unit *familiar; - int result = resolve_unit(data, &familiar); - if (result == 0 && familiar) { +static void * resolve_familiar(int id, void *data) { + if (data) { + unit *familiar = (unit *)data; attrib *a = a_find(familiar->attribs, &at_familiarmage); if (a != NULL && a->data.v) { unit *mage = (unit *)a->data.v; set_familiar(mage, familiar); } } - *(unit **)addr = familiar; - return result; + return data; } static int read_familiar(attrib * a, void *owner, struct gamedata *data) { - int result = - read_reference(&a->data.v, data, read_unit_reference, resolve_familiar); - if (result == 0 && a->data.v == NULL) { + if (read_unit_reference(data, (unit **)&a->data.v, resolve_familiar) <= 0) { return AT_READ_FAIL; } return AT_READ_OK; @@ -2348,52 +2341,42 @@ unit *has_clone(unit * mage) return NULL; } -static int resolve_clone(variant data, void *addr) -{ - unit *clone; - int result = resolve_unit(data, &clone); - if (result == 0 && clone) { +static void * resolve_clone(int id, void *data) { + if (data) { + unit *clone = (unit *)data; attrib *a = a_find(clone->attribs, &at_clonemage); if (a != NULL && a->data.v) { unit *mage = (unit *)a->data.v; set_clone(mage, clone); } } - *(unit **)addr = clone; - return result; + return data; } static int read_clone(attrib * a, void *owner, struct gamedata *data) { - int result = - read_reference(&a->data.v, data, read_unit_reference, resolve_clone); - if (result == 0 && a->data.v == NULL) { + if (read_unit_reference(data, (unit **)&a->data.v, resolve_clone) <= 0) { return AT_READ_FAIL; } return AT_READ_OK; } /* mages */ -static int resolve_mage(variant data, void *addr) -{ - unit *mage; - int result = resolve_unit(data, &mage); - if (result == 0 && mage) { +static void * resolve_mage(int id, void *data) { + if (data) { + unit *mage = (unit *)data; attrib *a = a_find(mage->attribs, &at_familiar); if (a != NULL && a->data.v) { unit *familiar = (unit *)a->data.v; set_familiar(mage, familiar); } } - *(unit **)addr = mage; - return result; + return data; } static int read_magician(attrib * a, void *owner, struct gamedata *data) { - int result = - read_reference(&a->data.v, data, read_unit_reference, resolve_mage); - if (result == 0 && a->data.v == NULL) { + if (read_unit_reference(data, (unit **)&a->data.v, resolve_mage) <= 0) { return AT_READ_FAIL; } return AT_READ_OK; @@ -3009,30 +2992,36 @@ int cast_spell(struct castorder *co) static critbit_tree cb_spellbooks; +#define SBNAMELEN 16 + +typedef struct sb_entry { + char key[SBNAMELEN]; + spellbook *value; +} sb_entry; + spellbook * get_spellbook(const char * name) { - char buffer[64]; - spellbook * result; - void * match; + size_t len = strlen(name); + const void * match; - if (cb_find_prefix(&cb_spellbooks, name, strlen(name), &match, 1, 0) > 0) { - cb_get_kv(match, &result, sizeof(result)); + if (len >= SBNAMELEN) { + log_error("spellbook name is longer than %d bytes: %s", SBNAMELEN-1, name); + return NULL; } - else { - size_t len = strlen(name); - result = create_spellbook(name); - assert(strlen(name) + sizeof(result) < sizeof(buffer)); - len = cb_new_kv(name, len, &result, sizeof(result), buffer); - if (cb_insert(&cb_spellbooks, buffer, len) == CB_EXISTS) { + + match = cb_find_str(&cb_spellbooks, name); + if (!match) { + sb_entry ent; + memset(ent.key, 0, SBNAMELEN); + memcpy(ent.key, name, len); + ent.value = create_spellbook(name); + if (cb_insert(&cb_spellbooks, &ent, sizeof(ent)) == CB_EXISTS) { log_error("cb_insert failed although cb_find returned nothing for spellbook=%s", name); assert(!"should not happen"); } - result = 0; - if (cb_find_prefix(&cb_spellbooks, name, strlen(name), &match, 1, 0) > 0) { - cb_get_kv(match, &result, sizeof(result)); - } + return ent.value; } - return result; + return ((const sb_entry *)match)->value; } void free_spellbook(spellbook *sb) { @@ -3041,9 +3030,8 @@ void free_spellbook(spellbook *sb) { } static int free_spellbook_cb(const void *match, const void *key, size_t keylen, void *data) { - spellbook *sb; - cb_get_kv(match, &sb, sizeof(sb)); - free_spellbook(sb); + const sb_entry *ent = (const sb_entry *)match; + free_spellbook(ent->value); return 0; } diff --git a/src/magic.test.c b/src/magic.test.c index a1b55b45d..c6866ce47 100644 --- a/src/magic.test.c +++ b/src/magic.test.c @@ -51,7 +51,18 @@ void test_updatespells(CuTest * tc) test_cleanup(); } -void test_spellbooks(CuTest * tc) +static void test_get_spellbook(CuTest * tc) +{ + spellbook *sb; + + test_setup(); + CuAssertPtrNotNull(tc, sb = get_spellbook("hodorhodorhodor")); + CuAssertPtrEquals(tc, sb, get_spellbook("hodorhodorhodor")); + CuAssertTrue(tc, sb != get_spellbook("hodor")); + test_cleanup(); +} + +static void test_spellbooks(CuTest * tc) { spell *sp; spellbook *herp, *derp; @@ -445,24 +456,6 @@ static void test_max_spellpoints(CuTest *tc) { test_cleanup(); } -static void test_familiar_mage(CuTest *tc) { - unit *um, *uf, *ut; - test_setup(); - um = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0)); - uf = test_create_unit(um->faction, um->region); - ut = test_create_unit(um->faction, um->region); - set_number(ut, 0); - CuAssertTrue(tc, create_newfamiliar(um, uf)); - CuAssertTrue(tc, is_familiar(uf)); - CuAssertTrue(tc, !is_familiar(um)); - CuAssertPtrEquals(tc, um, get_familiar_mage(uf)); - CuAssertPtrEquals(tc, uf, get_familiar(um)); - - CuAssertPtrEquals(tc, NULL, give_men(1, um, ut, NULL)); - CuAssertPtrEquals(tc, ut, get_familiar_mage(uf)); - test_cleanup(); -} - static void test_illusioncastle(CuTest *tc) { building *b; @@ -490,6 +483,7 @@ CuSuite *get_magic_suite(void) SUITE_ADD_TEST(suite, test_multi_cast); SUITE_ADD_TEST(suite, test_updatespells); SUITE_ADD_TEST(suite, test_spellbooks); + SUITE_ADD_TEST(suite, test_get_spellbook); SUITE_ADD_TEST(suite, test_pay_spell); SUITE_ADD_TEST(suite, test_pay_spell_failure); SUITE_ADD_TEST(suite, test_getspell_unit); @@ -502,6 +496,5 @@ CuSuite *get_magic_suite(void) SUITE_ADD_TEST(suite, test_magic_resistance); SUITE_ADD_TEST(suite, test_max_spellpoints); SUITE_ADD_TEST(suite, test_illusioncastle); - DISABLE_TEST(suite, test_familiar_mage); return suite; } diff --git a/src/modules/xmas.c b/src/modules/xmas.c index 4b90af68e..b76f14eab 100644 --- a/src/modules/xmas.c +++ b/src/modules/xmas.c @@ -1,4 +1,4 @@ -/* +/* +-------------------+ Christian Schlittchen | | Enno Rehling | Eressea PBEM host | Katja Zedel @@ -14,7 +14,7 @@ #include #include "xmas.h" -/* kernel includes */ + /* kernel includes */ #include #include #include @@ -50,10 +50,7 @@ static void xmasgate_write(const trigger * t, struct storage *store) static int xmasgate_read(trigger * t, struct gamedata *data) { - int bc = - read_reference(&t->data.v, data, read_building_reference, - resolve_building); - if (bc == 0 && !t->data.v) { + if (read_building_reference(data, (building **)&t->data.v, NULL) <= 0) { return AT_READ_FAIL; } return AT_READ_OK; diff --git a/src/monsters.c b/src/monsters.c index ddc30ca4d..115759d29 100644 --- a/src/monsters.c +++ b/src/monsters.c @@ -612,7 +612,7 @@ static void recruit_dracoids(unit * dragon, int size) name_unit(un); change_money(dragon, -un->number * 50); - equip_unit(un, get_equipment("recruited_dracoid")); + equip_unit(un, get_equipment("new_dracoid")); setstatus(un, ST_FIGHT); for (weapon = un->items; weapon; weapon = weapon->next) { @@ -863,7 +863,7 @@ static int nrand(int start, int sub) unit *spawn_seaserpent(region *r, faction *f) { unit *u = create_unit(r, f, 1, get_race(RC_SEASERPENT), 0, NULL, NULL); fset(u, UFL_ISNEW | UFL_MOVED); - equip_unit(u, get_equipment("monster_seaserpent")); + equip_unit(u, get_equipment("seed_seaserpent")); return u; } @@ -894,7 +894,7 @@ void spawn_dragons(void) u = create_unit(r, monsters, nrand(30, 20) + 1, get_race(RC_DRAGON), 0, NULL, NULL); } fset(u, UFL_ISNEW | UFL_MOVED); - equip_unit(u, get_equipment("monster_dragon")); + equip_unit(u, get_equipment("seed_dragon")); log_debug("spawning %d %s in %s.\n", u->number, LOC(default_locale, @@ -1132,7 +1132,7 @@ faction *get_or_create_monsters(void) if (!f) { const race *rc = rc_get_or_create("dragon"); const char *email = config_get("monster.email"); - f = addfaction(email ? email : "noreply@eressea.de", NULL, rc, default_locale, 0); + f = addfaction(email ? email : NULL, NULL, rc, default_locale, 0); renumber_faction(f, MONSTER_ID); faction_setname(f, "Monster"); fset(f, FFL_NPC | FFL_NOIDLEOUT); diff --git a/src/randenc.c b/src/randenc.c index 2b46499e6..b2b282eb1 100644 --- a/src/randenc.c +++ b/src/randenc.c @@ -263,7 +263,7 @@ static void get_villagers(region * r, unit * u) u); leave(newunit, true); fset(newunit, UFL_ISNEW | UFL_MOVED); - equip_unit(newunit, get_equipment("random_villagers")); + equip_unit(newunit, get_equipment("rand_villagers")); } static void get_allies(region * r, unit * u) @@ -282,7 +282,7 @@ static void get_allies(region * r, unit * u) if (get_money(u) / u->number < 100 + rng_int() % 200) return; name = "random_plain_men"; - equip = "random_plain"; + equip = "rand_plain"; number = rng_int() % 8 + 2; break; } @@ -293,7 +293,7 @@ static void get_allies(region * r, unit * u) return; } name = "random_forest_men"; - equip = "random_forest"; + equip = "rand_forest"; number = rng_int() % 6 + 2; } break; @@ -303,7 +303,7 @@ static void get_allies(region * r, unit * u) return; } name = "random_swamp_men"; - equip = "random_swamp"; + equip = "rand_swamp"; number = rng_int() % 6 + 2; break; @@ -312,7 +312,7 @@ static void get_allies(region * r, unit * u) return; } name = "random_desert_men"; - equip = "random_desert"; + equip = "rand_desert"; number = rng_int() % 12 + 2; break; @@ -321,7 +321,7 @@ static void get_allies(region * r, unit * u) return; } name = "random_highland_men"; - equip = "random_highland"; + equip = "rand_highland"; number = rng_int() % 8 + 2; break; @@ -330,7 +330,7 @@ static void get_allies(region * r, unit * u) return; } name = "random_mountain_men"; - equip = "random_mountain"; + equip = "rand_mountain"; number = rng_int() % 6 + 2; break; @@ -339,7 +339,7 @@ static void get_allies(region * r, unit * u) return; } name = "random_glacier_men"; - equip = "random_glacier"; + equip = "rand_glacier"; number = rng_int() % 4 + 2; break; diff --git a/src/report.c b/src/report.c index 18d48b86b..2dac94011 100644 --- a/src/report.c +++ b/src/report.c @@ -1069,15 +1069,15 @@ void report_region(struct stream *out, const region * r, faction * f) if (wrptr(&bufp, &size, bytes) != 0) WARN_STATIC_BUFFER(); - if (r->display && r->display[0]) { + if (r->land && r->land->display && r->land->display[0]) { bytes = (int)strlcpy(bufp, " ", size); if (wrptr(&bufp, &size, bytes) != 0) WARN_STATIC_BUFFER(); - bytes = (int)strlcpy(bufp, r->display, size); + bytes = (int)strlcpy(bufp, r->land->display, size); if (wrptr(&bufp, &size, bytes) != 0) WARN_STATIC_BUFFER(); - n = r->display[strlen(r->display) - 1]; + n = r->land->display[strlen(r->land->display) - 1]; if (n != '!' && n != '?' && n != '.') { bytes = (int)strlcpy(bufp, ".", size); if (wrptr(&bufp, &size, bytes) != 0) diff --git a/src/reports.c b/src/reports.c index cc11f4006..1182f89c9 100644 --- a/src/reports.c +++ b/src/reports.c @@ -1616,11 +1616,13 @@ int reports(void) } for (f = factions; f; f = f->next) { - int error = write_reports(f, ltime); - if (error) - retval = error; - if (mailit) - write_script(mailit, f); + if (f->email && !fval(f, FFL_NPC)) { + int error = write_reports(f, ltime); + if (error) + retval = error; + if (mailit) + write_script(mailit, f); + } } if (mailit) fclose(mailit); @@ -1701,7 +1703,7 @@ static void var_free_regions(variant x) /*-V524 */ const char *trailinto(const region * r, const struct locale *lang) { - char ref[32]; + static char ref[32]; const char *s; if (r) { const char *tname = terrain_name(r); @@ -2145,23 +2147,6 @@ static void eval_int36(struct opstack **stack, const void *userdata) /*** END MESSAGE RENDERING ***/ -#include - -static void log_orders(const struct message *msg) -{ - char buffer[4096]; - int i; - - for (i = 0; i != msg->type->nparameters; ++i) { - if (msg->type->types[i]->copy == &var_copy_order) { - const char *section = nr_section(msg); - nr_render(msg, default_locale, buffer, sizeof(buffer), NULL); - log_debug("MESSAGE [%s]: %s\n", section, buffer); - break; - } - } -} - int stream_printf(struct stream * out, const char *format, ...) { va_list args; @@ -2224,8 +2209,6 @@ void register_reports(void) register_argtype("items", var_free_resources, var_copy_items, VAR_VOIDPTR); register_argtype("regions", var_free_regions, NULL, VAR_VOIDPTR); - msg_log_create = &log_orders; - /* register functions that turn message contents to readable strings */ add_function("alliance", &eval_alliance); add_function("region", &eval_region); diff --git a/src/reports.test.c b/src/reports.test.c index 58ac425f1..7c6e8ccf4 100644 --- a/src/reports.test.c +++ b/src/reports.test.c @@ -279,13 +279,13 @@ static void test_bufunit(CuTest *tc) { bufunit(u->faction, u, 0, 0, buffer, sizeof(buffer)); CuAssertStrEquals(tc, "Hodor (1), 1 human, aggressiv.", buffer); - set_level(u, SK_SAILING, 1); - bufunit(u->faction, u, 0, 0, buffer, sizeof(buffer)); - CuAssertStrEquals(tc, "Hodor (1), 1 human, aggressiv, Talente: Segeln 1.", buffer); - set_level(u, SK_ALCHEMY, 1); bufunit(u->faction, u, 0, 0, buffer, sizeof(buffer)); - CuAssertStrEquals(tc, "Hodor (1), 1 human, aggressiv, Talente: Segeln 1, Alchemie 2.", buffer); + CuAssertStrEquals(tc, "Hodor (1), 1 human, aggressiv, Talente: Alchemie 2.", buffer); + + set_level(u, SK_SAILING, 1); + bufunit(u->faction, u, 0, 0, buffer, sizeof(buffer)); + CuAssertStrEquals(tc, "Hodor (1), 1 human, aggressiv, Talente: Alchemie 2, Segeln 1.", buffer); f = test_create_faction(0); f->locale = get_or_create_locale("de"); diff --git a/src/spells.c b/src/spells.c index c6860bebe..9d5481a60 100644 --- a/src/spells.c +++ b/src/spells.c @@ -519,7 +519,7 @@ static void make_familiar(unit * familiar, unit * mage) const struct equipment *eq; char eqname[64]; const race * rc = u_race(familiar); - snprintf(eqname, sizeof(eqname), "%s_familiar", rc->_name); + snprintf(eqname, sizeof(eqname), "fam_%s", rc->_name); eq = get_equipment(eqname); if (eq != NULL) { equip_items(&familiar->items, eq); @@ -2892,47 +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; - variant var; - int duration; - float strength; - int rx, ry; UNUSED_ARG(a); UNUSED_ARG(target); - READ_INT(store, &duration); - READ_FLT(store, &strength); - READ_INT(store, &var.i); - u = findunit(var.i); - - /* 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(var, &c->magician, resolve_unit); - } - } - 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 @@ -6705,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/spells/borders.c b/src/spells/borders.c index 331e7380f..d19470230 100644 --- a/src/spells/borders.c +++ b/src/spells/borders.c @@ -92,11 +92,9 @@ static void wall_read(connection * b, gamedata * data) static wall_data dummy; wall_data *fd = b->data.v ? (wall_data *)b->data.v : &dummy; - read_reference(&fd->mage, data, read_unit_reference, resolve_unit); + read_unit_reference(data, &fd->mage, NULL); READ_INT(data->store, &fd->force); - if (data->version >= NOBORDERATTRIBS_VERSION) { - READ_INT(data->store, &fd->countdown); - } + READ_INT(data->store, &fd->countdown); fd->active = true; } diff --git a/src/teleport.c b/src/teleport.c index f81f2f9f0..78098c264 100644 --- a/src/teleport.c +++ b/src/teleport.c @@ -160,7 +160,7 @@ void spawn_braineaters(float chance) unit *u = create_unit(r, f0, 1 + rng_int() % 10 + rng_int() % 10, get_race(RC_HIRNTOETER), 0, NULL, NULL); - equip_unit(u, get_equipment("monster_braineater")); + equip_unit(u, get_equipment("seed_braineater")); next = rng_int() % (int)(chance * 100); } diff --git a/src/triggers/changefaction.c b/src/triggers/changefaction.c index e8b6a4879..6a2700afa 100644 --- a/src/triggers/changefaction.c +++ b/src/triggers/changefaction.c @@ -83,16 +83,10 @@ static void changefaction_write(const trigger * t, struct storage *store) static int changefaction_read(trigger * t, gamedata *data) { - variant var; changefaction_data *td = (changefaction_data *)t->data.v; - read_reference(&td->unit, data, read_unit_reference, resolve_unit); - var = read_faction_reference(data); - if (var.i == 0) { - return AT_READ_FAIL; - } - ur_add(var, &td->faction, resolve_faction); - return AT_READ_OK; + read_unit_reference(data, &td->unit, NULL); + return read_faction_reference(data, &td->faction, NULL) > 0 ? AT_READ_OK : AT_READ_FAIL; } trigger_type tt_changefaction = { diff --git a/src/triggers/changerace.c b/src/triggers/changerace.c index a9f282698..1a065fce2 100644 --- a/src/triggers/changerace.c +++ b/src/triggers/changerace.c @@ -89,9 +89,9 @@ static void changerace_write(const trigger * t, struct storage *store) static int changerace_read(trigger * t, gamedata *data) { changerace_data *td = (changerace_data *)t->data.v; - read_reference(&td->u, data, read_unit_reference, resolve_unit); - td->race = (const struct race *)read_race_reference(data->store).v; - td->irace = (const struct race *)read_race_reference(data->store).v; + read_unit_reference(data, &td->u, NULL); + td->race = read_race_reference(data->store); + td->irace = read_race_reference(data->store); return AT_READ_OK; } diff --git a/src/triggers/clonedied.c b/src/triggers/clonedied.c index f3d1fc00b..edcf756f9 100644 --- a/src/triggers/clonedied.c +++ b/src/triggers/clonedied.c @@ -70,9 +70,7 @@ static void clonedied_write(const trigger * t, struct storage *store) static int clonedied_read(trigger * t, gamedata *data) { - int result = - read_reference(&t->data.v, data, read_unit_reference, resolve_unit); - if (result == 0 && t->data.v == NULL) { + if (read_unit_reference(data, (unit **)&t->data.v, NULL) <= 0) { return AT_READ_FAIL; } return AT_READ_OK; diff --git a/src/triggers/createcurse.c b/src/triggers/createcurse.c index 3eb0891ca..2551f7fb5 100644 --- a/src/triggers/createcurse.c +++ b/src/triggers/createcurse.c @@ -98,8 +98,8 @@ static int createcurse_read(trigger * t, gamedata *data) char zText[128]; float flt; - read_reference(&td->mage, data, read_unit_reference, resolve_unit); - read_reference(&td->target, data, read_unit_reference, resolve_unit); + read_unit_reference(data, &td->mage, NULL); + read_unit_reference(data, &td->target, NULL); READ_TOK(data->store, zText, sizeof(zText)); td->type = ct_find(zText); diff --git a/src/triggers/createunit.c b/src/triggers/createunit.c index 1148b1d5a..951887860 100644 --- a/src/triggers/createunit.c +++ b/src/triggers/createunit.c @@ -90,22 +90,16 @@ static void createunit_write(const trigger * t, struct storage *store) static int createunit_read(trigger * t, gamedata *data) { createunit_data *td = (createunit_data *)t->data.v; - variant var; + int id; int result = AT_READ_OK; - var = read_faction_reference(data); - if (var.i > 0) { - td->f = findfaction(var.i); - if (!td->f) { - ur_add(var, &td->f, resolve_faction); - } - } - else { + + id = read_faction_reference(data, &td->f, NULL); + if (id <= 0) { result = AT_READ_FAIL; } - read_reference(&td->r, data, read_region_reference, - RESOLVE_REGION(data->version)); - td->race = (const struct race *)read_race_reference(data->store).v; + read_region_reference(data, &td->r, NULL); + td->race = read_race_reference(data->store); if (!td->race) { result = AT_READ_FAIL; } diff --git a/src/triggers/gate.c b/src/triggers/gate.c index c70163a14..a66e0365e 100644 --- a/src/triggers/gate.c +++ b/src/triggers/gate.c @@ -74,16 +74,11 @@ static void gate_write(const trigger * t, struct storage *store) static int gate_read(trigger * t, gamedata *data) { gate_data *gd = (gate_data *)t->data.v; + int bc = read_building_reference(data, &gd->gate, NULL); + int rc = read_region_reference(data, &gd->target, NULL); - int bc = - read_reference(&gd->gate, data, read_building_reference, resolve_building); - int rc = - read_reference(&gd->target, data, read_region_reference, - RESOLVE_REGION(data->version)); - - if (bc == 0 && rc == 0) { - if (!gd->gate || !gd->target) - return AT_READ_FAIL; + if (bc <= 0 && rc <= 0) { + return AT_READ_FAIL; } return AT_READ_OK; } diff --git a/src/triggers/giveitem.c b/src/triggers/giveitem.c index 9bc2c56e1..0442d9295 100644 --- a/src/triggers/giveitem.c +++ b/src/triggers/giveitem.c @@ -86,15 +86,16 @@ static int giveitem_read(trigger * t, gamedata *data) { giveitem_data *td = (giveitem_data *)t->data.v; char zText[128]; + int result; - int result = read_reference(&td->u, data, read_unit_reference, resolve_unit); + result = read_unit_reference(data, &td->u, NULL); READ_INT(data->store, &td->number); READ_TOK(data->store, zText, sizeof(zText)); td->itype = it_find(zText); assert(td->itype); - if (result == 0 && td->u == NULL) { + if (result == 0) { return AT_READ_FAIL; } return AT_READ_OK; diff --git a/src/triggers/killunit.c b/src/triggers/killunit.c index 3e6c9defe..230efa7dc 100644 --- a/src/triggers/killunit.c +++ b/src/triggers/killunit.c @@ -60,9 +60,7 @@ static void killunit_write(const trigger * t, struct storage *store) static int killunit_read(trigger * t, gamedata *data) { - int result = read_reference(&t->data.v, data, read_unit_reference, - resolve_unit); - if (result == 0 && t->data.v == NULL) { + if (read_unit_reference(data, (unit **)&t->data.v, NULL) == 0) { return AT_READ_FAIL; } return AT_READ_OK; diff --git a/src/triggers/shock.c b/src/triggers/shock.c index 31424e979..ca4ad67df 100644 --- a/src/triggers/shock.c +++ b/src/triggers/shock.c @@ -125,11 +125,8 @@ static void shock_write(const trigger * t, struct storage *store) } } -static int shock_read(trigger * t, gamedata *data) -{ - int result = - read_reference(&t->data.v, data, read_unit_reference, resolve_unit); - if (result == 0 && t->data.v == NULL) { +static int shock_read(trigger * t, gamedata *data) { + if (read_unit_reference(data, (unit **)&t->data.v, NULL) <= 0) { return AT_READ_FAIL; } return AT_READ_OK; diff --git a/src/util/gamedata.h b/src/util/gamedata.h index 058bc3f07..82df55cc3 100644 --- a/src/util/gamedata.h +++ b/src/util/gamedata.h @@ -5,10 +5,7 @@ #include -#define INTPAK_VERSION 329 /* in binary, ints can get packed. starting with E2/572 */ -#define NOZEROIDS_VERSION 330 /* 2008-05-16 zero is not a valid ID for anything (including factions) */ -#define NOBORDERATTRIBS_VERSION 331 /* 2008-05-17 connection::attribs has been moved to userdata */ -#define UIDHASH_VERSION 332 /* 2008-05-22 borders use the region.uid to store */ +#define UIDHASH_VERSION 332 /* 2008-05-22 = 572 borders use the region.uid to store */ #define REGIONOWNER_VERSION 333 /* 2009-05-14 regions have owners and morale */ #define ALLIANCELEADER_VERSION 333 /* alliances have a leader */ #define CURSEFLOAT_VERSION 334 /* all curse-effects are float */ @@ -36,12 +33,14 @@ #define NOLANDITEM_VERSION 356 /* land_region has no items */ #define NORCSPELL_VERSION 357 /* data contains no RC_SPELL units */ #define SORTKEYS_VERSION 358 /* at_keys is sorted */ -#define FAMILIAR_FIX_VERSION 359 /* at_keys is sorted */ +#define FAMILIAR_FIX_VERSION 359 /* familiar links are fixed */ +#define SKILLSORT_VERSION 360 /* u->skills is sorted */ +#define LANDDISPLAY_VERSION 360 /* r.display is now in r.land.display */ /* unfinished: */ #define CRYPT_VERSION 400 /* passwords are encrypted */ -#define RELEASE_VERSION FAMILIAR_FIX_VERSION /* current datafile */ -#define MIN_VERSION INTPAK_VERSION /* minimal datafile we support */ +#define RELEASE_VERSION SKILLSORT_VERSION /* current datafile */ +#define MIN_VERSION UIDHASH_VERSION /* minimal datafile we support */ #define MAX_VERSION RELEASE_VERSION /* change this if we can need to read the future datafile, and we can do so */ #define STREAM_VERSION 2 /* internal encoding of binary files */ diff --git a/src/util/resolve.c b/src/util/resolve.c index 63ef5d933..5f1787056 100644 --- a/src/util/resolve.c +++ b/src/util/resolve.c @@ -17,80 +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 *ptrptr; - /* 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]; -variant read_int(struct storage *store) -{ - variant var; - READ_INT(store, &var.i); - return var; +int ur_key(int id) { + int h = id ^ (id >> 16); + return h & (HASHSIZE - 1); } -int -read_reference(void *address, struct gamedata * data, read_fun reader, - resolve_fun resolver) +void ur_add(int id, void **addr, resolve_fun fun) { - variant var = reader(data); - int result = resolver(var, address); - if (result != 0) { - ur_add(var, address, resolver); - } - return result; -} + int h, i; -void ur_add(variant data, void *ptrptr, resolve_fun fun) -{ - assert(ptrptr); - if (ur_list == NULL) { - ur_list = malloc(BLOCKSIZE * sizeof(unresolved)); - ur_begin = ur_current = ur_list; - } - 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 = data; - ur_current->resolve = fun; - ur_current->ptrptr = ptrptr; - - ++ur_current; - ur_current->resolve = NULL; - ur_current->data.v = NULL; -} - -void resolve(void) -{ - unresolved *ur = ur_list; - while (ur) { - if (ur->resolve == NULL) { - ur = ur->data.v; - free(ur_list); - ur_list = ur; - continue; + assert(id > 0); + assert(addr); + assert(!*addr); + + 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; + } + } + assert(!"hash table is full"); +} + +static bool addr_cb(void *data, void *more) { + void **addr = (void **)data; + *addr = more; + return true; +} + +void resolve(int id, void *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; } - assert(ur->ptrptr); - ur->resolve(ur->data, ur->ptrptr); - ++ur; } - free(ur_list); - ur_list = NULL; } diff --git a/src/util/resolve.h b/src/util/resolve.h index 076b20508..ef33fd67d 100644 --- a/src/util/resolve.h +++ b/src/util/resolve.h @@ -19,7 +19,6 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #ifndef RESOLVE_H #define RESOLVE_H -#include "variant.h" struct storage; struct gamedata; @@ -27,15 +26,11 @@ struct gamedata; extern "C" { #endif - typedef int(*resolve_fun) (variant data, void *address); - typedef variant(*read_fun) (struct gamedata * data); - extern int read_reference(void *address, struct gamedata *data, - read_fun reader, resolve_fun resolver); + typedef void *(*resolve_fun) (int id, void *data); + typedef int(*read_fun) (struct gamedata * data); - extern void ur_add(variant data, void *address, resolve_fun fun); - extern void resolve(void); - - extern variant read_int(struct storage *store); + void ur_add(int id, void **addr, resolve_fun fun); + void resolve(int id, void *data); #ifdef __cplusplus } diff --git a/src/util/translation.c b/src/util/translation.c index fb89a5af9..290e28c16 100644 --- a/src/util/translation.c +++ b/src/util/translation.c @@ -71,7 +71,7 @@ void opstack_push(opstack ** stackp, variant data) ** static buffer malloc **/ -#define BBUFSIZE 0x20000 +#define BBUFSIZE 0x10000 static struct { char *begin; char *end; @@ -81,16 +81,13 @@ static struct { char *balloc(size_t size) { - static int init = 0; /* STATIC_XCALL: used across calls */ + static int init = 0; if (!init) { init = 1; buffer.current = buffer.begin = malloc(BBUFSIZE * sizeof(char)); buffer.end = buffer.begin + BBUFSIZE; } - if (buffer.current + size > buffer.end) { - /* out of memory! */ - return NULL; - } + assert(buffer.current + size <= buffer.end || !"balloc is out of memory"); buffer.last = buffer.current; buffer.current += size; return buffer.last; @@ -99,6 +96,7 @@ char *balloc(size_t size) void bfree(char *c) /* only release this memory if it was part of the last allocation * that's a joke, but who cares. + * I'm afraid I don't get the joke. */ { if (c >= buffer.last && c < buffer.current) diff --git a/src/util/umlaut.c b/src/util/umlaut.c index d29cb78ac..27f7bc67d 100644 --- a/src/util/umlaut.c +++ b/src/util/umlaut.c @@ -21,6 +21,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include "assert.h" #include "log.h" +#include "bsdstring.h" #include "unicode.h" #include @@ -211,7 +212,7 @@ void addtoken(tnode ** root, const char *str, variant id) if (lcs == replace[i].ucs) { char zText[1024]; memcpy(zText, replace[i].str, 3); - strcpy(zText + 2, (const char *)str + len); + strlcpy(zText + 2, (const char *)str + len, sizeof(zText)-2); addtoken(root, zText, id); break; } diff --git a/src/wormhole.c b/src/wormhole.c index 462f4e637..b4dfa7068 100644 --- a/src/wormhole.c +++ b/src/wormhole.c @@ -96,36 +96,15 @@ static void wormhole_write(const struct attrib *a, const void *owner, struct sto write_region_reference(exit, store); } -/** conversion code, turn 573, 2008-05-23 */ -static int resolve_exit(variant id, void *address) -{ - building *b = findbuilding(id.i); - region **rp = address; - if (b) { - *rp = b->region; - return 0; - } - *rp = NULL; - return -1; -} - static int wormhole_read(struct attrib *a, void *owner, struct gamedata *data) { - storage *store = data->store; - resolve_fun resolver = (data->version < UIDHASH_VERSION) - ? resolve_exit : resolve_region_id; - read_fun reader = (data->version < UIDHASH_VERSION) - ? read_building_reference : read_region_reference; + int id; if (data->version < ATTRIBOWNER_VERSION) { - READ_INT(store, NULL); + READ_INT(data->store, NULL); } - if (read_reference(&a->data.v, data, reader, resolver) == 0) { - if (!a->data.v) { - return AT_READ_FAIL; - } - } - return AT_READ_OK; + id = read_region_reference(data, (region **)&a->data.v, NULL); + return (id <= 0) ? AT_READ_FAIL : AT_READ_OK; } static attrib_type at_wormhole = {