Merge branch 'develop' of github.com:ennorehling/eressea into develop

This commit is contained in:
Enno Rehling 2018-12-12 09:12:22 +01:00
commit 54579c95aa
84 changed files with 803 additions and 780 deletions

View file

@ -9,6 +9,11 @@ if len(sys.argv)<4:
filename=sys.argv[1] filename=sys.argv[1]
myfaction=sys.argv[2] myfaction=sys.argv[2]
mypasswd=sys.argv[3] mypasswd=sys.argv[3]
quiet=len(sys.argv)<=4
def log(str):
if not quiet:
print(str)
if mypasswd[0] == '"': if mypasswd[0] == '"':
mypasswd = mypasswd.strip('"') mypasswd = mypasswd.strip('"')
@ -16,10 +21,17 @@ if mypasswd[0] == '"':
pw_data = EPasswd() pw_data = EPasswd()
try: try:
pw_data.load_database(filename) pw_data.load_database(filename)
log("loaded from db " + filename)
except: except:
pw_data.load_file(filename) pw_data.load_file(filename)
log("loaded from file " + filename)
if pw_data.fac_exists(myfaction): if pw_data.fac_exists(myfaction):
if pw_data.check(myfaction, mypasswd): if pw_data.check(myfaction, mypasswd):
log("password match: " + myfaction)
sys.exit(0) sys.exit(0)
log("password mismatch: " + myfaction)
else:
log("faction missing: " + myfaction)
sys.exit(-1) sys.exit(-1)

View file

@ -19,7 +19,7 @@ fi
rm -f "orders.$TURN" rm -f "orders.$TURN"
find "orders.dir.$TURN" -maxdepth 1 -type f -printf "%T+\t%p\n" | sort | cut -f2 | while read -r find "orders.dir.$TURN" -maxdepth 1 -type f -printf "%T+\t%p\n" | sort | cut -f2 | while read -r
do do
cat "$REPLY" >> "orders.$TURN" tr -d '\r' < "$REPLY" >> "orders.$TURN"
done done
lockfile -r3 -l120 orders.queue.lock lockfile -r3 -l120 orders.queue.lock

View file

@ -69,7 +69,7 @@ class EPasswd:
def check(self, id, passwd): def check(self, id, passwd):
pw = self.get_passwd(id) pw = self.get_passwd(id)
if pw[0:4]=='$2a$' or pw[0:4]=='$2y$': if pw[0:4]=='$2a$' or pw[0:4]=='$2y$':
return bcrypt.checkpw(passwd, pw) return bcrypt.checkpw(passwd.encode('utf8'), pw.encode('utf8'))
return pw == passwd return pw == passwd
def get_passwd(self, id): def get_passwd(self, id):

View file

@ -52,6 +52,9 @@ messages = {
"validate-en": "Validating", "validate-en": "Validating",
"validate-de": "Verarbeite", "validate-de": "Verarbeite",
"noorders-en": "The email contained no recognizable orders.",
"noorders-de": "Es konnten keine Befehle gefunden werden.",
"faction-en": "Faction", "faction-en": "Faction",
"faction-de": "Partei", "faction-de": "Partei",
@ -183,6 +186,8 @@ for line in lines:
logfile = open(os.path.join(game_dir, "zug.log"), "a") logfile = open(os.path.join(game_dir, "zug.log"), "a")
dirname, filename = split_filename(infile) dirname, filename = split_filename(infile)
msg = messages["validate-"+locale] + " " + infile + "\n\n" msg = messages["validate-"+locale] + " " + infile + "\n\n"
if len(results)==0:
msg = msg + messages["noorders-"+locale]
for faction, game_email, success, pwd in results: for faction, game_email, success, pwd in results:
msg = msg + messages["faction-"+locale] + " " + faction + "\n" msg = msg + messages["faction-"+locale] + " " + faction + "\n"
if success: failed = False if success: failed = False

View file

@ -2331,7 +2331,7 @@ msgid "curseinfo::magicboost"
msgstr "Der Magier besitzt die Gabe des Chaos. ($int36($id))" msgstr "Der Magier besitzt die Gabe des Chaos. ($int36($id))"
msgid "illegal_password" msgid "illegal_password"
msgstr "\"Dein Passwort enthält Zeichen, die bei der Nachsendung von Reports Probleme bereiten können. Bitte beachte, dass Passwortenur aus Buchstaben von A bis Z und Zahlen bestehen dürfen. Dein neues Passwort ist '${newpass}'.\"" msgstr "\"Das Passwort enthielt Zeichen, die bei der Nachsendung von Reports Probleme bereiten können. Bitte beachte, dass Passworte nur aus Ziffern und Buchstaben von A bis Z bestehen dürfen. Dein neues Passwort ist '${newpass}'.\""
msgid "curseinfo::sparkle_12" msgid "curseinfo::sparkle_12"
msgstr "\"Leuchtende Blumen erblühen rund um das Lager von $unit($unit). ($int36($id))\"" msgstr "\"Leuchtende Blumen erblühen rund um das Lager von $unit($unit). ($int36($id))\""
@ -2429,6 +2429,9 @@ msgstr "\"$unit($unit) konnte nur $int($ships) von $int($maxships) Schiffen verz
msgid "error283" msgid "error283"
msgstr "\"$unit($unit) in $region($region): '$order($command)' - Das Passwort darf nur Buchstaben und Ziffern enthalten.\"" msgstr "\"$unit($unit) in $region($region): '$order($command)' - Das Passwort darf nur Buchstaben und Ziffern enthalten.\""
msgid "error321"
msgstr "\"$unit($unit) in $region($region): '$order($command)' - Das gewählte Passwort war zu lang.\""
msgid "rust_effect" msgid "rust_effect"
msgstr "\"$unit($mage) legt einen Rosthauch auf $unit($target). $int($amount) Waffen wurden vom Rost zerfressen.\"" msgstr "\"$unit($mage) legt einen Rosthauch auf $unit($target). $int($amount) Waffen wurden vom Rost zerfressen.\""

View file

@ -2426,6 +2426,9 @@ msgstr "\"$unit($unit) in $region($region): '$order($command)' - No luxury items
msgid "stormwinds_reduced" msgid "stormwinds_reduced"
msgstr "\"$unit($unit) could only enchant $int($ships) of $int($maxships) ships.\"" msgstr "\"$unit($unit) could only enchant $int($ships) of $int($maxships) ships.\""
msgid "error321"
msgstr "\"$unit($unit) in $region($region): '$order($command)' - The chosen password was too long.\""
msgid "error283" msgid "error283"
msgstr "\"$unit($unit) in $region($region): '$order($command)' - Your password may only contain alphanumeric symbols.\"" msgstr "\"$unit($unit) in $region($region): '$order($command)' - Your password may only contain alphanumeric symbols.\""

View file

@ -1,8 +1,8 @@
#!/bin/sh #!/bin/sh
IGNORE=$(find src -name "*.test.c" | awk '{ print "-i"$1 }') IGNORE=$(find src -name "*.test.c" | awk '{ print "-i"$1 }')
cppcheck $IGNORE -isrc/tests.c \ #cppcheck $IGNORE -isrc/tests.c \
--quiet --enable=all -U_MSC_VER -UCLEANUP_CODE -UTODO \ cppcheck --quiet --enable=warning,style,performance,portability -U_MSC_VER -UCLEANUP_CODE -UTODO \
-UERESSEA_BUILDNO -UERESSEA_VERSION \ -UERESSEA_BUILDNO -UERESSEA_VERSION -UTEST_THREADS \
-IcJSON -Isrc -Iclibs -Istorage src -IcJSON -Isrc -Iclibs -Istorage src

View file

@ -28,9 +28,10 @@ function test_undead_reserve_other()
u1.race = "undead" u1.race = "undead"
u1:clear_orders() u1:clear_orders()
u1:add_order("RESERVIERE 1 Holz") u1:add_order("RESERVIERE 1 Holz")
u1.name = 'Xolgrim'
process_orders() process_orders()
-- Intermittent Failure (clang): expected 0 but was 2 -- Intermittent Failure: expected 0 but was 2
assert_equal(0, u1:get_item("log")) assert_equal(0, u1:get_item("log"))
assert_equal(2, u2:get_item("log")) assert_equal(2, u2:get_item("log"))

View file

@ -121,7 +121,7 @@ static int read_keyval_orig(gamedata *data, int *keys, int n) {
#endif #endif
static int a_readkeys(variant *var, void *owner, gamedata *data) { static int a_readkeys(variant *var, void *owner, gamedata *data) {
int i, n, ksn, *keys; int n, ksn, *keys;
READ_INT(data->store, &n); READ_INT(data->store, &n);
assert(n < 4096 && n >= 0); assert(n < 4096 && n >= 0);
@ -155,7 +155,7 @@ static int a_readkeys(variant *var, void *owner, gamedata *data) {
} }
keys[0] = n; keys[0] = n;
if (data->version < SORTKEYS_VERSION) { if (data->version < SORTKEYS_VERSION) {
int e = 1; int i, e = 1;
for (i = 1; i != n; ++i) { for (i = 1; i != n; ++i) {
int k = keys[i * 2 + 1]; int k = keys[i * 2 + 1];
int v = keys[i * 2 + 2]; int v = keys[i * 2 + 2];
@ -260,6 +260,7 @@ static int *keys_update(int *base, int key, int val)
ptrdiff_t diff = kv - base; ptrdiff_t diff = kv - base;
sz = keys_size(n + 1); sz = keys_size(n + 1);
base = realloc(base, (sz * 2 + 1) * sizeof(int)); base = realloc(base, (sz * 2 + 1) * sizeof(int));
if (!base) abort();
kv = base + diff; kv = base + diff;
} }
base[0] = n + 1; base[0] = n + 1;

View file

@ -48,13 +48,12 @@ static int read_seenspells(variant *var, void *owner, struct gamedata *data)
{ {
selist *ql = NULL; selist *ql = NULL;
storage *store = data->store; storage *store = data->store;
spell *sp = 0;
char token[32]; char token[32];
UNUSED_ARG(owner); UNUSED_ARG(owner);
READ_TOK(store, token, sizeof(token)); READ_TOK(store, token, sizeof(token));
while (token[0]) { while (token[0]) {
sp = find_spell(token); spell *sp = find_spell(token);
if (!sp) { if (!sp) {
log_info("read_seenspells: could not find spell '%s'\n", token); log_info("read_seenspells: could not find spell '%s'\n", token);
return AT_READ_FAIL; return AT_READ_FAIL;

View file

@ -46,7 +46,7 @@ int autostudy_init(scholar scholars[], int max_scholars, unit **units)
st->level = effskill_study(u, st->sk); st->level = effskill_study(u, st->sk);
st->learn = 0; st->learn = 0;
st->u = u; st->u = u;
if (++nscholars == max_scholars) { if (++nscholars > max_scholars) {
log_fatal("you must increase MAXSCHOLARS"); log_fatal("you must increase MAXSCHOLARS");
} }
} }
@ -59,7 +59,6 @@ int autostudy_init(scholar scholars[], int max_scholars, unit **units)
u = u->next; u = u->next;
} }
*units = unext; *units = unext;
scholars[nscholars].u = NULL;
if (nscholars > 0) { if (nscholars > 0) {
qsort(scholars, nscholars, sizeof(scholar), cmp_scholars); qsort(scholars, nscholars, sizeof(scholar), cmp_scholars);
} }
@ -83,7 +82,7 @@ void autostudy_run(scholar scholars[], int nscholars)
int ti = 0; int ti = 0;
while (ti != nscholars) { while (ti != nscholars) {
skill_t sk = scholars[ti].sk; skill_t sk = scholars[ti].sk;
int t, s, se, ts = 0, tt = 0, si = ti; int t, se, ts = 0, tt = 0, si = ti;
for (se = ti; se != nscholars && scholars[se].sk == sk; ++se) { for (se = ti; se != nscholars && scholars[se].sk == sk; ++se) {
int mint; int mint;
ts += scholars[se].u->number; /* count total scholars */ ts += scholars[se].u->number; /* count total scholars */
@ -111,7 +110,7 @@ void autostudy_run(scholar scholars[], int nscholars)
/* invariant: unit ti can still teach i students */ /* invariant: unit ti can still teach i students */
int i = scholars[ti].u->number * STUDENTS_PER_TEACHER; int i = scholars[ti].u->number * STUDENTS_PER_TEACHER;
/* invariant: unit si has n students that can still be taught */ /* invariant: unit si has n students that can still be taught */
int n = scholars[si].u->number; int s, n = scholars[si].u->number;
for (t = ti, s = si; t != si && s != se; ) { for (t = ti, s = si; t != si && s != se; ) {
if (i >= n) { if (i >= n) {
/* t has more than enough teaching capacity for s */ /* t has more than enough teaching capacity for s */
@ -125,25 +124,20 @@ void autostudy_run(scholar scholars[], int nscholars)
n = scholars[s].u->number; n = scholars[s].u->number;
} }
else { else {
/* s gets partial credit and we need a new teacher */ /* a part of s gets credited and we need a new teacher: */
teaching(scholars + s, i); teaching(scholars + s, i);
/* we still need to teach n students in this unit: */
/* we are done with this teacher. any remaining people are regular learners: */ n -= i;
if (scholars[t].u->number > 1) { i = 0;
/* remain = number - ceil(taught/10); */
int remain = (STUDENTS_PER_TEACHER * scholars[t].u->number - i + STUDENTS_PER_TEACHER - 1) / STUDENTS_PER_TEACHER;
learning(scholars + t, remain);
}
/* we want a new teacher for s. if any exists, it's next in the sequence. */ /* we want a new teacher for s. if any exists, it's next in the sequence. */
if (++t == si) { if (++t == si) {
continue; continue;
} }
if (scholars[t].level - TEACHDIFFERENCE < scholars[s].level) { if (scholars[t].level - TEACHDIFFERENCE < scholars[s].level) {
/* next teacher cannot teach, we must skip students. */ /* no remaining teacher can teach this student, so we skip ahead */
do { do {
learning(scholars + s, (n - i)); /* remaining students learn without a teacher: */
i = 0; learning(scholars + s, n);
if (++s == se) { if (++s == se) {
break; break;
} }

View file

@ -62,13 +62,52 @@ static void test_autostudy_init(CuTest *tc) {
CuAssertIntEquals(tc, 0, scholars[0].level); CuAssertIntEquals(tc, 0, scholars[0].level);
CuAssertIntEquals(tc, 0, scholars[0].learn); CuAssertIntEquals(tc, 0, scholars[0].learn);
CuAssertIntEquals(tc, SK_PERCEPTION, scholars[0].sk); CuAssertIntEquals(tc, SK_PERCEPTION, scholars[0].sk);
CuAssertPtrEquals(tc, NULL, scholars[1].u);
CuAssertPtrEquals(tc, NULL, ulist); CuAssertPtrEquals(tc, NULL, ulist);
test_teardown(); test_teardown();
} }
/**
* Reproduce Bug 2520
*/
static void test_autostudy_run_twoteachers(CuTest *tc) {
scholar scholars[4];
int nscholars;
unit *u1, *u2, *u3, *u4, *ulist;
faction *f;
region *r;
test_setup();
r = test_create_plain(0, 0);
f = test_create_faction(NULL);
u1 = test_create_unit(f, r);
set_level(u1, SK_ENTERTAINMENT, 2);
u1->thisorder = create_order(K_AUTOSTUDY, f->locale, skillnames[SK_ENTERTAINMENT]);
u2 = test_create_unit(f, r);
set_level(u2, SK_ENTERTAINMENT, 2);
u2->thisorder = create_order(K_AUTOSTUDY, f->locale, skillnames[SK_ENTERTAINMENT]);
u3 = test_create_unit(f, r);
u3->thisorder = create_order(K_AUTOSTUDY, f->locale, skillnames[SK_ENTERTAINMENT]);
set_number(u3, 8);
u4 = test_create_unit(f, r);
u4->thisorder = create_order(K_AUTOSTUDY, f->locale, skillnames[SK_ENTERTAINMENT]);
set_number(u4, 12);
ulist = r->units;
CuAssertIntEquals(tc, 4, nscholars = autostudy_init(scholars, 4, &ulist));
CuAssertPtrEquals(tc, NULL, ulist);
autostudy_run(scholars, nscholars);
CuAssertIntEquals(tc, 0, scholars[0].learn);
CuAssertIntEquals(tc, 0, scholars[1].learn);
CuAssertIntEquals(tc, scholars[2].u->number * 2, scholars[2].learn);
CuAssertIntEquals(tc, scholars[3].u->number * 2, scholars[3].learn);
test_teardown();
}
static void test_autostudy_run(CuTest *tc) { static void test_autostudy_run(CuTest *tc) {
scholar scholars[4]; scholar scholars[4];
int nscholars;
unit *u1, *u2, *u3, *ulist; unit *u1, *u2, *u3, *ulist;
faction *f; faction *f;
region *r; region *r;
@ -88,9 +127,9 @@ static void test_autostudy_run(CuTest *tc) {
set_number(u3, 15); set_number(u3, 15);
scholars[3].u = NULL; scholars[3].u = NULL;
ulist = r->units; ulist = r->units;
CuAssertIntEquals(tc, 3, autostudy_init(scholars, 4, &ulist)); CuAssertIntEquals(tc, 3, nscholars = autostudy_init(scholars, 4, &ulist));
CuAssertPtrEquals(tc, NULL, ulist); CuAssertPtrEquals(tc, NULL, ulist);
autostudy_run(scholars, 3); autostudy_run(scholars, nscholars);
CuAssertIntEquals(tc, 1, scholars[0].learn); CuAssertIntEquals(tc, 1, scholars[0].learn);
CuAssertIntEquals(tc, 20, scholars[1].learn); CuAssertIntEquals(tc, 20, scholars[1].learn);
CuAssertIntEquals(tc, 15, scholars[2].learn); CuAssertIntEquals(tc, 15, scholars[2].learn);
@ -99,6 +138,7 @@ static void test_autostudy_run(CuTest *tc) {
static void test_autostudy_run_noteachers(CuTest *tc) { static void test_autostudy_run_noteachers(CuTest *tc) {
scholar scholars[4]; scholar scholars[4];
int nscholars;
unit *u1, *u2, *u3, *ulist; unit *u1, *u2, *u3, *ulist;
faction *f; faction *f;
region *r; region *r;
@ -118,20 +158,50 @@ static void test_autostudy_run_noteachers(CuTest *tc) {
set_number(u3, 15); set_number(u3, 15);
scholars[3].u = NULL; scholars[3].u = NULL;
ulist = r->units; ulist = r->units;
CuAssertIntEquals(tc, 3, autostudy_init(scholars, 4, &ulist)); CuAssertIntEquals(tc, 3, nscholars = autostudy_init(scholars, 4, &ulist));
CuAssertPtrEquals(tc, NULL, ulist); CuAssertPtrEquals(tc, NULL, ulist);
autostudy_run(scholars, 3); autostudy_run(scholars, nscholars);
CuAssertIntEquals(tc, 2, scholars[0].learn); CuAssertIntEquals(tc, 2, scholars[0].learn);
CuAssertIntEquals(tc, 10, scholars[1].learn); CuAssertIntEquals(tc, 10, scholars[1].learn);
CuAssertIntEquals(tc, 15, scholars[2].learn); CuAssertIntEquals(tc, 15, scholars[2].learn);
test_teardown(); test_teardown();
} }
/**
* If a teacher unit doesn't have enough students, the remaining members study.
*/
static void test_autostudy_run_teachers_learn(CuTest *tc) {
scholar scholars[4];
int nscholars;
unit *u1, *u2, *ulist;
faction *f;
region *r;
test_setup();
r = test_create_plain(0, 0);
f = test_create_faction(NULL);
u1 = test_create_unit(f, r);
u1->thisorder = create_order(K_AUTOSTUDY, f->locale, skillnames[SK_ENTERTAINMENT]);
set_number(u1, 2);
set_level(u1, SK_ENTERTAINMENT, 2);
u2 = test_create_unit(f, r);
u2->thisorder = create_order(K_AUTOSTUDY, f->locale, skillnames[SK_ENTERTAINMENT]);
set_number(u2, 10);
ulist = r->units;
CuAssertIntEquals(tc, 2, nscholars = autostudy_init(scholars, 4, &ulist));
CuAssertPtrEquals(tc, NULL, ulist);
autostudy_run(scholars, nscholars);
CuAssertIntEquals(tc, 1, scholars[0].learn);
CuAssertIntEquals(tc, 20, scholars[1].learn);
test_teardown();
}
/** /**
* Reproduce Bug 2514 * Reproduce Bug 2514
*/ */
static void test_autostudy_run_skilldiff(CuTest *tc) { static void test_autostudy_run_skilldiff(CuTest *tc) {
scholar scholars[4]; scholar scholars[4];
int nscholars;
unit *u1, *u2, *u3, *ulist; unit *u1, *u2, *u3, *ulist;
faction *f; faction *f;
region *r; region *r;
@ -152,9 +222,9 @@ static void test_autostudy_run_skilldiff(CuTest *tc) {
set_number(u3, 10); set_number(u3, 10);
scholars[3].u = NULL; scholars[3].u = NULL;
ulist = r->units; ulist = r->units;
CuAssertIntEquals(tc, 3, autostudy_init(scholars, 4, &ulist)); CuAssertIntEquals(tc, 3, nscholars = autostudy_init(scholars, 4, &ulist));
CuAssertPtrEquals(tc, NULL, ulist); CuAssertPtrEquals(tc, NULL, ulist);
autostudy_run(scholars, 3); autostudy_run(scholars, nscholars);
CuAssertIntEquals(tc, 0, scholars[0].learn); CuAssertIntEquals(tc, 0, scholars[0].learn);
CuAssertIntEquals(tc, 20, scholars[2].learn); CuAssertIntEquals(tc, 20, scholars[2].learn);
CuAssertIntEquals(tc, 10, scholars[1].learn); CuAssertIntEquals(tc, 10, scholars[1].learn);
@ -167,6 +237,8 @@ CuSuite *get_automate_suite(void)
SUITE_ADD_TEST(suite, test_autostudy_init); SUITE_ADD_TEST(suite, test_autostudy_init);
SUITE_ADD_TEST(suite, test_autostudy_run); SUITE_ADD_TEST(suite, test_autostudy_run);
SUITE_ADD_TEST(suite, test_autostudy_run_noteachers); SUITE_ADD_TEST(suite, test_autostudy_run_noteachers);
SUITE_ADD_TEST(suite, test_autostudy_run_teachers_learn);
SUITE_ADD_TEST(suite, test_autostudy_run_twoteachers);
SUITE_ADD_TEST(suite, test_autostudy_run_skilldiff); SUITE_ADD_TEST(suite, test_autostudy_run_skilldiff);
return suite; return suite;
} }

View file

@ -697,23 +697,20 @@ static int CavalryBonus(const unit * u, troop enemy, int type)
return 0; return 0;
} }
/**
* Effektiver Waffenskill waehrend des Kampfes.
*/
static int static int
weapon_effskill(troop t, troop enemy, const weapon * w, bool attacking, weapon_effskill(troop t, troop enemy, const weapon * w,
bool missile) bool attacking, bool missile)
/* effektiver Waffenskill w<>hrend des Kampfes */
{ {
/* In dieser Runde alle die Modifier berechnen, die fig durch die
* Waffen bekommt. */
fighter *tf = t.fighter; fighter *tf = t.fighter;
unit *tu = t.fighter->unit; unit *tu = t.fighter->unit;
int skill; /* Alle Modifier berechnen, die fig durch die Waffen bekommt. */
const weapon_type *wtype = w ? w->type : NULL; if (w) {
int skill = 0;
const weapon_type *wtype = w->type;
if (wtype == NULL) {
/* Ohne Waffe: Waffenlose Angriffe */
skill = weapon_skill(NULL, tu, attacking);
}
else {
if (attacking) { if (attacking) {
skill = w->attackskill; skill = w->attackskill;
} }
@ -745,30 +742,31 @@ bool missile)
} }
} }
} }
} /* Burgenbonus, Pferdebonus */
if (is_riding(t) && (wtype == NULL || (fval(wtype, WTF_HORSEBONUS)
&& !fval(wtype, WTF_MISSILE)))) {
skill += CavalryBonus(tu, enemy, BONUS_SKILL);
}
/* Burgenbonus, Pferdebonus */ if (t.index < tf->elvenhorses) {
if (is_riding(t) && (wtype == NULL || (fval(wtype, WTF_HORSEBONUS) /* Elfenpferde: Helfen dem Reiter, egal ob und welche Waffe. Das ist
&& !fval(wtype, WTF_MISSILE)))) { * eleganter, und vor allem einfacher, sonst mu<EFBFBD> man noch ein
skill += CavalryBonus(tu, enemy, BONUS_SKILL); * WMF_ELVENHORSE einbauen. */
} skill += 2;
}
if (t.index < tf->elvenhorses) { if (skill > 0 && !attacking && missile) {
/* Elfenpferde: Helfen dem Reiter, egal ob und welche Waffe. Das ist /*
* eleganter, und vor allem einfacher, sonst mu<EFBFBD> man noch ein * Wenn ich verteidige, und nicht direkt meinem Feind gegen<EFBFBD>berstehe,
* WMF_ELVENHORSE einbauen. */ * halbiert sich mein Skill: (z.B. gegen Fernk<EFBFBD>mpfer. Nahk<EFBFBD>mpfer
skill += 2; * k<EFBFBD>nnen mich eh nicht treffen)
*/
skill /= 2;
}
return skill;
} }
/* no weapon: fight weaponless */
if (skill > 0 && !attacking && missile) { return weapon_skill(NULL, tu, attacking);
/*
* Wenn ich verteidige, und nicht direkt meinem Feind gegen<EFBFBD>berstehe,
* halbiert sich mein Skill: (z.B. gegen Fernk<EFBFBD>mpfer. Nahk<EFBFBD>mpfer
* k<EFBFBD>nnen mich eh nicht treffen)
*/
skill /= 2;
}
return skill;
} }
const armor_type *select_armor(troop t, bool shield) const armor_type *select_armor(troop t, bool shield)
@ -1189,7 +1187,7 @@ static void destroy_items(troop dt) {
} }
static void calculate_defense_type(troop dt, troop at, int type, bool missile, static void calculate_defense_type(troop at, troop dt, int type, bool missile,
const weapon_type **dwtype, int *defskill) { const weapon_type **dwtype, int *defskill) {
const weapon *weapon; const weapon *weapon;
weapon = select_weapon(dt, false, true); /* missile=true to get the unmodified best weapon she has */ weapon = select_weapon(dt, false, true); /* missile=true to get the unmodified best weapon she has */
@ -1198,7 +1196,7 @@ static void calculate_defense_type(troop dt, troop at, int type, bool missile,
*dwtype = weapon->type; *dwtype = weapon->type;
} }
static void calculate_attack_type(troop dt, troop at, int type, bool missile, static void calculate_attack_type(troop at, troop dt, int type, bool missile,
const weapon_type **awtype, int *attskill, bool *magic) { const weapon_type **awtype, int *attskill, bool *magic) {
const weapon *weapon; const weapon *weapon;
@ -1318,7 +1316,7 @@ terminate(troop dt, troop at, int type, const char *damage_formula, bool missile
++at.fighter->hits; ++at.fighter->hits;
calculate_attack_type(at, dt, type, missile, &awtype, &attskill, &magic); calculate_attack_type(at, dt, type, missile, &awtype, &attskill, &magic);
calculate_defense_type(at, dt, type, missile, &awtype, &attskill); calculate_defense_type(at, dt, type, missile, &dwtype, &defskill);
if (is_riding(at) && (awtype == NULL || (fval(awtype, WTF_HORSEBONUS) if (is_riding(at) && (awtype == NULL || (fval(awtype, WTF_HORSEBONUS)
&& !fval(awtype, WTF_MISSILE)))) { && !fval(awtype, WTF_MISSILE)))) {
@ -3383,23 +3381,6 @@ fighter *make_fighter(battle * b, unit * u, side * s1, bool attack)
return fig; return fig;
} }
fighter * get_fighter(battle * b, const struct unit * u)
{
side * s;
for (s = b->sides; s != b->sides + b->nsides; ++s) {
fighter *fig;
if (s->faction == u->faction) {
for (fig = s->fighters; fig; fig = fig->next) {
if (fig->unit == u) {
return fig;
}
}
}
}
return 0;
}
int join_battle(battle * b, unit * u, bool attack, fighter ** cp) int join_battle(battle * b, unit * u, bool attack, fighter ** cp)
{ {
side *s; side *s;

View file

@ -213,7 +213,6 @@ extern "C" {
/* BEGIN battle interface */ /* BEGIN battle interface */
side * find_side(battle * b, const struct faction * f, const struct group * g, unsigned int flags, const struct faction * stealthfaction); side * find_side(battle * b, const struct faction * f, const struct group * g, unsigned int flags, const struct faction * stealthfaction);
side * get_side(battle * b, const struct unit * u); side * get_side(battle * b, const struct unit * u);
fighter * get_fighter(battle * b, const struct unit * u);
/* END battle interface */ /* END battle interface */
void do_battles(void); void do_battles(void);

View file

@ -123,6 +123,16 @@ static void test_select_weapon_restricted(CuTest *tc) {
CuAssertIntEquals(tc, 0, af->weapons[0].count); CuAssertIntEquals(tc, 0, af->weapons[0].count);
free_battle(b); free_battle(b);
itype->mask_deny = 0;
itype->mask_allow = rc_mask(au->_race);
b = make_battle(au->region);
af = make_fighter(b, au, make_side(b, au->faction, 0, 0, 0), false);
CuAssertPtrNotNull(tc, af->weapons);
CuAssertIntEquals(tc, 1, af->weapons[0].count);
CuAssertPtrEquals(tc, itype->rtype->wtype, (void *)af->weapons[0].type);
CuAssertIntEquals(tc, 0, af->weapons[1].count);
free_battle(b);
itype->mask_deny = 0; itype->mask_deny = 0;
itype->mask_allow = rc_mask(rc); itype->mask_allow = rc_mask(rc);
b = make_battle(au->region); b = make_battle(au->region);

View file

@ -22,7 +22,6 @@
#include "kernel/skills.h" #include "kernel/skills.h"
#include "kernel/types.h" #include "kernel/types.h"
#include <kernel/building.h> #include <kernel/building.h>
#include <kernel/config.h>
#include <kernel/curse.h> #include <kernel/curse.h>
#include "kernel/equipment.h" #include "kernel/equipment.h"
#include <kernel/faction.h> #include <kernel/faction.h>
@ -432,38 +431,11 @@ static int tolua_unit_effskill(lua_State * L)
return 1; return 1;
} }
typedef struct fctr_data {
unit *target;
int fhandle;
} fctr_data;
typedef struct event { typedef struct event {
struct event_arg *args; struct event_arg *args;
char *msg; char *msg;
} event; } event;
int fctr_handle(struct trigger *tp, void *data)
{
trigger *t = tp;
event evt = { 0 };
fctr_data *fd = (fctr_data *)t->data.v;
lua_State *L = (lua_State *)global.vm_state;
unit *u = fd->target;
evt.args = (event_arg *)data;
lua_rawgeti(L, LUA_REGISTRYINDEX, fd->fhandle);
tolua_pushusertype(L, u, TOLUA_CAST "unit");
tolua_pushusertype(L, &evt, TOLUA_CAST "event");
if (lua_pcall(L, 2, 0, 0) != 0) {
const char *error = lua_tostring(L, -1);
log_error("event (%s): %s\n", unitname(u), error);
lua_pop(L, 1);
tolua_error(L, TOLUA_CAST "event handler call failed", NULL);
}
return 0;
}
static int tolua_unit_addnotice(lua_State * L) static int tolua_unit_addnotice(lua_State * L)
{ {
unit *self = (unit *)tolua_tousertype(L, 1, 0); unit *self = (unit *)tolua_tousertype(L, 1, 0);

View file

@ -848,11 +848,13 @@ void cr_output_unit(stream *out, const faction * f,
pzTmp = get_racename(u->attribs); pzTmp = get_racename(u->attribs);
if (pzTmp) { if (pzTmp) {
stream_printf(out, "\"%s\";Typ\n", pzTmp); const char *pzRace = LOC(lang, mkname("race", pzTmp));
pzTmp = pzRace ? pzRace : pzTmp;
stream_printf(out, "\"%s\";Typ\n", translate(pzTmp, LOC(lang, pzTmp)));
if (u->faction == f && fval(u_race(u), RCF_SHAPESHIFTANY)) { if (u->faction == f && fval(u_race(u), RCF_SHAPESHIFTANY)) {
const char *zRace = rc_name_s(u_race(u), NAME_PLURAL); pzRace = rc_name_s(u_race(u), NAME_PLURAL);
stream_printf(out, "\"%s\";wahrerTyp\n", stream_printf(out, "\"%s\";wahrerTyp\n",
translate(zRace, LOC(lang, zRace))); translate(pzRace, LOC(lang, pzRace)));
} }
} }
else { else {
@ -1155,7 +1157,7 @@ static char *cr_output_resource(char *buf, const resource_type *rtype,
assert(rtype); assert(rtype);
name = resourcename(rtype, NMF_PLURAL); name = resourcename(rtype, NMF_PLURAL);
assert(name); assert(name);
buf += sprintf(buf, "RESOURCE %u\n", str_hash(rtype->_name)); buf += sprintf(buf, "RESOURCE %d\n", str_hash(rtype->_name));
tname = LOC(loc, name); tname = LOC(loc, name);
assert(tname); assert(tname);
tname = translate(name, tname); tname = translate(name, tname);

View file

@ -2239,7 +2239,6 @@ static void breed_cmd(unit * u, struct order *ord)
const char *s; const char *s;
param_t p; param_t p;
region *r = u->region; region *r = u->region;
const resource_type *rtype = NULL;
if (r->land == NULL) { if (r->land == NULL) {
ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error_onlandonly", "")); ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error_onlandonly", ""));
@ -2275,7 +2274,7 @@ static void breed_cmd(unit * u, struct order *ord)
break; break;
default: default:
if (p != P_ANY) { if (p != P_ANY) {
rtype = findresourcetype(s, u->faction->locale); const resource_type *rtype = findresourcetype(s, u->faction->locale);
if (rtype == get_resourcetype(R_SEED) || rtype == get_resourcetype(R_MALLORN_SEED)) { if (rtype == get_resourcetype(R_SEED) || rtype == get_resourcetype(R_MALLORN_SEED)) {
breedtrees(u, m); breedtrees(u, m);
break; break;

View file

@ -28,6 +28,7 @@
#include "creport.h" #include "creport.h"
#include "report.h" #include "report.h"
#include "names.h" #include "names.h"
#include "prefix.h"
#include "reports.h" #include "reports.h"
#include "spells.h" #include "spells.h"
#include "vortex.h" #include "vortex.h"
@ -50,9 +51,10 @@ void game_done(void)
calendar_cleanup(); calendar_cleanup();
free_functions(); free_functions();
free_config(); free_config();
free_special_directions();
free_locales(); free_locales();
#endif #endif
free_prefixes();
free_special_directions();
kernel_done(); kernel_done();
swapdb_close(); swapdb_close();
} }

View file

@ -874,7 +874,6 @@ static void start_resources(parseinfo *pi, const XML_Char *el, const XML_Char **
} }
static void start_ships(parseinfo *pi, const XML_Char *el, const XML_Char **attr) { static void start_ships(parseinfo *pi, const XML_Char *el, const XML_Char **attr) {
const char *flag_names[] = { "opensea", "fly", "nocoast", "speedy", NULL };
if (xml_strequal(el, "ship")) { if (xml_strequal(el, "ship")) {
const XML_Char *name; const XML_Char *name;
@ -917,10 +916,13 @@ static void start_ships(parseinfo *pi, const XML_Char *el, const XML_Char **attr
else if (xml_strequal(attr[i], "storm")) { else if (xml_strequal(attr[i], "storm")) {
stype->storm = xml_float(attr[i + 1]); stype->storm = xml_float(attr[i + 1]);
} }
else if (!handle_flag(&flags, attr + i, flag_names)) { else {
/* we already handled the name earlier */ const char *flag_names[] = { "opensea", "fly", "nocoast", "speedy", NULL };
if (!xml_strequal(attr[i], "name")) { if (!handle_flag(&flags, attr + i, flag_names)) {
handle_bad_input(pi, el, attr[i]); /* we already handled the name earlier */
if (!xml_strequal(attr[i], "name")) {
handle_bad_input(pi, el, attr[i]);
}
} }
} }
} }
@ -1209,7 +1211,6 @@ static void start_races(parseinfo *pi, const XML_Char *el, const XML_Char **attr
} }
static void start_buildings(parseinfo *pi, const XML_Char *el, const XML_Char **attr) { static void start_buildings(parseinfo *pi, const XML_Char *el, const XML_Char **attr) {
const char *flag_names[] = { "nodestroy", "nobuild", "unique", "decay", "magic", "namechange", "fort", "oneperturn", NULL };
if (xml_strequal(el, "building")) { if (xml_strequal(el, "building")) {
const XML_Char *name; const XML_Char *name;
@ -1245,10 +1246,13 @@ static void start_buildings(parseinfo *pi, const XML_Char *el, const XML_Char **
/* magres is specified in percent! */ /* magres is specified in percent! */
btype->magres = frac_make(xml_int(attr[i + 1]), 100); btype->magres = frac_make(xml_int(attr[i + 1]), 100);
} }
else if (!handle_flag(&flags, attr + i, flag_names)) { else {
/* we already handled the name earlier */ const char *flag_names[] = { "nodestroy", "nobuild", "unique", "decay", "magic", "namechange", "fort", "oneperturn", NULL };
if (!xml_strequal(attr[i], "name")) { if (!handle_flag(&flags, attr + i, flag_names)) {
handle_bad_input(pi, el, attr[i]); /* we already handled the name earlier */
if (!xml_strequal(attr[i], "name")) {
handle_bad_input(pi, el, attr[i]);
}
} }
} }
} }

View file

@ -169,7 +169,6 @@ int give_quota(const unit * src, const unit * dst, const item_type * type,
if (config_changed(&config)) { if (config_changed(&config)) {
divisor = config_get_int("rules.items.give_divisor", divisor); divisor = config_get_int("rules.items.give_divisor", divisor);
} }
assert(divisor <= 0 || divisor >= 1);
if (divisor >= 1) { if (divisor >= 1) {
/* predictable > correct: */ /* predictable > correct: */
return n / divisor; return n / divisor;

View file

@ -1065,10 +1065,9 @@ static void seed_player(state *st, const newfaction *player) {
pnormalize(&nx, &ny, st->cursor.pl); pnormalize(&nx, &ny, st->cursor.pl);
r = findregion(nx, ny); r = findregion(nx, ny);
if (r) { if (r) {
faction *f; faction *f = addfaction(player->email, player->password,
const char *password = player->password ? player->password : itoa36(rng_int()); player->race, player->lang);
addplayer(r, f = addfaction(player->email, password, addplayer(r, f);
player->race, player->lang));
} }
} }
} }

View file

@ -1032,12 +1032,14 @@ static int add_po_string(const char *msgid, const char *msgstr, const char *msgc
} }
static int include_po(const char *uri) { static int include_po(const char *uri) {
char name[PATH_MAX], lname[8]; char name[PATH_MAX];
const char *filename = uri_to_file(uri, name, sizeof(name)); const char *filename = uri_to_file(uri, name, sizeof(name));
const char *pos = strstr(filename, ".po"); const char *pos = strstr(filename, ".po");
if (pos) { if (pos) {
size_t len; size_t len;
const char *str = --pos; const char *str = --pos;
char lname[8];
while (str > filename && *str != '.') --str; while (str > filename && *str != '.') --str;
len = (size_t)(pos - str); len = (size_t)(pos - str);
if (len < sizeof(lname)) { if (len < sizeof(lname)) {

View file

@ -1,90 +0,0 @@
#include "reports.h"
#include "jsreport.h"
#include <kernel/faction.h>
#include <kernel/region.h>
#include <kernel/terrain.h>
#include <kernel/terrainid.h>
#include <kernel/config.h>
#include <util/log.h>
#include <limits.h>
#include <stdio.h>
#include <math.h>
static void coor_to_tiled(int *x, int *y) {
*y = -*y;
*x = *x - (*y + 1) / 2;
}
static void coor_from_tiled(int *x, int *y) {
*x = *x + (*y + 1) / 2;
*y = -*y;
}
static int report_json(const char *filename, report_context * ctx, const char *charset)
{
if (config_get_int("jsreport.enabled", 0) != 0) {
FILE * F = fopen(filename, "w");
if (F) {
int minx = INT_MAX, maxx = INT_MIN, miny = INT_MAX, maxy = INT_MIN;
seen_region *sr;
region *r;
/* traverse all regions */
for (sr = NULL, r = ctx->first; sr == NULL && r != ctx->last; r = r->next) {
sr = find_seen(ctx->f->seen, r);
}
for (; sr != NULL; sr = sr->next) {
int tx = sr->r->x;
int ty = sr->r->y;
coor_to_tiled(&tx, &ty);
if (ty < miny) miny = ty;
else if (ty > maxy) maxy = ty;
if (tx < minx) minx = tx;
else if (tx > maxx) maxx = tx;
}
if (maxx >= minx && maxy >= miny) {
int y, w = maxx - minx + 1, h = maxy - miny + 1;
fputs("{ \"orientation\":\"hexagonal\",\"staggeraxis\":\"y\",", F);
fprintf(F, "\"staggerindex\":\"%s\", \"height\":%d, \"width\":%d, \"layers\":[", (miny & 1) ? "odd" : "even", h, w);
fprintf(F, "{ \"height\":%d, \"width\":%d, ", h, w);
fputs("\"visible\":true, \"opacity\":1, \"type\":\"tilelayer\", \"name\":\"terrain\", \"x\":0, \"y\":0, \"data\":[", F);
for (y = miny; y <= maxy; ++y) {
int x;
for (x = minx; x <= maxx; ++x) {
int data = 0;
int tx = x, ty = y;
coor_from_tiled(&tx, &ty);
r = findregion(tx, ty);
if (r) {
sr = find_seen(ctx->f->seen, r);
if (sr) {
terrain_t ter = oldterrain(r->terrain);
if (ter == NOTERRAIN) {
data = 1 + r->terrain->_name[0];
}
else {
data = 1 + (int)ter;
}
}
}
fprintf(F, "%d", data);
if (x != maxx || y != maxy) fputs(", ", F);
}
}
fputs("]}], \"tilesets\": [{\"firstgid\": 1, \"image\": \"magellan.png\", \"imageheight\": 192, \"imagewidth\": 256,"
"\"margin\": 0, \"name\": \"hextiles\", \"properties\": { }, \"spacing\": 0, "
"\"tileheight\" : 64, \"tilewidth\" : 64 }], \"tilewidth\": 64, \"tileheight\": 96}", F);
}
fclose(F);
return 0;
}
return -1;
}
return 0;
}
void register_jsreport(void)
{
register_reporttype("json", &report_json, 1 << O_JSON);
}

View file

@ -1,24 +0,0 @@
#pragma once
/*
+-------------------+ Christian Schlittchen <corwin@amber.kn-bremen.de>
| | Enno Rehling <enno@eressea.de>
| Eressea PBEM host | Katja Zedel <katze@felidae.kn-bremen.de>
| (c) 1998 - 2003 | Henning Peters <faroul@beyond.kn-bremen.de>
| | Ingo Wilken <Ingo.Wilken@informatik.uni-oldenburg.de>
+-------------------+ Stefan Reich <reich@halbling.de>
This program may not be used, modified or distributed
without prior permission by the authors of Eressea.
*/
#ifndef H_GC_JSREPORT
#define H_GC_JSREPORT
#ifdef __cplusplus
extern "C" {
#endif
void register_jsreport(void);
#ifdef __cplusplus
}
#endif
#endif

View file

@ -185,15 +185,15 @@ void at_register(attrib_type * at)
static attrib_type *at_find_key(unsigned int hk) static attrib_type *at_find_key(unsigned int hk)
{ {
const char *translate[3][2] = {
{ "zielregion", "targetregion" }, /* remapping: from 'zielregion, heute targetregion */
{ "verzaubert", "curse" }, /* remapping: früher verzaubert, jetzt curse */
{ NULL, NULL }
};
attrib_type *find = at_hash[hk % MAXATHASH]; attrib_type *find = at_hash[hk % MAXATHASH];
while (find && hk != find->hashkey) while (find && hk != find->hashkey)
find = find->nexthash; find = find->nexthash;
if (!find) { if (!find) {
const char *translate[3][2] = {
{ "zielregion", "targetregion" }, /* remapping: from 'zielregion, heute targetregion */
{ "verzaubert", "curse" }, /* remapping: früher verzaubert, jetzt curse */
{ NULL, NULL }
};
int i = 0; int i = 0;
while (translate[i][0]) { while (translate[i][0]) {
if (__at_hashkey(translate[i][0]) == hk) if (__at_hashkey(translate[i][0]) == hk)

View file

@ -106,27 +106,31 @@ int findoption(const char *s, const struct locale *lang)
/* -- Erschaffung neuer Einheiten ------------------------------ */ /* -- Erschaffung neuer Einheiten ------------------------------ */
static const char *forbidden[] = { "t", "te", "tem", "temp", NULL };
static int *forbidden_ids; static int *forbidden_ids;
static const char *forbidden[] = { "t", "te", "tem", "temp", NULL };
int forbiddenid(int id) bool forbiddenid(int id)
{ {
static size_t len; static size_t len;
size_t i; size_t i;
if (id <= 0) if (id <= 0) {
return 1; return true;
}
if (!forbidden_ids) { if (!forbidden_ids) {
while (forbidden[len]) while (forbidden[len])
++len; ++len;
forbidden_ids = calloc(len, sizeof(int)); forbidden_ids = malloc(len * sizeof(int));
if (!forbidden_ids) abort();
for (i = 0; i != len; ++i) { for (i = 0; i != len; ++i) {
forbidden_ids[i] = atoi36(forbidden[i]); forbidden_ids[i] = atoi36(forbidden[i]);
} }
} }
for (i = 0; i != len; ++i) for (i = 0; i != len; ++i) {
if (id == forbidden_ids[i]) if (id == forbidden_ids[i]) {
return 1; return true;
return 0; }
}
return false;
} }
int newcontainerid(void) int newcontainerid(void)
@ -274,6 +278,7 @@ void set_param(struct param **p, const char *key, const char *value)
par = *p; par = *p;
if (!par && value) { if (!par && value) {
*p = par = calloc(1, sizeof(param)); *p = par = calloc(1, sizeof(param));
if (!par) abort();
} }
if (par) { if (par) {
void *match; void *match;
@ -509,7 +514,6 @@ order *default_order(const struct locale *lang)
int i = locale_index(lang); int i = locale_index(lang);
keyword_t kwd; keyword_t kwd;
const char * str; const char * str;
order *result = 0;
assert(i < MAXLOCALES); assert(i < MAXLOCALES);
kwd = keyword_disabled(K_WORK) ? NOKEYWORD : K_WORK; kwd = keyword_disabled(K_WORK) ? NOKEYWORD : K_WORK;
@ -518,7 +522,8 @@ order *default_order(const struct locale *lang)
kwd = findkeyword(str); kwd = findkeyword(str);
} }
if (kwd != NOKEYWORD) { if (kwd != NOKEYWORD) {
result = create_order(kwd, lang, NULL); /* TODO: why is there a copy_order made here? */
order *result = create_order(kwd, lang, NULL);
return copy_order(result); return copy_order(result);
} }
return NULL; return NULL;

View file

@ -52,7 +52,7 @@ extern "C" {
void init_locale(struct locale *lang); void init_locale(struct locale *lang);
void init_races(struct locale *lang); void init_races(struct locale *lang);
int forbiddenid(int id); bool forbiddenid(int id);
int newcontainerid(void); int newcontainerid(void);
bool rule_region_owners(void); bool rule_region_owners(void);

View file

@ -672,16 +672,6 @@ bool curse_active(const curse * c)
return true; return true;
} }
bool is_cursed_internal(attrib * ap, const curse_type * ct)
{
curse *c = get_curse(ap, ct);
if (!c)
return false;
return true;
}
bool is_cursed_with(const attrib * ap, const curse * c) bool is_cursed_with(const attrib * ap, const curse * c)
{ {
const attrib *a = ap; const attrib *a = ap;

View file

@ -168,28 +168,6 @@ void set_show_item(faction * f, const struct item_type *itype)
a->data.v = (void *)itype; a->data.v = (void *)itype;
} }
const unit *random_unit_in_faction(const faction * f)
{
unit *u;
int c = 0, u_nr;
if (!f->units) {
return NULL;
}
for (u = f->units; u; u = u->next)
c++;
u_nr = rng_int() % c;
c = 0;
for (u = f->units; u; u = u->next)
if (u_nr == c)
return u;
/* Hier sollte er nie ankommen */
return NULL;
}
const char *factionname(const faction * f) const char *factionname(const faction * f)
{ {
typedef char name[OBJECTIDSIZE + 1]; typedef char name[OBJECTIDSIZE + 1];
@ -227,6 +205,12 @@ static int unused_faction_id(void)
return id; return id;
} }
void faction_genpassword(faction *f) {
const char * password = itoa36(rng_int());
faction_setpassword(f, password_hash(password, PASSWORD_DEFAULT));
ADDMSG(&f->msgs, msg_message("changepasswd", "value", password));
}
faction *addfaction(const char *email, const char *password, faction *addfaction(const char *email, const char *password,
const struct race * frace, const struct locale * loc) const struct race * frace, const struct locale * loc)
{ {
@ -241,7 +225,7 @@ faction *addfaction(const char *email, const char *password,
} }
f->alliance_joindate = turn; f->alliance_joindate = turn;
f->lastorders = turn; f->lastorders = 0;
f->_alive = true; f->_alive = true;
f->password_id = 0; f->password_id = 0;
f->age = 0; f->age = 0;

View file

@ -117,7 +117,6 @@ extern "C" {
int max_magicians(const faction * f); int max_magicians(const faction * f);
void set_show_item(faction * f, const struct item_type *itype); void set_show_item(faction * f, const struct item_type *itype);
const struct unit *random_unit_in_faction(const struct faction *f);
const char *factionname(const struct faction *f); const char *factionname(const struct faction *f);
struct unit *addplayer(struct region *r, faction * f); struct unit *addplayer(struct region *r, faction * f);
struct faction *addfaction(const char *email, const char *password, struct faction *addfaction(const char *email, const char *password,
@ -151,6 +150,7 @@ extern "C" {
const char *faction_getemail(const struct faction *self); const char *faction_getemail(const struct faction *self);
void faction_setemail(struct faction *self, const char *email); void faction_setemail(struct faction *self, const char *email);
void faction_genpassword(struct faction *f);
void faction_setpassword(struct faction *self, const char *pwhash); void faction_setpassword(struct faction *self, const char *pwhash);
const char *faction_getpassword(const struct faction *f); const char *faction_getpassword(const struct faction *f);
bool valid_race(const struct faction *f, const struct race *rc); bool valid_race(const struct faction *f, const struct race *rc);

View file

@ -110,7 +110,7 @@ static void test_addfaction(CuTest *tc) {
test_setup(); test_setup();
rc = rc_get_or_create("human"); rc = rc_get_or_create("human");
lang = test_create_locale(); lang = test_create_locale();
f = addfaction("test@eressea.de", NULL, rc, lang); f = addfaction("test@example.com", NULL, rc, lang);
CuAssertPtrNotNull(tc, f); CuAssertPtrNotNull(tc, f);
CuAssertPtrNotNull(tc, f->name); CuAssertPtrNotNull(tc, f->name);
CuAssertPtrEquals(tc, NULL, (void *)f->units); CuAssertPtrEquals(tc, NULL, (void *)f->units);
@ -119,14 +119,14 @@ static void test_addfaction(CuTest *tc) {
CuAssertPtrEquals(tc, NULL, (void *)f->spellbook); CuAssertPtrEquals(tc, NULL, (void *)f->spellbook);
CuAssertPtrEquals(tc, NULL, (void *)f->origin); CuAssertPtrEquals(tc, NULL, (void *)f->origin);
CuAssertPtrEquals(tc, (void *)factions, (void *)f); CuAssertPtrEquals(tc, (void *)factions, (void *)f);
CuAssertStrEquals(tc, "test@eressea.de", f->email); CuAssertStrEquals(tc, "test@example.com", f->email);
CuAssertTrue(tc, checkpasswd(f, "hurrdurr")); CuAssertTrue(tc, checkpasswd(f, "hurrdurr"));
CuAssertPtrEquals(tc, (void *)lang, (void *)f->locale); CuAssertPtrEquals(tc, (void *)lang, (void *)f->locale);
CuAssertIntEquals(tc, FFL_ISNEW|FFL_PWMSG, f->flags); CuAssertIntEquals(tc, FFL_ISNEW|FFL_PWMSG, f->flags);
CuAssertIntEquals(tc, 0, f->age); CuAssertIntEquals(tc, 0, f->age);
CuAssertTrue(tc, faction_alive(f)); CuAssertTrue(tc, faction_alive(f));
CuAssertIntEquals(tc, M_GRAY, f->magiegebiet); CuAssertIntEquals(tc, M_GRAY, f->magiegebiet);
CuAssertIntEquals(tc, turn, f->lastorders); CuAssertIntEquals(tc, 0, f->lastorders);
CuAssertPtrEquals(tc, f, findfaction(f->no)); CuAssertPtrEquals(tc, f, findfaction(f->no));
test_teardown(); test_teardown();
} }

View file

@ -40,8 +40,9 @@
#define FACTION_UID_VERSION 362 /* f->uid contains a database id */ #define FACTION_UID_VERSION 362 /* f->uid contains a database id */
#define CRYPT_VERSION 363 /* passwords are encrypted */ #define CRYPT_VERSION 363 /* passwords are encrypted */
#define FAMILIAR_FIXMAGE_VERSION 364 /* familiar links are fixed */ #define FAMILIAR_FIXMAGE_VERSION 364 /* familiar links are fixed */
#define FAMILIAR_FIXSPELLBOOK_VERSION 365 /* familiar spells are fixed */
#define RELEASE_VERSION FAMILIAR_FIXMAGE_VERSION /* current datafile */ #define RELEASE_VERSION FAMILIAR_FIXSPELLBOOK_VERSION /* current datafile */
#define MIN_VERSION UIDHASH_VERSION /* minimal datafile we support */ #define MIN_VERSION UIDHASH_VERSION /* minimal datafile we support */
#define MAX_VERSION RELEASE_VERSION /* change this if we can need to read the future datafile, and we can do so */ #define MAX_VERSION RELEASE_VERSION /* change this if we can need to read the future datafile, and we can do so */

View file

@ -194,12 +194,10 @@ resource_type *rt_get_or_create(const char *name) {
if (!rtype) { if (!rtype) {
rtype = calloc(1, sizeof(resource_type)); rtype = calloc(1, sizeof(resource_type));
if (!rtype) { if (!rtype) {
perror("resource_type allocation failed"); abort();
}
else {
rtype->_name = str_strdup(name);
rt_register(rtype);
} }
rtype->_name = str_strdup(name);
rt_register(rtype);
} }
return rtype; return rtype;
} }
@ -247,6 +245,7 @@ item_type *it_get_or_create(resource_type *rtype) {
if (!rtype->itype) { if (!rtype->itype) {
item_type * itype; item_type * itype;
itype = (item_type *)calloc(sizeof(item_type), 1); itype = (item_type *)calloc(sizeof(item_type), 1);
if (!itype) abort();
itype->rtype = rtype; itype->rtype = rtype;
rtype->uchange = res_changeitem; rtype->uchange = res_changeitem;
rtype->itype = itype; rtype->itype = itype;
@ -269,6 +268,7 @@ luxury_type *new_luxurytype(item_type * itype, int price)
assert(resource2luxury(itype->rtype) == NULL); assert(resource2luxury(itype->rtype) == NULL);
ltype = calloc(sizeof(luxury_type), 1); ltype = calloc(sizeof(luxury_type), 1);
if (!ltype) abort();
ltype->itype = itype; ltype->itype = itype;
ltype->price = price; ltype->price = price;
lt_register(ltype); lt_register(ltype);
@ -285,6 +285,7 @@ weapon_type *new_weapontype(item_type * itype,
assert(itype && (!itype->rtype || !resource2weapon(itype->rtype))); assert(itype && (!itype->rtype || !resource2weapon(itype->rtype)));
wtype = calloc(sizeof(weapon_type), 1); wtype = calloc(sizeof(weapon_type), 1);
if (!wtype) abort();
if (damage) { if (damage) {
wtype->damage[0] = str_strdup(damage[0]); wtype->damage[0] = str_strdup(damage[0]);
wtype->damage[1] = str_strdup(damage[1]); wtype->damage[1] = str_strdup(damage[1]);
@ -309,6 +310,7 @@ armor_type *new_armortype(item_type * itype, double penalty, variant magres,
assert(itype->rtype->atype == NULL); assert(itype->rtype->atype == NULL);
atype = calloc(sizeof(armor_type), 1); atype = calloc(sizeof(armor_type), 1);
if (!atype) abort();
atype->itype = itype; atype->itype = itype;
atype->penalty = penalty; atype->penalty = penalty;
@ -530,6 +532,7 @@ item *i_new(const item_type * itype, int size)
} }
else { else {
i = malloc(sizeof(item)); i = malloc(sizeof(item));
if (!i) abort();
} }
assert(itype); assert(itype);
i->next = NULL; i->next = NULL;

View file

@ -2,6 +2,7 @@
#include "messages.h" #include "messages.h"
#include "unit.h" #include "unit.h"
#include "faction.h"
#include "order.h" #include "order.h"
#include <CuTest.h> #include <CuTest.h>
@ -25,10 +26,13 @@ void test_missing_message(CuTest *tc) {
void test_missing_feedback(CuTest *tc) { void test_missing_feedback(CuTest *tc) {
message *msg; message *msg;
unit *u;
test_setup(); test_setup();
u = test_create_unit(test_create_faction(NULL), test_create_region(0, 0, NULL));
u->thisorder = create_order(K_ENTERTAIN, u->faction->locale, NULL);
message_handle_missing(MESSAGE_MISSING_REPLACE); message_handle_missing(MESSAGE_MISSING_REPLACE);
msg = msg_error(NULL, NULL, 77); msg = msg_error(u, NULL, 77);
CuAssertPtrNotNull(tc, msg); CuAssertPtrNotNull(tc, msg);
CuAssertPtrNotNull(tc, msg->type); CuAssertPtrNotNull(tc, msg->type);
CuAssertStrEquals(tc, msg->type->name, "missing_feedback"); CuAssertStrEquals(tc, msg->type->name, "missing_feedback");
@ -113,6 +117,7 @@ static void test_noerror(CuTest *tc) {
CuSuite *get_messages_suite(void) { CuSuite *get_messages_suite(void) {
CuSuite *suite = CuSuiteNew(); CuSuite *suite = CuSuiteNew();
SUITE_ADD_TEST(suite, test_missing_message); SUITE_ADD_TEST(suite, test_missing_message);
SUITE_ADD_TEST(suite, test_missing_feedback);
SUITE_ADD_TEST(suite, test_merge_split); SUITE_ADD_TEST(suite, test_merge_split);
SUITE_ADD_TEST(suite, test_message); SUITE_ADD_TEST(suite, test_message);
SUITE_ADD_TEST(suite, test_noerror); SUITE_ADD_TEST(suite, test_noerror);

View file

@ -120,7 +120,7 @@ char* get_command(const order *ord, const struct locale *lang, char *sbuffer, si
sbs_init(&sbs, sbuffer, size); sbs_init(&sbs, sbuffer, size);
if (ord->command & CMD_QUIET) { if (ord->command & CMD_QUIET) {
sbs_strcpy(&sbs, "!"); sbs_strcat(&sbs, "!");
} }
if (ord->command & CMD_PERSIST) { if (ord->command & CMD_PERSIST) {
sbs_strcat(&sbs, "@"); sbs_strcat(&sbs, "@");
@ -170,7 +170,6 @@ const char *crescape(const char *str, char *buffer, size_t size) {
int stream_order(struct stream *out, const struct order *ord, const struct locale *lang, bool escape) int stream_order(struct stream *out, const struct order *ord, const struct locale *lang, bool escape)
{ {
const char *text; const char *text;
order_data *od = NULL;
keyword_t kwd = ORD_KEYWORD(ord); keyword_t kwd = ORD_KEYWORD(ord);
if (ord->command & CMD_QUIET) { if (ord->command & CMD_QUIET) {
@ -203,7 +202,7 @@ int stream_order(struct stream *out, const struct order *ord, const struct local
} }
} }
else { else {
od = odata_load(ord->id); order_data *od = odata_load(ord->id);
text = OD_STRING(od); text = OD_STRING(od);
if (text) { if (text) {
char obuf[1024]; char obuf[1024];

View file

@ -6,6 +6,7 @@
#include "unit.h" #include "unit.h"
#include "item.h" #include "item.h"
#include "faction.h" #include "faction.h"
#include "race.h"
#include "region.h" #include "region.h"
#include "skill.h" #include "skill.h"
@ -42,6 +43,30 @@ void test_reservation(CuTest *tc) {
test_teardown(); test_teardown();
} }
void test_pool_get_item(CuTest *tc) {
unit *u1, *u2;
faction *f;
region *r;
race *rc;
struct resource_type *rtype;
test_setup();
rtype = rt_get_or_create("money");
rtype->flags |= RTF_POOLED;
it_get_or_create(rtype);
f = test_create_faction(NULL);
r = test_create_plain(0, 0);
u1 = test_create_unit(f, r);
u_setrace(u1, rc = test_create_race("undead"));
rc->ec_flags &= ~ECF_GETITEM;
u2 = test_create_unit(f, r);
i_change(&u2->items, rtype->itype, 2);
CuAssertIntEquals(tc, 0, get_pooled(u1, rtype, GET_DEFAULT, 1));
CuAssertIntEquals(tc, 0, i_get(u1->items, rtype->itype));
CuAssertIntEquals(tc, 2, i_get(u2->items, rtype->itype));
test_teardown();
}
void test_pool(CuTest *tc) { void test_pool(CuTest *tc) {
unit *u1, *u2, *u3; unit *u1, *u2, *u3;
faction *f; faction *f;
@ -49,11 +74,11 @@ void test_pool(CuTest *tc) {
struct resource_type *rtype; struct resource_type *rtype;
test_setup(); test_setup();
test_create_world();
rtype = rt_get_or_create("money"); rtype = rt_get_or_create("money");
rtype->flags |= RTF_POOLED;
it_get_or_create(rtype); it_get_or_create(rtype);
f = test_create_faction(NULL); f = test_create_faction(NULL);
r = findregion(0, 0); r = test_create_plain(0, 0);
assert(r && f && rtype && rtype->itype); assert(r && f && rtype && rtype->itype);
u1 = test_create_unit(f, r); u1 = test_create_unit(f, r);
u2 = test_create_unit(f, r); u2 = test_create_unit(f, r);
@ -188,6 +213,7 @@ CuSuite *get_pool_suite(void)
CuSuite *suite = CuSuiteNew(); CuSuite *suite = CuSuiteNew();
SUITE_ADD_TEST(suite, test_reservation); SUITE_ADD_TEST(suite, test_reservation);
SUITE_ADD_TEST(suite, test_pool); SUITE_ADD_TEST(suite, test_pool);
SUITE_ADD_TEST(suite, test_pool_get_item);
SUITE_ADD_TEST(suite, test_pool_bug_2042); SUITE_ADD_TEST(suite, test_pool_bug_2042);
SUITE_ADD_TEST(suite, test_pool_use); SUITE_ADD_TEST(suite, test_pool_use);
SUITE_ADD_TEST(suite, test_change_resource); SUITE_ADD_TEST(suite, test_change_resource);

View file

@ -240,15 +240,6 @@ race_list *get_familiarraces(void)
return familiarraces; return familiarraces;
} }
void racelist_clear(struct race_list **rl)
{
while (*rl) {
race_list *rl2 = (*rl)->next;
free(*rl);
*rl = rl2;
}
}
void racelist_insert(struct race_list **rl, const struct race *r) void racelist_insert(struct race_list **rl, const struct race *r)
{ {
race_list *rl2 = (race_list *)malloc(sizeof(race_list)); race_list *rl2 = (race_list *)malloc(sizeof(race_list));
@ -546,7 +537,7 @@ const char *racename(const struct locale *loc, const unit * u, const race * rc)
char ch[2]; char ch[2];
sbs_init(&sbs, lbuf, sizeof(lbuf)); sbs_init(&sbs, lbuf, sizeof(lbuf));
sbs_strcpy(&sbs, LOC(loc, mkname("prefix", prefix))); sbs_strcat(&sbs, LOC(loc, mkname("prefix", prefix)));
str = LOC(loc, rc_name_s(rc, u->number != 1)); str = LOC(loc, rc_name_s(rc, u->number != 1));
assert(~str[0] & 0x80 || !"unicode/not implemented"); assert(~str[0] & 0x80 || !"unicode/not implemented");

View file

@ -181,10 +181,8 @@ struct rawmaterial_type *rmt_get(const struct resource_type *rtype)
struct rawmaterial_type *rmt_create(struct resource_type *rtype) struct rawmaterial_type *rmt_create(struct resource_type *rtype)
{ {
rawmaterial_type *rmtype;
if (!rtype->raw) { if (!rtype->raw) {
rmtype = rtype->raw = malloc(sizeof(rawmaterial_type)); rawmaterial_type *rmtype = rtype->raw = malloc(sizeof(rawmaterial_type));
rmtype->rtype = rtype; rmtype->rtype = rtype;
rmtype->terraform = terraform_default; rmtype->terraform = terraform_default;
rmtype->update = NULL; rmtype->update = NULL;

View file

@ -272,12 +272,11 @@ static void read_owner(gamedata *data, region_owner ** powner)
static void write_owner(gamedata *data, region_owner * owner) static void write_owner(gamedata *data, region_owner * owner)
{ {
if (owner) { if (owner) {
faction *f;
WRITE_INT(data->store, owner->since_turn); WRITE_INT(data->store, owner->since_turn);
if (owner->since_turn >= 0) { if (owner->since_turn >= 0) {
faction *f = owner->last_owner;
WRITE_INT(data->store, owner->morale_turn); WRITE_INT(data->store, owner->morale_turn);
WRITE_INT(data->store, owner->flags); WRITE_INT(data->store, owner->flags);
f = owner->last_owner;
write_faction_reference((f && f->_alive) ? f : NULL, data->store); write_faction_reference((f && f->_alive) ? f : NULL, data->store);
f = owner->owner; f = owner->owner;
write_faction_reference((f && f->_alive) ? f : NULL, data->store); write_faction_reference((f && f->_alive) ? f : NULL, data->store);
@ -887,12 +886,12 @@ int get_spell_level_faction(const spell * sp, void * cbdata)
} }
static char * getpasswd(int fno) { static char * getpasswd(int fno) {
const char *prefix = itoa36(fno);
size_t len = strlen(prefix);
FILE * F = fopen("passwords.txt", "r"); FILE * F = fopen("passwords.txt", "r");
char line[80];
if (F) { if (F) {
const char *prefix = itoa36(fno);
size_t len = strlen(prefix);
while (!feof(F)) { while (!feof(F)) {
char line[80];
fgets(line, sizeof(line), F); fgets(line, sizeof(line), F);
if (line[len] == ':' && strncmp(prefix, line, len) == 0) { if (line[len] == ':' && strncmp(prefix, line, len) == 0) {
size_t slen = strlen(line) - 1; size_t slen = strlen(line) - 1;
@ -1147,7 +1146,7 @@ static int cb_sb_maxlevel(spellbook_entry *sbe, void *cbdata) {
int readgame(const char *filename) int readgame(const char *filename)
{ {
int n, stream_version; int n = -2, stream_version;
char path[PATH_MAX]; char path[PATH_MAX];
gamedata gdata = { 0 }; gamedata gdata = { 0 };
storage store; storage store;
@ -1164,23 +1163,25 @@ int readgame(const char *filename)
return -1; return -1;
} }
sz = fread(&gdata.version, sizeof(int), 1, F); sz = fread(&gdata.version, sizeof(int), 1, F);
sz = fread(&stream_version, sizeof(int), 1, F); if (sz == 1) {
assert((sz == 1 && stream_version == STREAM_VERSION) || !"unsupported data format"); sz = fread(&stream_version, sizeof(int), 1, F);
assert(gdata.version >= MIN_VERSION || !"unsupported data format"); assert((sz == 1 && stream_version == STREAM_VERSION) || !"unsupported data format");
assert(gdata.version <= MAX_VERSION || !"unsupported data format"); assert(gdata.version >= MIN_VERSION || !"unsupported data format");
assert(gdata.version <= MAX_VERSION || !"unsupported data format");
fstream_init(&strm, F); fstream_init(&strm, F);
binstore_init(&store, &strm); binstore_init(&store, &strm);
gdata.store = &store; gdata.store = &store;
if (gdata.version >= BUILDNO_VERSION) { if (gdata.version >= BUILDNO_VERSION) {
int build; int build;
READ_INT(&store, &build); READ_INT(&store, &build);
log_debug("data in %s created with build %d.", filename, build); log_debug("data in %s created with build %d.", filename, build);
}
n = read_game(&gdata);
binstore_done(&store);
fstream_done(&strm);
} }
n = read_game(&gdata);
binstore_done(&store);
fstream_done(&strm);
return n; return n;
} }
@ -1350,8 +1351,6 @@ int read_game(gamedata *data)
int p, nread; int p, nread;
faction *f, **fp; faction *f, **fp;
region *r; region *r;
building **bp;
ship **shp;
unit *u; unit *u;
storage * store = data->store; storage * store = data->store;
const struct building_type *bt_lighthouse = bt_find("lighthouse"); const struct building_type *bt_lighthouse = bt_find("lighthouse");
@ -1407,6 +1406,8 @@ int read_game(gamedata *data)
while (--nread >= 0) { while (--nread >= 0) {
unit **up; unit **up;
building **bp;
ship **shp;
r = read_region(data); r = read_region(data);
@ -1527,7 +1528,7 @@ int read_game(gamedata *data)
if (data->version < FAMILIAR_FIX_VERSION) { if (data->version < FAMILIAR_FIX_VERSION) {
fix_familiars(fix_fam_triggers); fix_familiars(fix_fam_triggers);
} }
if (data->version < FAMILIAR_FIXMAGE_VERSION) { if (data->version < FAMILIAR_FIXSPELLBOOK_VERSION) {
fix_familiars(fix_fam_mage); fix_familiars(fix_fam_mage);
} }

View file

@ -67,7 +67,6 @@ bool terrain_changed(int *cache) {
return false; return false;
} }
void free_terrains(void) void free_terrains(void)
{ {
while (registered_terrains) { while (registered_terrains) {

View file

@ -776,7 +776,6 @@ void clone_men(const unit * u, unit * dst, int n)
/* "hat attackiert"-status wird uebergeben */ /* "hat attackiert"-status wird uebergeben */
if (dst) { if (dst) {
skill *sv, *sn;
skill_t sk; skill_t sk;
ship *sh; ship *sh;
@ -784,9 +783,8 @@ void clone_men(const unit * u, unit * dst, int n)
for (sk = 0; sk != MAXSKILLS; ++sk) { for (sk = 0; sk != MAXSKILLS; ++sk) {
int weeks, level = 0; int weeks, level = 0;
skill *sv = unit_skill(u, sk);
sv = unit_skill(u, sk); skill *sn = unit_skill(dst, sk);
sn = unit_skill(dst, sk);
if (sv == NULL && sn == NULL) if (sv == NULL && sn == NULL)
continue; continue;
@ -984,9 +982,8 @@ void set_number(unit * u, int count)
void remove_skill(unit * u, skill_t sk) void remove_skill(unit * u, skill_t sk)
{ {
int i; int i;
skill *sv;
for (i = 0; i != u->skill_size; ++i) { for (i = 0; i != u->skill_size; ++i) {
sv = u->skills + i; skill *sv = u->skills + i;
if (sv->id == sk) { if (sv->id == sk) {
if (u->skill_size - i - 1 > 0) { if (u->skill_size - i - 1 > 0) {
memmove(sv, sv + 1, (u->skill_size - i - 1) * sizeof(skill)); memmove(sv, sv + 1, (u->skill_size - i - 1) * sizeof(skill));

View file

@ -154,8 +154,11 @@ bool IsImmune(const faction * f)
int NMRTimeout(void) int NMRTimeout(void)
{ {
int nmr_timeout = config_get_int("nmr.timeout", 0); static int config, nmr_timeout, ini_timeout;
int ini_timeout = config_get_int("game.maxnmr", 0); if (config_changed(&config)) {
nmr_timeout = config_get_int("nmr.timeout", 0);
ini_timeout = config_get_int("game.maxnmr", 0);
}
if (nmr_timeout > 0) { if (nmr_timeout > 0) {
if (ini_timeout > nmr_timeout) { if (ini_timeout > nmr_timeout) {
return nmr_timeout; return nmr_timeout;
@ -1192,17 +1195,26 @@ void do_enter(struct region *r, bool is_final_attempt)
int dropouts[2]; int dropouts[2];
int *age = NULL; int *age = NULL;
static void nmr_death(faction * f) bool nmr_death(const faction * f, int turn, int timeout)
{ {
int rule = config_get_int("rules.nmr.destroy", 0) != 0; if (f->age >= timeout && turn - f->lastorders >= timeout) {
if (rule) { static bool rule_destroy;
unit *u; static int config;
for (u = f->units; u; u = u->nextF) {
if (u->building && building_owner(u->building) == u) { if (config_changed(&config)) {
remove_building(&u->region->buildings, u->building); rule_destroy = config_get_int("rules.nmr.destroy", 0) != 0;
}
if (rule_destroy) {
unit *u;
for (u = f->units; u; u = u->nextF) {
if (u->building && building_owner(u->building) == u) {
remove_building(&u->region->buildings, u->building);
}
} }
} }
return true;
} }
return false;
} }
static void remove_idle_players(void) static void remove_idle_players(void)
@ -1215,8 +1227,7 @@ static void remove_idle_players(void)
for (fp = &factions; *fp;) { for (fp = &factions; *fp;) {
faction *f = *fp; faction *f = *fp;
if (timeout > 0 && turn - f->lastorders >= timeout) { if (timeout > 0 && nmr_death(f, turn, timeout)) {
nmr_death(f);
destroyfaction(fp); destroyfaction(fp);
} else { } else {
if (fval(f, FFL_NOIDLEOUT)) { if (fval(f, FFL_NOIDLEOUT)) {
@ -2088,34 +2099,33 @@ int email_cmd(unit * u, struct order *ord)
int password_cmd(unit * u, struct order *ord) int password_cmd(unit * u, struct order *ord)
{ {
char pwbuf[32]; char pwbuf[PASSWORD_MAXSIZE + 1];
const char *s; const char *s;
bool pwok = true;
init_order_depr(ord); init_order_depr(ord);
pwbuf[PASSWORD_MAXSIZE] = '\n';
s = gettoken(pwbuf, sizeof(pwbuf)); s = gettoken(pwbuf, sizeof(pwbuf));
if (pwbuf[PASSWORD_MAXSIZE] == '\0') {
if (!s || !*s) { cmistake(u, ord, 321, MSG_EVENT);
int i; pwbuf[PASSWORD_MAXSIZE - 1] = '\0';
for (i = 0; i < 6; i++)
pwbuf[i] = (char)(97 + rng_int() % 26);
pwbuf[6] = 0;
} }
else {
char *c; if (s && *s) {
for (c = pwbuf; *c && pwok; ++c) { unsigned char *c = (unsigned char *)pwbuf;
if (!isalnum(*(unsigned char *)c)) { int i, r = 0;
pwok = false;
for (i = 0; c[i] && i != PASSWORD_MAXSIZE; ++i) {
if (!isalnum(c[i])) {
c[i] = 'X';
++r;
} }
} }
} if (r != 0) {
if (!pwok) { cmistake(u, ord, 283, MSG_EVENT);
cmistake(u, ord, 283, MSG_EVENT); }
str_strlcpy(pwbuf, itoa36(rng_int()), sizeof(pwbuf));
} }
faction_setpassword(u->faction, password_hash(pwbuf, PASSWORD_DEFAULT)); faction_setpassword(u->faction, password_hash(pwbuf, PASSWORD_DEFAULT));
ADDMSG(&u->faction->msgs, msg_message("changepasswd", ADDMSG(&u->faction->msgs, msg_message("changepasswd", "value", pwbuf));
"value", pwbuf));
u->faction->flags |= FFL_PWMSG; u->faction->flags |= FFL_PWMSG;
return 0; return 0;
} }
@ -3339,7 +3349,6 @@ int pay_cmd(unit * u, struct order *ord)
cmistake(u, ord, 6, MSG_EVENT); cmistake(u, ord, 6, MSG_EVENT);
} }
else { else {
building *b = NULL;
param_t p; param_t p;
int id; int id;
@ -3355,13 +3364,12 @@ int pay_cmd(unit * u, struct order *ord)
} }
else { else {
/* If no building id is given or it is the id of our building, just set the do-not-pay flag */ /* If no building id is given or it is the id of our building, just set the do-not-pay flag */
if (id == 0 || id == u->building->no) if (id == 0 || id == u->building->no) {
{
u->building->flags |= BLD_DONTPAY; u->building->flags |= BLD_DONTPAY;
} }
else { else {
/* Find the building that matches to the given id*/ /* Find the building that matches to the given id*/
b = findbuilding(id); building *b = findbuilding(id);
/* If there is a building and it is in the same region as the unit continue, else: error */ /* If there is a building and it is in the same region as the unit continue, else: error */
if (b && b->region == u->region) if (b && b->region == u->region)
{ {
@ -3391,8 +3399,8 @@ int pay_cmd(unit * u, struct order *ord)
static int reserve_i(unit * u, struct order *ord, int flags) static int reserve_i(unit * u, struct order *ord, int flags)
{ {
char token[128];
if (u->number > 0) { if (u->number > 0) {
char token[128];
int use, count, para; int use, count, para;
const item_type *itype; const item_type *itype;
const char *s; const char *s;
@ -3426,10 +3434,7 @@ static int reserve_i(unit * u, struct order *ord, int flags)
} }
int reserve_cmd(unit * u, struct order *ord) { int reserve_cmd(unit * u, struct order *ord) {
if ((u_race(u)->ec_flags & ECF_GETITEM)) { return reserve_i(u, ord, GET_DEFAULT);
return reserve_i(u, ord, GET_DEFAULT);
}
return 0;
} }
int reserve_self(unit * u, struct order *ord) { int reserve_self(unit * u, struct order *ord) {

View file

@ -95,6 +95,7 @@ extern "C" {
int claim_cmd(struct unit *u, struct order *ord); int claim_cmd(struct unit *u, struct order *ord);
void nmr_warnings(void); void nmr_warnings(void);
bool nmr_death(const struct faction * f, int turn, int timeout);
bool cansee(const struct faction * f, const struct region * r, bool cansee(const struct faction * f, const struct region * r,
const struct unit *u, int modifier); const struct unit *u, int modifier);

View file

@ -48,6 +48,37 @@ static void test_new_building_can_be_renamed(CuTest * tc)
test_teardown(); test_teardown();
} }
static void test_password_cmd(CuTest * tc)
{
unit *u;
faction * f;
test_setup();
u = test_create_unit(f = test_create_faction(NULL), test_create_plain(0, 0));
u->thisorder = create_order(K_PASSWORD, f->locale, "abcdefgh");
password_cmd(u, u->thisorder);
CuAssertPtrNotNull(tc, faction_getpassword(f));
CuAssertTrue(tc, checkpasswd(f, "abcdefgh"));
CuAssertPtrNotNull(tc, test_find_messagetype(f->msgs, "changepasswd"));
free_order(u->thisorder);
u->thisorder = create_order(K_PASSWORD, f->locale, "abc*de*");
password_cmd(u, u->thisorder);
CuAssertPtrNotNull(tc, test_find_messagetype(f->msgs, "error283"));
CuAssertPtrNotNull(tc, test_find_messagetype(f->msgs, "changepasswd"));
CuAssertTrue(tc, !checkpasswd(f, "abc*de*"));
CuAssertTrue(tc, checkpasswd(f, "abcXdeX"));
free_order(u->thisorder);
u->thisorder = create_order(K_PASSWORD, f->locale, "1234567890123456789012345678901234567890");
password_cmd(u, u->thisorder);
CuAssertPtrNotNull(tc, test_find_messagetype(f->msgs, "error321"));
CuAssertPtrNotNull(tc, test_find_messagetype(f->msgs, "changepasswd"));
CuAssertTrue(tc, checkpasswd(f, "1234567890123456789012345678901"));
test_teardown();
}
static void test_rename_building(CuTest * tc) static void test_rename_building(CuTest * tc)
{ {
region *r; region *r;
@ -1831,6 +1862,7 @@ CuSuite *get_laws_suite(void)
SUITE_ADD_TEST(suite, test_long_order_buy_cast); SUITE_ADD_TEST(suite, test_long_order_buy_cast);
SUITE_ADD_TEST(suite, test_long_order_hungry); SUITE_ADD_TEST(suite, test_long_order_hungry);
SUITE_ADD_TEST(suite, test_new_building_can_be_renamed); SUITE_ADD_TEST(suite, test_new_building_can_be_renamed);
SUITE_ADD_TEST(suite, test_password_cmd);
SUITE_ADD_TEST(suite, test_rename_building); SUITE_ADD_TEST(suite, test_rename_building);
SUITE_ADD_TEST(suite, test_rename_building_twice); SUITE_ADD_TEST(suite, test_rename_building_twice);
SUITE_ADD_TEST(suite, test_fishing_feeds_2_people); SUITE_ADD_TEST(suite, test_fishing_feeds_2_people);

View file

@ -1334,7 +1334,6 @@ static void do_fumble(castorder * co)
int level = co->level; int level = co->level;
int duration; int duration;
double effect; double effect;
static const race *rc_toad;
static int rc_cache; static int rc_cache;
fumble_f fun; fumble_f fun;
@ -1359,6 +1358,7 @@ static void do_fumble(castorder * co)
* The list of things to happen are attached to a timeout * The list of things to happen are attached to a timeout
* trigger and that's added to the triggerlit of the mage gone toad. * trigger and that's added to the triggerlit of the mage gone toad.
*/ */
static const race *rc_toad;
trigger *trestore = trigger_changerace(mage, u_race(mage), mage->irace); trigger *trestore = trigger_changerace(mage, u_race(mage), mage->irace);
if (chance(0.7)) { if (chance(0.7)) {
const resource_type *rtype = rt_find("toadslime"); const resource_type *rtype = rt_find("toadslime");
@ -2090,7 +2090,7 @@ castorder *create_castorder(castorder * co, unit *caster, unit * familiar, const
co->sp = sp; co->sp = sp;
co->level = lev; co->level = lev;
co->force = MagicPower(force); co->force = MagicPower(force);
co->_rtarget = r ? r : (familiar ? familiar->region : (caster ? caster->region : 0)); co->_rtarget = r ? r : (familiar ? familiar->region : (caster ? caster->region : NULL));
co->distance = range; co->distance = range;
co->order = copy_order(ord); co->order = copy_order(ord);
co->par = p; co->par = p;
@ -2119,10 +2119,9 @@ void add_castorder(spellrank * cll, castorder * co)
void free_castorders(castorder * co) void free_castorders(castorder * co)
{ {
castorder *co2;
while (co) { while (co) {
co2 = co; castorder *co2 = co;
co = co->next; co = co->next;
free_castorder(co2); free_castorder(co2);
free(co2); free(co2);
@ -2202,15 +2201,14 @@ void remove_familiar(unit * mage)
{ {
attrib *a = a_find(mage->attribs, &at_familiar); attrib *a = a_find(mage->attribs, &at_familiar);
attrib *an; attrib *an;
skillmod_data *smd;
if (a != NULL) { if (a != NULL) {
a_remove(&mage->attribs, a); a_remove(&mage->attribs, a);
} }
a = a_find(mage->attribs, &at_skillmod); a = a_find(mage->attribs, &at_skillmod);
while (a && a->type == &at_skillmod) { while (a && a->type == &at_skillmod) {
skillmod_data *smd = (skillmod_data *)a->data.v;
an = a->next; an = a->next;
smd = (skillmod_data *)a->data.v;
if (smd->special == sm_familiar) { if (smd->special == sm_familiar) {
a_remove(&mage->attribs, a); a_remove(&mage->attribs, a);
} }

View file

@ -108,11 +108,11 @@ static const char * valid_keys[] = {
static dictionary *parse_config(const char *filename) static dictionary *parse_config(const char *filename)
{ {
char path[PATH_MAX];
dictionary *d; dictionary *d;
const char *str, *cfgpath = config_get("config.path"); const char *str, *cfgpath = config_get("config.path");
if (cfgpath) { if (cfgpath) {
char path[PATH_MAX];
path_join(cfgpath, filename, path, sizeof(path)); path_join(cfgpath, filename, path, sizeof(path));
log_debug("reading from configuration file %s\n", path); log_debug("reading from configuration file %s\n", path);
d = iniparser_load(path); d = iniparser_load(path);

View file

@ -549,15 +549,13 @@ int autoseed(newfaction ** players, int nsize, int max_agediff)
newfaction **nfp, *nextf = *players; newfaction **nfp, *nextf = *players;
faction *f; faction *f;
unit *u; unit *u;
const char * password;
isize += REGIONS_PER_FACTION; isize += REGIONS_PER_FACTION;
terraform_region(r, preferred_terrain(nextf->race)); terraform_region(r, preferred_terrain(nextf->race));
prepare_starting_region(r); prepare_starting_region(r);
++tsize; ++tsize;
assert(r->land && r->units == 0); assert(r->land && r->units == 0);
password = nextf->password ? nextf->password : itoa36(rng_int()); u = addplayer(r, addfaction(nextf->email, nextf->password, nextf->race,
u = addplayer(r, addfaction(nextf->email, password, nextf->race,
nextf->lang)); nextf->lang));
f = u->faction; f = u->faction;
fset(f, FFL_ISNEW); fset(f, FFL_ISNEW);
@ -857,8 +855,7 @@ static void starting_region(newfaction ** players, region * r, region * rn[])
newfaction *nf = *players; newfaction *nf = *players;
const struct race *rc = nf->race ? nf->race : races; const struct race *rc = nf->race ? nf->race : races;
const struct locale *lang = nf->lang ? nf->lang : default_locale; const struct locale *lang = nf->lang ? nf->lang : default_locale;
const char * passwd = nf->password ? nf->password : itoa36(rng_int()); addplayer(r, addfaction(nf->email, nf->password, rc, lang));
addplayer(r, addfaction(nf->email, passwd, rc, lang));
*players = nf->next; *players = nf->next;
free_newfaction(nf); free_newfaction(nf);
} }

View file

@ -637,6 +637,7 @@ void move_ship(ship * sh, region * from, region * to, region_list * route)
unit **iunit = &from->units; unit **iunit = &from->units;
unit **ulist = &to->units; unit **ulist = &to->units;
assert(sh);
if (from != to) { if (from != to) {
translist(&from->ships, &to->ships, sh); translist(&from->ships, &to->ships, sh);
sh->region = to; sh->region = to;
@ -1676,10 +1677,9 @@ static bool ship_ready(const region * r, unit * u, order * ord)
unit *owner_buildingtyp(const region * r, const building_type * bt) unit *owner_buildingtyp(const region * r, const building_type * bt)
{ {
building *b; building *b;
unit *owner;
for (b = rbuildings(r); b; b = b->next) { for (b = rbuildings(r); b; b = b->next) {
owner = building_owner(b); unit *owner = building_owner(b);
if (b->type == bt && owner != NULL) { if (b->type == bt && owner != NULL) {
if (building_finished(b)) { if (building_finished(b)) {
return owner; return owner;
@ -1971,7 +1971,7 @@ static void sail(unit * u, order * ord, region_list ** routep, bool drifting)
/* Hafengebühren ? */ /* Hafengebühren ? */
harbourmaster = owner_buildingtyp(current_point, bt_find("harbour")); harbourmaster = owner_buildingtyp(current_point, bt_find("harbour"));
if (sh && harbourmaster != NULL) { if (harbourmaster != NULL) {
item *itm; item *itm;
unit *u2; unit *u2;
item *trans = NULL; item *trans = NULL;
@ -2286,7 +2286,7 @@ int follow_ship(unit * u, order * ord)
} }
sbs_init(&sbcmd, command, sizeof(command)); sbs_init(&sbcmd, command, sizeof(command));
sbs_strcpy(&sbcmd, LOC(u->faction->locale, keyword(K_MOVE))); sbs_strcat(&sbcmd, LOC(u->faction->locale, keyword(K_MOVE)));
sbs_strcat(&sbcmd, " "); sbs_strcat(&sbcmd, " ");
sbs_strcat(&sbcmd, LOC(u->faction->locale, directions[dir])); sbs_strcat(&sbcmd, LOC(u->faction->locale, directions[dir]));

View file

@ -14,6 +14,7 @@
#include "util/filereader.h" #include "util/filereader.h"
#include "util/param.h" #include "util/param.h"
#include "util/parser.h" #include "util/parser.h"
#include "util/password.h"
#include "util/order_parser.h" #include "util/order_parser.h"
#include <assert.h> #include <assert.h>
@ -22,7 +23,7 @@
#include <string.h> #include <string.h>
static void begin_orders(unit *u) { static void begin_orders(unit *u) {
if (u->flags & UFL_ORDERS) { if ((u->flags & UFL_ORDERS) == 0) {
order **ordp; order **ordp;
/* alle wiederholbaren, langen befehle werden gesichert: */ /* alle wiederholbaren, langen befehle werden gesichert: */
u->flags |= UFL_ORDERS; u->flags |= UFL_ORDERS;
@ -47,13 +48,12 @@ static void begin_orders(unit *u) {
u->orders = NULL; u->orders = NULL;
} }
static unit *unitorders(input *in, faction *f) static void unitorders(input *in, faction *f)
{ {
int i; int i;
unit *u; unit *u;
if (!f) assert(f);
return NULL;
i = getid(); i = getid();
u = findunit(i); u = findunit(i);
@ -120,10 +120,6 @@ static unit *unitorders(input *in, faction *f)
} }
} }
else {
return NULL;
}
return u;
} }
static faction *factionorders(void) static faction *factionorders(void)
@ -132,7 +128,7 @@ static faction *factionorders(void)
faction *f = findfaction(fid); faction *f = findfaction(fid);
if (f != NULL && (f->flags & FFL_NPC) == 0) { if (f != NULL && (f->flags & FFL_NPC) == 0) {
char token[128]; char token[PASSWORD_MAXSIZE];
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)) {
@ -189,7 +185,8 @@ int read_orders(input *in)
* vermerkt. */ * vermerkt. */
case P_UNIT: case P_UNIT:
if (!f || !unitorders(in, f)) { if (f) {
unitorders(in, f);
do { do {
b = in->getbuf(in->data); b = in->getbuf(in->data);
if (!b) { if (!b) {
@ -278,7 +275,7 @@ static void handle_unit(void *userData, int no) {
static void handle_order(void *userData, const char *str) { static void handle_order(void *userData, const char *str) {
parser_state *state = (parser_state *)userData; parser_state *state = (parser_state *)userData;
const char * tok, *input = str; const char * tok, *input = str;
char buffer[16]; char buffer[64];
const struct locale *lang; const struct locale *lang;
param_t p; param_t p;
faction * f = state->f; faction * f = state->f;

View file

@ -3,9 +3,20 @@
#include "orderfile.h" #include "orderfile.h"
#include "direction.h"
#include <kernel/calendar.h> #include <kernel/calendar.h>
#include <kernel/faction.h> #include <kernel/faction.h>
#include <kernel/order.h>
#include <kernel/unit.h>
#include <util/base36.h>
#include <util/keyword.h>
#include <util/language.h>
#include <util/lists.h>
#include <util/message.h> #include <util/message.h>
#include <util/param.h>
#include <util/password.h>
#include <CuTest.h> #include <CuTest.h>
#include <tests.h> #include <tests.h>
@ -24,6 +35,52 @@ static void test_read_orders(CuTest *tc) {
test_teardown(); test_teardown();
} }
static const char *getbuf_strings(void *data)
{
strlist **listp = (strlist **)data;
if (listp && *listp) {
strlist *list = *listp;
*listp = list->next;
return list->s;
}
return NULL;
}
static void test_unit_orders(CuTest *tc) {
input in;
unit *u;
faction *f;
strlist *orders = NULL, *backup;
char buf[64];
test_setup();
u = test_create_unit(f = test_create_faction(NULL), test_create_plain(0, 0));
f->locale = test_create_locale();
u->orders = create_order(K_ENTERTAIN, f->locale, NULL);
faction_setpassword(f, password_hash("password", PASSWORD_DEFAULT));
snprintf(buf, sizeof(buf), "%s %s %s",
LOC(f->locale, parameters[P_FACTION]), itoa36(f->no), "password");
addstrlist(&orders, buf);
snprintf(buf, sizeof(buf), "%s %s",
LOC(f->locale, parameters[P_UNIT]), itoa36(u->no));
addstrlist(&orders, buf);
snprintf(buf, sizeof(buf), "%s %s", keyword_name(K_MOVE, f->locale),
LOC(f->locale, shortdirections[D_WEST]));
backup = orders;
addstrlist(&orders, buf);
in.data = &orders;
in.getbuf = getbuf_strings;
CuAssertIntEquals(tc, 0, read_orders(&in));
CuAssertPtrNotNull(tc, u->old_orders);
CuAssertPtrNotNull(tc, u->orders);
CuAssertPtrEquals(tc, NULL, orders);
CuAssertIntEquals(tc, K_MOVE, getkeyword(u->orders));
CuAssertIntEquals(tc, K_ENTERTAIN, getkeyword(u->old_orders));
CuAssertIntEquals(tc, UFL_ORDERS, u->flags & UFL_ORDERS);
freestrlist(backup);
test_teardown();
}
typedef struct order_list { typedef struct order_list {
const char **orders; const char **orders;
int next; int next;
@ -85,6 +142,7 @@ CuSuite *get_orderfile_suite(void)
{ {
CuSuite *suite = CuSuiteNew(); CuSuite *suite = CuSuiteNew();
SUITE_ADD_TEST(suite, test_read_orders); SUITE_ADD_TEST(suite, test_read_orders);
SUITE_ADD_TEST(suite, test_unit_orders);
SUITE_ADD_TEST(suite, test_faction_password_okay); SUITE_ADD_TEST(suite, test_faction_password_okay);
SUITE_ADD_TEST(suite, test_faction_password_bad); SUITE_ADD_TEST(suite, test_faction_password_bad);

View file

@ -79,7 +79,6 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
/* util includes */ /* util includes */
#include <util/base36.h> #include <util/base36.h>
#include "util/bsdstring.h"
#include <util/goodies.h> #include <util/goodies.h>
#include <util/language.h> #include <util/language.h>
#include <util/lists.h> #include <util/lists.h>
@ -170,9 +169,8 @@ static void centre(struct stream *out, const char *s, bool breaking)
} }
} }
static void void paragraph(struct stream *out, const char *str, ptrdiff_t indent,
paragraph(struct stream *out, const char *str, ptrdiff_t indent, int hanging_indent, int hanging_indent, char marker)
char marker)
{ {
size_t length = REPORTWIDTH; size_t length = REPORTWIDTH;
const char *handle_end, *begin, *mark = 0; const char *handle_end, *begin, *mark = 0;
@ -257,10 +255,10 @@ void nr_spell_syntax(char *buf, size_t size, spellbook_entry * sbe, const struct
sbs_init(&sbs, buf, size); sbs_init(&sbs, buf, size);
if (sp->sptyp & ISCOMBATSPELL) { if (sp->sptyp & ISCOMBATSPELL) {
sbs_strcpy(&sbs, LOC(lang, keyword(K_COMBATSPELL))); sbs_strcat(&sbs, LOC(lang, keyword(K_COMBATSPELL)));
} }
else { else {
sbs_strcpy(&sbs, LOC(lang, keyword(K_CAST))); sbs_strcat(&sbs, LOC(lang, keyword(K_CAST)));
} }
/* Reihenfolge beachten: Erst REGION, dann STUFE! */ /* Reihenfolge beachten: Erst REGION, dann STUFE! */
@ -434,7 +432,7 @@ void nr_spell_syntax(char *buf, size_t size, spellbook_entry * sbe, const struct
void nr_spell(struct stream *out, spellbook_entry * sbe, const struct locale *lang) void nr_spell(struct stream *out, spellbook_entry * sbe, const struct locale *lang)
{ {
int k, itemanz, costtyp; int k;
bool cont; bool cont;
char buf[4096]; char buf[4096];
const spell *sp = spellref_get(&sbe->spref); const spell *sp = spellref_get(&sbe->spref);
@ -473,8 +471,8 @@ void nr_spell(struct stream *out, spellbook_entry * sbe, const struct locale *la
paragraph(out, LOC(lang, "nr_spell_components"), 0, 0, 0); paragraph(out, LOC(lang, "nr_spell_components"), 0, 0, 0);
for (k = 0; sp->components[k].type; ++k) { for (k = 0; sp->components[k].type; ++k) {
const resource_type *rtype = sp->components[k].type; const resource_type *rtype = sp->components[k].type;
itemanz = sp->components[k].amount; int itemanz = sp->components[k].amount;
costtyp = sp->components[k].cost; int costtyp = sp->components[k].cost;
if (itemanz > 0) { if (itemanz > 0) {
sbs_init(&sbs, buf, sizeof(buf)); sbs_init(&sbs, buf, sizeof(buf));
if (sp->sptyp & SPELLLEVEL) { if (sp->sptyp & SPELLLEVEL) {
@ -521,7 +519,6 @@ static void
nr_curses_i(struct stream *out, int indent, const faction *viewer, objtype_t typ, const void *obj, attrib *a, int self) nr_curses_i(struct stream *out, int indent, const faction *viewer, objtype_t typ, const void *obj, attrib *a, int self)
{ {
for (; a; a = a->next) { for (; a; a = a->next) {
char buf[4096];
message *msg = 0; message *msg = 0;
if (a->type == &at_curse) { if (a->type == &at_curse) {
@ -538,6 +535,7 @@ nr_curses_i(struct stream *out, int indent, const faction *viewer, objtype_t typ
} }
} }
if (msg) { if (msg) {
char buf[4096];
newline(out); newline(out);
nr_render(msg, viewer->locale, buf, sizeof(buf), viewer); nr_render(msg, viewer->locale, buf, sizeof(buf), viewer);
paragraph(out, buf, indent, 2, 0); paragraph(out, buf, indent, 2, 0);
@ -849,7 +847,6 @@ static void report_region_resource(sbstring *sbp, const struct locale *lang, con
static void report_region_description(struct stream *out, const region * r, faction * f, const bool see[]) static void report_region_description(struct stream *out, const region * r, faction * f, const bool see[])
{ {
int n; int n;
bool dh;
int trees; int trees;
int saplings; int saplings;
attrib *a; attrib *a;
@ -988,6 +985,7 @@ static void report_region_description(struct stream *out, const region * r, fact
} }
else { else {
int d, nrd = 0; int d, nrd = 0;
bool dh = false;
/* Nachbarregionen, die gesehen werden, ermitteln */ /* Nachbarregionen, die gesehen werden, ermitteln */
for (d = 0; d != MAXDIRECTIONS; d++) { for (d = 0; d != MAXDIRECTIONS; d++) {
@ -996,7 +994,6 @@ static void report_region_description(struct stream *out, const region * r, fact
} }
/* list directions */ /* list directions */
dh = false;
for (d = 0; d != MAXDIRECTIONS; d++) { for (d = 0; d != MAXDIRECTIONS; d++) {
if (see[d]) { if (see[d]) {
region *r2 = rconnect(r, d); region *r2 = rconnect(r, d);
@ -1039,7 +1036,6 @@ static void report_region_description(struct stream *out, const region * r, fact
sbs_strcat(&sbs, " (\""); sbs_strcat(&sbs, " (\"");
sbs_strcat(&sbs, LOC(f->locale, spd->keyword)); sbs_strcat(&sbs, LOC(f->locale, spd->keyword));
sbs_strcat(&sbs, "\")."); sbs_strcat(&sbs, "\").");
dh = 1;
} }
} }
pump_paragraph(&sbs, out, REPORTWIDTH, true); pump_paragraph(&sbs, out, REPORTWIDTH, true);
@ -1431,6 +1427,7 @@ void pump_paragraph(sbstring *sbp, stream *out, size_t maxlen, bool isfinal)
{ {
while (sbs_length(sbp) > maxlen) { while (sbs_length(sbp) > maxlen) {
char *pos, *begin = sbp->begin; char *pos, *begin = sbp->begin;
assert(begin);
while (*begin && IS_UTF8_SPACE(begin)) { while (*begin && IS_UTF8_SPACE(begin)) {
/* eat whitespace */ /* eat whitespace */
++begin; ++begin;
@ -1440,7 +1437,12 @@ void pump_paragraph(sbstring *sbp, stream *out, size_t maxlen, bool isfinal)
char *next = strchr(pos+1, ' '); char *next = strchr(pos+1, ' ');
if (next == NULL) { if (next == NULL) {
if (isfinal) { if (isfinal) {
swrite(begin, 1, sbp->end - begin, out); swrite(begin, 1, pos - begin, out);
while (*pos && IS_UTF8_SPACE(pos)) {
++pos;
}
newline(out);
swrite(pos, 1, sbp->end - pos, out);
newline(out); newline(out);
} }
return; return;
@ -1619,41 +1621,32 @@ static void guards(struct stream *out, const region * r, const faction * see)
} }
if (nextguard || tarned) { if (nextguard || tarned) {
char buf[8192]; char buf[2048];
char *bufp = buf; sbstring sbs;
size_t size = sizeof(buf) - 1;
int bytes;
bytes = (int)str_strlcpy(bufp, LOC(see->locale, "nr_guarding_prefix"), size); sbs_init(&sbs, buf, sizeof(buf));
if (wrptr(&bufp, &size, bytes) != 0) sbs_strcat(&sbs, LOC(see->locale, "nr_guarding_prefix"));
WARN_STATIC_BUFFER();
for (i = 0; i != nextguard + (tarned ? 1 : 0); ++i) { for (i = 0; i != nextguard + (tarned ? 1 : 0); ++i) {
if (i != 0) { if (i != 0) {
if (i == nextguard - (tarned ? 0 : 1)) { if (i == nextguard - (tarned ? 0 : 1)) {
bytes = (int)str_strlcpy(bufp, LOC(see->locale, "list_and"), size); sbs_strcat(&sbs, LOC(see->locale, "list_and"));
} }
else { else {
bytes = (int)str_strlcpy(bufp, ", ", size); sbs_strcat(&sbs, ", ");
} }
if (wrptr(&bufp, &size, bytes) != 0)
WARN_STATIC_BUFFER();
} }
if (i < nextguard) { if (i < nextguard) {
bytes = (int)str_strlcpy(bufp, factionname(guardians[i]), size); sbs_strcat(&sbs, factionname(guardians[i]));
} }
else { else {
bytes = (int)str_strlcpy(bufp, LOC(see->locale, "nr_guarding_unknown"), size); sbs_strcat(&sbs, LOC(see->locale, "nr_guarding_unknown"));
} }
if (wrptr(&bufp, &size, bytes) != 0) pump_paragraph(&sbs, out, REPORTWIDTH, false);
WARN_STATIC_BUFFER();
} }
bytes = (int)str_strlcpy(bufp, LOC(see->locale, "nr_guarding_postfix"), size); sbs_strcat(&sbs, LOC(see->locale, "nr_guarding_postfix"));
if (wrptr(&bufp, &size, bytes) != 0)
WARN_STATIC_BUFFER();
newline(out); newline(out);
*bufp = 0; pump_paragraph(&sbs, out, REPORTWIDTH, true);
paragraph(out, buf, 0, 0, 0);
} }
} }
@ -1704,11 +1697,11 @@ static void
nr_ship(struct stream *out, const region *r, const ship * sh, const faction * f, nr_ship(struct stream *out, const region *r, const ship * sh, const faction * f,
const unit * captain) const unit * captain)
{ {
char buffer[8192], *bufp = buffer; char buffer[1024];
size_t size = sizeof(buffer) - 1;
int bytes;
char ch; char ch;
sbstring sbs;
sbs_init(&sbs, buffer, sizeof(buffer));
newline(out); newline(out);
if (captain && captain->faction == f) { if (captain && captain->faction == f) {
@ -1716,57 +1709,37 @@ nr_ship(struct stream *out, const region *r, const ship * sh, const faction * f,
getshipweight(sh, &n, &p); getshipweight(sh, &n, &p);
n = (n + 99) / 100; /* 1 Silber = 1 GE */ n = (n + 99) / 100; /* 1 Silber = 1 GE */
bytes = snprintf(bufp, size, "%s, %s, (%d/%d)", shipname(sh), sbs_printf(&sbs, "%s, %s, (%d/%d)", shipname(sh),
LOC(f->locale, sh->type->_name), n, shipcapacity(sh) / 100); LOC(f->locale, sh->type->_name), n, shipcapacity(sh) / 100);
} }
else { else {
bytes = sbs_printf(&sbs, "%s, %s", shipname(sh), LOC(f->locale, sh->type->_name));
snprintf(bufp, size, "%s, %s", shipname(sh), LOC(f->locale,
sh->type->_name));
} }
if (wrptr(&bufp, &size, bytes) != 0)
WARN_STATIC_BUFFER();
if (sh->size != sh->type->construction->maxsize) { if (sh->size != sh->type->construction->maxsize) {
bytes = snprintf(bufp, size, ", %s (%d/%d)", sbs_printf(&sbs, ", %s (%d/%d)",
LOC(f->locale, "nr_undercons"), sh->size, LOC(f->locale, "nr_undercons"), sh->size,
sh->type->construction->maxsize); sh->type->construction->maxsize);
if (wrptr(&bufp, &size, bytes) != 0)
WARN_STATIC_BUFFER();
} }
if (sh->damage) { if (sh->damage) {
int percent = ship_damage_percent(sh); int percent = ship_damage_percent(sh);
bytes = sbs_printf(&sbs, ", %d%% %s", percent, LOC(f->locale, "nr_damaged"));
snprintf(bufp, size, ", %d%% %s", percent, LOC(f->locale, "nr_damaged"));
if (wrptr(&bufp, &size, bytes) != 0)
WARN_STATIC_BUFFER();
} }
if (!fval(r->terrain, SEA_REGION)) { if (!fval(r->terrain, SEA_REGION)) {
if (sh->coast != NODIRECTION) { if (sh->coast != NODIRECTION) {
bytes = (int)str_strlcpy(bufp, ", ", size); sbs_strcat(&sbs, ", ");
if (wrptr(&bufp, &size, bytes) != 0) sbs_strcat(&sbs, LOC(f->locale, coasts[sh->coast]));
WARN_STATIC_BUFFER();
bytes = (int)str_strlcpy(bufp, LOC(f->locale, coasts[sh->coast]), size);
if (wrptr(&bufp, &size, bytes) != 0)
WARN_STATIC_BUFFER();
} }
} }
ch = 0; ch = 0;
if (sh->display && sh->display[0]) { if (sh->display && sh->display[0]) {
bytes = (int)str_strlcpy(bufp, "; ", size); sbs_strcat(&sbs, "; ");
if (wrptr(&bufp, &size, bytes) != 0) sbs_strcat(&sbs, sh->display);
WARN_STATIC_BUFFER();
bytes = (int)str_strlcpy(bufp, sh->display, size);
if (wrptr(&bufp, &size, bytes) != 0)
WARN_STATIC_BUFFER();
ch = sh->display[strlen(sh->display) - 1]; ch = sh->display[strlen(sh->display) - 1];
} }
if (ch != '!' && ch != '?' && ch != '.') { if (ch != '!' && ch != '?' && ch != '.') {
bytes = (int)str_strlcpy(bufp, ".", size); sbs_strcat(&sbs, ".");
if (wrptr(&bufp, &size, bytes) != 0)
WARN_STATIC_BUFFER();
} }
*bufp = 0;
paragraph(out, buffer, 2, 0, 0); paragraph(out, buffer, 2, 0, 0);
nr_curses(out, 4, f, TYP_SHIP, sh); nr_curses(out, 4, f, TYP_SHIP, sh);
@ -1914,7 +1887,6 @@ static void cb_write_travelthru(region *r, unit *u, void *cbdata) {
void report_travelthru(struct stream *out, region *r, const faction *f) void report_travelthru(struct stream *out, region *r, const faction *f)
{ {
int maxtravel; int maxtravel;
char buf[8192];
assert(r); assert(r);
assert(f); assert(f);
@ -1926,6 +1898,7 @@ void report_travelthru(struct stream *out, region *r, const faction *f)
maxtravel = count_travelthru(r, f); maxtravel = count_travelthru(r, f);
if (maxtravel > 0) { if (maxtravel > 0) {
cb_data cbdata; cb_data cbdata;
char buf[8192];
init_cb(&cbdata, out, buf, sizeof(buf), f); init_cb(&cbdata, out, buf, sizeof(buf), f);
cbdata.maxtravel = maxtravel; cbdata.maxtravel = maxtravel;
@ -1985,12 +1958,11 @@ report_plaintext(const char *filename, report_context * ctx,
if (f->age <= 2) { if (f->age <= 2) {
const char *email; const char *email;
const char *subject;
email = config_get("game.email"); email = config_get("game.email");
if (!email) if (!email)
log_error("game.email not set"); log_error("game.email not set");
else { else {
subject = get_mailcmd(f->locale); const char *subject = get_mailcmd(f->locale);
m = msg_message("newbie_info_game", "email subject", email, subject); m = msg_message("newbie_info_game", "email subject", email, subject);
if (m) { if (m) {
@ -2093,9 +2065,9 @@ report_plaintext(const char *filename, report_context * ctx,
for (a = a_find(f->attribs, &at_showitem); a && a->type == &at_showitem; for (a = a_find(f->attribs, &at_showitem); a && a->type == &at_showitem;
a = a->next) { a = a->next) {
const item_type *itype = (const item_type *)a->data.v; const item_type *itype = (const item_type *)a->data.v;
const char *description = NULL;
if (itype) { if (itype) {
const char *pname = resourcename(itype->rtype, 0); const char *pname = resourcename(itype->rtype, 0);
const char *description;
if (ch == 0) { if (ch == 0) {
newline(out); newline(out);
@ -2127,8 +2099,7 @@ report_plaintext(const char *filename, report_context * ctx,
} }
centre(out, buf, true); centre(out, buf, true);
newline(out); newline(out);
description = mkname("describe", pname); description = LOC(f->locale, mkname("describe", pname));
description = LOC(f->locale, description);
centre(out, description, true); centre(out, description, true);
} }
} }

View file

@ -35,6 +35,7 @@ extern "C" {
void report_region(struct stream *out, const struct region * r, struct faction * f); void report_region(struct stream *out, const struct region * r, struct faction * f);
void report_allies(struct stream *out, size_t maxlen, const struct faction * f, struct allies * allies, const char *prefix); void report_allies(struct stream *out, size_t maxlen, const struct faction * f, struct allies * allies, const char *prefix);
void pump_paragraph(struct sbstring *sbp, struct stream *out, size_t maxlen, bool isfinal); void pump_paragraph(struct sbstring *sbp, struct stream *out, size_t maxlen, bool isfinal);
void paragraph(struct stream *out, const char *str, ptrdiff_t indent, int hanging_indent, char marker);
void nr_spell_syntax(char *buf, size_t size, struct spellbook_entry * sbe, const struct locale *lang); void nr_spell_syntax(char *buf, size_t size, struct spellbook_entry * sbe, const struct locale *lang);
void nr_spell(struct stream *out, struct spellbook_entry * sbe, const struct locale *lang); void nr_spell(struct stream *out, struct spellbook_entry * sbe, const struct locale *lang);

View file

@ -379,11 +379,66 @@ static void test_write_spell_syntax(CuTest *tc) {
test_teardown(); test_teardown();
} }
static void test_paragraph(CuTest *tc) {
const char *toolong = "im Westen das Hochland von Geraldin (93,-303).";
const char *expect = "im Westen das Hochland von Geraldin (93,-303).\n";
char buf[256];
stream out = { 0 };
size_t len;
mstream_init(&out);
paragraph(&out, toolong, 0, 0, 0);
out.api->rewind(out.handle);
len = out.api->read(out.handle, buf, sizeof(buf));
buf[len] = '\0';
CuAssertStrEquals(tc, expect, buf);
}
static void test_paragraph_break(CuTest *tc) {
const char *toolong = "die Ebene von Godsettova (94,-304) und im Westen das Hochland von Geraldin (93,-303).";
const char *expect = "die Ebene von Godsettova (94,-304) und im Westen das Hochland von Geraldin\n(93,-303).\n";
char buf[256];
stream out = { 0 };
size_t len;
mstream_init(&out);
paragraph(&out, toolong, 0, 0, 0);
out.api->rewind(out.handle);
len = out.api->read(out.handle, buf, sizeof(buf));
buf[len] = '\0';
CuAssertStrEquals(tc, expect, buf);
}
static void test_pump_paragraph_toolong(CuTest *tc) {
const char *toolong = "die Ebene von Godsettova (94,-304) und im Westen das Hochland von Geraldin (93,-303).";
const char *expect = "die Ebene von Godsettova (94,-304) und im Westen das Hochland von Geraldin\n(93,-303).\n";
sbstring sbs;
char buf[256];
stream out = { 0 };
size_t len;
mstream_init(&out);
sbs_init(&sbs, buf, sizeof(buf));
sbs_strcat(&sbs, toolong);
pump_paragraph(&sbs, &out, 78, true);
out.api->rewind(out.handle);
len = out.api->read(out.handle, buf, sizeof(buf));
buf[len] = '\0';
CuAssertStrEquals(tc, expect, buf);
}
CuSuite *get_report_suite(void) CuSuite *get_report_suite(void)
{ {
CuSuite *suite = CuSuiteNew(); CuSuite *suite = CuSuiteNew();
SUITE_ADD_TEST(suite, test_write_spaces); SUITE_ADD_TEST(suite, test_write_spaces);
SUITE_ADD_TEST(suite, test_write_many_spaces); SUITE_ADD_TEST(suite, test_write_many_spaces);
SUITE_ADD_TEST(suite, test_paragraph);
SUITE_ADD_TEST(suite, test_paragraph_break);
SUITE_ADD_TEST(suite, test_pump_paragraph_toolong);
SUITE_ADD_TEST(suite, test_report_travelthru); SUITE_ADD_TEST(suite, test_report_travelthru);
SUITE_ADD_TEST(suite, test_report_region); SUITE_ADD_TEST(suite, test_report_region);
SUITE_ADD_TEST(suite, test_report_allies); SUITE_ADD_TEST(suite, test_report_allies);

View file

@ -319,11 +319,11 @@ report_items(const unit *u, item * result, int size, const unit * owner,
} }
} }
for (itm = items; itm; itm = itm->next) { for (itm = items; itm; itm = itm->next) {
item *ishow;
const char *ic; const char *ic;
report_item(owner, itm, viewer, NULL, &ic, NULL, false); report_item(owner, itm, viewer, NULL, &ic, NULL, false);
if (ic && *ic) { if (ic && *ic) {
item *ishow;
for (ishow = result; ishow != result + n; ++ishow) { for (ishow = result; ishow != result + n; ++ishow) {
const char *sc; const char *sc;
@ -714,7 +714,8 @@ void bufunit(const faction * f, const unit * u, const faction *fv,
pzTmp = get_racename(u->attribs); pzTmp = get_racename(u->attribs);
if (pzTmp) { if (pzTmp) {
sbs_strcat(sbp, pzTmp); const char *name = LOC(lang, mkname("race", pzTmp));
sbs_strcat(sbp, name ? name : pzTmp);
if (u->faction == f && fval(u_race(u), RCF_SHAPESHIFTANY)) { if (u->faction == f && fval(u_race(u), RCF_SHAPESHIFTANY)) {
sbs_strcat(sbp, " ("); sbs_strcat(sbp, " (");
sbs_strcat(sbp, racename(lang, u, u_race(u))); sbs_strcat(sbp, racename(lang, u, u_race(u)));
@ -811,19 +812,14 @@ void bufunit(const faction * f, const unit * u, const faction *fv,
if (book) { if (book) {
selist *ql = book->spells; selist *ql = book->spells;
int qi, header, maxlevel = effskill(u, SK_MAGIC, 0); int qi, header, maxlevel = effskill(u, SK_MAGIC, 0);
sbs_strcat(sbp, ". Aura "); sbs_printf(sbp, ". Aura %d/%d", get_spellpoints(u), max_spellpoints(u, NULL));
sbs_strcat(sbp, str_itoa(get_spellpoints(u)));
sbs_strcat(sbp, "/");
sbs_strcat(sbp, str_itoa(max_spellpoints(u, NULL)));
for (header = 0, qi = 0; ql; selist_advance(&ql, &qi, 1)) { for (header = 0, qi = 0; ql; selist_advance(&ql, &qi, 1)) {
spellbook_entry * sbe = (spellbook_entry *)selist_get(ql, qi); spellbook_entry * sbe = (spellbook_entry *)selist_get(ql, qi);
const spell *sp = spellref_get(&sbe->spref); const spell *sp = spellref_get(&sbe->spref);
if (sbe->level <= maxlevel) { if (sbe->level <= maxlevel) {
if (!header) { if (!header) {
sbs_strcat(sbp, ", "); sbs_printf(sbp, ", %s: ", LOC(lang, "nr_spells"));
sbs_strcat(sbp, LOC(lang, "nr_spells"));
sbs_strcat(sbp, ": ");
header = 1; header = 1;
} }
else { else {
@ -839,9 +835,7 @@ void bufunit(const faction * f, const unit * u, const faction *fv,
break; break;
} }
if (i != MAXCOMBATSPELLS) { if (i != MAXCOMBATSPELLS) {
sbs_strcat(sbp, ", "); sbs_printf(sbp, ", %s: ", LOC(lang, "nr_combatspells"));
sbs_strcat(sbp, LOC(lang, "nr_combatspells"));
sbs_strcat(sbp, ": ");
dh = 0; dh = 0;
for (i = 0; i < MAXCOMBATSPELLS; i++) { for (i = 0; i < MAXCOMBATSPELLS; i++) {
const spell *sp; const spell *sp;
@ -856,9 +850,7 @@ void bufunit(const faction * f, const unit * u, const faction *fv,
int sl = get_combatspelllevel(u, i); int sl = get_combatspelllevel(u, i);
sbs_strcat(sbp, spell_name(sp, lang)); sbs_strcat(sbp, spell_name(sp, lang));
if (sl > 0) { if (sl > 0) {
sbs_strcat(sbp, "( "); sbs_printf(sbp, "(%d)", sl);
sbs_strcat(sbp, str_itoa(sl));
sbs_strcat(sbp, ")");
} }
} }
else { else {
@ -1606,6 +1598,9 @@ int write_reports(faction * f)
if (noreports) { if (noreports) {
return false; return false;
} }
if (f->lastorders == 0) {
faction_genpassword(f);
}
prepare_report(&ctx, f); prepare_report(&ctx, f);
get_addresses(&ctx); get_addresses(&ctx);
log_debug("Reports for %s", factionname(f)); log_debug("Reports for %s", factionname(f));
@ -1788,9 +1783,9 @@ static void var_free_regions(variant x) /*-V524 */
const char *trailinto(const region * r, const struct locale *lang) const char *trailinto(const region * r, const struct locale *lang)
{ {
static char ref[32];
const char *s;
if (r) { if (r) {
static char ref[32];
const char *s;
const char *tname = terrain_name(r); const char *tname = terrain_name(r);
size_t sz; size_t sz;
@ -2238,7 +2233,6 @@ static void eval_trail(struct opstack **stack, const void *userdata)
handle_end = aregs->nregions; handle_end = aregs->nregions;
for (i = begin; i < handle_end; ++i) { for (i = begin; i < handle_end; ++i) {
region *r = aregs->regions[i]; region *r = aregs->regions[i];
sbs_strcat(&sbs, ", ");
print_trail(report, r, lang, &sbs); print_trail(report, r, lang, &sbs);

View file

@ -16,6 +16,7 @@
#include "kernel/building.h" #include "kernel/building.h"
#include "kernel/faction.h" #include "kernel/faction.h"
#include "kernel/item.h" #include "kernel/item.h"
#include "kernel/messages.h"
#include "kernel/race.h" #include "kernel/race.h"
#include "kernel/region.h" #include "kernel/region.h"
#include "kernel/ship.h" #include "kernel/ship.h"
@ -29,6 +30,7 @@
#include "util/language.h" #include "util/language.h"
#include "util/lists.h" #include "util/lists.h"
#include "util/message.h" #include "util/message.h"
#include "util/nrmessage.h"
#include "attributes/attributes.h" #include "attributes/attributes.h"
#include "attributes/key.h" #include "attributes/key.h"
@ -599,14 +601,14 @@ static void test_prepare_lighthouse_owners(CuTest *tc)
f = test_create_faction(NULL); f = test_create_faction(NULL);
r1 = test_create_region(0, 0, t_plain); r1 = test_create_region(0, 0, t_plain);
r2 = test_create_region(1, 0, t_ocean); r2 = test_create_region(1, 0, t_ocean);
r3 = test_create_region(2, 0, t_ocean); test_create_region(2, 0, t_ocean);
r3 = test_create_region(3, 0, t_ocean); r3 = test_create_region(3, 0, t_ocean);
btype = test_create_buildingtype("lighthouse"); btype = test_create_buildingtype("lighthouse");
b = test_create_building(r1, btype); b = test_create_building(r1, btype);
b->flags |= BLD_MAINTAINED; b->flags |= BLD_MAINTAINED;
b->size = 10; b->size = 10;
update_lighthouse(b); update_lighthouse(b);
u = test_create_unit(f, r1); test_create_unit(f, r1);
u = test_create_unit(test_create_faction(NULL), r1); u = test_create_unit(test_create_faction(NULL), r1);
u->building = b; u->building = b;
region_set_owner(b->region, f, 0); region_set_owner(b->region, f, 0);
@ -906,6 +908,68 @@ static void test_visible_unit(CuTest *tc) {
test_teardown(); test_teardown();
} }
static void test_eval_functions(CuTest *tc)
{
message *msg;
message_type *mtype;
item *items = NULL;
char buf[1024];
struct locale * lang;
test_setup();
init_resources();
test_create_itemtype("stone");
test_create_itemtype("iron");
lang = test_create_locale();
locale_setstring(lang, "nr_claims", "$resources($items)");
register_reports();
mtype = mt_create_va(mt_new("nr_claims", NULL), "items:items", MT_NEW_END);
nrt_register(mtype);
msg = msg_message("nr_claims", "items", items);
nr_render(msg, lang, buf, sizeof(buf), NULL);
CuAssertStrEquals(tc, "", buf);
msg_release(msg);
i_change(&items, get_resourcetype(R_IRON)->itype, 1);
msg = msg_message("nr_claims", "items", items);
nr_render(msg, lang, buf, sizeof(buf), NULL);
CuAssertStrEquals(tc, "1 Eisen", buf);
msg_release(msg);
i_change(&items, get_resourcetype(R_STONE)->itype, 2);
msg = msg_message("nr_claims", "items", items);
nr_render(msg, lang, buf, sizeof(buf), NULL);
CuAssertStrEquals(tc, "1 Eisen, 2 Steine", buf);
msg_release(msg);
i_freeall(&items);
test_teardown();
}
static void test_reports_genpassword(CuTest *tc) {
faction *f;
int pwid;
test_setup();
mt_create_va(mt_new("changepasswd", NULL), "value:string", MT_NEW_END);
f = test_create_faction(NULL);
CuAssertIntEquals(tc, 0, f->lastorders);
CuAssertIntEquals(tc, 0, f->password_id);
f->options = 0;
write_reports(f);
CuAssertPtrNotNull(tc, test_find_messagetype(f->msgs, "changepasswd"));
CuAssertTrue(tc, f->password_id != 0);
test_clear_messagelist(&f->msgs);
f->lastorders = 1;
pwid = f->password_id;
write_reports(f);
CuAssertIntEquals(tc, pwid, f->password_id);
CuAssertPtrEquals(tc, NULL, test_find_messagetype(f->msgs, "changepasswd"));
test_teardown();
}
CuSuite *get_reports_suite(void) CuSuite *get_reports_suite(void)
{ {
CuSuite *suite = CuSuiteNew(); CuSuite *suite = CuSuiteNew();
@ -936,5 +1000,7 @@ CuSuite *get_reports_suite(void)
SUITE_ADD_TEST(suite, test_insect_warnings); SUITE_ADD_TEST(suite, test_insect_warnings);
SUITE_ADD_TEST(suite, test_newbie_warning); SUITE_ADD_TEST(suite, test_newbie_warning);
SUITE_ADD_TEST(suite, test_visible_unit); SUITE_ADD_TEST(suite, test_visible_unit);
SUITE_ADD_TEST(suite, test_eval_functions);
SUITE_ADD_TEST(suite, test_reports_genpassword);
return suite; return suite;
} }

View file

@ -94,9 +94,9 @@ skill_t findskill(const char *name)
skill_t get_skill(const char *s, const struct locale * lang) skill_t get_skill(const char *s, const struct locale * lang)
{ {
skill_t result = NOSKILL; skill_t result = NOSKILL;
char buffer[64];
if (s) { if (s) {
char buffer[64];
char * str = transliterate(buffer, sizeof(buffer) - sizeof(int), s); char * str = transliterate(buffer, sizeof(buffer) - sizeof(int), s);
if (str) { if (str) {
int i; int i;

View file

@ -2346,7 +2346,6 @@ static int sp_earthquake(castorder * co)
static void patzer_peasantmob(const castorder * co) static void patzer_peasantmob(const castorder * co)
{ {
unit *u; unit *u;
attrib *a;
region *r; region *r;
unit *mage = co_get_magician(co); unit *mage = co_get_magician(co);
r = mage->region->land ? mage->region : co_get_region(co); r = mage->region->land ? mage->region : co_get_region(co);
@ -2355,6 +2354,7 @@ static void patzer_peasantmob(const castorder * co)
faction *f = get_monsters(); faction *f = get_monsters();
const struct locale *lang = f->locale; const struct locale *lang = f->locale;
message *msg; message *msg;
attrib *a;
int anteil, n; int anteil, n;
anteil = 6 + rng_int() % 4; anteil = 6 + rng_int() % 4;
@ -2410,7 +2410,6 @@ static void patzer_peasantmob(const castorder * co)
static int sp_forest_fire(castorder * co) static int sp_forest_fire(castorder * co)
{ {
unit *u; unit *u;
region *nr;
direction_t i; direction_t i;
region *r = co_get_region(co); region *r = co_get_region(co);
unit *caster = co_get_caster(co); unit *caster = co_get_caster(co);
@ -2442,7 +2441,7 @@ static int sp_forest_fire(castorder * co)
msg_release(msg); msg_release(msg);
for (i = 0; i < MAXDIRECTIONS; i++) { for (i = 0; i < MAXDIRECTIONS; i++) {
nr = rconnect(r, i); region *nr = rconnect(r, i);
assert(nr); assert(nr);
destroyed = 0; destroyed = 0;
vernichtet_schoesslinge = 0; vernichtet_schoesslinge = 0;
@ -5629,7 +5628,6 @@ int sp_disruptastral(castorder * co)
attrib *a; attrib *a;
double effect; double effect;
region *r2 = rl2->data; region *r2 = rl2->data;
spec_direction *sd;
int inhab_regions = 0; int inhab_regions = 0;
region_list *trl = NULL; region_list *trl = NULL;
@ -5649,7 +5647,7 @@ int sp_disruptastral(castorder * co)
while (a != NULL && a->type == &at_direction) { while (a != NULL && a->type == &at_direction) {
attrib *a2 = a->next; attrib *a2 = a->next;
sd = (spec_direction *)(a->data.v); spec_direction *sd = (spec_direction *)(a->data.v);
if (sd->duration != -1) if (sd->duration != -1)
a_remove(&r->attribs, a); a_remove(&r->attribs, a);
a = a2; a = a2;
@ -6161,7 +6159,6 @@ int sp_speed2(castorder * co)
*/ */
int sp_break_curse(castorder * co) int sp_break_curse(castorder * co)
{ {
attrib **ap;
int obj; int obj;
curse *c; curse *c;
region *r = co_get_region(co); region *r = co_get_region(co);
@ -6169,7 +6166,6 @@ int sp_break_curse(castorder * co)
int cast_level = co->level; int cast_level = co->level;
double force = co->force; double force = co->force;
spellparameter *pa = co->par; spellparameter *pa = co->par;
const char *ts = NULL;
if (pa->length < 2) { if (pa->length < 2) {
/* Das Zielobjekt wurde vergessen */ /* Das Zielobjekt wurde vergessen */
@ -6186,6 +6182,8 @@ int sp_break_curse(castorder * co)
"unit region command", mage, mage->region, co->order)); "unit region command", mage, mage->region, co->order));
} }
else { else {
const char *ts = NULL;
attrib **ap;
switch (obj) { switch (obj) {
case SPP_REGION: case SPP_REGION:
ap = &r->attribs; ap = &r->attribs;

View file

@ -357,8 +357,6 @@ int sp_sleep(struct castorder * co)
const spell * sp = co->sp; const spell * sp = co->sp;
battle *b = fi->side->battle; battle *b = fi->side->battle;
unit *mage = fi->unit; unit *mage = fi->unit;
unit *du;
troop dt;
int force, enemies; int force, enemies;
int k = 0; int k = 0;
message *m; message *m;
@ -374,7 +372,8 @@ int sp_sleep(struct castorder * co)
return 0; return 0;
} }
while (force && enemies) { while (force && enemies) {
dt = select_enemy(fi, FIGHT_ROW, BEHIND_ROW, SELECT_ADVANCE); unit *du;
troop dt = select_enemy(fi, FIGHT_ROW, BEHIND_ROW, SELECT_ADVANCE);
assert(dt.fighter); assert(dt.fighter);
du = dt.fighter->unit; du = dt.fighter->unit;
if (!is_magic_resistant(mage, du, 0)) { if (!is_magic_resistant(mage, du, 0)) {

View file

@ -217,7 +217,6 @@ int setstealth_cmd(unit * u, struct order *ord)
{ {
char token[64]; char token[64];
const char *s; const char *s;
int level;
init_order_depr(ord); init_order_depr(ord);
s = gettoken(token, sizeof(token)); s = gettoken(token, sizeof(token));
@ -231,7 +230,7 @@ int setstealth_cmd(unit * u, struct order *ord)
if (isdigit(*(const unsigned char *)s)) { if (isdigit(*(const unsigned char *)s)) {
/* Tarnungslevel setzen */ /* Tarnungslevel setzen */
level = atoi((const char *)s); int level = atoi((const char *)s);
if (level > effskill(u, SK_STEALTH, 0)) { if (level > effskill(u, SK_STEALTH, 0)) {
ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error_lowstealth", "")); ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error_lowstealth", ""));
return 0; return 0;

View file

@ -77,11 +77,12 @@ int *nmrs = NULL;
int update_nmrs(void) int update_nmrs(void)
{ {
int i, newplayers = 0; int newplayers = 0;
faction *f; faction *f;
int timeout = NMRTimeout(); int timeout = NMRTimeout();
if (timeout>0) { if (timeout>0) {
int i;
if (nmrs == NULL) { if (nmrs == NULL) {
nmrs = malloc(sizeof(int) * (timeout + 1)); nmrs = malloc(sizeof(int) * (timeout + 1));
} }

View file

@ -1,6 +1,8 @@
#include <platform.h> #include <platform.h>
#include "tests.h" #include "tests.h"
#include "prefix.h" #include "prefix.h"
#include "creport.h"
#include "report.h"
#include "reports.h" #include "reports.h"
#include "vortex.h" #include "vortex.h"
@ -230,9 +232,12 @@ static void test_reset(void) {
free_gamedata(); free_gamedata();
free_terrains(); free_terrains();
free_resources(); free_resources();
free_functions();
free_config(); free_config();
default_locale = 0; default_locale = 0;
calendar_cleanup(); calendar_cleanup();
creport_cleanup();
report_cleanup();
close_orders(); close_orders();
log_close(); log_close();
stats_close(); stats_close();
@ -245,29 +250,7 @@ static void test_reset(void) {
free_spellbooks(); free_spellbooks();
free_prefixes(); free_prefixes();
mt_clear(); mt_clear();
/*
for (i = 0; i != MAXTERRAINS; ++i) {
int flags = 0;
if (i == T_FIREWALL) {
flags |= FORBIDDEN_REGION;
} else {
flags = FLY_INTO | WALK_INTO;
if (i == T_OCEAN) {
flags |= SEA_REGION | SWIM_INTO;
}
else {
flags |= LAND_REGION;
if (i == T_PLAIN) {
flags |= CAVALRY_REGION | FOREST_REGION;
}
else if (i == T_GLACIER || i == T_ICEBERG || i == T_ICEBERG_SLEEP) {
flags |= ARCTIC_REGION;
}
}
}
test_create_terrain(terrainnames[i], flags);
}
*/
for (i = 0; i != MAXSKILLS; ++i) { for (i = 0; i != MAXSKILLS; ++i) {
enable_skill(i, true); enable_skill(i, true);
} }

View file

@ -4,21 +4,23 @@
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
char key[4]; char key[4];
char code[4]; char code[4];
char result[4]; char result[4];
int a, i, rot; int a;
for (a = 1; a < argc; ++a) { for (a = 1; a < argc; ++a) {
const char *str = argv[a]; int rot, i;
size_t len = strlen(str); const char *str = argv[a];
str = str + len - 6; size_t len = strlen(str);
memcpy(key, str, 3); str = str + len - 6;
memcpy(code, str + 3, 3); memcpy(key, str, 3);
result[3] = key[3] = code[3] = 0; memcpy(code, str + 3, 3);
rot = atoi(key); result[3] = key[3] = code[3] = 0;
for (i = 0; i != 3; ++i) rot = atoi(key);
result[(i + rot) % 3] = ((code[i] + 10 - key[i]) % 10) + '0'; for (i = 0; i != 3; ++i) {
printf("%s %s\n", argv[a], result); result[(i + rot) % 3] = ((code[i] + 10 - key[i]) % 10) + '0';
} }
return 0; printf("%s %s\n", argv[a], result);
}
return 0;
} }

View file

@ -4,7 +4,6 @@ add_subdirectory (crypto)
SET(_TEST_FILES SET(_TEST_FILES
base36.test.c base36.test.c
# bsdstring.test.c
# crmessage.test.c # crmessage.test.c
# dice.test.c # dice.test.c
# filereader.test.c # filereader.test.c
@ -34,7 +33,6 @@ variant.test.c
SET(_FILES SET(_FILES
base36.c base36.c
bsdstring.c
crmessage.c crmessage.c
dice.c dice.c
filereader.c filereader.c

View file

@ -125,13 +125,3 @@ const char *itoa10(int i)
{ {
return itoab(i, 10); return itoab(i, 10);
} }
int i10toi36(int i)
{
int r = 0;
while (i) {
r = r * 36 + i % 10;
i = i / 10;
}
return r;
}

View file

@ -25,14 +25,13 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
extern "C" { extern "C" {
#endif #endif
const char *itoa36(int i);
int atoi36(const char *s);
const char *itoa36_r(int i, char *result, size_t len); const char *itoa36_r(int i, char *result, size_t len);
const char *itoab_r(int i, int base, char *result, size_t len); const char *itoab_r(int i, int base, char *result, size_t len);
const char *itoab(int i, int base); const char *itoab(int i, int base);
const char *itoa36(int i);
const char *itoa10(int i); const char *itoa10(int i);
extern int atoi36(const char *s);
extern int atoi10(const char *s);
int i10toi36(int i);
#ifdef __cplusplus #ifdef __cplusplus
} }

View file

@ -1,52 +0,0 @@
#ifdef _MSC_VER
#include <platform.h>
#endif
#include <string.h>
#include <errno.h>
#include <assert.h>
#include <limits.h>
#include "bsdstring.h"
#include "log.h"
#include "strings.h"
int wrptr(char **ptr, size_t * size, int result)
{
size_t bytes = (size_t)result;
if (result < 0) {
/* buffer was too small */
if (*size > 0) {
**ptr = 0;
*size = 0;
}
errno = 0;
return ERANGE;
}
if (bytes == 0) {
return 0;
}
if (bytes <= *size) {
*ptr += bytes;
*size -= bytes;
return 0;
}
*ptr += *size;
*size = 0;
return ERANGE;
}
char * strlcpy_w(char *dst, const char *src, size_t *siz, const char *err, const char *file, int line)
{
size_t bytes = str_strlcpy(dst, src, *siz);
char * buf = dst;
assert(bytes <= INT_MAX);
if (wrptr(&buf, siz, (int)bytes) != 0) {
if (err) {
log_warning("%s: static buffer too small in %s:%d\n", err, file, line);
} else {
log_warning("static buffer too small in %s:%d\n", file, line);
}
}
return buf;
}

View file

@ -1,16 +0,0 @@
#ifndef UTIL_BSDSTRING_H
#define UTIL_BSDSTRING_H
#include <stddef.h>
int wrptr(char **ptr, size_t * size, int bytes);
char * strlcpy_w(char *dst, const char *src, size_t *siz, const char *err, const char *file, int line);
#define BUFFER_STRCAT(bufp, size, bytes) if (wrptr(&bufp, &size, bytes) != 0) log_warning("static buffer too small in %s:%d\n", __FILE__, __LINE__);
#define WARN_STATIC_BUFFER() log_warning("static buffer too small in %s:%d\n", __FILE__, __LINE__)
#define INFO_STATIC_BUFFER() log_info("static buffer too small in %s:%d\n", __FILE__, __LINE__)
#define STRLCPY(dst, src, siz) strlcpy_w((dst), (src), &(siz), 0, __FILE__, __LINE__)
#define STRLCPY_EX(dst, src, siz, err) strlcpy_w((dst), (src), (siz), (err), __FILE__, __LINE__)
#endif

View file

@ -131,14 +131,14 @@ int bcrypt_gensalt(int factor, char salt[BCRYPT_HASHSIZE])
return (aux == NULL)?5:0; return (aux == NULL)?5:0;
} }
int bcrypt_hashpw(const char *passwd, const char salt[BCRYPT_HASHSIZE], char hash[BCRYPT_HASHSIZE]) int bcrypt_hashpw(const char *passwd, const char salt[], char hash[BCRYPT_HASHSIZE])
{ {
char *aux; char *aux;
aux = crypt_rn(passwd, salt, hash, BCRYPT_HASHSIZE); aux = crypt_rn(passwd, salt, hash, BCRYPT_HASHSIZE);
return (aux == NULL)?1:0; return (aux == NULL)?1:0;
} }
int bcrypt_checkpw(const char *passwd, const char hash[BCRYPT_HASHSIZE]) int bcrypt_checkpw(const char *passwd, const char hash[])
{ {
int ret; int ret;
char outhash[BCRYPT_HASHSIZE]; char outhash[BCRYPT_HASHSIZE];

View file

@ -45,7 +45,7 @@ int bcrypt_gensalt(int workfactor, char salt[BCRYPT_HASHSIZE]);
* The return value is zero if the password could be hashed and nonzero * The return value is zero if the password could be hashed and nonzero
* otherwise. * otherwise.
*/ */
int bcrypt_hashpw(const char *passwd, const char salt[BCRYPT_HASHSIZE], int bcrypt_hashpw(const char *passwd, const char salt[],
char hash[BCRYPT_HASHSIZE]); char hash[BCRYPT_HASHSIZE]);
/* /*
@ -57,7 +57,7 @@ int bcrypt_hashpw(const char *passwd, const char salt[BCRYPT_HASHSIZE],
* passwords don't match. * passwords don't match.
* *
*/ */
int bcrypt_checkpw(const char *passwd, const char hash[BCRYPT_HASHSIZE]); int bcrypt_checkpw(const char *passwd, const char hash[]);
/* /*
* Brief Example * Brief Example

View file

@ -52,13 +52,13 @@ keyword_t findkeyword(const char *s) {
keyword_t get_keyword(const char *s, const struct locale *lang) { keyword_t get_keyword(const char *s, const struct locale *lang) {
keyword_t result = NOKEYWORD; keyword_t result = NOKEYWORD;
char buffer[64];
assert(lang); assert(lang);
assert(s); assert(s);
while (*s == '@') ++s; while (*s == '@') ++s;
if (*s) { if (*s) {
char buffer[64];
char *str = transliterate(buffer, sizeof(buffer) - sizeof(int), s); char *str = transliterate(buffer, sizeof(buffer) - sizeof(int), s);
if (str) { if (str) {
@ -88,6 +88,11 @@ bool keyword_disabled(keyword_t kwd) {
return disabled_kwd[kwd]; return disabled_kwd[kwd];
} }
const char *keyword_name(keyword_t kwd, const struct locale *lang)
{
return LOC(lang, mkname("keyword", keywords[kwd]));
}
const char *keywords[MAXKEYWORDS] = { const char *keywords[MAXKEYWORDS] = {
"//", "//",
"banner", "banner",

View file

@ -83,6 +83,7 @@ extern "C"
void init_keywords(const struct locale *lang); void init_keywords(const struct locale *lang);
void init_keyword(const struct locale *lang, keyword_t kwd, const char *str); void init_keyword(const struct locale *lang, keyword_t kwd, const char *str);
bool keyword_disabled(keyword_t kwd); bool keyword_disabled(keyword_t kwd);
const char *keyword_name(keyword_t kwd, const struct locale *lang);
void enable_keyword(keyword_t kwd, bool enabled); void enable_keyword(keyword_t kwd, bool enabled);
const char *keyword(keyword_t kwd); const char *keyword(keyword_t kwd);

View file

@ -80,15 +80,6 @@ void translist(void *l1, void *l2, void *p)
addlist(l2, p); addlist(l2, p);
} }
void removelist(void *l, void *p)
{
/* remove entry p from list l; free p */
choplist(l, p);
free(p);
}
void freelist(void *p1) void freelist(void *p1)
{ {

View file

@ -32,7 +32,6 @@ extern "C" {
void addlist(void *l1, void *p1); void addlist(void *l1, void *p1);
void translist(void *l1, void *l2, void *p); void translist(void *l1, void *l2, void *p);
void freelist(void *p1); void freelist(void *p1);
void removelist(void *l, void *p);
unsigned int listlen(void *l); unsigned int listlen(void *l);
#ifdef __cplusplus #ifdef __cplusplus

View file

@ -205,15 +205,17 @@ log_t *log_to_file(int flags, FILE *out) {
return log_create(flags, out, log_stdio); return log_create(flags, out, log_stdio);
} }
#ifdef _MSC_VER /*
/* https://social.msdn.microsoft.com/Forums/vstudio/en-US/53a4fd75-9f97-48b2-aa63-2e2e5a15efa3/stdcversion-problem?forum=vclanguage */ * Notes for va_copy compatibility:
#define VA_COPY(c, a) va_copy(c, a) * MSVC: https://social.msdn.microsoft.com/Forums/vstudio/en-US/53a4fd75-9f97-48b2-aa63-2e2e5a15efa3/stdcversion-problem?forum=vclanguage
#elif !defined(__STDC_VERSION__) || __STDC_VERSION__ < 199901L * GNU: https://www.gnu.org/software/libc/manual/html_node/Argument-Macros.html
/* GNU only: https://www.gnu.org/software/libc/manual/html_node/Argument-Macros.html */ */
#define VA_COPY(c, a) __va_copy(c, a) static void vlog(log_t *lg, int level, const char *format, va_list args) {
#else va_list copy;
#define VA_COPY(c, a) va_copy(c, a) va_copy(copy, args);
#endif lg->log(lg->data, level, NULL, format, copy);
va_end(copy);
}
static void log_write(int flags, const char *module, const char *format, va_list args) { static void log_write(int flags, const char *module, const char *format, va_list args) {
log_t *lg; log_t *lg;
@ -225,10 +227,7 @@ static void log_write(int flags, const char *module, const char *format, va_list
dupe = check_dupe(format, level); dupe = check_dupe(format, level);
} }
if (dupe == 0) { if (dupe == 0) {
va_list copy; vlog(lg, level, format, args);
VA_COPY(copy, args);
lg->log(lg->data, level, NULL, format, copy);
va_end(copy);
} }
} }
} }
@ -325,10 +324,10 @@ int log_level(log_t * log, int flags)
static critbit_tree stats = CRITBIT_TREE(); static critbit_tree stats = CRITBIT_TREE();
int stats_count(const char *stat, int delta) { int stats_count(const char *stat, int delta) {
size_t len;
char data[128];
void * match; void * match;
if (cb_find_prefix_str(&stats, stat, &match, 1, 0) == 0) { if (cb_find_prefix_str(&stats, stat, &match, 1, 0) == 0) {
size_t len;
char data[128];
len = cb_new_kv(stat, strlen(stat), &delta, sizeof(delta), data); len = cb_new_kv(stat, strlen(stat), &delta, sizeof(delta), data);
cb_insert(&stats, data, len); cb_insert(&stats, data, len);
return delta; return delta;

View file

@ -148,6 +148,9 @@ const char *section_add(const char *name) {
} }
} }
assert(i < MAXSECTIONS); assert(i < MAXSECTIONS);
if (i == MAXSECTIONS) {
return NULL;
}
assert(sections[i] == NULL); assert(sections[i] == NULL);
if (i + 1 < MAXSECTIONS) { if (i + 1 < MAXSECTIONS) {
sections[i + 1] = NULL; sections[i + 1] = NULL;

View file

@ -100,10 +100,10 @@ void init_by_array(unsigned long init_key[], int key_length)
unsigned long genrand_int32(void) unsigned long genrand_int32(void)
{ {
unsigned long y; unsigned long y;
static unsigned long mag01[2]={0x0UL, MATRIX_A};
/* mag01[x] = x * MATRIX_A for x=0,1 */
if (mti >= N) { /* generate N words at one time */ if (mti >= N) { /* generate N words at one time */
static unsigned long mag01[2] = { 0x0UL, MATRIX_A };
/* mag01[x] = x * MATRIX_A for x=0,1 */
int kk; int kk;
if (mti == N+1) /* if init_genrand() has not been called, */ if (mti == N+1) /* if init_genrand() has not been called, */

View file

@ -6,6 +6,7 @@ typedef enum cryptalgo_t {
PASSWORD_BCRYPT PASSWORD_BCRYPT
} cryptalgo_t; } cryptalgo_t;
#define PASSWORD_DEFAULT PASSWORD_BCRYPT #define PASSWORD_DEFAULT PASSWORD_BCRYPT
#define PASSWORD_MAXSIZE 32
extern int bcrypt_workfactor; extern int bcrypt_workfactor;

View file

@ -2,7 +2,7 @@
#include <stddef.h> #include <stddef.h>
#ifdef _MSC_VER #ifndef PATH_MAX
/* @see https://insanecoding.blogspot.no/2007/11/pathmax-simply-isnt.html */ /* @see https://insanecoding.blogspot.no/2007/11/pathmax-simply-isnt.html */
#define PATH_MAX 260 #define PATH_MAX 260
#endif #endif

View file

@ -8,17 +8,13 @@
static void test_rng_round(CuTest * tc) static void test_rng_round(CuTest * tc)
{ {
double f; double f = rng_double();
int i, r; int r = RAND_ROUND(f);
for (i = 0; i < 1000; ++i) { CuAssertTrue(tc, f >= 0);
f = rng_double(); CuAssertTrue(tc, r <= (int)f + 1);
r = RAND_ROUND(f); CuAssertTrue(tc, r >= (int)f);
CuAssertTrue(tc, f >= 0); CuAssertTrue(tc, r == (int)r);
CuAssertTrue(tc, r <= (int)f + 1); CuAssertTrue(tc, r == RAND_ROUND(r));
CuAssertTrue(tc, r >= (int)f);
CuAssertTrue(tc, r == (int)r);
CuAssertTrue(tc, r == RAND_ROUND(r));
}
} }
CuSuite *get_rng_suite(void) CuSuite *get_rng_suite(void)

View file

@ -18,7 +18,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#ifdef _MSC_VER #ifdef _MSC_VER
#include <platform.h> #include <platform.h>
#define HAVE__ITOA #undef HAVE__ITOA
#endif #endif
#include "strings.h" #include "strings.h"
@ -35,27 +35,23 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#include <string.h> #include <string.h>
#endif #endif
const char* str_itoab(int val, int base) const char* str_itoa_r(int val, char *buf)
{ {
static char buf[32] = { 0 }; #ifdef HAVE__ITOA
#ifdef HAVE__ITOAB return _itoa(val, buf, 10);
return _itoa(val, buf, base);
#else #else
int i = 30; snprintf(buf, 12, "%d", val);
for (; val && i; --i, val /= base) { return buf;
buf[i] = "0123456789abcdefghijklmnopqrstuvwxyz"[val % base];
}
return &buf[i + 1];
#endif #endif
} }
const char *str_itoa(int n) const char *str_itoa(int n)
{ {
static char buf[12];
#ifdef HAVE__ITOA #ifdef HAVE__ITOA
static char buf[32] = { 0 };
return _itoa(n, buf, 10); return _itoa(n, buf, 10);
#else #else
return str_itoab(n, 10); return str_itoa_r(n, buf);
#endif #endif
} }
@ -181,49 +177,6 @@ int str_hash(const char *s)
return key & 0x7FFFFFFF; return key & 0x7FFFFFFF;
} }
const char *str_escape_wrong(const char *str, char *buffer, size_t len)
{
const char *handle_start = strchr(str, '\"');
if (!handle_start) handle_start = strchr(str, '\\');
assert(buffer);
if (handle_start) {
const char *p = str;
char *o = buffer;
size_t skip = handle_start - str;
if (skip > len) {
skip = len;
}
if (skip > 0) {
memcpy(buffer, str, skip);
o += skip;
p += skip;
len -= skip;
}
do {
if (*p == '\"' || *p == '\\') {
if (len < 2) {
break;
}
(*o++) = '\\';
len -= 2;
}
else {
if (len < 1) {
break;
}
--len;
}
if (len > 0) {
(*o++) = (*p);
}
} while (len > 0 && *p++);
*o = '\0';
return buffer;
}
return str;
}
unsigned int jenkins_hash(unsigned int a) unsigned int jenkins_hash(unsigned int a)
{ {
a = (a + 0x7ed55d16) + (a << 12); a = (a + 0x7ed55d16) + (a << 12);
@ -260,6 +213,26 @@ char *str_strdup(const char *s) {
#endif #endif
} }
void sbs_printf(struct sbstring *sbs, const char *format, ...)
{
size_t size = sbs->size - (sbs->end - sbs->begin);
if (size > 0) {
va_list argp;
va_start(argp, format);
int bytes = vsnprintf(sbs->end, size, format, argp);
if (bytes > 0) {
if ((size_t)bytes >= size) {
bytes = size - 1;
/* terminate truncated output */
sbs->end[bytes] = '\0';
}
sbs->end += bytes;
}
va_end(argp);
}
}
void sbs_init(struct sbstring *sbs, char *buffer, size_t size) void sbs_init(struct sbstring *sbs, char *buffer, size_t size)
{ {
assert(sbs); assert(sbs);
@ -303,16 +276,6 @@ void sbs_strcat(struct sbstring *sbs, const char *str)
assert(sbs->begin + sbs->size >= sbs->end); assert(sbs->begin + sbs->size >= sbs->end);
} }
void sbs_strcpy(struct sbstring *sbs, const char *str)
{
size_t len = str_strlcpy(sbs->begin, str, sbs->size);
if (len >= sbs->size) {
len = sbs->size - 1;
}
sbs->end = sbs->begin + len;
assert(sbs->begin + sbs->size >= sbs->end);
}
void sbs_substr(sbstring *sbs, ptrdiff_t pos, size_t len) void sbs_substr(sbstring *sbs, ptrdiff_t pos, size_t len)
{ {
if (pos > sbs->end - sbs->begin) { if (pos > sbs->end - sbs->begin) {

View file

@ -29,7 +29,6 @@ extern "C" {
void str_replace(char *buffer, size_t size, const char *tmpl, const char *var, const char *value); void str_replace(char *buffer, size_t size, const char *tmpl, const char *var, const char *value);
int str_hash(const char *s); int str_hash(const char *s);
const char *str_itoa(int i); const char *str_itoa(int i);
const char *str_itoab(int i, int base);
size_t str_slprintf(char * dst, size_t size, const char * format, ...); size_t str_slprintf(char * dst, size_t size, const char * format, ...);
size_t str_strlcpy(char *dst, const char *src, size_t len); size_t str_strlcpy(char *dst, const char *src, size_t len);
size_t str_strlcat(char *dst, const char *src, size_t len); size_t str_strlcat(char *dst, const char *src, size_t len);
@ -49,11 +48,11 @@ extern "C" {
char *end; char *end;
} sbstring; } sbstring;
void sbs_printf(struct sbstring *sbs, const char *format, ...);
void sbs_init(struct sbstring *sbs, char *buffer, size_t size); void sbs_init(struct sbstring *sbs, char *buffer, size_t size);
void sbs_adopt(struct sbstring *sbs, char *buffer, size_t size); void sbs_adopt(struct sbstring *sbs, char *buffer, size_t size);
void sbs_strcat(struct sbstring *sbs, const char *str); void sbs_strcat(struct sbstring *sbs, const char *str);
void sbs_strncat(struct sbstring *sbs, const char *str, size_t size); void sbs_strncat(struct sbstring *sbs, const char *str, size_t size);
void sbs_strcpy(struct sbstring *sbs, const char *str);
void sbs_substr(struct sbstring *sbp, ptrdiff_t pos, size_t len); void sbs_substr(struct sbstring *sbp, ptrdiff_t pos, size_t len);
size_t sbs_length(const struct sbstring *sbs); size_t sbs_length(const struct sbstring *sbs);

View file

@ -133,25 +133,41 @@ static void test_str_strlcpy(CuTest * tc)
errno = 0; errno = 0;
} }
static void test_str_itoa(CuTest * tc)
{
CuAssertStrEquals(tc, "1234", str_itoa(1234));
CuAssertStrEquals(tc, "0", str_itoa(0));
CuAssertStrEquals(tc, "1234567890", str_itoa(1234567890));
CuAssertStrEquals(tc, "-1234567890", str_itoa(-1234567890));
}
static void test_sbstring(CuTest * tc) static void test_sbstring(CuTest * tc)
{ {
char buffer[16]; char buffer[16];
sbstring sbs; sbstring sbs;
sbs_init(&sbs, buffer, sizeof(buffer)); sbs_init(&sbs, buffer, sizeof(buffer));
CuAssertStrEquals(tc, "", sbs.begin); CuAssertStrEquals(tc, "", sbs.begin);
sbs_strcpy(&sbs, "Hodor"); sbs_strcat(&sbs, "Hodor");
CuAssertStrEquals(tc, "Hodor", sbs.begin); CuAssertStrEquals(tc, "Hodor", sbs.begin);
sbs_strcat(&sbs, "Hodor"); sbs_strcat(&sbs, "Hodor");
CuAssertStrEquals(tc, "HodorHodor", sbs.begin); CuAssertStrEquals(tc, "HodorHodor", sbs.begin);
sbs_strcpy(&sbs, "Hodor");
sbs_init(&sbs, buffer, sizeof(buffer));
sbs_strcat(&sbs, "Hodor");
CuAssertStrEquals(tc, "Hodor", sbs.begin); CuAssertStrEquals(tc, "Hodor", sbs.begin);
sbs_strcpy(&sbs, "12345678901234567890");
sbs_init(&sbs, buffer, sizeof(buffer));
sbs_strcat(&sbs, "12345678901234567890");
CuAssertStrEquals(tc, "123456789012345", sbs.begin); CuAssertStrEquals(tc, "123456789012345", sbs.begin);
CuAssertPtrEquals(tc, sbs.begin + sbs.size - 1, sbs.end); CuAssertPtrEquals(tc, sbs.begin + sbs.size - 1, sbs.end);
sbs_init(&sbs, buffer, sizeof(buffer));
sbs_strcat(&sbs, "12345678901234567890"); sbs_strcat(&sbs, "12345678901234567890");
CuAssertStrEquals(tc, "123456789012345", sbs.begin); CuAssertStrEquals(tc, "123456789012345", sbs.begin);
CuAssertPtrEquals(tc, buffer, sbs.begin); CuAssertPtrEquals(tc, buffer, sbs.begin);
sbs_strcpy(&sbs, "1234567890");
sbs_init(&sbs, buffer, sizeof(buffer));
sbs_strcat(&sbs, "1234567890");
CuAssertStrEquals(tc, "1234567890", sbs.begin); CuAssertStrEquals(tc, "1234567890", sbs.begin);
sbs_strncat(&sbs, "1234567890", 4); sbs_strncat(&sbs, "1234567890", 4);
CuAssertStrEquals(tc, "12345678901234", sbs.begin); CuAssertStrEquals(tc, "12345678901234", sbs.begin);
@ -194,31 +210,35 @@ static void test_sbs_substr(CuTest * tc)
buffer[9] = 'A'; buffer[9] = 'A';
sbs_init(&sbs, buffer, sizeof(buffer)); sbs_init(&sbs, buffer, sizeof(buffer));
sbs_strcpy(&sbs, "12345678"); sbs_strcat(&sbs, "12345678");
CuAssertStrEquals(tc, "12345678", buffer); CuAssertStrEquals(tc, "12345678", buffer);
sbs_substr(&sbs, 0, 4); sbs_substr(&sbs, 0, 4);
CuAssertStrEquals(tc, "1234", buffer); CuAssertStrEquals(tc, "1234", buffer);
CuAssertIntEquals(tc, 4, (int)sbs_length(&sbs)); CuAssertIntEquals(tc, 4, (int)sbs_length(&sbs));
sbs_strcpy(&sbs, "12345678"); sbs_init(&sbs, buffer, sizeof(buffer));
sbs_strcat(&sbs, "12345678");
CuAssertStrEquals(tc, "12345678", buffer); CuAssertStrEquals(tc, "12345678", buffer);
sbs_substr(&sbs, 4, 4); sbs_substr(&sbs, 4, 4);
CuAssertStrEquals(tc, "5678", buffer); CuAssertStrEquals(tc, "5678", buffer);
CuAssertIntEquals(tc, 4, (int)sbs_length(&sbs)); CuAssertIntEquals(tc, 4, (int)sbs_length(&sbs));
sbs_strcpy(&sbs, "12345678"); sbs_init(&sbs, buffer, sizeof(buffer));
sbs_strcat(&sbs, "12345678");
CuAssertStrEquals(tc, "12345678", buffer); CuAssertStrEquals(tc, "12345678", buffer);
sbs_substr(&sbs, 2, 4); sbs_substr(&sbs, 2, 4);
CuAssertStrEquals(tc, "3456", buffer); CuAssertStrEquals(tc, "3456", buffer);
CuAssertIntEquals(tc, 4, (int)sbs_length(&sbs)); CuAssertIntEquals(tc, 4, (int)sbs_length(&sbs));
sbs_strcpy(&sbs, "12345678"); sbs_init(&sbs, buffer, sizeof(buffer));
sbs_strcat(&sbs, "12345678");
CuAssertStrEquals(tc, "12345678", buffer); CuAssertStrEquals(tc, "12345678", buffer);
sbs_substr(&sbs, 4, 4); sbs_substr(&sbs, 4, 4);
CuAssertStrEquals(tc, "5678", buffer); CuAssertStrEquals(tc, "5678", buffer);
CuAssertIntEquals(tc, 4, (int)sbs_length(&sbs)); CuAssertIntEquals(tc, 4, (int)sbs_length(&sbs));
sbs_strcpy(&sbs, "12345678"); sbs_init(&sbs, buffer, sizeof(buffer));
sbs_strcat(&sbs, "12345678");
CuAssertStrEquals(tc, "12345678", buffer); CuAssertStrEquals(tc, "12345678", buffer);
sbs_substr(&sbs, 4, 8); sbs_substr(&sbs, 4, 8);
CuAssertStrEquals(tc, "5678", buffer); CuAssertStrEquals(tc, "5678", buffer);
@ -226,6 +246,31 @@ static void test_sbs_substr(CuTest * tc)
CuAssertIntEquals(tc, 'A', buffer[9]); CuAssertIntEquals(tc, 'A', buffer[9]);
} }
static void test_sbs_printf(CuTest * tc)
{
char buffer[10];
sbstring sbs;
sbs_init(&sbs, buffer, sizeof(buffer));
sbs_printf(&sbs, "%s %d", "1234", 5678);
CuAssertStrEquals(tc, "1234 5678", buffer);
sbs_init(&sbs, buffer, sizeof(buffer));
sbs_printf(&sbs, "%s", "12345");
sbs_printf(&sbs, "%d", 6789);
CuAssertStrEquals(tc, "123456789", buffer);
sbs_init(&sbs, buffer, sizeof(buffer));
sbs_printf(&sbs, "%s", "1234567890");
CuAssertStrEquals(tc, "123456789", buffer);
sbs_init(&sbs, buffer, sizeof(buffer));
sbs_printf(&sbs, "%d", 123456789);
CuAssertStrEquals(tc, "123456789", buffer);
sbs_printf(&sbs, "%s", "Hodor");
CuAssertStrEquals(tc, "123456789", buffer);
}
CuSuite *get_strings_suite(void) CuSuite *get_strings_suite(void)
{ {
CuSuite *suite = CuSuiteNew(); CuSuite *suite = CuSuiteNew();
@ -237,8 +282,10 @@ CuSuite *get_strings_suite(void)
SUITE_ADD_TEST(suite, test_str_slprintf); SUITE_ADD_TEST(suite, test_str_slprintf);
SUITE_ADD_TEST(suite, test_str_strlcat); SUITE_ADD_TEST(suite, test_str_strlcat);
SUITE_ADD_TEST(suite, test_str_strlcpy); SUITE_ADD_TEST(suite, test_str_strlcpy);
SUITE_ADD_TEST(suite, test_str_itoa);
SUITE_ADD_TEST(suite, test_sbstring); SUITE_ADD_TEST(suite, test_sbstring);
SUITE_ADD_TEST(suite, test_sbs_strcat); SUITE_ADD_TEST(suite, test_sbs_strcat);
SUITE_ADD_TEST(suite, test_sbs_substr); SUITE_ADD_TEST(suite, test_sbs_substr);
SUITE_ADD_TEST(suite, test_sbs_printf);
return suite; return suite;
} }

View file

@ -129,13 +129,12 @@ attrib_type at_direction = {
region *find_special_direction(const region * r, const char *token) region *find_special_direction(const region * r, const char *token)
{ {
attrib *a; attrib *a;
spec_direction *d;
if (strlen(token) == 0) if (strlen(token) == 0)
return NULL; return NULL;
for (a = a_find(r->attribs, &at_direction); a && a->type == &at_direction; for (a = a_find(r->attribs, &at_direction); a && a->type == &at_direction;
a = a->next) { a = a->next) {
d = (spec_direction *)(a->data.v); spec_direction *d = (spec_direction *)(a->data.v);
if (d->active && strcmp(token, d->keyword) == 0) { if (d->active && strcmp(token, d->keyword) == 0) {
return findregion(d->x, d->y); return findregion(d->x, d->y);