BUG 2423: only apply other skill modifiers if race-modifier doesn't drop skill below 1.

This commit is contained in:
Enno Rehling 2018-03-04 20:30:29 +01:00
parent 7e33b2a94d
commit ef3b72ceb7
6 changed files with 111 additions and 74 deletions

View File

@ -21,10 +21,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#include "skill.h"
#include "curse.h"
#include "race.h"
#include "region.h"
#include "terrain.h"
#include "terrainid.h"
#include "unit.h"
#include <util/attrib.h>
@ -91,64 +88,9 @@ skillmod(const unit * u, const region * r, skill_t sk, int value)
return value;
}
int skill_mod(const race * rc, skill_t sk, const struct terrain_type *terrain)
{
int result = 0;
static int rc_cache;
static const race *rc_dwarf, *rc_insect;
if (rc_changed(&rc_cache)) {
rc_dwarf = get_race(RC_DWARF);
rc_insect = get_race(RC_INSECT);
}
result = rc->bonus[sk];
if (rc == rc_dwarf) {
if (sk == SK_TACTICS) {
if (terrain == newterrain(T_MOUNTAIN) || fval(terrain, ARCTIC_REGION))
++result;
}
}
else if (rc == rc_insect) {
if (terrain == newterrain(T_MOUNTAIN) || fval(terrain, ARCTIC_REGION))
--result;
else if (terrain == newterrain(T_DESERT) || terrain == newterrain(T_SWAMP))
++result;
}
return result;
}
int rc_skillmod(const struct race *rc, const region * r, skill_t sk)
{
int mods = 0;
if (!skill_enabled(sk)) {
return 0;
}
if (r) {
mods = skill_mod(rc, sk, r->terrain);
}
if (r && r_isforest(r)) {
static int rc_cache;
static const race * rc_elf;
if (rc_changed(&rc_cache)) {
rc_elf = get_race(RC_ELF);
}
if (rc == rc_elf) {
if (sk == SK_PERCEPTION || sk == SK_STEALTH) {
++mods;
}
else if (sk == SK_TACTICS) {
mods += 2;
}
}
}
return mods;
}
int level_days(int level)
{
/* FIXME STUDYDAYS * ((level + 1) * level / 2); */
/* FIXME STUDYDAYS * ((level + 1) * level / 2); */
return 30 * ((level + 1) * level / 2);
}

View File

@ -44,7 +44,6 @@ extern "C" {
extern struct attrib_type at_skillmod;
int rc_skillmod(const struct race *rc, const struct region *r, skill_t sk);
int skillmod(const struct unit *u, const struct region *r, skill_t sk, int value);
struct attrib *make_skillmod(skill_t sk, skillmod_fun special, double multiplier, int bonus);

View File

@ -38,6 +38,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#include "ship.h"
#include "skill.h"
#include "terrain.h"
#include "terrainid.h"
#include <attributes/otherfaction.h>
#include <attributes/racename.h>
@ -641,7 +642,7 @@ bool ucontact(const unit * u, const unit * u2)
/* Explizites KONTAKTIERE */
for (ru = a_find(u->attribs, &at_contact); ru && ru->type == &at_contact;
ru = ru->next) {
ru = ru->next) {
if (((unit *)ru->data.v) == u2) {
return true;
}
@ -1132,8 +1133,8 @@ skill *add_skill(unit * u, skill_t sk)
skill *sv;
int i;
for (i=0; i != u->skill_size; ++i) {
sv = u->skills+i;
for (i = 0; i != u->skill_size; ++i) {
sv = u->skills + i;
if (sv->id >= sk) break;
}
u->skills = realloc(u->skills, (1 + u->skill_size) * sizeof(skill));
@ -1235,8 +1236,62 @@ static int att_modification(const unit * u, skill_t sk)
return (int)result;
}
static int terrain_mod(const race * rc, skill_t sk, const region *r)
{
static int rc_cache, t_cache;
static const race *rc_dwarf, *rc_insect, *rc_elf;
static const terrain_type *t_mountain, *t_desert, *t_swamp;
const struct terrain_type *terrain = r->terrain;
if (terrain_changed(&t_cache)) {
t_mountain = get_terrain(terrainnames[T_MOUNTAIN]);
t_desert = get_terrain(terrainnames[T_DESERT]);
t_swamp = get_terrain(terrainnames[T_SWAMP]);
}
if (rc_changed(&rc_cache)) {
rc_elf = get_race(RC_ELF);
rc_dwarf = get_race(RC_DWARF);
rc_insect = get_race(RC_INSECT);
}
if (rc == rc_dwarf) {
if (sk == SK_TACTICS) {
if (terrain == t_mountain || fval(terrain, ARCTIC_REGION))
return 1;
}
}
else if (rc == rc_insect) {
if (terrain == t_mountain || fval(terrain, ARCTIC_REGION)) {
return -1;
}
else if (terrain == t_desert || terrain == t_swamp) {
return 1;
}
}
else if (rc == rc_elf) {
if (r_isforest(r)) {
if (sk == SK_PERCEPTION || sk == SK_STEALTH) {
return 1;
}
else if (sk == SK_TACTICS) {
return 2;
}
}
}
return 0;
}
static int rc_skillmod(const struct race *rc, skill_t sk)
{
if (!skill_enabled(sk)) {
return 0;
}
return rc->bonus[sk];
}
int get_modifier(const unit * u, skill_t sk, int level, const region * r, bool noitem)
{
const struct race *rc = u_race(u);
int bskill = level;
int skill = bskill;
@ -1247,12 +1302,16 @@ int get_modifier(const unit * u, skill_t sk, int level, const region * r, bool n
}
}
skill += rc_skillmod(u_race(u), r, sk);
skill += att_modification(u, sk);
if (u->attribs) {
skill = skillmod(u, r, sk, skill);
skill += rc_skillmod(rc, sk);
if (skill > 0) {
if (r) {
skill += terrain_mod(rc, sk, r);
}
skill += att_modification(u, sk);
if (u->attribs) {
skill = skillmod(u, r, sk, skill);
}
}
if (fval(u, UFL_HUNGER)) {
if (sk == SK_SAILING && skill > 2) {
skill = skill - 1;
@ -1374,7 +1433,7 @@ void default_name(const unit *u, char name[], int len) {
const char * prefix;
prefix = LOC(lang, "unitdefault");
if (!prefix) {
prefix= parameters[P_UNIT];
prefix = parameters[P_UNIT];
}
result = prefix;
}
@ -1631,7 +1690,7 @@ int unit_max_hp(const unit * u)
h = u_race(u)->hitpoints;
if (config_changed(&config)) {
rule_stamina = config_get_int("rules.stamina", 1)!=0;
rule_stamina = config_get_int("rules.stamina", 1) != 0;
}
if (rule_stamina) {
double p = pow(effskill(u, SK_STAMINA, u->region) / 2.0, 1.5) * 0.2;
@ -1654,7 +1713,7 @@ void scale_number(unit * u, int n)
return;
}
if (u->number > 0) {
if (n>0) {
if (n > 0) {
const attrib *a = a_find(u->attribs, &at_effect);
u->hp = (long long)u->hp * n / u->number;
@ -1928,7 +1987,7 @@ bool has_limited_skills(const struct unit * u)
double u_heal_factor(const unit * u)
{
const race * rc = u_race(u);
if (rc->healing>0) {
if (rc->healing > 0) {
return rc->healing / 100.0;
}
if (r_isforest(u->region)) {

View File

@ -622,6 +622,37 @@ static void test_transfermen(CuTest *tc) {
test_teardown();
}
static void test_get_modifier(CuTest *tc) {
race * rc;
region *r;
unit *u;
terrain_type *t_plain, *t_desert;
test_setup();
t_desert = test_create_terrain("desert", -1);
t_plain = test_create_terrain("plain", -1);
rc = test_create_race("insect");
rc->bonus[SK_ARMORER] = 1;
rc->bonus[SK_TAXING] = 0;
rc->bonus[SK_TRADE] = -1;
u = test_create_unit(test_create_faction(rc), r = test_create_region(0, 0, t_plain));
/* no effects for insects in plains: */
CuAssertIntEquals(tc, 0, get_modifier(u, SK_TAXING, 0, r, true));
CuAssertIntEquals(tc, 0, get_modifier(u, SK_TAXING, 1, r, true));
CuAssertIntEquals(tc, 0, get_modifier(u, SK_TAXING, 7, r, true));
r = test_create_region(1, 0, t_desert);
/* terrain effect: +1 for insects in deserts: */
CuAssertIntEquals(tc, 1, get_modifier(u, SK_TAXING, 1, r, true));
/* no terrain effects if no region is given: */
CuAssertIntEquals(tc, 0, get_modifier(u, SK_TAXING, 1, NULL, true));
/* only get terrain effect if they have at least level 1: */
CuAssertIntEquals(tc, 0, get_modifier(u, SK_TAXING, 0, r, true));
test_teardown();
}
CuSuite *get_unit_suite(void)
{
CuSuite *suite = CuSuiteNew();
@ -652,5 +683,6 @@ CuSuite *get_unit_suite(void)
SUITE_ADD_TEST(suite, test_renumber_unit);
SUITE_ADD_TEST(suite, test_name_unit);
SUITE_ADD_TEST(suite, test_heal_factor);
SUITE_ADD_TEST(suite, test_get_modifier);
return suite;
}

View File

@ -266,9 +266,14 @@ void test_teardown(void)
}
terrain_type *
test_create_terrain(const char * name, unsigned int flags)
test_create_terrain(const char * name, int flags)
{
terrain_type * t = get_or_create_terrain(name);
if (flags < 0) {
/* sensible defaults for most terrains */
flags = LAND_REGION | WALK_INTO | FLY_INTO;
}
if (flags & LAND_REGION) {
t->size = 1000;
}

View File

@ -41,7 +41,7 @@ extern "C" {
void test_log_stop(struct log_t *log, struct strlist *slist);
struct locale * test_create_locale(void);
struct terrain_type * test_create_terrain(const char * name, unsigned int flags);
struct terrain_type * test_create_terrain(const char * name, int flags);
struct race *test_create_race(const char *name);
struct region *test_create_region(int x, int y, const struct terrain_type *terrain);
struct region *test_create_ocean(int x, int y);