forked from github/server
Merge branch 'develop'
Conflicts: src/kernel/config.c
This commit is contained in:
commit
73f33a7d0f
27 changed files with 375 additions and 257 deletions
|
@ -717,7 +717,7 @@
|
||||||
<attack type="4" damage="1d6"/>
|
<attack type="4" damage="1d6"/>
|
||||||
<attack type="1" damage="1d5"/>
|
<attack type="1" damage="1d5"/>
|
||||||
</race>
|
</race>
|
||||||
<race name="catdragon" magres="0.900000" maxaura="1.000000" regaura="1.000000" recruitcost="500000" weight="20000" capacity="10000" speed="1.000000" hp="20" damage="2d40" unarmedattack="0" unarmeddefense="0" defensemodifier="50" fly="yes" walk="yes" teach="no" shapeshift="yes" giveperson="yes" getitem="yes">
|
<race name="catdragon" magres="0.900000" maxaura="1.000000" regaura="1.000000" recruitcost="500000" weight="20000" capacity="10000" speed="1.000000" hp="20" damage="2d40" unarmedattack="0" unarmeddefense="0" defensemodifier="50" fly="yes" walk="yes" teach="no" shapeshift="yes" giveperson="yes" getitem="yes" dragon="yes">
|
||||||
<ai splitsize="1"/>
|
<ai splitsize="1"/>
|
||||||
<attack type="4" damage="2d40"/>
|
<attack type="4" damage="2d40"/>
|
||||||
<attack type="4" damage="2d40"/>
|
<attack type="4" damage="2d40"/>
|
||||||
|
@ -742,7 +742,7 @@
|
||||||
<attack type="4" damage="5d30"/>
|
<attack type="4" damage="5d30"/>
|
||||||
<attack type="6" spell="powerful_dragonbreath" level="12" />
|
<attack type="6" spell="powerful_dragonbreath" level="12" />
|
||||||
</race>
|
</race>
|
||||||
<race name="dragon" magres="0.700000" maxaura="1.000000" regaura="2.000000" recruitcost="50000" weight="10000" capacity="1000000" speed="1.500000" hp="900" ac="6" damage="2d30" unarmedattack="0" unarmeddefense="0" attackmodifier="7" defensemodifier="7" scarepeasants="yes" fly="yes" walk="yes" teach="no" getitem="yes" resistbash="yes" unarmedguard="yes">
|
<race name="dragon" magres="0.700000" maxaura="1.000000" regaura="2.000000" recruitcost="50000" weight="10000" capacity="1000000" speed="1.500000" hp="900" ac="6" damage="2d30" unarmedattack="0" unarmeddefense="0" attackmodifier="7" defensemodifier="7" scarepeasants="yes" fly="yes" walk="yes" teach="no" getitem="yes" resistbash="yes" unarmedguard="yes" dragon="yes">
|
||||||
<ai splitsize="2" killpeasants="yes" learn="yes"/>
|
<ai splitsize="2" killpeasants="yes" learn="yes"/>
|
||||||
<function name="name" value="namedragon"/>
|
<function name="name" value="namedragon"/>
|
||||||
<function name="age" value="agedragon"/>
|
<function name="age" value="agedragon"/>
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<race name="dragon" magres="0.700000" maxaura="1.0" regaura="2.000000" weight="10000" capacity="1000000" speed="1.500000" hp="900" ac=
|
<race name="dragon" magres="0.700000" maxaura="1.0" regaura="2.000000" weight="10000" capacity="1000000" speed="1.500000" hp="900" ac=
|
||||||
"6" damage="2d30" unarmedattack="0" unarmeddefense="0" attackmodifier="7" defensemodifier="7" scarepeasants="yes" fly="yes" walk="yes" teach="no" getitem="yes" resistbash="yes">
|
"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">
|
||||||
<ai splitsize="2" killpeasants="yes" learn="yes"/>
|
<ai splitsize="2" killpeasants="yes" learn="yes"/>
|
||||||
<function name="name" value="namedragon"/>
|
<function name="name" value="namedragon"/>
|
||||||
<function name="age" value="agedragon"/>
|
<function name="age" value="agedragon"/>
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
<race name="wyrm" magres="0.900000" maxaura="1.0" regaura="3.000000" weight="18000" capacity="1000000" speed="1.0" hp="2700" ac="8" damage="2d60" unarmedattack="0" unarmeddefense="0" attackmodifier="10" defensemodifier="10" scarepeasants="yes" fly="yes" walk="yes" teach="no" getitem="yes" resistbash="yes">
|
<race name="wyrm" magres="0.900000" maxaura="1.0" regaura="3.000000" weight="18000" capacity="1000000" speed="1.0" hp="2700" ac="8" damage="2d60" unarmedattack="0" unarmeddefense="0" attackmodifier="10" defensemodifier="10" scarepeasants="yes" fly="yes" walk="yes" teach="no" getitem="yes" resistbash="yes" dragon="yes">
|
||||||
<ai splitsize="1" killpeasants="yes" learn="yes"/>
|
<ai splitsize="1" killpeasants="yes" learn="yes"/>
|
||||||
<function name="name" value="namedragon"/>
|
<function name="name" value="namedragon"/>
|
||||||
<function name="move" value="movedragon"/>
|
<function name="move" value="movedragon"/>
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
<race name="youngdragon" magres="0.500000" maxaura="1.0" regaura="1.0" weight="8000" capacity="10000" speed="1.0" hp="300" ac="4" damage="2d15" unarmedattack="0" unarmeddefense="0" attackmodifier="4" defensemodifier="4" scarepeasants="yes" fly="yes" walk="yes" teach="no" getitem="yes" resistbash="yes">
|
<race name="youngdragon" magres="0.500000" maxaura="1.0" regaura="1.0" weight="8000" capacity="10000" speed="1.0" hp="300" ac="4" damage="2d15" unarmedattack="0" unarmeddefense="0" attackmodifier="4" defensemodifier="4" scarepeasants="yes" fly="yes" walk="yes" teach="no" getitem="yes" resistbash="yes" dragon="yes">
|
||||||
<ai splitsize="6" killpeasants="yes" learn="yes"/>
|
<ai splitsize="6" killpeasants="yes" learn="yes"/>
|
||||||
<function name="name" value="namedragon"/>
|
<function name="name" value="namedragon"/>
|
||||||
<function name="age" value="agefiredragon"/>
|
<function name="age" value="agefiredragon"/>
|
||||||
|
|
46
src/battle.c
46
src/battle.c
|
@ -1036,31 +1036,33 @@ static int rc_specialdamage(const unit *au, const unit *du, const struct weapon_
|
||||||
{
|
{
|
||||||
const race *ar = u_race(au);
|
const race *ar = u_race(au);
|
||||||
int m, modifier = 0;
|
int m, modifier = 0;
|
||||||
|
if (wtype != NULL) {
|
||||||
switch (old_race(ar)) {
|
if (fval(u_race(du), RCF_DRAGON)) {
|
||||||
case RC_HALFLING:
|
static int cache;
|
||||||
if (wtype != NULL && dragonrace(u_race(du))) {
|
static race *rc_halfling;
|
||||||
modifier += 5;
|
if (rc_changed(&cache)) {
|
||||||
|
rc_halfling = get_race(RC_HALFLING);
|
||||||
|
}
|
||||||
|
if (ar == rc_halfling) {
|
||||||
|
modifier += 5;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
if (wtype->modifiers != NULL) {
|
||||||
default:
|
for (m = 0; wtype->modifiers[m].value; ++m) {
|
||||||
break;
|
/* weapon damage for this weapon, possibly by race */
|
||||||
}
|
if (wtype->modifiers[m].flags & WMF_DAMAGE) {
|
||||||
if (wtype != NULL && wtype->modifiers != NULL) {
|
race_list *rlist = wtype->modifiers[m].races;
|
||||||
for (m = 0; wtype->modifiers[m].value; ++m) {
|
if (rlist != NULL) {
|
||||||
/* weapon damage for this weapon, possibly by race */
|
while (rlist) {
|
||||||
if (wtype->modifiers[m].flags & WMF_DAMAGE) {
|
if (rlist->data == ar)
|
||||||
race_list *rlist = wtype->modifiers[m].races;
|
break;
|
||||||
if (rlist != NULL) {
|
rlist = rlist->next;
|
||||||
while (rlist) {
|
}
|
||||||
if (rlist->data == ar)
|
if (rlist == NULL)
|
||||||
break;
|
continue;
|
||||||
rlist = rlist->next;
|
|
||||||
}
|
}
|
||||||
if (rlist == NULL)
|
modifier += wtype->modifiers[m].value;
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
modifier += wtype->modifiers[m].value;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
106
src/economy.c
106
src/economy.c
|
@ -114,16 +114,20 @@ static void recruit_init(void)
|
||||||
|
|
||||||
int income(const unit * u)
|
int income(const unit * u)
|
||||||
{
|
{
|
||||||
switch (old_race(u_race(u))) {
|
// TODO: make this a property, like race.income, no hard-coding of values
|
||||||
case RC_FIREDRAGON:
|
if (fval(u_race(u), RCF_DRAGON)) {
|
||||||
return 150 * u->number;
|
switch (old_race(u_race(u))) {
|
||||||
case RC_DRAGON:
|
case RC_FIREDRAGON:
|
||||||
return 1000 * u->number;
|
return 150 * u->number;
|
||||||
case RC_WYRM:
|
case RC_DRAGON:
|
||||||
return 5000 * u->number;
|
return 1000 * u->number;
|
||||||
default:
|
case RC_WYRM:
|
||||||
return 20 * u->number;
|
return 5000 * u->number;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
return 20 * u->number;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void scramble(void *data, unsigned int n, size_t width)
|
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);
|
init_order(ord);
|
||||||
n = getint();
|
n = getint();
|
||||||
if (n<=0) {
|
if (n <= 0) {
|
||||||
syntax_error(u, ord);
|
syntax_error(u, ord);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -796,7 +800,7 @@ static int maintain(building * b)
|
||||||
|
|
||||||
cost -=
|
cost -=
|
||||||
use_pooled(u, m->rtype, GET_SLACK | GET_RESERVE | GET_POOLED_SLACK,
|
use_pooled(u, m->rtype, GET_SLACK | GET_RESERVE | GET_POOLED_SLACK,
|
||||||
cost);
|
cost);
|
||||||
assert(cost == 0);
|
assert(cost == 0);
|
||||||
}
|
}
|
||||||
if (work) {
|
if (work) {
|
||||||
|
@ -815,7 +819,7 @@ void maintain_buildings(region * r)
|
||||||
while (*bp) {
|
while (*bp) {
|
||||||
building *b = *bp;
|
building *b = *bp;
|
||||||
int flags = BLD_MAINTAINED;
|
int flags = BLD_MAINTAINED;
|
||||||
|
|
||||||
if (!curse_active(get_curse(b->attribs, nocost_ct))) {
|
if (!curse_active(get_curse(b->attribs, nocost_ct))) {
|
||||||
flags = maintain(b);
|
flags = maintain(b);
|
||||||
}
|
}
|
||||||
|
@ -929,12 +933,12 @@ static void manufacture(unit * u, const item_type * itype, int want)
|
||||||
case EBUILDINGREQ:
|
case EBUILDINGREQ:
|
||||||
ADDMSG(&u->faction->msgs,
|
ADDMSG(&u->faction->msgs,
|
||||||
msg_feedback(u, u->thisorder, "building_needed", "building",
|
msg_feedback(u, u->thisorder, "building_needed", "building",
|
||||||
itype->construction->btype->_name));
|
itype->construction->btype->_name));
|
||||||
return;
|
return;
|
||||||
case ELOWSKILL:
|
case ELOWSKILL:
|
||||||
ADDMSG(&u->faction->msgs,
|
ADDMSG(&u->faction->msgs,
|
||||||
msg_feedback(u, u->thisorder, "manufacture_skills",
|
msg_feedback(u, u->thisorder, "manufacture_skills",
|
||||||
"skill minskill product", sk, minskill, itype->rtype, 1));
|
"skill minskill product", sk, minskill, itype->rtype, 1));
|
||||||
return;
|
return;
|
||||||
case ENOMATERIALS:
|
case ENOMATERIALS:
|
||||||
ADDMSG(&u->faction->msgs, msg_materials_required(u, u->thisorder,
|
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;
|
skill_t sk = itype->construction->skill;
|
||||||
add_message(&u->faction->msgs,
|
add_message(&u->faction->msgs,
|
||||||
msg_feedback(u, u->thisorder, "manufacture_skills",
|
msg_feedback(u, u->thisorder, "manufacture_skills",
|
||||||
"skill minskill product", sk, itype->construction->minskill,
|
"skill minskill product", sk, itype->construction->minskill,
|
||||||
itype->rtype));
|
itype->rtype));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -1276,7 +1280,7 @@ attrib_allocation(const resource_type * rtype, region * r, allocation * alist)
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef void(*allocate_function) (const resource_type *, struct region *,
|
typedef void(*allocate_function) (const resource_type *, struct region *,
|
||||||
struct allocation *);
|
struct allocation *);
|
||||||
|
|
||||||
static allocate_function get_allocator(const struct resource_type *rtype)
|
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:
|
case EBUILDINGREQ:
|
||||||
ADDMSG(&u->faction->msgs,
|
ADDMSG(&u->faction->msgs,
|
||||||
msg_feedback(u, u->thisorder, "building_needed", "building",
|
msg_feedback(u, u->thisorder, "building_needed", "building",
|
||||||
ptype->itype->construction->btype->_name));
|
ptype->itype->construction->btype->_name));
|
||||||
break;
|
break;
|
||||||
case ECOMPLETE:
|
case ECOMPLETE:
|
||||||
assert(0);
|
assert(0);
|
||||||
|
@ -1687,7 +1691,7 @@ static void buy(unit * u, request ** buyorders, struct order *ord)
|
||||||
kwd = init_order(ord);
|
kwd = init_order(ord);
|
||||||
assert(kwd == K_BUY);
|
assert(kwd == K_BUY);
|
||||||
n = getint();
|
n = getint();
|
||||||
if (n<=0) {
|
if (n <= 0) {
|
||||||
cmistake(u, ord, 26, MSG_COMMERCE);
|
cmistake(u, ord, 26, MSG_COMMERCE);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -1709,7 +1713,11 @@ static void buy(unit * u, request ** buyorders, struct order *ord)
|
||||||
/* ...oder in der Region muß es eine Burg geben. */
|
/* ...oder in der Region muß es eine Burg geben. */
|
||||||
building *b = 0;
|
building *b = 0;
|
||||||
if (r->buildings) {
|
if (r->buildings) {
|
||||||
const struct building_type *bt_castle = bt_find("castle");
|
static int cache;
|
||||||
|
static const struct building_type *bt_castle;
|
||||||
|
if (bt_changed(&cache)) {
|
||||||
|
bt_castle = bt_find("castle");
|
||||||
|
}
|
||||||
|
|
||||||
for (b = r->buildings; b; b = b->next) {
|
for (b = r->buildings; b; b = b->next) {
|
||||||
if (b->type == bt_castle && b->size >= 2) {
|
if (b->type == bt_castle && b->size >= 2) {
|
||||||
|
@ -1795,8 +1803,14 @@ static void expandselling(region * r, request * sellorders, int limit)
|
||||||
unit *hafenowner;
|
unit *hafenowner;
|
||||||
static int counter[MAXLUXURIES];
|
static int counter[MAXLUXURIES];
|
||||||
static int ncounter = 0;
|
static int ncounter = 0;
|
||||||
const struct building_type *castle_bt;
|
static int bt_cache;
|
||||||
|
static const struct building_type *castle_bt, *harbour_bt, *caravan_bt;
|
||||||
|
|
||||||
|
if (bt_changed(&bt_cache)) {
|
||||||
|
castle_bt = bt_find("castle");
|
||||||
|
harbour_bt = bt_find("harbour");
|
||||||
|
caravan_bt = bt_find("caravan");
|
||||||
|
}
|
||||||
if (ncounter == 0) {
|
if (ncounter == 0) {
|
||||||
const luxury_type *ltype;
|
const luxury_type *ltype;
|
||||||
for (ltype = luxurytypes; ltype; ltype = ltype->next) {
|
for (ltype = luxurytypes; ltype; ltype = ltype->next) {
|
||||||
|
@ -1811,7 +1825,6 @@ static void expandselling(region * r, request * sellorders, int limit)
|
||||||
}
|
}
|
||||||
/* Stelle Eigentümer der größten Burg fest. Bekommt Steuern aus jedem
|
/* Stelle Eigentümer der größten Burg fest. Bekommt Steuern aus jedem
|
||||||
* Verkauf. Wenn zwei Burgen gleicher Größe bekommt gar keiner etwas. */
|
* Verkauf. Wenn zwei Burgen gleicher Größe bekommt gar keiner etwas. */
|
||||||
castle_bt = bt_find("castle");
|
|
||||||
for (b = rbuildings(r); b; b = b->next) {
|
for (b = rbuildings(r); b; b = b->next) {
|
||||||
if (b->size > maxsize && building_owner(b) != NULL
|
if (b->size > maxsize && building_owner(b) != NULL
|
||||||
&& b->type == castle_bt) {
|
&& b->type == castle_bt) {
|
||||||
|
@ -1825,7 +1838,7 @@ static void expandselling(region * r, request * sellorders, int limit)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
hafenowner = owner_buildingtyp(r, bt_find("harbour"));
|
hafenowner = owner_buildingtyp(r, harbour_bt);
|
||||||
|
|
||||||
if (maxb != (building *)NULL && maxowner != (unit *)NULL) {
|
if (maxb != (building *)NULL && maxowner != (unit *)NULL) {
|
||||||
maxeffsize = buildingeffsize(maxb, false);
|
maxeffsize = buildingeffsize(maxb, false);
|
||||||
|
@ -1847,7 +1860,7 @@ static void expandselling(region * r, request * sellorders, int limit)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (r->terrain == newterrain(T_DESERT)
|
if (r->terrain == newterrain(T_DESERT)
|
||||||
&& buildingtype_exists(r, bt_find("caravan"), true)) {
|
&& buildingtype_exists(r, caravan_bt, true)) {
|
||||||
max_products = rpeasants(r) * 2 / TRADE_FRACTION;
|
max_products = rpeasants(r) * 2 / TRADE_FRACTION;
|
||||||
}
|
}
|
||||||
/* Verkauf: so programmiert, dass er leicht auf mehrere Gueter pro
|
/* Verkauf: so programmiert, dass er leicht auf mehrere Gueter pro
|
||||||
|
@ -1974,6 +1987,13 @@ static bool sell(unit * u, request ** sellorders, struct order *ord)
|
||||||
region *r = u->region;
|
region *r = u->region;
|
||||||
const char *s;
|
const char *s;
|
||||||
keyword_t kwd;
|
keyword_t kwd;
|
||||||
|
static int bt_cache;
|
||||||
|
static const struct building_type *castle_bt, *caravan_bt;
|
||||||
|
|
||||||
|
if (bt_changed(&bt_cache)) {
|
||||||
|
castle_bt = bt_find("castle");
|
||||||
|
caravan_bt = bt_find("caravan");
|
||||||
|
}
|
||||||
|
|
||||||
if (u->ship && is_guarded(r, u, GUARD_CREWS)) {
|
if (u->ship && is_guarded(r, u, GUARD_CREWS)) {
|
||||||
cmistake(u, ord, 69, MSG_INCOME);
|
cmistake(u, ord, 69, MSG_INCOME);
|
||||||
|
@ -1990,7 +2010,7 @@ static bool sell(unit * u, request ** sellorders, struct order *ord)
|
||||||
unlimited = false;
|
unlimited = false;
|
||||||
n = rpeasants(r) / TRADE_FRACTION;
|
n = rpeasants(r) / TRADE_FRACTION;
|
||||||
if (r->terrain == newterrain(T_DESERT)
|
if (r->terrain == newterrain(T_DESERT)
|
||||||
&& buildingtype_exists(r, bt_find("caravan"), true))
|
&& buildingtype_exists(r, caravan_bt, true))
|
||||||
n *= 2;
|
n *= 2;
|
||||||
if (n == 0) {
|
if (n == 0) {
|
||||||
cmistake(u, ord, 303, MSG_COMMERCE);
|
cmistake(u, ord, 303, MSG_COMMERCE);
|
||||||
|
@ -2023,9 +2043,8 @@ static bool sell(unit * u, request ** sellorders, struct order *ord)
|
||||||
/* ...oder in der Region muß es eine Burg geben. */
|
/* ...oder in der Region muß es eine Burg geben. */
|
||||||
building *b = 0;
|
building *b = 0;
|
||||||
if (r->buildings) {
|
if (r->buildings) {
|
||||||
const struct building_type *bt_castle = bt_find("castle");
|
|
||||||
for (b = r->buildings; b; b = b->next) {
|
for (b = r->buildings; b; b = b->next) {
|
||||||
if (b->type == bt_castle && b->size >= 2) break;
|
if (b->type == castle_bt && b->size >= 2) break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!b) {
|
if (!b) {
|
||||||
|
@ -2082,7 +2101,7 @@ static bool sell(unit * u, request ** sellorders, struct order *ord)
|
||||||
* produktion, wo für jedes produkt einzeln eine obere limite
|
* produktion, wo für jedes produkt einzeln eine obere limite
|
||||||
* existiert, so dass man arrays von orders machen kann. */
|
* 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);
|
k = u->number * 10 * effskill(u, SK_TRADE, 0);
|
||||||
|
|
||||||
/* hat der Händler bereits gehandelt, muss die Menge der bereits
|
/* hat der Händler bereits gehandelt, muss die Menge der bereits
|
||||||
|
@ -2188,7 +2207,7 @@ static void plant(unit * u, int raw)
|
||||||
if (skill < 6) {
|
if (skill < 6) {
|
||||||
ADDMSG(&u->faction->msgs,
|
ADDMSG(&u->faction->msgs,
|
||||||
msg_feedback(u, u->thisorder, "plant_skills",
|
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;
|
return;
|
||||||
}
|
}
|
||||||
/* Wasser des Lebens prüfen */
|
/* Wasser des Lebens prüfen */
|
||||||
|
@ -2202,7 +2221,7 @@ static void plant(unit * u, int raw)
|
||||||
if (n == 0) {
|
if (n == 0) {
|
||||||
ADDMSG(&u->faction->msgs,
|
ADDMSG(&u->faction->msgs,
|
||||||
msg_feedback(u, u->thisorder, "resource_missing", "missing",
|
msg_feedback(u, u->thisorder, "resource_missing", "missing",
|
||||||
itype->rtype));
|
itype->rtype));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2218,7 +2237,7 @@ static void plant(unit * u, int raw)
|
||||||
/* Alles ok. Abziehen. */
|
/* Alles ok. Abziehen. */
|
||||||
use_pooled(u, rt_water, GET_DEFAULT, 1);
|
use_pooled(u, rt_water, GET_DEFAULT, 1);
|
||||||
use_pooled(u, itype->rtype, GET_DEFAULT, n);
|
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",
|
ADDMSG(&u->faction->msgs, msg_message("plant", "unit region amount herb",
|
||||||
u, r, planted, itype->rtype));
|
u, r, planted, itype->rtype));
|
||||||
}
|
}
|
||||||
|
@ -2241,13 +2260,13 @@ static void planttrees(unit * u, int raw)
|
||||||
if (skill < 6) {
|
if (skill < 6) {
|
||||||
ADDMSG(&u->faction->msgs,
|
ADDMSG(&u->faction->msgs,
|
||||||
msg_feedback(u, u->thisorder, "plant_skills",
|
msg_feedback(u, u->thisorder, "plant_skills",
|
||||||
"skill minskill product", SK_HERBALISM, 6, rtype, 1));
|
"skill minskill product", SK_HERBALISM, 6, rtype, 1));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (fval(r, RF_MALLORN) && skill < 7) {
|
if (fval(r, RF_MALLORN) && skill < 7) {
|
||||||
ADDMSG(&u->faction->msgs,
|
ADDMSG(&u->faction->msgs,
|
||||||
msg_feedback(u, u->thisorder, "plant_skills",
|
msg_feedback(u, u->thisorder, "plant_skills",
|
||||||
"skill minskill product", SK_HERBALISM, 7, rtype, 1));
|
"skill minskill product", SK_HERBALISM, 7, rtype, 1));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2284,7 +2303,7 @@ static void breedtrees(unit * u, int raw)
|
||||||
int current_season;
|
int current_season;
|
||||||
region *r = u->region;
|
region *r = u->region;
|
||||||
gamedate date;
|
gamedate date;
|
||||||
|
|
||||||
get_gamedate(turn, &date);
|
get_gamedate(turn, &date);
|
||||||
current_season = date.season;
|
current_season = date.season;
|
||||||
|
|
||||||
|
@ -2340,9 +2359,15 @@ static void breedhorses(unit * u)
|
||||||
int n, c, breed = 0;
|
int n, c, breed = 0;
|
||||||
const struct resource_type *rhorse = get_resourcetype(R_HORSE);
|
const struct resource_type *rhorse = get_resourcetype(R_HORSE);
|
||||||
int horses, effsk;
|
int horses, effsk;
|
||||||
|
static int bt_cache;
|
||||||
|
static const struct building_type *stables_bt;
|
||||||
|
|
||||||
|
if (bt_changed(&bt_cache)) {
|
||||||
|
stables_bt = bt_find("stables");
|
||||||
|
}
|
||||||
|
|
||||||
assert(rhorse && rhorse->itype);
|
assert(rhorse && rhorse->itype);
|
||||||
if (!active_building(u, bt_find("stables"))) {
|
if (!active_building(u, stables_bt)) {
|
||||||
cmistake(u, u->thisorder, 122, MSG_PRODUCE);
|
cmistake(u, u->thisorder, 122, MSG_PRODUCE);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -2536,7 +2561,7 @@ static void steal_cmd(unit * u, struct order *ord, request ** stealorders)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
id = read_unitid(u->faction, r);
|
id = read_unitid(u->faction, r);
|
||||||
if (id>0) {
|
if (id > 0) {
|
||||||
u2 = findunitr(r, id);
|
u2 = findunitr(r, id);
|
||||||
}
|
}
|
||||||
if (u2 && u2->region == u->region) {
|
if (u2 && u2->region == u->region) {
|
||||||
|
@ -3079,6 +3104,13 @@ void produce(struct region *r)
|
||||||
unit *u;
|
unit *u;
|
||||||
bool limited = true;
|
bool limited = true;
|
||||||
request *nextworker = workers;
|
request *nextworker = workers;
|
||||||
|
static int bt_cache;
|
||||||
|
static const struct building_type *caravan_bt;
|
||||||
|
|
||||||
|
if (bt_changed(&bt_cache)) {
|
||||||
|
caravan_bt = bt_find("caravan");
|
||||||
|
}
|
||||||
|
|
||||||
assert(r);
|
assert(r);
|
||||||
|
|
||||||
/* das sind alles befehle, die 30 tage brauchen, und die in thisorder
|
/* das sind alles befehle, die 30 tage brauchen, und die in thisorder
|
||||||
|
@ -3228,7 +3260,7 @@ void produce(struct region *r)
|
||||||
if (sellorders) {
|
if (sellorders) {
|
||||||
int limit = rpeasants(r) / TRADE_FRACTION;
|
int limit = rpeasants(r) / TRADE_FRACTION;
|
||||||
if (r->terrain == newterrain(T_DESERT)
|
if (r->terrain == newterrain(T_DESERT)
|
||||||
&& buildingtype_exists(r, bt_find("caravan"), true))
|
&& buildingtype_exists(r, caravan_bt, true))
|
||||||
limit *= 2;
|
limit *= 2;
|
||||||
expandselling(r, sellorders, limited ? limit : INT_MAX);
|
expandselling(r, sellorders, limited ? limit : INT_MAX);
|
||||||
}
|
}
|
||||||
|
|
30
src/guard.c
30
src/guard.c
|
@ -67,28 +67,34 @@ void update_guards(void)
|
||||||
|
|
||||||
unsigned int guard_flags(const unit * u)
|
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 =
|
unsigned int flags =
|
||||||
GUARD_CREWS | GUARD_LANDING | GUARD_TRAVELTHRU | GUARD_TAX;
|
GUARD_CREWS | GUARD_LANDING | GUARD_TRAVELTHRU | GUARD_TAX;
|
||||||
|
// TODO: configuration, not define
|
||||||
#if GUARD_DISABLES_PRODUCTION == 1
|
#if GUARD_DISABLES_PRODUCTION == 1
|
||||||
flags |= GUARD_PRODUCE;
|
flags |= GUARD_PRODUCE;
|
||||||
#endif
|
#endif
|
||||||
#if GUARD_DISABLES_RECRUIT == 1
|
#if GUARD_DISABLES_RECRUIT == 1
|
||||||
flags |= GUARD_RECRUIT;
|
flags |= GUARD_RECRUIT;
|
||||||
#endif
|
#endif
|
||||||
switch (old_race(u_race(u))) {
|
if (rc_changed(&rc_cache)) {
|
||||||
case RC_ELF:
|
rc_elf = get_race(RC_ELF);
|
||||||
if (u->faction->race != u_race(u))
|
rc_ent = get_race(RC_TREEMAN);
|
||||||
break;
|
rc_ironkeeper = get_race(RC_IRONKEEPER);
|
||||||
/* else fallthrough */
|
}
|
||||||
case RC_TREEMAN:
|
if (rc == rc_elf) {
|
||||||
|
if (u->faction->race == u_race(u)) {
|
||||||
|
flags |= GUARD_TREES;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (rc == rc_ent) {
|
||||||
flags |= GUARD_TREES;
|
flags |= GUARD_TREES;
|
||||||
break;
|
}
|
||||||
case RC_IRONKEEPER:
|
else if (rc == rc_ironkeeper) {
|
||||||
flags = GUARD_MINING;
|
flags = GUARD_MINING;
|
||||||
break;
|
|
||||||
default:
|
|
||||||
/* TODO: This should be configuration variables, all of it */
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
return flags;
|
return flags;
|
||||||
}
|
}
|
||||||
|
|
|
@ -83,15 +83,28 @@ const building_type *bt_find(const char *name)
|
||||||
return bt_find_i(name);
|
return bt_find_i(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int bt_changes = 1;
|
||||||
|
|
||||||
|
bool bt_changed(int *cache)
|
||||||
|
{
|
||||||
|
assert(cache);
|
||||||
|
if (*cache != bt_changes) {
|
||||||
|
*cache = bt_changes;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
void bt_register(building_type * type)
|
void bt_register(building_type * type)
|
||||||
{
|
{
|
||||||
if (type->init) {
|
if (type->init) {
|
||||||
type->init(type);
|
type->init(type);
|
||||||
}
|
}
|
||||||
ql_push(&buildingtypes, (void *)type);
|
ql_push(&buildingtypes, (void *)type);
|
||||||
|
++bt_changes;
|
||||||
}
|
}
|
||||||
|
|
||||||
void free_buildingtype(void *ptr) {
|
static void free_buildingtype(void *ptr) {
|
||||||
building_type *btype = (building_type *)ptr;
|
building_type *btype = (building_type *)ptr;
|
||||||
free_construction(btype->construction);
|
free_construction(btype->construction);
|
||||||
free(btype->maintenance);
|
free(btype->maintenance);
|
||||||
|
@ -103,6 +116,7 @@ void free_buildingtypes(void) {
|
||||||
ql_foreach(buildingtypes, free_buildingtype);
|
ql_foreach(buildingtypes, free_buildingtype);
|
||||||
ql_free(buildingtypes);
|
ql_free(buildingtypes);
|
||||||
buildingtypes = 0;
|
buildingtypes = 0;
|
||||||
|
++bt_changes;
|
||||||
}
|
}
|
||||||
|
|
||||||
building_type *bt_get_or_create(const char *name)
|
building_type *bt_get_or_create(const char *name)
|
||||||
|
|
|
@ -84,6 +84,7 @@ extern "C" {
|
||||||
extern struct attrib_type at_building_action;
|
extern struct attrib_type at_building_action;
|
||||||
|
|
||||||
building_type *bt_get_or_create(const char *name);
|
building_type *bt_get_or_create(const char *name);
|
||||||
|
bool bt_changed(int *cache);
|
||||||
const building_type *bt_find(const char *name);
|
const building_type *bt_find(const char *name);
|
||||||
void free_buildingtypes(void);
|
void free_buildingtypes(void);
|
||||||
void register_buildings(void);
|
void register_buildings(void);
|
||||||
|
|
|
@ -17,16 +17,20 @@
|
||||||
static void test_register_building(CuTest * tc)
|
static void test_register_building(CuTest * tc)
|
||||||
{
|
{
|
||||||
building_type *btype;
|
building_type *btype;
|
||||||
|
int cache = 0;
|
||||||
|
|
||||||
test_cleanup();
|
test_cleanup();
|
||||||
|
|
||||||
btype = (building_type *)calloc(sizeof(building_type), 1);
|
btype = (building_type *)calloc(sizeof(building_type), 1);
|
||||||
btype->_name = _strdup("herp");
|
btype->_name = _strdup("herp");
|
||||||
|
CuAssertIntEquals(tc, true, bt_changed(&cache));
|
||||||
|
CuAssertIntEquals(tc, false, bt_changed(&cache));
|
||||||
bt_register(btype);
|
bt_register(btype);
|
||||||
|
CuAssertIntEquals(tc, true, bt_changed(&cache));
|
||||||
|
|
||||||
CuAssertPtrNotNull(tc, bt_find("herp"));
|
CuAssertPtrNotNull(tc, bt_find("herp"));
|
||||||
// free(btype->_name);
|
free_buildingtypes();
|
||||||
// free(btype);
|
CuAssertIntEquals(tc, true, bt_changed(&cache));
|
||||||
test_cleanup();
|
test_cleanup();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -140,6 +140,7 @@ int NMRTimeout(void)
|
||||||
race_t old_race(const struct race * rc)
|
race_t old_race(const struct race * rc)
|
||||||
{
|
{
|
||||||
race_t i;
|
race_t i;
|
||||||
|
// TODO: this sucks so bad!
|
||||||
for (i = 0; i != MAXRACES; ++i) {
|
for (i = 0; i != MAXRACES; ++i) {
|
||||||
if (get_race(i) == rc) return i;
|
if (get_race(i) == rc) return i;
|
||||||
}
|
}
|
||||||
|
@ -922,7 +923,12 @@ default_wage(const region * r, const faction * f, const race * rc, int in_turn)
|
||||||
building *b = largestbuilding(r, &cmp_wage, false);
|
building *b = largestbuilding(r, &cmp_wage, false);
|
||||||
int esize = 0;
|
int esize = 0;
|
||||||
double wage;
|
double wage;
|
||||||
|
static int ct_cache;
|
||||||
|
static const struct curse_type *drought_ct;
|
||||||
|
|
||||||
|
if (ct_changed(&ct_cache)) {
|
||||||
|
drought_ct = ct_find("drought");
|
||||||
|
}
|
||||||
if (b != NULL) {
|
if (b != NULL) {
|
||||||
/* TODO: this reveals imaginary castles */
|
/* TODO: this reveals imaginary castles */
|
||||||
esize = buildingeffsize(b, false);
|
esize = buildingeffsize(b, false);
|
||||||
|
@ -971,9 +977,8 @@ default_wage(const region * r, const faction * f, const race * rc, int in_turn)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Bei einer Dürre verdient man nur noch ein Viertel */
|
/* Bei einer Dürre verdient man nur noch ein Viertel */
|
||||||
ctype = ct_find("drought");
|
if (drought_ct) {
|
||||||
if (ctype) {
|
curse *c = get_curse(r->attribs, drought_ct);
|
||||||
curse *c = get_curse(r->attribs, ctype);
|
|
||||||
if (curse_active(c))
|
if (curse_active(c))
|
||||||
wage /= curse_geteffect(c);
|
wage /= curse_geteffect(c);
|
||||||
}
|
}
|
||||||
|
|
|
@ -291,6 +291,17 @@ attrib_type at_curse = {
|
||||||
|
|
||||||
#define MAXCTHASH 128
|
#define MAXCTHASH 128
|
||||||
static quicklist *cursetypes[MAXCTHASH];
|
static quicklist *cursetypes[MAXCTHASH];
|
||||||
|
static int ct_changes = 1;
|
||||||
|
|
||||||
|
bool ct_changed(int *cache)
|
||||||
|
{
|
||||||
|
assert(cache);
|
||||||
|
if (*cache != ct_changes) {
|
||||||
|
*cache = ct_changes;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
void ct_register(const curse_type * ct)
|
void ct_register(const curse_type * ct)
|
||||||
{
|
{
|
||||||
|
@ -298,6 +309,27 @@ void ct_register(const curse_type * ct)
|
||||||
quicklist **ctlp = cursetypes + hash;
|
quicklist **ctlp = cursetypes + hash;
|
||||||
|
|
||||||
ql_set_insert(ctlp, (void *)ct);
|
ql_set_insert(ctlp, (void *)ct);
|
||||||
|
++ct_changes;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ct_remove(const char *c)
|
||||||
|
{
|
||||||
|
unsigned int hash = tolower(c[0]);
|
||||||
|
quicklist *ctl = cursetypes[hash];
|
||||||
|
|
||||||
|
if (ctl) {
|
||||||
|
int qi;
|
||||||
|
|
||||||
|
for (qi = 0; ctl; ql_advance(&ctl, &qi, 1)) {
|
||||||
|
curse_type *type = (curse_type *)ql_get(ctl, qi);
|
||||||
|
|
||||||
|
if (strcmp(c, type->cname) == 0) {
|
||||||
|
ql_delete(&ctl, qi);
|
||||||
|
++ct_changes;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const curse_type *ct_find(const char *c)
|
const curse_type *ct_find(const char *c)
|
||||||
|
@ -798,5 +830,7 @@ void curses_done(void) {
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; i != MAXCTHASH; ++i) {
|
for (i = 0; i != MAXCTHASH; ++i) {
|
||||||
ql_free(cursetypes[i]);
|
ql_free(cursetypes[i]);
|
||||||
|
cursetypes[i] = 0;
|
||||||
}
|
}
|
||||||
|
++ct_changes;
|
||||||
}
|
}
|
||||||
|
|
|
@ -282,7 +282,9 @@ extern "C" {
|
||||||
|
|
||||||
int find_cursebyname(const char *c);
|
int find_cursebyname(const char *c);
|
||||||
const curse_type *ct_find(const char *c);
|
const curse_type *ct_find(const char *c);
|
||||||
|
bool ct_changed(int *cache);
|
||||||
void ct_register(const curse_type *);
|
void ct_register(const curse_type *);
|
||||||
|
void ct_remove(const char *c);
|
||||||
void ct_checknames(void);
|
void ct_checknames(void);
|
||||||
|
|
||||||
curse *findcurse(int curseid);
|
curse *findcurse(int curseid);
|
||||||
|
|
|
@ -157,10 +157,29 @@ static void test_write_flag(CuTest *tc) {
|
||||||
cleanup_curse(&fix);
|
cleanup_curse(&fix);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void test_curse_cache(CuTest *tc)
|
||||||
|
{
|
||||||
|
int cache = 0;
|
||||||
|
const curse_type ct_dummy = { "dummy", CURSETYP_NORM, 0, M_SUMEFFECT, NULL };
|
||||||
|
test_setup();
|
||||||
|
CuAssertIntEquals(tc, true, ct_changed(&cache));
|
||||||
|
CuAssertIntEquals(tc, false, ct_changed(&cache));
|
||||||
|
CuAssertPtrEquals(tc, NULL, (void *)ct_find(ct_dummy.cname));
|
||||||
|
ct_register(&ct_dummy);
|
||||||
|
CuAssertIntEquals(tc, true, ct_changed(&cache));
|
||||||
|
CuAssertPtrEquals(tc, (void *)&ct_dummy, (void *)ct_find(ct_dummy.cname));
|
||||||
|
ct_remove(ct_dummy.cname);
|
||||||
|
CuAssertIntEquals(tc, true, ct_changed(&cache));
|
||||||
|
CuAssertIntEquals(tc, false, ct_changed(&cache));
|
||||||
|
CuAssertPtrEquals(tc, NULL, (void *)ct_find(ct_dummy.cname));
|
||||||
|
test_cleanup();
|
||||||
|
}
|
||||||
|
|
||||||
CuSuite *get_curse_suite(void)
|
CuSuite *get_curse_suite(void)
|
||||||
{
|
{
|
||||||
CuSuite *suite = CuSuiteNew();
|
CuSuite *suite = CuSuiteNew();
|
||||||
SUITE_ADD_TEST(suite, test_curse);
|
SUITE_ADD_TEST(suite, test_curse);
|
||||||
|
SUITE_ADD_TEST(suite, test_curse_cache);
|
||||||
SUITE_ADD_TEST(suite, test_magicstreet);
|
SUITE_ADD_TEST(suite, test_magicstreet);
|
||||||
SUITE_ADD_TEST(suite, test_magicstreet_warning);
|
SUITE_ADD_TEST(suite, test_magicstreet_warning);
|
||||||
SUITE_ADD_TEST(suite, test_good_dreams);
|
SUITE_ADD_TEST(suite, test_good_dreams);
|
||||||
|
|
|
@ -59,7 +59,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
/** external variables **/
|
/** external variables **/
|
||||||
race *races;
|
race *races;
|
||||||
int num_races = 0;
|
int num_races = 0;
|
||||||
static int cache_breaker;
|
static int rc_changes = 1;
|
||||||
|
|
||||||
static const char *racenames[MAXRACES] = {
|
static const char *racenames[MAXRACES] = {
|
||||||
"dwarf", "elf", NULL, "goblin", "human", "troll", "demon", "insect",
|
"dwarf", "elf", NULL, "goblin", "human", "troll", "demon", "insect",
|
||||||
|
@ -75,30 +75,15 @@ static const char *racenames[MAXRACES] = {
|
||||||
"clone"
|
"clone"
|
||||||
};
|
};
|
||||||
|
|
||||||
static race * race_cache[MAXRACES];
|
|
||||||
|
|
||||||
struct race *get_race(race_t rt) {
|
struct race *get_race(race_t rt) {
|
||||||
static int cache = -1;
|
|
||||||
const char * name;
|
const char * name;
|
||||||
race * result = 0;
|
|
||||||
|
|
||||||
assert(rt < MAXRACES);
|
assert(rt < MAXRACES);
|
||||||
name = racenames[rt];
|
name = racenames[rt];
|
||||||
if (!name) {
|
if (!name) {
|
||||||
return 0;
|
return NULL;
|
||||||
}
|
}
|
||||||
if (cache_breaker != cache) {
|
return rc_get_or_create(name);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
race_list *get_familiarraces(void)
|
race_list *get_familiarraces(void)
|
||||||
|
@ -147,6 +132,7 @@ void free_races(void) {
|
||||||
races = rc;
|
races = rc;
|
||||||
}
|
}
|
||||||
num_races = 0;
|
num_races = 0;
|
||||||
|
++rc_changes;
|
||||||
}
|
}
|
||||||
|
|
||||||
static race *rc_find_i(const char *name)
|
static race *rc_find_i(const char *name)
|
||||||
|
@ -168,6 +154,15 @@ const race * rc_find(const char *name) {
|
||||||
return rc_find_i(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_get_or_create(const char *zName)
|
||||||
{
|
{
|
||||||
race *rc;
|
race *rc;
|
||||||
|
@ -195,7 +190,7 @@ race *rc_get_or_create(const char *zName)
|
||||||
for (i = 1; i < RACE_ATTACKS; ++i)
|
for (i = 1; i < RACE_ATTACKS; ++i)
|
||||||
rc->attack[i].type = AT_NONE;
|
rc->attack[i].type = AT_NONE;
|
||||||
rc->index = num_races++;
|
rc->index = num_races++;
|
||||||
++cache_breaker;
|
++rc_changes;
|
||||||
rc->next = races;
|
rc->next = races;
|
||||||
return races = rc;
|
return races = rc;
|
||||||
}
|
}
|
||||||
|
|
|
@ -180,6 +180,7 @@ extern "C" {
|
||||||
race_t old_race(const struct race *);
|
race_t old_race(const struct race *);
|
||||||
|
|
||||||
race *rc_get_or_create(const char *name);
|
race *rc_get_or_create(const char *name);
|
||||||
|
bool rc_changed(int *cache);
|
||||||
const race *rc_find(const char *);
|
const race *rc_find(const char *);
|
||||||
void free_races(void);
|
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 omniscient(f) ((f)->race==get_race(RC_ILLUSION) || (f)->race==get_race(RC_TEMPLATE))
|
||||||
|
|
||||||
#define playerrace(rc) (!fval((rc), RCF_NPC))
|
#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 humanoidrace(rc) (fval((rc), RCF_UNDEAD) || (rc)==get_race(RC_DRACOID) || playerrace(rc))
|
||||||
#define illusionaryrace(rc) (fval(rc, RCF_ILLUSIONARY))
|
#define illusionaryrace(rc) (fval(rc, RCF_ILLUSIONARY))
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
|
|
||||||
static void test_rc_name(CuTest *tc) {
|
static void test_rc_name(CuTest *tc) {
|
||||||
struct race *rc;
|
struct race *rc;
|
||||||
test_cleanup();
|
test_setup();
|
||||||
rc = test_create_race("human");
|
rc = test_create_race("human");
|
||||||
CuAssertStrEquals(tc, "race::human", rc_name_s(rc, NAME_SINGULAR));
|
CuAssertStrEquals(tc, "race::human", rc_name_s(rc, NAME_SINGULAR));
|
||||||
CuAssertStrEquals(tc, "race::human_p", rc_name_s(rc, NAME_PLURAL));
|
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) {
|
static void test_rc_defaults(CuTest *tc) {
|
||||||
struct race *rc;
|
struct race *rc;
|
||||||
test_cleanup();
|
test_setup();
|
||||||
rc = rc_get_or_create("human");
|
rc = rc_get_or_create("human");
|
||||||
CuAssertStrEquals(tc, "human", rc->_name);
|
CuAssertStrEquals(tc, "human", rc->_name);
|
||||||
CuAssertDblEquals(tc, 0.0, rc->magres, 0.0);
|
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) {
|
static void test_rc_find(CuTest *tc) {
|
||||||
race *rc;
|
race *rc;
|
||||||
test_cleanup();
|
test_setup();
|
||||||
rc = test_create_race("hungryhippos");
|
rc = test_create_race("hungryhippos");
|
||||||
CuAssertPtrEquals(tc, rc, (void *)rc_find("hungryhippos"));
|
CuAssertPtrEquals(tc, rc, (void *)rc_find("hungryhippos"));
|
||||||
test_cleanup();
|
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 *get_race_suite(void)
|
||||||
{
|
{
|
||||||
CuSuite *suite = CuSuiteNew();
|
CuSuite *suite = CuSuiteNew();
|
||||||
|
SUITE_ADD_TEST(suite, test_race_get);
|
||||||
SUITE_ADD_TEST(suite, test_rc_name);
|
SUITE_ADD_TEST(suite, test_rc_name);
|
||||||
SUITE_ADD_TEST(suite, test_rc_defaults);
|
SUITE_ADD_TEST(suite, test_rc_defaults);
|
||||||
SUITE_ADD_TEST(suite, test_rc_find);
|
SUITE_ADD_TEST(suite, test_rc_find);
|
||||||
|
|
|
@ -104,16 +104,22 @@ int value, int flags)
|
||||||
int skill_mod(const race * rc, skill_t sk, const struct terrain_type *terrain)
|
int skill_mod(const race * rc, skill_t sk, const struct terrain_type *terrain)
|
||||||
{
|
{
|
||||||
int result = 0;
|
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];
|
result = rc->bonus[sk];
|
||||||
|
|
||||||
if (rc == get_race(RC_DWARF)) {
|
if (rc == rc_dwarf) {
|
||||||
if (sk == SK_TACTICS) {
|
if (sk == SK_TACTICS) {
|
||||||
if (terrain == newterrain(T_MOUNTAIN) || fval(terrain, ARCTIC_REGION))
|
if (terrain == newterrain(T_MOUNTAIN) || fval(terrain, ARCTIC_REGION))
|
||||||
++result;
|
++result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (rc == get_race(RC_INSECT)) {
|
else if (rc == rc_insect) {
|
||||||
if (terrain == newterrain(T_MOUNTAIN) || fval(terrain, ARCTIC_REGION))
|
if (terrain == newterrain(T_MOUNTAIN) || fval(terrain, ARCTIC_REGION))
|
||||||
--result;
|
--result;
|
||||||
else if (terrain == newterrain(T_DESERT) || terrain == newterrain(T_SWAMP))
|
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 rc_skillmod(const struct race *rc, const region * r, skill_t sk)
|
||||||
{
|
{
|
||||||
int mods = 0;
|
int mods = 0;
|
||||||
|
|
||||||
if (!skill_enabled(sk)) {
|
if (!skill_enabled(sk)) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if (r) {
|
if (r) {
|
||||||
mods = skill_mod(rc, sk, r->terrain);
|
mods = skill_mod(rc, sk, r->terrain);
|
||||||
}
|
}
|
||||||
if (rc == get_race(RC_ELF) && r && r_isforest(r)) {
|
if (r && r_isforest(r)) {
|
||||||
if (sk == SK_PERCEPTION || sk == SK_STEALTH) {
|
static int rc_cache;
|
||||||
++mods;
|
static race * rc_elf;
|
||||||
|
if (rc_changed(&rc_cache)) {
|
||||||
|
rc_elf = get_race(RC_ELF);
|
||||||
}
|
}
|
||||||
else if (sk == SK_TACTICS) {
|
if (rc == rc_elf) {
|
||||||
mods += 2;
|
if (sk == SK_PERCEPTION || sk == SK_STEALTH) {
|
||||||
|
++mods;
|
||||||
|
}
|
||||||
|
else if (sk == SK_TACTICS) {
|
||||||
|
mods += 2;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return mods;
|
return mods;
|
||||||
|
|
|
@ -1279,8 +1279,12 @@ static int att_modification(const unit * u, skill_t sk)
|
||||||
|
|
||||||
if (u->attribs) {
|
if (u->attribs) {
|
||||||
curse *c;
|
curse *c;
|
||||||
const curse_type *skillmod_ct = ct_find("skillmod");
|
static int cache;
|
||||||
const curse_type *worse_ct = ct_find("worse");
|
static const curse_type *skillmod_ct, *worse_ct;
|
||||||
|
if (ct_changed(&cache)) {
|
||||||
|
skillmod_ct = ct_find("skillmod");
|
||||||
|
worse_ct = ct_find("worse");
|
||||||
|
}
|
||||||
c = get_curse(u->attribs, worse_ct);
|
c = get_curse(u->attribs, worse_ct);
|
||||||
if (c != NULL)
|
if (c != NULL)
|
||||||
result += curse_geteffect(c);
|
result += curse_geteffect(c);
|
||||||
|
@ -1729,7 +1733,11 @@ int unit_max_hp(const unit * u)
|
||||||
|
|
||||||
/* der healing curse veraendert die maximalen hp */
|
/* der healing curse veraendert die maximalen hp */
|
||||||
if (u->region && u->region->attribs) {
|
if (u->region && u->region->attribs) {
|
||||||
const curse_type *heal_ct = ct_find("healingzone");
|
static int cache;
|
||||||
|
static const curse_type *heal_ct;
|
||||||
|
if (ct_changed(&cache)) {
|
||||||
|
heal_ct = ct_find("healingzone");
|
||||||
|
}
|
||||||
if (heal_ct) {
|
if (heal_ct) {
|
||||||
curse *c = get_curse(u->region->attribs, heal_ct);
|
curse *c = get_curse(u->region->attribs, heal_ct);
|
||||||
if (c) {
|
if (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)
|
static double heal_factor(const unit * u)
|
||||||
{
|
{
|
||||||
double elf_regen;
|
double elf_regen;
|
||||||
|
// TODO: do not hard-code, make this a property, race.healing
|
||||||
switch (old_race(u_race(u))) {
|
switch (old_race(u_race(u))) {
|
||||||
case RC_TROLL:
|
case RC_TROLL:
|
||||||
case RC_DAEMON:
|
case RC_DAEMON:
|
||||||
|
|
|
@ -83,6 +83,7 @@ static void eaten_by_monster(unit * u)
|
||||||
multi = RESOURCE_QUANTITY * newterrain(T_PLAIN)->size / 10000.0;
|
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))) {
|
switch (old_race(u_race(u))) {
|
||||||
case RC_FIREDRAGON:
|
case RC_FIREDRAGON:
|
||||||
n = rng_int() % 80 * u->number;
|
n = rng_int() % 80 * u->number;
|
||||||
|
@ -118,12 +119,7 @@ static void eaten_by_monster(unit * u)
|
||||||
|
|
||||||
static void absorbed_by_monster(unit * u)
|
static void absorbed_by_monster(unit * u)
|
||||||
{
|
{
|
||||||
int n;
|
int n = rng_int() % (u->number / 20 + 1);
|
||||||
|
|
||||||
switch (old_race(u_race(u))) {
|
|
||||||
default:
|
|
||||||
n = rng_int() % (u->number / 20 + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (n > 0) {
|
if (n > 0) {
|
||||||
n = lovar(n);
|
n = lovar(n);
|
||||||
|
|
144
src/monsters.c
144
src/monsters.c
|
@ -380,20 +380,15 @@ static order *monster_move(region * r, unit * u)
|
||||||
if (monster_is_waiting(u)) {
|
if (monster_is_waiting(u)) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
switch (old_race(u_race(u))) {
|
if (fval(u_race(u), RCF_DRAGON)) {
|
||||||
case RC_FIREDRAGON:
|
|
||||||
case RC_DRAGON:
|
|
||||||
case RC_WYRM:
|
|
||||||
d = richest_neighbour(r, u->faction, 1);
|
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
|
/* falls kein geld gefunden wird, zufaellig verreisen, aber nicht in
|
||||||
* den ozean */
|
* 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);
|
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)
|
void random_growl(const unit *u, region *target, int rand)
|
||||||
{
|
{
|
||||||
const struct locale *lang = u->faction->locale;
|
const struct locale *lang = u->faction->locale;
|
||||||
|
@ -657,6 +593,13 @@ static order *plan_dragon(unit * u)
|
||||||
region *tr = NULL;
|
region *tr = NULL;
|
||||||
bool move = false;
|
bool move = false;
|
||||||
order *long_order = NULL;
|
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) {
|
if (ta == NULL) {
|
||||||
move |= (rpeasants(r) == 0); /* when no peasants, move */
|
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 */
|
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;
|
unit *u2;
|
||||||
for (u2 = r->units; u2; u2 = u2->next) {
|
for (u2 = r->units; u2; u2 = u2->next) {
|
||||||
/* wyrme sind einzelgänger */
|
/* wyrme sind einzelgänger */
|
||||||
|
@ -694,18 +637,21 @@ static order *plan_dragon(unit * u)
|
||||||
}
|
}
|
||||||
if (tr != NULL) {
|
if (tr != NULL) {
|
||||||
assert(long_order == NULL);
|
assert(long_order == NULL);
|
||||||
switch (old_race(u_race(u))) {
|
// TODO: per-race planning functions?
|
||||||
case RC_FIREDRAGON:
|
if (rc == rc_wyrm) {
|
||||||
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:
|
|
||||||
long_order = make_movement_order(u, tr, 1, allowed_dragon);
|
long_order = make_movement_order(u, tr, 1, allowed_dragon);
|
||||||
break;
|
}
|
||||||
default:
|
else {
|
||||||
break;
|
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) {
|
if (long_order) {
|
||||||
reduce_weight(u);
|
reduce_weight(u);
|
||||||
|
@ -757,6 +703,7 @@ void plan_monsters(faction * f)
|
||||||
bool attacking = chance(attack_chance);
|
bool attacking = chance(attack_chance);
|
||||||
|
|
||||||
for (u = r->units; u; u = u->next) {
|
for (u = r->units; u; u = u->next) {
|
||||||
|
const race *rc = u_race(u);
|
||||||
attrib *ta;
|
attrib *ta;
|
||||||
order *long_order = NULL;
|
order *long_order = NULL;
|
||||||
|
|
||||||
|
@ -812,7 +759,7 @@ void plan_monsters(faction * f)
|
||||||
a_remove(&u->attribs, ta);
|
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)) {
|
if (chance(random_move_chance()) || check_overpopulated(u)) {
|
||||||
long_order = monster_move(r, u);
|
long_order = monster_move(r, u);
|
||||||
}
|
}
|
||||||
|
@ -826,31 +773,24 @@ void plan_monsters(faction * f)
|
||||||
handle_event(u->attribs, "ai_move", u);
|
handle_event(u->attribs, "ai_move", u);
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (old_race(u_race(u))) {
|
if (fval(rc, RCF_DRAGON)) {
|
||||||
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:
|
|
||||||
long_order = plan_dragon(u);
|
long_order = plan_dragon(u);
|
||||||
break;
|
}
|
||||||
default:
|
else {
|
||||||
if (u_race(u)->flags & RCF_LEARN) {
|
if (rc == get_race(RC_SEASERPENT)) {
|
||||||
long_order = monster_learn(u);
|
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)) {
|
if (long_order == NULL && unit_can_study(u)) {
|
||||||
/* Einheiten, die Waffenlosen Kampf lernen könnten, lernen es um
|
/* Einheiten, die Waffenlosen Kampf lernen könnten, lernen es um
|
||||||
* zu bewachen: */
|
* zu bewachen: */
|
||||||
if (u_race(u)->bonus[SK_WEAPONLESS] != -99) {
|
if (rc->bonus[SK_WEAPONLESS] != -99) {
|
||||||
if (effskill(u, SK_WEAPONLESS, 0) < 1) {
|
if (effskill(u, SK_WEAPONLESS, 0) < 1) {
|
||||||
long_order =
|
long_order =
|
||||||
create_order(K_STUDY, f->locale, "'%s'",
|
create_order(K_STUDY, f->locale, "'%s'",
|
||||||
|
|
|
@ -54,8 +54,7 @@ static void create_monsters(faction **player, faction **monsters, unit **u, unit
|
||||||
*monsters = get_or_create_monsters();
|
*monsters = get_or_create_monsters();
|
||||||
assert(rc_find((*monsters)->race->_name));
|
assert(rc_find((*monsters)->race->_name));
|
||||||
rc = rc_get_or_create((*monsters)->race->_name);
|
rc = rc_get_or_create((*monsters)->race->_name);
|
||||||
fset(rc, RCF_UNARMEDGUARD);
|
fset(rc, RCF_UNARMEDGUARD|RCF_NPC|RCF_DRAGON);
|
||||||
fset(rc, RCF_NPC);
|
|
||||||
fset(*monsters, FFL_NOIDLEOUT);
|
fset(*monsters, FFL_NOIDLEOUT);
|
||||||
assert(fval(*monsters, FFL_NPC) && fval((*monsters)->race, RCF_UNARMEDGUARD) && fval((*monsters)->race, RCF_NPC) && fval(*monsters, FFL_NOIDLEOUT));
|
assert(fval(*monsters, FFL_NPC) && fval((*monsters)->race, RCF_UNARMEDGUARD) && fval((*monsters)->race, RCF_NPC) && fval(*monsters, FFL_NOIDLEOUT));
|
||||||
|
|
||||||
|
|
13
src/move.c
13
src/move.c
|
@ -1465,16 +1465,15 @@ static void make_route(unit * u, order * ord, region_list ** routep)
|
||||||
static int movement_speed(unit * u)
|
static int movement_speed(unit * u)
|
||||||
{
|
{
|
||||||
int mp = BP_WALKING;
|
int mp = BP_WALKING;
|
||||||
double dk = u_race(u)->speed;
|
const race *rc = u_race(u);
|
||||||
|
double dk = rc->speed;
|
||||||
assert(u->number);
|
assert(u->number);
|
||||||
/* dragons have a fixed speed, and no other effects work on them: */
|
/* dragons have a fixed speed, and no other effects work on them: */
|
||||||
switch (old_race(u_race(u))) {
|
if (fval(rc, RCF_DRAGON)) {
|
||||||
case RC_DRAGON:
|
|
||||||
case RC_WYRM:
|
|
||||||
case RC_FIREDRAGON:
|
|
||||||
return BP_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:
|
case RC_SONGDRAGON:
|
||||||
mp = BP_DRAGON;
|
mp = BP_DRAGON;
|
||||||
break;
|
break;
|
||||||
|
|
58
src/spells.c
58
src/spells.c
|
@ -1501,16 +1501,23 @@ static int sp_create_irongolem(castorder * co)
|
||||||
int cast_level = co->level;
|
int cast_level = co->level;
|
||||||
double force = co->force;
|
double force = co->force;
|
||||||
int number = lovar(force * 8 * RESOURCE_QUANTITY);
|
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;
|
number = 1;
|
||||||
|
}
|
||||||
|
|
||||||
if (r->terrain == newterrain(T_SWAMP)) {
|
if (r->terrain == newterrain(T_SWAMP)) {
|
||||||
cmistake(mage, co->order, 188, MSG_MAGIC);
|
cmistake(mage, co->order, 188, MSG_MAGIC);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
u2 =
|
u2 = create_unit(r, mage->faction, number, golem_rc, 0, NULL, mage);
|
||||||
create_unit(r, mage->faction, number, rc_find("irongolem"), 0, NULL, mage);
|
|
||||||
|
|
||||||
set_level(u2, SK_ARMORER, 1);
|
set_level(u2, SK_ARMORER, 1);
|
||||||
set_level(u2, SK_WEAPONSMITH, 1);
|
set_level(u2, SK_WEAPONSMITH, 1);
|
||||||
|
@ -1523,7 +1530,7 @@ static int sp_create_irongolem(castorder * co)
|
||||||
ADDMSG(&mage->faction->msgs,
|
ADDMSG(&mage->faction->msgs,
|
||||||
msg_message("magiccreate_effect", "region command unit amount object",
|
msg_message("magiccreate_effect", "region command unit amount object",
|
||||||
mage->region, co->order, mage, number,
|
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;
|
return cast_level;
|
||||||
}
|
}
|
||||||
|
@ -1563,6 +1570,12 @@ static int sp_create_stonegolem(castorder * co)
|
||||||
unit *mage = co->magician.u;
|
unit *mage = co->magician.u;
|
||||||
int cast_level = co->level;
|
int cast_level = co->level;
|
||||||
int number = lovar(co->force * 5 * RESOURCE_QUANTITY);
|
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)
|
if (number < 1)
|
||||||
number = 1;
|
number = 1;
|
||||||
|
|
||||||
|
@ -1572,7 +1585,7 @@ static int sp_create_stonegolem(castorder * co)
|
||||||
}
|
}
|
||||||
|
|
||||||
u2 =
|
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_ROAD_BUILDING, 1);
|
||||||
set_level(u2, SK_BUILDING, 1);
|
set_level(u2, SK_BUILDING, 1);
|
||||||
|
|
||||||
|
@ -1584,7 +1597,7 @@ static int sp_create_stonegolem(castorder * co)
|
||||||
ADDMSG(&mage->faction->msgs,
|
ADDMSG(&mage->faction->msgs,
|
||||||
msg_message("magiccreate_effect", "region command unit amount object",
|
msg_message("magiccreate_effect", "region command unit amount object",
|
||||||
mage->region, co->order, mage, number,
|
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;
|
return cast_level;
|
||||||
}
|
}
|
||||||
|
@ -2717,6 +2730,26 @@ static int sp_firewall(castorder * co)
|
||||||
* (SPELLLEVEL | TESTCANSEE)
|
* (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)
|
static int sp_unholypower(castorder * co)
|
||||||
{
|
{
|
||||||
region * r = co_get_region(co);
|
region * r = co_get_region(co);
|
||||||
|
@ -2739,17 +2772,8 @@ static int sp_unholypower(castorder * co)
|
||||||
|
|
||||||
u = pa->param[i]->data.u;
|
u = pa->param[i]->data.u;
|
||||||
|
|
||||||
switch (old_race(u_race(u))) {
|
target_race = unholy_race(u_race(u));
|
||||||
case RC_SKELETON:
|
if (!target_race) {
|
||||||
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:
|
|
||||||
cmistake(mage, co->order, 284, MSG_MAGIC);
|
cmistake(mage, co->order, 284, MSG_MAGIC);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
18
src/study.c
18
src/study.c
|
@ -94,6 +94,9 @@ magic_t getmagicskill(const struct locale * lang)
|
||||||
/* familiars and toads are not migrants */
|
/* familiars and toads are not migrants */
|
||||||
bool is_migrant(unit * u)
|
bool is_migrant(unit * u)
|
||||||
{
|
{
|
||||||
|
static int cache;
|
||||||
|
static race *toad_rc;
|
||||||
|
|
||||||
if (u_race(u) == u->faction->race)
|
if (u_race(u) == u->faction->race)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
@ -101,16 +104,21 @@ bool is_migrant(unit * u)
|
||||||
return false;
|
return false;
|
||||||
if (is_familiar(u))
|
if (is_familiar(u))
|
||||||
return false;
|
return false;
|
||||||
if (u_race(u) == get_race(RC_TOAD))
|
if (rc_changed(&cache)) {
|
||||||
return false;
|
toad_rc = get_race(RC_TOAD);
|
||||||
|
}
|
||||||
return true;
|
return u_race(u) != toad_rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------- */
|
/* ------------------------------------------------------------- */
|
||||||
bool magic_lowskill(unit * u)
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------- */
|
/* ------------------------------------------------------------- */
|
||||||
|
|
|
@ -118,7 +118,7 @@ damage_unit(unit * u, const char *dam, bool physical, bool magic)
|
||||||
heiltrank = 0;
|
heiltrank = 0;
|
||||||
|
|
||||||
/* Sieben Leben */
|
/* 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[i] = u->hp / u->number;
|
||||||
hp_rem += hp[i];
|
hp_rem += hp[i];
|
||||||
continue;
|
continue;
|
||||||
|
|
Loading…
Reference in a new issue