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, "nmr.removenewbie": 0,
"GiveRestriction": 3, "GiveRestriction": 3,
"hunger.long": false, "hunger.long": false,
"hunger.demon.skill": true,
"hunger.damage": "1d9+9", "hunger.damage": "1d9+9",
"hunger.demons": true, "hunger.demons.skill": true,
"hunger.demons.peasant_tolerance": true,
"init_spells": 0, "init_spells": 0,
"recruit.allow_merge": true, "recruit.allow_merge": true,
"study.expensivemigrants": true, "study.expensivemigrants": true,

View File

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

View File

@ -22,9 +22,9 @@
<arg name="unit" type="unit"/> <arg name="unit" type="unit"/>
<arg name="region" type="region"/> <arg name="region" type="region"/>
<arg name="command" type="order"/> <arg name="command" type="order"/>
<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> </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>
</message> </message>
<message name="missing_direction"> <message name="missing_direction">
@ -32,9 +32,9 @@
<arg name="unit" type="unit"/> <arg name="unit" type="unit"/>
<arg name="region" type="region"/> <arg name="region" type="region"/>
<arg name="command" type="order"/> <arg name="command" type="order"/>
<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> </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>
</message> </message>
<message name="target_region_not_empty"> <message name="target_region_not_empty">
@ -42,9 +42,9 @@
<arg name="unit" type="unit"/> <arg name="unit" type="unit"/>
<arg name="region" type="region"/> <arg name="region" type="region"/>
<arg name="command" type="order"/> <arg name="command" type="order"/>
<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> </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>
</message> </message>
<message name="force_leave_ship" section="events"> <message name="force_leave_ship" section="events">

View File

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

View File

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

View File

@ -674,7 +674,7 @@ function test_laen2()
process_orders() process_orders()
init_reports() init_reports()
write_report(u1.faction) -- write_report(u1.faction)
assert_equal(laen - 2, r:get_resource("laen")) assert_equal(laen - 2, r:get_resource("laen"))
assert_equal(2, u1:get_item("laen")) assert_equal(2, u1:get_item("laen"))
end end
@ -985,13 +985,21 @@ local function find_in_report(f, pattern, extension)
return start~=nil return start~=nil
end 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() function test_coordinates_no_plane()
local r = region.create(0, 0, "mountain") 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) local u = unit.create(f, r, 1)
init_reports() init_reports()
write_report(f) write_report(f)
assert_true(find_in_report(f, r.name .. " %(0,0%), Berg")) assert_true(find_in_report(f, r.name .. " %(0,0%), Berg"))
remove_report(f)
end end
function test_show_shadowmaster_attacks() function test_show_shadowmaster_attacks()
@ -1005,6 +1013,7 @@ function test_show_shadowmaster_attacks()
init_reports() init_reports()
write_report(f) write_report(f)
assert_false(find_in_report(f, ", ,")) assert_false(find_in_report(f, ", ,"))
remove_report(f)
end end
function test_coordinates_named_plane() function test_coordinates_named_plane()
@ -1015,6 +1024,7 @@ function test_coordinates_named_plane()
init_reports() init_reports()
write_report(f) write_report(f)
assert_true(find_in_report(f, r.name .. " %(0,0,Hell%), Berg")) assert_true(find_in_report(f, r.name .. " %(0,0,Hell%), Berg"))
remove_report(f)
end end
function test_coordinates_unnamed_plane() function test_coordinates_unnamed_plane()
@ -1025,6 +1035,7 @@ function test_coordinates_unnamed_plane()
init_reports() init_reports()
write_report(f) write_report(f)
assert_true(find_in_report(f, r.name .. " %(0,0%), Berg")) assert_true(find_in_report(f, r.name .. " %(0,0%), Berg"))
remove_report(f)
end end
function test_coordinates_noname_plane() function test_coordinates_noname_plane()
@ -1035,6 +1046,7 @@ function test_coordinates_noname_plane()
init_reports() init_reports()
write_report(f) write_report(f)
assert_true(find_in_report(f, r.name .. " %(0,0%), Berg")) assert_true(find_in_report(f, r.name .. " %(0,0%), Berg"))
remove_report(f)
end end
function test_lighthouse() 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,0%) %(vom Turm erblickt%)"))
assert_false(find_in_report(f, " %(0,1%) %(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%)")) assert_false(find_in_report(f, " %(4,0%) %(vom Turm erblickt%)"))
remove_report(f)
end end
module("tests.parser", package.seeall, lunit.testcase) 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") local f1 = faction.create("noreply@eressea.de", "uruk", "de")
assert_equal(f1.race, "orc") assert_equal(f1.race, "orc")
end 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); attrib *a = a_find(u->attribs, &at_otherfaction);
if (a) { if (a) {
faction *fv = get_otherfaction(a); faction *fv = get_otherfaction(a);
assert(fv != NULL); /* fv should never be NULL! */ if (fv) return fv;
return fv;
} }
} }
return u->faction; return u->faction;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -33,10 +33,13 @@
#define SPELL_LEVEL_VERSION 348 /* f->max_spelllevel gets stored, not calculated */ #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 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 ATTRIBOWNER_VERSION 351 /* all attrib_type functions know who owns the attribute */
#define BADCRYPT_VERSION 351 /* passwords are encrypted, poorly */ #define BADCRYPT_VERSION 351 /* passwords are broken, 969.dat only. */
#define CRYPT_VERSION 352 /* passwords are encrypted */ #define NOCRYPT_VERSION 352 /* passwords are plaintext again */
#define RELEASE_VERSION ATTRIBOWNER_VERSION /* current datafile */ /* 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 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 */ #define STREAM_VERSION 2 /* internal encoding of binary files */

View File

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

View File

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

View File

@ -1299,6 +1299,46 @@ static void test_immigration(CuTest * tc)
test_cleanup(); 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 *get_laws_suite(void)
{ {
CuSuite *suite = CuSuiteNew(); CuSuite *suite = CuSuiteNew();
@ -1358,6 +1398,7 @@ CuSuite *get_laws_suite(void)
SUITE_ADD_TEST(suite, test_name_ship); SUITE_ADD_TEST(suite, test_name_ship);
SUITE_ADD_TEST(suite, test_show_without_item); SUITE_ADD_TEST(suite, test_show_without_item);
SUITE_ADD_TEST(suite, test_immigration); SUITE_ADD_TEST(suite, test_immigration);
SUITE_ADD_TEST(suite, test_demon_hunger);
return suite; return suite;
} }

View File

@ -963,7 +963,7 @@ static void demon_skillchanges(void)
if (fval(u, UFL_HUNGER)) { if (fval(u, UFL_HUNGER)) {
/* hungry demons only go down, never up in skill */ /* 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) { if (rule_hunger) {
upchance = 0; upchance = 0;
downchance = 15; downchance = 15;

View File

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

View File

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

View File

@ -271,7 +271,7 @@ void get_food(region * r)
peasantfood = 0; peasantfood = 0;
} }
if (hungry > 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) { if (demon_hunger) {
/* demons who don't feed are hungry */ /* demons who don't feed are hungry */
if (hunger(hungry, u)) if (hunger(hungry, u))

View File

@ -8,6 +8,7 @@ attrib.test.c
strings.test.c strings.test.c
bsdstring.test.c bsdstring.test.c
functions.test.c functions.test.c
log.test.c
umlaut.test.c umlaut.test.c
unicode.test.c unicode.test.c
rng.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(*log)(void *data, int level, const char *module, const char *format, va_list args);
void *data; void *data;
int flags; int flags;
int id;
struct logger *next; struct logger *next;
} logger; } logger;
static logger *loggers; 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)); logger *lgr = malloc(sizeof(logger));
lgr->log = call; lgr->log = call;
lgr->flags = flags; lgr->flags = flags;
lgr->data = data; lgr->data = data;
lgr->next = loggers; lgr->next = loggers;
loggers = lgr; 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 */ #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) { if (codepage) {
char buffer[MAXLENGTH]; char buffer[MAXLENGTH];
char converted[MAXLENGTH]; char converted[MAXLENGTH];
vsnprintf(buffer, sizeof(buffer), format, args); vsnprintf(buffer, sizeof(buffer), format, args);
if (cp_convert(buffer, converted, MAXLENGTH, codepage) == 0) { if (cp_convert(buffer, converted, MAXLENGTH, codepage) == 0) {
fputs(converted, stream); 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; int level = flags & LOG_LEVELS;
if (lg->flags & level) { if (lg->flags & level) {
int dupe = 0; int dupe = 0;
va_list copy;
va_copy(copy, args);
if (lg->flags & LOG_BRIEF) { if (lg->flags & LOG_BRIEF) {
dupe = check_dupe(format, level); dupe = check_dupe(format, level);
} }
if (dupe == 0) { 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); 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); void log_to_file(int flags, FILE *out);
extern int log_flags; 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% SET ERESSEA=%CD%
CD %SRCDIR% CD %SRCDIR%
IF exist build-vs%VSVERSION% goto HAVEDIR
mkdir build-vs%VSVERSION% mkdir build-vs%VSVERSION%
:HAVEDIR
cd build-vs%VSVERSION% 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 .. "%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 PAUSE