diff --git a/conf/e3/config.json b/conf/e3/config.json
index 8783055b8..1cecc89d2 100644
--- a/conf/e3/config.json
+++ b/conf/e3/config.json
@@ -42,6 +42,7 @@
"nmr.timeout": 5,
"nmr.removenewbie": 0,
"GiveRestriction": 3,
+ "healing.forest": 2.0,
"hunger.long": false,
"hunger.damage": "1d9+9",
"hunger.demons.skill": true,
diff --git a/res/core/messages.xml b/res/core/messages.xml
index 6892ec4e5..c28670d65 100644
--- a/res/core/messages.xml
+++ b/res/core/messages.xml
@@ -1910,10 +1910,9 @@
-
- "$unit($unit) benutzt in $region($region) einen Antimagiekristall."
- "$unit($unit) uses an antimagic crystal in $region($region)."
+ "$unit($unit) benutzt einen Antimagiekristall."
+ "$unit($unit) uses an antimagic crystal."
diff --git a/res/e3a/races.xml b/res/e3a/races.xml
index 2b0f68b9d..7e75f3fd4 100644
--- a/res/e3a/races.xml
+++ b/res/e3a/races.xml
@@ -8,7 +8,7 @@
-
+
@@ -32,11 +32,10 @@
-
+
-
@@ -47,11 +46,10 @@
-
+
-
@@ -76,11 +74,10 @@
-
+
-
@@ -104,7 +101,7 @@
-
+
@@ -124,10 +121,9 @@
-
+
-
@@ -144,7 +140,7 @@
-
+
@@ -167,7 +163,7 @@
-
+
@@ -192,7 +188,7 @@
-
+
@@ -219,7 +215,7 @@
-
+
@@ -241,7 +237,7 @@
-
+
@@ -263,7 +259,7 @@
-
+
@@ -287,7 +283,7 @@
-
+
@@ -311,7 +307,7 @@
-
+
@@ -334,7 +330,7 @@
-
+
@@ -361,7 +357,7 @@
-
+
@@ -384,7 +380,7 @@
-
+
@@ -409,7 +405,7 @@
-
+
@@ -435,7 +431,7 @@
-
+
@@ -460,7 +456,7 @@
-
+
@@ -484,7 +480,7 @@
-
+
@@ -507,7 +503,7 @@
-
+
@@ -535,7 +531,7 @@
-
+
@@ -559,7 +555,7 @@
-
+
@@ -582,7 +578,7 @@
-
+
@@ -607,16 +603,16 @@
-
+
-
+
-
+
@@ -624,7 +620,7 @@
-
+
@@ -672,47 +668,47 @@
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
@@ -720,21 +716,21 @@
-
+
-
+
-
+
@@ -742,7 +738,7 @@
-
+
@@ -768,7 +764,7 @@
-
+
@@ -787,7 +783,7 @@
-
+
@@ -806,7 +802,7 @@
-
+
@@ -823,7 +819,7 @@
-
+
@@ -839,7 +835,7 @@
-
+
@@ -855,7 +851,7 @@
-
+
@@ -871,13 +867,13 @@
-
+
-
+
@@ -890,7 +886,7 @@
-
+
@@ -898,7 +894,7 @@
-
+
diff --git a/res/eressea/races.xml b/res/eressea/races.xml
index 2ef5950c9..e4e22d0c3 100644
--- a/res/eressea/races.xml
+++ b/res/eressea/races.xml
@@ -1,7 +1,7 @@
-
-
+
@@ -27,7 +27,7 @@
-
+
@@ -61,7 +61,7 @@
-
+
@@ -90,7 +90,7 @@
-
+
@@ -118,7 +118,7 @@
-
+
@@ -148,7 +148,7 @@
-
+
@@ -178,7 +178,7 @@
-
+
@@ -209,7 +209,7 @@
-
+
@@ -244,7 +244,7 @@
-
+
@@ -275,7 +275,7 @@
-
+
@@ -308,7 +308,7 @@
-
+
@@ -339,7 +339,7 @@
-
+
@@ -370,7 +370,7 @@
-
+
@@ -401,7 +401,7 @@
-
+
@@ -431,7 +431,7 @@
-
+
@@ -463,7 +463,7 @@
-
+
@@ -495,7 +495,7 @@
-
+
@@ -525,7 +525,7 @@
-
+
@@ -558,7 +558,7 @@
-
+
@@ -589,16 +589,16 @@
-
+
-
+
-
@@ -607,7 +607,7 @@
-
+
@@ -671,66 +671,66 @@
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
@@ -742,7 +742,7 @@
-
+
@@ -755,7 +755,7 @@
-
+
@@ -769,20 +769,20 @@
-
+
-
+
-
+
@@ -801,7 +801,7 @@
-
+
@@ -827,7 +827,7 @@
-
+
@@ -860,7 +860,7 @@
-
+
@@ -889,7 +889,7 @@
-
+
@@ -921,7 +921,7 @@
-
+
@@ -978,7 +978,7 @@
-
+
@@ -1011,11 +1011,11 @@
-
+
-
+
@@ -1023,7 +1023,7 @@
-
+
@@ -1037,7 +1037,7 @@
-
+
@@ -1055,7 +1055,7 @@
-
+
@@ -1073,7 +1073,7 @@
-
+
@@ -1089,7 +1089,7 @@
-
+
@@ -1104,7 +1104,7 @@
-
+
@@ -1119,7 +1119,7 @@
-
+
@@ -1134,12 +1134,12 @@
-
+
-
+
@@ -1151,7 +1151,7 @@
-
@@ -1182,7 +1182,7 @@
-
+
@@ -1209,7 +1209,7 @@
-
+
@@ -1241,7 +1241,7 @@
-
+
@@ -1271,7 +1271,7 @@
-
+
@@ -1285,13 +1285,13 @@
-
+
-
+
@@ -1300,7 +1300,7 @@
-
+
diff --git a/res/races/aquarian.xml b/res/races/aquarian.xml
index 776f17e93..a0e1189b7 100644
--- a/res/races/aquarian.xml
+++ b/res/races/aquarian.xml
@@ -1,5 +1,5 @@
-
+
diff --git a/res/races/cat.xml b/res/races/cat.xml
index 818b24b36..75bc8019a 100644
--- a/res/races/cat.xml
+++ b/res/races/cat.xml
@@ -1,5 +1,5 @@
-
+
diff --git a/res/races/demon.xml b/res/races/demon.xml
index a350fef4a..0ce4c86ff 100644
--- a/res/races/demon.xml
+++ b/res/races/demon.xml
@@ -1,5 +1,5 @@
-
-
+
diff --git a/res/races/elf.xml b/res/races/elf.xml
index dfbd2f2ec..ee1278a26 100644
--- a/res/races/elf.xml
+++ b/res/races/elf.xml
@@ -1,5 +1,5 @@
-
+
diff --git a/res/races/goblin-2.xml b/res/races/goblin-2.xml
index 9a9c265be..f8964d7c0 100644
--- a/res/races/goblin-2.xml
+++ b/res/races/goblin-2.xml
@@ -1,5 +1,5 @@
-
-
diff --git a/res/races/goblin-3.xml b/res/races/goblin-3.xml
index e85b0c645..4ad83967d 100644
--- a/res/races/goblin-3.xml
+++ b/res/races/goblin-3.xml
@@ -1,5 +1,5 @@
-
-
diff --git a/res/races/goblin.xml b/res/races/goblin.xml
index 177c82ffe..101cdaa86 100644
--- a/res/races/goblin.xml
+++ b/res/races/goblin.xml
@@ -1,5 +1,5 @@
-
-
+
diff --git a/res/races/human.xml b/res/races/human.xml
index 2e4b94af2..8f1ad5cb4 100644
--- a/res/races/human.xml
+++ b/res/races/human.xml
@@ -1,5 +1,5 @@
-
+
diff --git a/res/races/insect.xml b/res/races/insect.xml
index cecbf0193..dc9faa06d 100644
--- a/res/races/insect.xml
+++ b/res/races/insect.xml
@@ -1,5 +1,5 @@
-
+
diff --git a/res/races/orc.xml b/res/races/orc.xml
index d9d26ab25..4f4d96ed5 100644
--- a/res/races/orc.xml
+++ b/res/races/orc.xml
@@ -1,5 +1,5 @@
-
+
diff --git a/res/races/troll.xml b/res/races/troll.xml
index a2341851b..c70020fa2 100644
--- a/res/races/troll.xml
+++ b/res/races/troll.xml
@@ -1,5 +1,5 @@
-
-parameters, "armor.stamina", -1);
-}
-
int natural_armor(unit * du)
{
const race *rc = u_race(du);
int an;
assert(rc);
- an = armor_bonus(rc);
+ an = rc_armor_bonus(rc);
if (an > 0) {
int sk = effskill(du, SK_STAMINA, 0);
return rc->armor + sk / an;
diff --git a/src/battle.test.c b/src/battle.test.c
index 7228ef90e..e8187c772 100644
--- a/src/battle.test.c
+++ b/src/battle.test.c
@@ -223,10 +223,13 @@ static void test_natural_armor(CuTest * tc)
rc = test_create_race("human");
u = test_create_unit(test_create_faction(rc), test_create_region(0, 0, 0));
set_level(u, SK_STAMINA, 2);
+ CuAssertIntEquals(tc, 0, rc_armor_bonus(rc));
CuAssertIntEquals(tc, 0, natural_armor(u));
set_param(&rc->parameters, "armor.stamina", "1");
+ CuAssertIntEquals(tc, 1, rc_armor_bonus(rc));
CuAssertIntEquals(tc, 2, natural_armor(u));
set_param(&rc->parameters, "armor.stamina", "2");
+ CuAssertIntEquals(tc, 2, rc_armor_bonus(rc));
CuAssertIntEquals(tc, 1, natural_armor(u));
test_cleanup();
}
@@ -352,12 +355,12 @@ static void test_magic_resistance(CuTest *tc)
calculate_armor(dt, 0, 0, &magres);
CuAssertDblEquals_Msg(tc, "skill bonus", 0.1, magic_resistance(du), 0.01);
CuAssertDblEquals_Msg(tc, "skill reduction", 0.9, magres, 0.01);
- rc->magres = 0.5; /* gets added to skill bonus */
+ rc->magres = 50; /* percentage, gets added to skill bonus */
calculate_armor(dt, 0, 0, &magres);
CuAssertDblEquals_Msg(tc, "race bonus", 0.6, magic_resistance(du), 0.01);
CuAssertDblEquals_Msg(tc, "race reduction", 0.4, magres, 0.01);
- rc->magres = 1.5; /* should not cause negative damage multiplier */
+ rc->magres = 150; /* should not cause negative damage multiplier */
CuAssertDblEquals_Msg(tc, "magic resistance is never > 0.9", 0.9, magic_resistance(du), 0.01);
calculate_armor(dt, 0, 0, &magres);
CuAssertDblEquals_Msg(tc, "damage reduction is never < 0.1", 0.1, magres, 0.01);
diff --git a/src/economy.c b/src/economy.c
index 16b201555..2d9fe6666 100644
--- a/src/economy.c
+++ b/src/economy.c
@@ -427,7 +427,6 @@ static int recruit_cost(const faction * f, const race * rc)
}
else if (valid_race(f, rc)) {
return rc->recruitcost;
- /* return get_param_int(f->race->parameters, "other_cost", -1); */
}
return -1;
}
diff --git a/src/items.c b/src/items.c
index 6e995edaa..bb5009038 100644
--- a/src/items.c
+++ b/src/items.c
@@ -167,8 +167,7 @@ struct order *ord)
}
}
use_pooled(u, rt_crystal, GET_DEFAULT, amount);
- ADDMSG(&u->faction->msgs, msg_message("use_antimagiccrystal",
- "unit region", u, r));
+ ADDMSG(&u->region->msgs, msg_message("use_antimagiccrystal", "unit", u));
return 0;
}
diff --git a/src/kernel/faction.c b/src/kernel/faction.c
index b7115c62f..28ac2e203 100755
--- a/src/kernel/faction.c
+++ b/src/kernel/faction.c
@@ -565,7 +565,7 @@ bool valid_race(const struct faction *f, const struct race *rc)
else {
const char *str = get_param(f->race->parameters, "other_race");
if (str)
- return (bool)(rc_find(str) == rc);
+ return rc_find(str) == rc;
return false;
}
}
@@ -753,12 +753,9 @@ int count_migrants(const faction * f)
return count_faction(f, COUNT_MIGRANTS);
}
-#define MIGRANTS_NONE 0
-#define MIGRANTS_LOG10 1
-
int count_maxmigrants(const faction * f)
{
- int formula = get_param_int(f->race->parameters, "migrants.formula", 0);
+ int formula = rc_migrants_formula(f->race);
if (formula == MIGRANTS_LOG10) {
int nsize = count_all(f);
diff --git a/src/kernel/faction.test.c b/src/kernel/faction.test.c
index b18121e2d..1b1a0236b 100644
--- a/src/kernel/faction.test.c
+++ b/src/kernel/faction.test.c
@@ -3,9 +3,10 @@
#include
#include
#include
+#include
#include
#include
-#include
+#include
#include
#include
#include
@@ -191,9 +192,27 @@ static void test_set_origin_bug(CuTest *tc) {
test_cleanup();
}
+static void test_max_migrants(CuTest *tc) {
+ faction *f;
+ unit *u;
+ race *rc;
+
+ test_setup();
+ rc = test_create_race("human");
+ f = test_create_faction(rc);
+ u = test_create_unit(f, test_create_region(0, 0, 0));
+ CuAssertIntEquals(tc, 0, count_maxmigrants(f));
+ rc->flags |= RCF_MIGRANTS;
+ CuAssertIntEquals(tc, 0, count_maxmigrants(f));
+ scale_number(u, 250);
+ CuAssertIntEquals(tc, 13, count_maxmigrants(f));
+ test_cleanup();
+}
+
CuSuite *get_faction_suite(void)
{
CuSuite *suite = CuSuiteNew();
+ SUITE_ADD_TEST(suite, test_max_migrants);
SUITE_ADD_TEST(suite, test_addfaction);
SUITE_ADD_TEST(suite, test_remove_empty_factions);
SUITE_ADD_TEST(suite, test_destroyfaction_allies);
diff --git a/src/kernel/jsonconf.c b/src/kernel/jsonconf.c
index 03e210ce0..7a074a410 100644
--- a/src/kernel/jsonconf.c
+++ b/src/kernel/jsonconf.c
@@ -458,10 +458,10 @@ static void json_race(cJSON *json, race *rc) {
break;
case cJSON_Number:
if (strcmp(child->string, "magres") == 0) {
- rc->magres = (float)child->valuedouble;
+ rc->magres = child->valueint;
}
else if (strcmp(child->string, "maxaura") == 0) {
- rc->maxaura = (float)child->valuedouble;
+ rc->maxaura = child->valueint;
}
else if (strcmp(child->string, "regaura") == 0) {
rc->regaura = (float)child->valuedouble;
diff --git a/src/kernel/jsonconf.test.c b/src/kernel/jsonconf.test.c
index 93fcd8d10..7c591f075 100644
--- a/src/kernel/jsonconf.test.c
+++ b/src/kernel/jsonconf.test.c
@@ -136,8 +136,8 @@ static void test_races(CuTest * tc)
{
const char * data = "{\"races\": { \"orc\" : { "
"\"damage\" : \"1d4\","
- "\"magres\" : 1.0,"
- "\"maxaura\" : 2.0,"
+ "\"magres\" : 100,"
+ "\"maxaura\" : 200,"
"\"regaura\" : 3.0,"
"\"speed\" : 4.0,"
"\"recruitcost\" : 1,"
@@ -163,8 +163,10 @@ static void test_races(CuTest * tc)
CuAssertPtrNotNull(tc, rc);
CuAssertIntEquals(tc, RCF_NPC | RCF_WALK | RCF_UNDEAD, rc->flags);
CuAssertStrEquals(tc, "1d4", rc->def_damage);
- CuAssertDblEquals(tc, 1.0, rc->magres, 0.0);
- CuAssertDblEquals(tc, 2.0, rc->maxaura, 0.0);
+ CuAssertIntEquals(tc, 100, rc->magres);
+ CuAssertDblEquals(tc, 1.0, rc_magres(rc), 0.0);
+ CuAssertIntEquals(tc, 200, rc->maxaura);
+ CuAssertDblEquals(tc, 2.0, rc_maxaura(rc), 0.0);
CuAssertDblEquals(tc, 3.0, rc->regaura, 0.0);
CuAssertDblEquals(tc, 4.0, rc->speed, 0.0);
CuAssertIntEquals(tc, 1, rc->recruitcost);
diff --git a/src/kernel/race.c b/src/kernel/race.c
index 1bdba8a1b..7f6fe15c2 100644
--- a/src/kernel/race.c
+++ b/src/kernel/race.c
@@ -282,6 +282,23 @@ bool r_insectstalled(const region * r)
return fval(r->terrain, ARCTIC_REGION);
}
+double rc_magres(const race *rc) {
+ return rc->magres / 100.0;
+}
+
+double rc_maxaura(const race *rc) {
+ return rc->maxaura / 100.0;
+}
+
+int rc_armor_bonus(const race *rc) {
+ return get_param_int(rc->parameters, "armor.stamina", 0);
+}
+
+int rc_migrants_formula(const race *rc)
+{
+ return (rc->flags&RCF_MIGRANTS) ? MIGRANTS_LOG10 : MIGRANTS_NONE;
+}
+
const char* rc_name(const race * rc, name_t n, char *name, size_t size) {
const char * postfix = 0;
if (!rc) {
diff --git a/src/kernel/race.h b/src/kernel/race.h
index 19b7b7ad3..67eea00f4 100644
--- a/src/kernel/race.h
+++ b/src/kernel/race.h
@@ -116,9 +116,9 @@ extern "C" {
typedef struct race {
char *_name;
- float magres;
- float healing;
- double maxaura; /* Faktor auf Maximale Aura */
+ int magres;
+ int healing;
+ int maxaura; /* Faktor auf Maximale Aura */
double regaura; /* Faktor auf Regeneration */
double recruit_multi; /* Faktor f�r Bauernverbrauch */
int index;
@@ -184,6 +184,14 @@ extern "C" {
const char * rc_name_s(const race *rc, name_t n);
const char * rc_name(const race *rc, name_t n, char *name, size_t size);
+ double rc_magres(const struct race *rc);
+ double rc_maxaura(const struct race *rc);
+ int rc_armor_bonus(const struct race *rc);
+
+#define MIGRANTS_NONE 0
+#define MIGRANTS_LOG10 1
+ int rc_migrants_formula(const race *rc);
+
/* Flags. Do not reorder these without changing json_race() in jsonconf.c */
#define RCF_NPC (1<<0) /* cannot be the race for a player faction (and other limits?) */
#define RCF_KILLPEASANTS (1<<1) /* a monster that eats peasants */
@@ -215,6 +223,7 @@ extern "C" {
#define RCF_STONEGOLEM (1<<27) /* race gets stonegolem properties */
#define RCF_IRONGOLEM (1<<28) /* race gets irongolem properties */
#define RCF_ATTACK_MOVED (1<<29) /* may attack if it has moved */
+#define RCF_MIGRANTS (1<<30) /* may have migrant units (human bonus) */
/* Economic flags */
#define ECF_KEEP_ITEM (1<<1) /* gibt Gegenst�nde weg */
diff --git a/src/kernel/race.test.c b/src/kernel/race.test.c
index 663a538ee..b730676a4 100644
--- a/src/kernel/race.test.c
+++ b/src/kernel/race.test.c
@@ -23,8 +23,11 @@ static void test_rc_defaults(CuTest *tc) {
test_setup();
rc = rc_get_or_create("human");
CuAssertStrEquals(tc, "human", rc->_name);
- CuAssertDblEquals(tc, 0.0, rc->magres, 0.0);
- CuAssertDblEquals(tc, 0.0, rc->maxaura, 0.0);
+ CuAssertIntEquals(tc, 0, rc_armor_bonus(rc));
+ CuAssertIntEquals(tc, 0, rc->magres);
+ CuAssertDblEquals(tc, 0.0, rc_magres(rc), 0.0);
+ CuAssertIntEquals(tc, 0, rc->healing);
+ CuAssertDblEquals(tc, 0.0, rc_maxaura(rc), 0.0);
CuAssertDblEquals(tc, 1.0, rc->recruit_multi, 0.0);
CuAssertDblEquals(tc, 1.0, rc->regaura, 0.0);
CuAssertDblEquals(tc, 1.0, rc->speed, 0.0);
diff --git a/src/kernel/unit.c b/src/kernel/unit.c
index 29766d4ef..27a296a15 100644
--- a/src/kernel/unit.c
+++ b/src/kernel/unit.c
@@ -2047,3 +2047,26 @@ bool has_limited_skills(const struct unit * u)
return false;
}
+double u_heal_factor(const unit * u)
+{
+ const race * rc = u_race(u);
+ if (rc->healing>0) {
+ return rc->healing / 100.0;
+ }
+ if (r_isforest(u->region)) {
+ static int rc_cache;
+ static const race *rc_elf;
+ if (rc_changed(&rc_cache)) {
+ rc_elf = get_race(RC_ELF);
+ }
+ if (rc == rc_elf) {
+ static int cache;
+ static double elf_regen;
+ if (config_changed(&cache)) {
+ elf_regen = config_get_flt("healing.forest", 1.0);
+ }
+ return elf_regen;
+ }
+ }
+ return 1.0;
+}
diff --git a/src/kernel/unit.h b/src/kernel/unit.h
index e846ca1f4..14096c872 100644
--- a/src/kernel/unit.h
+++ b/src/kernel/unit.h
@@ -190,6 +190,7 @@ extern "C" {
bool leave(struct unit *u, bool force);
bool can_leave(struct unit *u);
+ double u_heal_factor(const struct unit * u);
void u_set_building(struct unit * u, struct building * b);
void u_set_ship(struct unit * u, struct ship * sh);
void leave_ship(struct unit * u);
diff --git a/src/kernel/unit.test.c b/src/kernel/unit.test.c
index b0a2891c5..1ddf6282e 100644
--- a/src/kernel/unit.test.c
+++ b/src/kernel/unit.test.c
@@ -8,6 +8,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -483,6 +484,32 @@ static void test_name_unit(CuTest *tc) {
test_cleanup();
}
+static void test_heal_factor(CuTest *tc) {
+ unit * u;
+ region *r;
+ race *rc;
+ terrain_type *t_plain;
+
+ test_setup();
+ t_plain = test_create_terrain("plain", LAND_REGION|FOREST_REGION);
+ rc = rc_get_or_create("human");
+ u = test_create_unit(test_create_faction(rc), r = test_create_region(0, 0, t_plain));
+ rsettrees(r, 1, r->terrain->size / TREESIZE);
+ rsettrees(r, 2, 0);
+ CuAssertTrue(tc, r_isforest(r));
+ CuAssertDblEquals(tc, 1.0, u_heal_factor(u), 0.0);
+ rc->healing = 200;
+ CuAssertDblEquals(tc, 2.0, u_heal_factor(u), 0.0);
+ rc->healing = 0;
+ rc = rc_get_or_create("elf");
+ CuAssertPtrEquals(tc, (void *)rc, (void *)get_race(RC_ELF));
+ u_setrace(u, get_race(RC_ELF));
+ CuAssertDblEquals(tc, 1.0, u_heal_factor(u), 0.0);
+ config_set("healing.forest", "1.5");
+ CuAssertDblEquals(tc, 1.5, u_heal_factor(u), 0.0);
+ test_cleanup();
+}
+
CuSuite *get_unit_suite(void)
{
CuSuite *suite = CuSuiteNew();
@@ -507,5 +534,6 @@ CuSuite *get_unit_suite(void)
SUITE_ADD_TEST(suite, test_limited_skills);
SUITE_ADD_TEST(suite, test_renumber_unit);
SUITE_ADD_TEST(suite, test_name_unit);
+ SUITE_ADD_TEST(suite, test_heal_factor);
return suite;
}
diff --git a/src/kernel/xmlreader.c b/src/kernel/xmlreader.c
index 854a6dd4c..a0172313a 100644
--- a/src/kernel/xmlreader.c
+++ b/src/kernel/xmlreader.c
@@ -1573,17 +1573,6 @@ static int parse_spells(xmlDocPtr doc)
return 0;
}
-static void parse_param(struct param **params, xmlNodePtr node)
-{
- xmlChar *propName = xmlGetProp(node, BAD_CAST "name");
- xmlChar *propValue = xmlGetProp(node, BAD_CAST "value");
-
- set_param(params, (const char *)propName, (const char *)propValue);
-
- xmlFree(propName);
- xmlFree(propValue);
-}
-
static void parse_ai(race * rc, xmlNodePtr node)
{
int n;
@@ -1635,9 +1624,9 @@ static int parse_races(xmlDocPtr doc)
rc->def_damage = strdup((const char *)propValue);
xmlFree(propValue);
- rc->magres = (float)xml_fvalue(node, "magres", rc->magres);
- rc->healing = (float)xml_fvalue(node, "healing", rc->healing);
- rc->maxaura = (float)xml_fvalue(node, "maxaura", rc->maxaura);
+ rc->magres = xml_ivalue(node, "magres", rc->magres);
+ rc->healing = (int)(xml_fvalue(node, "healing", rc->healing) * 100); // TODO: store as int in XML
+ rc->maxaura = (int)(xml_fvalue(node, "maxaura", rc->maxaura) * 100); // TODO: store as int in XML
rc->regaura = (float)xml_fvalue(node, "regaura", rc->regaura);
rc->recruitcost = xml_ivalue(node, "recruitcost", rc->recruitcost);
rc->maintenance = xml_ivalue(node, "maintenance", rc->maintenance);
@@ -1737,12 +1726,27 @@ static int parse_races(xmlDocPtr doc)
if (xml_bvalue(node, "noattack", false))
rc->battle_flags |= BF_NO_ATTACK;
+ rc->recruit_multi = 1.0;
for (child = node->children; child; child = child->next) {
if (strcmp((const char *)child->name, "ai") == 0) {
parse_ai(rc, child);
}
else if (strcmp((const char *)child->name, "param") == 0) {
- parse_param(&rc->parameters, child);
+ xmlChar *propName = xmlGetProp(child, BAD_CAST "name");
+ xmlChar *propValue = xmlGetProp(child, BAD_CAST "value");
+ if (strcmp((const char *)propName, "recruit_multi")==0) {
+ rc->recruit_multi = atof((const char *)propValue);
+ }
+ else if (strcmp((const char *)propName, "migrants.formula") == 0) {
+ if (propValue[0] == '1') {
+ rc->flags |= RCF_MIGRANTS;
+ }
+ }
+ else {
+ set_param(&rc->parameters, (const char *)propName, (const char *)propValue);
+ }
+ xmlFree(propName);
+ xmlFree(propValue);
}
}
rc->recruit_multi = get_param_flt(rc->parameters, "recruit_multi", 1.0);
diff --git a/src/laws.c b/src/laws.c
index 6b0bfda8d..98ff5d9f6 100644
--- a/src/laws.c
+++ b/src/laws.c
@@ -3271,30 +3271,6 @@ static int use_item(unit * u, const item_type * itype, int amount, struct order
}
}
-static double heal_factor(const unit * u)
-{
- const race * rc = u_race(u);
- if (rc->healing>0) {
- return rc->healing;
- }
- if (r_isforest(u->region)) {
- static int rc_cache;
- static const race *rc_elf;
- if (rc_changed(&rc_cache)) {
- rc_elf = get_race(RC_ELF);
- }
- if (rc==rc_elf) {
- static int config;
- static double elf_regen = 1.0;
- if (config_changed(&config)) {
- elf_regen = get_param_flt(u_race(u)->parameters, "regen.forest", 1.0F);
- }
- return elf_regen;
- }
- }
- return 1.0;
-}
-
void monthly_healing(void)
{
region *r;
@@ -3334,7 +3310,7 @@ void monthly_healing(void)
continue;
}
- p *= heal_factor(u);
+ p *= u_heal_factor(u);
if (u->hp < umhp) {
double maxheal = MAX(u->number, umhp / 20.0);
int addhp;
diff --git a/src/magic.c b/src/magic.c
index 7e820f9c3..89774e96a 100644
--- a/src/magic.c
+++ b/src/magic.c
@@ -719,7 +719,7 @@ static int use_item_aura(const region * r, const unit * u)
int sk, n;
sk = effskill(u, SK_MAGIC, r);
- n = (int)(sk * sk * u_race(u)->maxaura / 4);
+ n = (int)(sk * sk * rc_maxaura(u_race(u)) / 4);
return n;
}
@@ -727,13 +727,13 @@ static int use_item_aura(const region * r, const unit * u)
int max_spellpoints(const region * r, const unit * u)
{
int sk;
- double n, msp;
+ double n, msp = 0;
double potenz = 2.1;
double divisor = 1.2;
const struct resource_type *rtype;
sk = effskill(u, SK_MAGIC, r);
- msp = u_race(u)->maxaura * (pow(sk, potenz) / divisor + 1) + get_spchange(u);
+ msp = rc_maxaura(u_race(u)) * (pow(sk, potenz) / divisor + 1) + get_spchange(u);
rtype = rt_find("aurafocus");
if (rtype && i_get(u->items, rtype->itype) > 0) {
@@ -1149,7 +1149,7 @@ double magic_resistance(unit * target)
const curse_type * ct_goodresist = 0, *ct_badresist = 0;
const resource_type *rtype;
const race *rc = u_race(target);
- double probability = rc->magres;
+ double probability = rc_magres(rc);
const plane *pl = rplane(target->region);
if (rc == get_race(RC_HIRNTOETER) && !pl) {
diff --git a/src/magic.test.c b/src/magic.test.c
index befd1986d..4a6078589 100644
--- a/src/magic.test.c
+++ b/src/magic.test.c
@@ -413,11 +413,11 @@ static void test_magic_resistance(CuTest *tc) {
test_setup();
rc = test_create_race("human");
u = test_create_unit(test_create_faction(rc), test_create_region(0, 0, 0));
- CuAssertDblEquals(tc, rc->magres, magic_resistance(u), 0.01);
- rc->magres = 1.0;
+ CuAssertDblEquals(tc, rc->magres/100.0, magic_resistance(u), 0.01);
+ rc->magres = 100;
CuAssertDblEquals_Msg(tc, "magic resistance is capped at 0.9", 0.9, magic_resistance(u), 0.01);
rc = test_create_race("braineater");
- rc->magres = 1.0;
+ rc->magres = 100;
u_setrace(u, rc);
CuAssertDblEquals_Msg(tc, "brain eaters outside astral space have 50% magres", 0.5, magic_resistance(u), 0.01);
u->region->_plane = get_astralplane();
@@ -425,6 +425,29 @@ static void test_magic_resistance(CuTest *tc) {
test_cleanup();
}
+static void test_max_spellpoints(CuTest *tc) {
+ unit *u;
+ race *rc;
+
+ test_setup();
+ rc = test_create_race("human");
+ u = test_create_unit(test_create_faction(rc), test_create_region(0, 0, 0));
+ CuAssertIntEquals(tc, 1, max_spellpoints(u->region, u));
+ rc->maxaura = 100;
+ CuAssertIntEquals(tc, 1, max_spellpoints(u->region, u));
+ rc->maxaura = 200;
+ CuAssertIntEquals(tc, 2, max_spellpoints(u->region, u));
+ create_mage(u, M_GRAY);
+ set_level(u, SK_MAGIC, 1);
+ CuAssertIntEquals(tc, 3, max_spellpoints(u->region, u));
+ set_level(u, SK_MAGIC, 2);
+ CuAssertIntEquals(tc, 9, max_spellpoints(u->region, u));
+ // permanent aura loss:
+ CuAssertIntEquals(tc, 7, change_maxspellpoints(u, -2));
+ CuAssertIntEquals(tc, 7, max_spellpoints(u->region, u));
+ test_cleanup();
+}
+
CuSuite *get_magic_suite(void)
{
CuSuite *suite = CuSuiteNew();
@@ -441,5 +464,6 @@ CuSuite *get_magic_suite(void)
SUITE_ADD_TEST(suite, test_set_post_combatspell);
SUITE_ADD_TEST(suite, test_hasspell);
SUITE_ADD_TEST(suite, test_magic_resistance);
+ SUITE_ADD_TEST(suite, test_max_spellpoints);
return suite;
}
diff --git a/src/market.c b/src/market.c
index 42819325f..254d3a483 100644
--- a/src/market.c
+++ b/src/market.c
@@ -66,7 +66,7 @@ attrib_type at_market = {
NULL, NULL, NULL, ATF_UNIQUE
};
-static int rc_luxury_trade(const struct race *rc)
+int rc_luxury_trade(const struct race *rc)
{
if (rc) {
return get_param_int(rc->parameters, "luxury_trade", 1000);
@@ -74,7 +74,7 @@ static int rc_luxury_trade(const struct race *rc)
return 1000;
}
-static int rc_herb_trade(const struct race *rc)
+int rc_herb_trade(const struct race *rc)
{
if (rc) {
return get_param_int(rc->parameters, "herb_trade", 500);
diff --git a/src/market.h b/src/market.h
index 74dc8db17..8f1d39eb4 100644
--- a/src/market.h
+++ b/src/market.h
@@ -19,10 +19,14 @@ without prior permission by the authors of Eressea.
extern "C" {
#endif
struct building;
+ struct race;
bool markets_module(void);
void do_markets(void);
+ int rc_luxury_trade(const struct race *rc);
+ int rc_herb_trade(const struct race *rc);
+
#ifdef __cplusplus
}
#endif
diff --git a/src/market.test.c b/src/market.test.c
index 6f1d74b88..1e0195a57 100644
--- a/src/market.test.c
+++ b/src/market.test.c
@@ -80,9 +80,23 @@ static void test_market_curse(CuTest * tc)
CuAssertIntEquals(tc, 35, i_get(u->items, ltype));
}
+static void test_rc_trade(CuTest *tc) {
+ race *rc;
+ test_setup();
+ rc = test_create_race("human");
+ CuAssertIntEquals(tc, 1000, rc_luxury_trade(rc));
+ CuAssertIntEquals(tc, 500, rc_herb_trade(rc));
+ set_param(&rc->parameters, "luxury_trade", "100");
+ set_param(&rc->parameters, "herb_trade", "50");
+ CuAssertIntEquals(tc, 100, rc_luxury_trade(rc));
+ CuAssertIntEquals(tc, 50, rc_herb_trade(rc));
+ test_cleanup();
+}
+
CuSuite *get_market_suite(void)
{
CuSuite *suite = CuSuiteNew();
SUITE_ADD_TEST(suite, test_market_curse);
+ SUITE_ADD_TEST(suite, test_rc_trade);
return suite;
}
diff --git a/src/move.c b/src/move.c
index 0184d22ca..f06a0b901 100644
--- a/src/move.c
+++ b/src/move.c
@@ -2061,7 +2061,9 @@ static const region_list *travel_i(unit * u, const region_list * route_begin,
route_end = cap_route(r, route_begin, route_end, movement_speed(u));
route_end = travel_route(u, route_begin, route_end, ord, mode);
- get_followers(u, r, route_end, followers);
+ if (u->flags&UFL_FOLLOWED) {
+ get_followers(u, r, route_end, followers);
+ }
/* transportation */
for (ord = u->orders; ord; ord = ord->next) {
diff --git a/src/spy.c b/src/spy.c
index eb58f792a..0ca3050c2 100644
--- a/src/spy.c
+++ b/src/spy.c
@@ -229,7 +229,7 @@ int setstealth_cmd(unit * u, struct order *ord)
return 0;
}
- if (isdigit(s[0])) {
+ if (isdigit(*(const unsigned char *)s)) {
/* Tarnungslevel setzen */
level = atoi((const char *)s);
if (level > effskill(u, SK_STEALTH, 0)) {
diff --git a/src/tests.c b/src/tests.c
index eb2631afe..6a43e6e79 100644
--- a/src/tests.c
+++ b/src/tests.c
@@ -40,7 +40,7 @@ struct race *test_create_race(const char *name)
race *rc = rc_get_or_create(name);
rc->maintenance = 10;
rc->hitpoints = 20;
- rc->maxaura = 1.0;
+ rc->maxaura = 100;
rc->ec_flags |= GETITEM;
rc->battle_flags = BF_EQUIPMENT;
return rc;
@@ -217,6 +217,9 @@ terrain_type *
test_create_terrain(const char * name, unsigned int flags)
{
terrain_type * t = get_or_create_terrain(name);
+ if (flags & LAND_REGION) {
+ t->size = 1000;
+ }
t->flags = flags;
return t;
}
diff --git a/src/upkeep.c b/src/upkeep.c
index 94cbc341d..c53c321d0 100644
--- a/src/upkeep.c
+++ b/src/upkeep.c
@@ -59,7 +59,7 @@ static void help_feed(unit * donor, unit * u, int *need_p)
}
static const char *hunger_damage(const race *rc) {
- const char * damage = get_param(rc->parameters, "hunger.damage");
+ const char * damage = rc->parameters ? get_param(rc->parameters, "hunger.damage") : NULL;
if (!damage) {
damage = config_get("hunger.damage");
}
diff --git a/src/util/base36.c b/src/util/base36.c
index 7edb46027..285e9760e 100644
--- a/src/util/base36.c
+++ b/src/util/base36.c
@@ -39,9 +39,9 @@ int atoi36(const char *str)
while (isalnum(*(unsigned char *)s)) {
if (isupper(*(unsigned char *)s))
i = i * 36 + (*s) - 'A' + 10;
- else if (islower(*(unsigned char *)s))
+ else if (islower(*s))
i = i * 36 + (*s) - 'a' + 10;
- else if (isdigit(*(unsigned char *)s))
+ else if (isdigit(*s))
i = i * 36 + (*s) - '0';
else
break;
diff --git a/src/util/dice.c b/src/util/dice.c
index e28a4bccd..6fa50261d 100644
--- a/src/util/dice.c
+++ b/src/util/dice.c
@@ -49,7 +49,7 @@ static int term_eval(const char **sptr)
int state = 1;
for (;;) {
- if (isdigit(*(unsigned char *)c)) {
+ if (isdigit(*(const unsigned char *)c)) {
k = k * 10 + (*c - '0');
}
else if (*c == '+' || *c == '-' || *c == 0 || *c == '*' || *c == ')'
diff --git a/src/util/parser.c b/src/util/parser.c
index bbdb5ac7e..fca066cb1 100644
--- a/src/util/parser.c
+++ b/src/util/parser.c
@@ -6,7 +6,6 @@
#include
#include
-#include
#include
#include
@@ -251,7 +250,8 @@ unsigned int atoip(const char *s)
int n;
assert(s);
- n = isdigit(s[0]) ? atoi(s) : 0;
+ n = (s[0] >='0' && s[0]<='9');
+ n = n ? atoi(s) : 0;
if (n < 0)
n = 0;
diff --git a/src/util/translation.c b/src/util/translation.c
index c733cc272..fb89a5af9 100644
--- a/src/util/translation.c
+++ b/src/util/translation.c
@@ -354,7 +354,7 @@ static const char *parse(opstack ** stack, const char *inn,
return parse_symbol(stack, ++b, userdata);
break;
default:
- if (isdigit(*(unsigned char *)b) || *b == '-' || *b == '+') {
+ if (isdigit(*(const unsigned char *)b) || *b == '-' || *b == '+') {
return parse_int(stack, b);
}
else