From 77ab9133c2ee7eab5bd7f458d5cf8434f9952b0d Mon Sep 17 00:00:00 2001
From: Enno Rehling <enno.rehling@gmail.com>
Date: Tue, 31 Dec 2013 01:06:28 -0800
Subject: [PATCH] use the storage submodule everywhere.

make most magic use float instead of double.
---
 .gitmodules                        |   4 +
 CMakeLists.txt                     |   1 +
 core/src/CMakeLists.txt            |  12 +-
 core/src/attributes/follow.c       |   3 +-
 core/src/attributes/giveitem.c     |  15 +-
 core/src/attributes/gm.c           |   3 +-
 core/src/attributes/hate.c         |   3 +-
 core/src/attributes/moved.c        |   7 +-
 core/src/attributes/movement.c     |   7 +-
 core/src/attributes/object.c       |  33 +-
 core/src/attributes/otherfaction.c |   7 +-
 core/src/attributes/targetregion.c |   5 +-
 core/src/bindings/CMakeLists.txt   |   1 +
 core/src/bindings/bind_eressea.c   |   7 +-
 core/src/bindings/bind_storage.c   |  77 +--
 core/src/bindings/bindings.c       |   7 +-
 core/src/gamecode/creport.c        |  31 +-
 core/src/gamecode/items.c          |  10 +-
 core/src/gamecode/laws.c           |   3 +-
 core/src/gmtool.c                  |   4 +-
 core/src/kernel/alchemy.c          |  11 +-
 core/src/kernel/battle.c           |  12 +-
 core/src/kernel/binarystore.c      | 274 --------
 core/src/kernel/binarystore.h      |  23 -
 core/src/kernel/building.c         |  36 +-
 core/src/kernel/config.h           |   9 +-
 core/src/kernel/connection.c       |  69 +-
 core/src/kernel/curse.c            |  81 +--
 core/src/kernel/curse.h            |  16 +-
 core/src/kernel/faction.c          |   7 +-
 core/src/kernel/group.c            |  31 +-
 core/src/kernel/group.h            |   6 +-
 core/src/kernel/item.c             |   6 +-
 core/src/kernel/magic.c            |  84 +--
 core/src/kernel/magic.h            |   8 +-
 core/src/kernel/move.c             |  17 +-
 core/src/kernel/plane.c            |   7 +-
 core/src/kernel/race.c             |   7 +-
 core/src/kernel/region.c           |  51 +-
 core/src/kernel/reports.c          |   2 +-
 core/src/kernel/save.c             | 967 ++++++++++++++++-------------
 core/src/kernel/save.h             |  14 +-
 core/src/kernel/ship.c             |   5 +-
 core/src/kernel/textstore.c        | 310 ---------
 core/src/kernel/textstore.h        |  23 -
 core/src/kernel/unit.c             |  15 +-
 core/src/kernel/version.h          |   2 +
 core/src/modules/arena.c           |   7 +-
 core/src/modules/gmcmd.c           |   7 +-
 core/src/modules/museum.c          |  15 +-
 core/src/modules/wormhole.c        |  12 +-
 core/src/modules/xmas.c            |   5 +-
 core/src/platform.h                |   7 +-
 core/src/triggers/changefaction.c  |   3 +-
 core/src/triggers/changerace.c     |   3 +-
 core/src/triggers/clonedied.c      |   3 +-
 core/src/triggers/createcurse.c    |  52 +-
 core/src/triggers/createcurse.h    |   4 +-
 core/src/triggers/createunit.c     |   9 +-
 core/src/triggers/gate.c           |   5 +-
 core/src/triggers/giveitem.c       |  11 +-
 core/src/triggers/killunit.c       |   3 +-
 core/src/triggers/removecurse.c    |   9 +-
 core/src/triggers/shock.c          |   3 +-
 core/src/triggers/timeout.c        |   7 +-
 core/src/triggers/unitmessage.c    |  16 +-
 core/src/util/attrib.c             |   8 +-
 core/src/util/attrib.h             |   6 +-
 core/src/util/event.c              |  10 +-
 core/src/util/resolve.c            |   2 +-
 core/src/util/storage.h            |  48 --
 src/CMakeLists.txt                 |   1 +
 src/bindings.c                     |   2 +-
 src/curses.c                       |  23 +-
 src/main.c                         |   5 +-
 src/spells/alp.c                   |   5 +-
 src/spells/combatspells.c          |   6 +-
 src/spells/shipcurse.c             |   9 +-
 src/spells/shipcurse.h             |   4 +-
 src/spells/spells.c                | 223 ++++---
 src/spells/unitcurse.c             |  13 +-
 storage                            |   1 +
 82 files changed, 1211 insertions(+), 1669 deletions(-)
 delete mode 100644 core/src/kernel/binarystore.c
 delete mode 100644 core/src/kernel/binarystore.h
 delete mode 100644 core/src/kernel/textstore.c
 delete mode 100644 core/src/kernel/textstore.h
 delete mode 100644 core/src/util/storage.h
 create mode 160000 storage

diff --git a/.gitmodules b/.gitmodules
index 06a4ecc3a..e23131b2c 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -25,3 +25,7 @@
 [submodule "cJSON"]
 	path = cJSON
 	url = git://github.com/kbranigan/cJSON.git
+[submodule "storage"]
+	path = storage
+	url = git@github.com:badgerman/storage.git
+	branch = master
diff --git a/CMakeLists.txt b/CMakeLists.txt
index dd7a8de61..cf04ffb40 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -35,6 +35,7 @@ find_package (ToLua REQUIRED)
 
 add_subdirectory (cutest)
 add_subdirectory (crypto)
+add_subdirectory (storage)
 add_subdirectory (iniparser)
 add_subdirectory (quicklist)
 add_subdirectory (critbit)
diff --git a/core/src/CMakeLists.txt b/core/src/CMakeLists.txt
index f1c6f73a0..a31116ddd 100755
--- a/core/src/CMakeLists.txt
+++ b/core/src/CMakeLists.txt
@@ -13,6 +13,7 @@ include_directories (${ERESSEA_INCLUDE_DIR})
 include_directories (${CRITBIT_INCLUDE_DIR})
 include_directories (${CRYPTO_INCLUDE_DIR})
 include_directories (${QUICKLIST_INCLUDE_DIR})
+include_directories (${STORAGE_INCLUDE_DIR})
 include_directories (${CUTEST_INCLUDE_DIR})
 include_directories (${LUA_INCLUDE_DIR})
 include_directories (${LIBXML2_INCLUDE_DIR})
@@ -95,7 +96,6 @@ set (LIB_SRC
   kernel/alliance.c
   kernel/ally.c
   kernel/battle.c
-  kernel/binarystore.c
   kernel/build.c
   kernel/building.c
   kernel/calendar.c
@@ -128,7 +128,6 @@ set (LIB_SRC
   kernel/sqlite.c
   kernel/teleport.c
   kernel/terrain.c
-  kernel/textstore.c
   kernel/unit.c
   kernel/xmlreader.c
   modules/arena.c
@@ -184,6 +183,7 @@ set (LIB_SRC
 
 add_library(${ERESSEA_LIBRARY} ${LIB_SRC} ${BIND_SRC} ${LIB_HDR})
 target_link_libraries(${ERESSEA_LIBRARY}
+  ${STORAGE_LIBRARIES}
   ${CRITBIT_LIBRARIES}
   ${QUICKLIST_LIBRARIES}
   ${CRYPTO_LIBRARIES}
@@ -191,12 +191,14 @@ target_link_libraries(${ERESSEA_LIBRARY}
   ${LIBXML2_LIBRARIES}
   ${SQLITE3_LIBRARIES}
   ${CURSES_LIBRARIES}
-	${LUA_LIBRARIES}
+  ${LUA_LIBRARIES}
 )
 
 add_executable(test_eressea ${TEST_SRC})
-target_link_libraries(test_eressea ${ERESSEA_LIBRARY})
-target_link_libraries(test_eressea ${CUTEST_LIBRARIES})
+target_link_libraries(test_eressea
+  ${ERESSEA_LIBRARY}
+  ${CUTEST_LIBRARIES}
+)
 
 add_test(eressea test_eressea)
 
diff --git a/core/src/attributes/follow.c b/core/src/attributes/follow.c
index 6d5f1b540..16d8dcff0 100644
--- a/core/src/attributes/follow.c
+++ b/core/src/attributes/follow.c
@@ -23,9 +23,10 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #include <kernel/unit.h>
 
 #include <util/attrib.h>
-#include <util/storage.h>
 #include <util/variant.h>
 
+#include <storage.h>
+
 static int read_follow(attrib * a, void *owner, struct storage *store)
 {
   read_unit_reference(store);   /* skip it */
diff --git a/core/src/attributes/giveitem.c b/core/src/attributes/giveitem.c
index ed996ed93..d809eb111 100644
--- a/core/src/attributes/giveitem.c
+++ b/core/src/attributes/giveitem.c
@@ -30,9 +30,10 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #include <util/attrib.h>
 #include <util/base36.h>
 #include <util/resolve.h>
-#include <util/storage.h>
 #include <util/goodies.h>
 
+#include <storage.h>
+
 /* libc includes */
 #include <stdlib.h>
 #include <string.h>
@@ -49,10 +50,10 @@ a_writegive(const attrib * a, const void *owner, struct storage *store)
   item *itm;
   write_building_reference(gdata->building, store);
   for (itm = gdata->items; itm; itm = itm->next) {
-    store->w_tok(store, resourcename(itm->type->rtype, 0));
-    store->w_int(store, itm->number);
+    WRITE_TOK(store, resourcename(itm->type->rtype, 0));
+    WRITE_INT(store, itm->number);
   }
-  store->w_tok(store, "end");
+  WRITE_TOK(store, "end");
 }
 
 static int a_readgive(attrib * a, void *owner, struct storage *store)
@@ -61,7 +62,7 @@ static int a_readgive(attrib * a, void *owner, struct storage *store)
   variant var;
   char zText[32];
 
-  var.i = store->r_id(store);
+  READ_INT(store, &var.i);
   if (var.i > 0) {
     gdata->building = findbuilding(var.i);
     if (gdata->building == NULL) {
@@ -72,10 +73,10 @@ static int a_readgive(attrib * a, void *owner, struct storage *store)
   }
   for (;;) {
     int i;
-    store->r_tok_buf(store, zText, sizeof(zText));
+    READ_TOK(store, zText, sizeof(zText));
     if (!strcmp("end", zText))
       break;
-    i = store->r_int(store);
+    READ_INT(store, &i);
     if (i == 0)
       i_add(&gdata->items, i_new(it_find(zText), i));
   }
diff --git a/core/src/attributes/gm.c b/core/src/attributes/gm.c
index a507b679c..f5cde3801 100644
--- a/core/src/attributes/gm.c
+++ b/core/src/attributes/gm.c
@@ -25,7 +25,8 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 
 /* util includes */
 #include <util/attrib.h>
-#include <util/storage.h>
+
+#include <storage.h>
 
 static void write_gm(const attrib * a, const void *owner, struct storage *store)
 {
diff --git a/core/src/attributes/hate.c b/core/src/attributes/hate.c
index c2c9d0536..b3a80f1bc 100644
--- a/core/src/attributes/hate.c
+++ b/core/src/attributes/hate.c
@@ -25,7 +25,8 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 
 #include <util/attrib.h>
 #include <util/resolve.h>
-#include <util/storage.h>
+
+#include <storage.h>
 
 static int verify_hate(attrib * a)
 {
diff --git a/core/src/attributes/moved.c b/core/src/attributes/moved.c
index 6ddad1b17..995a190cd 100644
--- a/core/src/attributes/moved.c
+++ b/core/src/attributes/moved.c
@@ -21,7 +21,8 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #include "moved.h"
 
 #include <util/attrib.h>
-#include <util/storage.h>
+
+#include <storage.h>
 
 static int age_moved(attrib * a)
 {
@@ -32,12 +33,12 @@ static int age_moved(attrib * a)
 static void
 write_moved(const attrib * a, const void *owner, struct storage *store)
 {
-  store->w_int(store, a->data.i);
+  WRITE_INT(store, a->data.i);
 }
 
 static int read_moved(attrib * a, void *owner, struct storage *store)
 {
-  a->data.i = store->r_int(store);
+  READ_INT(store, &a->data.i);
   if (a->data.i != 0)
     return AT_READ_OK;
   else
diff --git a/core/src/attributes/movement.c b/core/src/attributes/movement.c
index 1f3bf51c0..4a393ed97 100644
--- a/core/src/attributes/movement.c
+++ b/core/src/attributes/movement.c
@@ -21,17 +21,18 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #include "movement.h"
 
 #include <util/attrib.h>
-#include <util/storage.h>
+
+#include <storage.h>
 
 static void
 write_movement(const attrib * a, const void *owner, struct storage *store)
 {
-  store->w_int(store, a->data.i);
+  WRITE_INT(store, a->data.i);
 }
 
 static int read_movement(attrib * a, void *owner, struct storage *store)
 {
-  a->data.i = store->r_int(store);
+  READ_INT(store, &a->data.i);
   if (a->data.i != 0)
     return AT_READ_OK;
   else
diff --git a/core/src/attributes/object.c b/core/src/attributes/object.c
index 327cac5fc..b4177ab9b 100644
--- a/core/src/attributes/object.c
+++ b/core/src/attributes/object.c
@@ -32,7 +32,8 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 /* util includes */
 #include <util/attrib.h>
 #include <util/resolve.h>
-#include <util/storage.h>
+
+#include <storage.h>
 
 /* stdc includes */
 #include <string.h>
@@ -58,17 +59,17 @@ object_write(const attrib * a, const void *owner, struct storage *store)
 {
   const object_data *data = (object_data *) a->data.v;
   int type = (int)data->type;
-  store->w_tok(store, data->name);
-  store->w_int(store, type);
+  WRITE_TOK(store, data->name);
+  WRITE_INT(store, type);
   switch (data->type) {
     case TINTEGER:
-      store->w_int(store, data->data.i);
+      WRITE_INT(store, data->data.i);
       break;
     case TREAL:
-      store->w_flt(store, (float)data->data.real);
+      WRITE_FLT(store, (float)data->data.real);
       break;
     case TSTRING:
-      store->w_str(store, data->data.str);
+      WRITE_STR(store, data->data.str);
       break;
     case TUNIT:
       write_unit_reference(data->data.u, store);
@@ -95,20 +96,26 @@ object_write(const attrib * a, const void *owner, struct storage *store)
 
 static int object_read(attrib * a, void *owner, struct storage *store)
 {
+  char name[NAMESIZE];
   object_data *data = (object_data *) a->data.v;
-  int result;
+  int result, n;
+  float flt;
 
-  data->name = store->r_str(store);
-  data->type = (object_type) store->r_int(store);
+  READ_STR(store, name, sizeof(name));
+  data->name = _strdup(name);
+  READ_INT(store, &n);
+  data->type = (object_type)n;
   switch (data->type) {
     case TINTEGER:
-      data->data.i = store->r_int(store);
+      READ_INT(store, &data->data.i);
       break;
     case TREAL:
-      data->data.real = store->r_flt(store);
+      READ_FLT(store, &flt);
+      data->data.real = flt;
       break;
     case TSTRING:
-      data->data.str = store->r_str(store);
+      READ_STR(store, name, sizeof(name));
+      data->data.str = _strdup(name);
       break;
     case TBUILDING:
       result =
@@ -136,7 +143,7 @@ static int object_read(attrib * a, void *owner, struct storage *store)
     case TREGION:
       result =
         read_reference(&data->data.r, store, read_region_reference,
-        RESOLVE_REGION(store->version));
+        RESOLVE_REGION(global.data_version));
       if (result == 0 && !data->data.r) {
         return AT_READ_FAIL;
       }
diff --git a/core/src/attributes/otherfaction.c b/core/src/attributes/otherfaction.c
index bd0b501fc..768e57c9f 100644
--- a/core/src/attributes/otherfaction.c
+++ b/core/src/attributes/otherfaction.c
@@ -23,7 +23,8 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #include <kernel/faction.h>
 #include <kernel/unit.h>
 #include <util/attrib.h>
-#include <util/storage.h>
+
+#include <storage.h>
 #include <assert.h>
 
 /*
@@ -33,7 +34,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 void write_of(const struct attrib *a, const void *owner, struct storage *store)
 {
   const faction *f = (faction *) a->data.v;
-  store->w_int(store, f->no);
+  WRITE_INT(store, f->no);
 }
 
 int read_of(struct attrib *a, void *owner, struct storage *store)
@@ -44,7 +45,7 @@ int read_of(struct attrib *a, void *owner, struct storage *store)
     rule = rule_stealth_faction();
   }
 
-  of = store->r_int(store);
+  READ_INT(store, &of);
   if (rule&2) {
     a->data.v = findfaction(of);
     if (a->data.v) {
diff --git a/core/src/attributes/targetregion.c b/core/src/attributes/targetregion.c
index 4900016f1..f33b1007f 100644
--- a/core/src/attributes/targetregion.c
+++ b/core/src/attributes/targetregion.c
@@ -26,7 +26,8 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 
 #include <util/attrib.h>
 #include <util/resolve.h>
-#include <util/storage.h>
+
+#include <storage.h>
 
 static void
 write_targetregion(const attrib * a, const void *owner, struct storage *store)
@@ -38,7 +39,7 @@ static int read_targetregion(attrib * a, void *owner, struct storage *store)
 {
   int result =
     read_reference(&a->data.v, store, read_region_reference,
-    RESOLVE_REGION(store->version));
+    RESOLVE_REGION(global.data_version));
   if (result == 0 && !a->data.v)
     return AT_READ_FAIL;
   return AT_READ_OK;
diff --git a/core/src/bindings/CMakeLists.txt b/core/src/bindings/CMakeLists.txt
index c3d6b4db0..88df05cfb 100755
--- a/core/src/bindings/CMakeLists.txt
+++ b/core/src/bindings/CMakeLists.txt
@@ -13,6 +13,7 @@ set (BINDINGS_LIBRARY ${PROJECT_NAME} CACHE INTERNAL "Eressea Lua Bindings")
 find_package (Lua 5 REQUIRED)
 find_package (ToLua REQUIRED)
 
+include_directories (${STORAGE_INCLUDE_DIR})
 include_directories (${TOLUA_INCLUDE_DIR})
 
 FILE (GLOB_RECURSE BINDINGS_HDR *.h)
diff --git a/core/src/bindings/bind_eressea.c b/core/src/bindings/bind_eressea.c
index 1972bd0b1..e6ff82c2d 100755
--- a/core/src/bindings/bind_eressea.c
+++ b/core/src/bindings/bind_eressea.c
@@ -4,19 +4,20 @@
 #include <kernel/types.h>
 #include <kernel/config.h>
 #include <kernel/save.h>
-#include <util/storage.h>
+
+#include <storage.h>
 
 void eressea_free_game(void) {
   free_gamedata();
 }
 
 int eressea_read_game(const char * filename) {
-  return readgame(filename, IO_BINARY, 0);
+  return readgame(filename, false);
 } 
 
 int eressea_write_game(const char * filename) {
   remove_empty_factions();
-  return writegame(filename, IO_BINARY);
+  return writegame(filename);
 }
 
 int eressea_read_orders(const char * filename) {
diff --git a/core/src/bindings/bind_storage.c b/core/src/bindings/bind_storage.c
index e2b83b670..8cc084dc6 100644
--- a/core/src/bindings/bind_storage.c
+++ b/core/src/bindings/bind_storage.c
@@ -11,13 +11,15 @@ without prior permission by the authors of Eressea.
 */
 
 #include <platform.h>
+#include <kernel/config.h>
 #include <kernel/types.h>
 #include "bind_storage.h"
 
-#include <util/storage.h>
 #include <kernel/save.h>
-#include <kernel/textstore.h>
-#include <kernel/binarystore.h>
+#include <kernel/version.h>
+
+#include <storage.h>
+#include <binarystore.h>
 
 #include <math.h>
 #include <stdio.h>
@@ -28,68 +30,73 @@ static int tolua_storage_create(lua_State * L)
 {
   const char *filename = tolua_tostring(L, 1, 0);
   const char *type = tolua_tostring(L, 2, "rb");
-  storage *store = 0;
-  int mode = IO_READ;
-  if (strchr(type, 't')) {
-    store = malloc(sizeof(text_store));
-    memcpy(store, &text_store, sizeof(text_store));
-  } else {
-    store = malloc(sizeof(binary_store));
-    memcpy(store, &binary_store, sizeof(binary_store));
+  gamedata *data = (gamedata *)calloc(1, sizeof(gamedata));
+  storage *store = (storage *)calloc(1, sizeof(storage));
+
+  data->store = store;
+
+  FILE *F = fopen(filename, type);
+  if (strchr(type, 'r')) {
+    fread(&data->version, sizeof(int), 1, F);
+    fseek(F, sizeof(int), SEEK_CUR);
   }
-  if (strchr(type, 'r'))
-    mode = IO_READ;
-  if (strchr(type, 'w'))
-    mode = IO_WRITE;
-  store->open(store, filename, mode);
-  tolua_pushusertype(L, (void *)store, TOLUA_CAST "storage");
+  else if (strchr(type, 'w')) {
+    int n = STREAM_VERSION;
+    data->version = RELEASE_VERSION;
+    fwrite(&data->version, sizeof(int), 1, F);
+    fwrite(&n, sizeof(int), 1, F);
+  }
+  binstore_init(store, F);
+  tolua_pushusertype(L, (void *)data, TOLUA_CAST "storage");
   return 1;
 }
 
 static int tolua_storage_read_unit(lua_State * L)
 {
-  storage *self = (storage *) tolua_tousertype(L, 1, 0);
-  struct unit *u = read_unit(self);
+  gamedata *data = (gamedata *)tolua_tousertype(L, 1, 0);
+  struct unit *u = read_unit(data);
   tolua_pushusertype(L, (void *)u, TOLUA_CAST "unit");
   return 1;
 }
 
 static int tolua_storage_write_unit(lua_State * L)
 {
-  storage *store = (storage *) tolua_tousertype(L, 1, 0);
+  gamedata *data = (gamedata *)tolua_tousertype(L, 1, 0);
   struct unit *u = (struct unit *)tolua_tousertype(L, 2, 0);
-  if (store->version) {
-    write_unit(store, u);
+  if (global.data_version) {
+    write_unit(data, u);
   }
   return 0;
 }
 
 static int tolua_storage_read_float(lua_State * L)
 {
-  storage *self = (storage *) tolua_tousertype(L, 1, 0);
-  float num = self->r_flt(self);
+  gamedata *data = (gamedata *)tolua_tousertype(L, 1, 0);
+  float num;
+  READ_FLT(data->store, &num);
   tolua_pushnumber(L, (lua_Number) num);
   return 1;
 }
 
 static int tolua_storage_read_int(lua_State * L)
 {
-  storage *self = (storage *) tolua_tousertype(L, 1, 0);
-  int num = self->r_int(self);
+  gamedata *data = (gamedata *)tolua_tousertype(L, 1, 0);
+  int num;
+  READ_INT(data->store, &num);
   tolua_pushnumber(L, (lua_Number) num);
   return 1;
 }
 
 static int tolua_storage_write(lua_State * L)
 {
-  storage *self = (storage *) tolua_tousertype(L, 1, 0);
-  if (self->version && tolua_isnumber(L, 2, 0, 0)) {
+  gamedata *data = (gamedata *)tolua_tousertype(L, 1, 0);
+  if (data->version && tolua_isnumber(L, 2, 0, 0)) {
     lua_Number num = tolua_tonumber(L, 2, 0);
     double n;
     if (modf(num, &n) == 0.0) {
-      self->w_int(self, (int)num);
+      WRITE_INT(data->store, (int)num);
     } else {
-      self->w_flt(self, (float)num);
+      WRITE_FLT(data->store, (float)num);
     }
   }
   return 0;
@@ -97,18 +104,18 @@ static int tolua_storage_write(lua_State * L)
 
 static int tolua_storage_tostring(lua_State * L)
 {
-  storage *self = (storage *) tolua_tousertype(L, 1, 0);
+  gamedata *data = (gamedata *)tolua_tousertype(L, 1, 0);
   char name[64];
-  snprintf(name, sizeof(name), "<storage enc=%d ver=%d>", self->encoding,
-    self->version);
+  snprintf(name, sizeof(name), "<storage enc=%d ver=%d>", data->encoding,
+    data->version);
   lua_pushstring(L, name);
   return 1;
 }
 
 static int tolua_storage_close(lua_State * L)
 {
-  storage *self = (storage *) tolua_tousertype(L, 1, 0);
-  self->close(self);
+  gamedata *data = (gamedata *)tolua_tousertype(L, 1, 0);
+  binstore_done(data->store);
   return 0;
 }
 
diff --git a/core/src/bindings/bindings.c b/core/src/bindings/bindings.c
index 904e3e015..7d19db282 100755
--- a/core/src/bindings/bindings.c
+++ b/core/src/bindings/bindings.c
@@ -68,7 +68,8 @@ without prior permission by the authors of Eressea.
 #include <quicklist.h>
 #include <util/rand.h>
 #include <util/rng.h>
-#include <util/storage.h>
+
+#include <storage.h>
 
 #include <iniparser.h>
 #include <tolua.h>
@@ -351,9 +352,9 @@ static int tolua_create_curse(lua_State * L)
     const char *cname = tolua_tostring(L, 3, 0);
     const curse_type *ctype = ct_find(cname);
     if (ctype) {
-      double vigour = tolua_tonumber(L, 4, 0);
+      float vigour = (float)tolua_tonumber(L, 4, 0);
       int duration = (int)tolua_tonumber(L, 5, 0);
-      double effect = tolua_tonumber(L, 6, 0);
+      float effect = (float)tolua_tonumber(L, 6, 0);
       int men = (int)tolua_tonumber(L, 7, 0);   /* optional */
       curse *c = create_curse(u, ap, ctype, vigour, duration, effect, men);
       if (c) {
diff --git a/core/src/gamecode/creport.c b/core/src/gamecode/creport.c
index 94f1ae3a3..5f2ec83ba 100644
--- a/core/src/gamecode/creport.c
+++ b/core/src/gamecode/creport.c
@@ -504,7 +504,36 @@ static unsigned int messagehash(const struct message *msg)
   return (unsigned int)var.i;
 }
 
-extern int fwritestr(FILE * F, const char *str);
+/** writes a quoted string to the file
+* no trailing space, since this is used to make the creport.
+*/
+static int fwritestr(FILE * F, const char *str)
+{
+  int nwrite = 0;
+  fputc('\"', F);
+  if (str)
+  while (*str) {
+    int c = (int)(unsigned char)*str++;
+    switch (c) {
+    case '"':
+    case '\\':
+      fputc('\\', F);
+      fputc(c, F);
+      nwrite += 2;
+      break;
+    case '\n':
+      fputc('\\', F);
+      fputc('n', F);
+      nwrite += 2;
+      break;
+    default:
+      fputc(c, F);
+      ++nwrite;
+    }
+  }
+  fputc('\"', F);
+  return nwrite + 2;
+}
 
 static void render_messages(FILE * F, faction * f, message_list * msgs)
 {
diff --git a/core/src/gamecode/items.c b/core/src/gamecode/items.c
index 7e04b4190..410b05427 100644
--- a/core/src/gamecode/items.c
+++ b/core/src/gamecode/items.c
@@ -77,7 +77,7 @@ use_speedsail(struct unit *u, const struct item_type *itype, int amount,
   struct order *ord)
 {
   curse *c;
-  double effect;
+  float effect;
   ship *sh = u->ship;
   if (!sh) {
     cmistake(u, ord, 20, MSG_MOVE);
@@ -116,7 +116,7 @@ use_antimagiccrystal(unit * u, const struct item_type *itype, int amount,
   }
   for (i = 0; i != amount; ++i) {
     int effect, duration = 2;
-    double force;
+    float force;
     spell *sp = find_spell("antimagiczone");
     attrib **ap = &r->attribs;
     unused(ord);
@@ -128,7 +128,7 @@ use_antimagiccrystal(unit * u, const struct item_type *itype, int amount,
     /* H�lt Spr�che bis zu einem summierten Gesamtlevel von power aus.
      * Jeder Zauber reduziert die 'Lebenskraft' (vigour) der Antimagiezone
      * um seine Stufe */
-    force = effect * 20;     /* Stufe 5 =~ 100 */
+    force = (float)effect * 20;     /* Stufe 5 =~ 100 */
 
     /* Regionszauber aufl�sen */
     while (*ap && force > 0) {
@@ -159,8 +159,8 @@ use_antimagiccrystal(unit * u, const struct item_type *itype, int amount,
     }
 
     if (force > 0) {
-      create_curse(u, &r->attribs, ct_find("antimagiczone"), force, duration,
-        effect, 0);
+      create_curse(u, &r->attribs, ct_find("antimagiczone"), (float)force, duration,
+        (float)effect, 0);
     }
   }
   use_pooled(u, rt_crystal, GET_DEFAULT, amount);
diff --git a/core/src/gamecode/laws.c b/core/src/gamecode/laws.c
index 1c380f547..daa7a6334 100755
--- a/core/src/gamecode/laws.c
+++ b/core/src/gamecode/laws.c
@@ -3328,8 +3328,7 @@ static building *age_building(building * b)
       if (c == NULL) {
         if (mage != NULL) {
           int sk = effskill(mage, SK_MAGIC);
-          double effect;
-          effect = 100;
+          float effect = 100;
           /* the mage reactivates the circle */
           c = create_curse(mage, &rt->attribs, ct_astralblock,
             (float)MAX(1, sk), MAX(1, sk / 2), effect, 0);
diff --git a/core/src/gmtool.c b/core/src/gmtool.c
index 6036970f9..6f3e334fc 100644
--- a/core/src/gmtool.c
+++ b/core/src/gmtool.c
@@ -59,10 +59,10 @@
 #include <util/base36.h>
 #include <util/console.h>
 #include <util/listbox.h>
-#include <util/storage.h>
 
 #include <libxml/encoding.h>
 
+#include <storage.h>
 #include <lua.h>
 
 #include <assert.h>
@@ -807,7 +807,7 @@ static void handlekey(state * st, int c)
       if (strlen(datafile) > 0) {
         create_backup(datafile);
         remove_empty_units();
-        writegame(datafile, IO_DEFAULT);
+        writegame(datafile);
         st->modified = 0;
       }
     }
diff --git a/core/src/kernel/alchemy.c b/core/src/kernel/alchemy.c
index 4a6f17052..c7e4d2979 100644
--- a/core/src/kernel/alchemy.c
+++ b/core/src/kernel/alchemy.c
@@ -37,7 +37,8 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #include <util/base36.h>
 #include <util/log.h>
 #include <util/rand.h>
-#include <util/storage.h>
+
+#include <storage.h>
 
 /* libc includes */
 #include <stdio.h>
@@ -270,8 +271,8 @@ static void
 a_writeeffect(const attrib * a, const void *owner, struct storage *store)
 {
   effect_data *edata = (effect_data *) a->data.v;
-  store->w_tok(store, resourcename(edata->type->itype->rtype, 0));
-  store->w_int(store, edata->value);
+  WRITE_TOK(store, resourcename(edata->type->itype->rtype, 0));
+  WRITE_INT(store, edata->value);
 }
 
 static int a_readeffect(attrib * a, void *owner, struct storage *store)
@@ -281,10 +282,10 @@ static int a_readeffect(attrib * a, void *owner, struct storage *store)
   effect_data *edata = (effect_data *) a->data.v;
   char zText[32];
 
-  store->r_tok_buf(store, zText, sizeof(zText));
+  READ_TOK(store, zText, sizeof(zText));
   itype = it_find(zText);
 
-  power = store->r_int(store);
+  READ_INT(store, &power);
   if (itype == NULL || itype->rtype == NULL || itype->rtype->ptype == NULL
     || power <= 0) {
     return AT_READ_FAIL;
diff --git a/core/src/kernel/battle.c b/core/src/kernel/battle.c
index 9b249609d..a380c5d78 100644
--- a/core/src/kernel/battle.c
+++ b/core/src/kernel/battle.c
@@ -109,8 +109,8 @@ static int obs_count = 0;
 #ifndef ROW_FACTOR
 # define ROW_FACTOR 10
 #endif
-static const double EFFECT_PANIC_SPELL = 0.25;
-static const double TROLL_REGENERATION = 0.10;
+#define EFFECT_PANIC_SPELL 0.25
+#define TROLL_REGENERATION 0.10
 
 /* Nach dem alten System: */
 static int missile_range[2] = { FIGHT_ROW, BEHIND_ROW };
@@ -1662,7 +1662,7 @@ void do_combatmagic(battle * b, combatmagic_t was)
 
       level = eff_skill(mage, SK_MAGIC, r);
       if (level > 0) {
-        double power;
+        float power;
         const spell *sp;
         const struct locale *lang = mage->faction->locale;
         order *ord;
@@ -1735,7 +1735,7 @@ void do_combatmagic(battle * b, combatmagic_t was)
   }
 }
 
-static int cast_combatspell(troop at, const spell * sp, int level, double force)
+static int cast_combatspell(troop at, const spell * sp, int level, float force)
 {
   castorder co;
 
@@ -1758,7 +1758,7 @@ static void do_combatspell(troop at)
   region *r = b->region;
   quicklist *ql;
   int level, qi;
-  double power;
+  float power;
   int fumblechance = 0;
   order *ord;
   int sl;
@@ -3569,7 +3569,7 @@ battle *make_battle(region * r)
     char zText[MAX_PATH];
     char zFilename[MAX_PATH];
     sprintf(zText, "%s/battles", basepath());
-    os_mkdir(zText, 0700);
+    _mkdir(zText);
     sprintf(zFilename, "%s/battle-%d-%s.log", zText, obs_count, simplename(r));
     bdebug = fopen(zFilename, "w");
     if (!bdebug)
diff --git a/core/src/kernel/binarystore.c b/core/src/kernel/binarystore.c
deleted file mode 100644
index 2f750f4b4..000000000
--- a/core/src/kernel/binarystore.c
+++ /dev/null
@@ -1,274 +0,0 @@
-/* vi: set ts=2:
-+-------------------+  Enno Rehling <enno@eressea.de>
-| Eressea PBEM host |  Christian Schlittchen <corwin@amber.kn-bremen.de>
-| (c) 1998 - 2008   |  Katja Zedel <katze@felidae.kn-bremen.de>
-+-------------------+  
-This program may not be used, modified or distributed 
-without prior permission by the authors of Eressea.
-*/
-#include <platform.h>
-#include "config.h"
-#include "textstore.h"
-
-#include "save.h"
-#include "version.h"
-#include <util/base36.h>
-#include <util/log.h>
-
-#include <assert.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <libxml/encoding.h>
-
-#define file(store) (FILE *)((store)->userdata)
-
-#define STREAM_VERSION 2
-
-INLINE_FUNCTION size_t pack_int(int v, char *buffer)
-{
-  int sign = (v < 0);
-
-  if (sign) {
-    v = ~v + 1;
-    sign = 0x40;
-  }
-  if (v < 0x40) {
-    buffer[0] = (char)(v | sign);
-    return 1;
-  } else if (v < 0x2000) {
-    buffer[0] = (char)((v >> 6) | 0x80);
-    buffer[1] = (char)((v & 0x3F) | sign);
-    return 2;
-  } else if (v < 0x100000) {
-    buffer[0] = (char)(((v >> 13) & 0x7f) | 0x80);
-    buffer[1] = (char)(((v >> 6) & 0x7f) | 0x80);
-    buffer[2] = (char)((v & 0x3F) | sign);
-    return 3;
-  } else if (v < 0x8000000) {
-    buffer[0] = (char)(((v >> 20) & 0x7f) | 0x80);
-    buffer[1] = (char)(((v >> 13) & 0x7f) | 0x80);
-    buffer[2] = (char)(((v >> 6) & 0x7f) | 0x80);
-    buffer[3] = (char)((v & 0x3F) | sign);
-    return 4;
-  }
-  buffer[0] = (char)(((v >> 27) & 0x7f) | 0x80);
-  buffer[1] = (char)(((v >> 20) & 0x7f) | 0x80);
-  buffer[2] = (char)(((v >> 13) & 0x7f) | 0x80);
-  buffer[3] = (char)(((v >> 6) & 0x7f) | 0x80);
-  buffer[4] = (char)((v & 0x3F) | sign);
-  return 5;
-}
-
-INLINE_FUNCTION int unpack_int(const char *buffer)
-{
-  int i = 0, v = 0;
-
-  while (buffer[i] & 0x80) {
-    v = (v << 7) | (buffer[i++] & 0x7f);
-  }
-  v = (v << 6) | (buffer[i] & 0x3f);
-
-  if (buffer[i] & 0x40) {
-    v = ~v + 1;
-  }
-  return v;
-}
-
-static int bin_w_brk(struct storage *store)
-{
-  return 0;
-}
-
-static int bin_w_int_pak(struct storage *store, int arg)
-{
-  char buffer[5];
-  size_t size = pack_int(arg, buffer);
-  return (int)fwrite(buffer, sizeof(char), size, file(store));
-}
-
-static int bin_r_int_pak(struct storage *store)
-{
-  int v = 0;
-  char ch;
-
-  fread(&ch, sizeof(char), 1, file(store));
-  while (ch & 0x80) {
-    v = (v << 7) | (ch & 0x7f);
-    fread(&ch, sizeof(char), 1, file(store));
-  }
-  v = (v << 6) | (ch & 0x3f);
-
-  if (ch & 0x40) {
-    v = ~v + 1;
-  }
-  return v;
-}
-
-static int bin_w_int(struct storage *store, int arg)
-{
-  return (int)fwrite(&arg, sizeof(arg), 1, file(store));
-}
-
-static int bin_r_int(struct storage *store)
-{
-  int result;
-  fread(&result, sizeof(result), 1, file(store));
-  return result;
-}
-
-static int bin_w_flt(struct storage *store, float arg)
-{
-  return (int)fwrite(&arg, sizeof(arg), 1, file(store));
-}
-
-static float bin_r_flt(struct storage *store)
-{
-  float result;
-  fread(&result, sizeof(result), 1, file(store));
-  return result;
-}
-
-static int bin_w_str(struct storage *store, const char *tok)
-{
-  int result;
-  if (tok == NULL || tok[0] == 0) {
-    result = store->w_int(store, 0);
-  } else {
-    int size = (int)strlen(tok);
-    result = store->w_int(store, size);
-    result += (int)fwrite(tok, size, 1, file(store));
-  }
-  return result;
-}
-
-#define FIX_INVALID_CHARS       /* required for data pre-574 */
-static char *bin_r_str(struct storage *store)
-{
-  int len;
-
-  len = store->r_int(store);
-  if (len >= 0) {
-    char *result = malloc(len + 1);
-
-    fread(result, sizeof(char), len, file(store));
-    result[len] = 0;
-#ifdef FIX_INVALID_CHARS
-    {
-      char *p = strpbrk(result, "\n\r");
-      while (p) {
-        log_error("Invalid character %d in input string \"%s\".\n", *p, result);
-        strcpy(p, p + 1);
-        p = strpbrk(p, "\n\r");
-      }
-    }
-#endif
-    return result;
-  } else if (len < 0) {
-    log_error("invalid string-length %d in input.\n", len);
-  }
-  return NULL;
-}
-
-static void bin_r_str_buf(struct storage *store, char *result, size_t size)
-{
-  int i;
-  size_t rd, len;
-
-  i = store->r_int(store);
-  assert(i >= 0);
-  if (i == 0) {
-    result[0] = 0;
-  } else {
-    len = (size_t) i;
-    rd = MIN(len, size - 1);
-    fread(result, sizeof(char), rd, file(store));
-    if (rd < len) {
-      fseek(file(store), (long)(len - rd), SEEK_CUR);
-      result[size - 1] = 0;
-    } else {
-      result[len] = 0;
-    }
-#ifdef FIX_INVALID_CHARS
-    {
-      char *p = strpbrk(result, "\n\r");
-      while (p) {
-        log_error("Invalid character %d in input string \"%s\".\n", *p, result);
-        strcpy(p, p + 1);
-        p = strpbrk(p, "\n\r");
-      }
-    }
-#endif
-  }
-}
-
-static int bin_w_bin(struct storage *store, void *arg, size_t size)
-{
-  int result;
-  int len = (int)size;
-
-  result = store->w_int(store, len);
-  if (len > 0) {
-    result += (int)fwrite(arg, len, 1, file(store));
-  }
-  return result;
-}
-
-static void bin_r_bin(struct storage *store, void *result, size_t size)
-{
-  int len = store->r_int(store);
-  if (len > 0) {
-    if ((size_t) len > size) {
-      log_error("destination buffer too small %d %u.\n", len, size);
-      fseek(file(store), len, SEEK_CUR);
-    } else {
-      fread(result, len, 1, file(store));
-    }
-  }
-}
-
-static int bin_open(struct storage *store, const char *filename, int mode)
-{
-  const char *modes[] = { 0, "rb", "wb", "ab" };
-  FILE *F = fopen(filename, modes[mode]);
-  store->userdata = F;
-  store->encoding = XML_CHAR_ENCODING_UTF8;     /* always utf8 it is */
-  if (F) {
-    if (mode == IO_READ) {
-      int stream_version = 0;
-      store->version = bin_r_int(store);
-      if (store->version >= INTPAK_VERSION) {
-        stream_version = bin_r_int(store);
-      }
-      if (stream_version <= 1) {
-        store->r_id = bin_r_int;
-        store->w_id = bin_w_int;
-      }
-      if (stream_version == 0) {
-        store->r_int = bin_r_int;
-        store->w_int = bin_w_int;
-      }
-    } else if (store->encoding == XML_CHAR_ENCODING_UTF8) {
-      store->version = RELEASE_VERSION;
-      bin_w_int(store, RELEASE_VERSION);
-      bin_w_int(store, STREAM_VERSION);
-    }
-  }
-  return (F == NULL);
-}
-
-static int bin_close(struct storage *store)
-{
-  return fclose(file(store));
-}
-
-const storage binary_store = {
-  bin_w_brk,                    /* newline (ignore) */
-  bin_w_int_pak, bin_r_int_pak, /* int storage */
-  bin_w_flt, bin_r_flt,         /* float storage */
-  bin_w_int_pak, bin_r_int_pak, /* id storage */
-  bin_w_str, bin_r_str, bin_r_str_buf,  /* token storage */
-  bin_w_str, bin_r_str, bin_r_str_buf,  /* string storage */
-  bin_w_bin, bin_r_bin,         /* binary storage */
-  bin_open, bin_close,
-  0, 0, NULL
-};
diff --git a/core/src/kernel/binarystore.h b/core/src/kernel/binarystore.h
deleted file mode 100644
index c2ebc1c7b..000000000
--- a/core/src/kernel/binarystore.h
+++ /dev/null
@@ -1,23 +0,0 @@
-/* vi: set ts=2:
-+-------------------+  Enno Rehling <enno@eressea.de>
-| Eressea PBEM host |  Christian Schlittchen <corwin@amber.kn-bremen.de>
-| (c) 1998 - 2008   |  Katja Zedel <katze@felidae.kn-bremen.de>
-+-------------------+  
-This program may not be used, modified or distributed 
-without prior permission by the authors of Eressea.
-*/
-
-#ifndef H_KERNEL_BINSTORE
-#define H_KERNEL_BINSTORE
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#include <util/storage.h>
-
-  extern const storage binary_store;
-
-#ifdef __cplusplus
-}
-#endif
-#endif
diff --git a/core/src/kernel/building.c b/core/src/kernel/building.c
index 20f5fe480..4b0c08eae 100644
--- a/core/src/kernel/building.c
+++ b/core/src/kernel/building.c
@@ -42,9 +42,10 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #include <util/log.h>
 #include <quicklist.h>
 #include <util/resolve.h>
-#include <util/storage.h>
 #include <util/umlaut.h>
 
+#include <storage.h>
+
 /* libc includes */
 #include <assert.h>
 #include <stdlib.h>
@@ -80,33 +81,34 @@ lc_write(const struct attrib *a, const void *owner, struct storage *store)
   building *b = data->b;
 
   write_building_reference(b, store);
-  store->w_tok(store, fname);
-  store->w_tok(store, fparam ? fparam : NULLSTRING);
+  WRITE_TOK(store, fname);
+  WRITE_TOK(store, fparam ? fparam : NULLSTRING);
 }
 
 static int lc_read(struct attrib *a, void *owner, struct storage *store)
 {
+  char name[NAMESIZE];
   building_action *data = (building_action *) a->data.v;
   int result =
     read_reference(&data->b, store, read_building_reference, resolve_building);
-  if (store->version < UNICODE_VERSION) {
-    data->fname = store->r_str(store);
+  if (global.data_version < UNICODE_VERSION) {
+    READ_STR(store, name, sizeof(name));
   } else {
-    data->fname = store->r_tok(store);
+    READ_TOK(store, name, sizeof(name));
   }
-  if (store->version >= BACTION_VERSION) {
-    char lbuf[256];
-    if (store->version < UNICODE_VERSION) {
-      store->r_str_buf(store, lbuf, sizeof(lbuf));
+  data->fname = _strdup(name);
+  if (global.data_version >= BACTION_VERSION) {
+    if (global.data_version < UNICODE_VERSION) {
+      READ_STR(store, name, sizeof(name));
     } else {
-      store->r_tok_buf(store, lbuf, sizeof(lbuf));
+      READ_TOK(store, name, sizeof(name));
     }
-    if (strcmp(lbuf, NULLSTRING) == 0)
-      data->param = NULL;
+    if (strcmp(name, NULLSTRING) == 0)
+      data->param = 0;
     else
-      data->param = _strdup(lbuf);
+      data->param = _strdup(name);
   } else {
-    data->param = _strdup(NULLSTRING);
+    data->param = 0;
   }
   if (result == 0 && !data->b) {
     return AT_READ_FAIL;
@@ -422,7 +424,7 @@ void register_buildings(void)
 
 void write_building_reference(const struct building *b, struct storage *store)
 {
-  store->w_id(store, (b && b->region) ? b->no : 0);
+  WRITE_INT(store, (b && b->region) ? b->no : 0);
 }
 
 int resolve_building(variant id, void *address)
@@ -442,7 +444,7 @@ int resolve_building(variant id, void *address)
 variant read_building_reference(struct storage * store)
 {
   variant result;
-  result.i = store->r_id(store);
+  READ_INT(store, &result.i);
   return result;
 }
 
diff --git a/core/src/kernel/config.h b/core/src/kernel/config.h
index acc67637b..2e6008017 100644
--- a/core/src/kernel/config.h
+++ b/core/src/kernel/config.h
@@ -87,10 +87,10 @@ extern "C" {
 
 #define ENCCHANCE           10  /* %-Chance f�r einmalige Zufallsbegegnung */
 
-#define DISPLAYSIZE         8191        /* max. L�nge einer Beschreibung, ohne trailing 0 */
-#define NAMESIZE            127 /* max. L�nge eines Namens, ohne trailing 0 */
-#define IDSIZE              15  /* max. L�nge einer no (als String), ohne trailing 0 */
-#define KEYWORDSIZE         15  /* max. L�nge eines Keyword, ohne trailing 0 */
+#define DISPLAYSIZE         8192        /* max. L�nge einer Beschreibung, incl trailing 0 */
+#define NAMESIZE            128 /* max. L�nge eines Namens, incl trailing 0 */
+#define IDSIZE              16  /* max. L�nge einer no (als String), incl trailing 0 */
+#define KEYWORDSIZE         16  /* max. L�nge eines Keyword, incl trailing 0 */
 #define OBJECTIDSIZE        (NAMESIZE+5+IDSIZE) /* max. L�nge der Strings, die
                                                  * von struct unitname, etc. zur�ckgegeben werden. ohne die 0 */
 
@@ -392,6 +392,7 @@ extern "C" {
     void *vm_state;
     float producexpchance;
     int cookie;
+    int data_version; /* TODO: eliminate in favor of gamedata.version */
     struct _dictionary_ *inifile;
 
     struct global_functions {
diff --git a/core/src/kernel/connection.c b/core/src/kernel/connection.c
index 7bbb2e75a..5dc4c470f 100644
--- a/core/src/kernel/connection.c
+++ b/core/src/kernel/connection.c
@@ -32,7 +32,8 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #include <util/log.h>
 #include <quicklist.h>
 #include <util/rng.h>
-#include <util/storage.h>
+
+#include <storage.h>
 
 /* libc includes */
 #include <assert.h>
@@ -189,15 +190,17 @@ border_type *find_bordertype(const char *name)
 
 void b_read(connection * b, storage * store)
 {
-  int result = 0;
+  int n, result = 0;
   switch (b->type->datatype) {
     case VAR_NONE:
     case VAR_INT:
-      b->data.i = store->r_int(store);
+      READ_INT(store, &b->data.i);
       break;
     case VAR_SHORTA:
-      b->data.sa[0] = (short)store->r_int(store);
-      b->data.sa[1] = (short)store->r_int(store);
+      READ_INT(store, &n);
+      b->data.sa[0] = (short)n;
+      READ_INT(store, &n);
+      b->data.sa[1] = (short)n;
       break;
     case VAR_VOIDPTR:
     default:
@@ -212,11 +215,11 @@ void b_write(const connection * b, storage * store)
   switch (b->type->datatype) {
     case VAR_NONE:
     case VAR_INT:
-      store->w_int(store, b->data.i);
+      WRITE_INT(store, b->data.i);
       break;
     case VAR_SHORTA:
-      store->w_int(store, b->data.sa[0]);
-      store->w_int(store, b->data.sa[1]);
+      WRITE_INT(store, b->data.sa[0]);
+      WRITE_INT(store, b->data.sa[1]);
       break;
     case VAR_VOIDPTR:
     default:
@@ -548,21 +551,22 @@ static const char *b_nameroad(const connection * b, const region * r,
 
 static void b_readroad(connection * b, storage * store)
 {
-  b->data.sa[0] = (short)store->r_int(store);
-  b->data.sa[1] = (short)store->r_int(store);
+  int n;
+  READ_INT(store, &n);
+  b->data.sa[0] = (short)n;
+  READ_INT(store, &n);
+  b->data.sa[1] = (short)n;
 }
 
 static void b_writeroad(const connection * b, storage * store)
 {
-  store->w_int(store, b->data.sa[0]);
-  store->w_int(store, b->data.sa[1]);
+  WRITE_INT(store, b->data.sa[0]);
+  WRITE_INT(store, b->data.sa[1]);
 }
 
 static bool b_validroad(const connection * b)
 {
-  if (b->data.sa[0] == SHRT_MAX)
-    return false;
-  return true;
+  return (b->data.sa[0] != SHRT_MAX);
 }
 
 static bool b_rvisibleroad(const connection * b, const region * r)
@@ -603,18 +607,18 @@ void write_borders(struct storage *store)
       for (b = bhash; b != NULL; b = b->next) {
         if (b->type->valid && !b->type->valid(b))
           continue;
-        store->w_tok(store, b->type->__name);
-        store->w_int(store, b->id);
-        store->w_int(store, b->from->uid);
-        store->w_int(store, b->to->uid);
+        WRITE_TOK(store, b->type->__name);
+        WRITE_INT(store, b->id);
+        WRITE_INT(store, b->from->uid);
+        WRITE_INT(store, b->to->uid);
 
         if (b->type->write)
           b->type->write(b, store);
-        store->w_brk(store);
+        WRITE_SECTION(store);
       }
     }
   }
-  store->w_tok(store, "end");
+  WRITE_TOK(store, "end");
 }
 
 int read_borders(struct storage *store)
@@ -626,21 +630,22 @@ int read_borders(struct storage *store)
     region *from, *to;
     border_type *type;
 
-    store->r_tok_buf(store, zText, sizeof(zText));
+    READ_TOK(store, zText, sizeof(zText));
     if (!strcmp(zText, "end"))
       break;
-    bid = store->r_int(store);
-    if (store->version < UIDHASH_VERSION) {
-      short fx, fy, tx, ty;
-      fx = (short)store->r_int(store);
-      fy = (short)store->r_int(store);
-      tx = (short)store->r_int(store);
-      ty = (short)store->r_int(store);
+    READ_INT(store, &bid);
+    if (global.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 {
-      unsigned int fid = (unsigned int)store->r_int(store);
-      unsigned int tid = (unsigned int)store->r_int(store);
+      unsigned int fid, tid;
+      READ_INT(store, &fid);
+      READ_INT(store, &tid);
       from = findregionbyid(fid);
       to = findregionbyid(tid);
     }
@@ -664,7 +669,7 @@ int read_borders(struct storage *store)
     assert(bid <= nextborder);
     if (type->read)
       type->read(b, store);
-    if (store->version < NOBORDERATTRIBS_VERSION) {
+    if (global.data_version < NOBORDERATTRIBS_VERSION) {
       attrib *a = NULL;
       int result = a_read(store, &a, b);
       if (border_convert_cb)
diff --git a/core/src/kernel/curse.c b/core/src/kernel/curse.c
index a903d8bed..7ea26d624 100644
--- a/core/src/kernel/curse.c
+++ b/core/src/kernel/curse.c
@@ -43,9 +43,10 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #include <util/rand.h>
 #include <util/resolve.h>
 #include <util/rng.h>
-#include <util/storage.h>
 #include <util/variant.h>
 
+#include <storage.h>
+
 /* libc includes */
 #include <stdio.h>
 #include <string.h>
@@ -159,19 +160,19 @@ static int read_ccompat(const char *cursename, struct storage *store)
       for (p = seek->name; p; ++p) {
         switch (*p) {
           case 'd':
-            store->r_int(store);
+            READ_INT(store, 0);
             break;
           case 's':
-            store->r_str(store);
+            READ_STR(store, 0, 0);
             break;
           case 't':
-            store->r_tok(store);
+            READ_TOK(store, 0, 0);
             break;
           case 'i':
-            store->r_id(store);
+            READ_INT(store, 0);
             break;
           case 'f':
-            store->r_flt(store);
+            READ_FLT(store, 0);
             break;
         }
       }
@@ -186,28 +187,32 @@ int curse_read(attrib * a, void *owner, struct storage *store)
   curse *c = (curse *) a->data.v;
   int ur;
   char cursename[64];
-  unsigned int flags;
+  unsigned int n, flags;
+  float flt;
 
-  c->no = store->r_int(store);
+  READ_INT(store, &c->no);
   chash(c);
-  store->r_tok_buf(store, cursename, sizeof(cursename));
-  flags = store->r_int(store);
-  c->duration = store->r_int(store);
-  if (store->version >= CURSEVIGOURISFLOAT_VERSION) {
-    c->vigour = store->r_flt(store);
+  READ_TOK(store, cursename, sizeof(cursename));
+  READ_INT(store, &flags);
+  READ_INT(store, &c->duration);
+  if (global.data_version >= CURSEVIGOURISFLOAT_VERSION) {
+    READ_FLT(store, &flt);
+    c->vigour = flt;
   } else {
-    int vigour = store->r_int(store);
-    c->vigour = vigour;
+    READ_INT(store, &n);
+    c->vigour = (float)n;
   }
-  if (store->version < INTPAK_VERSION) {
+  if (global.data_version < INTPAK_VERSION) {
     ur = read_reference(&c->magician, store, read_int, resolve_unit);
   } else {
     ur = read_reference(&c->magician, store, read_unit_reference, resolve_unit);
   }
-  if (store->version < CURSEFLOAT_VERSION) {
-    c->effect = (double)store->r_int(store);
+  if (global.data_version < CURSEFLOAT_VERSION) {
+    READ_INT(store, &n);
+    c->effect = (float)n;
   } else {
-    c->effect = store->r_flt(store);
+    READ_FLT(store, &flt);
+    c->effect = flt;
   }
   c->type = ct_find(cursename);
   if (c->type == NULL) {
@@ -218,7 +223,7 @@ int curse_read(attrib * a, void *owner, struct storage *store)
     assert(result == 0);
     return AT_READ_FAIL;
   }
-  if (store->version < CURSEFLAGS_VERSION) {
+  if (global.data_version < CURSEFLAGS_VERSION) {
     c_setflag(c, flags);
   } else {
     c->flags = flags;
@@ -228,12 +233,12 @@ int curse_read(attrib * a, void *owner, struct storage *store)
   if (c->type->read)
     c->type->read(store, c, owner);
   else if (c->type->typ == CURSETYP_UNIT) {
-    c->data.i = store->r_int(store);
+    READ_INT(store, &c->data.i);
   }
   if (c->type->typ == CURSETYP_REGION) {
     int rr =
       read_reference(&c->data.v, store, read_region_reference,
-      RESOLVE_REGION(store->version));
+      RESOLVE_REGION(global.data_version));
     if (ur == 0 && rr == 0 && !c->data.v) {
       return AT_READ_FAIL;
     }
@@ -252,18 +257,18 @@ void curse_write(const attrib * a, const void *owner, struct storage *store)
   /* copied from c_clearflag */
   flags = (c->flags & ~CURSE_ISNEW) | (c->type->flags & CURSE_ISNEW);
 
-  store->w_int(store, c->no);
-  store->w_tok(store, ct->cname);
-  store->w_int(store, flags);
-  store->w_int(store, c->duration);
-  store->w_flt(store, (float)c->vigour);
+  WRITE_INT(store, c->no);
+  WRITE_TOK(store, ct->cname);
+  WRITE_INT(store, flags);
+  WRITE_INT(store, c->duration);
+  WRITE_FLT(store, (float)c->vigour);
   write_unit_reference(mage, store);
-  store->w_flt(store, (float)c->effect);
+  WRITE_FLT(store, (float)c->effect);
 
   if (c->type->write)
     c->type->write(store, c, owner);
   else if (c->type->typ == CURSETYP_UNIT) {
-    store->w_int(store, c->data.i);
+    WRITE_INT(store, c->data.i);
   }
   if (c->type->typ == CURSETYP_REGION) {
     write_region_reference((region *) c->data.v, store);
@@ -393,7 +398,7 @@ void remove_curse(attrib ** ap, const curse * c)
 /* gibt die allgemeine St�rke der Verzauberung zur�ck. id2 wird wie
  * oben benutzt. Dies ist nicht die Wirkung, sondern die Kraft und
  * damit der gegen Antimagie wirkende Widerstand einer Verzauberung */
-static double get_cursevigour(const curse * c)
+static float get_cursevigour(const curse * c)
 {
   if (c)
     return c->vigour;
@@ -401,7 +406,7 @@ static double get_cursevigour(const curse * c)
 }
 
 /* setzt die St�rke der Verzauberung auf i */
-static void set_cursevigour(curse * c, double vigour)
+static void set_cursevigour(curse * c, float vigour)
 {
   assert(c && vigour > 0);
   c->vigour = vigour;
@@ -411,7 +416,7 @@ static void set_cursevigour(curse * c, double vigour)
  * St�rke zur�ck. Sollte die Zauberst�rke unter Null sinken, l�st er
  * sich auf.
  */
-double curse_changevigour(attrib ** ap, curse * c, double vigour)
+float curse_changevigour(attrib ** ap, curse * c, float vigour)
 {
   vigour += get_cursevigour(c);
 
@@ -426,7 +431,7 @@ double curse_changevigour(attrib ** ap, curse * c, double vigour)
 
 /* ------------------------------------------------------------- */
 
-double curse_geteffect(const curse * c)
+float curse_geteffect(const curse * c)
 {
   if (c == NULL)
     return 0;
@@ -437,7 +442,7 @@ double curse_geteffect(const curse * c)
 
 int curse_geteffect_int(const curse * c)
 {
-  double effect = curse_geteffect(c);
+  float effect = curse_geteffect(c);
   if (effect - (int)effect != 0) {
     log_error("curse has an integer attribute with float value: '%s' = %lf",
               c->type->cname, effect);
@@ -491,7 +496,7 @@ static void set_cursedmen(curse * c, int cursedmen)
  * dieses Typs geben, gibt es den bestehenden zur�ck.
  */
 static curse *make_curse(unit * mage, attrib ** ap, const curse_type * ct,
-  double vigour, int duration, double effect, int men)
+  float vigour, int duration, float effect, int men)
 {
   curse *c;
   attrib *a;
@@ -528,7 +533,7 @@ static curse *make_curse(unit * mage, attrib ** ap, const curse_type * ct,
  * passenden Typ verzweigt und die relevanten Variablen weitergegeben.
  */
 curse *create_curse(unit * magician, attrib ** ap, const curse_type * ct,
-  double vigour, int duration, double effect, int men)
+  float vigour, int duration, float effect, int men)
 {
   curse *c;
 
@@ -784,7 +789,7 @@ message *cinfo_simple(const void *obj, objtype_t typ, const struct curse * c,
 * die Kraft des Curse um die halbe St�rke der Antimagie reduziert.
 * Zur�ckgegeben wird der noch unverbrauchte Rest von force.
 */
-double destr_curse(curse * c, int cast_level, double force)
+float destr_curse(curse * c, int cast_level, float force)
 {
   if (cast_level < c->vigour) { /* Zauber ist nicht stark genug */
     double probability = 0.1 + (cast_level - c->vigour) * 0.2;
@@ -792,7 +797,7 @@ double destr_curse(curse * c, int cast_level, double force)
     if (chance(probability)) {
       force -= c->vigour;
       if (c->type->change_vigour) {
-        c->type->change_vigour(c, -(cast_level + 1 / 2));
+        c->type->change_vigour(c, -((float)cast_level + 1) / 2);
       } else {
         c->vigour -= cast_level + 1 / 2;
       }
diff --git a/core/src/kernel/curse.h b/core/src/kernel/curse.h
index a4b2f9c80..078e9855e 100644
--- a/core/src/kernel/curse.h
+++ b/core/src/kernel/curse.h
@@ -194,9 +194,9 @@ extern "C" {
     const struct curse_type *type;      /* Zeiger auf ein curse_type-struct */
     unsigned int flags;         /* WARNING: these are XORed with type->flags! */
     int duration;               /* Dauer der Verzauberung. Wird jede Runde vermindert */
-    double vigour;              /* St�rke der Verzauberung, Widerstand gegen Antimagie */
+    float vigour;              /* St�rke der Verzauberung, Widerstand gegen Antimagie */
     struct unit *magician;      /* Pointer auf den Magier, der den Spruch gewirkt hat */
-    double effect;
+    float effect;
     variant data;               /* pointer auf spezielle curse-unterstructs */
   } curse;
 
@@ -211,7 +211,7 @@ extern "C" {
     unsigned int mergeflags;
     struct message *(*curseinfo) (const void *, objtype_t, const struct curse *,
       int);
-    void (*change_vigour) (curse *, double);
+    void(*change_vigour) (curse *, float);
     int (*read) (struct storage * store, curse * c, void *target);
     int (*write) (struct storage * store, const struct curse * c,
       const void *target);
@@ -238,7 +238,7 @@ extern "C" {
 */
 
   curse *create_curse(struct unit *magician, struct attrib **ap,
-    const curse_type * ctype, double vigour, int duration, double ceffect,
+    const curse_type * ctype, float vigour, int duration, float ceffect,
     int men);
   /* Verzweigt automatisch zum passenden struct-typ. Sollte es schon
    * einen Zauber dieses Typs geben, so wird der neue dazuaddiert. Die
@@ -255,15 +255,15 @@ extern "C" {
   /* l�scht einen konkreten Spruch auf einem Objekt.
    */
 
-  extern int curse_geteffect_int(const struct curse *c);
-  extern double curse_geteffect(const struct curse *c);
+  int curse_geteffect_int(const struct curse *c);
+  float curse_geteffect(const struct curse *c);
   /* gibt die Auswirkungen der Verzauberungen zur�ck. zB bei
    * Skillmodifiziernden Verzauberungen ist hier der Modifizierer
    * gespeichert. Wird automatisch beim Anlegen eines neuen curse
    * gesetzt. Gibt immer den ersten Treffer von ap aus zur�ck.
    */
 
-  extern double curse_changevigour(struct attrib **ap, curse * c, double i);
+  float curse_changevigour(struct attrib **ap, curse * c, float i);
   /* ver�ndert die St�rke der Verzauberung um i */
 
   extern int get_cursedmen(struct unit *u, const struct curse *c);
@@ -306,7 +306,7 @@ extern "C" {
   extern bool cmp_curse(const struct attrib *a, const void *data);
   extern bool cmp_cursetype(const struct attrib *a, const void *data);
 
-  extern double destr_curse(struct curse *c, int cast_level, double force);
+  extern float destr_curse(struct curse *c, int cast_level, float force);
 
   extern int resolve_curse(variant data, void *address);
   extern bool is_cursed_with(const struct attrib *ap, const struct curse *c);
diff --git a/core/src/kernel/faction.c b/core/src/kernel/faction.c
index 02091050c..340eb5d5e 100755
--- a/core/src/kernel/faction.c
+++ b/core/src/kernel/faction.c
@@ -46,12 +46,13 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #include <quicklist.h>
 #include <util/resolve.h>
 #include <util/rng.h>
-#include <util/storage.h>
 #include <util/sql.h>
 #include <util/variant.h>
 #include <util/unicode.h>
 #include <attributes/otherfaction.h>
 
+#include <storage.h>
+
 /* libc includes */
 #include <assert.h>
 #include <stdio.h>
@@ -271,13 +272,13 @@ bool checkpasswd(const faction * f, const char *passwd, bool shortp)
 variant read_faction_reference(struct storage * store)
 {
   variant id;
-  id.i = store->r_id(store);
+  READ_INT(store, &id.i);
   return id;
 }
 
 void write_faction_reference(const faction * f, struct storage *store)
 {
-  store->w_id(store, f ? f->no : 0);
+  WRITE_INT(store, f ? f->no : 0);
 }
 
 void destroyfaction(faction * f)
diff --git a/core/src/kernel/group.c b/core/src/kernel/group.c
index bf954ec40..2a5098490 100755
--- a/core/src/kernel/group.c
+++ b/core/src/kernel/group.c
@@ -34,9 +34,10 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #include <util/attrib.h>
 #include <util/base36.h>
 #include <util/resolve.h>
-#include <util/storage.h>
 #include <util/unicode.h>
 
+#include <storage.h>
+
 /* libc includes */
 #include <assert.h>
 #include <stdlib.h>
@@ -98,7 +99,9 @@ static group *find_group(int gid)
 static int read_group(attrib * a, void *owner, struct storage *store)
 {
   group *g;
-  int gid = store->r_int(store);
+  int gid;
+
+  READ_INT(store, &gid);
   a->data.v = g = find_group(gid);
   if (g != 0) {
     g->members++;
@@ -111,7 +114,7 @@ static void
 write_group(const attrib * a, const void *owner, struct storage *store)
 {
   group *g = (group *) a->data.v;
-  store->w_int(store, g->gid);
+  WRITE_INT(store, g->gid);
 }
 
 attrib_type at_group = {        /* attribute for units assigned to a group */
@@ -196,20 +199,20 @@ void write_groups(struct storage *store, group * g)
 {
   while (g) {
     ally *a;
-    store->w_int(store, g->gid);
-    store->w_str(store, g->name);
+    WRITE_INT(store, g->gid);
+    WRITE_STR(store, g->name);
     for (a = g->allies; a; a = a->next) {
       if (a->faction) {
         write_faction_reference(a->faction, store);
-        store->w_int(store, a->status);
+        WRITE_INT(store, a->status);
       }
     }
-    store->w_id(store, 0);
+    WRITE_INT(store, 0);
     a_write(store, g->attribs, g);
-    store->w_brk(store);
+    WRITE_SECTION(store);
     g = g->next;
   }
-  store->w_int(store, 0);
+  WRITE_INT(store, 0);
 }
 
 void read_groups(struct storage *store, faction * f)
@@ -220,24 +223,24 @@ void read_groups(struct storage *store, faction * f)
     int gid;
     char buf[1024];
 
-    gid = store->r_int(store);
+    READ_INT(store, &gid);
     if (gid == 0)
       break;
-    store->r_str_buf(store, buf, sizeof(buf));
+    READ_STR(store, buf, sizeof(buf));
     g = new_group(f, buf, gid);
     pa = &g->allies;
     for (;;) {
       ally *a;
       variant fid;
-      fid.i = store->r_id(store);
+      READ_INT(store, &fid.i);
       if (fid.i <= 0)
         break;
-      if (store->version < STORAGE_VERSION && fid.i == 0)
+      if (global.data_version < STORAGE_VERSION && fid.i == 0)
         break;
       a = malloc(sizeof(ally));
       *pa = a;
       pa = &a->next;
-      a->status = store->r_int(store);
+      READ_INT(store, &a->status);
 
       a->faction = findfaction(fid.i);
       if (!a->faction)
diff --git a/core/src/kernel/group.h b/core/src/kernel/group.h
index 17b44ab3d..ea312542c 100755
--- a/core/src/kernel/group.h
+++ b/core/src/kernel/group.h
@@ -25,6 +25,8 @@ extern "C" {
 /* bitfield value for group::flags */
 #define GFL_ALIVE 0x01          /* There is at least one struct unit in the group */
 
+  struct gamedata;
+
   typedef struct group {
     struct group *next;
     struct group *nexthash;
@@ -43,8 +45,8 @@ extern "C" {
   extern struct group * get_group(const struct unit *u);
   extern void free_group(struct group *g);
 
-  extern void write_groups(struct storage *F, struct group *g);
-  extern void read_groups(struct storage *F, struct faction *f);
+  extern void write_groups(struct storage *data, struct group *g);
+  extern void read_groups(struct storage *data, struct faction *f);
 
 #ifdef __cplusplus
 }
diff --git a/core/src/kernel/item.c b/core/src/kernel/item.c
index 9f94054a8..c7ed8304b 100644
--- a/core/src/kernel/item.c
+++ b/core/src/kernel/item.c
@@ -666,13 +666,13 @@ use_tacticcrystal(unit * u, const struct item_type *itype, int amount,
   int i;
   for (i = 0; i != amount; ++i) {
     int duration = 1;           /* wirkt nur eine Runde */
+    curse *c;
+    float effect;
     float power = 5;            /* Widerstand gegen Antimagiespr�che, ist in diesem
                                    Fall egal, da der curse f�r den Kampf gelten soll,
                                    der vor den Antimagiezaubern passiert */
-    curse *c;
-    double effect;
 
-    effect = rng_int() % 6 - 1;
+    effect = (float)(rng_int() % 6 - 1);
     c = create_curse(u, &u->attribs, ct_find("skillmod"), power,
       duration, effect, u->number);
     c->data.i = SK_TACTICS;
diff --git a/core/src/kernel/magic.c b/core/src/kernel/magic.c
index ea34080b4..5d98b1d6d 100644
--- a/core/src/kernel/magic.c
+++ b/core/src/kernel/magic.c
@@ -61,11 +61,12 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #include <util/resolve.h>
 #include <util/rand.h>
 #include <util/rng.h>
-#include <util/storage.h>
 #include <util/umlaut.h>
 #include <util/base36.h>
 #include <util/event.h>
 
+#include <storage.h>
+
 /* libc includes */
 #include <assert.h>
 #include <stdio.h>
@@ -104,22 +105,22 @@ attrib_type at_reportspell = {
  ** TODO: separate castle-appearance from illusion-effects
  **/
 
-static double MagicRegeneration(void)
+static float MagicRegeneration(void)
 {
-  static double value = -1.0;
+  static float value = -1.0;
   if (value < 0) {
     const char *str = get_param(global.parameters, "magic.regeneration");
-    value = str ? atof(str) : 1.0;
+    value = str ? (float)atof(str) : 1.0F;
   }
   return value;
 }
 
-double MagicPower(void)
+float MagicPower(void)
 {
-  static double value = -1.0;
+  static float value = -1.0;
   if (value < 0) {
     const char *str = get_param(global.parameters, "magic.power");
-    value = str ? atof(str) : 1.0;
+    value = str ? (float)atof(str) : 1.0f;
   }
   return value;
 }
@@ -129,9 +130,9 @@ static int a_readicastle(attrib * a, void *owner, struct storage *store)
   icastle_data *data = (icastle_data *) a->data.v;
   variant bno;
   char token[32];
-  store->r_tok_buf(store, token, sizeof(token));
-  bno.i = store->r_int(store);
-  data->time = store->r_int(store);
+  READ_TOK(store, token, sizeof(token));
+  READ_INT(store, &bno.i);
+  READ_INT(store, &data->time);
   data->building = findbuilding(bno.i);
   if (!data->building) {
     /* this shouldn't happen, but just in case it does: */
@@ -145,9 +146,9 @@ static void
 a_writeicastle(const attrib * a, const void *owner, struct storage *store)
 {
   icastle_data *data = (icastle_data *) a->data.v;
-  store->w_tok(store, data->type->_name);
-  store->w_int(store, data->building->no);
-  store->w_int(store, data->time);
+  WRITE_TOK(store, data->type->_name);
+  WRITE_INT(store, data->building->no);
+  WRITE_INT(store, data->time);
 }
 
 static int a_ageicastle(struct attrib *a)
@@ -225,13 +226,14 @@ void read_spells(struct quicklist **slistp, magic_t mtype,
     spell *sp;
     char spname[64];
 
-    if (store->version < SPELLNAME_VERSION) {
-      int i = store->r_int(store);
+    if (global.data_version < SPELLNAME_VERSION) {
+      int i;
+      READ_INT(store, &i);
       if (i < 0)
         break;
       sp = find_spellbyid((unsigned int) i);
     } else {
-      store->r_tok_buf(store, spname, sizeof(spname));
+      READ_TOK(store, spname, sizeof(spname));
       if (strcmp(spname, "end") == 0)
         break;
       sp = find_spell(spname);
@@ -259,23 +261,23 @@ static int read_mage(attrib * a, void *owner, struct storage *store)
   sc_mage *mage = (sc_mage *) a->data.v;
   char spname[64];
 
-  mtype = store->r_int(store);
-  mage->spellpoints = store->r_int(store);
-  mage->spchange = store->r_int(store);
-  mage->magietyp = (magic_t) mtype;
+  READ_INT(store, &mtype);
+  mage->magietyp = (magic_t)mtype;
+  READ_INT(store, &mage->spellpoints);
+  READ_INT(store, &mage->spchange);
   for (i = 0; i != MAXCOMBATSPELLS; ++i) {
     spell *sp = NULL;
     int level = 0;
-    if (store->version < SPELLNAME_VERSION) {
+    if (global.data_version < SPELLNAME_VERSION) {
       int spid;
-      spid = store->r_int(store);
-      level = store->r_int(store);
+      READ_INT(store, &spid);
+      READ_INT(store, &level);
       if (spid >= 0) {
         sp = find_spellbyid((unsigned int) spid);
       }
     } else {
-      store->r_tok_buf(store, spname, sizeof(spname));
-      level = store->r_int(store);
+      READ_TOK(store, spname, sizeof(spname));
+      READ_INT(store, &level);
 
       if (strcmp("none", spname) != 0) {
         sp = find_spell(spname);
@@ -313,9 +315,9 @@ void write_spells(struct quicklist *slist, struct storage *store)
 
   for (ql = slist, qi = 0; ql; ql_advance(&ql, &qi, 1)) {
     spell *sp = (spell *) ql_get(ql, qi);
-    store->w_tok(store, sp->sname);
+    WRITE_TOK(store, sp->sname);
   }
-  store->w_tok(store, "end");
+  WRITE_TOK(store, "end");
 }
 
 static void
@@ -324,13 +326,13 @@ write_mage(const attrib * a, const void *owner, struct storage *store)
   int i;
   sc_mage *mage = (sc_mage *) a->data.v;
 
-  store->w_int(store, mage->magietyp);
-  store->w_int(store, mage->spellpoints);
-  store->w_int(store, mage->spchange);
+  WRITE_INT(store, mage->magietyp);
+  WRITE_INT(store, mage->spellpoints);
+  WRITE_INT(store, mage->spchange);
   for (i = 0; i != MAXCOMBATSPELLS; ++i) {
-    store->w_tok(store,
+    WRITE_TOK(store,
       mage->combatspells[i].sp ? mage->combatspells[i].sp->sname : "none");
-    store->w_int(store, mage->combatspells[i].level);
+    WRITE_INT(store, mage->combatspells[i].level);
   }
   write_spellbook(mage->spellbook, store);
 }
@@ -374,13 +376,13 @@ static int read_seenspell(attrib * a, void *owner, struct storage *store)
   spell *sp = 0;
   char token[32];
 
-  store->r_tok_buf(store, token, sizeof(token));
+  READ_TOK(store, token, sizeof(token));
   i = atoi(token);
   if (i != 0) {
     sp = find_spellbyid((unsigned int) i);
   } else {
-    if (store->version<UNIQUE_SPELLS_VERSION) {
-      store->r_int(store); /* ignore mtype */
+    if (global.data_version<UNIQUE_SPELLS_VERSION) {
+      READ_INT(store, 0); /* ignore mtype */
     }
     sp = find_spell(token);
     if (!sp) {
@@ -398,7 +400,7 @@ static void
 write_seenspell(const attrib * a, const void *owner, struct storage *store)
 {
   const spell *sp = (const spell *)a->data.v;
-  store->w_tok(store, sp->sname);
+  WRITE_TOK(store, sp->sname);
 }
 
 attrib_type at_seenspell = {
@@ -1002,12 +1004,12 @@ cancast(unit * u, const spell * sp, int level, int range, struct order * ord)
  * Spruchfunktionsroutine ermittelt.
  */
 
-double
+float
 spellpower(region * r, unit * u, const spell * sp, int cast_level,
   struct order *ord)
 {
   curse *c;
-  double force = cast_level;
+  float force = (float)cast_level;
   int elf_power = -1;
 
   if (sp == NULL) {
@@ -1333,7 +1335,7 @@ static void do_fumble(castorder * co)
   const spell *sp = co->sp;
   int level = co->level;
   int duration;
-  double effect;
+  float effect;
 
   ADDMSG(&u->faction->msgs, msg_message("patzer", "unit region spell",
       u, r, sp));
@@ -1377,7 +1379,7 @@ static void do_fumble(castorder * co)
   case 2:
     /* tempor�rer Stufenverlust */
     duration = MAX(rng_int() % level / 2, 2);
-    effect = -0.5 * level;
+    effect = -(float)level/2;
     c =
       create_curse(u, &u->attribs, ct_find("skillmod"), (float)level,
       duration, effect, 1);
@@ -2057,7 +2059,7 @@ struct region * co_get_region(struct castorder * co) {
 }
 
 castorder *create_castorder(castorder * co, unit *caster, unit * familiar, const spell * sp, region * r,
-  int lev, double force, int range, struct order * ord, spellparameter * p)
+  int lev, float force, int range, struct order * ord, spellparameter * p)
 {
   if (!co) co = (castorder*)calloc(1, sizeof(castorder));
 
diff --git a/core/src/kernel/magic.h b/core/src/kernel/magic.h
index f2dfaa5ba..eb3c27d4c 100644
--- a/core/src/kernel/magic.h
+++ b/core/src/kernel/magic.h
@@ -128,7 +128,7 @@ typedef struct sc_mage {
                                    den Vertrauten gezaubert wird */
     const struct spell *sp;     /* Spruch */
     int level;                  /* gew�nschte Stufe oder Stufe des Magiers */
-    double force;               /* St�rke des Zaubers */
+    float force;               /* St�rke des Zaubers */
     struct region *_rtarget;     /* Zielregion des Spruchs */
     int distance;               /* Entfernung zur Zielregion */
     struct order *order;        /* Befehl */
@@ -274,7 +274,7 @@ typedef struct sc_mage {
   /* ver�ndert die maximalen Magiepunkte einer Einheit */
 
 /* Zaubern */
-  extern double spellpower(struct region *r, struct unit *u, const struct spell * sp,
+  extern float spellpower(struct region *r, struct unit *u, const struct spell * sp,
     int cast_level, struct order *ord);
   /*      ermittelt die St�rke eines Spruchs */
   bool fumble(struct region *r, struct unit *u, const struct spell * sp,
@@ -288,7 +288,7 @@ typedef struct sc_mage {
 
   struct castorder *create_castorder(struct castorder * co, struct unit *caster, 
     struct unit * familiar, const struct spell * sp, struct region * r,
-    int lev, double force, int range, struct order * ord, struct spellparameter * p);
+    int lev, float force, int range, struct order * ord, struct spellparameter * p);
   void free_castorder(struct castorder *co);
   /* Zwischenspreicher f�r Zauberbefehle, notwendig f�r Priorit�ten */
   void add_castorder(struct spellrank *cll, struct castorder *co);
@@ -357,7 +357,7 @@ typedef struct sc_mage {
   extern void write_spells(struct quicklist *slist, struct storage *store);
   extern void read_spells(struct quicklist **slistp, magic_t mtype,
     struct storage *store);
-  extern double MagicPower(void);
+  extern float MagicPower(void);
 
   extern struct spellbook * get_spellbook(const char * name);
   extern void free_spellbooks(void);
diff --git a/core/src/kernel/move.c b/core/src/kernel/move.c
index 8f595dda5..c66a0b629 100644
--- a/core/src/kernel/move.c
+++ b/core/src/kernel/move.c
@@ -54,7 +54,8 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #include <util/parser.h>
 #include <util/rand.h>
 #include <util/rng.h>
-#include <util/storage.h>
+
+#include <storage.h>
 
 /* attributes includes */
 #include <attributes/follow.h>
@@ -132,11 +133,13 @@ static int shiptrail_age(attrib * a)
 
 static int shiptrail_read(attrib * a, void *owner, struct storage *store)
 {
+  int n;
   traveldir *t = (traveldir *) (a->data.v);
 
-  t->no = store->r_int(store);
-  t->dir = (direction_t) store->r_int(store);
-  t->age = store->r_int(store);
+  READ_INT(store, &t->no);
+  READ_INT(store, &n);
+  t->dir = (direction_t)n;
+  READ_INT(store, &t->age);
   return AT_READ_OK;
 }
 
@@ -144,9 +147,9 @@ static void
 shiptrail_write(const attrib * a, const void *owner, struct storage *store)
 {
   traveldir *t = (traveldir *) (a->data.v);
-  store->w_int(store, t->no);
-  store->w_int(store, t->dir);
-  store->w_int(store, t->age);
+  WRITE_INT(store, t->no);
+  WRITE_INT(store, t->dir);
+  WRITE_INT(store, t->age);
 }
 
 attrib_type at_shiptrail = {
diff --git a/core/src/kernel/plane.c b/core/src/kernel/plane.c
index 9c3eaa31e..d02bfa22c 100644
--- a/core/src/kernel/plane.c
+++ b/core/src/kernel/plane.c
@@ -27,9 +27,10 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 /* util includes */
 #include <util/attrib.h>
 #include <util/resolve.h>
-#include <util/storage.h>
 #include <util/lists.h>
 
+#include <storage.h>
+
 /* libc includes */
 #include <assert.h>
 #include <string.h>
@@ -292,13 +293,13 @@ int resolve_plane(variant id, void *addr)
 
 void write_plane_reference(const plane * u, struct storage *store)
 {
-  store->w_int(store, u ? (u->id) : 0);
+  WRITE_INT(store, u ? (u->id) : 0);
 }
 
 int read_plane_reference(plane ** pp, struct storage *store)
 {
   variant id;
-  id.i = store->r_int(store);
+  READ_INT(store, &id.i);
   if (id.i == 0) {
     *pp = NULL;
     return AT_READ_FAIL;
diff --git a/core/src/kernel/race.c b/core/src/kernel/race.c
index 0edb59d7e..43df15f21 100644
--- a/core/src/kernel/race.c
+++ b/core/src/kernel/race.c
@@ -44,7 +44,8 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #include <util/language.h>
 #include <util/log.h>
 #include <util/rng.h>
-#include <util/storage.h>
+
+#include <storage.h>
 
 /* attrib includes */
 #include <attributes/raceprefix.h>
@@ -274,14 +275,14 @@ rc_specialdamage(const race * ar, const race * dr,
 
 void write_race_reference(const race * rc, struct storage *store)
 {
-  store->w_tok(store, rc ? rc->_name[0] : "none");
+  WRITE_TOK(store, rc ? rc->_name[0] : "none");
 }
 
 variant read_race_reference(struct storage *store)
 {
   variant result;
   char zName[20];
-  store->r_tok_buf(store, zName, sizeof(zName));
+  READ_TOK(store, zName, sizeof(zName));
 
   if (strcmp(zName, "none") == 0) {
     result.v = NULL;
diff --git a/core/src/kernel/region.c b/core/src/kernel/region.c
index 744af5eeb..ee20e2067 100644
--- a/core/src/kernel/region.c
+++ b/core/src/kernel/region.c
@@ -50,7 +50,8 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #include <util/language.h>
 #include <util/rand.h>
 #include <util/rng.h>
-#include <util/storage.h>
+
+#include <storage.h>
 
 #include <modules/autoseed.h>
 
@@ -247,15 +248,15 @@ static int a_readdirection(attrib * a, void *owner, struct storage *store)
 {
   spec_direction *d = (spec_direction *) (a->data.v);
 
-  d->x = (short)store->r_int(store);
-  d->y = (short)store->r_int(store);
-  d->duration = store->r_int(store);
-  if (store->version < UNICODE_VERSION) {
+  READ_INT(store, &d->x);
+  READ_INT(store, &d->y);
+  READ_INT(store, &d->duration);
+  if (global.data_version < UNICODE_VERSION) {
     char lbuf[16];
     dir_lookup *dl = dir_name_lookup;
 
-    store->r_tok_buf(store, NULL, 0);
-    store->r_tok_buf(store, lbuf, sizeof(lbuf));
+    READ_TOK(store, NULL, 0);
+    READ_TOK(store, lbuf, sizeof(lbuf));
 
     cstring_i(lbuf);
     for (; dl; dl = dl->next) {
@@ -271,8 +272,11 @@ static int a_readdirection(attrib * a, void *owner, struct storage *store)
       assert(!"not implemented");
     }
   } else {
-    d->desc = store->r_tok(store);
-    d->keyword = store->r_tok(store);
+    char lbuf[32];
+    READ_TOK(store, lbuf, sizeof(lbuf));
+    d->desc = _strdup(lbuf);
+    READ_TOK(store, lbuf, sizeof(lbuf));
+    d->keyword = _strdup(lbuf);
   }
   d->active = true;
   return AT_READ_OK;
@@ -283,11 +287,11 @@ a_writedirection(const attrib * a, const void *owner, struct storage *store)
 {
   spec_direction *d = (spec_direction *) (a->data.v);
 
-  store->w_int(store, d->x);
-  store->w_int(store, d->y);
-  store->w_int(store, d->duration);
-  store->w_tok(store, d->desc);
-  store->w_tok(store, d->keyword);
+  WRITE_INT(store, d->x);
+  WRITE_INT(store, d->y);
+  WRITE_INT(store, d->duration);
+  WRITE_TOK(store, d->desc);
+  WRITE_TOK(store, d->keyword);
 }
 
 attrib_type at_direction = {
@@ -358,7 +362,7 @@ int a_readmoveblock(attrib * a, void *owner, struct storage *store)
   moveblock *m = (moveblock *) (a->data.v);
   int i;
 
-  i = store->r_int(store);
+  READ_INT(store, &i);
   m->dir = (direction_t) i;
   return AT_READ_OK;
 }
@@ -367,7 +371,7 @@ void
 a_writemoveblock(const attrib * a, const void *owner, struct storage *store)
 {
   moveblock *m = (moveblock *) (a->data.v);
-  store->w_int(store, (int)m->dir);
+  WRITE_INT(store, (int)m->dir);
 }
 
 attrib_type at_moveblock = {
@@ -1417,11 +1421,14 @@ int resolve_region_id(variant id, void *address)
 variant read_region_reference(struct storage * store)
 {
   variant result;
-  if (store->version < UIDHASH_VERSION) {
-    result.sa[0] = (short)store->r_int(store);
-    result.sa[1] = (short)store->r_int(store);
+  if (global.data_version < UIDHASH_VERSION) {
+    int n;
+    READ_INT(store, &n);
+    result.sa[0] = (short)n;
+    READ_INT(store, &n);
+    result.sa[1] = (short)n;
   } else {
-    result.i = store->r_int(store);
+    READ_INT(store, &result.i);
   }
   return result;
 }
@@ -1429,9 +1436,9 @@ variant read_region_reference(struct storage * store)
 void write_region_reference(const region * r, struct storage *store)
 {
   if (r) {
-    store->w_int(store, r->uid);
+    WRITE_INT(store, r->uid);
   } else {
-    store->w_int(store, 0);
+    WRITE_INT(store, 0);
   }
 }
 
diff --git a/core/src/kernel/reports.c b/core/src/kernel/reports.c
index 3e378edda..86d0489ec 100644
--- a/core/src/kernel/reports.c
+++ b/core/src/kernel/reports.c
@@ -1734,7 +1734,7 @@ int init_reports(void)
       return 0;
   }
 #endif
-  if (os_mkdir(reportpath(), 0700) != 0) {
+  if (_mkdir(reportpath()) != 0) {
     if (errno != EEXIST) {
       perror("could not create reportpath");
       return -1;
diff --git a/core/src/kernel/save.c b/core/src/kernel/save.c
index 87d512221..e50df12e6 100644
--- a/core/src/kernel/save.c
+++ b/core/src/kernel/save.c
@@ -47,9 +47,6 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #include "unit.h"
 #include "version.h"
 
-#include "textstore.h"
-#include "binarystore.h"
-
 /* attributes includes */
 #include <attributes/key.h>
 #include <triggers/timeout.h>
@@ -71,10 +68,12 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #include <util/resolve.h>
 #include <util/rng.h>
 #include <util/sql.h>
-#include <util/storage.h>
 #include <util/umlaut.h>
 #include <util/unicode.h>
 
+#include <storage.h>
+#include <binarystore.h>
+
 #include <libxml/encoding.h>
 
 /* libc includes */
@@ -244,11 +243,6 @@ static faction *factionorders(void)
   return f;
 }
 
-double version(void)
-{
-  return RELEASE_VERSION * 0.1;
-}
-
 /* ------------------------------------------------------------- */
 
 static param_t igetparam(const char *s, const struct locale *lang)
@@ -410,11 +404,11 @@ void read_items(struct storage *store, item ** ilist)
     char ibuf[32];
     const item_type *itype;
     int i;
-    store->r_str_buf(store, ibuf, sizeof(ibuf));
+    READ_STR(store, ibuf, sizeof(ibuf));
     if (!strcmp("end", ibuf))
       break;
     itype = it_find(ibuf);
-    i = store->r_int(store);
+    READ_INT(store, &i);
     if (i <= 0) {
       log_error("data contains an entry with %d %s\n", i, itype->rtype->_name[1]);
     } else {
@@ -430,51 +424,51 @@ static void read_alliances(struct storage *store)
 {
   char pbuf[8];
   int id, terminator = 0;
-  if (store->version < SAVEALLIANCE_VERSION) {
+  if (global.data_version < SAVEALLIANCE_VERSION) {
     if (!AllianceRestricted() && !AllianceAuto())
       return;
   }
-  if (store->version < ALLIANCELEADER_VERSION) {
+  if (global.data_version < ALLIANCELEADER_VERSION) {
     terminator = atoi36("end");
-    store->r_str_buf(store, pbuf, sizeof(pbuf));
+    READ_STR(store, pbuf, sizeof(pbuf));
     id = atoi36(pbuf);
   } else {
-    id = store->r_id(store);
+    READ_INT(store, &id);
   }
   while (id != terminator) {
     char aname[128];
     alliance *al;
-    store->r_str_buf(store, aname, sizeof(aname));
+    READ_STR(store, aname, sizeof(aname));
     al = makealliance(id, aname);
-    if (store->version >= OWNER_2_VERSION) {
-      al->flags = store->r_int(store);
+    if (global.data_version >= OWNER_2_VERSION) {
+      READ_INT(store, &al->flags);
     }
-    if (store->version >= ALLIANCELEADER_VERSION) {
+    if (global.data_version >= ALLIANCELEADER_VERSION) {
       read_reference(&al->_leader, store, read_faction_reference,
         resolve_faction);
-      id = store->r_id(store);
+      READ_INT(store, &id);
     } else {
-      store->r_str_buf(store, pbuf, sizeof(pbuf));
+      READ_STR(store, pbuf, sizeof(pbuf));
       id = atoi36(pbuf);
     }
   }
 }
 
-void write_alliances(struct storage *store)
+void write_alliances(struct gamedata *data)
 {
   alliance *al = alliances;
   while (al) {
     if (al->_leader) {
-      store->w_id(store, al->id);
-      store->w_str(store, al->name);
-      store->w_int(store, (int)al->flags);
-      write_faction_reference(al->_leader, store);
-      store->w_brk(store);
+      WRITE_INT(data->store, al->id);
+      WRITE_STR(data->store, al->name);
+      WRITE_INT(data->store, (int)al->flags);
+      write_faction_reference(al->_leader, data->store);
+      WRITE_SECTION(data->store);
     }
     al = al->next;
   }
-  store->w_id(store, 0);
-  store->w_brk(store);
+  WRITE_INT(data->store, 0);
+  WRITE_SECTION(data->store);
 }
 
 void write_items(struct storage *store, item * ilist)
@@ -483,11 +477,11 @@ void write_items(struct storage *store, item * ilist)
   for (itm = ilist; itm; itm = itm->next) {
     assert(itm->number >= 0);
     if (itm->number) {
-      store->w_tok(store, resourcename(itm->type->rtype, 0));
-      store->w_int(store, itm->number);
+      WRITE_TOK(store, resourcename(itm->type->rtype, 0));
+      WRITE_INT(store, itm->number);
     }
   }
-  store->w_tok(store, "end");
+  WRITE_TOK(store, "end");
 }
 
 static int resolve_owner(variant id, void *address)
@@ -509,41 +503,44 @@ static int resolve_owner(variant id, void *address)
   return result;
 }
 
-static void read_owner(struct storage *store, region_owner ** powner)
+static void read_owner(struct gamedata *data, region_owner ** powner)
 {
-  int since_turn = store->r_int(store);
+  int since_turn;
+
+  READ_INT(data->store, &since_turn);
   if (since_turn >= 0) {
     region_owner *owner = malloc(sizeof(region_owner));
     owner->since_turn = since_turn;
-    owner->morale_turn = store->r_int(store);
-    if (store->version >= MOURNING_VERSION) {
-      owner->flags = store->r_int(store);
+    READ_INT(data->store, &owner->morale_turn);
+    if (data->version >= MOURNING_VERSION) {
+      READ_INT(data->store, &owner->flags);
     } else {
       owner->flags = 0;
     }
-    if (store->version >= OWNER_2_VERSION) {
-      int id = store->r_int(store);
+    if (data->version >= OWNER_2_VERSION) {
+      int id;
+      READ_INT(data->store, &id);
       owner->alliance = id ? findalliance(id) : NULL;
     } else {
       owner->alliance = NULL;
     }
-    read_reference(owner, store, &read_faction_reference, &resolve_owner);
+    read_reference(owner, data->store, &read_faction_reference, &resolve_owner);
     *powner = owner;
   } else {
     *powner = 0;
   }
 }
 
-static void write_owner(struct storage *store, region_owner * owner)
+static void write_owner(struct gamedata *data, region_owner * owner)
 {
   if (owner) {
-    store->w_int(store, owner->since_turn);
-    store->w_int(store, owner->morale_turn);
-    store->w_int(store, owner->flags);
-    store->w_id(store, owner->alliance ? owner->alliance->id : 0);
-    write_faction_reference(owner->owner, store);
+    WRITE_INT(data->store, owner->since_turn);
+    WRITE_INT(data->store, owner->morale_turn);
+    WRITE_INT(data->store, owner->flags);
+    WRITE_INT(data->store, owner->alliance ? owner->alliance->id : 0);
+    write_faction_reference(owner->owner, data->store);
   } else {
-    store->w_int(store, -1);
+    WRITE_INT(data->store, -1);
   }
 }
 
@@ -566,18 +563,17 @@ int current_turn(void)
 }
 
 static void
-writeorder(struct storage *store, const struct order *ord,
+writeorder(struct gamedata *data, const struct order *ord,
   const struct locale *lang)
 {
   char obuf[1024];
   write_order(ord, obuf, sizeof(obuf));
   if (obuf[0])
-    store->w_str(store, obuf);
+    WRITE_STR(data->store, obuf);
 }
 
-unit *read_unit(struct storage *store)
+unit *read_unit(struct gamedata *data)
 {
-  skill_t sk;
   unit *u;
   int number, n, p;
   order **orderp;
@@ -585,7 +581,7 @@ unit *read_unit(struct storage *store)
   faction *f;
   char rname[32];
 
-  n = store->r_id(store);
+  READ_INT(data->store, &n);
   if (n <= 0)
     return NULL;
   u = findunit(n);
@@ -604,23 +600,26 @@ unit *read_unit(struct storage *store)
     u_setfaction(u, NULL);
   }
 
-  n = store->r_id(store);
+  READ_INT(data->store, &n);
   f = findfaction(n);
   if (f != u->faction)
     u_setfaction(u, f);
 
-  u->name = store->r_str(store);
+  READ_STR(data->store, obuf, sizeof(obuf));
+  u->name = _strdup(obuf);
   if (lomem) {
-    store->r_str_buf(store, NULL, 0);
+    READ_STR(data->store, NULL, 0);
   } else {
-    u->display = store->r_str(store);
+    READ_STR(data->store, obuf, sizeof(obuf));
+    u->display = _strdup(obuf);
   }
-  number = store->r_int(store);
-  u->age = (short)store->r_int(store);
+  READ_INT(data->store, &number);
+  READ_INT(data->store, &n);
+  u->age = (short)n;
 
-  if (store->version < STORAGE_VERSION) {
+  if (data->version < STORAGE_VERSION) {
     char *space;
-    store->r_str_buf(store, rname, sizeof(rname));
+    READ_STR(data->store, rname, sizeof(rname));
     space = strchr(rname, ' ');
     if (space != NULL) {
       char *inc = space + 1;
@@ -637,14 +636,14 @@ unit *read_unit(struct storage *store)
       *outc = 0;
     }
   } else {
-    store->r_tok_buf(store, rname, sizeof(rname));
+    READ_TOK(data->store, rname, sizeof(rname));
   }
   u_setrace(u, rc_find(rname));
 
-  if (store->version < STORAGE_VERSION) {
-    store->r_str_buf(store, rname, sizeof(rname));
+  if (data->version < STORAGE_VERSION) {
+    READ_STR(data->store, rname, sizeof(rname));
   } else {
-    store->r_tok_buf(store, rname, sizeof(rname));
+    READ_TOK(data->store, rname, sizeof(rname));
   }
   if (rname[0] && skill_enabled[SK_STEALTH])
     u->irace = rc_find(rname);
@@ -672,7 +671,7 @@ unit *read_unit(struct storage *store)
 
   set_number(u, number);
 
-  n = store->r_id(store);
+  READ_INT(data->store, &n);
   if (n > 0) {
     building * b = findbuilding(n);
     if (b) {
@@ -685,7 +684,7 @@ unit *read_unit(struct storage *store)
     }
   }
 
-  n = store->r_id(store);
+  READ_INT(data->store, &n);
   if (n > 0) {
     ship * sh = findship(n);
     if (sh) {
@@ -698,8 +697,9 @@ unit *read_unit(struct storage *store)
     }
   }
 
-  setstatus(u, store->r_int(store));
-  u->flags = store->r_int(store);
+  READ_INT(data->store, &n);
+  setstatus(u, n);
+  READ_INT(data->store, &u->flags);
   u->flags &= UFL_SAVEMASK;
   if ((u->flags & UFL_ANON_FACTION) && !rule_stealth_faction()) {
     /* if this rule is broken, then fix broken units */
@@ -708,7 +708,7 @@ unit *read_unit(struct storage *store)
   }
   /* Persistente Befehle einlesen */
   free_orders(&u->orders);
-  store->r_str_buf(store, obuf, sizeof(obuf));
+  READ_STR(data->store, obuf, sizeof(obuf));
   p = n = 0;
   orderp = &u->orders;
   while (obuf[0]) {
@@ -730,11 +730,11 @@ unit *read_unit(struct storage *store)
           free_order(ord);
       }
     }
-    store->r_str_buf(store, obuf, sizeof(obuf));
+    READ_STR(data->store, obuf, sizeof(obuf));
   }
-  if (store->version < NOLASTORDER_VERSION) {
+  if (data->version < NOLASTORDER_VERSION) {
     order *ord;
-    store->r_str_buf(store, obuf, sizeof(obuf));
+    READ_STR(data->store, obuf, sizeof(obuf));
     ord = parse_order(obuf, u->faction->locale);
     if (ord != NULL) {
       addlist(&u->orders, ord);
@@ -743,51 +743,56 @@ unit *read_unit(struct storage *store)
   set_order(&u->thisorder, NULL);
 
   assert(u_race(u));
-  while ((sk = (skill_t) store->r_int(store)) != NOSKILL) {
-    int level = store->r_int(store);
-    int weeks = store->r_int(store);
+  for (;;) {
+    int n, 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_items(store, &u->items);
-  u->hp = store->r_int(store);
+  read_items(data->store, &u->items);
+  READ_INT(data->store, &u->hp);
   if (u->hp < u->number) {
     log_error("Einheit %s hat %u Personen, und %u Trefferpunkte\n", itoa36(u->no), u->number, u->hp);
     u->hp = u->number;
   }
 
-  a_read(store, &u->attribs, u);
+  a_read(data->store, &u->attribs, u);
   return u;
 }
 
-void write_unit(struct storage *store, const unit * u)
+void write_unit(struct gamedata *data, const unit * u)
 {
   order *ord;
   int i, p = 0;
   unsigned int flags = u->flags & UFL_SAVEMASK;
   const race *irace = u_irace(u);
 
-  write_unit_reference(u, store);
-  write_faction_reference(u->faction, store);
-  store->w_str(store, (const char *)u->name);
-  store->w_str(store, u->display ? (const char *)u->display : "");
-  store->w_int(store, u->number);
-  store->w_int(store, u->age);
-  store->w_tok(store, u_race(u)->_name[0]);
-  store->w_tok(store, (irace && irace != u_race(u)) ? irace->_name[0] : "");
-  write_building_reference(u->building, store);
-  write_ship_reference(u->ship, store);
-  store->w_int(store, u->status);
+  write_unit_reference(u, data->store);
+  write_faction_reference(u->faction, data->store);
+  WRITE_STR(data->store, (const char *)u->name);
+  WRITE_STR(data->store, u->display ? (const char *)u->display : "");
+  WRITE_INT(data->store, u->number);
+  WRITE_INT(data->store, u->age);
+  WRITE_TOK(data->store, u_race(u)->_name[0]);
+  WRITE_TOK(data->store, (irace && irace != u_race(u)) ? irace->_name[0] : "");
+  write_building_reference(u->building, data->store);
+  write_ship_reference(u->ship, data->store);
+  WRITE_INT(data->store, u->status);
   if (u->building && u==building_owner(u->building)) flags |= UFL_OWNER;
   if (u->ship && u==ship_owner(u->ship)) flags |= UFL_OWNER;
-  store->w_int(store, flags);
-  store->w_brk(store);
+  WRITE_INT(data->store, flags);
+  WRITE_SECTION(data->store);
   for (ord = u->old_orders; ord; ord = ord->next) {
     if (++p < MAXPERSISTENT) {
-      writeorder(store, ord, u->faction->locale);
+      writeorder(data, ord, u->faction->locale);
     } else {
       log_error("%s had %d or more persistent orders\n", unitname(u), MAXPERSISTENT);
       break;
@@ -798,7 +803,7 @@ void write_unit(struct storage *store, const unit * u)
       continue;                 /* has new defaults */
     if (is_persistent(ord)) {
       if (++p < MAXPERSISTENT) {
-        writeorder(store, ord, u->faction->locale);
+        writeorder(data, ord, u->faction->locale);
       } else {
         log_error("%s had %d or more persistent orders\n", unitname(u), MAXPERSISTENT);
         break;
@@ -806,8 +811,8 @@ void write_unit(struct storage *store, const unit * u)
     }
   }
   /* write an empty string to terminate the list */
-  store->w_str(store, "");
-  store->w_brk(store);
+  WRITE_STR(data->store, "");
+  WRITE_SECTION(data->store);
 
   assert(u_race(u));
 
@@ -815,34 +820,35 @@ void write_unit(struct storage *store, const unit * u)
     skill *sv = u->skills + i;
     assert(sv->weeks <= sv->level * 2 + 1);
     if (sv->level > 0) {
-      store->w_int(store, sv->id);
-      store->w_int(store, sv->level);
-      store->w_int(store, sv->weeks);
+      WRITE_INT(data->store, sv->id);
+      WRITE_INT(data->store, sv->level);
+      WRITE_INT(data->store, sv->weeks);
     }
   }
-  store->w_int(store, -1);
-  store->w_brk(store);
-  write_items(store, u->items);
-  store->w_brk(store);
+  WRITE_INT(data->store, -1);
+  WRITE_SECTION(data->store);
+  write_items(data->store, u->items);
+  WRITE_SECTION(data->store);
   if (u->hp == 0) {
     log_error("unit %s has 0 hitpoints, adjusting.\n", itoa36(u->no));
     ((unit *) u)->hp = u->number;
   }
-  store->w_int(store, u->hp);
-  store->w_brk(store);
-  a_write(store, u->attribs, u);
-  store->w_brk(store);
+  WRITE_INT(data->store, u->hp);
+  WRITE_SECTION(data->store);
+  a_write(data->store, u->attribs, u);
+  WRITE_SECTION(data->store);
 }
 
-static region *readregion(struct storage *store, int x, int y)
+static region *readregion(struct gamedata *data, int x, int y)
 {
   region *r = findregion(x, y);
   const terrain_type *terrain;
   char token[32];
   unsigned int uid = 0;
+  int n;
 
-  if (store->version >= UID_VERSION) {
-    uid = store->r_int(store);
+  if (data->version >= UID_VERSION) {
+    READ_INT(data->store, &uid);
   }
 
   if (r == NULL) {
@@ -865,15 +871,16 @@ static region *readregion(struct storage *store, int x, int y)
     r->land = 0;
   }
   if (lomem) {
-    store->r_str_buf(store, NULL, 0);
+    READ_STR(data->store, NULL, 0);
   } else {
     char info[DISPLAYSIZE];
-    store->r_str_buf(store, info, sizeof(info));
+    READ_STR(data->store, info, sizeof(info));
     region_setinfo(r, info);
   }
 
-  if (store->version < TERRAIN_VERSION) {
-    int ter = store->r_int(store);
+  if (data->version < TERRAIN_VERSION) {
+    int ter;
+    READ_INT(data->store, &ter);
     terrain = newterrain((terrain_t) ter);
     if (terrain == NULL) {
       log_error("while reading datafile from pre-TERRAIN_VERSION, could not find terrain #%d.\n", ter);
@@ -881,7 +888,7 @@ static region *readregion(struct storage *store, int x, int y)
     }
   } else {
     char name[64];
-    store->r_str_buf(store, name, sizeof(name));
+    READ_STR(data->store, name, sizeof(name));
     terrain = get_terrain(name);
     if (terrain == NULL) {
       log_error("Unknown terrain '%s'\n", name);
@@ -889,43 +896,45 @@ static region *readregion(struct storage *store, int x, int y)
     }
   }
   r->terrain = terrain;
-  r->flags = (char)store->r_int(store);
-
-  r->age = (unsigned short)store->r_int(store);
+  READ_INT(data->store, &r->flags);
+  READ_INT(data->store, &n);
+  r->age = (unsigned short)n;
 
   if (fval(r->terrain, LAND_REGION)) {
+    char name[NAMESIZE];
     r->land = calloc(1, sizeof(land_region));
-    r->land->name = store->r_str(store);
+    READ_STR(data->store, name, sizeof(name));
+    r->land->name = _strdup(name);
   }
   if (r->land) {
     int i;
     rawmaterial **pres = &r->resources;
 
-    i = store->r_int(store);
+    READ_INT(data->store, &i);
     if (i < 0) {
       log_error("number of trees in %s is %d.\n", regionname(r, NULL), i);
       i = 0;
     }
     rsettrees(r, 0, i);
-    i = store->r_int(store);
+    READ_INT(data->store, &i);
     if (i < 0) {
       log_error("number of young trees in %s is %d.\n", regionname(r, NULL), i);
       i = 0;
     }
     rsettrees(r, 1, i);
-    i = store->r_int(store);
+    READ_INT(data->store, &i);
     if (i < 0) {
       log_error("number of seeds in %s is %d.\n", regionname(r, NULL), i);
       i = 0;
     }
     rsettrees(r, 2, i);
 
-    i = store->r_int(store);
+    READ_INT(data->store, &i);
     rsethorses(r, i);
     assert(*pres == NULL);
     for (;;) {
       rawmaterial *res;
-      store->r_str_buf(store, token, sizeof(token));
+      READ_STR(data->store, token, sizeof(token));
       if (strcmp(token, "end") == 0)
         break;
       res = malloc(sizeof(rawmaterial));
@@ -934,20 +943,25 @@ static region *readregion(struct storage *store, int x, int y)
         log_error("invalid resourcetype %s in data.\n", token);
       }
       assert(res->type != NULL);
-      res->level = store->r_int(store);
-      res->amount = store->r_int(store);
+      READ_INT(data->store, &n);
+      res->level = n;
+      READ_INT(data->store, &n);
+      res->amount = n;
       res->flags = 0;
 
-      res->startlevel = store->r_int(store);
-      res->base = store->r_int(store);
-      res->divisor = store->r_int(store);
+      READ_INT(data->store, &n);
+      res->startlevel = n;
+      READ_INT(data->store, &n);
+      res->base = n;
+      READ_INT(data->store, &n);
+      res->divisor = n;
 
       *pres = res;
       pres = &res->next;
     }
     *pres = NULL;
 
-    store->r_str_buf(store, token, sizeof(token));
+    READ_STR(data->store, token, sizeof(token));
     if (strcmp(token, "noherb") != 0) {
       const resource_type *rtype = rt_find(token);
       assert(rtype && rtype->itype && fval(rtype->itype, ITF_HERB));
@@ -955,9 +969,12 @@ static region *readregion(struct storage *store, int x, int y)
     } else {
       rsetherbtype(r, NULL);
     }
-    rsetherbs(r, (short)store->r_int(store));
-    rsetpeasants(r, store->r_int(store));
-    rsetmoney(r, store->r_int(store));
+    READ_INT(data->store, &n);
+    rsetherbs(r, (short)n);
+    READ_INT(data->store, &n);
+    rsetpeasants(r, n);
+    READ_INT(data->store, &n);
+    rsetmoney(r, n);
   }
 
   assert(r->terrain != NULL);
@@ -966,89 +983,93 @@ static region *readregion(struct storage *store, int x, int y)
   assert(rmoney(r) >= 0);
 
   if (r->land) {
+    int n;
     for (;;) {
       const struct item_type *itype;
-      store->r_str_buf(store, token, sizeof(token));
+      READ_STR(data->store, token, sizeof(token));
       if (!strcmp(token, "end"))
         break;
       itype = it_find(token);
       assert(itype->rtype->ltype);
-      r_setdemand(r, itype->rtype->ltype, store->r_int(store));
+      READ_INT(data->store, &n);
+      r_setdemand(r, itype->rtype->ltype, n);
     }
-    if (store->version >= REGIONITEMS_VERSION) {
-      read_items(store, &r->land->items);
+    if (data->version >= REGIONITEMS_VERSION) {
+      read_items(data->store, &r->land->items);
     }
-    if (store->version >= REGIONOWNER_VERSION) {
-      r->land->morale = (short)store->r_int(store);
-      if (r->land->morale < 0)
+    if (data->version >= REGIONOWNER_VERSION) {
+      READ_INT(data->store, &n);
+      r->land->morale = (short)n;
+      if (r->land->morale < 0) {
         r->land->morale = 0;
-      read_owner(store, &r->land->ownership);
+      }
+      read_owner(data, &r->land->ownership);
     }
   }
-  a_read(store, &r->attribs, r);
+  a_read(data->store, &r->attribs, r);
 
   return r;
 }
 
-void writeregion(struct storage *store, const region * r)
+void writeregion(struct gamedata *data, const region * r)
 {
-  store->w_int(store, r->uid);
-  store->w_str(store, region_getinfo(r));
-  store->w_tok(store, r->terrain->_name);
-  store->w_int(store, r->flags & RF_SAVEMASK);
-  store->w_int(store, r->age);
-  store->w_brk(store);
+  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)) {
     const item_type *rht;
     struct demand *demand;
     rawmaterial *res = r->resources;
-    store->w_str(store, (const char *)r->land->name);
+    WRITE_STR(data->store, (const char *)r->land->name);
     assert(rtrees(r, 0) >= 0);
     assert(rtrees(r, 1) >= 0);
     assert(rtrees(r, 2) >= 0);
-    store->w_int(store, rtrees(r, 0));
-    store->w_int(store, rtrees(r, 1));
-    store->w_int(store, rtrees(r, 2));
-    store->w_int(store, rhorses(r));
+    WRITE_INT(data->store, rtrees(r, 0));
+    WRITE_INT(data->store, rtrees(r, 1));
+    WRITE_INT(data->store, rtrees(r, 2));
+    WRITE_INT(data->store, rhorses(r));
 
     while (res) {
-      store->w_tok(store, res->type->name);
-      store->w_int(store, res->level);
-      store->w_int(store, res->amount);
-      store->w_int(store, res->startlevel);
-      store->w_int(store, res->base);
-      store->w_int(store, res->divisor);
+      WRITE_TOK(data->store, res->type->name);
+      WRITE_INT(data->store, res->level);
+      WRITE_INT(data->store, res->amount);
+      WRITE_INT(data->store, res->startlevel);
+      WRITE_INT(data->store, res->base);
+      WRITE_INT(data->store, res->divisor);
       res = res->next;
     }
-    store->w_tok(store, "end");
+    WRITE_TOK(data->store, "end");
 
     rht = rherbtype(r);
     if (rht) {
-      store->w_tok(store, resourcename(rht->rtype, 0));
+      WRITE_TOK(data->store, resourcename(rht->rtype, 0));
     } else {
-      store->w_tok(store, "noherb");
+      WRITE_TOK(data->store, "noherb");
     }
-    store->w_int(store, rherbs(r));
-    store->w_int(store, rpeasants(r));
-    store->w_int(store, rmoney(r));
+    WRITE_INT(data->store, rherbs(r));
+    WRITE_INT(data->store, rpeasants(r));
+    WRITE_INT(data->store, rmoney(r));
     if (r->land)
       for (demand = r->land->demands; demand; demand = demand->next) {
-        store->w_tok(store, resourcename(demand->type->itype->rtype, 0));
-        store->w_int(store, demand->value);
+        WRITE_TOK(data->store, resourcename(demand->type->itype->rtype, 0));
+        WRITE_INT(data->store, demand->value);
       }
-    store->w_tok(store, "end");
+    WRITE_TOK(data->store, "end");
 #if RELEASE_VERSION>=REGIONITEMS_VERSION
-    write_items(store, r->land->items);
-    store->w_brk(store);
+    write_items(data->store, r->land->items);
+    WRITE_SECTION(data->store);
 #endif
 #if RELEASE_VERSION>=REGIONOWNER_VERSION
-    store->w_int(store, r->land->morale);
-    write_owner(store, r->land->ownership);
-    store->w_brk(store);
+    WRITE_INT(data->store, r->land->morale);
+    write_owner(data, r->land->ownership);
+    WRITE_SECTION(data->store);
 #endif
   }
-  a_write(store, r->attribs, r);
-  store->w_brk(store);
+  a_write(data->store, r->attribs, r);
+  WRITE_SECTION(data->store);
 }
 
 static ally **addally(const faction * f, ally ** sfp, int aid, int state)
@@ -1104,22 +1125,23 @@ int get_spell_level_faction(const spell * sp, void * cbdata)
   return 0;
 }
 
-void read_spellbook(spellbook **bookp, struct storage *store, int (*get_level)(const spell * sp, void *), void * cbdata)
+void read_spellbook(spellbook **bookp, struct storage *store, int(*get_level)(const spell * sp, void *), void * cbdata)
 {
   for (;;) {
     spell *sp = 0;
     char spname[64];
     int level = 0;
 
-    if (store->version < SPELLNAME_VERSION) {
-      int i = store->r_int(store);
+    if (global.data_version < SPELLNAME_VERSION) {
+      int i;
+      READ_INT(store, &i);
       if (i < 0)
         break;
       if (bookp) {
         sp = find_spellbyid((unsigned int) i);
       }
     } else {
-      store->r_tok_buf(store, spname, sizeof(spname));
+      READ_TOK(store, spname, sizeof(spname));
       if (strcmp(spname, "end") == 0)
         break;
       if (bookp) {
@@ -1129,8 +1151,8 @@ void read_spellbook(spellbook **bookp, struct storage *store, int (*get_level)(c
         }
       }
     }
-    if (store->version >= SPELLBOOK_VERSION) {
-      level = store->r_int(store);
+    if (global.data_version >= SPELLBOOK_VERSION) {
+      READ_INT(store, &level);
     }
     if (sp) {
       spellbook * sb = *bookp;
@@ -1141,7 +1163,7 @@ void read_spellbook(spellbook **bookp, struct storage *store, int (*get_level)(c
         *bookp = create_spellbook(0);
         sb = *bookp;
       }
-      if (store->version>=SPELLBOOK_VERSION || !spellbook_get(sb, sp)) {
+      if (global.data_version >= SPELLBOOK_VERSION || !spellbook_get(sb, sp)) {
         spellbook_add(sb, sp, level);
       }
     }
@@ -1156,38 +1178,39 @@ void write_spellbook(const struct spellbook *book, struct storage *store)
   if (book) {
     for (ql = book->spells, qi = 0; ql; ql_advance(&ql, &qi, 1)) {
       spellbook_entry *sbe = (spellbook_entry *) ql_get(ql, qi);
-      store->w_tok(store, sbe->sp->sname);
-      store->w_int(store, sbe->level);
+      WRITE_TOK(store, sbe->sp->sname);
+      WRITE_INT(store, sbe->level);
     }
   }
-  store->w_tok(store, "end");
+  WRITE_TOK(store, "end");
 }
 
 /** Reads a faction from a file.
  * This function requires no context, can be called in any state. The
  * faction may not already exist, however.
  */
-faction *readfaction(struct storage * store)
+faction *readfaction(struct gamedata * data)
 {
   ally **sfp;
-  int planes;
-  int i = store->r_id(store);
-  faction *f = findfaction(i);
-  char email[128];
-  char token[32];
+  int planes, n;
+  faction *f;
+  char name[NAMESIZE];
 
+  READ_INT(data->store, &n);
+  f = findfaction(n);
   if (f == NULL) {
     f = (faction *) calloc(1, sizeof(faction));
-    f->no = i;
+    f->no = n;
   } else {
     f->allies = NULL;           /* mem leak */
     while (f->attribs)
       a_remove(&f->attribs, f->attribs);
   }
-  f->subscription = store->r_int(store);
+  READ_INT(data->store, &f->subscription);
 
-  if (alliances || store->version >= OWNER_2_VERSION) {
-    int allianceid = store->r_id(store);
+  if (alliances || data->version >= OWNER_2_VERSION) {
+    int allianceid;
+    READ_INT(data->store, &allianceid);
     if (allianceid > 0)
       f->alliance = findalliance(allianceid);
     if (f->alliance) {
@@ -1202,173 +1225,183 @@ faction *readfaction(struct storage * store)
       alliance *al = makealliance(0, NULL);
       setalliance(f, al);
     }
-    if (store->version >= OWNER_2_VERSION) {
-      f->alliance_joindate = store->r_int(store);
+    if (data->version >= OWNER_2_VERSION) {
+      READ_INT(data->store, &f->alliance_joindate);
     } else {
       f->alliance_joindate = turn - 10; /* we're guessing something safe here */
     }
   }
 
-  f->name = store->r_str(store);
-  f->banner = store->r_str(store);
+  READ_STR(data->store, name, sizeof(name));
+  f->name = _strdup(name);
+  READ_STR(data->store, name, sizeof(name));
+  f->banner = _strdup(name);
 
   log_printf(stdout, "   - Lese Partei %s (%s)\n", f->name, factionid(f));
 
-  store->r_str_buf(store, email, sizeof(email));
-  if (set_email(&f->email, email) != 0) {
-    log_warning("Invalid email address for faction %s: %s\n", itoa36(f->no), email);
+  READ_STR(data->store, name, sizeof(name));
+  if (set_email(&f->email, name) != 0) {
+    log_warning("Invalid email address for faction %s: %s\n", itoa36(f->no), name);
     set_email(&f->email, "");
   }
 
-  f->passw = store->r_str(store);
-  if (store->version >= OVERRIDE_VERSION) {
-    f->override = store->r_str(store);
+  READ_STR(data->store, name, sizeof(name));
+  f->passw = _strdup(name);
+  if (data->version >= OVERRIDE_VERSION) {
+    READ_STR(data->store, name, sizeof(name));
+    f->override = _strdup(name);
   } else {
     f->override = _strdup(itoa36(rng_int()));
   }
 
-  store->r_str_buf(store, token, sizeof(token));
-  f->locale = find_locale(token);
-  f->lastorders = store->r_int(store);
-  f->age = store->r_int(store);
-  store->r_str_buf(store, token, sizeof(token));
-  f->race = rc_find(token);
+  READ_STR(data->store, name, sizeof(name));
+  f->locale = find_locale(name);
+  READ_INT(data->store, &f->lastorders);
+  READ_INT(data->store, &f->age);
+  READ_STR(data->store, name, sizeof(name));
+  f->race = rc_find(name);
   assert(f->race);
-  f->magiegebiet = (magic_t) store->r_int(store);
+  READ_INT(data->store, &n);
+  f->magiegebiet = (magic_t)n;
 
-  if (store->version < FOSS_VERSION) {
+  if (data->version < FOSS_VERSION) {
     /* ignore karma */
-    store->r_int(store);
+    READ_INT(data->store, &n);
   }
 
-  f->flags = store->r_int(store);
+  READ_INT(data->store, &f->flags);
   if (f->no == 0) {
     f->flags |= FFL_NPC;
   }
 
-  a_read(store, &f->attribs, f);
-  if (store->version >= CLAIM_VERSION) {
-    read_items(store, &f->items);
+  a_read(data->store, &f->attribs, f);
+  if (data->version >= CLAIM_VERSION) {
+    read_items(data->store, &f->items);
   }
   for (;;) {
-    store->r_tok_buf(store, token, sizeof(token));
-    if (strcmp("end", token) == 0)
+    READ_TOK(data->store, name, sizeof(name));
+    if (strcmp("end", name) == 0)
       break;
-    store->r_int(store); /* there used to be a level here, which is now ignored */
+    READ_INT(data->store, &n); /* there used to be a level here, which is now ignored */
   }
-  planes = store->r_int(store);
+  READ_INT(data->store, &planes);
   while (--planes >= 0) {
-    int id = store->r_int(store);
-    int ux = store->r_int(store);
-    int uy = store->r_int(store);
+    int id, ux, uy;
+    READ_INT(data->store, &id);
+    READ_INT(data->store, &ux);
+    READ_INT(data->store, &uy);
     set_ursprung(f, id, ux, uy);
   }
   f->newbies = 0;
 
-  i = f->options = store->r_int(store);
+  READ_INT(data->store, &n);
+  f->options = n;
 
-  if ((i & (want(O_REPORT) | want(O_COMPUTER))) == 0 && !is_monsters(f)) {
+  if ((n & (want(O_REPORT) | want(O_COMPUTER))) == 0 && !is_monsters(f)) {
     /* Kein Report eingestellt, Fehler */
-    f->options = f->options | want(O_REPORT) | want(O_ZUGVORLAGE);
+    f->options |= (want(O_REPORT) | want(O_ZUGVORLAGE));
   }
 
   sfp = &f->allies;
-  if (store->version < ALLIANCES_VERSION) {
-    int p = store->r_int(store);
+  if (data->version < ALLIANCES_VERSION) {
+    int p;
+    READ_INT(data->store, &p);
     while (--p >= 0) {
-      int aid = store->r_id(store);
-      int state = store->r_int(store);
+      int aid, state;
+      READ_INT(data->store, &aid);
+      READ_INT(data->store, &state);
       sfp = addally(f, sfp, aid, state);
     }
   } else {
     for (;;) {
       int aid = 0;
-      if (store->version < STORAGE_VERSION) {
-        store->r_tok_buf(store, token, sizeof(token));
-        if (strcmp(token, "end") != 0) {
-          aid = atoi36(token);
+      if (data->version < STORAGE_VERSION) {
+        READ_TOK(data->store, name, sizeof(name));
+        if (strcmp(name, "end") != 0) {
+          aid = atoi36(name);
         }
       } else {
-        aid = store->r_id(store);
+        READ_INT(data->store, &aid);
       }
       if (aid > 0) {
-        int state = store->r_int(store);
+        int state;
+        READ_INT(data->store, &state);
         sfp = addally(f, sfp, aid, state);
       } else {
         break;
       }
     }
   }
-  read_groups(store, f);
+  read_groups(data->store, f);
   f->spellbook = 0;
-  if (store->version >= REGIONOWNER_VERSION) {
-    read_spellbook(FactionSpells() ? &f->spellbook : 0, store, get_spell_level_faction, (void *)f);
+  if (data->version >= REGIONOWNER_VERSION) {
+    read_spellbook(FactionSpells() ? &f->spellbook : 0, data->store, get_spell_level_faction, (void *)f);
   }
   return f;
 }
 
-void writefaction(struct storage *store, const faction * f)
+void writefaction(struct gamedata *data, const faction * f)
 {
   ally *sf;
   ursprung *ur;
 
-  write_faction_reference(f, store);
-  store->w_int(store, f->subscription);
+  write_faction_reference(f, data->store);
+  WRITE_INT(data->store, f->subscription);
   if (f->alliance) {
-    store->w_id(store, f->alliance->id);
+    WRITE_INT(data->store, f->alliance->id);
     if (f->alliance->flags & ALF_NON_ALLIED) {
       assert(f == f->alliance->_leader
         || !"non-allied faction is not leader of its own dummy-alliance.");
     }
   } else {
-    store->w_id(store, 0);
+    WRITE_INT(data->store, 0);
   }
-  store->w_int(store, f->alliance_joindate);
+  WRITE_INT(data->store, f->alliance_joindate);
 
-  store->w_str(store, (const char *)f->name);
-  store->w_str(store, (const char *)f->banner);
-  store->w_str(store, f->email);
-  store->w_tok(store, (const char *)f->passw);
-  store->w_tok(store, (const char *)f->override);
-  store->w_tok(store, locale_name(f->locale));
-  store->w_int(store, f->lastorders);
-  store->w_int(store, f->age);
-  store->w_tok(store, f->race->_name[0]);
-  store->w_brk(store);
-  store->w_int(store, f->magiegebiet);
+  WRITE_STR(data->store, (const char *)f->name);
+  WRITE_STR(data->store, (const char *)f->banner);
+  WRITE_STR(data->store, f->email);
+  WRITE_TOK(data->store, (const char *)f->passw);
+  WRITE_TOK(data->store, (const char *)f->override);
+  WRITE_TOK(data->store, locale_name(f->locale));
+  WRITE_INT(data->store, f->lastorders);
+  WRITE_INT(data->store, f->age);
+  WRITE_TOK(data->store, f->race->_name[0]);
+  WRITE_SECTION(data->store);
+  WRITE_INT(data->store, f->magiegebiet);
 
-  store->w_int(store, f->flags & FFL_SAVEMASK);
-  a_write(store, f->attribs, f);
-  store->w_brk(store);
-  write_items(store, f->items);
-  store->w_brk(store);
-  store->w_tok(store, "end");
-  store->w_brk(store);
-  store->w_int(store, listlen(f->ursprung));
+  WRITE_INT(data->store, f->flags & FFL_SAVEMASK);
+  a_write(data->store, f->attribs, f);
+  WRITE_SECTION(data->store);
+  write_items(data->store, f->items);
+  WRITE_SECTION(data->store);
+  WRITE_TOK(data->store, "end");
+  WRITE_SECTION(data->store);
+  WRITE_INT(data->store, listlen(f->ursprung));
   for (ur = f->ursprung; ur; ur = ur->next) {
-    store->w_int(store, ur->id);
-    store->w_int(store, ur->x);
-    store->w_int(store, ur->y);
+    WRITE_INT(data->store, ur->id);
+    WRITE_INT(data->store, ur->x);
+    WRITE_INT(data->store, ur->y);
   }
-  store->w_brk(store);
-  store->w_int(store, f->options & ~want(O_DEBUG));
-  store->w_brk(store);
+  WRITE_SECTION(data->store);
+  WRITE_INT(data->store, f->options & ~want(O_DEBUG));
+  WRITE_SECTION(data->store);
 
   for (sf = f->allies; sf; sf = sf->next) {
     int no = (sf->faction != NULL) ? sf->faction->no : 0;
     int status = alliedfaction(NULL, f, sf->faction, HELP_ALL);
     if (status != 0) {
-      store->w_id(store, no);
-      store->w_int(store, sf->status);
+      WRITE_INT(data->store, no);
+      WRITE_INT(data->store, sf->status);
     }
   }
-  store->w_id(store, 0);
-  store->w_brk(store);
-  write_groups(store, f->groups);
-  write_spellbook(f->spellbook, store);
+  WRITE_INT(data->store, 0);
+  WRITE_SECTION(data->store);
+  write_groups(data->store, f->groups);
+  write_spellbook(f->spellbook, data->store);
 }
 
-int readgame(const char *filename, int mode, int backup)
+int readgame(const char *filename, int backup)
 {
   int i, n, p;
   faction *f, **fp;
@@ -1378,29 +1411,42 @@ int readgame(const char *filename, int mode, int backup)
   unit *u;
   int rmax = maxregions;
   char path[MAX_PATH];
-  char token[32];
+  char name[NAMESIZE];
   const struct building_type *bt_lighthouse = bt_find("lighthouse");
-  storage my_store = (mode == IO_BINARY) ? binary_store : text_store;
-  storage *store = &my_store;
+  gamedata gdata = { 0 };
+  storage store;
+  FILE *F;
 
-  sprintf(path, "%s/%s", datapath(), filename);
   log_printf(stdout, "- reading game data from %s\n", filename);
-  if (backup)
-    create_backup(path);
+  sprintf(path, "%s/%s", datapath(), filename);
 
-  store->encoding = enc_gamedata;
-  if (store->open(store, path, IO_READ) != 0) {
+  if (backup) {
+    create_backup(path);
+  }
+
+  F = fopen(path, "rb");
+  if (!F) {
+    perror(path);
     return -1;
   }
-  enc_gamedata = store->encoding;
+  fread(&gdata.version, sizeof(int), 1, F);
+  if (gdata.version >= INTPAK_VERSION) {
+    int stream_version;
+    fread(&stream_version, sizeof(int), 1, F);
+    assert(stream_version == STREAM_VERSION || !"unsupported data format");
+  }
+  assert(gdata.version >= MIN_VERSION || !"unsupported data format");
+  assert(gdata.version <= RELEASE_VERSION || !"unsupported data format");
 
-  assert(store->version >= MIN_VERSION || !"unsupported data format");
-  assert(store->version <= RELEASE_VERSION || !"unsupported data format");
+  gdata.encoding = enc_gamedata;
+  binstore_init(&store, F);
+  gdata.store = &store;
+  global.data_version = gdata.version; /* HACK: attribute::read does not have access to gamedata, only storage */
 
-  if (store->version >= SAVEXMLNAME_VERSION) {
+  if (gdata.version >= SAVEXMLNAME_VERSION) {
     char basefile[1024];
 
-    store->r_str_buf(store, basefile, sizeof(basefile));
+    READ_STR(&store, basefile, sizeof(basefile));
     if (strcmp(game_name, basefile) != 0) {
       char buffer[64];
       strlcpy(buffer, game_name, sizeof(buffer));
@@ -1412,21 +1458,25 @@ int readgame(const char *filename, int mode, int backup)
       }
     }
   }
-  a_read(store, &global.attribs, NULL);
-  global.data_turn = turn = store->r_int(store);
+  a_read(&store, &global.attribs, NULL);
+  READ_INT(&store, &turn);
+  global.data_turn = turn;
   log_printf(stdout, " - reading turn %d\n", turn);
   rng_init(turn);
   ++global.cookie;
-  store->r_int(store);          /* max_unique_id = */
-  nextborder = store->r_int(store);
+  READ_INT(&store, &n);          /* max_unique_id = ignore */
+  READ_INT(&store, &nextborder);
 
   /* Planes */
   planes = NULL;
-  n = store->r_int(store);
+  READ_INT(&store, &n);
   while (--n >= 0) {
-    int id = store->r_int(store);
+    int id;
     variant fno;
-    plane *pl = getplanebyid(id);
+    plane *pl;
+
+    READ_INT(&store, &id);
+    pl = getplanebyid(id);
 
     if (pl == NULL) {
       pl = calloc(1, sizeof(plane));
@@ -1434,19 +1484,20 @@ int readgame(const char *filename, int mode, int backup)
       log_warning("the plane with id=%d already exists.\n", id);
     }
     pl->id = id;
-    pl->name = store->r_str(store);
-    pl->minx = store->r_int(store);
-    pl->maxx = store->r_int(store);
-    pl->miny = store->r_int(store);
-    pl->maxy = store->r_int(store);
-    pl->flags = store->r_int(store);
+    READ_STR(&store, name, sizeof(name));
+    pl->name = _strdup(name);
+    READ_INT(&store, &pl->minx);
+    READ_INT(&store, &pl->maxx);
+    READ_INT(&store, &pl->miny);
+    READ_INT(&store, &pl->maxy);
+    READ_INT(&store, &pl->flags);
 
     /* read watchers */
-    if (store->version < FIX_WATCHERS_VERSION) {
+    if (gdata.version < FIX_WATCHERS_VERSION) {
       char rname[64];
       /* before this version, watcher storage was pretty broken. we are incompatible and don't read them */
       for (;;) {
-        store->r_tok_buf(store, rname, sizeof(rname));
+        READ_TOK(&store, rname, sizeof(rname));
         if (strcmp(rname, "end") == 0) {
           break;                /* this is most likely the end of the list */
         } else {
@@ -1455,32 +1506,33 @@ int readgame(const char *filename, int mode, int backup)
         }
       }
     } else {
-      fno = read_faction_reference(store);
+      fno = read_faction_reference(&store);
       while (fno.i) {
         watcher *w = (watcher *) malloc(sizeof(watcher));
         ur_add(fno, &w->faction, resolve_faction);
-        w->mode = (unsigned char)store->r_int(store);
+        READ_INT(&store, &n);
+        w->mode = (unsigned char)n;
         w->next = pl->watchers;
         pl->watchers = w;
-        fno = read_faction_reference(store);
+        fno = read_faction_reference(&store);
       }
     }
-    a_read(store, &pl->attribs, pl);
+    a_read(&store, &pl->attribs, pl);
     addlist(&planes, pl);
   }
 
   /* Read factions */
-  if (store->version >= ALLIANCES_VERSION) {
-    read_alliances(store);
+  if (gdata.version >= ALLIANCES_VERSION) {
+    read_alliances(&store);
   }
-  n = store->r_int(store);
+  READ_INT(&store, &n);
   log_printf(stdout, " - Einzulesende Parteien: %d\n", n);
   fp = &factions;
   while (*fp)
     fp = &(*fp)->next;
 
   while (--n >= 0) {
-    faction *f = readfaction(store);
+    faction *f = readfaction(&gdata);
 
     *fp = f;
     fp = &f->next;
@@ -1488,17 +1540,17 @@ int readgame(const char *filename, int mode, int backup)
   }
   *fp = 0;
 
-  /* Benutzte Faction-Ids */
-  if (store->version < STORAGE_VERSION) {
-    i = store->r_int(store);
+  /* ignore the obsolete list of "used" faction ids */
+  if (gdata.version < STORAGE_VERSION) {
+    READ_INT(&store, &i);
     while (i--) {
-      store->r_int(store);      /* used faction ids. ignore. */
+      READ_INT(&store, &n);
     }
   }
 
   /* Regionen */
 
-  n = store->r_int(store);
+  READ_INT(&store, &n);
   assert(n < MAXREGIONS);
   if (rmax < 0) {
     rmax = n;
@@ -1506,91 +1558,98 @@ int readgame(const char *filename, int mode, int backup)
   log_printf(stdout, " - Einzulesende Regionen: %d/%d\r", rmax, n);
   while (--n >= 0) {
     unit **up;
-    int x = store->r_int(store);
-    int y = store->r_int(store);
+    int x, y;
+    READ_INT(&store, &x);
+    READ_INT(&store, &y);
 
     if ((n & 0x3FF) == 0) {     /* das spart extrem Zeit */
       log_printf(stdout, " - Einzulesende Regionen: %d/%d * %d,%d    \r", rmax, n, x, y);
     }
     --rmax;
 
-    r = readregion(store, x, y);
+    r = readregion(&gdata, x, y);
 
     /* Burgen */
-    p = store->r_int(store);
+    READ_INT(&store, &p);
     bp = &r->buildings;
 
     while (--p >= 0) {
 
       b = (building *) calloc(1, sizeof(building));
-      b->no = store->r_id(store);
+      READ_INT(&store, &b->no);
       *bp = b;
       bp = &b->next;
       bhash(b);
-      b->name = store->r_str(store);
+      READ_STR(&store, name, sizeof(name));
+      b->name = _strdup(name);
       if (lomem) {
-        store->r_str_buf(store, NULL, 0);
+        READ_STR(gdata.store, NULL, 0);
       } else {
-        b->display = store->r_str(store);
+        READ_STR(&store, name, sizeof(name));
+        b->display = _strdup(name);
       }
-      b->size = store->r_int(store);
-      store->r_str_buf(store, token, sizeof(token));
-      b->type = bt_find(token);
+      READ_INT(&store, &b->size);
+      READ_STR(&store, name, sizeof(name));
+      b->type = bt_find(name);
       b->region = r;
-      a_read(store, &b->attribs, b);
+      a_read(&store, &b->attribs, b);
       if (b->type == bt_lighthouse) {
         r->flags |= RF_LIGHTHOUSE;
       }
     }
     /* Schiffe */
 
-    p = store->r_int(store);
+    READ_INT(&store, &p);
     shp = &r->ships;
 
     while (--p >= 0) {
       ship *sh = (ship *) calloc(1, sizeof(ship));
       sh->region = r;
-      sh->no = store->r_id(store);
+      READ_INT(&store, &sh->no);
       *shp = sh;
       shp = &sh->next;
       shash(sh);
-      sh->name = store->r_str(store);
+      READ_STR(&store, name, sizeof(name));
+      sh->name = _strdup(name);
       if (lomem) {
-        store->r_str_buf(store, NULL, 0);
+        READ_STR(&store, NULL, 0);
       } else {
-        sh->display = store->r_str(store);
+        READ_STR(&store, name, sizeof(name));
+        sh->display = _strdup(name);
       }
-      store->r_str_buf(store, token, sizeof(token));
-      sh->type = st_find(token);
+      READ_STR(&store, name, sizeof(name));
+      sh->type = st_find(name);
       if (sh->type == NULL) {
         /* old datafiles */
-        sh->type = st_find((const char *)locale_string(default_locale, token));
+        sh->type = st_find((const char *)locale_string(default_locale, name));
       }
       assert(sh->type || !"ship_type not registered!");
-      sh->size = store->r_int(store);
-      sh->damage = store->r_int(store);
-      if (store->version >= FOSS_VERSION) {
-        sh->flags = store->r_int(store);
+
+      READ_INT(&store, &sh->size);
+      READ_INT(&store, &sh->damage);
+      if (gdata.version >= FOSS_VERSION) {
+        READ_INT(&store, &sh->flags);
       }
 
       /* Attribute rekursiv einlesen */
 
-      sh->coast = (direction_t) store->r_int(store);
+      READ_INT(&store, &n);
+      sh->coast = (direction_t)n;
       if (sh->type->flags & SFL_NOCOAST) {
         sh->coast = NODIRECTION;
       }
-      a_read(store, &sh->attribs, sh);
+      a_read(&store, &sh->attribs, sh);
     }
 
     *shp = 0;
 
     /* Einheiten */
 
-    p = store->r_int(store);
+    READ_INT(&store, &p);
     up = &r->units;
 
     while (--p >= 0) {
-      unit *u = read_unit(store);
+      unit *u = read_unit(&gdata);
       sc_mage *mage;
 
       assert(u->region == NULL);
@@ -1617,9 +1676,9 @@ int readgame(const char *filename, int mode, int backup)
     }
   }
   log_printf(stdout, "\n");
-  read_borders(store);
+  read_borders(&store);
 
-  store->close(store);
+  binstore_done(&store);
 
   /* Unaufgeloeste Zeiger initialisieren */
   log_printf(stdout, "fixing unresolved references.\n");
@@ -1671,7 +1730,7 @@ static void clear_monster_orders(void)
   }
 }
 
-int writegame(const char *filename, int mode)
+int writegame(const char *filename)
 {
   char *base;
   int n;
@@ -1682,9 +1741,9 @@ int writegame(const char *filename, int mode)
   unit *u;
   plane *pl;
   char path[MAX_PATH];
-  storage my_store = (mode == IO_BINARY) ? binary_store : text_store;
-  storage *store = &my_store;
-  store->version = RELEASE_VERSION;
+  gamedata gdata;
+  storage store;
+  FILE *F;
 
   clear_monster_orders();
   sprintf(path, "%s/%s", datapath(), filename);
@@ -1694,80 +1753,90 @@ int writegame(const char *filename, int mode)
     unlink(path);
   }
 #endif
-
-  store->encoding = enc_gamedata;
-  if (store->open(store, path, IO_WRITE) != 0) {
-    int err = os_mkdir(datapath(), 0700);
-    if (err)
-      return err;
-    if (store->open(store, path, IO_WRITE) != 0) {
+  F = fopen(path, "wb");
+  if (!F) {
+    /* we might be missing the directory, let's try creating it */
+    int err = _mkdir(datapath());
+    if (err) return err;
+    F = fopen(path, "wb");
+    if (!F) {
+      perror(path);
       return -1;
     }
   }
 
+  gdata.store = &store;
+  gdata.encoding = enc_gamedata;
+  gdata.version = RELEASE_VERSION;
+  n = STREAM_VERSION;
+  fwrite(&gdata.version, sizeof(int), 1, F);
+  fwrite(&n, sizeof(int), 1, F);
+
+  binstore_init(&store, F);
+
   /* globale Variablen */
 
   base = strrchr(game_name, '/');
   if (base) {
-    store->w_str(store, base + 1);
+    WRITE_STR(&store, base + 1);
   } else {
-    store->w_str(store, game_name);
+    WRITE_STR(&store, game_name);
   }
-  store->w_brk(store);
+  WRITE_SECTION(&store);
 
-  a_write(store, global.attribs, NULL);
-  store->w_brk(store);
+  a_write(&store, global.attribs, NULL);
+  WRITE_SECTION(&store);
 
-  store->w_int(store, turn);
-  store->w_int(store, 0 /*max_unique_id */ );
-  store->w_int(store, nextborder);
+  WRITE_INT(&store, turn);
+  WRITE_INT(&store, 0 /*max_unique_id */ );
+  WRITE_INT(&store, nextborder);
 
   /* Write planes */
-  store->w_brk(store);
-  store->w_int(store, listlen(planes));
-  store->w_brk(store);
+  WRITE_SECTION(&store);
+  WRITE_INT(&store, listlen(planes));
+  WRITE_SECTION(&store);
 
   for (pl = planes; pl; pl = pl->next) {
     watcher *w;
-    store->w_int(store, pl->id);
-    store->w_str(store, pl->name);
-    store->w_int(store, pl->minx);
-    store->w_int(store, pl->maxx);
-    store->w_int(store, pl->miny);
-    store->w_int(store, pl->maxy);
-    store->w_int(store, pl->flags);
+    WRITE_INT(&store, pl->id);
+    WRITE_STR(&store, pl->name);
+    WRITE_INT(&store, pl->minx);
+    WRITE_INT(&store, pl->maxx);
+    WRITE_INT(&store, pl->miny);
+    WRITE_INT(&store, pl->maxy);
+    WRITE_INT(&store, pl->flags);
     w = pl->watchers;
     while (w) {
       if (w->faction) {
-        write_faction_reference(w->faction, store);
-        store->w_int(store, w->mode);
+        write_faction_reference(w->faction, &store);
+        WRITE_INT(&store, w->mode);
       }
       w = w->next;
     }
-    write_faction_reference(NULL, store);       /* mark the end of the list */
-    a_write(store, pl->attribs, pl);
-    store->w_brk(store);
+    write_faction_reference(NULL, &store);       /* mark the end of the list */
+    a_write(&store, pl->attribs, pl);
+    WRITE_SECTION(&store);
   }
 
   /* Write factions */
 #if RELEASE_VERSION>=ALLIANCES_VERSION
-  write_alliances(store);
+  write_alliances(&gdata);
 #endif
   n = listlen(factions);
-  store->w_int(store, n);
-  store->w_brk(store);
+  WRITE_INT(&store, n);
+  WRITE_SECTION(&store);
 
   log_printf(stdout, " - Schreibe %d Parteien...\n", n);
   for (f = factions; f; f = f->next) {
-    writefaction(store, f);
-    store->w_brk(store);
+    writefaction(&gdata, f);
+    WRITE_SECTION(&store);
   }
 
   /* Write regions */
 
   n = listlen(regions);
-  store->w_int(store, n);
-  store->w_brk(store);
+  WRITE_INT(&store, n);
+  WRITE_SECTION(&store);
   log_printf(stdout, " - Schreibe Regionen: %d  \r", n);
 
   for (r = regions; r; r = r->next, --n) {
@@ -1776,53 +1845,53 @@ int writegame(const char *filename, int mode)
       log_printf(stdout, " - Schreibe Regionen: %d  \r", n);
       fflush(stdout);
     }
-    store->w_brk(store);
-    store->w_int(store, r->x);
-    store->w_int(store, r->y);
-    writeregion(store, r);
+    WRITE_SECTION(&store);
+    WRITE_INT(&store, r->x);
+    WRITE_INT(&store, r->y);
+    writeregion(&gdata, r);
 
-    store->w_int(store, listlen(r->buildings));
-    store->w_brk(store);
+    WRITE_INT(&store, listlen(r->buildings));
+    WRITE_SECTION(&store);
     for (b = r->buildings; b; b = b->next) {
-      write_building_reference(b, store);
-      store->w_str(store, b->name);
-      store->w_str(store, b->display ? b->display : "");
-      store->w_int(store, b->size);
-      store->w_tok(store, b->type->_name);
-      store->w_brk(store);
-      a_write(store, b->attribs, b);
-      store->w_brk(store);
+      write_building_reference(b, &store);
+      WRITE_STR(&store, b->name);
+      WRITE_STR(&store, b->display ? b->display : "");
+      WRITE_INT(&store, b->size);
+      WRITE_TOK(&store, b->type->_name);
+      WRITE_SECTION(&store);
+      a_write(&store, b->attribs, b);
+      WRITE_SECTION(&store);
     }
 
-    store->w_int(store, listlen(r->ships));
-    store->w_brk(store);
+    WRITE_INT(&store, listlen(r->ships));
+    WRITE_SECTION(&store);
     for (sh = r->ships; sh; sh = sh->next) {
       assert(sh->region == r);
-      write_ship_reference(sh, store);
-      store->w_str(store, (const char *)sh->name);
-      store->w_str(store, sh->display ? (const char *)sh->display : "");
-      store->w_tok(store, sh->type->name[0]);
-      store->w_int(store, sh->size);
-      store->w_int(store, sh->damage);
-      store->w_int(store, sh->flags & SFL_SAVEMASK);
+      write_ship_reference(sh, &store);
+      WRITE_STR(&store, (const char *)sh->name);
+      WRITE_STR(&store, sh->display ? (const char *)sh->display : "");
+      WRITE_TOK(&store, sh->type->name[0]);
+      WRITE_INT(&store, sh->size);
+      WRITE_INT(&store, sh->damage);
+      WRITE_INT(&store, sh->flags & SFL_SAVEMASK);
       assert((sh->type->flags & SFL_NOCOAST) == 0 || sh->coast == NODIRECTION);
-      store->w_int(store, sh->coast);
-      store->w_brk(store);
-      a_write(store, sh->attribs, sh);
-      store->w_brk(store);
+      WRITE_INT(&store, sh->coast);
+      WRITE_SECTION(&store);
+      a_write(&store, sh->attribs, sh);
+      WRITE_SECTION(&store);
     }
 
-    store->w_int(store, listlen(r->units));
-    store->w_brk(store);
+    WRITE_INT(&store, listlen(r->units));
+    WRITE_SECTION(&store);
     for (u = r->units; u; u = u->next) {
-      write_unit(store, u);
+      write_unit(&gdata, u);
     }
   }
-  store->w_brk(store);
-  write_borders(store);
-  store->w_brk(store);
+  WRITE_SECTION(&store);
+  write_borders(&store);
+  WRITE_SECTION(&store);
 
-  store->close(store);
+  binstore_done(&store);
 
   log_printf(stdout, "\nOk.\n");
   return 0;
@@ -1831,39 +1900,44 @@ int writegame(const char *filename, int mode)
 int a_readint(attrib * a, void *owner, struct storage *store)
 {
   /*  assert(sizeof(int)==sizeof(a->data)); */
-  a->data.i = store->r_int(store);
+  READ_INT(store, &a->data.i);
   return AT_READ_OK;
 }
 
 void a_writeint(const attrib * a, const void *owner, struct storage *store)
 {
-  store->w_int(store, a->data.i);
+  WRITE_INT(store, a->data.i);
 }
 
 int a_readshorts(attrib * a, void *owner, struct storage *store)
 {
-  if (store->version < ATTRIBREAD_VERSION) {
+  int n;
+  if (global.data_version < ATTRIBREAD_VERSION) {
     return a_readint(a, store, owner);
   }
-  a->data.sa[0] = (short)store->r_int(store);
-  a->data.sa[1] = (short)store->r_int(store);
+  READ_INT(store, &n);
+  a->data.sa[0] = (short)n;
+  READ_INT(store, &n);
+  a->data.sa[1] = (short)n;
   return AT_READ_OK;
 }
 
 void a_writeshorts(const attrib * a, const void *owner, struct storage *store)
 {
-  store->w_int(store, a->data.sa[0]);
-  store->w_int(store, a->data.sa[1]);
+  WRITE_INT(store, a->data.sa[0]);
+  WRITE_INT(store, a->data.sa[1]);
 }
 
 int a_readchars(attrib * a, void *owner, struct storage *store)
 {
   int i;
-  if (store->version < ATTRIBREAD_VERSION) {
+  if (global.data_version < ATTRIBREAD_VERSION) {
     return a_readint(a, store, owner);
   }
   for (i = 0; i != 4; ++i) {
-    a->data.ca[i] = (char)store->r_int(store);
+    int n;
+    READ_INT(store, &n);
+    a->data.ca[i] = (char)n;
   }
   return AT_READ_OK;
 }
@@ -1873,13 +1947,13 @@ void a_writechars(const attrib * a, const void *owner, struct storage *store)
   int i;
 
   for (i = 0; i != 4; ++i) {
-    store->w_int(store, a->data.ca[i]);
+    WRITE_INT(store, a->data.ca[i]);
   }
 }
 
 int a_readvoid(attrib * a, void *owner, struct storage *store)
 {
-  if (store->version < ATTRIBREAD_VERSION) {
+  if (global.data_version < ATTRIBREAD_VERSION) {
     return a_readint(a, store, owner);
   }
   return AT_READ_OK;
@@ -1891,14 +1965,29 @@ void a_writevoid(const attrib * a, const void *owner, struct storage *store)
 
 int a_readstring(attrib * a, void *owner, struct storage *store)
 {
-  a->data.v = store->r_str(store);
+  char buf[DISPLAYSIZE];
+  char * result = 0;
+  int e;
+  size_t len = 0;
+  do {
+    e = READ_STR(store, buf, sizeof(buf));
+    if (result) {
+      result = realloc(result, len + DISPLAYSIZE - 1);
+      strcpy(result + len, buf);
+      len += DISPLAYSIZE - 1;
+    }
+    else {
+      result = _strdup(buf);
+    }
+  } while (e == ENOMEM);
+  a->data.v = result;
   return AT_READ_OK;
 }
 
 void a_writestring(const attrib * a, const void *owner, struct storage *store)
 {
   assert(a->data.v);
-  store->w_str(store, (const char *)a->data.v);
+  WRITE_STR(store, (const char *)a->data.v);
 }
 
 void a_finalizestring(attrib * a)
diff --git a/core/src/kernel/save.h b/core/src/kernel/save.h
index fcbd4881e..c3051a722 100644
--- a/core/src/kernel/save.h
+++ b/core/src/kernel/save.h
@@ -22,7 +22,11 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 extern "C" {
 #endif
 
-  double version(void);
+  typedef struct gamedata {
+    struct storage *store;
+    int version;
+    int encoding;
+  } gamedata;
 
 #define MAX_INPUT_SIZE	DISPLAYSIZE*2
 /* Nach MAX_INPUT_SIZE brechen wir das Einlesen der Zeile ab und nehmen an,
@@ -30,8 +34,8 @@ extern "C" {
 
   int readorders(const char *filename);
   int creategame(void);
-  extern int readgame(const char *filename, int mode, int backup);
-  int writegame(const char *filename, int mode);
+  extern int readgame(const char *filename, int backup);
+  int writegame(const char *filename);
 
 /* Versions�nderungen: */
   extern int data_version;
@@ -47,8 +51,8 @@ extern "C" {
   extern void read_spellbook(struct spellbook **bookp, struct storage *store, int (*get_level)(const struct spell * sp, void *), void * cbdata);
   extern void write_spellbook(const struct spellbook *book, struct storage *store);
 
-  extern void write_unit(struct storage *store, const struct unit *u);
-  extern struct unit *read_unit(struct storage *store);
+  extern void write_unit(struct gamedata *data, const struct unit *u);
+  extern struct unit *read_unit(struct gamedata *data);
 
   extern int a_readint(struct attrib *a, void *owner, struct storage *store);
   extern void a_writeint(const struct attrib *a, const void *owner,
diff --git a/core/src/kernel/ship.c b/core/src/kernel/ship.c
index 142c0f9f3..c2cc312c4 100644
--- a/core/src/kernel/ship.c
+++ b/core/src/kernel/ship.c
@@ -37,9 +37,10 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #include <util/lists.h>
 #include <util/umlaut.h>
 #include <quicklist.h>
-#include <util/storage.h>
 #include <util/xml.h>
 
+#include <storage.h>
+
 /* libc includes */
 #include <assert.h>
 #include <math.h>
@@ -330,7 +331,7 @@ unit *ship_owner(const ship * sh)
 
 void write_ship_reference(const struct ship *sh, struct storage *store)
 {
-  store->w_id(store, (sh && sh->region) ? sh->no : 0);
+  WRITE_INT(store, (sh && sh->region) ? sh->no : 0);
 }
 
 void ship_setname(ship * self, const char *name)
diff --git a/core/src/kernel/textstore.c b/core/src/kernel/textstore.c
deleted file mode 100644
index b04b8b076..000000000
--- a/core/src/kernel/textstore.c
+++ /dev/null
@@ -1,310 +0,0 @@
-/* vi: set ts=2:
-+-------------------+  Enno Rehling <enno@eressea.de>
-| Eressea PBEM host |  Christian Schlittchen <corwin@amber.kn-bremen.de>
-| (c) 1998 - 2008   |  Katja Zedel <katze@felidae.kn-bremen.de>
-+-------------------+  
-This program may not be used, modified or distributed 
-without prior permission by the authors of Eressea.
-*/
-#include <platform.h>
-#include "config.h"
-#include "textstore.h"
-
-#include "save.h"
-#include "version.h"
-#include <util/unicode.h>
-#include <util/base36.h>
-#include <util/log.h>
-
-#include <assert.h>
-#include <ctype.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <libxml/encoding.h>
-
-#define NULL_TOKEN '@'
-
-/** writes a quoted string to the file
-* no trailing space, since this is used to make the creport.
-*/
-int fwritestr(FILE * F, const char *str)
-{
-  int nwrite = 0;
-  fputc('\"', F);
-  if (str)
-  while (*str) {
-    int c = (int)(unsigned char)*str++;
-    switch (c) {
-    case '"':
-    case '\\':
-      fputc('\\', F);
-      fputc(c, F);
-      nwrite += 2;
-      break;
-    case '\n':
-      fputc('\\', F);
-      fputc('n', F);
-      nwrite += 2;
-      break;
-    default:
-      fputc(c, F);
-      ++nwrite;
-    }
-  }
-  fputc('\"', F);
-  return nwrite + 2;
-}
-
-static int freadstr(FILE * F, int encoding, char *start, size_t size)
-{
-  char *str = start;
-  bool quote = false;
-  for (;;) {
-    int c = fgetc(F);
-
-    if (isxspace(c)) {
-      if (str == start) {
-        continue;
-      }
-      if (!quote) {
-        *str = 0;
-        return (int)(str - start);
-      }
-    }
-    switch (c) {
-    case EOF:
-      return EOF;
-    case '"':
-      if (!quote && str != start) {
-        log_error(
-          ("datafile contains a \" that isn't at the start of a string.\n"));
-        assert
-          (!"datafile contains a \" that isn't at the start of a string.\n");
-      }
-      if (quote) {
-        *str = 0;
-        return (int)(str - start);
-      }
-      quote = true;
-      break;
-    case '\\':
-      c = fgetc(F);
-      switch (c) {
-      case EOF:
-        return EOF;
-      case 'n':
-        if ((size_t)(str - start + 1) < size) {
-          *str++ = '\n';
-        }
-        break;
-      default:
-        if ((size_t)(str - start + 1) < size) {
-          if (encoding == XML_CHAR_ENCODING_8859_1 && c & 0x80) {
-            char inbuf = (char)c;
-            size_t inbytes = 1;
-            size_t outbytes = size - (str - start);
-            int ret = unicode_latin1_to_utf8(str, &outbytes, &inbuf, &inbytes);
-            if (ret > 0)
-              str += ret;
-            else {
-              log_error("input data was not iso-8859-1! assuming utf-8\n");
-              encoding = XML_CHAR_ENCODING_ERROR;
-              *str++ = (char)c;
-            }
-          }
-          else {
-            *str++ = (char)c;
-          }
-        }
-      }
-      break;
-    default:
-      if ((size_t)(str - start + 1) < size) {
-        if (encoding == XML_CHAR_ENCODING_8859_1 && c & 0x80) {
-          char inbuf = (char)c;
-          size_t inbytes = 1;
-          size_t outbytes = size - (str - start);
-          int ret = unicode_latin1_to_utf8(str, &outbytes, &inbuf, &inbytes);
-          if (ret > 0)
-            str += ret;
-          else {
-            log_error("input data was not iso-8859-1! assuming utf-8\n");
-            encoding = XML_CHAR_ENCODING_ERROR;
-            *str++ = (char)c;
-          }
-        }
-        else {
-          *str++ = (char)c;
-        }
-      }
-    }
-  }
-}
-
-static int txt_w_brk(struct storage *store)
-{
-  putc('\n', (FILE *) store->userdata);
-  return 1;
-}
-
-static int txt_w_id(struct storage *store, int arg)
-{
-  return fprintf((FILE *) store->userdata, "%s ", itoa36(arg));
-}
-
-static int txt_r_id(struct storage *store)
-{
-  char id[8];
-  fscanf((FILE *) store->userdata, "%7s", id);
-  return atoi36(id);
-}
-
-static int txt_w_int(struct storage *store, int arg)
-{
-  return fprintf((FILE *) store->userdata, "%d ", arg);
-}
-
-static int txt_r_int(struct storage *store)
-{
-  int result;
-  fscanf((FILE *) store->userdata, "%d", &result);
-  return result;
-}
-
-static int txt_w_flt(struct storage *store, float arg)
-{
-  return fprintf((FILE *) store->userdata, "%f ", arg);
-}
-
-static float txt_r_flt(struct storage *store)
-{
-  double result;
-  fscanf((FILE *) store->userdata, "%lf", &result);
-  return (float)result;
-}
-
-static int txt_w_tok(struct storage *store, const char *tok)
-{
-  int result;
-  if (tok == NULL || tok[0] == 0) {
-    result = fputc(NULL_TOKEN, (FILE *) store->userdata);
-  } else {
-#ifndef NDEBUG
-    const char *find = strchr(tok, ' ');
-    if (!find)
-      find = strchr(tok, NULL_TOKEN);
-    assert(!find || !"reserved character in token");
-#endif
-    assert(tok[0] != ' ');
-    result = fputs(tok, (FILE *) store->userdata);
-  }
-  fputc(' ', (FILE *) store->userdata);
-  return result;
-}
-
-static char *txt_r_tok(struct storage *store)
-{
-  char result[256];
-  fscanf((FILE *) store->userdata, "%256s", result);
-  if (result[0] == NULL_TOKEN || result[0] == 0) {
-    return NULL;
-  }
-  return _strdup(result);
-}
-
-static void txt_r_tok_buf(struct storage *store, char *result, size_t size)
-{
-  char format[16];
-  if (result && size > 0) {
-    format[0] = '%';
-    sprintf(format + 1, "%lus", (unsigned long)size);
-    fscanf((FILE *) store->userdata, format, result);
-    if (result[0] == NULL_TOKEN) {
-      result[0] = 0;
-    }
-  } else {
-    /* trick to skip when no result expected */
-    fscanf((FILE *) store->userdata, "%*s");
-  }
-}
-
-static int txt_w_str(struct storage *store, const char *str)
-{
-  int result = fwritestr((FILE *) store->userdata, str);
-  fputc(' ', (FILE *) store->userdata);
-  return result + 1;
-}
-
-static char *txt_r_str(struct storage *store)
-{
-  char buffer[DISPLAYSIZE];
-  /* you should not use this */
-  freadstr((FILE *) store->userdata, store->encoding, buffer, sizeof(buffer));
-  return _strdup(buffer);
-}
-
-static void txt_r_str_buf(struct storage *store, char *result, size_t size)
-{
-  freadstr((FILE *) store->userdata, store->encoding, result, size);
-}
-
-static int txt_open(struct storage *store, const char *filename, int mode)
-{
-  const char *modes[] = { 0, "rt", "wt", "at" };
-  FILE *F = fopen(filename, modes[mode]);
-  store->userdata = F;
-  if (F) {
-    const unsigned char utf8_bom[4] = { 0xef, 0xbb, 0xbf };
-    if (mode == IO_READ) {
-      char token[8];
-      /* recognize UTF8 BOM */
-      store->r_tok_buf(store, token, sizeof(token));
-      if (memcmp(token, utf8_bom, 3) == 0) {
-        if (enc_gamedata != XML_CHAR_ENCODING_UTF8) {
-          log_warning("Found UTF-8 BOM, assuming unicode game data.\n");
-          store->encoding = XML_CHAR_ENCODING_UTF8;
-        }
-        store->version = atoi(token + 3);
-      } else {
-        if (store->encoding == XML_CHAR_ENCODING_NONE) {
-          store->encoding = XML_CHAR_ENCODING_8859_1;
-          log_warning("No BOM, assuming 8859-1 game data.\n");
-        }
-        store->version = atoi(token);
-      }
-    } else if (store->encoding == XML_CHAR_ENCODING_UTF8) {
-      fputs((const char *)utf8_bom, F);
-      fprintf(F, "%d\n", RELEASE_VERSION);
-    }
-  }
-  return (F == NULL);
-}
-
-static int txt_w_bin(struct storage *store, void *arg, size_t size)
-{
-  assert(!"not implemented!");
-  return 0;
-}
-
-static void txt_r_bin(struct storage *store, void *result, size_t size)
-{
-  assert(!"not implemented!");
-}
-
-static int txt_close(struct storage *store)
-{
-  return fclose((FILE *) store->userdata);
-}
-
-const storage text_store = {
-  txt_w_brk,
-  txt_w_int, txt_r_int,
-  txt_w_flt, txt_r_flt,
-  txt_w_id, txt_r_id,
-  txt_w_tok, txt_r_tok, txt_r_tok_buf,
-  txt_w_str, txt_r_str, txt_r_str_buf,
-  txt_w_bin, txt_r_bin,
-  txt_open, txt_close,
-  0, 0, NULL
-};
diff --git a/core/src/kernel/textstore.h b/core/src/kernel/textstore.h
deleted file mode 100644
index 46eb2090a..000000000
--- a/core/src/kernel/textstore.h
+++ /dev/null
@@ -1,23 +0,0 @@
-/* vi: set ts=2:
-+-------------------+  Enno Rehling <enno@eressea.de>
-| Eressea PBEM host |  Christian Schlittchen <corwin@amber.kn-bremen.de>
-| (c) 1998 - 2008   |  Katja Zedel <katze@felidae.kn-bremen.de>
-+-------------------+  
-This program may not be used, modified or distributed 
-without prior permission by the authors of Eressea.
-*/
-
-#ifndef H_KERNEL_TEXTSTORE
-#define H_KERNEL_TEXTSTORE
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#include <util/storage.h>
-
-  extern const storage text_store;
-
-#ifdef __cplusplus
-}
-#endif
-#endif
diff --git a/core/src/kernel/unit.c b/core/src/kernel/unit.c
index 9a7ea1e86..256338325 100644
--- a/core/src/kernel/unit.c
+++ b/core/src/kernel/unit.c
@@ -54,9 +54,10 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #include <util/log.h>
 #include <util/resolve.h>
 #include <util/rng.h>
-#include <util/storage.h>
 #include <util/variant.h>
 
+#include <storage.h>
+
 /* libc includes */
 #include <assert.h>
 #include <limits.h>
@@ -416,10 +417,10 @@ int ualias(const unit * u)
 
 int a_readprivate(attrib * a, void *owner, struct storage *store)
 {
-  a->data.v = store->r_str(store);
-  if (a->data.v)
-    return AT_READ_OK;
-  return AT_READ_FAIL;
+  char lbuf[DISPLAYSIZE];
+  READ_STR(store, lbuf, sizeof(lbuf));
+  a->data.v = _strdup(lbuf);
+  return (a->data.v) ? AT_READ_OK : AT_READ_FAIL;
 }
 
 /*********************/
@@ -646,7 +647,7 @@ void free_units(void)
 
 void write_unit_reference(const unit * u, struct storage *store)
 {
-  store->w_id(store, (u && u->region) ? u->no : 0);
+  WRITE_INT(store, (u && u->region) ? u->no : 0);
 }
 
 int resolve_unit(variant id, void *address)
@@ -666,7 +667,7 @@ int resolve_unit(variant id, void *address)
 variant read_unit_reference(struct storage * store)
 {
   variant var;
-  var.i = store->r_id(store);
+  READ_INT(store, &var.i);
   return var;
 }
 
diff --git a/core/src/kernel/version.h b/core/src/kernel/version.h
index b7ec62b01..00d5d539c 100644
--- a/core/src/kernel/version.h
+++ b/core/src/kernel/version.h
@@ -72,3 +72,5 @@
 
 #define MIN_VERSION CURSETYPE_VERSION   /* minimal datafile we support */
 #define RELEASE_VERSION SPELLBOOK_VERSION    /* current datafile */
+
+#define STREAM_VERSION 2 /* internal encoding of binary files */
diff --git a/core/src/modules/arena.c b/core/src/modules/arena.c
index ae99674cb..eaf574fca 100644
--- a/core/src/modules/arena.c
+++ b/core/src/modules/arena.c
@@ -59,7 +59,8 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #include <util/log.h>
 #include <util/resolve.h>
 #include <util/rng.h>
-#include <util/storage.h>
+
+#include <storage.h>
 
 /* libc include */
 #include <assert.h>
@@ -238,13 +239,13 @@ static void
 write_hurting(const attrib * a, const void *owner, struct storage *store)
 {
   building *b = a->data.v;
-  store->w_int(store, b->no);
+  WRITE_INT(store, b->no);
 }
 
 static int read_hurting(attrib * a, void *owner, struct storage *store)
 {
   int i;
-  i = store->r_int(store);
+  READ_INT(store, &i);
   a->data.v = (void *)findbuilding(i);
   if (a->data.v == NULL) {
     log_error("temple of pain is broken\n");
diff --git a/core/src/modules/gmcmd.c b/core/src/modules/gmcmd.c
index 41ebe28c6..d83a84aaa 100644
--- a/core/src/modules/gmcmd.c
+++ b/core/src/modules/gmcmd.c
@@ -45,7 +45,8 @@
 #include <util/umlaut.h>
 #include <util/parser.h>
 #include <util/rng.h>
-#include <util/storage.h>
+
+#include <storage.h>
 
 /* libc includes */
 #include <stdlib.h>
@@ -100,13 +101,13 @@ write_gmcreate(const attrib * a, const void *owner, struct storage *store)
 {
   const item_type *itype = (const item_type *)a->data.v;
   assert(itype);
-  store->w_tok(store, resourcename(itype->rtype, 0));
+  WRITE_TOK(store, resourcename(itype->rtype, 0));
 }
 
 static int read_gmcreate(attrib * a, void *owner, struct storage *store)
 {
   char zText[32];
-  store->r_tok_buf(store, zText, sizeof(zText));
+  READ_TOK(store, zText, sizeof(zText));
   a->data.v = it_find(zText);
   if (a->data.v == NULL) {
     log_error("unknown itemtype %s in gmcreate attribute\n", zText);
diff --git a/core/src/modules/museum.c b/core/src/modules/museum.c
index ba9a28cfa..61359781f 100644
--- a/core/src/modules/museum.c
+++ b/core/src/modules/museum.c
@@ -42,7 +42,8 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #include <util/base36.h>
 #include <util/functions.h>
 #include <util/goodies.h>
-#include <util/storage.h>
+
+#include <storage.h>
 
 /* libc includes */
 #include <limits.h>
@@ -70,16 +71,16 @@ a_writemuseumgivebackcookie(const attrib * a, const void *owner,
   struct storage *store)
 {
   museumgivebackcookie *gbc = (museumgivebackcookie *) a->data.v;
-  store->w_int(store, gbc->warden_no);
-  store->w_int(store, gbc->cookie);
+  WRITE_INT(store, gbc->warden_no);
+  WRITE_INT(store, gbc->cookie);
 }
 
 static int
 a_readmuseumgivebackcookie(attrib * a, void *owner, struct storage *store)
 {
   museumgivebackcookie *gbc = (museumgivebackcookie *) a->data.v;
-  gbc->warden_no = store->r_int(store);
-  gbc->cookie = store->r_int(store);
+  READ_INT(store, &gbc->warden_no);
+  READ_INT(store, &gbc->cookie);
   return AT_READ_OK;
 }
 
@@ -113,14 +114,14 @@ a_writemuseumgiveback(const attrib * a, const void *owner,
   struct storage *store)
 {
   museumgiveback *gb = (museumgiveback *) a->data.v;
-  store->w_int(store, gb->cookie);
+  WRITE_INT(store, gb->cookie);
   write_items(store, gb->items);
 }
 
 static int a_readmuseumgiveback(attrib * a, void *owner, struct storage *store)
 {
   museumgiveback *gb = (museumgiveback *) a->data.v;
-  gb->cookie = store->r_int(store);
+  READ_INT(store, &gb->cookie);
   read_items(store, &gb->items);
   return AT_READ_OK;
 }
diff --git a/core/src/modules/wormhole.c b/core/src/modules/wormhole.c
index 4a4730df3..c20d6c39f 100644
--- a/core/src/modules/wormhole.c
+++ b/core/src/modules/wormhole.c
@@ -31,7 +31,8 @@
 #include <util/resolve.h>
 #include <util/rng.h>
 #include <quicklist.h>
-#include <util/storage.h>
+
+#include <storage.h>
 
 /* libc includes */
 #include <assert.h>
@@ -125,11 +126,10 @@ static int resolve_exit(variant id, void *address)
 static int wormhole_read(struct attrib *a, void *owner, struct storage *store)
 {
   wormhole_data *data = (wormhole_data *) a->data.v;
-  resolve_fun resolver =
-    (store->version < UIDHASH_VERSION) ? resolve_exit : resolve_region_id;
-  read_fun reader =
-    (store->version <
-    UIDHASH_VERSION) ? read_building_reference : read_region_reference;
+  resolve_fun resolver = (global.data_version < UIDHASH_VERSION)
+    ? resolve_exit : resolve_region_id;
+  read_fun reader = (global.data_version < UIDHASH_VERSION) 
+    ? read_building_reference : read_region_reference;
 
   int rb =
     read_reference(&data->entry, store, read_building_reference,
diff --git a/core/src/modules/xmas.c b/core/src/modules/xmas.c
index 9c44011b1..42dd8c791 100644
--- a/core/src/modules/xmas.c
+++ b/core/src/modules/xmas.c
@@ -28,9 +28,10 @@
 #include <util/base36.h>
 #include <util/event.h>
 #include <util/goodies.h>
-#include <util/storage.h>
 #include <util/resolve.h>
 
+#include <storage.h>
+
 /* libc includes */
 #include <stdlib.h>
 
@@ -42,7 +43,7 @@ static int xmasgate_handle(trigger * t, void *data)
 static void xmasgate_write(const trigger * t, struct storage *store)
 {
   building *b = (building *) t->data.v;
-  store->w_tok(store, itoa36(b->no));
+  WRITE_TOK(store, itoa36(b->no));
 }
 
 static int xmasgate_read(trigger * t, struct storage *store)
diff --git a/core/src/platform.h b/core/src/platform.h
index e29b1c040..96754eaa8 100644
--- a/core/src/platform.h
+++ b/core/src/platform.h
@@ -43,7 +43,11 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 # define _CRT_SECURE_NO_DEPRECATE
 #endif
 
-/* http://msdn2.microsoft.com/en-us/library/ms235505(VS.80).aspx */
+/*
+ * http://msdn2.microsoft.com/en-us/library/ms235505(VS.80).aspx
+ * Defining _CRT_DISABLE_PERFCRIT_LOCKS forces all I/O operations to assume a 
+ * single-threaded I/O model and use the _nolock forms of the functions. 
+ */
 #ifndef _CRT_DISABLE_PERFCRIT_LOCKS
 # define _CRT_DISABLE_PERFCRIT_LOCKS
 #endif
@@ -152,6 +156,7 @@ typedef struct stat stat_type;
 
 /* Microsoft Visual C */
 #ifdef _MSC_VER
+# include <direct.h>
 # include <string.h>            /* must be included here so strdup is not redefined */
 # define R_OK 4
 # define HAVE_INLINE
diff --git a/core/src/triggers/changefaction.c b/core/src/triggers/changefaction.c
index 60d821412..3ad35f44a 100644
--- a/core/src/triggers/changefaction.c
+++ b/core/src/triggers/changefaction.c
@@ -31,7 +31,8 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #include <util/log.h>
 #include <util/resolve.h>
 #include <util/base36.h>
-#include <util/storage.h>
+
+#include <storage.h>
 
 /* ansi includes */
 #include <stdio.h>
diff --git a/core/src/triggers/changerace.c b/core/src/triggers/changerace.c
index a78ac2d55..f03483a0d 100644
--- a/core/src/triggers/changerace.c
+++ b/core/src/triggers/changerace.c
@@ -29,9 +29,10 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #include <util/event.h>
 #include <util/log.h>
 #include <util/resolve.h>
-#include <util/storage.h>
 #include <util/base36.h>
 
+#include <storage.h>
+
 /* ansi includes */
 #include <stdio.h>
 #include <stdlib.h>
diff --git a/core/src/triggers/clonedied.c b/core/src/triggers/clonedied.c
index 665379ae7..652aa9228 100644
--- a/core/src/triggers/clonedied.c
+++ b/core/src/triggers/clonedied.c
@@ -30,9 +30,10 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #include <util/event.h>
 #include <util/log.h>
 #include <util/resolve.h>
-#include <util/storage.h>
 #include <util/base36.h>
 
+#include <storage.h>
+
 /* libc includes */
 #include <stdio.h>
 #include <stdlib.h>
diff --git a/core/src/triggers/createcurse.c b/core/src/triggers/createcurse.c
index 01135f588..752765af1 100644
--- a/core/src/triggers/createcurse.c
+++ b/core/src/triggers/createcurse.c
@@ -30,9 +30,10 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #include <util/event.h>
 #include <util/log.h>
 #include <util/resolve.h>
-#include <util/storage.h>
 #include <util/base36.h>
 
+#include <storage.h>
+
 /* ansi includes */
 #include <stdio.h>
 #include <stdlib.h>
@@ -47,9 +48,9 @@ typedef struct createcurse_data {
   struct unit *mage;
   struct unit *target;
   const curse_type *type;
-  double vigour;
+  float vigour;
   int duration;
-  double effect;
+  float effect;
   int men;
 } createcurse_data;
 
@@ -84,11 +85,11 @@ static void createcurse_write(const trigger * t, struct storage *store)
   createcurse_data *td = (createcurse_data *) t->data.v;
   write_unit_reference(td->mage, store);
   write_unit_reference(td->target, store);
-  store->w_tok(store, td->type->cname);
-  store->w_flt(store, (float)td->vigour);
-  store->w_int(store, td->duration);
-  store->w_flt(store, (float)td->effect);
-  store->w_int(store, td->men);
+  WRITE_TOK(store, td->type->cname);
+  WRITE_FLT(store, (float)td->vigour);
+  WRITE_INT(store, td->duration);
+  WRITE_FLT(store, (float)td->effect);
+  WRITE_INT(store, td->men);
 }
 
 static int createcurse_read(trigger * t, struct storage *store)
@@ -99,27 +100,30 @@ static int createcurse_read(trigger * t, struct storage *store)
   read_reference(&td->mage, store, read_unit_reference, resolve_unit);
   read_reference(&td->target, store, read_unit_reference, resolve_unit);
 
-  if (store->version < CURSETYPE_VERSION) {
-    int id1, id2;
-    id1 = store->r_int(store);
-    id2 = store->r_int(store);
+  if (global.data_version < CURSETYPE_VERSION) {
+    int id1, id2, n;
+    READ_INT(store, &id1);
+    READ_INT(store, &id2);
     assert(id2 == 0);
-    td->vigour = store->r_flt(store);
-    td->duration = store->r_int(store);
-    td->effect = store->r_int(store);
-    td->men = store->r_int(store);
+    READ_FLT(store, &td->vigour);
+    READ_INT(store, &td->duration);
+    READ_INT(store, &n);
+    td->effect = (float)n;
+    READ_INT(store, &td->men);
     td->type = ct_find(oldcursename(id1));
   } else {
-    store->r_tok_buf(store, zText, sizeof(zText));
+    READ_TOK(store, zText, sizeof(zText));
     td->type = ct_find(zText);
-    td->vigour = store->r_flt(store);
-    td->duration = store->r_int(store);
-    if (store->version < CURSEFLOAT_VERSION) {
-      td->effect = (double)store->r_int(store);
+    READ_FLT(store, &td->vigour);
+    READ_INT(store, &td->duration);
+    if (global.data_version < CURSEFLOAT_VERSION) {
+      int n;
+      READ_INT(store, &n);
+      td->effect = (float)n;
     } else {
-      td->effect = store->r_flt(store);
+      READ_FLT(store, &td->effect);
     }
-    td->men = store->r_int(store);
+    READ_INT(store, &td->men);
   }
   return AT_READ_OK;
 }
@@ -134,7 +138,7 @@ trigger_type tt_createcurse = {
 };
 
 trigger *trigger_createcurse(struct unit * mage, struct unit * target,
-  const curse_type * ct, double vigour, int duration, double effect, int men)
+  const curse_type * ct, float vigour, int duration, float effect, int men)
 {
   trigger *t = t_new(&tt_createcurse);
   createcurse_data *td = (createcurse_data *) t->data.v;
diff --git a/core/src/triggers/createcurse.h b/core/src/triggers/createcurse.h
index eaa3b35e6..84fd33a77 100644
--- a/core/src/triggers/createcurse.h
+++ b/core/src/triggers/createcurse.h
@@ -33,8 +33,8 @@ extern "C" {
   extern struct trigger_type tt_createcurse;
 
   extern struct trigger *trigger_createcurse(struct unit *mage,
-    struct unit *target, const struct curse_type *ct, double vigour,
-    int duration, double effect, int men);
+    struct unit *target, const struct curse_type *ct, float vigour,
+    int duration, float effect, int men);
 
 #ifdef __cplusplus
 }
diff --git a/core/src/triggers/createunit.c b/core/src/triggers/createunit.c
index 45671735a..5ea487901 100644
--- a/core/src/triggers/createunit.c
+++ b/core/src/triggers/createunit.c
@@ -33,7 +33,8 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #include <util/event.h>
 #include <util/log.h>
 #include <util/resolve.h>
-#include <util/storage.h>
+
+#include <storage.h>
 
 /* ansi includes */
 #include <stdio.h>
@@ -83,7 +84,7 @@ static void createunit_write(const trigger * t, struct storage *store)
   write_faction_reference(td->f, store);
   write_region_reference(td->r, store);
   write_race_reference(td->race, store);
-  store->w_int(store, td->number);
+  WRITE_INT(store, td->number);
 }
 
 static int createunit_read(trigger * t, struct storage *store)
@@ -94,14 +95,14 @@ static int createunit_read(trigger * t, struct storage *store)
     read_reference(&td->f, store, read_faction_reference, resolve_faction);
   int rc =
     read_reference(&td->r, store, read_region_reference,
-    RESOLVE_REGION(store->version));
+    RESOLVE_REGION(global.data_version));
   td->race = (const struct race *)read_race_reference(store).v;
 
   if (uc == 0 && rc == 0) {
     if (!td->f || !td->r)
       return AT_READ_FAIL;
   }
-  td->number = store->r_int(store);
+  READ_INT(store, &td->number);
 
   return AT_READ_OK;
 }
diff --git a/core/src/triggers/gate.c b/core/src/triggers/gate.c
index 4859d929c..d460d6d49 100644
--- a/core/src/triggers/gate.c
+++ b/core/src/triggers/gate.c
@@ -24,7 +24,8 @@
 #include <util/event.h>
 #include <util/log.h>
 #include <util/resolve.h>
-#include <util/storage.h>
+
+#include <storage.h>
 
 /* libc includes */
 #include <stdlib.h>
@@ -78,7 +79,7 @@ static int gate_read(trigger * t, struct storage *store)
     read_reference(&gd->gate, store, read_building_reference, resolve_building);
   int rc =
     read_reference(&gd->target, store, read_region_reference,
-    RESOLVE_REGION(store->version));
+    RESOLVE_REGION(global.data_version));
 
   if (bc == 0 && rc == 0) {
     if (!gd->gate || !gd->target)
diff --git a/core/src/triggers/giveitem.c b/core/src/triggers/giveitem.c
index 3cdefd63e..cf8015849 100644
--- a/core/src/triggers/giveitem.c
+++ b/core/src/triggers/giveitem.c
@@ -30,7 +30,8 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #include <util/event.h>
 #include <util/log.h>
 #include <util/resolve.h>
-#include <util/storage.h>
+
+#include <storage.h>
 
 /* ansi includes */
 #include <stdio.h>
@@ -76,8 +77,8 @@ static void giveitem_write(const trigger * t, struct storage *store)
 {
   giveitem_data *td = (giveitem_data *) t->data.v;
   write_unit_reference(td->u, store);
-  store->w_int(store, td->number);
-  store->w_tok(store, td->itype->rtype->_name[0]);
+  WRITE_INT(store, td->number);
+  WRITE_TOK(store, td->itype->rtype->_name[0]);
 }
 
 static int giveitem_read(trigger * t, struct storage *store)
@@ -87,8 +88,8 @@ static int giveitem_read(trigger * t, struct storage *store)
 
   int result = read_reference(&td->u, store, read_unit_reference, resolve_unit);
 
-  td->number = store->r_int(store);
-  store->r_tok_buf(store, zText, sizeof(zText));
+  READ_INT(store, &td->number);
+  READ_TOK(store, zText, sizeof(zText));
   td->itype = it_find(zText);
   assert(td->itype);
 
diff --git a/core/src/triggers/killunit.c b/core/src/triggers/killunit.c
index aa24982de..450d3ac66 100644
--- a/core/src/triggers/killunit.c
+++ b/core/src/triggers/killunit.c
@@ -29,7 +29,8 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #include <util/event.h>
 #include <util/log.h>
 #include <util/resolve.h>
-#include <util/storage.h>
+
+#include <storage.h>
 
 #include <stdio.h>
 #include <stdlib.h>
diff --git a/core/src/triggers/removecurse.c b/core/src/triggers/removecurse.c
index 80eb6c3c6..43d2e6f30 100644
--- a/core/src/triggers/removecurse.c
+++ b/core/src/triggers/removecurse.c
@@ -26,11 +26,12 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 
 /* util includes */
 #include <util/attrib.h>
+#include <util/base36.h>
 #include <util/event.h>
 #include <util/log.h>
 #include <util/resolve.h>
-#include <util/storage.h>
-#include <util/base36.h>
+
+#include <storage.h>
 
 /* ansi includes */
 #include <stdio.h>
@@ -74,8 +75,8 @@ static int removecurse_handle(trigger * t, void *data)
 static void removecurse_write(const trigger * t, struct storage *store)
 {
   removecurse_data *td = (removecurse_data *) t->data.v;
-  store->w_tok(store, td->target ? itoa36(td->target->no) : 0);
-  store->w_int(store, td->curse ? td->curse->no : 0);
+  WRITE_TOK(store, td->target ? itoa36(td->target->no) : 0);
+  WRITE_INT(store, td->curse ? td->curse->no : 0);
 }
 
 static int removecurse_read(trigger * t, struct storage *store)
diff --git a/core/src/triggers/shock.c b/core/src/triggers/shock.c
index 75f1829d8..ef0dab03e 100644
--- a/core/src/triggers/shock.c
+++ b/core/src/triggers/shock.c
@@ -36,7 +36,8 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #include <util/log.h>
 #include <util/resolve.h>
 #include <util/rng.h>
-#include <util/storage.h>
+
+#include <storage.h>
 
 /* libc includes */
 #include <assert.h>
diff --git a/core/src/triggers/timeout.c b/core/src/triggers/timeout.c
index 65a1dc10f..d4c11167c 100644
--- a/core/src/triggers/timeout.c
+++ b/core/src/triggers/timeout.c
@@ -24,7 +24,8 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #include <util/attrib.h>
 #include <util/event.h>
 #include <util/log.h>
-#include <util/storage.h>
+
+#include <storage.h>
 
 #include <stdio.h>
 #include <stdlib.h>
@@ -67,14 +68,14 @@ static int timeout_handle(trigger * t, void *data)
 static void timeout_write(const trigger * t, struct storage *store)
 {
   timeout_data *td = (timeout_data *) t->data.v;
-  store->w_int(store, td->timer);
+  WRITE_INT(store, td->timer);
   write_triggers(store, td->triggers);
 }
 
 static int timeout_read(trigger * t, struct storage *store)
 {
   timeout_data *td = (timeout_data *) t->data.v;
-  td->timer = store->r_int(store);
+  READ_INT(store, &td->timer);
   read_triggers(store, &td->triggers);
   if (td->timer > 20) {
     trigger *tr = td->triggers;
diff --git a/core/src/triggers/unitmessage.c b/core/src/triggers/unitmessage.c
index d564c81c9..cb5e4857b 100644
--- a/core/src/triggers/unitmessage.c
+++ b/core/src/triggers/unitmessage.c
@@ -24,7 +24,8 @@ without prior permission by the authors of Eressea.
 #include <util/language.h>
 #include <util/log.h>
 #include <util/resolve.h>
-#include <util/storage.h>
+
+#include <storage.h>
 
 /* ansi includes */
 #include <stdio.h>
@@ -78,9 +79,9 @@ static void unitmessage_write(const trigger * t, struct storage *store)
 {
   unitmessage_data *td = (unitmessage_data *) t->data.v;
   write_unit_reference(td->target, store);
-  store->w_tok(store, td->string);
-  store->w_int(store, td->type);
-  store->w_int(store, td->level);
+  WRITE_TOK(store, td->string);
+  WRITE_INT(store, td->type);
+  WRITE_INT(store, td->level);
 }
 
 static int unitmessage_read(trigger * t, struct storage *store)
@@ -90,11 +91,10 @@ static int unitmessage_read(trigger * t, struct storage *store)
 
   int result =
     read_reference(&td->target, store, read_unit_reference, resolve_unit);
-
-  td->string = store->r_tok(store);
-  td->type = store->r_int(store);
-  td->level = store->r_int(store);
+  READ_TOK(store, zText, sizeof(zText));
   td->string = _strdup(zText);
+  READ_INT(store, &td->type);
+  READ_INT(store, &td->level);
 
   if (result == 0 && td->target == NULL) {
     return AT_READ_FAIL;
diff --git a/core/src/util/attrib.c b/core/src/util/attrib.c
index ef7674534..197fea808 100644
--- a/core/src/util/attrib.c
+++ b/core/src/util/attrib.c
@@ -280,7 +280,7 @@ int a_read(struct storage *store, attrib ** attribs, void *owner)
   
   zText[0] = 0;
   key = -1;
-  store->r_tok_buf(store, zText, sizeof(zText));
+  READ_TOK(store, zText, sizeof(zText));
   if (strcmp(zText, "end") == 0)
     return retval;
   else
@@ -324,7 +324,7 @@ int a_read(struct storage *store, attrib ** attribs, void *owner)
       assert(!"fehler: keine laderoutine f�r attribut");
     }
 
-    store->r_tok_buf(store, zText, sizeof(zText));
+    READ_TOK(store, zText, sizeof(zText));
     if (!strcmp(zText, "end"))
       break;
     key = __at_hashkey(zText);
@@ -339,12 +339,12 @@ void a_write(struct storage *store, const attrib * attribs, const void *owner)
   while (na) {
     if (na->type->write) {
       assert(na->type->hashkey || !"attribute not registered");
-      store->w_tok(store, na->type->name);
+      WRITE_TOK(store, na->type->name);
       na->type->write(na, owner, store);
       na = na->next;
     } else {
       na = na->nexttype;
     }
   }
-  store->w_tok(store, "end");
+  WRITE_TOK(store, "end");
 }
diff --git a/core/src/util/attrib.h b/core/src/util/attrib.h
index 6096a4cbe..dc26e80ea 100644
--- a/core/src/util/attrib.h
+++ b/core/src/util/attrib.h
@@ -22,7 +22,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 extern "C" {
 #endif
 
-  struct storage;
+  struct gamedata;
   typedef void (*afun) (void);
 
   typedef struct attrib {
@@ -52,8 +52,8 @@ extern "C" {
     void (*finalize) (struct attrib *);
     int (*age) (struct attrib *);
     /* age returns 0 if the attribute needs to be removed, !=0 otherwise */
-    void (*write) (const struct attrib *, const void *owner, struct storage *);
-    int (*read) (struct attrib *, void *owner, struct storage *);       /* return AT_READ_OK on success, AT_READ_FAIL if attrib needs removal */
+    void(*write) (const struct attrib *, const void *owner, struct storage *);
+    int(*read) (struct attrib *, void *owner, struct storage *);       /* return AT_READ_OK on success, AT_READ_FAIL if attrib needs removal */
     unsigned int flags;
     /* ---- internal data, do not modify: ---- */
     struct attrib_type *nexthash;
diff --git a/core/src/util/event.c b/core/src/util/event.c
index 8127012a6..a75eca6dd 100644
--- a/core/src/util/event.c
+++ b/core/src/util/event.c
@@ -34,12 +34,12 @@ void write_triggers(struct storage *store, const trigger * t)
 {
   while (t) {
     if (t->type->write) {
-      store->w_tok(store, t->type->name);
+      WRITE_TOK(store, t->type->name);
       t->type->write(t, store);
     }
     t = t->next;
   }
-  store->w_tok(store, "end");
+  WRITE_TOK(store, "end");
 }
 
 int read_triggers(struct storage *store, trigger ** tp)
@@ -48,7 +48,7 @@ int read_triggers(struct storage *store, trigger ** tp)
     trigger_type *ttype;
     char zText[128];
 
-    store->r_tok_buf(store, zText, sizeof(zText));
+    READ_TOK(store, zText, sizeof(zText));
     if (!strcmp(zText, "end"))
       break;
     ttype = tt_find(zText);
@@ -137,7 +137,7 @@ static void
 write_handler(const attrib * a, const void *owner, struct storage *store)
 {
   handler_info *hi = (handler_info *) a->data.v;
-  store->w_tok(store, hi->event);
+  WRITE_TOK(store, hi->event);
   write_triggers(store, hi->triggers);
 }
 
@@ -146,7 +146,7 @@ static int read_handler(attrib * a, void *owner, struct storage *store)
   char zText[128];
   handler_info *hi = (handler_info *) a->data.v;
 
-  store->r_tok_buf(store, zText, sizeof(zText));
+  READ_TOK(store, zText, sizeof(zText));
   hi->event = _strdup(zText);
   read_triggers(store, &hi->triggers);
   if (hi->triggers != NULL) {
diff --git a/core/src/util/resolve.c b/core/src/util/resolve.c
index dbe6d2cc2..7f28c942a 100644
--- a/core/src/util/resolve.c
+++ b/core/src/util/resolve.c
@@ -40,7 +40,7 @@ static unresolved *ur_current;
 variant read_int(struct storage *store)
 {
   variant var;
-  var.i = store->r_int(store);
+  READ_INT(store, &var.i);
   return var;
 }
 
diff --git a/core/src/util/storage.h b/core/src/util/storage.h
deleted file mode 100644
index 15f5ce3ae..000000000
--- a/core/src/util/storage.h
+++ /dev/null
@@ -1,48 +0,0 @@
-#ifndef STORAGE_H
-#define STORAGE_H
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-  typedef struct storage {
-    /* separator for readable files: */
-    int (*w_brk) (struct storage *);
-    /* integer values: */
-    int (*w_int) (struct storage *, int arg);
-    int (*r_int) (struct storage *);
-    /* float values: */
-    int (*w_flt) (struct storage *, float arg);
-    float (*r_flt) (struct storage *);
-    /* id values: */
-    int (*w_id) (struct storage *, int arg);
-    int (*r_id) (struct storage *);
-    /* tokens that contain no whitespace: */
-    int (*w_tok) (struct storage *, const char *tok);
-    char *(*r_tok) (struct storage *);
-    void (*r_tok_buf) (struct storage *, char *result, size_t size);
-    /* strings that need to be quoted: */
-    int (*w_str) (struct storage *, const char *tok);
-    char *(*r_str) (struct storage *);
-    void (*r_str_buf) (struct storage *, char *result, size_t size);
-    /* binary data: */
-    int (*w_bin) (struct storage *, void *arg, size_t size);
-    void (*r_bin) (struct storage *, void *result, size_t size);
-
-    int (*open) (struct storage *, const char *filename, int mode);
-    int (*close) (struct storage *);
-
-    int encoding;
-    int version;
-    void *userdata;
-  } storage;
-
-#define IO_READ 0x01
-#define IO_WRITE 0x02
-#define IO_BINARY 0x04
-#define IO_TEXT 0x08
-#define IO_DEFAULT IO_BINARY
-
-#ifdef __cplusplus
-}
-#endif
-#endif
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index a1cdae203..2488de482 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -11,6 +11,7 @@ ENDIF(CMAKE_COMPILER_IS_GNUCC)
 
 include_directories (${ERESSEA_INCLUDE_DIR})
 include_directories (${CRITBIT_INCLUDE_DIR})
+include_directories (${STORAGE_INCLUDE_DIR})
 include_directories (${CRYPTO_INCLUDE_DIR})
 include_directories (${QUICKLIST_INCLUDE_DIR})
 include_directories (${CUTEST_INCLUDE_DIR})
diff --git a/src/bindings.c b/src/bindings.c
index ca2f27c55..eb325b501 100644
--- a/src/bindings.c
+++ b/src/bindings.c
@@ -18,7 +18,7 @@ static int tolua_levitate_ship(lua_State * L)
 {
   ship *sh = (ship *) tolua_tousertype(L, 1, 0);
   unit *mage = (unit *) tolua_tousertype(L, 2, 0);
-  double power = (double)tolua_tonumber(L, 3, 0);
+  float power = (float)tolua_tonumber(L, 3, 0);
   int duration = (int)tolua_tonumber(L, 4, 0);
   int cno = levitate_ship(sh, mage, power, duration);
   tolua_pushnumber(L, (lua_Number) cno);
diff --git a/src/curses.c b/src/curses.c
index 7dd9be6ff..34f723159 100644
--- a/src/curses.c
+++ b/src/curses.c
@@ -24,7 +24,8 @@
 #include <util/rand.h>
 #include <util/rng.h>
 #include <util/resolve.h>
-#include <util/storage.h>
+
+#include <storage.h>
 
 #include <assert.h>
 
@@ -45,7 +46,7 @@ void cw_write(const attrib * a, const void *target, storage * store)
 {
   connection *b = ((wallcurse *) ((curse *) a->data.v)->data.v)->wall;
   curse_write(a, target, store);
-  store->w_int(store, b->id);
+  WRITE_INT(store, b->id);
 }
 
 typedef struct bresolve {
@@ -64,7 +65,7 @@ static int cw_read(attrib * a, void *target, storage * store)
 
   curse_read(a, store, target);
   br->self = c;
-  br->id = store->r_int(store);
+  READ_INT(store, &br->id);
 
   var.i = br->id;
   ur_add(var, &wc->wall, resolve_borderid);
@@ -90,7 +91,7 @@ static int cw_read(attrib * a, void *target, storage * store)
  *   Was fuer eine Wirkung hat die?
  */
 
-void wall_vigour(curse * c, double delta)
+void wall_vigour(curse * c, float delta)
 {
   wallcurse *wc = (wallcurse *) c->data.v;
   assert(wc->buddy->vigour == c->vigour);
@@ -180,8 +181,8 @@ static void wall_read(connection * b, storage * store)
   wall_data *fd = b->data.v ? (wall_data *) b->data.v : &dummy;
   variant mno;
 
-  if (store->version < STORAGE_VERSION) {
-    mno.i = store->r_int(store);
+  if (global.data_version < STORAGE_VERSION) {
+    READ_INT(store, &mno.i);
     fd->mage = findunit(mno.i);
     if (!fd->mage && b->data.v) {
       ur_add(mno, &fd->mage, resolve_unit);
@@ -189,9 +190,9 @@ static void wall_read(connection * b, storage * store)
   } else {
     read_reference(&fd->mage, store, read_unit_reference, resolve_unit);
   }
-  fd->force = store->r_int(store);
-  if (store->version >= NOBORDERATTRIBS_VERSION) {
-    fd->countdown = store->r_int(store);
+  READ_INT(store, &fd->force);
+  if (global.data_version >= NOBORDERATTRIBS_VERSION) {
+    READ_INT(store, &fd->countdown);
   }
   fd->active = true;
 }
@@ -200,8 +201,8 @@ static void wall_write(const connection * b, storage * store)
 {
   wall_data *fd = (wall_data *) b->data.v;
   write_unit_reference(fd->mage, store);
-  store->w_int(store, fd->force);
-  store->w_int(store, fd->countdown);
+  WRITE_INT(store, fd->force);
+  WRITE_INT(store, fd->countdown);
 }
 
 static int wall_age(connection * b)
diff --git a/src/main.c b/src/main.c
index 289196769..cd0e4053c 100644
--- a/src/main.c
+++ b/src/main.c
@@ -22,6 +22,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #include <kernel/config.h>
 #include <kernel/types.h>
 #include <kernel/save.h>
+#include <kernel/version.h>
 #include <bindings/bindings.h>
 #include <eressea.h>
 #include <gmtool.h>
@@ -102,8 +103,8 @@ static int parse_args(int argc, char **argv, int *exitcode)
       if (strcmp(argv[i] + 2, "version") == 0) {
         printf("\n%s PBEM host\n"
           "Copyright (C) 1996-2005 C. Schlittchen, K. Zedel, E. Rehling, H. Peters.\n\n"
-          "Compilation: " __DATE__ " at " __TIME__ "\nVersion: %f\n\n",
-          global.gamename, version());
+          "Compilation: " __DATE__ " at " __TIME__ "\nVersion: %d\n\n",
+          global.gamename, RELEASE_VERSION);
       } else if (strcmp(argv[i] + 2, "color") == 0) {
         /* force the editor to have colors */
         force_color = 1;
diff --git a/src/spells/alp.c b/src/spells/alp.c
index 1c3da3dcf..cfffb0b87 100644
--- a/src/spells/alp.c
+++ b/src/spells/alp.c
@@ -29,7 +29,8 @@
 #include <util/event.h>
 #include <util/resolve.h>
 #include <util/umlaut.h>
-#include <util/storage.h>
+
+#include <storage.h>
 
 #include <triggers/createcurse.h>
 #include <triggers/killunit.h>
@@ -147,7 +148,7 @@ void alp_findet_opfer(unit * alp, region * r)
   alp_data *ad = (alp_data *) a->data.v;
   unit *mage = ad->mage;
   unit *opfer = ad->target;
-  double effect;
+  float effect;
   message *msg;
 
   assert(opfer);
diff --git a/src/spells/combatspells.c b/src/spells/combatspells.c
index 8ec78f5df..a6eaf97f1 100644
--- a/src/spells/combatspells.c
+++ b/src/spells/combatspells.c
@@ -904,11 +904,11 @@ int sp_strong_wall(struct castorder * co)
 {
   fighter * fi = co->magician.fig;
   int level = co->level;
-  double power = co->force;
+  float power = co->force;
   battle *b = fi->side->battle;
   unit *mage = fi->unit;
   building *burg;
-  double effect;
+  float effect;
   static bool init = false;
   message *msg;
   static const curse_type *strongwall_ct;
@@ -922,7 +922,7 @@ int sp_strong_wall(struct castorder * co)
   }
   burg = mage->building;
 
-  effect = power * 0.25;
+  effect = power / 4;
   create_curse(mage, &burg->attribs, strongwall_ct, power, 1, effect, 0);
 
   msg =
diff --git a/src/spells/shipcurse.c b/src/spells/shipcurse.c
index 39d530770..13d7d1e8a 100644
--- a/src/spells/shipcurse.c
+++ b/src/spells/shipcurse.c
@@ -28,7 +28,8 @@
 #include <util/functions.h>
 #include <util/language.h>
 #include <util/log.h>
-#include <util/storage.h>
+
+#include <storage.h>
 
 /* libc includes */
 #include <string.h>
@@ -80,7 +81,7 @@ static int flyingship_read(storage * store, curse * c, void *target)
 {
   ship *sh = (ship *) target;
   c->data.v = sh;
-  if (store->version < FOSS_VERSION) {
+  if (global.data_version < FOSS_VERSION) {
     sh->flags |= SF_FLYING;
     return 0;
   }
@@ -119,7 +120,7 @@ static struct curse_type ct_shipspeedup = { "shipspeedup",
   CURSETYP_NORM, 0, 0, cinfo_ship
 };
 
-curse *shipcurse_flyingship(ship * sh, unit * mage, double power, int duration)
+curse *shipcurse_flyingship(ship * sh, unit * mage, float power, int duration)
 {
   static const curse_type *ct_flyingship = NULL;
   if (!ct_flyingship) {
@@ -142,7 +143,7 @@ curse *shipcurse_flyingship(ship * sh, unit * mage, double power, int duration)
   }
 }
 
-int levitate_ship(ship * sh, unit * mage, double power, int duration)
+int levitate_ship(ship * sh, unit * mage, float power, int duration)
 {
   curse *c = shipcurse_flyingship(sh, mage, power, duration);
   if (c) {
diff --git a/src/spells/shipcurse.h b/src/spells/shipcurse.h
index 5d416bc54..ab60d7232 100644
--- a/src/spells/shipcurse.h
+++ b/src/spells/shipcurse.h
@@ -26,8 +26,8 @@ extern "C" {
     const struct curse *c, int self);
   extern void register_shipcurse(void);
   extern struct curse *shipcurse_flyingship(struct ship *sh, struct unit *mage,
-    double power, int duration);
-  int levitate_ship(struct ship *sh, struct unit *mage, double power,
+    float power, int duration);
+  int levitate_ship(struct ship *sh, struct unit *mage, float power,
     int duration);
 
 #ifdef __cplusplus
diff --git a/src/spells/spells.c b/src/spells/spells.c
index 0b3ea79ca..234edee51 100644
--- a/src/spells/spells.c
+++ b/src/spells/spells.c
@@ -76,7 +76,8 @@
 #include <util/goodies.h>
 #include <util/resolve.h>
 #include <util/rng.h>
-#include <util/storage.h>
+
+#include <storage.h>
 
 /* libc includes */
 #include <assert.h>
@@ -100,7 +101,7 @@
 #include <attributes/hate.h>
 /* ----------------------------------------------------------------------- */
 
-static double zero_effect = 0.0;
+static float zero_effect = 0.0F;
 
 attrib_type at_wdwpyramid = {
   "wdwpyramid", NULL, NULL, NULL, a_writevoid, a_readvoid
@@ -288,7 +289,7 @@ static void magicanalyse_ship(ship * sh, unit * mage, double force)
 
 }
 
-int break_curse(attrib ** alist, int cast_level, double force, curse * c)
+static int break_curse(attrib ** alist, int cast_level, float force, curse * c)
 {
   int succ = 0;
 /*  attrib **a = a_find(*ap, &at_curse); */
@@ -317,7 +318,7 @@ int break_curse(attrib ** alist, int cast_level, double force, curse * c)
      * auf alle Verzauberungen wirken. Ansonsten pruefe, ob der Curse vom
      * richtigen Typ ist. */
     if (!c || c == c1) {
-      double remain = destr_curse(c1, cast_level, force);
+      float remain = destr_curse(c1, cast_level, force);
       if (remain < force) {
         succ = cast_level;
         force = remain;
@@ -609,7 +610,7 @@ static int sp_destroy_magic(castorder * co)
 {
   unit *mage = co->magician.u;
   int cast_level = co->level;
-  double force = co->force;
+  float force = co->force;
   spellparameter *pa = co->par;
   curse *c = NULL;
   char ts[80];
@@ -770,7 +771,7 @@ static int sp_goodwinds(castorder * co)
   region *r = co_get_region(co);
   unit *mage = co->magician.u;
   int cast_level = co->level;
-  double power = co->force;
+  float power = co->force;
   int duration = cast_level + 1;
   spellparameter *pa = co->par;
   message *m;
@@ -867,7 +868,7 @@ static int sp_summonent(castorder * co)
   region *r = co_get_region(co);
   unit *mage = co->magician.u;
   int cast_level = co->level;
-  double power = co->force;
+  float power = co->force;
   unit *u;
   attrib *a;
   int ents;
@@ -971,9 +972,7 @@ static int sp_maelstrom(castorder * co)
   unit *mage = co->magician.u;
   int cast_level = co->level;
   curse *c;
-  double power = co->force;
-  double effect = co->force;
-  int duration = (int)power + 1;
+  int duration = (int)co->force + 1;
 
   if (!fval(r->terrain, SEA_REGION)) {
     cmistake(mage, co->order, 205, MSG_MAGIC);
@@ -984,7 +983,7 @@ static int sp_maelstrom(castorder * co)
   /* Attribut auf Region.
    * Existiert schon ein curse, so wird dieser verstaerkt
    * (Max(Dauer), Max(Staerke))*/
-  c = create_curse(mage, &r->attribs, ct_find("maelstrom"), power, duration, effect, 0);
+  c = create_curse(mage, &r->attribs, ct_find("maelstrom"), co->force, duration, co->force, 0);
 
   /* melden, 1x pro Partei */
   if (c) {
@@ -1059,13 +1058,12 @@ static int sp_blessedharvest(castorder * co)
   region *r = co_get_region(co);
   unit *mage = co->magician.u;
   int cast_level = co->level;
-  double power = co->force;
-  int duration = (int)power + 1;
+  int duration = (int)co->force + 1;
   /* Attribut auf Region.
    * Existiert schon ein curse, so wird dieser verstaerkt
    * (Max(Dauer), Max(Staerke))*/
 
-  if (create_curse(mage, &r->attribs, ct_find("blessedharvest"), power,
+  if (create_curse(mage, &r->attribs, ct_find("blessedharvest"), co->force,
       duration, 1.0, 0)) {
     message *seen = msg_message("harvest_effect", "mage", mage);
     message *unseen = msg_message("harvest_effect", "mage", NULL);
@@ -1096,7 +1094,7 @@ static int sp_hain(castorder * co)
   region *r = co_get_region(co);
   unit *mage = co->magician.u;
   int cast_level = co->level;
-  double force = co->force;
+  float force = co->force;
 
   if (!r->land) {
     cmistake(mage, co->order, 296, MSG_MAGIC);
@@ -1142,7 +1140,7 @@ static int sp_mallornhain(castorder * co)
   region *r = co_get_region(co);
   unit *mage = co->magician.u;
   int cast_level = co->level;
-  double force = co->force;
+  float force = co->force;
 
   if (!r->land) {
     cmistake(mage, co->order, 296, MSG_MAGIC);
@@ -1176,7 +1174,7 @@ void patzer_ents(castorder * co)
   region *r = co_get_region(co);
   unit *mage = co->magician.u;
   /* int cast_level = co->level; */
-  double force = co->force;
+  float force = co->force;
 
   if (!r->land) {
     cmistake(mage, co->order, 296, MSG_MAGIC);
@@ -1338,10 +1336,10 @@ static int sp_kaelteschutz(castorder * co)
   region *r = co_get_region(co);
   unit *mage = co->magician.u;
   int cast_level = co->level;
-  double force = co->force;
+  float force = co->force;
   int duration = MAX(cast_level, (int)force) + 1;
   spellparameter *pa = co->par;
-  double effect;
+  float effect;
 
   force *= 10;                  /* 10 Personen pro Force-Punkt */
 
@@ -1363,7 +1361,7 @@ static int sp_kaelteschutz(castorder * co)
     }
 
     effect = 1;
-    create_curse(mage, &u->attribs, ct_find("insectfur"), cast_level,
+    create_curse(mage, &u->attribs, ct_find("insectfur"), (float)cast_level,
       duration, effect, men);
 
     force -= u->number;
@@ -1400,7 +1398,7 @@ static int sp_sparkle(castorder * co)
   int cast_level = co->level;
   spellparameter *pa = co->par;
   int duration = cast_level + 1;
-  double effect;
+  float effect;
 
   /* wenn kein Ziel gefunden, Zauber abbrechen */
   if (pa->param[0]->flag == TARGET_NOTFOUND)
@@ -1412,8 +1410,8 @@ static int sp_sparkle(castorder * co)
     return cast_level;
 
   u = pa->param[0]->data.u;
-  effect = rng_int() % 0xffffff;
-  create_curse(mage, &u->attribs, ct_find("sparkle"), cast_level,
+  effect = (float)(rng_int() % 0xffffff);
+  create_curse(mage, &u->attribs, ct_find("sparkle"), (float)cast_level,
     duration, effect, u->number);
 
   ADDMSG(&mage->faction->msgs, msg_message("sparkle_effect", "mage target",
@@ -1460,7 +1458,7 @@ static int sp_create_irongolem(castorder * co)
   region *r = co_get_region(co);
   unit *mage = co->magician.u;
   int cast_level = co->level;
-  double force = co->force;
+  float force = co->force;
   int number = lovar(force * 8 * RESOURCE_QUANTITY);
   if (number < 1)
     number = 1;
@@ -1585,9 +1583,9 @@ static int sp_great_drought(castorder * co)
   region *r = co_get_region(co);
   unit *mage = co->magician.u;
   int cast_level = co->level;
-  double force = co->force;
+  float force = co->force;
   int duration = 2;
-  double effect;
+  float effect;
 
   if (fval(r->terrain, SEA_REGION)) {
     cmistake(mage, co->order, 189, MSG_MAGIC);
@@ -1708,7 +1706,7 @@ static int sp_treewalkenter(castorder * co)
   region *r = co_get_region(co);
   unit *mage = co->magician.u;
   spellparameter *pa = co->par;
-  double power = co->force;
+  float power = co->force;
   int cast_level = co->level;
   region *rt;
   int remaining_cap;
@@ -1832,7 +1830,7 @@ static int sp_treewalkexit(castorder * co)
   int erfolg = 0;
   region *r = co_get_region(co);
   unit *mage = co->magician.u;
-  double power = co->force;
+  float power = co->force;
   spellparameter *pa = co->par;
   int cast_level = co->level;
 
@@ -1968,7 +1966,7 @@ static int sp_holyground(castorder * co)
   region *r = co_get_region(co);
   unit *mage = co->magician.u;
   int cast_level = co->level;
-  double power = co->force;
+  float power = co->force;
   message *msg = msg_message("sp_holyground_effect", "mage region", mage, r);
   report_spell(mage, r, msg);
   msg_release(msg);
@@ -2003,8 +2001,8 @@ static int sp_homestone(castorder * co)
   region *r = co_get_region(co);
   unit *mage = co->magician.u;
   int cast_level = co->level;
-  double force = co->force;
-  double effect;
+  float force = co->force;
+  float effect;
   message *msg;
   if (!mage->building || mage->building->type != bt_find("castle")) {
     cmistake(mage, co->order, 197, MSG_MAGIC);
@@ -2021,7 +2019,7 @@ static int sp_homestone(castorder * co)
   c_setflag(c, CURSE_NOAGE | CURSE_ONLYONE);
 
   /* Magieresistenz der Burg erhoeht sich um 50% */
-  effect = 50;
+  effect = 50.0F;
   c = create_curse(mage, &mage->building->attribs,
     ct_find("magicresistance"), force * force, 1, effect, 0);
   c_setflag(c, CURSE_NOAGE);
@@ -2062,7 +2060,7 @@ static int sp_drought(castorder * co)
   region *r = co_get_region(co);
   unit *mage = co->magician.u;
   int cast_level = co->level;
-  double power = co->force;
+  float power = co->force;
   int duration = (int)power + 1;
   message *msg;
 
@@ -2086,14 +2084,13 @@ static int sp_drought(castorder * co)
     c->vigour = MAX(c->vigour, power);
     c->duration = MAX(c->duration, (int)power);
   } else {
-    double effect;
+    float effect = 4.0;
     /* Baeume und Pferde sterben */
     rsettrees(r, 2, rtrees(r, 2) / 2);
     rsettrees(r, 1, rtrees(r, 1) / 2);
     rsettrees(r, 0, rtrees(r, 0) / 2);
     rsethorses(r, rhorses(r) / 2);
 
-    effect = 4.0;
     create_curse(mage, &r->attribs, ct_find("drought"), power, duration, effect,
       0);
   }
@@ -2183,7 +2180,7 @@ static int sp_stormwinds(castorder * co)
   int erfolg = 0;
   region *r = co_get_region(co);
   unit *mage = co->magician.u;
-  double power = co->force;
+  float power = co->force;
   spellparameter *pa = co->par;
   int n, force = (int)power;
   message *m = NULL;
@@ -2462,8 +2459,8 @@ static int sp_fumblecurse(castorder * co)
   int duration;
   unit *mage = co->magician.u;
   int cast_level = co->level;
-  double force = co->force;
-  double effect;
+  float force = co->force;
+  float effect;
   curse *c;
   spellparameter *pa = co->par;
 
@@ -2477,7 +2474,7 @@ static int sp_fumblecurse(castorder * co)
   sx = cast_level - effskill(target, SK_MAGIC);
   duration = MAX(sx, rx) + 1;
 
-  effect = force * 0.5;
+  effect = force/2;
   c = create_curse(mage, &target->attribs, ct_find("fumble"),
     force, duration, effect, 0);
   if (c == NULL) {
@@ -2495,12 +2492,12 @@ void patzer_fumblecurse(castorder * co)
 {
   unit *mage = co->magician.u;
   int cast_level = co->level;
-  double force = co->force;
+  float force = co->force;
   int duration = (cast_level / 2) + 1;
-  double effect;
+  float effect;
   curse *c;
 
-  effect = force * 0.5;
+  effect = force/2;
   c = create_curse(mage, &mage->attribs, ct_find("fumble"), force,
     duration, effect, 0);
   if (c != NULL) {
@@ -2534,7 +2531,7 @@ static int sp_summondragon(castorder * co)
   unit *mage = co->magician.u;
   unit *u;
   int cast_level = co->level;
-  double power = co->force;
+  float power = co->force;
   region_list *rl, *rl2;
   faction *f;
   int time;
@@ -2605,7 +2602,7 @@ static int sp_firewall(castorder * co)
   region *r = co_get_region(co);
   unit *mage = co->magician.u;
   int cast_level = co->level;
-  double force = co->force;
+  float force = co->force;
   spellparameter *pa = co->par;
   direction_t dir;
   region *r2;
@@ -2782,12 +2779,12 @@ static struct curse_type ct_deathcloud = {
     NULL, dc_age
 };
 
-static curse *mk_deathcloud(unit * mage, region * r, double force, int duration)
+static curse *mk_deathcloud(unit * mage, region * r, float force, int duration)
 {
-  double effect;
+  float effect;
   curse *c;
 
-  effect = force * 0.5;
+  effect = force/2;
   c =
     create_curse(mage, &r->attribs, &ct_deathcloud, force, duration, effect, 0);
   c->data.v = r;
@@ -2796,26 +2793,28 @@ static curse *mk_deathcloud(unit * mage, region * r, double force, int duration)
 
 #define COMPAT_DEATHCLOUD
 #ifdef COMPAT_DEATHCLOUD
-static int dc_read_compat(struct attrib *a, void *target, storage * store)
+static int dc_read_compat(struct attrib *a, void *target, struct storage * store)
 /* return AT_READ_OK on success, AT_READ_FAIL if attrib needs removal */
 {
   region *r = NULL;
   unit *u;
   variant var;
-  int duration = store->r_int(store);
-  double strength = store->r_flt(store);
-  short rx, ry;
+  int duration;
+  float strength;
+  int rx, ry;
 
-  var.i = store->r_id(store);
+  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: */
-  rx = (short)store->r_int(store);
-  ry = (short)store->r_int(store);
+  READ_INT(store, &rx);
+  READ_INT(store, &ry);
   r = findregion(rx, ry);
 
   if (r != NULL) {
-    double effect;
+    float effect;
     curse *c;
 
     effect = strength;
@@ -2960,7 +2959,7 @@ static int sp_summonshadow(castorder * co)
   region *r = co_get_region(co);
   unit *mage = co->magician.u;
   int cast_level = co->level;
-  double force = co->force;
+  float force = co->force;
   unit *u;
   int val, number = (int)(force * force);
 
@@ -3001,7 +3000,7 @@ static int sp_summonshadowlords(castorder * co)
   region *r = co_get_region(co);
   unit *mage = co->magician.u;
   int cast_level = co->level;
-  double force = co->force;
+  float force = co->force;
   int amount = (int)(force * force);
 
   u =
@@ -3128,8 +3127,8 @@ static int sp_magicboost(castorder * co)
   curse *c;
   unit *mage = co->magician.u;
   int cast_level = co->level;
-  double power = co->force;
-  double effect;
+  float power = co->force;
+  float effect;
   trigger *tsummon;
   static const curse_type *ct_auraboost;
   static const curse_type *ct_magicboost;
@@ -3353,7 +3352,7 @@ static int sp_analysesong_obj(castorder * co)
   region *r = co_get_region(co);
   unit *mage = co->magician.u;
   int cast_level = co->level;
-  double force = co->force;
+  float force = co->force;
   spellparameter *pa = co->par;
 
   obj = pa->param[0]->typ;
@@ -3402,7 +3401,7 @@ static int sp_analysesong_unit(castorder * co)
   unit *u;
   unit *mage = co->magician.u;
   int cast_level = co->level;
-  double force = co->force;
+  float force = co->force;
   spellparameter *pa = co->par;
 
   /* wenn kein Ziel gefunden, Zauber abbrechen */
@@ -3485,7 +3484,7 @@ static int sp_charmingsong(castorder * co)
   skill_t i;
   unit *mage = co->magician.u;
   int cast_level = co->level;
-  double force = co->force;
+  float force = co->force;
   spellparameter *pa = co->par;
   int resist_bonus = 0;
   int tb = 0;
@@ -3579,7 +3578,7 @@ static int sp_song_resistmagic(castorder * co)
   region *r = co_get_region(co);
   unit *mage = co->magician.u;
   int cast_level = co->level;
-  double force = co->force;
+  float force = co->force;
   int duration = (int)force + 1;
 
   create_curse(mage, &r->attribs, ct_find("goodmagicresistancezone"),
@@ -3608,7 +3607,7 @@ static int sp_song_susceptmagic(castorder * co)
   region *r = co_get_region(co);
   unit *mage = co->magician.u;
   int cast_level = co->level;
-  double force = co->force;
+  float force = co->force;
   int duration = (int)force + 1;
 
   create_curse(mage, &r->attribs, ct_find("badmagicresistancezone"),
@@ -3690,7 +3689,7 @@ static int sp_raisepeasantmob(castorder * co)
   region *r = co_get_region(co);
   unit *mage = co->magician.u;
   int cast_level = co->level;
-  double force = co->force;
+  float force = co->force;
   int duration = (int)force + 1;
   faction *monsters = get_monsters();
   message *msg;
@@ -3719,8 +3718,8 @@ static int sp_raisepeasantmob(castorder * co)
   a->data.ca[1] = 15;           /* 15% */
   a_add(&u->attribs, a);
 
-  create_curse(mage, &r->attribs, ct_find("riotzone"), cast_level, duration,
-    (double)anteil, 0);
+  create_curse(mage, &r->attribs, ct_find("riotzone"), (float)cast_level, duration,
+    (float)anteil, 0);
 
   msg = msg_message("sp_raisepeasantmob_effect", "mage region", mage, r);
   report_spell(mage, r, msg);
@@ -3814,7 +3813,7 @@ static int sp_song_of_peace(castorder * co)
   region *r = co_get_region(co);
   unit *mage = co->magician.u;
   int cast_level = co->level;
-  double force = co->force;
+  float force = co->force;
   int duration = 2 + lovar(force / 2);
   message *msg[2] = { NULL, NULL };
 
@@ -3862,9 +3861,9 @@ static int sp_generous(castorder * co)
   region *r = co_get_region(co);
   unit *mage = co->magician.u;
   int cast_level = co->level;
-  double force = co->force;
+  float force = co->force;
   int duration = (int)force + 1;
-  double effect;
+  float effect;
   message *msg[2] = { NULL, NULL };
 
   if (is_cursed(r->attribs, C_DEPRESSION, 0)) {
@@ -3919,7 +3918,7 @@ static int sp_recruit(castorder * co)
   double n;
   unit *mage = co->magician.u;
   int cast_level = co->level;
-  double force = co->force;
+  float force = co->force;
   faction *f = mage->faction;
   const struct race *rc = f->race;
 
@@ -3973,7 +3972,7 @@ static int sp_bigrecruit(castorder * co)
   int n, maxp = rpeasants(r);
   unit *mage = co->magician.u;
   int cast_level = co->level;
-  double force = co->force;
+  float force = co->force;
   faction *f = mage->faction;
   message *msg;
 
@@ -4094,7 +4093,7 @@ static int sp_seduce(castorder * co)
   unit *mage = co->magician.u;
   spellparameter *pa = co->par;
   int cast_level = co->level;
-  double force = co->force;
+  float force = co->force;
 
   /* wenn kein Ziel gefunden, Zauber abbrechen */
   if (pa->param[0]->flag == TARGET_NOTFOUND)
@@ -4169,8 +4168,8 @@ static int sp_calm_monster(castorder * co)
   unit *mage = co->magician.u;
   spellparameter *pa = co->par;
   int cast_level = co->level;
-  double force = co->force;
-  double effect;
+  float force = co->force;
+  float effect;
   message *msg;
 
   /* wenn kein Ziel gefunden, Zauber abbrechen */
@@ -4185,7 +4184,7 @@ static int sp_calm_monster(castorder * co)
     return 0;
   }
 
-  effect = mage->faction->subscription;
+  effect = (float)mage->faction->subscription;
   c = create_curse(mage, &target->attribs, ct_find("calmmonster"), force,
     (int)force, effect, 0);
   if (c == NULL) {
@@ -4277,7 +4276,7 @@ static int sp_raisepeasants(castorder * co)
   region *r = co_get_region(co);
   unit *mage = co->magician.u;
   int cast_level = co->level;
-  double power = co->force;
+  float power = co->force;
   message *msg;
 
   if (rpeasants(r) == 0) {
@@ -4330,7 +4329,7 @@ static int sp_depression(castorder * co)
   region *r = co_get_region(co);
   unit *mage = co->magician.u;
   int cast_level = co->level;
-  double force = co->force;
+  float force = co->force;
   int duration = (int)force + 1;
   message *msg;
 
@@ -4397,7 +4396,7 @@ int sp_icastle(castorder * co)
   region *r = co_get_region(co);
   unit *mage = co->magician.u;
   int cast_level = co->level;
-  double power = co->force;
+  float power = co->force;
   spellparameter *pa = co->par;
   icastle_data *data;
   const char *bname;
@@ -4475,7 +4474,7 @@ int sp_illusionary_shapeshift(castorder * co)
   const race *rc;
   unit *mage = co->magician.u;
   int cast_level = co->level;
-  double power = co->force;
+  float power = co->force;
   spellparameter *pa = co->par;
   const race *irace;
 
@@ -4589,10 +4588,10 @@ int sp_baddreams(castorder * co)
   int duration;
   unit *mage = co->magician.u;
   int cast_level = co->level;
-  double power = co->force;
+  float power = co->force;
   region *r = co_get_region(co);
   curse *c;
-  double effect;
+  float effect;
 
   /* wirkt erst in der Folgerunde, soll mindestens eine Runde wirken,
    * also duration+2 */
@@ -4629,8 +4628,8 @@ int sp_gooddreams(castorder * co)
   region *r = co_get_region(co);
   unit *mage = co->magician.u;
   int cast_level = co->level;
-  double power = co->force;
-  double effect;
+  float power = co->force;
+  float effect;
 
   /* wirkt erst in der Folgerunde, soll mindestens eine Runde wirken,
    * also duration+2 */
@@ -4697,7 +4696,7 @@ int sp_dreamreading(castorder * co)
   unit *mage = co->magician.u;
   int cast_level = co->level;
   spellparameter *pa = co->par;
-  double power = co->force;
+  float power = co->force;
   message *msg;
 
   /* wenn kein Ziel gefunden, Zauber abbrechen */
@@ -4748,7 +4747,7 @@ int sp_sweetdreams(castorder * co)
   region *r = co_get_region(co);
   unit *mage = co->magician.u;
   int cast_level = co->level;
-  double power = co->force;
+  float power = co->force;
   spellparameter *pa = co->par;
   int men, n;
   int duration = (int)(power / 2) + 1;
@@ -4758,7 +4757,7 @@ int sp_sweetdreams(castorder * co)
   for (n = 0; n < pa->length; n++) {
     curse *c;
     unit *u;
-    double effect;
+    float effect;
     message *msg;
     /* sollte nie negativ werden */
     if (opfer < 1)
@@ -4779,7 +4778,7 @@ int sp_sweetdreams(castorder * co)
     opfer -= men;
 
     /* Nichts machen als ein entsprechendes Attribut an die Einheit legen. */
-    effect = 0.05;
+    effect = 0.05f;
     c = create_curse(mage, &u->attribs, ct_find("orcish"), power, duration, effect, men);
 
     msg = msg_message("sp_sweetdreams_effect", "mage unit region", c->magician, u, r);
@@ -4798,9 +4797,9 @@ int sp_disturbingdreams(castorder * co)
   region *r = co_get_region(co);
   unit *mage = co->magician.u;
   int cast_level = co->level;
-  double power = co->force;
+  float power = co->force;
   int duration = 1 + (int)(power / 6);
-  double effect;
+  float effect;
   curse *c;
 
   effect = 10;
@@ -4888,7 +4887,7 @@ int sp_itemcloak(castorder * co)
   unit *mage = co->magician.u;
   spellparameter *pa = co->par;
   int cast_level = co->level;
-  double power = co->force;
+  float power = co->force;
   int duration = (int)MAX(2.0, power + 1);      /* works in the report, and ageing this round would kill it if it's <=1 */
 
   /* wenn kein Ziel gefunden, Zauber abbrechen */
@@ -4928,7 +4927,7 @@ int sp_resist_magic_bonus(castorder * co)
   int duration = 6;
   unit *mage = co->magician.u;
   int cast_level = co->level;
-  double power = co->force;
+  float power = co->force;
   spellparameter *pa = co->par;
   /* Pro Stufe koennen bis zu 5 Personen verzaubert werden */
   double maxvictims = 5;
@@ -4988,7 +4987,7 @@ int sp_enterastral(castorder * co)
   region *r = co_get_region(co);
   unit *mage = co->magician.u;
   int cast_level = co->level;
-  double power = co->force;
+  float power = co->force;
   spellparameter *pa = co->par;
 
   switch (getplaneid(r)) {
@@ -5100,7 +5099,7 @@ int sp_pullastral(castorder * co)
   region *r = co_get_region(co);
   unit *mage = co->magician.u;
   int cast_level = co->level;
-  double power = co->force;
+  float power = co->force;
   spellparameter *pa = co->par;
 
   switch (getplaneid(r)) {
@@ -5238,7 +5237,7 @@ int sp_leaveastral(castorder * co)
   region *r = co_get_region(co);
   unit *mage = co->magician.u;
   int cast_level = co->level;
-  double power = co->force;
+  float power = co->force;
   spellparameter *pa = co->par;
 
   switch (getplaneid(r)) {
@@ -5362,7 +5361,7 @@ int sp_fetchastral(castorder * co)
   unit *mage = co->magician.u;
   int cast_level = co->level;
   spellparameter *pa = co->par;
-  double power = co->force;
+  float power = co->force;
   int remaining_cap = (int)((power - 3) * 1500);
   region_list *rtl = NULL;
   region *rt = co_get_region(co);          /* region to which we are fetching */
@@ -5493,7 +5492,7 @@ int sp_showastral(castorder * co)
   region *r = co_get_region(co);
   unit *mage = co->magician.u;
   int cast_level = co->level;
-  double power = co->force;
+  float power = co->force;
 
   switch (getplaneid(r)) {
     case 0:
@@ -5624,7 +5623,7 @@ int sp_disruptastral(castorder * co)
   region *r = co_get_region(co);
   unit *mage = co->magician.u;
   int cast_level = co->level;
-  double power = co->force;
+  float power = co->force;
   int duration = (int)(power / 3) + 1;
 
   switch (getplaneid(r)) {
@@ -5649,7 +5648,7 @@ int sp_disruptastral(castorder * co)
 
   for (rl2 = rl; rl2 != NULL; rl2 = rl2->next) {
     attrib *a;
-    double effect;
+    float effect;
     region *r2 = rl2->data;
     spec_direction *sd;
     int inhab_regions = 0;
@@ -5733,7 +5732,7 @@ static int sp_eternizewall(castorder * co)
   region *r = co_get_region(co);
   unit *mage = co->magician.u;
   int cast_level = co->level;
-  double power = co->force;
+  float power = co->force;
   spellparameter *pa = co->par;
   message *msg;
 
@@ -5936,7 +5935,7 @@ int sp_flying_ship(castorder * co)
   region *r = co_get_region(co);
   unit *mage = co->magician.u;
   int cast_level = co->level;
-  double power = co->force;
+  float power = co->force;
   spellparameter *pa = co->par;
   message *m = NULL;
   int cno;
@@ -6002,7 +6001,7 @@ int sp_stealaura(castorder * co)
   unit *u;
   unit *mage = co->magician.u;
   int cast_level = co->level;
-  double power = co->force;
+  float power = co->force;
   spellparameter *pa = co->par;
 
   /* wenn kein Ziel gefunden, Zauber abbrechen */
@@ -6066,12 +6065,12 @@ int sp_stealaura(castorder * co)
  */
 int sp_antimagiczone(castorder * co)
 {
-  double power;
-  double effect;
+  float power;
+  float effect;
   region *r = co_get_region(co);
   unit *mage = co->magician.u;
   int cast_level = co->level;
-  double force = co->force;
+  float force = co->force;
   int duration = (int)force + 1;
 
   /* Haelt Sprueche bis zu einem summierten Gesamtlevel von power aus.
@@ -6080,7 +6079,7 @@ int sp_antimagiczone(castorder * co)
   power = force * 10;
 
   /* Reduziert die Staerke jedes Spruchs um effect */
-  effect = cast_level;
+  effect = (float)cast_level;
 
   create_curse(mage, &r->attribs, ct_find("antimagiczone"), power, duration,
     effect, 0);
@@ -6128,9 +6127,9 @@ static int sp_magicrunes(castorder * co)
   int duration;
   unit *mage = co->magician.u;
   int cast_level = co->level;
-  double force = co->force;
+  float force = co->force;
   spellparameter *pa = co->par;
-  double effect;
+  float effect;
 
   duration = 3 + rng_int() % cast_level;
   effect = 20;
@@ -6188,14 +6187,14 @@ int sp_speed2(castorder * co)
   unit *u;
   unit *mage = co->magician.u;
   int cast_level = co->level;
-  double force = co->force;
+  float force = co->force;
   spellparameter *pa = co->par;
 
   maxmen = 2 * cast_level * cast_level;
   dur = MAX(1, cast_level / 2);
 
   for (n = 0; n < pa->length; n++) {
-    double effect;
+    float effect;
     /* sollte nie negativ werden */
     if (maxmen < 1)
       break;
@@ -6249,7 +6248,7 @@ int sp_q_antimagie(castorder * co)
   region *r = co_get_region(co);
   unit *mage = co->magician.u;
   int cast_level = co->level;
-  double force = co->force;
+  float force = co->force;
   spellparameter *pa = co->par;
   const char *ts = NULL;
 
@@ -6328,7 +6327,7 @@ int sp_break_curse(castorder * co)
   region *r = co_get_region(co);
   unit *mage = co->magician.u;
   int cast_level = co->level;
-  double force = co->force;
+  float force = co->force;
   spellparameter *pa = co->par;
   const char *ts = NULL;
 
diff --git a/src/spells/unitcurse.c b/src/spells/unitcurse.c
index 0587661a0..b62e10627 100644
--- a/src/spells/unitcurse.c
+++ b/src/spells/unitcurse.c
@@ -31,7 +31,8 @@
 #include <util/message.h>
 #include <util/base36.h>
 #include <util/functions.h>
-#include <util/storage.h>
+
+#include <storage.h>
 
 /* libc includes */
 #include <string.h>
@@ -312,11 +313,11 @@ static struct curse_type ct_magicresistance = {
 static int read_skill(struct storage *store, curse * c, void *target)
 {
   int skill;
-  if (store->version < CURSETYPE_VERSION) {
-    skill = store->r_int(store);
-    store->r_int(store); /* men, deprecated */
+  if (global.data_version < CURSETYPE_VERSION) {
+    READ_INT(store, &skill);
+    READ_INT(store, 0); /* men, ignored */
   } else {
-    skill = store->r_int(store);
+    READ_INT(store, &skill);
   }
   c->data.i = skill;
   return 0;
@@ -325,7 +326,7 @@ static int read_skill(struct storage *store, curse * c, void *target)
 static int
 write_skill(struct storage *store, const curse * c, const void *target)
 {
-  store->w_int(store, c->data.i);
+  WRITE_INT(store, c->data.i);
   return 0;
 }
 
diff --git a/storage b/storage
new file mode 160000
index 000000000..6746f58d5
--- /dev/null
+++ b/storage
@@ -0,0 +1 @@
+Subproject commit 6746f58d52d7386391b49a512d3d42b6d2dc0678