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 = {