diff --git a/process/accept-orders.py b/process/accept-orders.py
index 69a6ce28f..237184861 100755
--- a/process/accept-orders.py
+++ b/process/accept-orders.py
@@ -54,7 +54,7 @@ hostname = gethostname()
orderbase = "orders.dir"
sendmail = True
# maximum number of reports per sender:
-maxfiles = 20
+maxfiles = 30
# write headers to file?
writeheaders = True
# reject all html email?
diff --git a/process/epasswd.py b/process/epasswd.py
index bdb3c4a6d..c5e1712b9 100755
--- a/process/epasswd.py
+++ b/process/epasswd.py
@@ -45,9 +45,7 @@ class EPasswd:
def load_database(self, file):
conn = sqlite3.connect(file)
c = conn.cursor()
- c.execute('SELECT MAX(turn) FROM factions')
- args = c.fetchone()
- for row in c.execute('SELECT no, email, password FROM factions WHERE turn=?', args):
+ for row in c.execute('SELECT `no`, `email`, `password` FROM `faction`'):
(no, email, passwd) = row
self.set_data(baseconvert(no, 36), email, passwd)
conn.close()
diff --git a/res/e3a/spellbooks/gray.xml b/res/e3a/spellbooks/gray.xml
index 998405b03..f3f4e496d 100644
--- a/res/e3a/spellbooks/gray.xml
+++ b/res/e3a/spellbooks/gray.xml
@@ -25,7 +25,7 @@
-
+
diff --git a/res/e3a/spellbooks/illaun.xml b/res/e3a/spellbooks/illaun.xml
index 0392842c2..8d820bf71 100644
--- a/res/e3a/spellbooks/illaun.xml
+++ b/res/e3a/spellbooks/illaun.xml
@@ -27,7 +27,7 @@
-
+
diff --git a/res/e3a/spells.xml b/res/e3a/spells.xml
index 94d7cbc08..d72386803 100644
--- a/res/e3a/spells.xml
+++ b/res/e3a/spells.xml
@@ -79,13 +79,13 @@
+
-
+ -->
diff --git a/res/eressea/spellbooks/gray.xml b/res/eressea/spellbooks/gray.xml
index 942b50237..74486f004 100644
--- a/res/eressea/spellbooks/gray.xml
+++ b/res/eressea/spellbooks/gray.xml
@@ -30,7 +30,7 @@
-
+
diff --git a/res/eressea/spellbooks/illaun.xml b/res/eressea/spellbooks/illaun.xml
index 83ffcfc27..6552a4bd8 100644
--- a/res/eressea/spellbooks/illaun.xml
+++ b/res/eressea/spellbooks/illaun.xml
@@ -20,7 +20,7 @@
-
+
diff --git a/res/eressea/spells.xml b/res/eressea/spells.xml
index 1931a4c74..a56b147ef 100644
--- a/res/eressea/spells.xml
+++ b/res/eressea/spells.xml
@@ -314,7 +314,7 @@
-
+
@@ -446,12 +446,13 @@
-
+
diff --git a/scripts/eressea/tunnels.lua b/scripts/eressea/tunnels.lua
index 4a787a373..96d482abd 100644
--- a/scripts/eressea/tunnels.lua
+++ b/scripts/eressea/tunnels.lua
@@ -16,22 +16,37 @@ local function tunnel_travelers(b)
end
local function get_target(param)
- local ntargets = table.maxn(targets)
- if ntargets==0 then
+ local ntargets = #targets
+ if ntargets == 0 then
+ eressea.log.error("Zero tunnel targets for [" .. param .. "]")
return nil
end
local rn = math.fmod(rng_int(), ntargets)
- return targets[rn]
+ local t = targets[rn + 1]
+ if not t then
+ eressea.log.error("NULL target for [" .. param .. "]" .. " at index " .. rn)
+ end
+ return t
end
local function tunnel_action(b, param)
local units = tunnel_travelers(b)
local rto = get_target(param)
+ eressea.log.info("Tunnel from " .. tostring(b) .. " [" .. param .. "]")
if rto and units then
- eressea.log.debug("Tunnel from " .. tostring(b) .. " [" .. param .. "]")
- for key, u in pairs(units) do
+ for _, u in pairs(units) do
u.region = rto
- eressea.log.debug("teleported " .. tostring(u) .. " to " .. tostring(rto))
+ eressea.log.info("teleported " .. tostring(u) .. " to " .. tostring(rto))
+ end
+ elseif not units then
+ eressea.log.info("No units in tunnel " .. tostring(b) .. " [" .. param .. "]")
+ elseif not rto then
+ eressea.log.error("No target for tunnel " .. tostring(b) .. " [" .. param .. "]")
+ end
+ -- debug code to find bugs:
+ for u in b.region.units do
+ if u.building == b then
+ eressea.log.error("Did not teleport " .. tostring(u) .. " from tunnel " .. tostring(b))
end
end
end
@@ -40,7 +55,7 @@ function tunnels.init()
local r, b
for r in regions() do
if r:get_key('tnnL') then
- targets[table.maxn(targets)+1] = r
+ table.insert(targets, r)
if (r:get_flag(0)) then
-- target region is chaotic? nope.
r:set_flag(0, false)
@@ -52,10 +67,11 @@ function tunnels.init()
end
for b in r.buildings do
if b.type == 'portal' then
- buildings[table.maxn(buildings)+1] = b
+ table.insert(buildings, b)
end
end
end
+ eressea.log.info("Found " .. #targets .. " tunnel targets")
end
function tunnels.update()
diff --git a/scripts/eressea/wedding.lua b/scripts/eressea/wedding.lua
index 71664eec9..1732392fb 100644
--- a/scripts/eressea/wedding.lua
+++ b/scripts/eressea/wedding.lua
@@ -15,7 +15,7 @@ local function wedding_travellers(b)
local units = {}
for u in b.units do
- if u:get_flag('wdgt') then
+ if u:get_key('wdgt') then
units[u] = u
end
end
diff --git a/scripts/tests/e2/init.lua b/scripts/tests/e2/init.lua
index 55feab5bf..fde840f98 100644
--- a/scripts/tests/e2/init.lua
+++ b/scripts/tests/e2/init.lua
@@ -1,9 +1,3 @@
-function dump_messages(f)
- for k, v in ipairs(f.messages) do
- print(v)
- end
-end
-
require 'tests.e2.movement'
require 'tests.e2.astral'
require 'tests.e2.spells'
diff --git a/scripts/tests/economy.lua b/scripts/tests/economy.lua
index 3379b2ab7..9c72e7e70 100644
--- a/scripts/tests/economy.lua
+++ b/scripts/tests/economy.lua
@@ -216,21 +216,3 @@ function test_sawmill()
assert_equal(6, u:get_item("log"))
assert_equal(97, r:get_resource("tree"))
end
-
-function test_ent_guards_trees()
- local r = region.create(0, 0, "plain")
- r:set_resource("tree", 100)
- local u = unit.create(faction.create("human"), r)
- u:set_skill("mining", 1)
- local guard = unit.create(get_monsters(), r, 1, "ent")
- u:set_skill("forestry", 1)
- guard:clear_orders()
- u:clear_orders()
-
- guard:add_order("BEWACHEN")
- u:add_order("MACHE HOLZ")
- process_orders()
- assert_equal(1, u:get_item("log"))
- process_orders()
- assert_equal(1, u:get_item("log"))
-end
diff --git a/src/attributes/seenspell.c b/src/attributes/seenspell.c
index e20976015..698a83076 100644
--- a/src/attributes/seenspell.c
+++ b/src/attributes/seenspell.c
@@ -54,11 +54,12 @@ static int read_seenspells(variant *var, void *owner, struct gamedata *data)
READ_TOK(store, token, sizeof(token));
while (token[0]) {
spell *sp = find_spell(token);
- if (!sp) {
- log_info("read_seenspells: could not find spell '%s'\n", token);
- return AT_READ_FAIL;
+ if (sp) {
+ selist_push(&ql, sp);
+ }
+ else {
+ log_info("read_seenspells: could not find spell '%s'\n", token);
}
- selist_push(&ql, sp);
READ_TOK(store, token, sizeof(token));
}
var->v = ql;
@@ -70,8 +71,8 @@ static bool cb_write_spell(void *data, void *more) {
storage *store = (storage *)more;
WRITE_TOK(store, sp->sname);
return true;
-
}
+
static void
write_seenspells(const variant *var, const void *owner, struct storage *store)
{
diff --git a/src/bind_unit.c b/src/bind_unit.c
index d75323f0b..c5954082b 100644
--- a/src/bind_unit.c
+++ b/src/bind_unit.c
@@ -760,7 +760,7 @@ static int tolua_unit_has_attrib(lua_State *L) {
return 1;
}
-static int tolua_unit_get_flag(lua_State * L)
+static int tolua_unit_get_key(lua_State * L)
{
unit *self = (unit *)tolua_tousertype(L, 1, 0);
const char *name = tolua_tostring(L, 2, 0);
@@ -769,7 +769,7 @@ static int tolua_unit_get_flag(lua_State * L)
return 1;
}
-static int tolua_unit_set_flag(lua_State * L)
+static int tolua_unit_set_key(lua_State * L)
{
unit *self = (unit *)tolua_tousertype(L, 1, 0);
const char *name = tolua_tostring(L, 2, 0);
@@ -784,6 +784,28 @@ static int tolua_unit_set_flag(lua_State * L)
return 0;
}
+static int tolua_unit_get_flag(lua_State * L)
+{
+ unit *self = (unit *)tolua_tousertype(L, 1, NULL);
+ int bit = (int)tolua_tonumber(L, 2, 0);
+
+ lua_pushboolean(L, (self->flags & (1 << bit)));
+ return 1;
+}
+
+static int tolua_unit_set_flag(lua_State * L)
+{
+ unit *self = (unit *)tolua_tousertype(L, 1, NULL);
+ int bit = (int)tolua_tonumber(L, 2, 0);
+ int set = tolua_toboolean(L, 3, 1);
+
+ if (set)
+ self->flags |= (1 << bit);
+ else
+ self->flags &= ~(1 << bit);
+ return 0;
+}
+
static int tolua_unit_get_weight(lua_State * L)
{
unit *self = (unit *)tolua_tousertype(L, 1, 0);
@@ -959,6 +981,8 @@ void tolua_unit_open(lua_State * L)
tolua_function(L, TOLUA_CAST "has_attrib", tolua_unit_has_attrib);
/* key-attributes for named flags: */
+ tolua_function(L, TOLUA_CAST "set_key", tolua_unit_set_key);
+ tolua_function(L, TOLUA_CAST "get_key", tolua_unit_get_key);
tolua_function(L, TOLUA_CAST "set_flag", tolua_unit_set_flag);
tolua_function(L, TOLUA_CAST "get_flag", tolua_unit_get_flag);
tolua_variable(L, TOLUA_CAST "guard", tolua_unit_get_guard,
diff --git a/src/creport.c b/src/creport.c
index 45400f241..fce3b8bff 100644
--- a/src/creport.c
+++ b/src/creport.c
@@ -100,7 +100,7 @@ struct locale *crtag_locale(void) {
static int config;
if (config_changed(&config)) {
const char *lname = config_get("creport.tags");
- lang = get_locale(lname ? lname : "de");
+ lang = lname ? get_locale(lname) : default_locale;
}
return lang;
}
@@ -108,8 +108,8 @@ struct locale *crtag_locale(void) {
static const char *crtag(const char *key)
{
const char *result;
- result = LOC(crtag_locale(), key);
- return result;
+ result = locale_string(crtag_locale(), key, false);
+ return result ? result : key;
}
/*
* translation table
@@ -848,13 +848,18 @@ void cr_output_unit(stream *out, const faction * f,
pzTmp = get_racename(u->attribs);
if (pzTmp) {
- const char *pzRace = LOC(lang, mkname("race", pzTmp));
- pzTmp = pzRace ? pzRace : pzTmp;
- stream_printf(out, "\"%s\";Typ\n", translate(pzTmp, LOC(lang, pzTmp)));
+ const char *pzRace = locale_string(lang, mkname("race", pzTmp), false);
+ if (pzRace) {
+ pzTmp = pzRace;
+ }
+ pzRace = translate(pzTmp, locale_string(lang, pzTmp, false));
+ if (!pzRace) {
+ pzRace = pzTmp;
+ }
+ stream_printf(out, "\"%s\";Typ\n", pzRace);
if (u->faction == f && fval(u_race(u), RCF_SHAPESHIFTANY)) {
pzRace = rc_name_s(u_race(u), NAME_PLURAL);
- stream_printf(out, "\"%s\";wahrerTyp\n",
- translate(pzRace, LOC(lang, pzRace)));
+ stream_printf(out, "\"%s\";wahrerTyp\n", pzRace);
}
}
else {
diff --git a/src/gamedb.c b/src/gamedb.c
index 5f53d9120..abd738ffc 100644
--- a/src/gamedb.c
+++ b/src/gamedb.c
@@ -9,9 +9,27 @@
#include "kernel/faction.h"
#include "kernel/db/driver.h"
+#include "util/strings.h"
+
+static int generate_factions(void *data, db_faction *results, int nresults)
+{
+ int i;
+ faction **iter = (faction **)data;
+ for (i = 0; *iter && i != nresults; ++i) {
+ faction *f = *iter;
+ const char *pwhash;
+ results[i].p_uid = &f->uid;
+ results[i].no = f->no;
+ results[i].email = faction_getemail(f);
+ pwhash = faction_getpassword(f);
+ str_strlcpy(results[i].pwhash, pwhash ? pwhash : "", sizeof(results[i].pwhash));
+ *iter = f->next;
+ }
+ return i;
+}
+
int gamedb_update(void)
{
- faction *f;
int err;
const char *dbname;
@@ -19,14 +37,9 @@ int gamedb_update(void)
err = db_driver_open(DB_GAME, dbname);
if (err == 0) {
- for (f = factions; f; f = f->next) {
- int uid = db_driver_faction_save(f->uid, f->no, turn,
- faction_getemail(f),
- faction_getpassword(f));
- if (uid > 0) {
- f->uid = uid;
- }
- }
+ faction *list = factions;
+ db_driver_update_factions(generate_factions, &list);
+ db_driver_compact(turn);
db_driver_close(DB_GAME);
}
return err;
diff --git a/src/kernel/database.test.c b/src/kernel/database.test.c
index c5aae1af6..975d98f7d 100644
--- a/src/kernel/database.test.c
+++ b/src/kernel/database.test.c
@@ -47,19 +47,28 @@ static void test_save_load_order(CuTest *tc) {
static void test_update_faction(CuTest *tc) {
faction *f;
- int uid;
+ int err;
+ dbrow_id id;
test_setup();
db_driver_open(DB_GAME, NULL);
f = test_create_faction(NULL);
- uid = db_driver_faction_save(f->uid, f->no, 0,
+ CuAssertIntEquals(tc, 0, f->uid);
+ id = 0;
+ err = db_driver_faction_save(&id, f->no,
faction_getemail(f),
faction_getpassword(f));
- f->uid = uid;
- uid = db_driver_faction_save(f->uid, f->no, 0,
+ CuAssertIntEquals(tc, 0, err);
+ CuAssertTrue(tc, 0 != id);
+ f->uid = (int)id;
+ db_driver_close(DB_GAME);
+
+ db_driver_open(DB_GAME, NULL);
+ err = db_driver_faction_save(&id, f->no,
faction_getemail(f),
faction_getpassword(f));
- CuAssertIntEquals(tc, f->uid, uid);
+ CuAssertIntEquals(tc, 0, err);
+ CuAssertIntEquals(tc, f->uid, id);
db_driver_close(DB_GAME);
test_teardown();
}
diff --git a/src/kernel/db/driver.h b/src/kernel/db/driver.h
index 341653991..91fcfbb27 100644
--- a/src/kernel/db/driver.h
+++ b/src/kernel/db/driver.h
@@ -1,6 +1,7 @@
#pragma once
#include
+#include
struct order_data;
@@ -17,6 +18,17 @@ int db_driver_open(database_t db, const char *dbname);
void db_driver_close(database_t db);
dbrow_id db_driver_order_save(const char *str);
struct order_data *db_driver_order_load(dbrow_id id);
-dbrow_id db_driver_faction_save(dbrow_id id, int no, int turn, const char *email, const char *password);
dbrow_id db_driver_string_save(const char *s);
const char *db_driver_string_load(dbrow_id id, size_t *size);
+void db_driver_compact(int turn);
+
+typedef struct db_faction {
+ int *p_uid;
+ int no;
+ const char *email;
+ char pwhash[128];
+} db_faction;
+
+typedef int (*db_faction_generator)(void *, db_faction *, int);
+int db_driver_update_factions(db_faction_generator gen, void *data);
+int db_driver_faction_save(dbrow_id * p_id, int no, const char *email, const char *password);
diff --git a/src/kernel/db/sqlite.c b/src/kernel/db/sqlite.c
index 29638d900..6b88ad6c5 100644
--- a/src/kernel/db/sqlite.c
+++ b/src/kernel/db/sqlite.c
@@ -3,6 +3,7 @@
#include
#include
+#include
#include "driver.h"
@@ -95,68 +96,113 @@ dbrow_id db_driver_order_save(const char *str) {
return (dbrow_id)id;
}
-
-dbrow_id db_driver_faction_save(dbrow_id id, int no, int turn, const char *email, const char *password)
+int db_driver_faction_save(dbrow_id * p_id, int no, const char *email, const char *password)
{
- sqlite3_int64 row_id;
+ dbrow_id id = *p_id;
int err;
+ char dbno[4];
+ size_t len;
+ const char *str;
+ sqlite3_stmt *stmt = (id > 0) ? g_stmt_update_faction : g_stmt_insert_faction;
assert(g_game_db);
- if (id != 0) {
- int rows;
- err = sqlite3_reset(g_stmt_update_faction);
- assert(err == SQLITE_OK);
- err = sqlite3_bind_int(g_stmt_update_faction, 1, no);
- assert(err == SQLITE_OK);
- err = sqlite3_bind_int(g_stmt_update_faction, 2, turn);
- assert(err == SQLITE_OK);
- err = sqlite3_bind_text(g_stmt_update_faction, 3, email, -1, SQLITE_STATIC);
- assert(err == SQLITE_OK);
- err = sqlite3_bind_text(g_stmt_update_faction, 4, password, -1, SQLITE_STATIC);
- assert(err == SQLITE_OK);
- err = sqlite3_bind_int(g_stmt_update_faction, 5, id);
- assert(err == SQLITE_OK);
- err = sqlite3_step(g_stmt_update_faction);
- assert(err == SQLITE_DONE);
- rows = sqlite3_changes(g_game_db);
- if (rows != 0) {
- return id;
- }
+ err = sqlite3_reset(stmt);
+ if (err != SQLITE_OK) return err;
+ str = itoa36(no);
+ len = strlen(str);
+ assert(len <= 4);
+ memcpy(dbno, str, len);
+ err = sqlite3_bind_text(stmt, 1, dbno, len, SQLITE_STATIC);
+ if (err != SQLITE_OK) return err;
+ err = sqlite3_bind_text(stmt, 2, email, -1, SQLITE_STATIC);
+ if (err != SQLITE_OK) return err;
+ err = sqlite3_bind_text(stmt, 3, password, -1, SQLITE_STATIC);
+ if (err != SQLITE_OK) return err;
+
+ if (id > 0) {
+ err = sqlite3_bind_int(stmt, 4, id);
+ if (err != SQLITE_OK) return err;
}
- err = sqlite3_reset(g_stmt_insert_faction);
- assert(err == SQLITE_OK);
- err = sqlite3_bind_int(g_stmt_insert_faction, 1, no);
- assert(err == SQLITE_OK);
- err = sqlite3_bind_int(g_stmt_insert_faction, 2, turn);
- assert(err == SQLITE_OK);
- err = sqlite3_bind_text(g_stmt_insert_faction, 3, email, -1, SQLITE_STATIC);
- assert(err == SQLITE_OK);
- err = sqlite3_bind_text(g_stmt_insert_faction, 4, password, -1, SQLITE_STATIC);
- assert(err == SQLITE_OK);
- err = sqlite3_step(g_stmt_insert_faction);
- assert(err == SQLITE_DONE);
+ err = sqlite3_step(stmt);
+ if (err != SQLITE_DONE) return err;
ERRNO_CHECK();
- row_id = sqlite3_last_insert_rowid(g_game_db);
- assert(row_id>0 && row_id <= UINT_MAX);
- return (dbrow_id)row_id;
+ if (id <= 0) {
+ sqlite3_int64 row_id;
+ row_id = sqlite3_last_insert_rowid(g_game_db);
+ assert(row_id > 0 && row_id <= UINT_MAX);
+ *p_id = (dbrow_id)row_id;
+ }
+ return SQLITE_OK;
+}
+
+int db_driver_update_factions(db_faction_generator gen, void *data)
+{
+ db_faction results[32];
+ int num, err;
+
+ err = sqlite3_exec(g_game_db, "BEGIN TRANSACTION", NULL, NULL, NULL);
+ assert(err == SQLITE_OK);
+ err = sqlite3_exec(g_game_db, "DELETE FROM `faction`", NULL, NULL, NULL);
+ if (err != SQLITE_OK) {
+ sqlite3_exec(g_game_db, "ROLLBACK", NULL, NULL, NULL);
+ return err;
+ }
+ num = gen(data, results, 32);
+ while (num > 0) {
+ int i;
+ for (i = 0; i != num; ++i) {
+ db_faction *dbf = results + i;
+ dbrow_id id = (dbrow_id)*dbf->p_uid;
+ err = db_driver_faction_save(&id, dbf->no, dbf->email, dbf->pwhash);
+ if (err != SQLITE_OK) {
+ sqlite3_exec(g_game_db, "ROLLBACK", NULL, NULL, NULL);
+ return err;
+ }
+ assert(id > 0 && id <= INT_MAX);
+ *dbf->p_uid = (int)id;
+ }
+ num = gen(data, results, 32);
+ }
+ err = sqlite3_exec(g_game_db, "COMMIT", NULL, NULL, NULL);
+ return err;
+}
+
+static int cb_int_col(void *data, int ncols, char **text, char **name) {
+ int *p_int = (int *)data;
+ *p_int = atoi(text[0]);
+ return SQLITE_OK;
}
static int db_open_game(const char *dbname) {
- int err;
+ int err, version = 0;
err = sqlite3_open(dbname, &g_game_db);
assert(err == SQLITE_OK);
- err = sqlite3_exec(g_game_db, "CREATE TABLE IF NOT EXISTS factions (id INTEGER PRIMARY KEY, no INTEGER NOT NULL, email VARCHAR(128), password VARCHAR(128), turn INTEGER NOT NULL)", NULL, NULL, NULL);
+
+ err = sqlite3_exec(g_game_db, "PRAGMA user_version", cb_int_col, &version, NULL);
assert(err == SQLITE_OK);
- err = sqlite3_prepare_v2(g_game_db, "UPDATE factions SET no=?, turn=?, email=?, password=? WHERE id=?", -1, &g_stmt_update_faction, NULL);
+ if (version < 1) {
+ /* drop deprecated table */
+ err = sqlite3_exec(g_game_db, "DROP TABLE IF EXISTS `factions`", NULL, NULL, NULL);
+ assert(err == SQLITE_OK);
+ }
+ if (version < 2) {
+ /* install schema version 2: */
+ err = sqlite3_exec(g_game_db, "CREATE TABLE IF NOT EXISTS `faction` (`id` INTEGER PRIMARY KEY, `no` CHAR(4) NOT NULL UNIQUE, `email` VARCHAR(128), `password` VARCHAR(128))", NULL, NULL, NULL);
+ assert(err == SQLITE_OK);
+ err = sqlite3_exec(g_game_db, "PRAGMA user_version = 2", NULL, NULL, NULL);
+ assert(err == SQLITE_OK);
+ }
+ /* create prepared statments: */
+ err = sqlite3_prepare_v2(g_game_db, "INSERT INTO `faction` (`no`, `email`, `password`, `id`) VALUES (?,?,?,?)", -1, &g_stmt_update_faction, NULL);
assert(err == SQLITE_OK);
- err = sqlite3_prepare_v2(g_game_db, "INSERT INTO factions (no, turn, email, password) VALUES (?,?,?,?)", -1, &g_stmt_insert_faction, NULL);
+ err = sqlite3_prepare_v2(g_game_db, "INSERT INTO `faction` (`no`, `email`, `password`) VALUES (?,?,?)", -1, &g_stmt_insert_faction, NULL);
assert(err == SQLITE_OK);
ERRNO_CHECK();
- return 0;
+ return err;
}
static int db_open_swap(const char *dbname) {
@@ -303,3 +349,13 @@ const char *db_driver_string_load(dbrow_id id, size_t *size) {
ERRNO_CHECK();
return NULL;
}
+
+void db_driver_compact(int turn)
+{
+ int err;
+
+ /* repack database: */
+ err = sqlite3_exec(g_game_db, "VACUUM", 0, 0, 0);
+ assert(err == SQLITE_OK);
+}
+
diff --git a/src/kernel/gamedata.h b/src/kernel/gamedata.h
index 587ee0a40..d4293d461 100644
--- a/src/kernel/gamedata.h
+++ b/src/kernel/gamedata.h
@@ -42,8 +42,9 @@
#define FAMILIAR_FIXMAGE_VERSION 364 /* familiar links are fixed */
#define FAMILIAR_FIXSPELLBOOK_VERSION 365 /* familiar spells are fixed */
#define FIX_STARTLEVEL_VERSION 366 /* fixing resource startlevels */
+#define FIX_CLONES_VERSION 367 /* dissolve clones */
-#define RELEASE_VERSION FIX_STARTLEVEL_VERSION /* current datafile */
+#define RELEASE_VERSION FIX_CLONES_VERSION /* current datafile */
#define MIN_VERSION UIDHASH_VERSION /* minimal datafile we support */
#define MAX_VERSION RELEASE_VERSION /* change this if we can need to read the future datafile, and we can do so */
diff --git a/src/kernel/save.c b/src/kernel/save.c
index 0b3ade593..70c75f62a 100644
--- a/src/kernel/save.c
+++ b/src/kernel/save.c
@@ -1368,6 +1368,72 @@ static void fix_fam_triggers(unit *u) {
}
}
+static void fix_clone(unit *uc) {
+ attrib * a;
+ assert(uc);
+ assert(uc->number > 0);
+ ADDMSG(&uc->faction->msgs, msg_message("dissolve_units_5",
+ "unit region number race", uc, uc->region, uc->number, u_race(uc)));
+ a_removeall(&uc->attribs, &at_clonemage);
+ a = a_new(&at_unitdissolve);
+ a->data.ca[0] = 0;
+ a->data.ca[1] = 100;
+ a_add(&uc->attribs, a);
+}
+
+static void fix_clone_mage(unit *um, const item_type *itype) {
+ i_change(&um->items, itype, 1);
+ change_maxspellpoints(um, 20);
+ a_removeall(&um->attribs, &at_clone);
+}
+
+static void fix_clones(void) {
+ const race *rc_clone = rc_find("clone");
+ const item_type *it_potion = it_find("lifepotion");
+
+ if (rc_clone && it_potion) {
+ region *r;
+ for (r = regions; r; r = r->next) {
+ unit * u;
+ for (u = r->units; u; u = u->next) {
+ if (!fval(u, UFL_MARK)) {
+ if (u_race(u) == rc_clone) {
+ attrib *a = a_find(u->attribs, &at_clonemage);
+ unit * um = NULL;
+ fset(u, UFL_MARK);
+ if (a) {
+ um = (unit *)a->data.v;
+ fset(um, UFL_MARK);
+ }
+ }
+ else {
+ attrib *a = a_find(u->attribs, &at_clone);
+ if (a) {
+ unit *uc = (unit *)a->data.v;
+ fset(u, UFL_MARK);
+ fset(uc, UFL_MARK);
+ }
+ }
+ }
+ }
+ }
+ for (r = regions; r; r = r->next) {
+ unit * u;
+ for (u = r->units; u; u = u->next) {
+ if (fval(u, UFL_MARK)) {
+ if (u_race(u) == rc_clone) {
+ fix_clone(u);
+ }
+ else {
+ fix_clone_mage(u, it_potion);
+ }
+ freset(u, UFL_MARK);
+ }
+ }
+ }
+ }
+}
+
static void fix_familiars(void (*callback)(unit *)) {
region *r;
for (r = regions; r; r = r->next) {
@@ -1559,7 +1625,9 @@ int read_game(gamedata *data)
}
}
}
-
+ if (data->version < FIX_CLONES_VERSION) {
+ fix_clones();
+ }
if (data->version < FAMILIAR_FIX_VERSION) {
fix_familiars(fix_fam_triggers);
}
diff --git a/src/laws.c b/src/laws.c
index f7eba8c97..fda3f434f 100644
--- a/src/laws.c
+++ b/src/laws.c
@@ -1488,7 +1488,7 @@ int display_cmd(unit * u, struct order *ord)
{
char token[128];
char **s = NULL;
- const char *str;
+ char *str;
region *r = u->region;
init_order_depr(ord);
@@ -1525,11 +1525,19 @@ int display_cmd(unit * u, struct order *ord)
break;
case P_UNIT:
- unit_setinfo(u, getstrtoken());
+ str = getstrtoken();
+ if (str) {
+ unicode_utf8_trim(str);
+ }
+ unit_setinfo(u, str);
break;
case P_PRIVAT:
- usetprivate(u, getstrtoken());
+ str = getstrtoken();
+ if (str) {
+ unicode_utf8_trim(str);
+ }
+ usetprivate(u, str);
break;
case P_REGION:
@@ -1664,7 +1672,7 @@ int name_cmd(struct unit *u, struct order *ord)
bool foreign = false;
const char *str;
- init_order_depr(ord);
+ init_order(ord, u->faction->locale);
str = gettoken(token, sizeof(token));
p = findparam_ex(str, u->faction->locale);
diff --git a/src/laws.test.c b/src/laws.test.c
index 0896b54f3..cead8605a 100644
--- a/src/laws.test.c
+++ b/src/laws.test.c
@@ -221,6 +221,21 @@ static void test_display_cmd(CuTest *tc) {
CuAssertStrEquals(tc, "Hodor", unit_getinfo(u));
free_order(ord);
+ ord = create_order(K_DISPLAY, f->locale, "%s ' Klabautermann '", LOC(f->locale, parameters[P_UNIT]));
+ CuAssertIntEquals(tc, 0, display_cmd(u, ord));
+ CuAssertStrEquals(tc, "Klabautermann", unit_getinfo(u));
+ free_order(ord);
+
+ ord = create_order(K_DISPLAY, f->locale, "%s Hodor", LOC(f->locale, parameters[P_PRIVAT]));
+ CuAssertIntEquals(tc, 0, display_cmd(u, ord));
+ CuAssertStrEquals(tc, "Hodor", uprivate(u));
+ free_order(ord);
+
+ ord = create_order(K_DISPLAY, f->locale, "%s ' Klabautermann '", LOC(f->locale, parameters[P_PRIVAT]));
+ CuAssertIntEquals(tc, 0, display_cmd(u, ord));
+ CuAssertStrEquals(tc, "Klabautermann", uprivate(u));
+ free_order(ord);
+
ord = create_order(K_DISPLAY, f->locale, LOC(f->locale, parameters[P_UNIT]));
CuAssertIntEquals(tc, 0, display_cmd(u, ord));
CuAssertPtrEquals(tc, NULL, (void *)unit_getinfo(u));
@@ -940,6 +955,12 @@ static void test_name_unit(CuTest *tc) {
u = setup_name_cmd();
f = u->faction;
+
+ ord = create_order(K_NAME, f->locale, "%s ' Klabauterfrau '", LOC(f->locale, parameters[P_UNIT]));
+ name_cmd(u, ord);
+ CuAssertStrEquals(tc, "Klabauterfrau", u->_name);
+ free_order(ord);
+
ord = create_order(K_NAME, f->locale, "%s Hodor", LOC(f->locale, parameters[P_UNIT]));
name_cmd(u, ord);
CuAssertStrEquals(tc, "Hodor", u->_name);
@@ -960,10 +981,15 @@ static void test_name_region(CuTest *tc) {
order *ord;
u = setup_name_cmd();
+ u_set_building(u, test_create_building(u->region, NULL));
f = u->faction;
+ ord = create_order(K_NAME, f->locale, "%s ' Hodor Hodor '", LOC(f->locale, parameters[P_REGION]));
+ name_cmd(u, ord);
+ CuAssertStrEquals(tc, "Hodor Hodor", u->region->land->name);
+ free_order(ord);
+
ord = create_order(K_NAME, f->locale, "%s Hodor", LOC(f->locale, parameters[P_REGION]));
- u_set_building(u, test_create_building(u->region, NULL));
name_cmd(u, ord);
CuAssertStrEquals(tc, "Hodor", u->region->land->name);
free_order(ord);
@@ -980,6 +1006,7 @@ static void test_name_region(CuTest *tc) {
static void test_name_building(CuTest *tc) {
unit *uo, *u, *ux;
faction *f;
+ order *ord;
u = setup_name_cmd();
u->building = test_create_building(u->region, NULL);
@@ -989,29 +1016,33 @@ static void test_name_building(CuTest *tc) {
ux = test_create_unit(f, test_create_region(0, 0, NULL));
u_set_building(ux, u->building);
- u->thisorder = create_order(K_NAME, f->locale, "%s Hodor", LOC(f->locale, parameters[P_BUILDING]));
-
+ ord = create_order(K_NAME, f->locale, "%s ' Hodor Hodor '", LOC(f->locale, parameters[P_BUILDING]));
building_set_owner(uo);
- name_cmd(u, u->thisorder);
+ name_cmd(u, ord);
CuAssertPtrNotNull(tc, test_find_messagetype(f->msgs, "error148"));
test_clear_messages(f);
-
building_set_owner(u);
- name_cmd(u, u->thisorder);
+ name_cmd(u, ord);
+ CuAssertStrEquals(tc, "Hodor Hodor", u->building->name);
+ free_order(ord);
+
+ ord = create_order(K_NAME, f->locale, "%s Hodor", LOC(f->locale, parameters[P_BUILDING]));
+ name_cmd(u, ord);
CuAssertStrEquals(tc, "Hodor", u->building->name);
building_setname(u->building, "Home");
building_set_owner(ux);
- name_cmd(u, u->thisorder);
+ name_cmd(u, ord);
CuAssertPtrEquals(tc, NULL, test_find_messagetype(f->msgs, "error148"));
CuAssertStrEquals(tc, "Hodor", u->building->name);
-
test_clear_messages(f);
- free_order(u->thisorder);
- u->thisorder = create_order(K_NAME, f->locale, LOC(f->locale, parameters[P_BUILDING]));
- name_cmd(u, u->thisorder);
+ free_order(ord);
+
+ ord = create_order(K_NAME, f->locale, LOC(f->locale, parameters[P_BUILDING]));
+ name_cmd(u, ord);
CuAssertPtrNotNull(tc, test_find_messagetype(f->msgs, "error84"));
CuAssertStrEquals(tc, "Hodor", u->building->name);
+ free_order(ord);
/* TODO: test BTF_NAMECHANGE:
btype->flags |= BTF_NAMECHANGE;
diff --git a/src/magic.c b/src/magic.c
index d7b57f24d..fdd74d55e 100644
--- a/src/magic.c
+++ b/src/magic.c
@@ -2237,7 +2237,7 @@ static void equip_familiar(unit *fam) {
snprintf(eqname, sizeof(eqname), "fam_%s", rc->_name);
if (!equip_unit(fam, eqname)) {
- log_info("could not perform initialization for familiar %s.\n", rc->_name);
+ log_debug("could not perform initialization for familiar %s.\n", rc->_name);
}
}
diff --git a/src/main.c b/src/main.c
index 6b80c0cb0..4216d3046 100644
--- a/src/main.c
+++ b/src/main.c
@@ -53,7 +53,7 @@ static const char *logfile = "eressea.log";
static const char *luafile = 0;
static const char *inifile = "eressea.ini";
static int memdebug = 0;
-static int verbosity = 1;
+static int verbosity = 2;
static void load_inifile(void)
{
@@ -183,7 +183,7 @@ static int verbosity_to_flags(int verbosity) {
static int parse_args(int argc, char **argv)
{
int i;
- int log_stderr, log_flags = 2;
+ int log_stderr, log_flags = 3;
for (i = 1; i != argc; ++i) {
char *argi = argv[i];
diff --git a/src/monsters.c b/src/monsters.c
index 290cbdb87..535e03166 100644
--- a/src/monsters.c
+++ b/src/monsters.c
@@ -442,7 +442,7 @@ static order *monster_move(region * r, unit * u)
if (fval(u_race(u), RCF_DRAGON)) {
d = richest_neighbour(r, u->faction, 1);
}
- else if (get_race(RC_TREEMAN)==u_race(u)) {
+ else if (get_race(RC_TREEMAN) == u_race(u)) {
d = treeman_neighbour(r);
}
else {
diff --git a/src/races/dragons.c b/src/races/dragons.c
index 5ab877c40..872893b64 100644
--- a/src/races/dragons.c
+++ b/src/races/dragons.c
@@ -32,9 +32,9 @@ static int age_chance(int a, int b, int p) {
static void evolve_dragon(unit * u, const struct race *rc) {
scale_number(u, 1);
+ u->hp = unit_max_hp(u);
u_setrace(u, rc);
u->irace = NULL;
- u->hp = unit_max_hp(u);
}
void age_firedragon(unit * u)
diff --git a/src/report.c b/src/report.c
index 961f5227e..61cb915b8 100644
--- a/src/report.c
+++ b/src/report.c
@@ -1607,7 +1607,6 @@ static void allies(struct stream *out, const faction * f)
}
g = g->next;
}
- rpline(out);
}
static void guards(struct stream *out, const region * r, const faction * see)
@@ -1703,8 +1702,6 @@ static void list_address(struct stream *out, const faction * uf, selist * seenfa
}
selist_advance(&flist, &qi, 1);
}
- newline(out);
- rpline(out);
}
static void
@@ -2130,9 +2127,10 @@ report_plaintext(const char *filename, report_context * ctx,
continue;
/* Beschreibung */
+ rpline(out);
+ newline(out);
if (r->seen.mode >= seen_unit) {
anyunits = 1;
- newline(out);
report_region(out, r, f);
if (markets_module() && r->land) {
const item_type *lux = r_luxury(r);
@@ -2169,20 +2167,21 @@ report_plaintext(const char *filename, report_context * ctx,
newline(out);
report_travelthru(out, r, f);
}
- newline(out);
if (wants_stats && r->seen.mode >= seen_travel) {
if (r->land || r->seen.mode >= seen_unit) {
- statistics(out, r, f);
newline(out);
+ statistics(out, r, f);
}
}
/* Nachrichten an REGION in der Region */
if (r->seen.mode >= seen_travel) {
message_list *mlist = r_getmessages(r, f);
+ newline(out);
if (mlist) {
struct mlist **split = merge_messages(mlist, r->msgs);
+ newline(out);
rp_messages(out, mlist, f, 0, false);
split_messages(mlist, split);
}
@@ -2236,7 +2235,6 @@ report_plaintext(const char *filename, report_context * ctx,
assert(!u);
newline(out);
- rpline(out);
ERRNO_CHECK();
}
if (!is_monsters(f)) {
diff --git a/src/reports.c b/src/reports.c
index 4b950b73b..306fe0e10 100644
--- a/src/reports.c
+++ b/src/reports.c
@@ -713,7 +713,7 @@ void bufunit(const faction * f, const unit * u, const faction *fv,
pzTmp = get_racename(u->attribs);
if (pzTmp) {
- const char *name = LOC(lang, mkname("race", pzTmp));
+ const char *name = locale_string(lang, mkname("race", pzTmp), false);
sbs_strcat(sbp, name ? name : pzTmp);
if (u->faction == f && fval(u_race(u), RCF_SHAPESHIFTANY)) {
sbs_strcat(sbp, " (");
diff --git a/src/spells/combatspells.c b/src/spells/combatspells.c
index 2eae5dc6a..e8a1be274 100644
--- a/src/spells/combatspells.c
+++ b/src/spells/combatspells.c
@@ -62,7 +62,7 @@ static const char *spell_damage(int sp)
{
switch (sp) {
case 0:
- /* meist toetlich 20-65 HP */
+ /* meist toedlich 20-65 HP */
return "5d10+15";
case 1:
/* sehr variabel 4-48 HP */
@@ -71,7 +71,7 @@ static const char *spell_damage(int sp)
/* leicht verwundet 4-18 HP */
return "2d8+2";
case 3:
- /* fast immer toetlich 30-50 HP */
+ /* fast immer toedlich 30-50 HP */
return "5d5+25";
case 4:
/* verwundet 11-26 HP */
diff --git a/src/util/parser.c b/src/util/parser.c
index 3d1ba250d..bd187b5f8 100644
--- a/src/util/parser.c
+++ b/src/util/parser.c
@@ -233,12 +233,12 @@ const char *parse_token_depr(const char **str)
return parse_token(str, pbuf, MAXTOKENSIZE);
}
-const char *getstrtoken(void)
+char *getstrtoken(void)
{
return parse_token((const char **)&states->current_token, pbuf, MAXTOKENSIZE);
}
-const char *gettoken(char *lbuf, size_t bufsize)
+char *gettoken(char *lbuf, size_t bufsize)
{
return parse_token((const char **)&states->current_token, lbuf, bufsize);
}
diff --git a/src/util/parser.h b/src/util/parser.h
index a540aa2ac..329d6f654 100644
--- a/src/util/parser.h
+++ b/src/util/parser.h
@@ -26,8 +26,8 @@ extern "C" {
void parser_pushstate(void);
void parser_popstate(void);
bool parser_end(void);
- const char *getstrtoken(void);
- const char *gettoken(char *lbuf, size_t bufsize);
+ char *getstrtoken(void);
+ char *gettoken(char *lbuf, size_t bufsize);
int getuint(void);
int getint(void);
int getid(void);
diff --git a/src/util/unicode.c b/src/util/unicode.c
index 90b63205d..b4bb803dd 100644
--- a/src/util/unicode.c
+++ b/src/util/unicode.c
@@ -11,6 +11,7 @@
#include
#include "unicode.h"
+#include
#include
#include
#include
@@ -36,6 +37,7 @@ int unicode_utf8_trim(utf8_t *buf)
{
int result = 0, ts = 0;
utf8_t *op = buf, *ip = buf, *lc = buf;
+ assert(buf);
while (*ip) {
size_t size = 1;
wint_t wc = *ip;
diff --git a/tests/runtests.bat b/tests/runtests.bat
index 88afc8d31..e73580851 100644
--- a/tests/runtests.bat
+++ b/tests/runtests.bat
@@ -7,9 +7,9 @@ IF EXIST ..\build-vs15 SET BUILD=..\build-vs15\eressea\Debug
SET SERVER=%BUILD%\eressea.exe
%BUILD%\test_eressea.exe
-%SERVER% ..\scripts\run-tests.lua
-%SERVER% -re2 ..\scripts\run-tests-e2.lua
-%SERVER% -re3 ..\scripts\run-tests-e3.lua
+%SERVER% -v1 ..\scripts\run-tests.lua
+%SERVER% -v1 -re2 ..\scripts\run-tests-e2.lua
+%SERVER% -v1 -re3 ..\scripts\run-tests-e3.lua
%SERVER% --version
PAUSE
RMDIR /s /q reports
diff --git a/vs2017-build.bat b/vs2017-build.bat
index 22e153874..b79a81e85 100644
--- a/vs2017-build.bat
+++ b/vs2017-build.bat
@@ -12,5 +12,8 @@ IF exist build-vs%VSVERSION% goto HAVEDIR
mkdir build-vs%VSVERSION%
:HAVEDIR
cd build-vs%VSVERSION%
+IF NOT EXIST CMakeCache.txt GOTO NOCACHE
+DEL CMakeCache.txt
+:NOCACHE
"%CMAKE_ROOT%\bin\cmake.exe" -G "Visual Studio %VSVERSION%" -DCMAKE_PREFIX_PATH="%LUA_DEV%;%WIN32_DEV%" -DCMAKE_MODULE_PATH="%SRCDIR%/cmake/Modules" -DCMAKE_SUPPRESS_REGENERATION=TRUE ..
PAUSE