WIP: reimplemented production modifiers.

The system itself seems to work, but some Lua tests are still failing.
This commit is contained in:
Enno Rehling 2017-04-02 14:43:53 +02:00
parent 4aa26343f6
commit e72155a563
24 changed files with 385 additions and 312 deletions

View File

@ -93,7 +93,6 @@
</building> </building>
<building name="smithy" capacity="1"> <building name="smithy" capacity="1">
<function name="init" value="init_smithy"/>
<maintenance type="money" amount="300"/> <maintenance type="money" amount="300"/>
<maintenance type="log" amount="1"/> <maintenance type="log" amount="1"/>
<construction skill="building" minskill="3"> <construction skill="building" minskill="3">
@ -102,6 +101,8 @@
<requirement type="iron" quantity="2"/> <requirement type="iron" quantity="2"/>
<requirement type="money" quantity="200"/> <requirement type="money" quantity="200"/>
</construction> </construction>
<modifier type="skill" skill="weaponsmithing" value="1"/>
<modifier type="skill" skill="armorer" value="1"/>
</building> </building>
<building name="magictower" maxcapacity="2" maxsize="50" magic="yes" magres="40" fumblebonus="10" auraregen="1.75"> <building name="magictower" maxcapacity="2" maxsize="50" magic="yes" magres="40" fumblebonus="10" auraregen="1.75">

View File

@ -5539,6 +5539,15 @@
<text locale="de">"$unit($unit) in $region($region): '$order($command)' - Diesen Gegenstand kann die Einheit nicht herstellen."</text> <text locale="de">"$unit($unit) in $region($region): '$order($command)' - Diesen Gegenstand kann die Einheit nicht herstellen."</text>
<text locale="en">"$unit($unit) in $region($region): '$order($command)' - This unit cannot produce that."</text> <text locale="en">"$unit($unit) in $region($region): '$order($command)' - This unit cannot produce that."</text>
</message> </message>
<message name="error117" section="errors">
<type>
<arg name="unit" type="unit"/>
<arg name="region" type="region"/>
<arg name="command" type="order"/>
</type>
<text locale="de">"$unit($unit) in $region($region): '$order($command)' - Diese Rasse kann das nicht herstellen."</text>
<text locale="en">"$unit($unit) in $region($region): '$order($command)' - This race cannot produce that."</text>
</message>
<message name="error116" section="errors"> <message name="error116" section="errors">
<type> <type>
<arg name="unit" type="unit"/> <arg name="unit" type="unit"/>

View File

@ -3,7 +3,8 @@
<item weight="500" score="10"> <item weight="500" score="10">
<construction skill="mining" minskill="1"/> <construction skill="mining" minskill="1"/>
</item> </item>
<modifier building="smithy" type="save" value="2"/>
<modifier building="mine" type="skill" value="1"/> <modifier building="mine" type="skill" value="1"/>
<modifier building="mine" type="material" value="0.5"/> <modifier building="mine" type="material" value="0.5"/>
<modifier race="dwarf" type="material" value="0.60"/> <modifier race="dwarf" type="material" value="0.6"/>
</resource> </resource>

View File

@ -1,8 +1,8 @@
<?xml version="1.0"?> <?xml version="1.0"?>
<resource name="greatbow"> <resource name="greatbow">
<modifier type="require" race="elf"/>
<item weight="100"> <item weight="100">
<construction skill="weaponsmithing" minskill="5"> <construction skill="weaponsmithing" minskill="5">
<modifier function="mod_elves_only"/>
<requirement type="mallorn" quantity="2"/> <requirement type="mallorn" quantity="2"/>
</construction> </construction>
<weapon pierce="true" missile="true" skill="bow" offmod="0" defmod="0" reload="0" magres="0.0"> <weapon pierce="true" missile="true" skill="bow" offmod="0" defmod="0" reload="0" magres="0.0">

View File

@ -1,8 +1,8 @@
<?xml version="1.0"?> <?xml version="1.0"?>
<resource name="scale"> <resource name="scale">
<modifier type="require" race="dwarf"/>
<item weight="300" score="150" allow="dwarf halfling"> <item weight="300" score="150" allow="dwarf halfling">
<construction skill="armorer" minskill="5"> <construction skill="armorer" minskill="5">
<modifier function="mod_dwarves_only"/>
<requirement type="iron" quantity="2"/> <requirement type="iron" quantity="2"/>
</construction> </construction>
<armor ac="3" penalty="0.10" projectile="0.05" magres="0.0"/> <armor ac="3" penalty="0.10" projectile="0.05" magres="0.0"/>

View File

@ -1,8 +1,8 @@
<?xml version="1.0"?> <?xml version="1.0"?>
<resource name="towershield"> <resource name="towershield">
<modifier type="require" race="dwarf"/>
<item weight="200" score="60" allow="dwarf"> <item weight="200" score="60" allow="dwarf">
<construction skill="armorer" minskill="4"> <construction skill="armorer" minskill="4">
<modifier function="mod_dwarves_only"/>
<requirement type="iron" quantity="1"/> <requirement type="iron" quantity="1"/>
</construction> </construction>
<armor ac="0" penalty="-0.15" projectile="0.25" magres="0.0" shield="yes"> <armor ac="0" penalty="-0.15" projectile="0.25" magres="0.0" shield="yes">

View File

@ -3,6 +3,7 @@
<item weight="500" score="10"> <item weight="500" score="10">
<construction skill="mining" minskill="1"/> <construction skill="mining" minskill="1"/>
</item> </item>
<modifier building="smithy" type="save" value="2"/>
<modifier building="mine" type="skill" value="1"/> <modifier building="mine" type="skill" value="1"/>
<modifier building="mine" type="material" value="0.5"/> <modifier building="mine" type="material" value="0.5"/>
</resource> </resource>

View File

@ -4,9 +4,9 @@
* has lower damage * has lower damage
--> -->
<resource name="greatbow"> <resource name="greatbow">
<modifier type="require" race="elf"/>
<item weight="100" allow="elf"> <item weight="100" allow="elf">
<construction skill="weaponsmithing" minskill="5"> <construction skill="weaponsmithing" minskill="5">
<modifier function="mod_elves_only"/>
<requirement type="mallorn" quantity="2"/> <requirement type="mallorn" quantity="2"/>
</construction> </construction>
<weapon pierce="true" missile="true" skill="bow" offmod="0" defmod="0" reload="0" magres="0.0"> <weapon pierce="true" missile="true" skill="bow" offmod="0" defmod="0" reload="0" magres="0.0">

View File

@ -1,8 +1,8 @@
<?xml version="1.0"?> <?xml version="1.0"?>
<resource name="rep_crossbow"> <resource name="rep_crossbow">
<modifier type="require" race="dwarf"/>
<item weight="100" allow="dwarf halfling"> <item weight="100" allow="dwarf halfling">
<construction skill="weaponsmithing" minskill="5"> <construction skill="weaponsmithing" minskill="5">
<modifier function="mod_dwarves_only"/>
<requirement type="log" quantity="1"/> <requirement type="log" quantity="1"/>
<requirement type="iron" quantity="1"/> <requirement type="iron" quantity="1"/>
</construction> </construction>

View File

@ -124,6 +124,33 @@ function test_quarry_bonus()
turn_end() turn_end()
end end
function test_smithy_no_bonus()
-- a smithy does not give a bonus to other skills
-- five cartmakers make 5 carts, no matter what
local r = region.create(0, 0, 'mountain')
local f = create_faction('human')
local u = unit.create(f, r, 1)
turn_begin()
u.building = building.create(u.region, 'smithy')
u.building.working = false
u.building.size = 10
u.number = 5
u:set_skill('cartmaking', 1) -- needs 1 min
u:add_item('log', 100)
u:add_order("MACHE Wagen")
turn_process() -- building disabled
assert_equal(5, u:get_item('cart'))
assert_equal(75, u:get_item('log'))
u.building.working = true
turn_process() -- building active
assert_equal(10, u:get_item('cart'))
assert_equal(50, u:get_item('log'))
turn_end()
end
function test_smithy_bonus_iron() function test_smithy_bonus_iron()
-- a smithy adds +1 to weaponsmithing, and saves 50% iron -- a smithy adds +1 to weaponsmithing, and saves 50% iron
local r = region.create(0, 0, 'mountain') local r = region.create(0, 0, 'mountain')

View File

@ -12,7 +12,6 @@ follow.c
hate.c hate.c
iceberg.c iceberg.c
key.c key.c
matmod.c
moved.c moved.c
movement.c movement.c
dict.c dict.c

View File

@ -1,41 +0,0 @@
/*
Copyright (c) 1998-2015, Enno Rehling <enno@eressea.de>
Katja Zedel <katze@felidae.kn-bremen.de
Christian Schlittchen <corwin@amber.kn-bremen.de>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
**/
#include <platform.h>
#include "matmod.h"
#include <util/attrib.h>
#include <stddef.h>
attrib_type at_matmod = {
"matmod",
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
ATF_PRESERVE
};
attrib *make_matmod(mm_fun function)
{
attrib *a = a_new(&at_matmod);
a->data.f = (void(*)(void))function;
return a;
}

View File

@ -1,37 +0,0 @@
/*
Copyright (c) 1998-2015, Enno Rehling <enno@eressea.de>
Katja Zedel <katze@felidae.kn-bremen.de
Christian Schlittchen <corwin@amber.kn-bremen.de>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
**/
#ifndef H_ATTRIBUTE_MATMOD
#define H_ATTRIBUTE_MATMOD
#ifdef __cplusplus
extern "C" {
#endif
struct resource_type;
struct unit;
typedef int(*mm_fun) (const struct unit * u,
const struct resource_type * rtype, int value);
extern struct attrib_type at_matmod;
extern struct attrib *make_matmod(mm_fun function);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -798,7 +798,69 @@ void economics(region * r)
} }
/* ------------------------------------------------------------- */ static void mod_skill(const resource_mod *mod, skill_t sk, int *skill) {
skill_t msk;
assert(mod->type == RMT_PROD_SKILL);
msk = (skill_t)mod->value.sa[0];
if (msk == NOSKILL || msk == sk) {
*skill += mod->value.sa[1];
}
}
static struct message * get_modifiers(unit *u, skill_t sk, const resource_type *rtype, variant *savep, int *skillp) {
struct building *b = inside_building(u);
const struct building_type *btype = building_is_active(b) ? b->type : NULL;
int save_n = 1, save_d = 1;
int skill = 0;
int need_race = 0, need_bldg = 0;
resource_mod *mod;
if (btype && btype->modifiers) {
for (mod = btype->modifiers; mod && mod->type != RMT_END; ++mod) {
if (mod->type == RMT_PROD_SKILL) {
mod_skill(mod, sk, &skill);
}
}
}
for (mod = rtype->modifiers; mod && mod->type != RMT_END; ++mod) {
if (mod->btype == NULL || mod->btype == btype) {
if (mod->race == NULL || mod->race == u_race(u)) {
switch (mod->type) {
case RMT_PROD_SAVE:
if (savep) {
save_n *= mod->value.sa[0];
save_d *= mod->value.sa[1];
}
break;
case RMT_PROD_SKILL:
mod_skill(mod, sk, &skill);
break;
case RMT_PROD_REQUIRE:
if (mod->race) need_race |= 1;
if (mod->btype) need_bldg |= 1;
break;
default:
/* is not a production modifier, ignore it */
break;
}
}
}
if (mod->type == RMT_PROD_REQUIRE) {
if (mod->race) need_race |= 2;
if (mod->btype) need_bldg |= 2;
}
}
if (need_race == 2) {
return msg_error(u, u->thisorder, 117);
}
if (need_bldg == 2) {
return msg_error(u, u->thisorder, 104);
}
*skillp = skill;
if (savep) *savep = frac_make(save_n, save_d);
return NULL;
}
static void manufacture(unit * u, const item_type * itype, int want) static void manufacture(unit * u, const item_type * itype, int want)
{ {
@ -806,22 +868,20 @@ static void manufacture(unit * u, const item_type * itype, int want)
int skill; int skill;
int minskill = itype->construction->minskill; int minskill = itype->construction->minskill;
skill_t sk = itype->construction->skill; skill_t sk = itype->construction->skill;
message *msg;
int skill_mod;
skill = effskill(u, sk, 0); msg = get_modifiers(u, sk, itype->rtype, NULL, &skill_mod);
skill = if (msg) {
skillmod(itype->construction->attribs, u, u->region, sk, skill, SMF_PRODUCTION); ADDMSG(&u->faction->msgs, msg);
if (skill < 0) {
/* an error occured */
int err = -skill;
cmistake(u, u->thisorder, err, MSG_PRODUCE);
return; return;
} }
skill = effskill(u, sk, 0);
if (want == 0) { if (want == 0) {
want = maxbuild(u, itype->construction); want = maxbuild(u, itype->construction);
} }
n = build(u, itype->construction, 0, want); n = build(u, itype->construction, 0, want, skill_mod);
switch (n) { switch (n) {
case ENEEDSKILL: case ENEEDSKILL:
ADDMSG(&u->faction->msgs, ADDMSG(&u->faction->msgs,
@ -879,38 +939,6 @@ enum {
AFL_LOWSKILL = 1 << 1 AFL_LOWSKILL = 1 << 1
}; };
struct message * get_modifiers(unit *u, const resource_type *rtype, variant *savep, int *skillp) {
struct building *b = inside_building(u);
const struct building_type *btype = building_is_active(b) ? b->type : NULL;
int save_n = 1, save_d = 1;
int skill = 0;
resource_mod *mod;
for (mod = rtype->modifiers; mod && mod->flags != 0; ++mod) {
if (mod->btype == NULL || mod->btype == btype) {
if (mod->race == NULL || mod->race == u_race(u)) {
if (mod->flags & RMF_SAVEMATERIAL) {
save_n *= mod->value.sa[0];
save_d *= mod->value.sa[1];
}
if (mod->flags & RMF_SKILL) {
skill += mod->value.i;
}
}
} else if (mod->flags & RMF_REQUIREDBUILDING) {
return msg_error(u, u->thisorder, 104);
}
}
*skillp = skill;
assert(save_n < SHRT_MAX);
assert(save_n > SHRT_MIN);
assert(save_d < SHRT_MAX);
assert(save_d > SHRT_MIN);
savep->sa[0] = (short)save_n;
savep->sa[1] = (short)save_d;
return NULL;
}
static void allocate_resource(unit * u, const resource_type * rtype, int want) static void allocate_resource(unit * u, const resource_type * rtype, int want)
{ {
const item_type *itype = resource2item(rtype); const item_type *itype = resource2item(rtype);
@ -921,12 +949,14 @@ static void allocate_resource(unit * u, const resource_type * rtype, int want)
const resource_type *rring; const resource_type *rring;
int amount, skill, skill_mod = 0; int amount, skill, skill_mod = 0;
variant save_mod; variant save_mod;
skill_t sk;
/* momentan kann man keine ressourcen abbauen, wenn man daf<61>r /* momentan kann man keine ressourcen abbauen, wenn man daf<61>r
* Materialverbrauch hat: */ * Materialverbrauch hat: */
assert(itype != NULL && (itype->construction == NULL assert(itype != NULL && (itype->construction == NULL
|| itype->construction->materials == NULL)); || itype->construction->materials == NULL));
sk = itype->construction->skill;
if (!rtype->raw) { if (!rtype->raw) {
int avail = limit_resource(r, rtype); int avail = limit_resource(r, rtype);
if (avail <= 0) { if (avail <= 0) {
@ -941,7 +971,7 @@ static void allocate_resource(unit * u, const resource_type * rtype, int want)
} }
if (rtype->modifiers) { if (rtype->modifiers) {
message *msg = get_modifiers(u, rtype, &save_mod, &skill_mod); message *msg = get_modifiers(u, sk, rtype, &save_mod, &skill_mod);
if (msg) { if (msg) {
ADDMSG(&u->faction->msgs, msg); ADDMSG(&u->faction->msgs, msg);
return; return;
@ -969,17 +999,14 @@ static void allocate_resource(unit * u, const resource_type * rtype, int want)
} }
} }
assert(itype->construction->skill != 0 assert(sk != NOSKILL || "limited resource needs a required skill for making it");
|| "limited resource needs a required skill for making it"); skill = effskill(u, sk, 0);
skill = effskill(u, itype->construction->skill, 0);
if (skill == 0) { if (skill == 0) {
skill_t sk = itype->construction->skill;
add_message(&u->faction->msgs, add_message(&u->faction->msgs,
msg_feedback(u, u->thisorder, "skill_needed", "skill", sk)); msg_feedback(u, u->thisorder, "skill_needed", "skill", sk));
return; return;
} }
if (skill < itype->construction->minskill) { if (skill < itype->construction->minskill) {
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,
@ -1204,7 +1231,7 @@ static void create_potion(unit * u, const potion_type * ptype, int want)
if (want == 0) { if (want == 0) {
want = maxbuild(u, ptype->itype->construction); want = maxbuild(u, ptype->itype->construction);
} }
built = build(u, ptype->itype->construction, 0, want); built = build(u, ptype->itype->construction, 0, want, 0);
switch (built) { switch (built) {
case ELOWSKILL: case ELOWSKILL:
case ENEEDSKILL: case ENEEDSKILL:

View File

@ -345,7 +345,114 @@ static void test_income(CuTest *tc)
test_cleanup(); test_cleanup();
} }
static void test_make_item(CuTest *tc) { static void test_modify_material(CuTest *tc) {
unit *u;
struct item_type *itype;
resource_type *rtype;
resource_mod *mod;
test_setup();
init_resources();
u = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0));
set_level(u, SK_WEAPONSMITH, 1);
/* the unit's race gets 2x savings on iron used to produce goods */
itype = test_create_itemtype("iron");
rtype = itype->rtype;
mod = rtype->modifiers = calloc(2, sizeof(resource_mod));
mod[0].type = RMT_USE_SAVE;
mod[0].value = frac_make(2, 1);
mod[0].race = u_race(u);
itype = test_create_itemtype("sword");
make_item(u, itype, 1);
CuAssertPtrNotNull(tc, test_find_messagetype(u->faction->msgs, "error_cannotmake"));
CuAssertIntEquals(tc, 0, get_item(u, itype));
test_clear_messages(u->faction);
itype->construction = calloc(1, sizeof(construction));
itype->construction->skill = SK_WEAPONSMITH;
itype->construction->minskill = 1;
itype->construction->maxsize = 1;
itype->construction->reqsize = 1;
itype->construction->materials = calloc(2, sizeof(requirement));
itype->construction->materials[0].rtype = rtype;
itype->construction->materials[0].number = 2;
set_item(u, rtype->itype, 1); /* 1 iron should get us 1 sword */
make_item(u, itype, 1);
CuAssertIntEquals(tc, 1, get_item(u, itype));
CuAssertIntEquals(tc, 0, get_item(u, rtype->itype));
u_setrace(u, test_create_race("smurf"));
set_item(u, rtype->itype, 2); /* 2 iron should be required now */
make_item(u, itype, 1);
CuAssertIntEquals(tc, 2, get_item(u, itype));
CuAssertIntEquals(tc, 0, get_item(u, rtype->itype));
test_cleanup();
}
static void test_modify_skill(CuTest *tc) {
unit *u;
struct item_type *itype;
/* building_type *btype; */
resource_type *rtype;
resource_mod *mod;
test_setup();
init_resources();
u = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0));
set_level(u, SK_WEAPONSMITH, 1);
itype = test_create_itemtype("iron");
rtype = itype->rtype;
itype = test_create_itemtype("sword");
make_item(u, itype, 1);
CuAssertPtrNotNull(tc, test_find_messagetype(u->faction->msgs, "error_cannotmake"));
CuAssertIntEquals(tc, 0, get_item(u, itype));
test_clear_messages(u->faction);
itype->construction = calloc(1, sizeof(construction));
itype->construction->skill = SK_WEAPONSMITH;
itype->construction->minskill = 1;
itype->construction->maxsize = -1;
itype->construction->reqsize = 1;
itype->construction->materials = calloc(2, sizeof(requirement));
itype->construction->materials[0].rtype = rtype;
itype->construction->materials[0].number = 1;
/* our race gets a +1 bonus to the item's production skill */
mod = itype->rtype->modifiers = calloc(2, sizeof(resource_mod));
mod[0].type = RMT_PROD_SKILL;
mod[0].value.sa[0] = SK_WEAPONSMITH;
mod[0].value.sa[1] = 1;
mod[0].race = u_race(u);
set_item(u, rtype->itype, 2); /* 2 iron should get us 2 swords */
make_item(u, itype, 2);
CuAssertIntEquals(tc, 2, get_item(u, itype));
CuAssertIntEquals(tc, 0, get_item(u, rtype->itype));
mod[0].value.sa[0] = NOSKILL; /* match any skill */
set_item(u, rtype->itype, 2);
make_item(u, itype, 2);
CuAssertIntEquals(tc, 4, get_item(u, itype));
CuAssertIntEquals(tc, 0, get_item(u, rtype->itype));
u_setrace(u, test_create_race("smurf"));
set_item(u, rtype->itype, 2);
make_item(u, itype, 1); /* only enough skill to make 1 now */
CuAssertIntEquals(tc, 5, get_item(u, itype));
CuAssertIntEquals(tc, 1, get_item(u, rtype->itype));
test_cleanup();
}
static void test_modify_production(CuTest *tc) {
unit *u; unit *u;
struct item_type *itype; struct item_type *itype;
const struct resource_type *rt_silver; const struct resource_type *rt_silver;
@ -393,7 +500,7 @@ static void test_make_item(CuTest *tc) {
CuAssertIntEquals(tc, 290, region_getresource(u->region, rtype)); /* used 10 stones to make 10 stones */ CuAssertIntEquals(tc, 290, region_getresource(u->region, rtype)); /* used 10 stones to make 10 stones */
rtype->modifiers = calloc(2, sizeof(resource_mod)); rtype->modifiers = calloc(2, sizeof(resource_mod));
rtype->modifiers[0].flags = RMF_SAVEMATERIAL; rtype->modifiers[0].type = RMT_PROD_SAVE;
rtype->modifiers[0].race = u->_race; rtype->modifiers[0].race = u->_race;
rtype->modifiers[0].value.sa[0] = (short)(0.5+100*d); rtype->modifiers[0].value.sa[0] = (short)(0.5+100*d);
rtype->modifiers[0].value.sa[1] = 100; rtype->modifiers[0].value.sa[1] = 100;
@ -413,13 +520,34 @@ static void test_make_item(CuTest *tc) {
CuAssertIntEquals(tc, 28, get_item(u, itype)); CuAssertIntEquals(tc, 28, get_item(u, itype));
CuAssertIntEquals(tc, 280, region_getresource(u->region, rtype)); /* 50% saving = 3 stones make 6 stones */ CuAssertIntEquals(tc, 280, region_getresource(u->region, rtype)); /* 50% saving = 3 stones make 6 stones */
rtype->modifiers[0].flags = RMF_REQUIREDBUILDING; rtype->modifiers[0].type = RMT_PROD_REQUIRE;
rtype->modifiers[0].race = NULL; rtype->modifiers[0].race = NULL;
rtype->modifiers[0].btype = bt_get_or_create("mine"); rtype->modifiers[0].btype = bt_get_or_create("mine");
test_clear_messages(u->faction);
make_item(u, itype, 10); make_item(u, itype, 10);
CuAssertIntEquals(tc, 28, get_item(u, itype));
CuAssertPtrNotNull(tc, test_find_messagetype(u->faction->msgs, "error104")); CuAssertPtrNotNull(tc, test_find_messagetype(u->faction->msgs, "error104"));
rtype->modifiers[0].type = RMT_PROD_REQUIRE;
rtype->modifiers[0].race = test_create_race("smurf");
rtype->modifiers[0].btype = NULL;
test_clear_messages(u->faction);
make_item(u, itype, 10);
CuAssertIntEquals(tc, 28, get_item(u, itype));
CuAssertPtrNotNull(tc, test_find_messagetype(u->faction->msgs, "error117"));
rtype->modifiers[1].type = RMT_PROD_REQUIRE;
rtype->modifiers[1].race = u_race(u);
rtype->modifiers[1].btype = NULL;
test_clear_messages(u->faction);
make_item(u, itype, 10);
CuAssertPtrEquals(tc, NULL, u->faction->msgs);
split_allocations(u->region);
CuAssertIntEquals(tc, 38, get_item(u, itype));
test_cleanup(); test_cleanup();
} }
@ -429,7 +557,9 @@ CuSuite *get_economy_suite(void)
SUITE_ADD_TEST(suite, test_give_control_building); SUITE_ADD_TEST(suite, test_give_control_building);
SUITE_ADD_TEST(suite, test_give_control_ship); SUITE_ADD_TEST(suite, test_give_control_ship);
SUITE_ADD_TEST(suite, test_income); SUITE_ADD_TEST(suite, test_income);
SUITE_ADD_TEST(suite, test_make_item); SUITE_ADD_TEST(suite, test_modify_production);
SUITE_ADD_TEST(suite, test_modify_skill);
SUITE_ADD_TEST(suite, test_modify_material);
SUITE_ADD_TEST(suite, test_steal_okay); SUITE_ADD_TEST(suite, test_steal_okay);
SUITE_ADD_TEST(suite, test_steal_ocean); SUITE_ADD_TEST(suite, test_steal_ocean);
SUITE_ADD_TEST(suite, test_steal_nosteal); SUITE_ADD_TEST(suite, test_steal_nosteal);

View File

@ -43,6 +43,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#include <kernel/pool.h> #include <kernel/pool.h>
#include <kernel/race.h> #include <kernel/race.h>
#include <kernel/region.h> #include <kernel/region.h>
#include <kernel/resources.h>
#include <kernel/ship.h> #include <kernel/ship.h>
#include <kernel/terrain.h> #include <kernel/terrain.h>
#include <kernel/terrainid.h> #include <kernel/terrainid.h>
@ -67,9 +68,6 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
/* attributes inclues */
#include <attributes/matmod.h>
struct building *getbuilding(const struct region *r) struct building *getbuilding(const struct region *r)
{ {
building *b = findbuilding(getid()); building *b = findbuilding(getid());
@ -404,16 +402,26 @@ static int required(int size, int msize, int maxneed)
return used; return used;
} }
static int static int matmod(const unit * u, const resource_type * rtype, int value)
matmod(const attrib * a, const unit * u, const resource_type * material,
int value)
{ {
for (a = a_find((attrib *)a, &at_matmod); a && a->type == &at_matmod; if (rtype->modifiers) {
a = a->next) { variant save = frac_make(1, 1);
mm_fun fun = (mm_fun)a->data.f; const struct building_type *btype = NULL;
value = fun(u, material, value); const struct race *rc = u_race(u);
if (value < 0) resource_mod *mod;
return value; /* pass errors to caller */ if (u->building && inside_building(u)) {
btype = u->building->type;
}
for (mod = rtype->modifiers; mod->type != RMT_END; ++mod) {
if (mod->type == RMT_USE_SAVE) {
if (!mod->btype || mod->btype == btype) {
if (!mod->race || mod->race == rc) {
save = frac_mul(save, mod->value);
}
}
}
}
return value * save.sa[0] / save.sa[1];
} }
return value; return value;
} }
@ -439,14 +447,8 @@ static int use_materials(unit *u, const construction *type, int n, int completed
required(completed + n, type->reqsize, type->materials[c].number); required(completed + n, type->reqsize, type->materials[c].number);
int multi = 1; int multi = 1;
int canuse = 100; /* normalization */ int canuse = 100; /* normalization */
if (building_is_active(u->building) && inside_building(u)) { canuse = matmod(u, rtype, canuse);
canuse = matmod(u->building->type->attribs, u, rtype, canuse); assert(canuse >= 0);
}
if (canuse < 0) {
return canuse; /* pass errors to caller */
}
canuse = matmod(type->attribs, u, rtype, canuse);
assert(canuse % 100 == 0 assert(canuse % 100 == 0
|| !"only constant multipliers are implemented in build()"); || !"only constant multipliers are implemented in build()");
multi = canuse / 100; multi = canuse / 100;
@ -468,14 +470,9 @@ static int count_materials(unit *u, const construction *type, int n, int complet
const struct resource_type *rtype = type->materials[c].rtype; const struct resource_type *rtype = type->materials[c].rtype;
int need, prebuilt; int need, prebuilt;
int canuse = get_pooled(u, rtype, GET_DEFAULT, INT_MAX); int canuse = get_pooled(u, rtype, GET_DEFAULT, INT_MAX);
canuse = matmod(u, rtype, canuse);
if (building_is_active(u->building) && inside_building(u)) { assert(canuse >= 0);
canuse = matmod(u->building->type->attribs, u, rtype, canuse);
}
if (canuse < 0)
return canuse; /* pass errors to caller */
canuse = matmod(type->attribs, u, rtype, canuse);
if (type->reqsize > 1) { if (type->reqsize > 1) {
prebuilt = prebuilt =
required(completed, type->reqsize, type->materials[c].number); required(completed, type->reqsize, type->materials[c].number);
@ -503,7 +500,7 @@ static int count_materials(unit *u, const construction *type, int n, int complet
* of the first object have already been finished. return the * of the first object have already been finished. return the
* actual size that could be built. * actual size that could be built.
*/ */
int build(unit * u, const construction * ctype, int completed, int want) int build(unit * u, const construction * ctype, int completed, int want, int skill_mod)
{ {
const construction *type = ctype; const construction *type = ctype;
int skills = INT_MAX; /* number of skill points remainig */ int skills = INT_MAX; /* number of skill points remainig */
@ -536,17 +533,8 @@ int build(unit * u, const construction * ctype, int completed, int want)
if (basesk == 0) if (basesk == 0)
return ENEEDSKILL; return ENEEDSKILL;
effsk = basesk; effsk = basesk + skill_mod;
if (building_is_active(u->building) && inside_building(u)) { assert(effsk >= 0);
effsk = skillmod(u->building->type->attribs, u, u->region, type->skill,
effsk, SMF_PRODUCTION);
}
effsk = skillmod(type->attribs, u, u->region, type->skill,
effsk, SMF_PRODUCTION);
if (effsk < 0)
return effsk; /* pass errors to caller */
if (effsk == 0)
return ENEEDSKILL;
skills = effsk * u->number; skills = effsk * u->number;
@ -799,7 +787,7 @@ build_building(unit * u, const building_type * btype, int id, int want, order *
} }
} }
} }
built = build(u, btype->construction, built, n); built = build(u, btype->construction, built, n, 0);
switch (built) { switch (built) {
case ECOMPLETE: case ECOMPLETE:
@ -884,7 +872,7 @@ static void build_ship(unit * u, ship * sh, int want)
const construction *construction = sh->type->construction; const construction *construction = sh->type->construction;
int size = (sh->size * DAMAGE_SCALE - sh->damage) / DAMAGE_SCALE; int size = (sh->size * DAMAGE_SCALE - sh->damage) / DAMAGE_SCALE;
int n; int n;
int can = build(u, construction, size, want); int can = build(u, construction, size, want, 0);
if ((n = construction->maxsize - sh->size) > 0 && can > 0) { if ((n = construction->maxsize - sh->size) > 0 && can > 0) {
if (can >= n) { if (can >= n) {

View File

@ -55,9 +55,6 @@ extern "C" {
* last level of a building points to NULL, as do objects of * last level of a building points to NULL, as do objects of
* an unlimited size. * an unlimited size.
*/ */
struct attrib *attribs;
/* stores skill modifiers and other attributes */
} construction; } construction;
void free_construction(struct construction *cons); void free_construction(struct construction *cons);
@ -76,7 +73,7 @@ extern "C" {
void sunhash(struct ship *sh); void sunhash(struct ship *sh);
int roqf_factor(void); int roqf_factor(void);
int build(struct unit *u, const construction * ctype, int completed, int want); int build(struct unit *u, const construction * ctype, int completed, int want, int skill_mod);
int maxbuild(const struct unit *u, const construction * cons); int maxbuild(const struct unit *u, const construction * cons);
struct message *msg_materials_required(struct unit *u, struct order *ord, struct message *msg_materials_required(struct unit *u, struct order *ord,
const struct construction *ctype, int multi); const struct construction *ctype, int multi);

View File

@ -63,10 +63,10 @@ static void test_build_requires_materials(CuTest *tc) {
u = setup_build(&bf); u = setup_build(&bf);
set_level(u, SK_ARMORER, 2); set_level(u, SK_ARMORER, 2);
CuAssertIntEquals(tc, ENOMATERIALS, build(u, &bf.cons, 0, 1)); CuAssertIntEquals(tc, ENOMATERIALS, build(u, &bf.cons, 0, 1, 0));
itype = bf.cons.materials[0].rtype->itype; itype = bf.cons.materials[0].rtype->itype;
i_change(&u->items, itype, 2); i_change(&u->items, itype, 2);
CuAssertIntEquals(tc, 1, build(u, &bf.cons, 0, 1)); CuAssertIntEquals(tc, 1, build(u, &bf.cons, 0, 1, 0));
CuAssertIntEquals(tc, 1, i_get(u->items, itype)); CuAssertIntEquals(tc, 1, i_get(u->items, itype));
teardown_build(&bf); teardown_build(&bf);
} }
@ -84,12 +84,12 @@ static void test_build_requires_building(CuTest *tc) {
bf.cons.btype = btype = bt_get_or_create("hodor"); bf.cons.btype = btype = bt_get_or_create("hodor");
btype->maxcapacity = 1; btype->maxcapacity = 1;
btype->capacity = 1; btype->capacity = 1;
CuAssertIntEquals_Msg(tc, "must be inside a production building", EBUILDINGREQ, build(u, &bf.cons, 0, 1)); CuAssertIntEquals_Msg(tc, "must be inside a production building", EBUILDINGREQ, build(u, &bf.cons, 0, 1, 0));
u->building = test_create_building(u->region, btype); u->building = test_create_building(u->region, btype);
fset(u->building, BLD_MAINTAINED); fset(u->building, BLD_MAINTAINED);
CuAssertIntEquals(tc, 1, build(u, &bf.cons, 0, 1)); CuAssertIntEquals(tc, 1, build(u, &bf.cons, 0, 1, 0));
btype->maxcapacity = 0; btype->maxcapacity = 0;
CuAssertIntEquals_Msg(tc, "cannot build when production building capacity exceeded", EBUILDINGREQ, build(u, &bf.cons, 0, 1)); CuAssertIntEquals_Msg(tc, "cannot build when production building capacity exceeded", EBUILDINGREQ, build(u, &bf.cons, 0, 1, 0));
teardown_build(&bf); teardown_build(&bf);
} }
@ -101,7 +101,7 @@ static void test_build_failure_missing_skill(CuTest *tc) {
u = setup_build(&bf); u = setup_build(&bf);
rtype = bf.cons.materials[0].rtype; rtype = bf.cons.materials[0].rtype;
i_change(&u->items, rtype->itype, 1); i_change(&u->items, rtype->itype, 1);
CuAssertIntEquals(tc, ENEEDSKILL, build(u, &bf.cons, 1, 1)); CuAssertIntEquals(tc, ENEEDSKILL, build(u, &bf.cons, 1, 1, 0));
teardown_build(&bf); teardown_build(&bf);
} }
@ -114,7 +114,7 @@ static void test_build_failure_low_skill(CuTest *tc) {
rtype = bf.cons.materials[0].rtype; rtype = bf.cons.materials[0].rtype;
i_change(&u->items, rtype->itype, 1); i_change(&u->items, rtype->itype, 1);
set_level(u, SK_ARMORER, bf.cons.minskill - 1); set_level(u, SK_ARMORER, bf.cons.minskill - 1);
CuAssertIntEquals(tc, ELOWSKILL, build(u, &bf.cons, 0, 10)); CuAssertIntEquals(tc, ELOWSKILL, build(u, &bf.cons, 0, 10, 0));
teardown_build(&bf); teardown_build(&bf);
} }
@ -128,7 +128,7 @@ static void test_build_failure_completed(CuTest *tc) {
i_change(&u->items, rtype->itype, 1); i_change(&u->items, rtype->itype, 1);
set_level(u, SK_ARMORER, bf.cons.minskill); set_level(u, SK_ARMORER, bf.cons.minskill);
bf.cons.maxsize = 1; bf.cons.maxsize = 1;
CuAssertIntEquals(tc, ECOMPLETE, build(u, &bf.cons, bf.cons.maxsize, 10)); CuAssertIntEquals(tc, ECOMPLETE, build(u, &bf.cons, bf.cons.maxsize, 10, 0));
CuAssertIntEquals(tc, 1, i_get(u->items, rtype->itype)); CuAssertIntEquals(tc, 1, i_get(u->items, rtype->itype));
teardown_build(&bf); teardown_build(&bf);
} }
@ -143,19 +143,19 @@ static void test_build_limits(CuTest *tc) {
assert(rtype); assert(rtype);
i_change(&u->items, rtype->itype, 1); i_change(&u->items, rtype->itype, 1);
set_level(u, SK_ARMORER, bf.cons.minskill); set_level(u, SK_ARMORER, bf.cons.minskill);
CuAssertIntEquals(tc, 1, build(u, &bf.cons, 0, 10)); CuAssertIntEquals(tc, 1, build(u, &bf.cons, 0, 10, 0));
CuAssertIntEquals(tc, 0, i_get(u->items, rtype->itype)); CuAssertIntEquals(tc, 0, i_get(u->items, rtype->itype));
scale_number(u, 2); scale_number(u, 2);
set_level(u, SK_ARMORER, bf.cons.minskill); set_level(u, SK_ARMORER, bf.cons.minskill);
i_change(&u->items, rtype->itype, 2); i_change(&u->items, rtype->itype, 2);
CuAssertIntEquals(tc, 2, build(u, &bf.cons, 0, 10)); CuAssertIntEquals(tc, 2, build(u, &bf.cons, 0, 10, 0));
CuAssertIntEquals(tc, 0, i_get(u->items, rtype->itype)); CuAssertIntEquals(tc, 0, i_get(u->items, rtype->itype));
scale_number(u, 2); scale_number(u, 2);
set_level(u, SK_ARMORER, bf.cons.minskill * 2); set_level(u, SK_ARMORER, bf.cons.minskill * 2);
i_change(&u->items, rtype->itype, 4); i_change(&u->items, rtype->itype, 4);
CuAssertIntEquals(tc, 4, build(u, &bf.cons, 0, 10)); CuAssertIntEquals(tc, 4, build(u, &bf.cons, 0, 10, 0));
CuAssertIntEquals(tc, 0, i_get(u->items, rtype->itype)); CuAssertIntEquals(tc, 0, i_get(u->items, rtype->itype));
teardown_build(&bf); teardown_build(&bf);
} }
@ -174,7 +174,7 @@ static void test_build_with_ring(CuTest *tc) {
set_level(u, SK_ARMORER, bf.cons.minskill); set_level(u, SK_ARMORER, bf.cons.minskill);
i_change(&u->items, rtype->itype, 20); i_change(&u->items, rtype->itype, 20);
i_change(&u->items, ring, 1); i_change(&u->items, ring, 1);
CuAssertIntEquals(tc, 10, build(u, &bf.cons, 0, 20)); CuAssertIntEquals(tc, 10, build(u, &bf.cons, 0, 20, 0));
CuAssertIntEquals(tc, 10, i_get(u->items, rtype->itype)); CuAssertIntEquals(tc, 10, i_get(u->items, rtype->itype));
teardown_build(&bf); teardown_build(&bf);
} }
@ -193,16 +193,16 @@ static void test_build_with_potion(CuTest *tc) {
i_change(&u->items, rtype->itype, 20); i_change(&u->items, rtype->itype, 20);
change_effect(u, ptype, 4); change_effect(u, ptype, 4);
set_level(u, SK_ARMORER, bf.cons.minskill); set_level(u, SK_ARMORER, bf.cons.minskill);
CuAssertIntEquals(tc, 2, build(u, &bf.cons, 0, 20)); CuAssertIntEquals(tc, 2, build(u, &bf.cons, 0, 20, 0));
CuAssertIntEquals(tc, 18, i_get(u->items, rtype->itype)); CuAssertIntEquals(tc, 18, i_get(u->items, rtype->itype));
CuAssertIntEquals(tc, 3, get_effect(u, ptype)); CuAssertIntEquals(tc, 3, get_effect(u, ptype));
set_level(u, SK_ARMORER, bf.cons.minskill * 2); set_level(u, SK_ARMORER, bf.cons.minskill * 2);
CuAssertIntEquals(tc, 4, build(u, &bf.cons, 0, 20)); CuAssertIntEquals(tc, 4, build(u, &bf.cons, 0, 20, 0));
CuAssertIntEquals(tc, 2, get_effect(u, ptype)); CuAssertIntEquals(tc, 2, get_effect(u, ptype));
set_level(u, SK_ARMORER, bf.cons.minskill); set_level(u, SK_ARMORER, bf.cons.minskill);
scale_number(u, 2); /* OBS: this scales the effects, too: */ scale_number(u, 2); /* OBS: this scales the effects, too: */
CuAssertIntEquals(tc, 4, get_effect(u, ptype)); CuAssertIntEquals(tc, 4, get_effect(u, ptype));
CuAssertIntEquals(tc, 4, build(u, &bf.cons, 0, 20)); CuAssertIntEquals(tc, 4, build(u, &bf.cons, 0, 20, 0));
CuAssertIntEquals(tc, 2, get_effect(u, ptype)); CuAssertIntEquals(tc, 2, get_effect(u, ptype));
teardown_build(&bf); teardown_build(&bf);
} }

View File

@ -55,7 +55,6 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
/* attributes includes */ /* attributes includes */
#include <attributes/reduceproduction.h> #include <attributes/reduceproduction.h>
#include <attributes/matmod.h>
typedef struct building_typelist { typedef struct building_typelist {
struct building_typelist *next; struct building_typelist *next;
@ -99,9 +98,6 @@ bool bt_changed(int *cache)
void bt_register(building_type * type) void bt_register(building_type * type)
{ {
if (type->init) {
type->init(type);
}
selist_push(&buildingtypes, (void *)type); selist_push(&buildingtypes, (void *)type);
++bt_changes; ++bt_changes;
} }
@ -224,31 +220,6 @@ building *findbuilding(int i)
return bfindhash(i); return bfindhash(i);
} }
/* ** old building types ** */
static int sm_smithy(const unit * u, const region * r, skill_t sk, int value)
{ /* skillmod */
if (sk == SK_WEAPONSMITH || sk == SK_ARMORER) {
if (u->region == r)
return value + 1;
}
return value;
}
static int mm_smithy(const unit * u, const resource_type * rtype, int value)
{ /* material-mod */
if (rtype == get_resourcetype(R_IRON))
return value * 2;
return value;
}
static void init_smithy(struct building_type *bt)
{
a_add(&bt->attribs, make_skillmod(NOSKILL, SMF_PRODUCTION, sm_smithy, 1.0,
0));
a_add(&bt->attribs, make_matmod(mm_smithy));
}
static const char *castle_name_i(const struct building_type *btype, static const char *castle_name_i(const struct building_type *btype,
const struct building *b, int bsize, const char *fname[]) const struct building *b, int bsize, const char *fname[])
{ {
@ -915,7 +886,6 @@ int cmp_current_owner(const building * b, const building * a)
void register_buildings(void) void register_buildings(void)
{ {
register_function((pf_generic)init_smithy, "init_smithy");
register_function((pf_generic)castle_name, "castle_name"); register_function((pf_generic)castle_name, "castle_name");
register_function((pf_generic)castle_name_2, "castle_name_2"); register_function((pf_generic)castle_name_2, "castle_name_2");
register_function((pf_generic)fort_name, "fort_name"); register_function((pf_generic)fort_name, "fort_name");

View File

@ -66,10 +66,10 @@ extern "C" {
double auraregen; /* modifier for aura regeneration inside building */ double auraregen; /* modifier for aura regeneration inside building */
struct maintenance *maintenance; /* array of requirements */ struct maintenance *maintenance; /* array of requirements */
struct construction *construction; /* construction of 1 building-level */ struct construction *construction; /* construction of 1 building-level */
struct resource_mod *modifiers; /* modify production skills */
const char *(*name) (const struct building_type *, const char *(*name) (const struct building_type *,
const struct building * b, int size); const struct building * b, int size);
void(*init) (struct building_type *);
void(*age) (struct building *); void(*age) (struct building *);
double(*taxes) (const struct building *, int size); double(*taxes) (const struct building *, int size);
struct attrib *attribs; struct attrib *attribs;

View File

@ -296,7 +296,6 @@ static void test_btype_defaults(CuTest *tc) {
CuAssertPtrEquals(tc, 0, btype->maintenance); CuAssertPtrEquals(tc, 0, btype->maintenance);
CuAssertPtrEquals(tc, 0, btype->construction); CuAssertPtrEquals(tc, 0, btype->construction);
CuAssertTrue(tc, !btype->name); CuAssertTrue(tc, !btype->name);
CuAssertTrue(tc, !btype->init);
CuAssertTrue(tc, !btype->age); CuAssertTrue(tc, !btype->age);
CuAssertTrue(tc, !btype->taxes); CuAssertTrue(tc, !btype->taxes);
CuAssertDblEquals(tc, 1.0, btype->auraregen, 0.0); CuAssertDblEquals(tc, 1.0, btype->auraregen, 0.0);

View File

@ -90,11 +90,6 @@ extern "C" {
const resource_type *findresourcetype(const char *name, const resource_type *findresourcetype(const char *name,
const struct locale *lang); const struct locale *lang);
/* resource-limits for regions */
#define RMF_SKILL 0x01 /* int, bonus on resource production skill */
#define RMF_SAVEMATERIAL 0x02 /* fraction (sa[0]/sa[1]), multiplier on resource usage */
#define RMF_REQUIREDBUILDING 0x04 /* building, required to build */
/* bitfield values for item_type::flags */ /* bitfield values for item_type::flags */
#define ITF_NONE 0x0000 #define ITF_NONE 0x0000
#define ITF_HERB 0x0001 /* this item is a herb */ #define ITF_HERB 0x0001 /* this item is a herb */

View File

@ -34,8 +34,17 @@ extern "C" {
struct rawmaterial *next; struct rawmaterial *next;
} rawmaterial; } rawmaterial;
/* resource-limits for regions */
typedef enum resource_modifier_type {
RMT_END, /* array terminator */
RMT_PROD_SKILL, /* bonus on resource production skill */
RMT_PROD_SAVE, /* fractional multiplier when produced */
RMT_PROD_REQUIRE, /* building or race is required to produce this item */
RMT_USE_SAVE, /* fractional multiplier when used to manufacture something */
} resource_modifier_type;
typedef struct resource_mod { typedef struct resource_mod {
int flags; resource_modifier_type type;
variant value; variant value;
const struct building_type *btype; const struct building_type *btype;
const struct race *race; const struct race *race;

View File

@ -120,6 +120,72 @@ static xmlChar *xml_cleanup_string(xmlChar * str)
return str; return str;
} }
static resource_mod * xml_readmodifiers(xmlXPathObjectPtr result, xmlNodePtr node) {
/* reading eressea/resources/resource/modifier */
if (result->nodesetval != NULL && result->nodesetval->nodeNr > 0) {
int k;
resource_mod * modifiers =
calloc(result->nodesetval->nodeNr + 1, sizeof(resource_mod));
for (k = 0; k != result->nodesetval->nodeNr; ++k) {
xmlNodePtr node = result->nodesetval->nodeTab[k];
xmlChar *propValue;
building_type *btype = NULL;
const race *rc = NULL;
propValue = xmlGetProp(node, BAD_CAST "race");
if (propValue != NULL) {
rc = rc_find((const char *)propValue);
if (rc == NULL)
rc = rc_get_or_create((const char *)propValue);
xmlFree(propValue);
}
modifiers[k].race = rc;
propValue = xmlGetProp(node, BAD_CAST "building");
if (propValue != NULL) {
btype = bt_get_or_create((const char *)propValue);
xmlFree(propValue);
}
modifiers[k].btype = btype;
propValue = xmlGetProp(node, BAD_CAST "type");
assert(propValue != NULL);
if (strcmp((const char *)propValue, "skill") == 0) {
xmlChar *propSkill;
skill_t sk = NOSKILL;
modifiers[k].type = RMT_PROD_SKILL;
propSkill = xmlGetProp(node, BAD_CAST "skill");
if (propSkill) {
sk = findskill((const char *)propSkill);
xmlFree(propSkill);
}
modifiers[k].value.sa[0] = (short)sk;
modifiers[k].value.sa[1] = (short)xml_ivalue(node, "value", 0);
}
else if (strcmp((const char *)propValue, "material") == 0) {
modifiers[k].value = xml_fraction(node, "value");
modifiers[k].type = RMT_PROD_SAVE;
}
else {
if (strcmp((const char *)propValue, "require") == 0) {
modifiers[k].type = RMT_PROD_REQUIRE;
}
else if (strcmp((const char *)propValue, "save") == 0) {
modifiers[k].type = RMT_USE_SAVE;
modifiers[k].value = xml_fraction(node, "value");
}
else {
log_error("unknown type '%s' for resourcelimit-modifier", (const char *)propValue);
}
}
xmlFree(propValue);
}
return modifiers;
}
return NULL;
}
static void static void
xml_readrequirements(xmlNodePtr * nodeTab, int nodeNr, requirement ** reqArray) xml_readrequirements(xmlNodePtr * nodeTab, int nodeNr, requirement ** reqArray)
{ {
@ -157,7 +223,6 @@ construction ** consPtr)
xmlChar *propValue; xmlChar *propValue;
construction *con; construction *con;
xmlXPathObjectPtr req; xmlXPathObjectPtr req;
int m;
skill_t sk = NOSKILL; skill_t sk = NOSKILL;
propValue = xmlGetProp(node, BAD_CAST "skill"); propValue = xmlGetProp(node, BAD_CAST "skill");
@ -193,23 +258,6 @@ construction ** consPtr)
xml_readrequirements(req->nodesetval->nodeTab, xml_readrequirements(req->nodesetval->nodeTab,
req->nodesetval->nodeNr, &con->materials); req->nodesetval->nodeNr, &con->materials);
xmlXPathFreeObject(req); xmlXPathFreeObject(req);
/* read construction/modifier */
xpath->node = node;
req = xmlXPathEvalExpression(BAD_CAST "modifier", xpath);
for (m = 0; m != req->nodesetval->nodeNr; ++m) {
xmlNodePtr node = req->nodesetval->nodeTab[m];
propValue = xmlGetProp(node, BAD_CAST "function");
if (propValue != NULL) {
pf_generic foo = get_function((const char *)propValue);
a_add(&con->attribs, make_skillmod(NOSKILL, SMF_PRODUCTION,
(skillmod_fun)foo, 1.0, 0));
xmlFree(propValue);
}
}
xmlXPathFreeObject(req);
} }
xpath->node = pushNode; xpath->node = pushNode;
} }
@ -280,6 +328,12 @@ static int parse_buildings(xmlDocPtr doc)
if (xml_bvalue(node, "fort", false)) if (xml_bvalue(node, "fort", false))
btype->flags |= BTF_FORTIFICATION; btype->flags |= BTF_FORTIFICATION;
/* reading eressea/buildings/building/modifier */
xpath->node = node;
result = xmlXPathEvalExpression(BAD_CAST "modifier", xpath);
btype->modifiers = xml_readmodifiers(result, node);
xmlXPathFreeObject(result);
/* reading eressea/buildings/building/construction */ /* reading eressea/buildings/building/construction */
xpath->node = node; xpath->node = node;
result = xmlXPathEvalExpression(BAD_CAST "construction", xpath); result = xmlXPathEvalExpression(BAD_CAST "construction", xpath);
@ -305,9 +359,6 @@ static int parse_buildings(xmlDocPtr doc)
(const char *(*)(const struct building_type *, (const char *(*)(const struct building_type *,
const struct building *, int))fun; const struct building *, int))fun;
} }
else if (strcmp((const char *)propValue, "init") == 0) {
btype->init = (void(*)(struct building_type *))fun;
}
else if (strcmp((const char *)propValue, "age") == 0) { else if (strcmp((const char *)propValue, "age") == 0) {
btype->age = (void(*)(struct building *))fun; btype->age = (void(*)(struct building *))fun;
} }
@ -344,10 +395,6 @@ static int parse_buildings(xmlDocPtr doc)
mt->flags |= MTF_VARIABLE; mt->flags |= MTF_VARIABLE;
} }
xmlXPathFreeObject(result); xmlXPathFreeObject(result);
/* finally, initialize the new building type */
if (btype->init)
btype->init(btype);
} }
} }
xmlXPathFreeObject(buildings); xmlXPathFreeObject(buildings);
@ -951,58 +998,9 @@ static int parse_resources(xmlDocPtr doc)
if (xml_bvalue(node, "limited", false)) { if (xml_bvalue(node, "limited", false)) {
rtype->flags |= RTF_LIMITED; rtype->flags |= RTF_LIMITED;
} }
/* reading eressea/resources/resource/modifier */
xpath->node = node; xpath->node = node;
result = xmlXPathEvalExpression(BAD_CAST "modifier", xpath); result = xmlXPathEvalExpression(BAD_CAST "modifier", xpath);
if (result->nodesetval != NULL && result->nodesetval->nodeNr > 0) { rtype->modifiers = xml_readmodifiers(result, node);
rtype->modifiers =
calloc(result->nodesetval->nodeNr + 1, sizeof(resource_mod));
for (k = 0; k != result->nodesetval->nodeNr; ++k) {
xmlNodePtr node = result->nodesetval->nodeTab[k];
building_type *btype = NULL;
const race *rc = NULL;
propValue = xmlGetProp(node, BAD_CAST "race");
if (propValue != NULL) {
rc = rc_find((const char *)propValue);
if (rc == NULL)
rc = rc_get_or_create((const char *)propValue);
xmlFree(propValue);
}
rtype->modifiers[k].race = rc;
propValue = xmlGetProp(node, BAD_CAST "building");
if (propValue != NULL) {
btype = bt_get_or_create((const char *)propValue);
xmlFree(propValue);
}
rtype->modifiers[k].btype = btype;
propValue = xmlGetProp(node, BAD_CAST "type");
assert(propValue != NULL);
if (strcmp((const char *)propValue, "skill") == 0) {
rtype->modifiers[k].value.i = xml_ivalue(node, "value", 0);
rtype->modifiers[k].flags = RMF_SKILL;
}
else if (strcmp((const char *)propValue, "material") == 0) {
rtype->modifiers[k].value = xml_fraction(node, "value");
rtype->modifiers[k].flags = RMF_SAVEMATERIAL;
}
else if (strcmp((const char *)propValue, "require") == 0) {
xmlChar *propBldg = xmlGetProp(node, BAD_CAST "building");
if (propBldg != NULL) {
btype = bt_get_or_create((const char *)propBldg);
rtype->modifiers[k].btype = btype;
rtype->modifiers[k].flags = RMF_REQUIREDBUILDING;
xmlFree(propBldg);
}
}
else {
log_error("unknown type '%s' for resourcelimit-modifier '%s'\n", (const char *)propValue, rtype->_name);
}
xmlFree(propValue);
}
}
xmlXPathFreeObject(result); xmlXPathFreeObject(result);
/* reading eressea/resources/resource/resourcelimit/function */ /* reading eressea/resources/resource/resourcelimit/function */
xpath->node = node; xpath->node = node;