Merge branch 'master' of github.com:ennorehling/eressea

Conflicts:
	src/kernel/save.c
This commit is contained in:
Enno Rehling 2016-08-13 19:56:48 +02:00
commit ecc2eaf999
28 changed files with 250 additions and 103 deletions

View File

@ -42,9 +42,9 @@
"nmr.removenewbie": 0,
"GiveRestriction": 3,
"hunger.long": false,
"hunger.demon.skill": true,
"hunger.damage": "1d9+9",
"hunger.demons": true,
"hunger.demons.skill": true,
"hunger.demons.peasant_tolerance": true,
"init_spells": 0,
"recruit.allow_merge": true,
"study.expensivemigrants": true,

View File

@ -42,9 +42,9 @@
"nmr.removenewbie": 0,
"GiveRestriction": 3,
"hunger.long": false,
"hunger.demon.skill": true,
"hunger.damage": "1d9+9",
"hunger.demons": true,
"hunger.demons.skill": true,
"hunger.demons.peasant_tolerance": true,
"init_spells": 0,
"recruit.allow_merge": true,
"study.expensivemigrants": true,

View File

@ -22,9 +22,9 @@
<arg name="unit" type="unit"/>
<arg name="region" type="region"/>
<arg name="command" type="order"/>
</type>
<text locale="de">"$unit($unit) in $region($region): '$order($command)' - Ungültige Zielregion."</text>
<text locale="en">"$unit($unit) in $region($region): '$order($command)' - invalid target region."</text>
</type>
</message>
<message name="missing_direction">
@ -32,9 +32,9 @@
<arg name="unit" type="unit"/>
<arg name="region" type="region"/>
<arg name="command" type="order"/>
</type>
<text locale="de">"$unit($unit) in $region($region): '$order($command)' - keine Richtung angegeben."</text>
<text locale="en">"$unit($unit) in $region($region): '$order($command)' - no direction was specified."</text>
</type>
</message>
<message name="target_region_not_empty">
@ -42,9 +42,9 @@
<arg name="unit" type="unit"/>
<arg name="region" type="region"/>
<arg name="command" type="order"/>
</type>
<text locale="de">"$unit($unit) in $region($region): '$order($command)' - In der Zielregion befinden sich noch Einheiten."</text>
<text locale="en">"$unit($unit) in $region($region): '$order($command)' - There are units in the target region."</text>
</type>
</message>
<message name="force_leave_ship" section="events">

View File

@ -39,7 +39,7 @@ local function read_players()
local str = input:read("*line")
if str==nil then break end
local email, race, lang = str:match("([^ ]*) ([^ ]*) ([^ ]*)")
if string.char(string.byte(email, 1))~='#' then
if email and string.char(string.byte(email, 1))~='#' then
table.insert(players, { race = race, lang = lang, email = email })
end
end
@ -69,12 +69,12 @@ end
function autoseed.init()
-- local newbs = {}
local num_seeded = 2
local num_seeded = per_region
local start = nil
eressea.log.info('autoseed new players')
players = read_players()
if players and #players > 0 then
if players and #players >= per_region then
local sel
eressea.log.info(#players .. ' new players')
sel = select_regions(regions(), peasants, trees)

View File

@ -3,7 +3,7 @@ eressea.log.debug("rules for game E2")
return {
require('eressea'),
require('eressea.autoseed'),
-- require('eressea.autoseed'),
require('eressea.xmas'),
require('eressea.xmasitems'),
require('eressea.wedding'),

View File

@ -674,7 +674,7 @@ function test_laen2()
process_orders()
init_reports()
write_report(u1.faction)
-- write_report(u1.faction)
assert_equal(laen - 2, r:get_resource("laen"))
assert_equal(2, u1:get_item("laen"))
end
@ -985,13 +985,21 @@ local function find_in_report(f, pattern, extension)
return start~=nil
end
local function remove_report(faction)
local filetrunk = config.reportpath .. "/" .. get_turn() .. "-" .. itoa36(faction.id)
os.remove(filetrunk .. ".nr")
os.remove(filetrunk .. ".cr")
os.remove(filetrunk .. ".txt")
end
function test_coordinates_no_plane()
local r = region.create(0, 0, "mountain")
local f = faction.create("noreply@eressea.de", "human", "de")
local f = faction.create("noplane@eressea.de", "human", "de")
local u = unit.create(f, r, 1)
init_reports()
write_report(f)
assert_true(find_in_report(f, r.name .. " %(0,0%), Berg"))
remove_report(f)
end
function test_show_shadowmaster_attacks()
@ -1005,6 +1013,7 @@ function test_show_shadowmaster_attacks()
init_reports()
write_report(f)
assert_false(find_in_report(f, ", ,"))
remove_report(f)
end
function test_coordinates_named_plane()
@ -1015,6 +1024,7 @@ function test_coordinates_named_plane()
init_reports()
write_report(f)
assert_true(find_in_report(f, r.name .. " %(0,0,Hell%), Berg"))
remove_report(f)
end
function test_coordinates_unnamed_plane()
@ -1025,6 +1035,7 @@ function test_coordinates_unnamed_plane()
init_reports()
write_report(f)
assert_true(find_in_report(f, r.name .. " %(0,0%), Berg"))
remove_report(f)
end
function test_coordinates_noname_plane()
@ -1035,6 +1046,7 @@ function test_coordinates_noname_plane()
init_reports()
write_report(f)
assert_true(find_in_report(f, r.name .. " %(0,0%), Berg"))
remove_report(f)
end
function test_lighthouse()
@ -1064,6 +1076,7 @@ function test_lighthouse()
assert_false(find_in_report(f, " %(0,0%) %(vom Turm erblickt%)"))
assert_false(find_in_report(f, " %(0,1%) %(vom Turm erblickt%)"))
assert_false(find_in_report(f, " %(4,0%) %(vom Turm erblickt%)"))
remove_report(f)
end
module("tests.parser", package.seeall, lunit.testcase)

View File

@ -965,3 +965,24 @@ function test_no_uruk()
local f1 = faction.create("noreply@eressea.de", "uruk", "de")
assert_equal(f1.race, "orc")
end
function test_bug2187()
set_rule("rules.food.flags", "0")
local r = region.create(0,0,"plain")
local f = faction.create("2187@eressea.de", "goblin", "de")
local u = unit.create(f, r, 1)
u.race = "demon"
u.hp = u.hp_max * u.number
r:set_resource("peasant", 0)
u:add_item("money", 500)
hp = u.hp
process_orders()
assert_equal(hp, u.hp)
-- init_reports()
-- write_report(f)
set_rule("rules.food.flags", "4")
end

View File

@ -75,8 +75,7 @@ faction *visible_faction(const faction * f, const unit * u)
attrib *a = a_find(u->attribs, &at_otherfaction);
if (a) {
faction *fv = get_otherfaction(a);
assert(fv != NULL); /* fv should never be NULL! */
return fv;
if (fv) return fv;
}
}
return u->faction;

View File

@ -1,3 +1,3 @@
#define VERSION_MAJOR 3
#define VERSION_MINOR 8
#define VERSION_BUILD 5
#define VERSION_BUILD 16

View File

@ -795,11 +795,9 @@ void cr_output_unit(stream *out, const region * r, const faction * f,
stream_printf(out, "%d;Verkleidung\n", sf->no);
if (fval(u, UFL_ANON_FACTION))
stream_printf(out, "%d;Parteitarnung\n", i2b(fval(u, UFL_ANON_FACTION)));
if (otherfaction) {
if (otherfaction != u->faction) {
if (otherfaction && otherfaction != u->faction) {
stream_printf(out, "%d;Anderepartei\n", otherfaction->no);
}
}
mage = get_familiar_mage(u);
if (mage) {
stream_printf(out, "%u;familiarmage\n", mage->no);
@ -819,15 +817,13 @@ void cr_output_unit(stream *out, const region * r, const faction * f,
if (sf == f) {
stream_printf(out, "1;Verraeter\n");
}
if (a_otherfaction) {
if (otherfaction != u->faction) {
if (otherfaction && otherfaction != u->faction) {
if (alliedunit(u, f, HELP_FSTEALTH)) {
stream_printf(out, "%d;Anderepartei\n", otherfaction->no);
}
}
}
}
}
if (prefix) {
prefix = mkname("prefix", prefix);
stream_printf(out, "\"%s\";typprefix\n", translate(prefix, LOC(f->locale,

View File

@ -74,9 +74,6 @@ faction *factions;
static void free_faction(faction * f)
{
funhash(f);
if (f->alliance && f->alliance->_leader == f) {
setalliance(f, 0);
}
if (f->msgs) {
free_messagelist(f->msgs->begin);
free(f->msgs);
@ -390,7 +387,7 @@ void destroyfaction(faction ** fp)
else {
region *r = u->region;
if (!fval(r->terrain, SEA_REGION) && !!playerrace(u_race(u))) {
if (r->land && !!playerrace(u_race(u))) {
const race *rc = u_race(u);
int m = rmoney(r);
@ -454,7 +451,7 @@ void destroyfaction(faction ** fp)
}
#endif
if (f->alliance && f->alliance->_leader == f) {
if (f->alliance) {
setalliance(f, 0);
}
@ -681,8 +678,6 @@ void remove_empty_factions(void)
if (!(f->_alive && f->units!=NULL) && !fval(f, FFL_NOIDLEOUT)) {
log_debug("dead: %s", factionname(f));
destroyfaction(fp);
free_faction(f);
free(f);
}
else {
fp = &(*fp)->next;

View File

@ -13,6 +13,7 @@
#include "monster.h"
#include <CuTest.h>
#include <tests.h>
#include <quicklist.h>
#include <assert.h>
#include <stdio.h>
@ -46,8 +47,10 @@ static void test_remove_empty_factions_alliance(CuTest *tc) {
al = makealliance(0, "Hodor");
setalliance(f, al);
CuAssertPtrEquals(tc, f, alliance_get_leader(al));
CuAssertIntEquals(tc, 1, ql_length(al->members));
remove_empty_factions();
CuAssertPtrEquals(tc, 0, al->_leader);
CuAssertIntEquals(tc, 0, ql_length(al->members));
test_cleanup();
}
@ -61,6 +64,9 @@ static void test_remove_empty_factions(CuTest *tc) {
f = test_create_faction(0);
fno = f->no;
remove_empty_factions();
CuAssertIntEquals(tc, false, f->_alive);
CuAssertPtrEquals(tc, fm, factions);
CuAssertPtrEquals(tc, NULL, fm->next);
CuAssertPtrEquals(tc, 0, findfaction(fno));
CuAssertPtrEquals(tc, fm, get_monsters());
test_cleanup();

View File

@ -230,7 +230,7 @@ static faction *factionorders(void)
const char *pass = gettoken(token, sizeof(token));
if (!checkpasswd(f, (const char *)pass)) {
log_debug("Invalid password for faction %s\n", itoa36(fid));
log_debug("Invalid password for faction %s", itoa36(fid));
ADDMSG(&f->msgs, msg_message("wrongpasswd", "faction password",
f->no, pass));
return 0;
@ -244,7 +244,7 @@ static faction *factionorders(void)
}
else {
log_debug("orders for invalid faction %s\n", itoa36(fid));
log_debug("orders for invalid faction %s", itoa36(fid));
}
return f;
}
@ -403,14 +403,14 @@ void read_items(struct storage *store, item ** ilist)
itype = it_find(ibuf);
READ_INT(store, &i);
if (i <= 0) {
log_error("data contains an entry with %d %s\n", i, resourcename(itype->rtype, NMF_PLURAL));
log_error("data contains an entry with %d %s", i, resourcename(itype->rtype, NMF_PLURAL));
}
else {
if (itype && itype->rtype) {
i_change(ilist, itype, i);
}
else {
log_error("data contains unknown item type %s.\n", ibuf);
log_error("data contains unknown item type %s.", ibuf);
}
assert(itype && itype->rtype);
}
@ -487,7 +487,7 @@ static int resolve_owner(variant id, void *address)
if (id.i != 0) {
f = findfaction(id.i);
if (f == NULL) {
log_error("region has an invalid owner (%s)\n", itoa36(id.i));
log_error("region has an invalid owner (%s)", itoa36(id.i));
}
}
owner->owner = f;
@ -592,13 +592,13 @@ unit *read_unit(struct gamedata *data)
READ_INT(data->store, &n);
if (n <= 0) {
log_error("data contains invalid unit %d.\n", n);
log_error("data contains invalid unit %d.", n);
assert(n > 0);
return 0;
}
u = findunit(n);
if (u) {
log_error("reading unit %s that already exists.\n", unitname(u));
log_error("reading unit %s that already exists.", unitname(u));
while (u->attribs) {
a_remove(&u->attribs, u->attribs);
}
@ -625,7 +625,7 @@ unit *read_unit(struct gamedata *data)
++u->faction->no_units;
}
else {
log_error("unit %s has faction == NULL\n", itoa36(u->no));
log_error("unit %s has faction == NULL", itoa36(u->no));
return 0;
}
@ -674,7 +674,7 @@ unit *read_unit(struct gamedata *data)
}
}
else {
log_error("read_unit: unit in unkown building '%s'\n", itoa36(n));
log_error("read_unit: unit in unkown building '%s'", itoa36(n));
}
}
@ -688,7 +688,7 @@ unit *read_unit(struct gamedata *data)
}
}
else {
log_error("read_unit: unit in unkown ship '%s'\n", itoa36(n));
log_error("read_unit: unit in unkown ship '%s'", itoa36(n));
}
}
@ -699,7 +699,7 @@ unit *read_unit(struct gamedata *data)
if ((u->flags & UFL_ANON_FACTION) && !rule_stealth_anon()) {
/* if this rule is broken, then fix broken units */
u->flags -= UFL_ANON_FACTION;
log_warning("%s was anonymous.\n", unitname(u));
log_warning("%s was anonymous.", unitname(u));
}
/* Persistente Befehle einlesen */
free_orders(&u->orders);
@ -717,11 +717,11 @@ unit *read_unit(struct gamedata *data)
ord = NULL;
}
else if (p == MAXPERSISTENT) {
log_info("%s had %d or more persistent orders\n", unitname(u), MAXPERSISTENT);
log_info("%s had %d or more persistent orders", unitname(u), MAXPERSISTENT);
}
}
else if (n == MAXORDERS) {
log_info("%s had %d or more orders\n", unitname(u), MAXORDERS);
log_info("%s had %d or more orders", unitname(u), MAXORDERS);
}
if (ord != NULL)
free_order(ord);
@ -749,7 +749,7 @@ unit *read_unit(struct gamedata *data)
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);
log_error("Einheit %s hat %u Personen, und %u Trefferpunkte", itoa36(u->no), u->number, u->hp);
u->hp = u->number;
}
@ -785,7 +785,7 @@ void write_unit(struct gamedata *data, const unit * u)
writeorder(data, ord, u->faction->locale);
}
else {
log_info("%s had %d or more persistent orders\n", unitname(u), MAXPERSISTENT);
log_info("%s had %d or more persistent orders", unitname(u), MAXPERSISTENT);
break;
}
}
@ -798,7 +798,7 @@ void write_unit(struct gamedata *data, const unit * u)
writeorder(data, ord, u->faction->locale);
}
else {
log_info("%s had %d or more persistent orders\n", unitname(u), MAXPERSISTENT);
log_info("%s had %d or more persistent orders", unitname(u), MAXPERSISTENT);
break;
}
}
@ -822,8 +822,8 @@ void write_unit(struct gamedata *data, const unit * u)
WRITE_SECTION(data->store);
write_items(data->store, u->items);
WRITE_SECTION(data->store);
if (u->hp == 0 && u_race(u) != get_race(RC_SPELL)) {
log_error("unit %s has 0 hitpoints, adjusting.\n", itoa36(u->no));
if (u->hp == 0 && u_race(u)!= get_race(RC_SPELL)) {
log_error("unit %s has 0 hitpoints, adjusting.", itoa36(u->no));
((unit *)u)->hp = u->number;
}
WRITE_INT(data->store, u->hp);
@ -874,7 +874,7 @@ static region *readregion(struct gamedata *data, int x, int y)
READ_STR(data->store, name, sizeof(name));
terrain = get_terrain(name);
if (terrain == NULL) {
log_error("Unknown terrain '%s'\n", name);
log_error("Unknown terrain '%s'", name);
assert(!"unknown terrain");
}
r->terrain = terrain;
@ -893,19 +893,19 @@ static region *readregion(struct gamedata *data, int x, int y)
READ_INT(data->store, &i);
if (i < 0) {
log_error("number of trees in %s is %d.\n", regionname(r, NULL), i);
log_error("number of trees in %s is %d.", regionname(r, NULL), i);
i = 0;
}
rsettrees(r, 0, i);
READ_INT(data->store, &i);
if (i < 0) {
log_error("number of young trees in %s is %d.\n", regionname(r, NULL), i);
log_error("number of young trees in %s is %d.", regionname(r, NULL), i);
i = 0;
}
rsettrees(r, 1, i);
READ_INT(data->store, &i);
if (i < 0) {
log_error("number of seeds in %s is %d.\n", regionname(r, NULL), i);
log_error("number of seeds in %s is %d.", regionname(r, NULL), i);
i = 0;
}
rsettrees(r, 2, i);
@ -921,7 +921,7 @@ static region *readregion(struct gamedata *data, int x, int y)
res = malloc(sizeof(rawmaterial));
res->type = rmt_find(name);
if (res->type == NULL) {
log_error("invalid resourcetype %s in data.\n", name);
log_error("invalid resourcetype %s in data.", name);
}
assert(res->type != NULL);
READ_INT(data->store, &n);
@ -1122,7 +1122,7 @@ void read_spellbook(spellbook **bookp, struct storage *store, int(*get_level)(co
if (bookp) {
sp = find_spell(spname);
if (!sp) {
log_error("read_spells: could not find spell '%s'\n", spname);
log_error("read_spells: could not find spell '%s'", spname);
}
}
if (global.data_version >= SPELLBOOK_VERSION) {
@ -1183,15 +1183,14 @@ static char * getpasswd(int fno) {
static void read_password(gamedata *data, faction *f) {
char name[128];
READ_STR(data->store, name, sizeof(name));
if (data->version == BADCRYPT_VERSION) {
if (name[0] == '$' && data->version == BADCRYPT_VERSION) {
char * pass = getpasswd(f->no);
if (pass) {
faction_setpassword(f, password_encode(pass, PASSWORD_DEFAULT));
free(pass); // TODO: remove this allocation!
}
else {
free(f->_password);
f->_password = NULL;
log_error("data version is BADCRYPT but %s not in password.txt", itoa36(f->no));
}
}
else {
@ -1273,7 +1272,7 @@ faction *readfaction(struct gamedata * data)
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);
log_warning("Invalid email address for faction %s: %s", itoa36(f->no), name);
set_email(&f->email, "");
}
@ -1290,7 +1289,7 @@ faction *readfaction(struct gamedata * data)
READ_STR(data->store, name, sizeof(name));
f->race = rc_find(name);
if (!f->race) {
log_error("unknown race in data: %s\n", name);
log_error("unknown race in data: %s", name);
}
assert(f->race);
READ_INT(data->store, &n);
@ -1457,7 +1456,7 @@ int readgame(const char *filename, bool backup)
size_t sz;
init_locales();
log_debug("- reading game data from %s\n", filename);
log_debug("- reading game data from %s", filename);
sprintf(path, "%s/%s", datapath(), filename);
if (backup) {
@ -1510,7 +1509,7 @@ int readgame(const char *filename, bool backup)
a_read(&store, &global.attribs, NULL);
READ_INT(&store, &turn);
global.data_turn = turn;
log_debug(" - reading turn %d\n", turn);
log_debug(" - reading turn %d", turn);
rng_init(turn);
READ_INT(&store, &nread); /* max_unique_id = ignore */
READ_INT(&store, &nextborder);
@ -1530,7 +1529,7 @@ int readgame(const char *filename, bool backup)
pl = calloc(1, sizeof(plane));
}
else {
log_warning("the plane with id=%d already exists.\n", id);
log_warning("the plane with id=%d already exists.", id);
}
pl->id = id;
READ_STR(&store, name, sizeof(name));
@ -1552,7 +1551,7 @@ int readgame(const char *filename, bool backup)
}
else {
log_error(
("This datafile contains watchers, but we are unable to read them\n"));
("This datafile contains watchers, but we are unable to read them."));
}
}
}
@ -1713,10 +1712,10 @@ int readgame(const char *filename, bool backup)
binstore_done(&store);
fstream_done(&strm);
/* Unaufgeloeste Zeiger initialisieren */
log_debug("fixing unresolved references.\n");
log_debug("fixing unresolved references.");
resolve();
log_debug("updating area information for lighthouses.\n");
log_debug("updating area information for lighthouses.");
for (r = regions; r; r = r->next) {
if (r->flags & RF_LIGHTHOUSE) {
building *b;
@ -1724,7 +1723,7 @@ int readgame(const char *filename, bool backup)
update_lighthouse(b);
}
}
log_debug("marking factions as alive.\n");
log_debug("marking factions as alive.");
for (f = factions; f; f = f->next) {
if (f->flags & FFL_NPC) {
f->_alive = true;
@ -1733,7 +1732,7 @@ int readgame(const char *filename, bool backup)
int no = 666;
while (findfaction(no))
++no;
log_warning("renum(monsters, %d)\n", no);
log_warning("renum(monsters, %d)", no);
renumber_faction(f, no);
}
}
@ -1745,7 +1744,7 @@ int readgame(const char *filename, bool backup)
faction *f = u->faction;
int skl = effskill(u, SK_MAGIC, 0);
if (f->magiegebiet == M_GRAY) {
log_error("faction %s had magic=gray, fixing (%s)\n", factionname(f), magic_school[mage->magietyp]);
log_error("faction %s had magic=gray, fixing (%s)", factionname(f), magic_school[mage->magietyp]);
f->magiegebiet = mage->magietyp;
}
if (f->max_spelllevel < skl) {
@ -1771,7 +1770,7 @@ int readgame(const char *filename, bool backup)
if (loadplane || maxregions >= 0) {
remove_empty_factions();
}
log_debug("Done loading turn %d.\n", turn);
log_debug("Done loading turn %d.", turn);
return 0;
}
@ -1863,7 +1862,7 @@ int writegame(const char *filename)
WRITE_INT(&store, n);
WRITE_SECTION(&store);
log_debug(" - Schreibe %d Parteien...\n", n);
log_debug(" - Schreibe %d Parteien...", n);
for (f = factions; f; f = f->next) {
if (fval(f, FFL_NPC)) {
clear_npc_orders(f);

View File

@ -231,21 +231,25 @@ static void test_read_password_external(CuTest *tc) {
CuAssertPtrNotNull(tc, f->_password);
data = gamedata_open(path, "wb");
CuAssertPtrNotNull(tc, data);
WRITE_TOK(data->store, (const char *)f->_password);
WRITE_TOK(data->store, (const char *)f->_password);
WRITE_TOK(data->store, "newpassword");
WRITE_TOK(data->store, "secret");
WRITE_TOK(data->store, "$brokenhash");
gamedata_close(data);
data = gamedata_open(path, "rb");
CuAssertPtrNotNull(tc, data);
data->version = NOCRYPT_VERSION;
_test_read_password(data, f);
CuAssertStrEquals(tc, "newpassword", f->_password);
data->version = BADCRYPT_VERSION;
_test_read_password(data, f);
CuAssertPtrEquals(tc, 0, f->_password);
CuAssertStrEquals(tc, "secret", f->_password);
F = fopen(pwfile, "wt");
fprintf(F, "%s:secret\n", itoa36(f->no));
fprintf(F, "%s:pwfile\n", itoa36(f->no));
fclose(F);
_test_read_password(data, f);
CuAssertPtrNotNull(tc, f->_password);
CuAssertStrEquals(tc, "pwfile", f->_password);
CuAssertTrue(tc, checkpasswd(f, "pwfile"));
gamedata_close(data);
CuAssertTrue(tc, checkpasswd(f, "secret"));
CuAssertIntEquals(tc, 0, remove(path));
CuAssertIntEquals(tc, 0, remove(pwfile));
}

View File

@ -334,7 +334,7 @@ int gift_items(unit * u, int flags)
item *itm = *itm_p;
if (flags & GIFT_PEASANTS) {
if (!fval(u->region->terrain, SEA_REGION)) {
if (u->region->land) {
if (itm->type->rtype == rsilver) {
rsetmoney(r, rmoney(r) + itm->number);
itm->number = 0;

View File

@ -33,10 +33,13 @@
#define SPELL_LEVEL_VERSION 348 /* f->max_spelllevel gets stored, not calculated */
#define OWNER_3_VERSION 349 /* regions store last owner, not last alliance */
#define ATTRIBOWNER_VERSION 351 /* all attrib_type functions know who owns the attribute */
#define BADCRYPT_VERSION 351 /* passwords are encrypted, poorly */
#define CRYPT_VERSION 352 /* passwords are encrypted */
#define RELEASE_VERSION ATTRIBOWNER_VERSION /* current datafile */
#define BADCRYPT_VERSION 351 /* passwords are broken, 969.dat only. */
#define NOCRYPT_VERSION 352 /* passwords are plaintext again */
/* unfinished: */
#define CRYPT_VERSION 400 /* passwords are encrypted */
#define RELEASE_VERSION NOCRYPT_VERSION /* current datafile */
#define MIN_VERSION INTPAK_VERSION /* minimal datafile we support */
#define MAX_VERSION BADCRYPT_VERSION /* change this if we can need to read the future datafile, and we can do so */
#define MAX_VERSION RELEASE_VERSION /* change this if we can need to read the future datafile, and we can do so */
#define STREAM_VERSION 2 /* internal encoding of binary files */

View File

@ -1981,6 +1981,7 @@ static int parse_messages(xmlDocPtr doc)
/* strings */
xpath->node = node;
result = xmlXPathEvalExpression(BAD_CAST "text", xpath);
assert(result->nodesetval->nodeNr>0);
for (k = 0; k != result->nodesetval->nodeNr; ++k) {
xmlNodePtr node = result->nodesetval->nodeTab[k];
struct locale *lang;

View File

@ -1221,24 +1221,29 @@ static void nmr_death(faction * f)
static void remove_idle_players(void)
{
faction **fp;
int timeout = NMRTimeout();
log_info(" - beseitige Spieler, die sich zu lange nicht mehr gemeldet haben...");
for (fp = &factions; *fp;) {
faction *f = *fp;
if (fval(f, FFL_NOIDLEOUT)) {
f->lastorders = turn;
}
if (NMRTimeout() > 0 && turn - f->lastorders >= NMRTimeout()) {
if (timeout > 0 && turn - f->lastorders >= timeout) {
nmr_death(f);
destroyfaction(fp);
} else if (turn != f->lastorders) {
} else {
if (fval(f, FFL_NOIDLEOUT)) {
f->lastorders = turn;
fp = &f->next;
}
else if (turn != f->lastorders) {
char info[256];
sprintf(info, "%d Einheiten, %d Personen, %d Silber",
f->no_units, f->num_total, f->money);
}
fp = &f->next;
}
}
log_info(" - beseitige Spieler, die sich nach der Anmeldung nicht gemeldet haben...");
age = calloc(_max(4, turn + 1), sizeof(int));

View File

@ -1299,6 +1299,46 @@ static void test_immigration(CuTest * tc)
test_cleanup();
}
static void test_demon_hunger(CuTest * tc)
{
const resource_type *rtype;
region *r;
race *rc;
faction *f;
unit *u;
message* msg;
test_cleanup();
test_create_world();
r = findregion(0, 0);
rc = test_create_race("demon");
f = test_create_faction(rc);
u = test_create_unit(f, r);
u->hp = 999;
config_set("hunger.demons.peasant_tolerance", "1");
rtype = get_resourcetype(R_SILVER);
i_change(&u->items, rtype->itype, 30);
scale_number(u, 1);
rsetpeasants(r, 0);
get_food(r);
CuAssertIntEquals(tc, 20, i_get(u->items, rtype->itype));
CuAssertPtrEquals(tc, 0, test_find_messagetype(f->msgs, "malnourish"));
config_set("hunger.demons.peasant_tolerance", "0");
get_food(r);
CuAssertIntEquals(tc, 10, i_get(u->items, rtype->itype));
msg = test_get_last_message(u->faction->msgs);
CuAssertStrEquals(tc, "malnourish", test_get_messagetype(msg));
test_cleanup();
}
CuSuite *get_laws_suite(void)
{
CuSuite *suite = CuSuiteNew();
@ -1358,6 +1398,7 @@ CuSuite *get_laws_suite(void)
SUITE_ADD_TEST(suite, test_name_ship);
SUITE_ADD_TEST(suite, test_show_without_item);
SUITE_ADD_TEST(suite, test_immigration);
SUITE_ADD_TEST(suite, test_demon_hunger);
return suite;
}

View File

@ -963,7 +963,7 @@ static void demon_skillchanges(void)
if (fval(u, UFL_HUNGER)) {
/* hungry demons only go down, never up in skill */
int rule_hunger = config_get_int("hunger.demon.skill", 0) != 0;
int rule_hunger = config_get_int("hunger.demons.skill", 0) != 0;
if (rule_hunger) {
upchance = 0;
downchance = 15;

View File

@ -89,13 +89,16 @@ int update_nmrs(void)
if (fval(f, FFL_ISNEW)) {
++newplayers;
}
else if (!fval(f, FFL_NOIDLEOUT)) {
else if (!fval(f, FFL_NOIDLEOUT|FFL_CURSED)) {
int nmr = turn - f->lastorders + 1;
if (nmr < 0 || nmr > NMRTimeout()) {
log_error("faction %s has %d NMRS\n", factionid(f), nmr);
log_error("faction %s has %d NMR", factionid(f), nmr);
nmr = _max(0, nmr);
nmr = _min(nmr, NMRTimeout());
}
if (nmr > 0) {
log_debug("faction %s has %d NMR", factionid(f), nmr);
}
++nmrs[nmr];
}
}

View File

@ -84,6 +84,7 @@ int RunAllTests(int argc, char *argv[])
ADD_SUITE(umlaut);
ADD_SUITE(unicode);
ADD_SUITE(strings);
ADD_SUITE(log);
ADD_SUITE(rng);
/* items */
ADD_SUITE(xerewards);

View File

@ -271,7 +271,7 @@ void get_food(region * r)
peasantfood = 0;
}
if (hungry > 0) {
bool demon_hunger = config_get_int("hunger.demons", 0) != 0;
bool demon_hunger = config_get_int("hunger.demons.peasant_tolerance", 0) == 0;
if (demon_hunger) {
/* demons who don't feed are hungry */
if (hunger(hungry, u))

View File

@ -8,6 +8,7 @@ attrib.test.c
strings.test.c
bsdstring.test.c
functions.test.c
log.test.c
umlaut.test.c
unicode.test.c
rng.test.c

View File

@ -35,18 +35,34 @@ typedef struct logger {
void(*log)(void *data, int level, const char *module, const char *format, va_list args);
void *data;
int flags;
int id;
struct logger *next;
} logger;
static logger *loggers;
static int log_id;
void log_create(int flags, void *data, log_fun call) {
int log_create(int flags, void *data, log_fun call) {
logger *lgr = malloc(sizeof(logger));
lgr->log = call;
lgr->flags = flags;
lgr->data = data;
lgr->next = loggers;
loggers = lgr;
return lgr->id = ++log_id;
}
void log_destroy(int id) {
logger ** lp = &loggers;
while (*lp) {
logger *lg = *lp;
if (lg->id==id) {
*lp = lg->next;
free(lg);
break;
}
lp = &lg->next;
}
}
#define MAXLENGTH 4096 /* because I am lazy, CP437 output is limited to this many chars */
@ -138,7 +154,6 @@ static void _log_write(FILE * stream, int codepage, const char *format, va_list
if (codepage) {
char buffer[MAXLENGTH];
char converted[MAXLENGTH];
vsnprintf(buffer, sizeof(buffer), format, args);
if (cp_convert(buffer, converted, MAXLENGTH, codepage) == 0) {
fputs(converted, stream);
@ -177,12 +192,16 @@ static void log_write(int flags, const char *module, const char *format, va_list
int level = flags & LOG_LEVELS;
if (lg->flags & level) {
int dupe = 0;
va_list copy;
va_copy(copy, args);
if (lg->flags & LOG_BRIEF) {
dupe = check_dupe(format, level);
}
if (dupe == 0) {
lg->log(lg->data, level, NULL, format, args);
lg->log(lg->data, level, NULL, format, copy);
}
va_end(copy);
}
}
}

View File

@ -38,7 +38,8 @@ extern "C" {
typedef void(*log_fun)(void *data, int level, const char *module, const char *format, va_list args);
void log_create(int flags, void *data, log_fun call);
int log_create(int flags, void *data, log_fun call);
void log_destroy(int id);
void log_to_file(int flags, FILE *out);
extern int log_flags;

37
src/util/log.test.c Normal file
View File

@ -0,0 +1,37 @@
#include <platform.h>
#include <CuTest.h>
#include "log.h"
#include <stdarg.h>
#include <string.h>
void log_string(void *data, int level, const char *module, const char *format, va_list args) {
char *str = (char *)data;
const char *arg = va_arg(args, const char *);
unused_arg(format);
unused_arg(module);
unused_arg(level);
strncpy(str, arg, 32);
}
static void test_logging(CuTest * tc)
{
char str1[32];
char str2[32];
int id1 = log_create(LOG_CPWARNING, str1, log_string);
int id2 = log_create(LOG_CPWARNING, str2, log_string);
CuAssertTrue(tc, id1!=id2);
log_warning("Hello %s", "World");
CuAssertStrEquals(tc, str1, "World");
CuAssertStrEquals(tc, str2, "World");
log_destroy(id1);
log_destroy(id2);
}
CuSuite *get_log_suite(void)
{
CuSuite *suite = CuSuiteNew();
SUITE_ADD_TEST(suite, test_logging);
return suite;
}

View File

@ -5,7 +5,9 @@ CD ..
SET ERESSEA=%CD%
CD %SRCDIR%
IF exist build-vs%VSVERSION% goto HAVEDIR
mkdir build-vs%VSVERSION%
:HAVEDIR
cd build-vs%VSVERSION%
"%ProgramFiles(x86)%\CMake\bin\cmake.exe" -G "Visual Studio %VSVERSION%" -DCMAKE_PREFIX_PATH="%ProgramFiles(x86)%/Lua/5.1;%ERESSEA%/dependencies-win32" -DCMAKE_MODULE_PATH="%SRCDIR%/cmake/Modules" -DCMAKE_SUPPRESS_REGENERATION=TRUE ..
PAUSE