diff --git a/res/eressea/races.xml b/res/eressea/races.xml
index 201a6a797..513797d8d 100644
--- a/res/eressea/races.xml
+++ b/res/eressea/races.xml
@@ -717,7 +717,7 @@
-
+
@@ -742,7 +742,7 @@
-
+
diff --git a/res/races/dragon.xml b/res/races/dragon.xml
index 7a6dee3a7..a1f347105 100644
--- a/res/races/dragon.xml
+++ b/res/races/dragon.xml
@@ -1,5 +1,5 @@
+"6" damage="2d30" unarmedattack="0" unarmeddefense="0" attackmodifier="7" defensemodifier="7" scarepeasants="yes" fly="yes" walk="yes" teach="no" getitem="yes" resistbash="yes" dragon="yes">
diff --git a/res/races/wyrm.xml b/res/races/wyrm.xml
index 8569f4c19..5c63b0fb6 100644
--- a/res/races/wyrm.xml
+++ b/res/races/wyrm.xml
@@ -1,4 +1,4 @@
-
+
diff --git a/res/races/youngdragon.xml b/res/races/youngdragon.xml
index 541f68142..fe29bbfde 100644
--- a/res/races/youngdragon.xml
+++ b/res/races/youngdragon.xml
@@ -1,4 +1,4 @@
-
+
diff --git a/src/battle.c b/src/battle.c
index 392b24441..534984fb1 100644
--- a/src/battle.c
+++ b/src/battle.c
@@ -1037,31 +1037,33 @@ static int rc_specialdamage(const unit *au, const unit *du, const struct weapon_
{
const race *ar = u_race(au);
int m, modifier = 0;
-
- switch (old_race(ar)) {
- case RC_HALFLING:
- if (wtype != NULL && dragonrace(u_race(du))) {
- modifier += 5;
+ if (wtype != NULL) {
+ if (fval(u_race(du), RCF_DRAGON)) {
+ static int cache;
+ static race *rc_halfling;
+ if (rc_changed(&cache)) {
+ rc_halfling = get_race(RC_HALFLING);
+ }
+ if (ar == rc_halfling) {
+ modifier += 5;
+ }
}
- break;
- default:
- break;
- }
- if (wtype != NULL && wtype->modifiers != NULL) {
- for (m = 0; wtype->modifiers[m].value; ++m) {
- /* weapon damage for this weapon, possibly by race */
- if (wtype->modifiers[m].flags & WMF_DAMAGE) {
- race_list *rlist = wtype->modifiers[m].races;
- if (rlist != NULL) {
- while (rlist) {
- if (rlist->data == ar)
- break;
- rlist = rlist->next;
+ if (wtype->modifiers != NULL) {
+ for (m = 0; wtype->modifiers[m].value; ++m) {
+ /* weapon damage for this weapon, possibly by race */
+ if (wtype->modifiers[m].flags & WMF_DAMAGE) {
+ race_list *rlist = wtype->modifiers[m].races;
+ if (rlist != NULL) {
+ while (rlist) {
+ if (rlist->data == ar)
+ break;
+ rlist = rlist->next;
+ }
+ if (rlist == NULL)
+ continue;
}
- if (rlist == NULL)
- continue;
+ modifier += wtype->modifiers[m].value;
}
- modifier += wtype->modifiers[m].value;
}
}
}
diff --git a/src/economy.c b/src/economy.c
index 1eda7bf61..ae13d5ecc 100644
--- a/src/economy.c
+++ b/src/economy.c
@@ -114,16 +114,20 @@ static void recruit_init(void)
int income(const unit * u)
{
- switch (old_race(u_race(u))) {
- case RC_FIREDRAGON:
- return 150 * u->number;
- case RC_DRAGON:
- return 1000 * u->number;
- case RC_WYRM:
- return 5000 * u->number;
- default:
- return 20 * u->number;
+ // TODO: make this a property, like race.income, no hard-coding of values
+ if (fval(u_race(u), RCF_DRAGON)) {
+ switch (old_race(u_race(u))) {
+ case RC_FIREDRAGON:
+ return 150 * u->number;
+ case RC_DRAGON:
+ return 1000 * u->number;
+ case RC_WYRM:
+ return 5000 * u->number;
+ default:
+ break;
+ }
}
+ return 20 * u->number;
}
static void scramble(void *data, unsigned int n, size_t width)
@@ -478,7 +482,7 @@ static void recruit(unit * u, struct order *ord, request ** recruitorders)
init_order(ord);
n = getint();
- if (n<=0) {
+ if (n <= 0) {
syntax_error(u, ord);
return;
}
@@ -796,7 +800,7 @@ static int maintain(building * b)
cost -=
use_pooled(u, m->rtype, GET_SLACK | GET_RESERVE | GET_POOLED_SLACK,
- cost);
+ cost);
assert(cost == 0);
}
if (work) {
@@ -815,7 +819,7 @@ void maintain_buildings(region * r)
while (*bp) {
building *b = *bp;
int flags = BLD_MAINTAINED;
-
+
if (!curse_active(get_curse(b->attribs, nocost_ct))) {
flags = maintain(b);
}
@@ -929,12 +933,12 @@ static void manufacture(unit * u, const item_type * itype, int want)
case EBUILDINGREQ:
ADDMSG(&u->faction->msgs,
msg_feedback(u, u->thisorder, "building_needed", "building",
- itype->construction->btype->_name));
+ itype->construction->btype->_name));
return;
case ELOWSKILL:
ADDMSG(&u->faction->msgs,
msg_feedback(u, u->thisorder, "manufacture_skills",
- "skill minskill product", sk, minskill, itype->rtype, 1));
+ "skill minskill product", sk, minskill, itype->rtype, 1));
return;
case ENOMATERIALS:
ADDMSG(&u->faction->msgs, msg_materials_required(u, u->thisorder,
@@ -1077,8 +1081,8 @@ static void allocate_resource(unit * u, const resource_type * rtype, int want)
skill_t sk = itype->construction->skill;
add_message(&u->faction->msgs,
msg_feedback(u, u->thisorder, "manufacture_skills",
- "skill minskill product", sk, itype->construction->minskill,
- itype->rtype));
+ "skill minskill product", sk, itype->construction->minskill,
+ itype->rtype));
return;
}
else {
@@ -1276,7 +1280,7 @@ attrib_allocation(const resource_type * rtype, region * r, allocation * alist)
}
typedef void(*allocate_function) (const resource_type *, struct region *,
-struct allocation *);
+ struct allocation *);
static allocate_function get_allocator(const struct resource_type *rtype)
{
@@ -1345,7 +1349,7 @@ static void create_potion(unit * u, const potion_type * ptype, int want)
case EBUILDINGREQ:
ADDMSG(&u->faction->msgs,
msg_feedback(u, u->thisorder, "building_needed", "building",
- ptype->itype->construction->btype->_name));
+ ptype->itype->construction->btype->_name));
break;
case ECOMPLETE:
assert(0);
@@ -1687,7 +1691,7 @@ static void buy(unit * u, request ** buyorders, struct order *ord)
kwd = init_order(ord);
assert(kwd == K_BUY);
n = getint();
- if (n<=0) {
+ if (n <= 0) {
cmistake(u, ord, 26, MSG_COMMERCE);
return;
}
@@ -2082,7 +2086,7 @@ static bool sell(unit * u, request ** sellorders, struct order *ord)
* produktion, wo für jedes produkt einzeln eine obere limite
* existiert, so dass man arrays von orders machen kann. */
- /* Ein Händler kann nur 10 Güter pro Talentpunkt handeln. */
+ /* Ein Händler kann nur 10 Güter pro Talentpunkt handeln. */
k = u->number * 10 * effskill(u, SK_TRADE, 0);
/* hat der Händler bereits gehandelt, muss die Menge der bereits
@@ -2188,7 +2192,7 @@ static void plant(unit * u, int raw)
if (skill < 6) {
ADDMSG(&u->faction->msgs,
msg_feedback(u, u->thisorder, "plant_skills",
- "skill minskill product", SK_HERBALISM, 6, itype->rtype, 1));
+ "skill minskill product", SK_HERBALISM, 6, itype->rtype, 1));
return;
}
/* Wasser des Lebens prüfen */
@@ -2202,7 +2206,7 @@ static void plant(unit * u, int raw)
if (n == 0) {
ADDMSG(&u->faction->msgs,
msg_feedback(u, u->thisorder, "resource_missing", "missing",
- itype->rtype));
+ itype->rtype));
return;
}
@@ -2218,7 +2222,7 @@ static void plant(unit * u, int raw)
/* Alles ok. Abziehen. */
use_pooled(u, rt_water, GET_DEFAULT, 1);
use_pooled(u, itype->rtype, GET_DEFAULT, n);
- rsetherbs(r, (short) (rherbs(r) + planted));
+ rsetherbs(r, (short)(rherbs(r) + planted));
ADDMSG(&u->faction->msgs, msg_message("plant", "unit region amount herb",
u, r, planted, itype->rtype));
}
@@ -2241,13 +2245,13 @@ static void planttrees(unit * u, int raw)
if (skill < 6) {
ADDMSG(&u->faction->msgs,
msg_feedback(u, u->thisorder, "plant_skills",
- "skill minskill product", SK_HERBALISM, 6, rtype, 1));
+ "skill minskill product", SK_HERBALISM, 6, rtype, 1));
return;
}
if (fval(r, RF_MALLORN) && skill < 7) {
ADDMSG(&u->faction->msgs,
msg_feedback(u, u->thisorder, "plant_skills",
- "skill minskill product", SK_HERBALISM, 7, rtype, 1));
+ "skill minskill product", SK_HERBALISM, 7, rtype, 1));
return;
}
@@ -2284,7 +2288,7 @@ static void breedtrees(unit * u, int raw)
int current_season;
region *r = u->region;
gamedate date;
-
+
get_gamedate(turn, &date);
current_season = date.season;
@@ -2536,7 +2540,7 @@ static void steal_cmd(unit * u, struct order *ord, request ** stealorders)
return;
}
id = read_unitid(u->faction, r);
- if (id>0) {
+ if (id > 0) {
u2 = findunitr(r, id);
}
if (u2 && u2->region == u->region) {
diff --git a/src/guard.c b/src/guard.c
index f779e7e2e..326b89bee 100644
--- a/src/guard.c
+++ b/src/guard.c
@@ -67,28 +67,34 @@ void update_guards(void)
unsigned int guard_flags(const unit * u)
{
+ // TODO: this should be a property of the race, like race.guard_flags
+ static int rc_cache;
+ static race *rc_elf, *rc_ent, *rc_ironkeeper;
+ const race *rc = u_race(u);
unsigned int flags =
GUARD_CREWS | GUARD_LANDING | GUARD_TRAVELTHRU | GUARD_TAX;
+ // TODO: configuration, not define
#if GUARD_DISABLES_PRODUCTION == 1
flags |= GUARD_PRODUCE;
#endif
#if GUARD_DISABLES_RECRUIT == 1
flags |= GUARD_RECRUIT;
#endif
- switch (old_race(u_race(u))) {
- case RC_ELF:
- if (u->faction->race != u_race(u))
- break;
- /* else fallthrough */
- case RC_TREEMAN:
+ if (rc_changed(&rc_cache)) {
+ rc_elf = get_race(RC_ELF);
+ rc_ent = get_race(RC_TREEMAN);
+ rc_ironkeeper = get_race(RC_IRONKEEPER);
+ }
+ if (rc == rc_elf) {
+ if (u->faction->race == u_race(u)) {
+ flags |= GUARD_TREES;
+ }
+ }
+ else if (rc == rc_ent) {
flags |= GUARD_TREES;
- break;
- case RC_IRONKEEPER:
+ }
+ else if (rc == rc_ironkeeper) {
flags = GUARD_MINING;
- break;
- default:
- /* TODO: This should be configuration variables, all of it */
- break;
}
return flags;
}
diff --git a/src/kernel/config.c b/src/kernel/config.c
index d78362f3c..dc61e643b 100644
--- a/src/kernel/config.c
+++ b/src/kernel/config.c
@@ -140,6 +140,7 @@ int NMRTimeout(void)
race_t old_race(const struct race * rc)
{
race_t i;
+ // TODO: this sucks so bad!
for (i = 0; i != MAXRACES; ++i) {
if (get_race(i) == rc) return i;
}
diff --git a/src/kernel/race.c b/src/kernel/race.c
index 57f443ea5..1088681d2 100644
--- a/src/kernel/race.c
+++ b/src/kernel/race.c
@@ -59,7 +59,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
/** external variables **/
race *races;
int num_races = 0;
-static int cache_breaker;
+static int rc_changes = 1;
static const char *racenames[MAXRACES] = {
"dwarf", "elf", NULL, "goblin", "human", "troll", "demon", "insect",
@@ -75,30 +75,15 @@ static const char *racenames[MAXRACES] = {
"clone"
};
-static race * race_cache[MAXRACES];
-
struct race *get_race(race_t rt) {
- static int cache = -1;
const char * name;
- race * result = 0;
assert(rt < MAXRACES);
name = racenames[rt];
if (!name) {
- return 0;
+ return NULL;
}
- if (cache_breaker != cache) {
- cache = cache_breaker;
- memset(race_cache, 0, sizeof(race_cache));
- return race_cache[rt] = rc_get_or_create(name);
- }
- else {
- result = race_cache[rt];
- if (!result) {
- result = race_cache[rt] = rc_get_or_create(name);
- }
- }
- return result;
+ return rc_get_or_create(name);
}
race_list *get_familiarraces(void)
@@ -147,6 +132,7 @@ void free_races(void) {
races = rc;
}
num_races = 0;
+ ++rc_changes;
}
static race *rc_find_i(const char *name)
@@ -168,6 +154,15 @@ const race * rc_find(const char *name) {
return rc_find_i(name);
}
+bool rc_changed(int *cache) {
+ assert(cache);
+ if (*cache != rc_changes) {
+ *cache = rc_changes;
+ return true;
+ }
+ return false;
+}
+
race *rc_get_or_create(const char *zName)
{
race *rc;
@@ -195,7 +190,7 @@ race *rc_get_or_create(const char *zName)
for (i = 1; i < RACE_ATTACKS; ++i)
rc->attack[i].type = AT_NONE;
rc->index = num_races++;
- ++cache_breaker;
+ ++rc_changes;
rc->next = races;
return races = rc;
}
diff --git a/src/kernel/race.h b/src/kernel/race.h
index b1632f62d..d11dc5fd1 100644
--- a/src/kernel/race.h
+++ b/src/kernel/race.h
@@ -180,6 +180,7 @@ extern "C" {
race_t old_race(const struct race *);
race *rc_get_or_create(const char *name);
+ bool rc_changed(int *cache);
const race *rc_find(const char *);
void free_races(void);
@@ -243,7 +244,7 @@ extern "C" {
#define omniscient(f) ((f)->race==get_race(RC_ILLUSION) || (f)->race==get_race(RC_TEMPLATE))
#define playerrace(rc) (!fval((rc), RCF_NPC))
-#define dragonrace(rc) ((rc) == get_race(RC_FIREDRAGON) || (rc) == get_race(RC_DRAGON) || (rc) == get_race(RC_WYRM) || (rc) == get_race(RC_BIRTHDAYDRAGON))
+#define dragonrace(rc) (fval(rc, RCF_DRAGON))
#define humanoidrace(rc) (fval((rc), RCF_UNDEAD) || (rc)==get_race(RC_DRACOID) || playerrace(rc))
#define illusionaryrace(rc) (fval(rc, RCF_ILLUSIONARY))
diff --git a/src/kernel/race.test.c b/src/kernel/race.test.c
index e8bbfcf29..7c464e4da 100644
--- a/src/kernel/race.test.c
+++ b/src/kernel/race.test.c
@@ -9,7 +9,7 @@
static void test_rc_name(CuTest *tc) {
struct race *rc;
- test_cleanup();
+ test_setup();
rc = test_create_race("human");
CuAssertStrEquals(tc, "race::human", rc_name_s(rc, NAME_SINGULAR));
CuAssertStrEquals(tc, "race::human_p", rc_name_s(rc, NAME_PLURAL));
@@ -20,7 +20,7 @@ static void test_rc_name(CuTest *tc) {
static void test_rc_defaults(CuTest *tc) {
struct race *rc;
- test_cleanup();
+ test_setup();
rc = rc_get_or_create("human");
CuAssertStrEquals(tc, "human", rc->_name);
CuAssertDblEquals(tc, 0.0, rc->magres, 0.0);
@@ -43,15 +43,32 @@ static void test_rc_defaults(CuTest *tc) {
static void test_rc_find(CuTest *tc) {
race *rc;
- test_cleanup();
+ test_setup();
rc = test_create_race("hungryhippos");
CuAssertPtrEquals(tc, rc, (void *)rc_find("hungryhippos"));
test_cleanup();
}
+static void test_race_get(CuTest *tc) {
+ int cache = 0;
+ race *rc;
+ test_setup();
+ CuAssertTrue(tc, rc_changed(&cache));
+ CuAssertTrue(tc, !rc_changed(&cache));
+ rc = get_race(RC_ELF);
+ CuAssertPtrEquals(tc, rc, (void *)rc_get_or_create("elf"));
+ CuAssertTrue(tc, rc_changed(&cache));
+ CuAssertTrue(tc, !rc_changed(&cache));
+ CuAssertPtrEquals(tc, rc, (void *)rc_find("elf"));
+ free_races();
+ CuAssertTrue(tc, rc_changed(&cache));
+ test_cleanup();
+}
+
CuSuite *get_race_suite(void)
{
CuSuite *suite = CuSuiteNew();
+ SUITE_ADD_TEST(suite, test_race_get);
SUITE_ADD_TEST(suite, test_rc_name);
SUITE_ADD_TEST(suite, test_rc_defaults);
SUITE_ADD_TEST(suite, test_rc_find);
diff --git a/src/kernel/skills.c b/src/kernel/skills.c
index caae7b836..e773424ab 100644
--- a/src/kernel/skills.c
+++ b/src/kernel/skills.c
@@ -104,16 +104,22 @@ int value, int flags)
int skill_mod(const race * rc, skill_t sk, const struct terrain_type *terrain)
{
int result = 0;
+ static int rc_cache;
+ static 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 == get_race(RC_DWARF)) {
+ if (rc == rc_dwarf) {
if (sk == SK_TACTICS) {
if (terrain == newterrain(T_MOUNTAIN) || fval(terrain, ARCTIC_REGION))
++result;
}
}
- else if (rc == get_race(RC_INSECT)) {
+ 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))
@@ -126,19 +132,25 @@ int skill_mod(const race * rc, skill_t sk, const struct terrain_type *terrain)
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 (rc == get_race(RC_ELF) && r && r_isforest(r)) {
- if (sk == SK_PERCEPTION || sk == SK_STEALTH) {
- ++mods;
+ if (r && r_isforest(r)) {
+ static int rc_cache;
+ static race * rc_elf;
+ if (rc_changed(&rc_cache)) {
+ rc_elf = get_race(RC_ELF);
}
- else if (sk == SK_TACTICS) {
- mods += 2;
+ if (rc == rc_elf) {
+ if (sk == SK_PERCEPTION || sk == SK_STEALTH) {
+ ++mods;
+ }
+ else if (sk == SK_TACTICS) {
+ mods += 2;
+ }
}
}
return mods;
diff --git a/src/laws.c b/src/laws.c
index 19078353e..199d9e0a0 100755
--- a/src/laws.c
+++ b/src/laws.c
@@ -3464,7 +3464,7 @@ static int use_item(unit * u, const item_type * itype, int amount, struct order
static double heal_factor(const unit * u)
{
double elf_regen;
-
+ // TODO: do not hard-code, make this a property, race.healing
switch (old_race(u_race(u))) {
case RC_TROLL:
case RC_DAEMON:
diff --git a/src/monster.c b/src/monster.c
index 5eafba1ea..37c48f8b5 100644
--- a/src/monster.c
+++ b/src/monster.c
@@ -83,6 +83,7 @@ static void eaten_by_monster(unit * u)
multi = RESOURCE_QUANTITY * newterrain(T_PLAIN)->size / 10000.0;
}
+ // TODO: do not hard-code, make it a race property or callback? it's already RCF_KILLPEASANTS
switch (old_race(u_race(u))) {
case RC_FIREDRAGON:
n = rng_int() % 80 * u->number;
@@ -118,12 +119,7 @@ static void eaten_by_monster(unit * u)
static void absorbed_by_monster(unit * u)
{
- int n;
-
- switch (old_race(u_race(u))) {
- default:
- n = rng_int() % (u->number / 20 + 1);
- }
+ int n = rng_int() % (u->number / 20 + 1);
if (n > 0) {
n = lovar(n);
diff --git a/src/monsters.c b/src/monsters.c
index 0da4947f2..78999e015 100644
--- a/src/monsters.c
+++ b/src/monsters.c
@@ -380,20 +380,15 @@ static order *monster_move(region * r, unit * u)
if (monster_is_waiting(u)) {
return NULL;
}
- switch (old_race(u_race(u))) {
- case RC_FIREDRAGON:
- case RC_DRAGON:
- case RC_WYRM:
+ if (fval(u_race(u), RCF_DRAGON)) {
d = richest_neighbour(r, u->faction, 1);
- break;
- case RC_TREEMAN:
- d = treeman_neighbour(r);
- break;
- default:
- d = random_neighbour(r, u);
- break;
}
-
+ else if (get_race(RC_TREEMAN)==u_race(u)) {
+ d = treeman_neighbour(r);
+ }
+ else {
+ d = random_neighbour(r, u);
+ }
/* falls kein geld gefunden wird, zufaellig verreisen, aber nicht in
* den ozean */
@@ -490,65 +485,6 @@ static order *make_movement_order(unit * u, const region * target, int moves,
return parse_order(zOrder, u->faction->locale);
}
-#ifdef TODO_ALP
-static order *monster_seeks_target(region * r, unit * u)
-{
- direction_t d;
- unit *target = NULL;
- int dist, dist2;
- direction_t i;
- region *nr;
-
- /* Das Monster sucht ein bestimmtes Opfer. Welches, steht
- * in einer Referenz/attribut
- * derzeit gibt es nur den alp
- */
-
- switch (old_race(u_race(u))) {
- case RC_ALP:
- target = alp_target(u);
- break;
- default:
- assert(!"Seeker-Monster gibt kein Ziel an");
- }
-
- /* TODO: prüfen, ob target überhaupt noch existiert... */
- if (!target) {
- log_error("Monster '%s' hat kein Ziel!\n", unitname(u));
- return NULL; /* this is a bug workaround! remove!! */
- }
-
- if (r == target->region) { /* Wir haben ihn! */
- if (u_race(u) == get_race(RC_ALP)) {
- alp_findet_opfer(u, r);
- } else {
- assert(!"Seeker-Monster hat keine Aktion fuer Ziel");
- }
- return NULL;
- }
-
- /* Simpler Ansatz: Nachbarregion mit gerinster Distanz suchen.
- * Sinnvoll momentan nur bei Monstern, die sich nicht um das
- * Terrain kümmern. Nebelwände & Co machen derzeit auch nix...
- */
- dist2 = distance(r, target->region);
- d = NODIRECTION;
- for (i = 0; i < MAXDIRECTIONS; i++) {
- nr = rconnect(r, i);
- assert(nr);
- dist = distance(nr, target->region);
- if (dist < dist2) {
- dist2 = dist;
- d = i;
- }
- }
- assert(d != NODIRECTION);
-
- return create_order(K_MOVE, u->faction->locale, "%s",
- LOC(u->faction->locale, directions[d]));
-}
-#endif
-
void random_growl(const unit *u, region *target, int rand)
{
const struct locale *lang = u->faction->locale;
@@ -657,6 +593,13 @@ static order *plan_dragon(unit * u)
region *tr = NULL;
bool move = false;
order *long_order = NULL;
+ static int rc_cache;
+ static const race *rc_wyrm;
+ const race * rc = u_race(u);
+
+ if (rc_changed(&rc_cache)) {
+ rc_wyrm = get_race(RC_WYRM);
+ }
if (ta == NULL) {
move |= (rpeasants(r) == 0); /* when no peasants, move */
@@ -664,7 +607,7 @@ static order *plan_dragon(unit * u)
}
move |= chance(0.04); /* 4% chance to change your mind */
- if (u_race(u) == get_race(RC_WYRM) && !move) {
+ if (rc == rc_wyrm && !move) {
unit *u2;
for (u2 = r->units; u2; u2 = u2->next) {
/* wyrme sind einzelgänger */
@@ -694,18 +637,21 @@ static order *plan_dragon(unit * u)
}
if (tr != NULL) {
assert(long_order == NULL);
- switch (old_race(u_race(u))) {
- case RC_FIREDRAGON:
- long_order = make_movement_order(u, tr, 4, allowed_dragon);
- break;
- case RC_DRAGON:
- long_order = make_movement_order(u, tr, 3, allowed_dragon);
- break;
- case RC_WYRM:
+ // TODO: per-race planning functions?
+ if (rc == rc_wyrm) {
long_order = make_movement_order(u, tr, 1, allowed_dragon);
- break;
- default:
- break;
+ }
+ else {
+ switch (old_race(rc)) {
+ case RC_FIREDRAGON:
+ long_order = make_movement_order(u, tr, 4, allowed_dragon);
+ break;
+ case RC_DRAGON:
+ long_order = make_movement_order(u, tr, 3, allowed_dragon);
+ break;
+ default:
+ break;
+ }
}
if (long_order) {
reduce_weight(u);
@@ -757,6 +703,7 @@ void plan_monsters(faction * f)
bool attacking = chance(attack_chance);
for (u = r->units; u; u = u->next) {
+ const race *rc = u_race(u);
attrib *ta;
order *long_order = NULL;
@@ -812,7 +759,7 @@ void plan_monsters(faction * f)
a_remove(&u->attribs, ta);
}
}
- else if (u_race(u)->flags & RCF_MOVERANDOM) {
+ else if (rc->flags & RCF_MOVERANDOM) {
if (chance(random_move_chance()) || check_overpopulated(u)) {
long_order = monster_move(r, u);
}
@@ -826,31 +773,24 @@ void plan_monsters(faction * f)
handle_event(u->attribs, "ai_move", u);
}
- switch (old_race(u_race(u))) {
- case RC_SEASERPENT:
- long_order = create_order(K_PIRACY, f->locale, NULL);
- break;
-#ifdef TODO_ALP
- case RC_ALP:
- long_order = monster_seeks_target(r, u);
- break;
-#endif
- case RC_FIREDRAGON:
- case RC_DRAGON:
- case RC_WYRM:
+ if (fval(rc, RCF_DRAGON)) {
long_order = plan_dragon(u);
- break;
- default:
- if (u_race(u)->flags & RCF_LEARN) {
- long_order = monster_learn(u);
+ }
+ else {
+ if (rc == get_race(RC_SEASERPENT)) {
+ long_order = create_order(K_PIRACY, f->locale, NULL);
+ }
+ else {
+ if (rc->flags & RCF_LEARN) {
+ long_order = monster_learn(u);
+ }
}
- break;
}
}
if (long_order == NULL && unit_can_study(u)) {
/* Einheiten, die Waffenlosen Kampf lernen könnten, lernen es um
* zu bewachen: */
- if (u_race(u)->bonus[SK_WEAPONLESS] != -99) {
+ if (rc->bonus[SK_WEAPONLESS] != -99) {
if (effskill(u, SK_WEAPONLESS, 0) < 1) {
long_order =
create_order(K_STUDY, f->locale, "'%s'",
diff --git a/src/monsters.test.c b/src/monsters.test.c
index a44a354d9..6797a9ce0 100644
--- a/src/monsters.test.c
+++ b/src/monsters.test.c
@@ -54,8 +54,7 @@ static void create_monsters(faction **player, faction **monsters, unit **u, unit
*monsters = get_or_create_monsters();
assert(rc_find((*monsters)->race->_name));
rc = rc_get_or_create((*monsters)->race->_name);
- fset(rc, RCF_UNARMEDGUARD);
- fset(rc, RCF_NPC);
+ fset(rc, RCF_UNARMEDGUARD|RCF_NPC|RCF_DRAGON);
fset(*monsters, FFL_NOIDLEOUT);
assert(fval(*monsters, FFL_NPC) && fval((*monsters)->race, RCF_UNARMEDGUARD) && fval((*monsters)->race, RCF_NPC) && fval(*monsters, FFL_NOIDLEOUT));
diff --git a/src/move.c b/src/move.c
index c95775b5a..63c79dd6b 100644
--- a/src/move.c
+++ b/src/move.c
@@ -1465,16 +1465,15 @@ static void make_route(unit * u, order * ord, region_list ** routep)
static int movement_speed(unit * u)
{
int mp = BP_WALKING;
- double dk = u_race(u)->speed;
-
+ const race *rc = u_race(u);
+ double dk = rc->speed;
assert(u->number);
/* dragons have a fixed speed, and no other effects work on them: */
- switch (old_race(u_race(u))) {
- case RC_DRAGON:
- case RC_WYRM:
- case RC_FIREDRAGON:
+ if (fval(rc, RCF_DRAGON)) {
return BP_DRAGON;
- case RC_BIRTHDAYDRAGON:
+ }
+ switch (old_race(u_race(u))) {
+ case RC_BIRTHDAYDRAGON: // FIXME: catdragon has RCF_DRAGON, so this cannot happen
case RC_SONGDRAGON:
mp = BP_DRAGON;
break;
diff --git a/src/spells.c b/src/spells.c
index ab4d6dd6d..a860abe3c 100644
--- a/src/spells.c
+++ b/src/spells.c
@@ -1501,16 +1501,23 @@ static int sp_create_irongolem(castorder * co)
int cast_level = co->level;
double force = co->force;
int number = lovar(force * 8 * RESOURCE_QUANTITY);
- if (number < 1)
+ static int cache;
+ static const race * golem_rc;
+
+ if (rc_changed(&cache)) {
+ golem_rc = rc_find("irongolem");
+ }
+
+ if (number < 1) {
number = 1;
+ }
if (r->terrain == newterrain(T_SWAMP)) {
cmistake(mage, co->order, 188, MSG_MAGIC);
return 0;
}
- u2 =
- create_unit(r, mage->faction, number, rc_find("irongolem"), 0, NULL, mage);
+ u2 = create_unit(r, mage->faction, number, golem_rc, 0, NULL, mage);
set_level(u2, SK_ARMORER, 1);
set_level(u2, SK_WEAPONSMITH, 1);
@@ -1523,7 +1530,7 @@ static int sp_create_irongolem(castorder * co)
ADDMSG(&mage->faction->msgs,
msg_message("magiccreate_effect", "region command unit amount object",
mage->region, co->order, mage, number,
- LOC(mage->faction->locale, rc_name_s(rc_find("irongolem"), (u2->number == 1) ? NAME_SINGULAR : NAME_PLURAL))));
+ LOC(mage->faction->locale, rc_name_s(golem_rc, (u2->number == 1) ? NAME_SINGULAR : NAME_PLURAL))));
return cast_level;
}
@@ -1563,6 +1570,12 @@ static int sp_create_stonegolem(castorder * co)
unit *mage = co->magician.u;
int cast_level = co->level;
int number = lovar(co->force * 5 * RESOURCE_QUANTITY);
+ static int cache;
+ static const race * golem_rc;
+
+ if (rc_changed(&cache)) {
+ golem_rc = rc_find("stonegolem");
+ }
if (number < 1)
number = 1;
@@ -1572,7 +1585,7 @@ static int sp_create_stonegolem(castorder * co)
}
u2 =
- create_unit(r, mage->faction, number, rc_find("stonegolem"), 0, NULL, mage);
+ create_unit(r, mage->faction, number, golem_rc, 0, NULL, mage);
set_level(u2, SK_ROAD_BUILDING, 1);
set_level(u2, SK_BUILDING, 1);
@@ -1584,7 +1597,7 @@ static int sp_create_stonegolem(castorder * co)
ADDMSG(&mage->faction->msgs,
msg_message("magiccreate_effect", "region command unit amount object",
mage->region, co->order, mage, number,
- LOC(mage->faction->locale, rc_name_s(rc_find("stonegolem"), (u2->number == 1) ? NAME_SINGULAR : NAME_PLURAL))));
+ LOC(mage->faction->locale, rc_name_s(golem_rc, (u2->number == 1) ? NAME_SINGULAR : NAME_PLURAL))));
return cast_level;
}
@@ -2717,6 +2730,26 @@ static int sp_firewall(castorder * co)
* (SPELLLEVEL | TESTCANSEE)
*/
+static race *unholy_race(const race *rc) {
+ static int cache;
+ static race * rc_skeleton, *rc_zombie, *rc_ghoul;
+ if (rc_changed(&cache)) {
+ rc_skeleton = get_race(RC_SKELETON);
+ rc_zombie = get_race(RC_ZOMBIE);
+ rc_ghoul = get_race(RC_GHOUL);
+ }
+ if (rc == rc_skeleton) {
+ return get_race(RC_SKELETON_LORD);
+ }
+ if (rc == rc_zombie) {
+ return get_race(RC_ZOMBIE_LORD);
+ }
+ if (rc == rc_ghoul) {
+ return get_race(RC_GHOUL_LORD);
+ }
+ return NULL;
+}
+
static int sp_unholypower(castorder * co)
{
region * r = co_get_region(co);
@@ -2739,17 +2772,8 @@ static int sp_unholypower(castorder * co)
u = pa->param[i]->data.u;
- switch (old_race(u_race(u))) {
- case RC_SKELETON:
- target_race = get_race(RC_SKELETON_LORD);
- break;
- case RC_ZOMBIE:
- target_race = get_race(RC_ZOMBIE_LORD);
- break;
- case RC_GHOUL:
- target_race = get_race(RC_GHOUL_LORD);
- break;
- default:
+ target_race = unholy_race(u_race(u));
+ if (!target_race) {
cmistake(mage, co->order, 284, MSG_MAGIC);
continue;
}
diff --git a/src/study.c b/src/study.c
index 58cbde94a..70c016dfc 100644
--- a/src/study.c
+++ b/src/study.c
@@ -94,6 +94,9 @@ magic_t getmagicskill(const struct locale * lang)
/* familiars and toads are not migrants */
bool is_migrant(unit * u)
{
+ static int cache;
+ static race *toad_rc;
+
if (u_race(u) == u->faction->race)
return false;
@@ -101,16 +104,21 @@ bool is_migrant(unit * u)
return false;
if (is_familiar(u))
return false;
- if (u_race(u) == get_race(RC_TOAD))
- return false;
-
- return true;
+ if (rc_changed(&cache)) {
+ toad_rc = get_race(RC_TOAD);
+ }
+ return u_race(u) != toad_rc;
}
/* ------------------------------------------------------------- */
bool magic_lowskill(unit * u)
{
- return (u_race(u) == get_race(RC_TOAD)) ? true : false;
+ static race *toad_rc;
+ static int cache;
+ if (rc_changed(&cache)) {
+ toad_rc = get_race(RC_TOAD);
+ }
+ return u_race(u) == toad_rc;
}
/* ------------------------------------------------------------- */
diff --git a/src/volcano.c b/src/volcano.c
index 910bd8775..bd8c56b30 100644
--- a/src/volcano.c
+++ b/src/volcano.c
@@ -118,7 +118,7 @@ damage_unit(unit * u, const char *dam, bool physical, bool magic)
heiltrank = 0;
/* Sieben Leben */
- if (old_race(u_race(u)) == RC_CAT && (chance(1.0 / 7))) {
+ if (u_race(u) == get_race(RC_CAT) && (chance(1.0 / 7))) {
hp[i] = u->hp / u->number;
hp_rem += hp[i];
continue;