Merge pull request #663 from ennorehling/develop

ongoing refactoring towards the noxml branch
This commit is contained in:
Enno Rehling 2017-02-25 21:46:06 +01:00 committed by GitHub
commit 2137c51509
73 changed files with 642 additions and 907 deletions

3
.gitignore vendored
View file

@ -39,3 +39,6 @@ tmp/
tests/config.lua
tests/reports/
tests/data/185.dat
/quicklist/
/cutest/
/critbit/

View file

@ -1,13 +1,12 @@
<?xml version="1.0" encoding="utf-8" ?>
<resources>
<resource name="adamantium" limited="yes" material="rm_adamantium">
<resource name="adamantium" limited="yes" material="yes">
<item weight="200" score="200">
<construction skill="mining" minskill="8"/>
</item>
<resourcelimit>
<modifier type="require" building="mine"/>
<guard flag="mining"/>
</resourcelimit>
</resource>

View file

@ -1,24 +1,23 @@
<?xml version="1.0"?>
<building name="castle" capacity="1" fort="yes">
<function name="name" value="castle_name_2"/>
<function name="protection" value="building_protection"/>
<function name="taxes" value="lua_building_taxes"/>
<construction skill="building" minskill="1" maxsize="10" defense_bonus="0">
<construction skill="building" minskill="1" maxsize="10">
<requirement type="stone" quantity="1"/>
</construction>
<construction skill="building" minskill="2" maxsize="40" defense_bonus="1">
<construction skill="building" minskill="2" maxsize="40">
<requirement type="stone" quantity="1"/>
</construction>
<construction skill="building" minskill="3" maxsize="200" defense_bonus="3">
<construction skill="building" minskill="3" maxsize="200">
<requirement type="stone" quantity="1"/>
</construction>
<construction skill="building" minskill="4" maxsize="1000" defense_bonus="5">
<construction skill="building" minskill="4" maxsize="1000">
<requirement type="stone" quantity="1"/>
</construction>
<construction skill="building" minskill="5" maxsize="5000" defense_bonus="8">
<construction skill="building" minskill="5" maxsize="5000">
<requirement type="stone" quantity="1"/>
</construction>
<construction skill="building" minskill="6" defense_bonus="12">
<construction skill="building" minskill="6">
<requirement type="stone" quantity="1"/>
</construction>
</building>

View file

@ -1,26 +1,25 @@
<?xml version="1.0"?>
<building name="castle" capacity="1" fort="yes">
<function name="name" value="castle_name"/>
<function name="protection" value="building_protection"/>
<construction skill="building" minskill="1" maxsize="2" defense_bonus="0">
<construction skill="building" minskill="1" maxsize="2">
<requirement type="stone" quantity="1"/>
</construction>
<construction skill="building" minskill="1" maxsize="8" defense_bonus="0">
<construction skill="building" minskill="1" maxsize="8">
<requirement type="stone" quantity="1"/>
</construction>
<construction skill="building" minskill="2" maxsize="40" defense_bonus="1">
<construction skill="building" minskill="2" maxsize="40">
<requirement type="stone" quantity="1"/>
</construction>
<construction skill="building" minskill="3" maxsize="200" defense_bonus="3">
<construction skill="building" minskill="3" maxsize="200">
<requirement type="stone" quantity="1"/>
</construction>
<construction skill="building" minskill="4" maxsize="1000" defense_bonus="5">
<construction skill="building" minskill="4" maxsize="1000">
<requirement type="stone" quantity="1"/>
</construction>
<construction skill="building" minskill="5" maxsize="5000" defense_bonus="8">
<construction skill="building" minskill="5" maxsize="5000">
<requirement type="stone" quantity="1"/>
</construction>
<construction skill="building" minskill="6" defense_bonus="12">
<construction skill="building" minskill="6">
<requirement type="stone" quantity="1"/>
</construction>
</building>

View file

@ -4,9 +4,7 @@
<building name="illusioncastle" capacity="0" maxcapacity="0" maxsize="0" nobuild="yes"/>
<building name="xmas_exit" maxsize="10" maxcapacity="2" nobuild="yes" nodestroy="yes" unique="yes"/>
<building name="caldera" capacity="1" nodestroy="yes" nobuild="yes"/>
<building name="genericbuilding" namechange="no" maxsize="1" nobuild="yes"/>
<building name="artacademy" maxsize="100" nobuild="yes" nodestroy="yes" unique="yes"/>
<building name="artsculpture" namechange="no" maxsize="100" nobuild="yes" nodestroy="yes" unique="yes"/>
<building name="building" namechange="no" maxsize="1" nobuild="yes"/>
<building name="blessedstonecircle" maxcapacity="3" maxsize="100" nobuild="yes" magic="yes" magres="60" magresbonus="30" auraregen="1.50">
<construction skill="building" minskill="2" reqsize="100" maxsize="100">

View file

@ -912,17 +912,9 @@
<string name="illusioncastle">
<text locale="de">Traumschlößchen</text>
</string>
<string name="genericbuilding">
<string name="building">
<text locale="de">Struktur</text>
</string>
<string name="artacademy">
<text locale="de">Akademie der Künste</text>
<text locale="en">academy of arts</text>
</string>
<string name="artsculpture">
<text locale="de">Skulptur</text>
<text locale="en">sculpture</text>
</string>
<!--Testitem -->
<string name="wand">
@ -6619,53 +6611,17 @@
<text locale="de">EINLADEN</text>
<text locale="en">INVITE</text>
</string>
<string name="rm_stone">
<text locale="de">Steine</text>
<text locale="en">stones</text>
</string>
<string name="rm_horse">
<text locale="de">Pferde</text>
<text locale="en">horses</text>
</string>
<string name="rm_peasant">
<text locale="de">Bauern</text>
<text locale="en">peasants</text>
</string>
<string name="rm_money">
<text locale="de">Silber</text>
<text locale="en">silver</text>
</string>
<string name="rm_laen">
<text locale="de">Laen</text>
<text locale="en">laen</text>
</string>
<string name="rm_sapling">
<string name="sapling">
<text locale="de">Schößlinge</text>
<text locale="en">saplings</text>
</string>
<string name="rm_mallornsapling">
<string name="mallornsapling">
<text locale="de">Mallornschößlinge</text>
<text locale="en">mallorn saplings</text>
</string>
<string name="rm_tree">
<text locale="de">Bäume</text>
<text locale="en">trees</text>
</string>
<string name="rm_mallorn">
<text locale="de">Mallorn</text>
<text locale="en">mallorn</text>
</string>
<string name="rm_iron">
<text locale="de">Eisen</text>
<text locale="en">iron</text>
</string>
<string name="Winter">
<text locale="de">Winter</text>
<text locale="en">winter</text>

View file

@ -310,7 +310,7 @@
<string name="dam">
<text locale="en">dam</text>
</string>
<string name="genericbuilding">
<string name="building">
<text locale="en">structure</text>
</string>
<string name="harbour">

View file

@ -324,7 +324,7 @@
<string name="dam">
<text locale="fr">barrage</text>
</string>
<string name="genericbuilding">
<string name="building">
<text locale="fr">bâtiment</text>
</string>
<string name="harbour">

View file

@ -1,5 +1,5 @@
<?xml version="1.0"?>
<resource name="horse" limited="yes" material="rm_horse">
<resource name="horse" limited="yes">
<item big="yes" weight="5000" score="10" capacity="7000" animal="yes">
<construction skill="training" minskill="1"/>
<function name="give" value="givehorses"/>

View file

@ -1,5 +1,5 @@
<?xml version="1.0"?>
<resource name="iron" limited="yes" material="rm_iron">
<resource name="iron" limited="yes" material="yes">
<item weight="500" score="10">
<construction skill="mining" minskill="1"/>
</item>

View file

@ -1,5 +1,5 @@
<?xml version="1.0"?>
<resource name="laen" limited="yes" material="rm_laen">
<resource name="laen" limited="yes" material="yes">
<item weight="200" score="100">
<construction skill="mining" minskill="7"/>
</item>

View file

@ -1,5 +1,5 @@
<?xml version="1.0"?>
<resource name="log" material="rm_tree">
<resource name="log">
<item weight="500" score="10">
<construction skill="forestry" minskill="1"/>
</item>

View file

@ -1,12 +1,11 @@
<?xml version="1.0"?>
<resource name="mallorn" material="rm_mallorn">
<resource name="mallorn">
<item weight="500" score="30">
<construction skill="forestry" minskill="2"/>
</item>
<resourcelimit>
<modifier building="sawmill" type="skill" value="1"/>
<modifier building="sawmill" type="material" value="0.5"/>
<guard flag="logging"/>
<function name="produce" value="lua_produceresource"/>
<function name="limit" value="lua_limitresource"/>
</resourcelimit>

View file

@ -3,4 +3,8 @@
<item weight="10" score="100">
<construction skill="herbalism" minskill="4"/>
</item>
<resourcelimit>
<function name="produce" value="lua_produceresource"/>
<function name="limit" value="lua_limitresource"/>
</resourcelimit>
</resource>

View file

@ -3,4 +3,8 @@
<item weight="10" score="50">
<construction skill="herbalism" minskill="3"/>
</item>
<resourcelimit>
<function name="produce" value="lua_produceresource"/>
<function name="limit" value="lua_limitresource"/>
</resourcelimit>
</resource>

View file

@ -1,5 +1,5 @@
<?xml version="1.0"?>
<resource name="stone" limited="yes" material="rm_stone">
<resource name="stone" limited="yes" material="yes">
<item weight="6000" score="10" big="yes">
<construction skill="quarrying" minskill="1"/>
</item>

View file

@ -5,15 +5,14 @@
<building name="watch" maxsize="10" capacity="1" fort="yes">
<function name="name" value="fort_name"/>
<function name="protection" value="building_protection"/>
<function name="taxes" value="lua_building_taxes"/>
<construction skill="building" minskill="1" maxsize="5" defense_bonus="0">
<construction skill="building" minskill="1" maxsize="5">
<requirement type="log" quantity="1"/>
</construction>
<construction skill="building" minskill="2" maxsize="5" defense_bonus="1">
<construction skill="building" minskill="2" maxsize="5">
<requirement type="log" quantity="1"/>
</construction>
<construction skill="building" minskill="2" defense_bonus="2">
<construction skill="building" minskill="2">
<requirement type="log" quantity="1"/>
</construction>
</building>

View file

@ -1,11 +1,10 @@
<?xml version="1.0"?>
<resource name="iron" limited="yes" material="rm_iron">
<resource name="iron" limited="yes" material="yes">
<item weight="500" score="10">
<construction skill="mining" minskill="1"/>
</item>
<resourcelimit>
<modifier building="mine" type="skill" value="1"/>
<modifier building="mine" type="material" value="0.5"/>
<guard flag="mining"/>
</resourcelimit>
</resource>

View file

@ -1,4 +1,4 @@
<?xml version="1.0"?>
<resource name="mallornseed" limited="yes">
<resource name="mallornseed">
<item weight="10" score="100"/>
</resource>

View file

@ -1,4 +1,4 @@
<?xml version="1.0"?>
<resource name="seed" limited="yes">
<resource name="seed">
<item weight="10" score="50"/>
</resource>

View file

@ -1,5 +1,5 @@
<?xml version="1.0"?>
<resource name="stone" limited="yes" material="rm_stone">
<resource name="stone" limited="yes" material="yes">
<item weight="6000" score="10" big="yes">
<construction skill="quarrying" minskill="1"/>
</item>

View file

@ -1,20 +1,6 @@
<?xml version="1.0"?>
<resources>
<resource name="instantartsculpture">
<function name="change" value="changeitem"/>
<item weight="0">
<function name="use" value="use_instantartsculpture"/>
</item>
</resource>
<resource name="instantartacademy">
<function name="change" value="changeitem"/>
<item weight="0">
<function name="use" value="use_instantartacademy"/>
</item>
</resource>
<resource name="aurapotion50">
<function name="change" value="changeitem"/>
<item weight="0">

View file

@ -4,4 +4,5 @@
<building name="temple" maxsize="50" maxcapacity="2" nobuild="yes" nodestroy="yes" unique="yes" auraregen="1.00" />
<building name="portal" maxsize="2" capacity="1" maxcapacity="2" nobuild="yes" nodestroy="yes" unique="yes" />
<building name="pavilion" maxsize="2" capacity="1" maxcapacity="2" nobuild="yes" nodestroy="yes" unique="yes" />
<building name="artacademy" maxsize="100" nobuild="yes" nodestroy="yes" unique="yes"/>
</buildings>

View file

@ -63,19 +63,6 @@
</item>
</resource>
<!-- art rewards -->
<resource name="trappedairelemental">
<item weight="0">
<function name="use" value="use_trappedairelemental"/>
</item>
</resource>
<resource name="hornofdancing">
<item weight="0">
<function name="use" value="use_hornofdancing"/>
</item>
</resource>
<!-- museum items -->
<resource name="questkey1" appearance="key">
<!-- Key for an old quest. placeholder item -->

View file

@ -352,37 +352,9 @@
<!-- ending here: Wildente and Jadee's wedding -->
<!-- art rewards begin -->
<string name="hornofdancing">
<text locale="de">Horn des Tanzes</text>
<text locale="en">horn of dancing</text>
</string>
<string name="hornofdancing_p">
<text locale="de">Hörner des Tanzes</text>
<text locale="en">horns of dancing</text>
</string>
<string name="instantartacademy">
<text locale="de">Miniatur einer Akademie der Künste</text>
<text locale="en">academy of arts in a box</text>
</string>
<string name="instantartacademy_p">
<text locale="de">Miniaturen einer Akademie der Künste</text>
<text locale="en">academies of arts in a box</text>
</string>
<string name="instantartsculpture">
<text locale="de">Miniatur einer Skulptur</text>
<text locale="en">art sculpture in a box</text>
</string>
<string name="instantartsculpture_p">
<text locale="de">Miniaturen einer Skulptur</text>
<text locale="en">art sculptures in a box</text>
</string>
<string name="trappedairelemental">
<text locale="de">Gefangener Windgeist</text>
<text locale="en">trapped air elemental</text>
</string>
<string name="trappedairelemental_p">
<text locale="de">Gefangene Windgeister</text>
<text locale="en">trapped air elementals</text>
<string name="artacademy">
<text locale="de">Akademie der Künste</text>
<text locale="en">academy of arts</text>
</string>
<string name="aurapotion50">
<text locale="de">Auratrank</text>

View file

@ -1,3 +0,0 @@
<?xml version="1.0" ?>
<items>
</items>

View file

@ -38,6 +38,45 @@ function hp_changeresource(u, delta)
return hp
end
local function mallorn_region(r)
return r:get_flag(1) -- RF_MALLORN
end
function seed_limit(r)
if mallorn_region(r) then
return 0
end
return r:get_resource("seed")
end
function seed_produce(r, n)
if not mallorn_region(r) then
local seeds = r:get_resource("seed")
if seeds>=n then
r:set_resource("seed", seeds-n)
else
r:set_resource("seed", 0)
end
end
end
function mallornseed_limit(r)
if mallorn_region(r) then
return r:get_resource("seed")
end
return 0
end
function mallornseed_produce(r, n)
if mallorn_region(r) then
local seeds = r:get_resource("seed")
if seeds>=n then
r:set_resource("seed", seeds-n)
else
r:set_resource("seed", 0)
end
end
end
function horse_limit(r)
return r:get_resource("horse")
end
@ -52,9 +91,6 @@ function horse_produce(r, n)
end
function log_limit(r)
-- if r:get_flag(1) then -- RF_MALLORN
-- return 0
-- end
return r:get_resource("tree") + r:get_resource("sapling")
end
@ -75,7 +111,7 @@ function log_produce(r, n)
end
function mallorn_limit(r)
if not r:get_flag(1) then -- RF_MALLORN
if not mallorn_region(r) then
return 0
end
return r:get_resource("tree") + r:get_resource("sapling")

View file

@ -438,10 +438,9 @@ function test_recruit()
u:add_item("money", 110*n+20)
u:add_order("REKRUTIERE " .. n)
process_orders()
assert(u.number == n+1)
assert_equal(n+1, u.number)
local p = r:get_resource("peasant")
assert(p<200 and p>=200-n)
-- assert(u:get_item("money")==10)
assert_true(p<200 and p>=200-n)
end
function test_produce()
@ -468,7 +467,7 @@ function test_work()
u:clear_orders()
u:add_order("ARBEITEN")
process_orders()
assert(u:get_item("money")>=10)
assert_equal(20, u:get_item("money"))
end
function test_upkeep()
@ -480,7 +479,7 @@ function test_upkeep()
u:clear_orders()
u:add_order("LERNE Waffenbau")
process_orders()
assert(u:get_item("money")==u.number)
assert_equal(u:get_item("money"), u.number)
end
function test_id()
@ -488,50 +487,39 @@ function test_id()
local f = faction.create("noreply11@eressea.de", "human", "de")
f.id = atoi36("42")
assert(get_faction(42)~=f)
assert(get_faction("42")==f)
assert(get_faction(atoi36("42"))==f)
assert_not_equal(f, get_faction(42))
assert_equal(f, get_faction("42"))
assert_equal(f, get_faction(atoi36("42")))
local u = unit.create(f, r, 1)
u.id = atoi36("42")
assert(get_unit(42)~=u)
assert(get_unit("42")==u)
assert(get_unit(atoi36("42"))==u)
assert_not_equal(get_unit(42), u)
assert_equal(get_unit("42"), u)
assert_equal(get_unit(atoi36("42")), u)
local b = building.create(r, "castle")
-- <not working> b.id = atoi36("42")
local fortytwo = itoa36(b.id)
assert(get_building(fortytwo)==b)
assert(get_building(atoi36(fortytwo))==b)
assert_equal(get_building(fortytwo), b)
assert_equal(get_building(atoi36(fortytwo)), b)
local s = _test_create_ship(r)
assert_not_nil(s)
-- <not working> s.id = atoi36("42")
local fortytwo = itoa36(s.id)
assert(get_ship(fortytwo)==s)
assert(get_ship(atoi36(fortytwo))==s)
end
function test_herbalism()
local r = region.create(0, 0, "plain")
local f = faction.create("noreply12@eressea.de", "human", "de")
local u = unit.create(f, r, 1)
u:add_item("money", u.number * 100)
u:set_skill("herbalism", 5)
u:clear_orders()
u:add_order("MACHE Samen")
process_orders()
assert_equal(get_ship(fortytwo), s)
assert_equal(get_ship(atoi36(fortytwo)), s)
end
function test_mallorn()
local r = region.create(0, 0, "plain")
r:set_flag(1, false) -- not mallorn
r:set_resource("tree", 100)
assert(r:get_resource("tree")==100)
assert_equal(100, r:get_resource("tree"))
local m = region.create(0, 0, "plain")
m:set_flag(1, true) -- mallorn
m:set_resource("tree", 100)
assert(m:get_resource("tree")==100)
assert_equal(100, m:get_resource("tree"))
local f = faction.create("noreply13@eressea.de", "human", "de")

View file

@ -2,6 +2,38 @@ require "lunit"
module("tests.e2.e2features", package.seeall, lunit.testcase )
function setup()
eressea.free_game()
eressea.settings.set("nmr.timeout", "0")
eressea.settings.set("rules.food.flags", "4")
eressea.settings.set("rules.ship.storms", "0")
eressea.settings.set("rules.encounters", "0")
end
function test_herbalism()
-- OBS: herbalism is currently an E2-only skill
local r = region.create(0, 0, "plain")
local f = faction.create("herbalism@eressea.de", "human", "de")
local u = unit.create(f, r, 1)
eressea.settings.set("rules.grow.formula", 0) -- plants do not grow
u:add_item("money", u.number * 100)
u:set_skill("herbalism", 5)
r:set_resource("seed", 100)
r:set_flag(1, false) -- regular trees
u:clear_orders()
u:add_order("MACHE Samen")
process_orders()
assert_equal(1, u:get_item("seed"))
assert_equal(99, r:get_resource("seed"))
r:set_flag(1, true) -- mallorn
u:clear_orders()
u:add_order("MACHE Mallornsamen")
process_orders()
assert_equal(1, u:get_item("mallornseed"))
assert_equal(98, r:get_resource("seed"))
end
function test_build_harbour()
-- try to reproduce mantis bug 2221
local r = region.create(0, 0, "plain")
@ -42,13 +74,6 @@ local function two_units(r, f1, f2)
return one_unit(r, f1), one_unit(r, f2)
end
function setup()
eressea.free_game()
eressea.settings.set("nmr.timeout", "0")
eressea.settings.set("rules.food.flags", "4")
eressea.settings.set("rules.ship.storms", "0")
end
function test_learn()
eressea.settings.set("study.random_progress", "0")
local r = region.create(0, 0, "plain")

View file

@ -1059,7 +1059,7 @@ static int rc_specialdamage(const unit *au, const unit *du, const struct weapon_
return modifier;
}
int calculate_armor(troop dt, const weapon_type *dwtype, const weapon_type *awtype, double *magres) {
int calculate_armor(troop dt, const weapon_type *dwtype, const weapon_type *awtype, variant *magres) {
fighter *df = dt.fighter;
unit *du = df->unit;
int ar = 0, an, am;
@ -1110,21 +1110,31 @@ int calculate_armor(troop dt, const weapon_type *dwtype, const weapon_type *awty
if (magres) {
/* calculate damage multiplier for magical damage */
double res = 1.0 - magic_resistance(du);
variant res;
res = frac_sub(frac_one, magic_resistance(du));
if (u_race(du)->battle_flags & BF_EQUIPMENT) {
/* der Effekt von Laen steigt nicht linear */
if (armor && fval(armor, ATF_LAEN))
res *= (1 - armor->magres);
if (shield && fval(shield, ATF_LAEN))
res *= (1 - shield->magres);
if (dwtype)
res *= (1 - dwtype->magres);
if (armor && fval(armor, ATF_LAEN)) {
res = frac_mul(res, frac_sub(frac_one, armor->magres));
}
if (shield && fval(shield, ATF_LAEN)) {
res = frac_mul(res, frac_sub(frac_one, shield->magres));
}
if (dwtype) {
res = frac_mul(res, frac_sub(frac_one, dwtype->magres));
}
}
/* gegen Magie wirkt nur nat<61>rliche und magische R<>stung */
/* gegen Magie wirkt nur natuerliche und magische Ruestung */
ar = an + am;
*magres = res > 0 ? res : 0;
if (res.sa[0] >= 0) {
*magres = res;
}
else {
*magres = frac_make(0, 1);
}
}
return ar;
@ -1147,7 +1157,7 @@ terminate(troop dt, troop at, int type, const char *damage, bool missile)
const weapon_type *dwtype = NULL;
const weapon_type *awtype = NULL;
const weapon *weapon;
double res = 1.0;
variant res = frac_make(1, 1);
int rda, sk = 0, sd;
bool magic = false;
@ -1190,9 +1200,9 @@ terminate(troop dt, troop at, int type, const char *damage, bool missile)
return false;
}
/* TODO not sure if res could be > 1 here */
if (magic) {
da = (int)(MAX(da * res, 0));
res = frac_mul(frac_make(da, 1), res);
da = res.sa[0] / res.sa[1];
}
if (type != AT_COMBATSPELL && type != AT_SPELL) {
@ -1892,10 +1902,11 @@ int skilldiff(troop at, troop dt, int dist)
}
if (df->building) {
if (df->building->attribs) {
building *b = df->building;
if (b->attribs) {
const curse_type *strongwall_ct = ct_find("strongwall");
if (strongwall_ct) {
curse *c = get_curse(df->building->attribs, strongwall_ct);
curse *c = get_curse(b->attribs, strongwall_ct);
if (curse_active(c)) {
/* wirkt auf alle Geb<65>ude */
skdiff -= curse_geteffect_int(c);
@ -1903,15 +1914,16 @@ int skilldiff(troop at, troop dt, int dist)
}
}
}
if (df->building->type->protection) {
int beff = df->building->type->protection(df->building, du, DEFENSE_BONUS);
if (beff) {
if (b->type->flags & BTF_FORTIFICATION) {
int stage = buildingeffsize(b, false);
int beff = building_protection(b->type, stage);
if (beff > 0) {
skdiff -= beff;
is_protected = 2;
if (df->building->attribs) {
if (b->attribs) {
const curse_type *magicwalls_ct = ct_find("magicwalls");
if (magicwalls_ct
&& curse_active(get_curse(df->building->attribs, magicwalls_ct))) {
&& curse_active(get_curse(b->attribs, magicwalls_ct))) {
/* Verdoppelt Burgenbonus */
skdiff -= beff;
}
@ -2022,7 +2034,7 @@ void damage_building(battle * b, building * bldg, int damage_abs)
/* Wenn Burg, dann gucken, ob die Leute alle noch in das Geb<65>ude passen. */
if (bldg->type->protection) {
if (bldg->type->flags & BTF_FORTIFICATION) {
side *s;
bldg->sizeleft = bldg->size;

View file

@ -248,7 +248,7 @@ extern "C" {
int count_enemies(struct battle *b, const struct fighter *af,
int minrow, int maxrow, int select);
int natural_armor(struct unit * u);
int calculate_armor(troop dt, const struct weapon_type *dwtype, const struct weapon_type *awtype, double *magres);
int calculate_armor(troop dt, const struct weapon_type *dwtype, const struct weapon_type *awtype, union variant *magres);
bool terminate(troop dt, troop at, int type, const char *damage,
bool missile);
extern void message_all(battle * b, struct message *m);

View file

@ -26,7 +26,7 @@ static void test_make_fighter(CuTest * tc)
faction * f;
const resource_type *rtype;
test_cleanup();
test_setup();
test_create_horse();
r = test_create_region(0, 0, 0);
f = test_create_faction(NULL);
@ -60,8 +60,17 @@ static void test_make_fighter(CuTest * tc)
test_cleanup();
}
static int add_two(const building * b, const unit * u, building_bonus bonus) {
return 2;
static building_type * setup_castle(void) {
building_type * btype;
construction *cons;
btype = bt_get_or_create("castle");
btype->flags |= BTF_FORTIFICATION;
cons = btype->construction = calloc(1, sizeof(construction));
cons->maxsize = 5;
cons = cons->improvement = calloc(1, sizeof(construction));
cons->maxsize = -1;
return btype;
}
static void test_defenders_get_building_bonus(CuTest * tc)
@ -72,16 +81,13 @@ static void test_defenders_get_building_bonus(CuTest * tc)
fighter *df, *af;
battle *b;
side *ds, *as;
int diff;
troop dt, at;
building_type * btype;
test_cleanup();
test_setup();
btype = setup_castle();
r = test_create_region(0, 0, 0);
btype = bt_get_or_create("castle");
btype->protection = &add_two;
bld = test_create_building(r, btype);
bld->size = 10;
du = test_create_unit(test_create_faction(NULL), r);
au = test_create_unit(test_create_faction(NULL), r);
@ -101,11 +107,14 @@ static void test_defenders_get_building_bonus(CuTest * tc)
at.fighter = af;
at.index = 0;
diff = skilldiff(at, dt, 0);
CuAssertIntEquals(tc, -2, diff);
bld->size = 10; /* stage 1 building */
CuAssertIntEquals(tc, -1, skilldiff(at, dt, 0));
CuAssertIntEquals(tc, 0, skilldiff(dt, at, 0));
bld->size = 1; /* stage 0 building */
CuAssertIntEquals(tc, 0, skilldiff(at, dt, 0));
CuAssertIntEquals(tc, 0, skilldiff(dt, at, 0));
diff = skilldiff(dt, at, 0);
CuAssertIntEquals(tc, 0, diff);
free_battle(b);
test_cleanup();
}
@ -120,10 +129,10 @@ static void test_attackers_get_no_building_bonus(CuTest * tc)
side *as;
building_type * btype;
test_cleanup();
test_setup();
r = test_create_region(0, 0, 0);
btype = bt_get_or_create("castle");
btype->protection = &add_two;
btype = setup_castle();
btype->flags |= BTF_FORTIFICATION;
bld = test_create_building(r, btype);
bld->size = 10;
@ -150,10 +159,10 @@ static void test_building_bonus_respects_size(CuTest * tc)
building_type * btype;
faction * f;
test_cleanup();
test_setup();
btype = setup_castle();
r = test_create_region(0, 0, 0);
btype = bt_get_or_create("castle");
btype->protection = &add_two;
btype->flags |= BTF_FORTIFICATION;
bld = test_create_building(r, btype);
bld->size = 10;
@ -178,28 +187,25 @@ static void test_building_bonus_respects_size(CuTest * tc)
static void test_building_defence_bonus(CuTest * tc)
{
unit *au;
region *r;
building * bld;
building_type * btype;
faction * f;
int def;
test_cleanup();
r = test_create_region(0, 0, 0);
btype = test_create_buildingtype("castle");
btype->protection = (int(*)(const struct building *, const struct unit *, building_bonus))get_function("building_protection");
btype->construction->defense_bonus = 3;
bld = test_create_building(r, btype);
bld->size = 1;
test_setup();
btype = setup_castle();
f = test_create_faction(NULL);
au = test_create_unit(f, r);
scale_number(au, 1);
u_set_building(au, bld);
btype->maxsize = -1; /* unlimited buildigs get the castle bonus */
CuAssertIntEquals(tc, 0, building_protection(btype, 0));
CuAssertIntEquals(tc, 1, building_protection(btype, 1));
CuAssertIntEquals(tc, 3, building_protection(btype, 2));
CuAssertIntEquals(tc, 5, building_protection(btype, 3));
CuAssertIntEquals(tc, 8, building_protection(btype, 4));
CuAssertIntEquals(tc, 12, building_protection(btype, 5));
CuAssertIntEquals(tc, 12, building_protection(btype, 6));
def = btype->protection(bld, au, DEFENSE_BONUS);
CuAssertIntEquals(tc, 3, def);
btype->maxsize = 10; /* limited-size buildings are treated like an E3 watchtower */
CuAssertIntEquals(tc, 0, building_protection(btype, 0));
CuAssertIntEquals(tc, 1, building_protection(btype, 1));
CuAssertIntEquals(tc, 2, building_protection(btype, 2));
CuAssertIntEquals(tc, 2, building_protection(btype, 3));
test_cleanup();
}
@ -219,7 +225,7 @@ static void test_natural_armor(CuTest * tc)
race *rc;
unit *u;
test_cleanup();
test_setup();
rc = test_create_race("human");
u = test_create_unit(test_create_faction(rc), test_create_region(0, 0, 0));
set_level(u, SK_STAMINA, 2);
@ -244,23 +250,24 @@ static void test_calculate_armor(CuTest * tc)
armor_type *ashield, *achain;
item_type *ibelt, *ishield, *ichain;
race *rc;
double magres = 0.0;
variant magres = frac_zero;
variant v50p = frac_make(1, 2);
test_cleanup();
test_setup();
r = test_create_region(0, 0, 0);
ibelt = it_get_or_create(rt_get_or_create("trollbelt"));
ishield = it_get_or_create(rt_get_or_create("shield"));
ashield = new_armortype(ishield, 0.0, 0.5, 1, ATF_SHIELD);
ashield = new_armortype(ishield, 0.0, v50p, 1, ATF_SHIELD);
ichain = it_get_or_create(rt_get_or_create("chainmail"));
achain = new_armortype(ichain, 0.0, 0.5, 3, ATF_NONE);
wtype = new_weapontype(it_get_or_create(rt_get_or_create("sword")), 0, 0.5, 0, 0, 0, 0, SK_MELEE, 1);
achain = new_armortype(ichain, 0.0, v50p, 3, ATF_NONE);
wtype = new_weapontype(it_get_or_create(rt_get_or_create("sword")), 0, v50p, 0, 0, 0, 0, SK_MELEE, 1);
rc = test_create_race("human");
du = test_create_unit(test_create_faction(rc), r);
dt.index = 0;
dt.fighter = setup_fighter(&b, du);
CuAssertIntEquals_Msg(tc, "default ac", 0, calculate_armor(dt, 0, 0, &magres));
CuAssertDblEquals_Msg(tc, "magres unmodified", 1.0, magres, 0.01);
CuAssertIntEquals_Msg(tc, "magres unmodified", magres.sa[0], magres.sa[1]);
free_battle(b);
b = NULL;
@ -293,13 +300,13 @@ static void test_calculate_armor(CuTest * tc)
wtype->flags = WTF_NONE;
CuAssertIntEquals_Msg(tc, "magical attack", 3, calculate_armor(dt, 0, 0, &magres));
CuAssertDblEquals_Msg(tc, "magres unmodified", 1.0, magres, 0.01);
CuAssertIntEquals_Msg(tc, "magres unmodified", magres.sa[1], magres.sa[0]);
ashield->flags |= ATF_LAEN;
achain->flags |= ATF_LAEN;
magres = 1.0;
magres = frac_one;
CuAssertIntEquals_Msg(tc, "laen armor", 3, calculate_armor(dt, 0, 0, &magres));
CuAssertDblEquals_Msg(tc, "laen magres bonus", 0.25, magres, 0.01);
CuAssertIntEquals_Msg(tc, "laen magres bonus", 4, magres.sa[1]);
free_battle(b);
test_cleanup();
}
@ -313,38 +320,42 @@ static void test_magic_resistance(CuTest *tc)
armor_type *ashield, *achain;
item_type *ishield, *ichain;
race *rc;
double magres;
variant magres;
variant v50p = frac_make(1, 2);
variant v10p = frac_make(1, 10);
test_cleanup();
test_setup();
r = test_create_region(0, 0, 0);
ishield = it_get_or_create(rt_get_or_create("shield"));
ashield = new_armortype(ishield, 0.0, 0.5, 1, ATF_SHIELD);
ashield = new_armortype(ishield, 0.0, v50p, 1, ATF_SHIELD);
ichain = it_get_or_create(rt_get_or_create("chainmail"));
achain = new_armortype(ichain, 0.0, 0.5, 3, ATF_NONE);
achain = new_armortype(ichain, 0.0, v50p, 3, ATF_NONE);
rc = test_create_race("human");
du = test_create_unit(test_create_faction(rc), r);
dt.index = 0;
i_change(&du->items, ishield, 1);
dt.fighter = setup_fighter(&b, du);
calculate_armor(dt, 0, 0, &magres);
CuAssertDblEquals_Msg(tc, "no magres bonus", 0.0, magic_resistance(du), 0.01);
CuAssertDblEquals_Msg(tc, "no magres reduction", 1.0, magres, 0.01);
CuAssertIntEquals_Msg(tc, "no magres reduction", magres.sa[1], magres.sa[0]);
magres = magic_resistance(du);
CuAssertIntEquals_Msg(tc, "no magres reduction", 0, magres.sa[0]);
ashield->flags |= ATF_LAEN;
ashield->magres = 0.1;
ashield->magres = v10p;
calculate_armor(dt, 0, 0, &magres);
CuAssert(tc, "laen reduction => 10%%", frac_equal(frac_make(9, 10), magres));
free_battle(b);
b = NULL;
i_change(&du->items, ishield, 1);
i_change(&du->items, ichain, 1);
achain->flags |= ATF_LAEN;
achain->magres = 0.1;
achain->magres = v10p;
ashield->flags |= ATF_LAEN;
ashield->magres = 0.1;
ashield->magres = v10p;
dt.fighter = setup_fighter(&b, du);
calculate_armor(dt, 0, 0, &magres);
CuAssertDblEquals_Msg(tc, "laen reduction", 0.81, magres, 0.01);
CuAssert(tc, "2x laen reduction => 81%%", frac_equal(frac_make(81, 100), magres));
free_battle(b);
b = NULL;
@ -353,17 +364,20 @@ static void test_magic_resistance(CuTest *tc)
set_level(du, SK_MAGIC, 2);
dt.fighter = setup_fighter(&b, du);
calculate_armor(dt, 0, 0, &magres);
CuAssertDblEquals_Msg(tc, "skill bonus", 0.1, magic_resistance(du), 0.01);
CuAssertDblEquals_Msg(tc, "skill reduction", 0.9, magres, 0.01);
rc->magres = 50; /* percentage, gets added to skill bonus */
CuAssert(tc, "skill reduction => 90%%", frac_equal(magres, frac_make(9, 10)));
magres = magic_resistance(du);
CuAssert(tc, "skill reduction", frac_equal(magres, v10p));
rc->magres = v50p; /* percentage, gets added to skill bonus */
calculate_armor(dt, 0, 0, &magres);
CuAssertDblEquals_Msg(tc, "race bonus", 0.6, magic_resistance(du), 0.01);
CuAssertDblEquals_Msg(tc, "race reduction", 0.4, magres, 0.01);
CuAssert(tc, "race reduction => 40%%", frac_equal(magres, frac_make(4, 10)));
magres = magic_resistance(du);
CuAssert(tc, "race bonus => 60%%", frac_equal(magres, frac_make(60, 100)));
rc->magres = 150; /* should not cause negative damage multiplier */
CuAssertDblEquals_Msg(tc, "magic resistance is never > 0.9", 0.9, magic_resistance(du), 0.01);
rc->magres = frac_make(15, 10); /* 150% resistance should not cause negative damage multiplier */
magres = magic_resistance(du);
CuAssert(tc, "magic resistance is never > 0.9", frac_equal(magres, frac_make(9, 10)));
calculate_armor(dt, 0, 0, &magres);
CuAssertDblEquals_Msg(tc, "damage reduction is never < 0.1", 0.1, magres, 0.01);
CuAssert(tc, "damage reduction is never < 0.1", frac_equal(magres, frac_make(1, 10)));
free_battle(b);
test_cleanup();
@ -379,14 +393,15 @@ static void test_projectile_armor(CuTest * tc)
armor_type *ashield, *achain;
item_type *ishield, *ichain;
race *rc;
variant v50p = frac_make(1, 2);
test_cleanup();
test_setup();
r = test_create_region(0, 0, 0);
ishield = it_get_or_create(rt_get_or_create("shield"));
ashield = new_armortype(ishield, 0.0, 0.5, 1, ATF_SHIELD);
ashield = new_armortype(ishield, 0.0, v50p, 1, ATF_SHIELD);
ichain = it_get_or_create(rt_get_or_create("chainmail"));
achain = new_armortype(ichain, 0.0, 0.5, 3, ATF_NONE);
wtype = new_weapontype(it_get_or_create(rt_get_or_create("sword")), 0, 0.5, 0, 0, 0, 0, SK_MELEE, 1);
achain = new_armortype(ichain, 0.0, v50p, 3, ATF_NONE);
wtype = new_weapontype(it_get_or_create(rt_get_or_create("sword")), 0, v50p, 0, 0, 0, 0, SK_MELEE, 1);
rc = test_create_race("human");
rc->battle_flags |= BF_EQUIPMENT;
du = test_create_unit(test_create_faction(rc), r);
@ -414,7 +429,7 @@ static void test_battle_skilldiff(CuTest *tc)
unit *ua, *ud;
battle *b = NULL;
test_cleanup();
test_setup();
r = test_create_region(0, 0, 0);
ud = test_create_unit(test_create_faction(0), r);
@ -441,10 +456,6 @@ static void test_battle_skilldiff(CuTest *tc)
test_cleanup();
}
static int protect(const building *b, const unit *u, building_bonus bonus) {
return (bonus == DEFENSE_BONUS) ? 4 : 0;
}
static void test_battle_skilldiff_building(CuTest *tc)
{
troop ta, td;
@ -454,8 +465,8 @@ static void test_battle_skilldiff_building(CuTest *tc)
building_type *btype;
const curse_type *strongwall_ct, *magicwalls_ct;
test_cleanup();
btype = test_create_buildingtype("castle");
test_setup();
btype = setup_castle();
strongwall_ct = ct_find("strongwall");
magicwalls_ct = ct_find("magicwalls");
@ -470,14 +481,14 @@ static void test_battle_skilldiff_building(CuTest *tc)
ua = test_create_unit(test_create_faction(0), r);
CuAssertIntEquals(tc, 0, skilldiff(ta, td, 0));
btype->protection = protect;
CuAssertIntEquals(tc, -4, skilldiff(ta, td, 0));
ud->building->size = 10;
CuAssertIntEquals(tc, -1, skilldiff(ta, td, 0));
create_curse(NULL, &ud->building->attribs, magicwalls_ct, 1, 1, 1, 1);
CuAssertIntEquals(tc, -8, skilldiff(ta, td, 0));
CuAssertIntEquals(tc, -2, skilldiff(ta, td, 0));
create_curse(NULL, &ud->building->attribs, strongwall_ct, 1, 1, 2, 1);
CuAssertIntEquals(tc, -10, skilldiff(ta, td, 0));
CuAssertIntEquals(tc, -4, skilldiff(ta, td, 0));
free_battle(b);
test_cleanup();

View file

@ -914,6 +914,10 @@ struct message * get_modifiers(unit *u, const resource_mod *mod, variant *savep,
return NULL;
}
static resource_limit *get_resourcelimit(const resource_type *rtype) {
return rtype->limit;
}
static void allocate_resource(unit * u, const resource_type * rtype, int want)
{
const item_type *itype = resource2item(rtype);
@ -921,8 +925,7 @@ static void allocate_resource(unit * u, const resource_type * rtype, int want)
int dm = 0;
allocation_list *alist;
allocation *al;
attrib *a = a_find(rtype->attribs, &at_resourcelimit);
resource_limit *rdata = (resource_limit *)a->data.v;
resource_limit *rdata = get_resourcelimit(rtype);
const resource_type *rring;
int amount, skill, skill_mod = 0;
variant save_mod;
@ -1119,9 +1122,8 @@ attrib_allocation(const resource_type * rtype, region * r, allocation * alist)
{
allocation *al;
int nreq = 0;
attrib *a = a_find(rtype->attribs, &at_resourcelimit);
resource_limit *rdata = (resource_limit *)a->data.v;
int avail = rdata->value;
resource_limit *rdata = get_resourcelimit(rtype);
int avail = 0;
for (al = alist; al; al = al->next) {
nreq += required(al->want, al->save);
@ -1160,11 +1162,10 @@ typedef void(*allocate_function) (const resource_type *, struct region *,
static allocate_function get_allocator(const struct resource_type *rtype)
{
attrib *a = a_find(rtype->attribs, &at_resourcelimit);
resource_limit *rdata = get_resourcelimit(rtype);
if (a != NULL) {
resource_limit *rdata = (resource_limit *)a->data.v;
if (rdata->value > 0 || rdata->limit != NULL) {
if (rdata) {
if (rdata->limit != NULL) {
return attrib_allocation;
}
return leveled_allocation;

View file

@ -211,7 +211,7 @@ static void test_tax_cmd(CuTest *tc) {
silver = get_resourcetype(R_SILVER)->itype;
sword = it_get_or_create(rt_get_or_create("sword"));
new_weapontype(sword, 0, 0.0, NULL, 0, 0, 0, SK_MELEE, 1);
new_weapontype(sword, 0, frac_zero, NULL, 0, 0, 0, SK_MELEE, 1);
i_change(&u->items, sword, 1);
set_level(u, SK_MELEE, 1);
@ -348,7 +348,6 @@ static void test_make_item(CuTest *tc) {
struct item_type *itype;
const struct resource_type *rt_silver;
resource_type *rtype;
attrib *a;
resource_limit *rdata;
double d = 0.6;
@ -382,10 +381,8 @@ static void test_make_item(CuTest *tc) {
free(itype->construction->materials);
itype->construction->materials = 0;
rtype->flags |= RTF_LIMITED;
a = a_add(&rtype->attribs, a_new(&at_resourcelimit));
rdata = (resource_limit *)a->data.v;
rdata->value = 0;
rmt_create(rtype, "stone");
rmt_create(rtype);
rdata = rtype->limit = calloc(1, sizeof(resource_limit));
add_resource(u->region, 1, 300, 150, rtype);
u->region->resources->amount = 300; /* there are 300 stones at level 1 */
set_level(u, SK_ALCHEMY, 10);

View file

@ -21,7 +21,9 @@
#include <kernel/xmlreader.h>
#include <modules/gmcmd.h>
#include <modules/xmas.h>
#include <items/itemtypes.h>
#include <items/xerewards.h>
#include <items/weapons.h>
#include <attributes/attributes.h>
#include <util/message.h>
#include <races/races.h>
@ -81,7 +83,8 @@ void game_init(void)
#endif
wormholes_register();
register_itemtypes();
register_weapons();
register_xerewards();
#ifdef USE_LIBXML2
register_xmlreader();
#endif

View file

@ -47,7 +47,6 @@
#include <attributes/attributes.h>
#include <triggers/triggers.h>
#include <items/itemtypes.h>
#include <util/log.h>
#include <util/unicode.h>

View file

@ -42,7 +42,7 @@ static void test_guard_unskilled(CuTest * tc)
test_setup();
itype = it_get_or_create(rt_get_or_create("sword"));
new_weapontype(itype, 0, 0.0, NULL, 0, 0, 0, SK_MELEE, 2);
new_weapontype(itype, 0, frac_zero, NULL, 0, 0, 0, SK_MELEE, 2);
r = test_create_region(0, 0, 0);
u = test_create_unit(test_create_faction(0), r);
ug = test_create_unit(test_create_faction(0), r);
@ -61,7 +61,7 @@ static void test_guard_armed(CuTest * tc)
test_setup();
itype = it_get_or_create(rt_get_or_create("sword"));
new_weapontype(itype, 0, 0.0, NULL, 0, 0, 0, SK_MELEE, 2);
new_weapontype(itype, 0, frac_zero, NULL, 0, 0, 0, SK_MELEE, 2);
r = test_create_region(0, 0, 0);
u = test_create_unit(test_create_faction(0), r);
ug = test_create_unit(test_create_faction(0), r);
@ -80,7 +80,7 @@ static void test_is_guard(CuTest * tc)
test_setup();
itype = it_get_or_create(rt_get_or_create("sword"));
new_weapontype(itype, 0, 0.0, NULL, 0, 0, 0, SK_MELEE, 2);
new_weapontype(itype, 0, frac_zero, NULL, 0, 0, 0, SK_MELEE, 2);
r = test_create_region(0, 0, 0);
ug = test_create_unit(test_create_faction(0), r);
i_change(&ug->items, itype, 1);

View file

@ -5,10 +5,7 @@ xerewards.test.c
)
SET(_FILES
artrewards.c
demonseye.c
itemtypes.c
seed.c
speedsail.c
weapons.c
xerewards.c

View file

@ -1,155 +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 "artrewards.h"
/* kernel includes */
#include <kernel/item.h>
#include <kernel/pool.h>
#include <kernel/region.h>
#include <kernel/faction.h>
#include <kernel/unit.h>
#include <kernel/curse.h>
#include <kernel/messages.h>
#include <kernel/ship.h>
/* util includes */
#include <util/attrib.h>
#include <util/rand.h>
/* libc includes */
#include <assert.h>
#include <limits.h>
#include <string.h>
#include <stdlib.h>
#define HORNRANGE 10
#define HORNDURATION 3
#define HORNIMMUNITY 30
static int age_peaceimmune(attrib * a, void *owner)
{
UNUSED_ARG(owner);
return (--a->data.i > 0) ? AT_AGE_KEEP : AT_AGE_REMOVE;
}
static attrib_type at_peaceimmune = {
"peaceimmune",
NULL, NULL,
age_peaceimmune,
a_writeint,
a_readint
};
static int
use_hornofdancing(struct unit *u, const struct item_type *itype,
int amount, struct order *ord)
{
region *r;
int regionsPacified = 0;
for (r = regions; r; r = r->next) {
if (distance(u->region, r) < HORNRANGE) {
if (a_find(r->attribs, &at_peaceimmune) == NULL) {
attrib *a;
create_curse(u, &r->attribs, ct_find("peacezone"),
20, HORNDURATION, 1.0, 0);
a = a_add(&r->attribs, a_new(&at_peaceimmune));
a->data.i = HORNIMMUNITY;
ADDMSG(&r->msgs, msg_message("hornofpeace_r_success",
"unit region", u, u->region));
regionsPacified++;
}
else {
ADDMSG(&r->msgs, msg_message("hornofpeace_r_nosuccess",
"unit region", u, u->region));
}
}
}
if (regionsPacified > 0) {
ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "hornofpeace_u_success",
"pacified", regionsPacified));
}
else {
ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "hornofpeace_u_nosuccess",
""));
}
return 0;
}
#define SPEEDUP 2
static int
useonother_trappedairelemental(struct unit *u, int shipId,
const struct item_type *itype, int amount, struct order *ord)
{
curse *c;
ship *sh;
if (shipId <= 0) {
cmistake(u, ord, 20, MSG_MOVE);
return -1;
}
sh = findshipr(u->region, shipId);
if (!sh) {
cmistake(u, ord, 20, MSG_MOVE);
return -1;
}
c =
create_curse(u, &sh->attribs, ct_find("shipspeedup"), 20, INT_MAX, SPEEDUP,
0);
c_setflag(c, CURSE_NOAGE);
ADDMSG(&u->faction->msgs, msg_message("trappedairelemental_success",
"unit region command ship", u, u->region, ord, sh));
use_pooled(u, itype->rtype, GET_DEFAULT, 1);
return 0;
}
static int
use_trappedairelemental(struct unit *u,
const struct item_type *itype, int amount, struct order *ord)
{
ship *sh = u->ship;
if (sh == NULL) {
cmistake(u, ord, 20, MSG_MOVE);
return -1;
}
return useonother_trappedairelemental(u, sh->no, itype, amount, ord);
}
void register_artrewards(void)
{
at_register(&at_peaceimmune);
register_item_use(use_hornofdancing, "use_hornofdancing");
register_item_use(use_trappedairelemental, "use_trappedairelemental");
register_item_useonother(useonother_trappedairelemental,
"useonother_trappedairelemental");
}

View file

@ -1,30 +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_ITM_ARTREWARDS
#define H_ITM_ARTREWARDS
#ifdef __cplusplus
extern "C" {
#endif
extern void register_artrewards(void);
#ifdef __cplusplus
}
#endif
#endif

View file

@ -1,33 +0,0 @@
/*
+-------------------+ Christian Schlittchen <corwin@amber.kn-bremen.de>
| | Enno Rehling <enno@eressea.de>
| Eressea PBEM host | Katja Zedel <katze@felidae.kn-bremen.de>
| (c) 1998 - 2003 | Henning Peters <faroul@beyond.kn-bremen.de>
| | Ingo Wilken <Ingo.Wilken@informatik.uni-oldenburg.de>
+-------------------+ Stefan Reich <reich@halbling.de>
This program may not be used, modified or distributed
without prior permission by the authors of Eressea.
*/
#include <platform.h>
#include "itemtypes.h"
#include "xerewards.h"
#include "artrewards.h"
#include "weapons.h"
#include "seed.h"
void register_itemtypes(void)
{
/* registering misc. functions */
register_weapons();
register_xerewards();
register_artrewards();
}
void init_itemtypes(void)
{
init_seed();
init_mallornseed();
}

View file

@ -1,25 +0,0 @@
/*
+-------------------+ Christian Schlittchen <corwin@amber.kn-bremen.de>
| | Enno Rehling <enno@eressea.de>
| Eressea PBEM host | Katja Zedel <katze@felidae.kn-bremen.de>
| (c) 1998 - 2003 | Henning Peters <faroul@beyond.kn-bremen.de>
| | Ingo Wilken <Ingo.Wilken@informatik.uni-oldenburg.de>
+-------------------+ Stefan Reich <reich@halbling.de>
This program may not be used, modified or distributed
without prior permission by the authors of Eressea.
*/
#ifndef H_ITM_ITEMS
#define H_ITM_ITEMS
#ifdef __cplusplus
extern "C" {
#endif
extern void init_itemtypes(void);
extern void register_itemtypes(void);
#ifdef __cplusplus
}
#endif
#endif

View file

@ -1,97 +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 "seed.h"
/* kernel includes */
#include <kernel/build.h>
#include <kernel/item.h>
#include <kernel/region.h>
/* util includes */
#include <util/attrib.h>
#include <util/functions.h>
/* libc includes */
#include <assert.h>
static void produce_seeds(region * r, const resource_type * rtype, int norders)
{
assert(r->land && r->land->trees[0] >= norders);
r->land->trees[0] -= norders;
}
static int limit_seeds(const region * r, const resource_type * rtype)
{
if ((r->flags & RF_MALLORN)) {
return 0;
}
return r->land ? r->land->trees[0] : 0;
}
void init_seed(void)
{
attrib *a;
resource_limit *rdata;
resource_type *rtype;
rtype = rt_find("seed");
if (rtype != NULL) {
a = a_add(&rtype->attribs, a_new(&at_resourcelimit));
rdata = (resource_limit *)a->data.v;
rdata->limit = limit_seeds;
rdata->produce = produce_seeds;
}
}
/* mallorn */
static void
produce_mallornseeds(region * r, const resource_type * rtype, int norders)
{
assert(r->flags & RF_MALLORN);
r->land->trees[0] -= norders;
}
static int limit_mallornseeds(const region * r, const resource_type * rtype)
{
if (!(r->flags & RF_MALLORN)) {
return 0;
}
return r->land ? r->land->trees[0] : 0;
}
void init_mallornseed(void)
{
attrib *a;
resource_limit *rdata;
resource_type *rtype;
rtype = rt_find("mallornseed");
if (rtype != NULL) {
rtype->flags |= RTF_LIMITED;
rtype->flags |= RTF_POOLED;
a = a_add(&rtype->attribs, a_new(&at_resourcelimit));
rdata = (resource_limit *)a->data.v;
rdata->limit = limit_mallornseeds;
rdata->produce = produce_mallornseeds;
}
}

View file

@ -1,31 +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_ITM_SEED
#define H_ITM_SEED
#ifdef __cplusplus
extern "C" {
#endif
extern void init_seed(void);
extern void init_mallornseed(void);
#ifdef __cplusplus
}
#endif
#endif

View file

@ -45,9 +45,6 @@ extern "C" {
int maxsize; /* maximum size of this type */
int reqsize; /* size of object using up 1 set of requirement. */
int defense_bonus; /* protection bonus (defense) during combat */
int close_combat_bonus; /* close combat attack bonus*/
int ranged_bonus; /* ranged attack bonus */
requirement *materials; /* material req'd to build one object */
const struct building_type *btype;
/* building type required to make this thing */

View file

@ -325,9 +325,14 @@ const building_type *findbuildingtype(const char *name,
building_type *btype = (building_type *)selist_get(ql, qi);
const char *n = LOC(lang, btype->_name);
if (!n) {
log_error("building type %s has no translation in %s",
btype->_name, locale_name(lang));
} else {
type.v = (void *)btype;
addtoken((struct tnode **)&bn->names, n, type);
}
}
bnames = bn;
}
if (findtoken(bn->names, name, &type) == E_TOK_NOMATCH)
@ -337,40 +342,24 @@ const building_type *findbuildingtype(const char *name,
int cmp_castle_size(const building * b, const building * a)
{
if (!b || !b->type->protection || !building_owner(b)) {
if (!b || !(b->type->flags & BTF_FORTIFICATION) || !building_owner(b)) {
return -1;
}
if (!a || !a->type->protection || !building_owner(a)) {
if (!a || !(a->type->flags & BTF_FORTIFICATION) || !building_owner(a)) {
return 1;
}
return b->size - a->size;
}
int building_protection(const building * b, const unit * u, building_bonus bonus)
{
int i = 0;
int bsize = buildingeffsize(b, false);
const construction *cons = b->type->construction;
if (!cons) {
return 0;
}
static const int castle_bonus[6] = { 0, 1, 3, 5, 8, 12 };
static const int watch_bonus[3] = { 0, 1, 2 };
for (i = 0; i < bsize; i++)
int building_protection(const building_type * btype, int stage)
{
cons = cons->improvement;
}
switch (bonus)
{
case DEFENSE_BONUS:
return cons->defense_bonus;
case CLOSE_COMBAT_ATTACK_BONUS:
return cons->close_combat_bonus;
case RANGED_ATTACK_BONUS:
return cons->ranged_bonus;
default:
return 0;
if (btype->maxsize < 0) {
return castle_bonus[MIN(stage, 5)];
}
return watch_bonus[MIN(stage, 2)];
}
void write_building_reference(const struct building *b, struct storage *store)
@ -925,8 +914,6 @@ int cmp_current_owner(const building * b, const building * a)
void register_buildings(void)
{
register_function((pf_generic)minimum_wage, "minimum_wage");
register_function((pf_generic)building_protection,
"building_protection");
register_function((pf_generic)init_smithy, "init_smithy");
register_function((pf_generic)castle_name, "castle_name");
register_function((pf_generic)castle_name_2, "castle_name_2");

View file

@ -51,13 +51,7 @@ extern "C" {
#define BTF_MAGIC 0x40 /* magical effect */
#define BTF_ONEPERTURN 0x80 /* one one sizepoint can be added per turn */
#define BTF_NAMECHANGE 0x100 /* name and description can be changed more than once */
#define BTF_FORTIFICATION 0x200 /* safe from monsters */
typedef enum {
DEFENSE_BONUS,
CLOSE_COMBAT_ATTACK_BONUS, /* TODO: only DEFENSE_BONUS is in use? */
RANGED_ATTACK_BONUS
} building_bonus;
#define BTF_FORTIFICATION 0x200 /* building_protection, safe from monsters */
typedef struct building_type {
char *_name;
@ -66,7 +60,7 @@ extern "C" {
int capacity; /* Kapazit<69>t pro Gr<47><72>enpunkt */
int maxcapacity; /* Max. Kapazit<69>t */
int maxsize; /* how big can it get, with all the extensions? */
int magres; /* how well it resists against spells */
variant magres; /* how well it resists against spells */
int magresbonus; /* bonus it gives the target against spells */
int fumblebonus; /* bonus that reduces fumbling */
double auraregen; /* modifier for aura regeneration inside building */
@ -77,7 +71,6 @@ extern "C" {
const struct building * b, int size);
void(*init) (struct building_type *);
void(*age) (struct building *);
int(*protection) (const struct building *, const struct unit *, building_bonus bonus);
double(*taxes) (const struct building *, int size);
struct attrib *attribs;
} building_type;
@ -86,7 +79,7 @@ extern "C" {
extern struct attrib_type at_building_action;
int cmp_castle_size(const struct building *b, const struct building *a);
int building_protection(const struct building * b, const struct unit * u, building_bonus bonus);
int building_protection(const struct building_type *btype, int stage);
building_type *bt_get_or_create(const char *name);
bool bt_changed(int *cache);
const building_type *bt_find(const char *name);

View file

@ -376,13 +376,12 @@ static void test_btype_defaults(CuTest *tc) {
CuAssertTrue(tc, !btype->name);
CuAssertTrue(tc, !btype->init);
CuAssertTrue(tc, !btype->age);
CuAssertTrue(tc, !btype->protection);
CuAssertTrue(tc, !btype->taxes);
CuAssertDblEquals(tc, 1.0, btype->auraregen, 0.0);
CuAssertIntEquals(tc, -1, btype->maxsize);
CuAssertIntEquals(tc, 1, btype->capacity);
CuAssertIntEquals(tc, -1, btype->maxcapacity);
CuAssertIntEquals(tc, 0, btype->magres);
CuAssertIntEquals(tc, 0, btype->magres.sa[0]);
CuAssertIntEquals(tc, 0, btype->magresbonus);
CuAssertIntEquals(tc, 0, btype->fumblebonus);
CuAssertIntEquals(tc, 0, btype->flags);
@ -515,6 +514,31 @@ static void test_cmp_castle_size(CuTest *tc) {
test_cleanup();
}
static void test_building_effsize(CuTest *tc) {
building *b;
building_type *btype;
construction *cons;
test_setup();
btype = bt_get_or_create("castle");
cons = btype->construction = calloc(1, sizeof(construction));
cons->maxsize = 5;
cons = cons->improvement = calloc(1, sizeof(construction));
cons->maxsize = 5;
cons = cons->improvement = calloc(1, sizeof(construction));
cons->maxsize = -1;
b = test_create_building(test_create_region(0,0,0), btype);
b->size = 1;
CuAssertIntEquals(tc, 0, buildingeffsize(b, false));
b->size = 5;
CuAssertIntEquals(tc, 1, buildingeffsize(b, false));
b->size = 10;
CuAssertIntEquals(tc, 2, buildingeffsize(b, false));
b->size = 20;
CuAssertIntEquals(tc, 2, buildingeffsize(b, false));
test_cleanup();
}
CuSuite *get_building_suite(void)
{
CuSuite *suite = CuSuiteNew();
@ -522,6 +546,7 @@ CuSuite *get_building_suite(void)
SUITE_ADD_TEST(suite, test_register_building);
SUITE_ADD_TEST(suite, test_btype_defaults);
SUITE_ADD_TEST(suite, test_building_set_owner);
SUITE_ADD_TEST(suite, test_building_effsize);
SUITE_ADD_TEST(suite, test_buildingowner_resets_when_empty);
SUITE_ADD_TEST(suite, test_buildingowner_goes_to_next_when_empty);
SUITE_ADD_TEST(suite, test_buildingowner_goes_to_other_when_empty);

View file

@ -275,7 +275,7 @@ luxury_type *new_luxurytype(item_type * itype, int price)
}
weapon_type *new_weapontype(item_type * itype,
int wflags, double magres, const char *damage[], int offmod, int defmod,
int wflags, variant magres, const char *damage[], int offmod, int defmod,
int reload, skill_t sk, int minskill)
{
weapon_type *wtype;
@ -301,7 +301,7 @@ weapon_type *new_weapontype(item_type * itype,
return wtype;
}
armor_type *new_armortype(item_type * itype, double penalty, double magres,
armor_type *new_armortype(item_type * itype, double penalty, variant magres,
int prot, unsigned int flags)
{
armor_type *atype;
@ -1159,22 +1159,6 @@ const item_type *finditemtype(const char *name, const struct locale *lang)
return 0;
}
static void init_resourcelimit(attrib * a)
{
a->data.v = calloc(sizeof(resource_limit), 1);
}
static void finalize_resourcelimit(attrib * a)
{
free(a->data.v);
}
attrib_type at_resourcelimit = {
"resourcelimit",
init_resourcelimit,
finalize_resourcelimit,
};
item *item_spoil(const struct race *rc, int size)
{
item *itm = NULL;
@ -1258,6 +1242,9 @@ void free_rtype(resource_type *rtype) {
if (rtype->itype) {
free_itype(rtype->itype);
}
if (rtype->raw) {
free(rtype->raw);
}
free(rtype->_name);
free(rtype);
}

View file

@ -29,6 +29,7 @@ extern "C" {
struct unit;
struct attrib;
struct attrib_type;
struct race;
struct region;
struct resource_type;
struct locale;
@ -37,6 +38,8 @@ extern "C" {
struct order;
struct storage;
struct gamedata;
struct rawmaterial_type;
struct resource_limit;
typedef struct item {
struct item *next;
@ -76,6 +79,8 @@ extern "C" {
rtype_uchange uchange;
rtype_uget uget;
rtype_name name;
struct rawmaterial_type *raw;
struct resource_limit *limit;
/* --- pointers --- */
struct attrib *attribs;
struct item_type *itype;
@ -94,25 +99,6 @@ extern "C" {
#define RMF_SAVEMATERIAL 0x02 /* fraction (sa[0]/sa[1]), multiplier on resource usage */
#define RMF_REQUIREDBUILDING 0x04 /* building, required to build */
typedef struct resource_mod {
variant value;
const struct building_type *btype;
const struct race *race;
unsigned int flags;
} resource_mod;
extern struct attrib_type at_resourcelimit;
typedef int(*rlimit_limit) (const struct region * r,
const struct resource_type * rtype);
typedef void(*rlimit_produce) (struct region * r,
const struct resource_type * rtype, int n);
typedef struct resource_limit {
rlimit_limit limit;
rlimit_produce produce;
int value;
resource_mod *modifiers;
} resource_limit;
/* bitfield values for item_type::flags */
#define ITF_NONE 0x0000
#define ITF_HERB 0x0001 /* this item is a herb */
@ -195,7 +181,7 @@ extern "C" {
const item_type *itype;
unsigned int flags;
double penalty;
double magres;
variant magres;
int prot;
float projectile; /* chance, dass ein projektil abprallt */
} armor_type;
@ -219,7 +205,7 @@ extern "C" {
int minskill;
int offmod;
int defmod;
double magres;
variant magres;
int reload; /* time to reload this weapon */
weapon_mod *modifiers;
/* --- functions --- */
@ -258,14 +244,12 @@ extern "C" {
/* creation */
resource_type *rt_get_or_create(const char *name);
item_type *it_get_or_create(resource_type *rtype);
item_type *new_itemtype(resource_type * rtype, int iflags, int weight,
int capacity);
luxury_type *new_luxurytype(item_type * itype, int price);
weapon_type *new_weapontype(item_type * itype, int wflags,
double magres, const char *damage[], int offmod, int defmod, int reload,
variant magres, const char *damage[], int offmod, int defmod, int reload,
skill_t sk, int minskill);
armor_type *new_armortype(item_type * itype, double penalty,
double magres, int prot, unsigned int flags);
variant magres, int prot, unsigned int flags);
potion_type *new_potiontype(item_type * itype, int level);
typedef enum {

View file

@ -460,7 +460,7 @@ static void json_race(cJSON *json, race *rc) {
break;
case cJSON_Number:
if (strcmp(child->string, "magres") == 0) {
rc->magres = child->valueint;
rc->magres = frac_make(child->valueint, 100);
}
else if (strcmp(child->string, "maxaura") == 0) {
rc->maxaura = child->valueint;

View file

@ -163,8 +163,7 @@ static void test_races(CuTest * tc)
CuAssertPtrNotNull(tc, rc);
CuAssertIntEquals(tc, RCF_NPC | RCF_WALK | RCF_UNDEAD, rc->flags);
CuAssertStrEquals(tc, "1d4", rc->def_damage);
CuAssertIntEquals(tc, 100, rc->magres);
CuAssertDblEquals(tc, 1.0, rc_magres(rc), 0.0);
CuAssertTrue(tc, frac_equal(frac_one, rc->magres));
CuAssertIntEquals(tc, 200, rc->maxaura);
CuAssertDblEquals(tc, 2.0, rc_maxaura(rc), 0.0);
CuAssertDblEquals(tc, 3.0, rc->regaura, 0.0);

View file

@ -331,6 +331,7 @@ race *rc_create(const char *zName)
assert(zName);
rc = (race *)calloc(sizeof(race), 1);
rc->magres.sa[1] = 1;
rc->hitpoints = 1;
rc->weight = PERSON_WEIGHT;
rc->capacity = 540;
@ -383,8 +384,8 @@ bool r_insectstalled(const region * r)
return fval(r->terrain, ARCTIC_REGION);
}
double rc_magres(const race *rc) {
return rc->magres / 100.0;
variant rc_magres(const race *rc) {
return rc->magres;
}
double rc_maxaura(const race *rc) {

View file

@ -116,7 +116,7 @@ extern "C" {
typedef struct race {
char *_name;
int magres;
variant magres;
int healing;
int maxaura; /* Faktor auf Maximale Aura */
double regaura; /* Faktor auf Regeneration */
@ -182,7 +182,7 @@ extern "C" {
int rc_luxury_trade(const struct race *rc);
int rc_herb_trade(const struct race *rc);
double rc_magres(const struct race *rc);
variant rc_magres(const struct race *rc);
double rc_maxaura(const struct race *rc);
int rc_armor_bonus(const struct race *rc);
int rc_scare(const struct race *rc);

View file

@ -24,8 +24,7 @@ static void test_rc_defaults(CuTest *tc) {
rc = rc_get_or_create("human");
CuAssertStrEquals(tc, "human", rc->_name);
CuAssertIntEquals(tc, 0, rc_armor_bonus(rc));
CuAssertIntEquals(tc, 0, rc->magres);
CuAssertDblEquals(tc, 0.0, rc_magres(rc), 0.0);
CuAssertIntEquals(tc, 0, rc->magres.sa[0]);
CuAssertIntEquals(tc, 0, rc->healing);
CuAssertDblEquals(tc, 0.0, rc_maxaura(rc), 0.0);
CuAssertDblEquals(tc, 1.0, rc->recruit_multi, 0.0);

View file

@ -183,35 +183,31 @@ struct rawmaterial *rm_get(region * r, const struct resource_type *rtype)
return rm;
}
struct rawmaterial_type *rawmaterialtypes = 0;
struct rawmaterial_type *rmt_find(const char *str)
{
rawmaterial_type *rmt = rawmaterialtypes;
while (rmt && strcmp(rmt->name, str) != 0)
rmt = rmt->next;
return rmt;
resource_type *rtype = rt_find(str);
if (!rtype && strncmp(str, "rm_", 3) == 0) {
rtype = rt_find(str+3);
}
assert(rtype);
return rtype ? rtype->raw : NULL;
}
struct rawmaterial_type *rmt_get(const struct resource_type *rtype)
{
rawmaterial_type *rmt = rawmaterialtypes;
while (rmt && rmt->rtype != rtype)
rmt = rmt->next;
return rmt;
return rtype->raw;
}
struct rawmaterial_type *rmt_create(const struct resource_type *rtype,
const char *name)
struct rawmaterial_type *rmt_create(struct resource_type *rtype)
{
rawmaterial_type *rmtype = malloc(sizeof(rawmaterial_type));
rmtype->name = strdup(name);
rawmaterial_type *rmtype;
assert(!rtype->raw);
rmtype = rtype->raw = malloc(sizeof(rawmaterial_type));
rmtype->rtype = rtype;
rmtype->terraform = terraform_default;
rmtype->update = NULL;
rmtype->use = use_default;
rmtype->visible = visible_default;
rmtype->next = rawmaterialtypes;
rawmaterialtypes = rmtype;
return rmtype;
}

View file

@ -15,6 +15,9 @@
extern "C" {
#endif
struct building_type;
struct race;
enum {
RM_USED = 1 << 0, /* resource has been used */
RM_MALLORN = 1 << 1 /* this is not wood. it's mallorn */
@ -40,17 +43,31 @@ extern "C" {
struct rawmaterial *next;
} rawmaterial;
typedef int(*rlimit_limit) (const struct region * r,
const struct resource_type * rtype);
typedef void(*rlimit_produce) (struct region * r,
const struct resource_type * rtype, int n);
typedef struct resource_mod {
variant value;
const struct building_type *btype;
const struct race *race;
unsigned int flags;
} resource_mod;
typedef struct resource_limit {
rlimit_limit limit;
rlimit_produce produce;
resource_mod *modifiers;
} resource_limit;
typedef struct rawmaterial_type {
char *name;
const struct resource_type *rtype;
void(*terraform) (struct rawmaterial *, const struct region *);
void(*update) (struct rawmaterial *, const struct region *);
void(*use) (struct rawmaterial *, const struct region *, int amount);
int(*visible) (const struct rawmaterial *, int skilllevel);
/* no initialization required */
struct rawmaterial_type *next;
} rawmaterial_type;
extern struct rawmaterial_type *rawmaterialtypes;
@ -64,8 +81,7 @@ extern "C" {
void add_resource(struct region *r, int level, int base, int divisor,
const struct resource_type *rtype);
struct rawmaterial_type *rmt_create(const struct resource_type *rtype,
const char *name);
struct rawmaterial_type *rmt_create(struct resource_type *rtype);
#ifdef __cplusplus
}

View file

@ -1068,7 +1068,7 @@ void writeregion(struct gamedata *data, const region * r)
WRITE_INT(data->store, rhorses(r));
while (res) {
WRITE_TOK(data->store, res->type->name);
WRITE_TOK(data->store, res->type->rtype->_name);
WRITE_INT(data->store, res->level);
WRITE_INT(data->store, res->amount);
WRITE_INT(data->store, res->startlevel);
@ -1529,6 +1529,11 @@ struct building *read_building(gamedata *data) {
READ_INT(store, &b->size);
READ_STR(store, name, sizeof(name));
b->type = bt_find(name);
if (!b->type) {
log_error("building %d has unknown type %s", b->no, name);
b->type = bt_find("building");
assert(b->type);
}
read_attribs(data, &b->attribs, b);
/* repairs, bug 2221: */

View file

@ -61,6 +61,19 @@ without prior permission by the authors of Eressea.
#include <string.h>
#ifdef USE_LIBXML2
static variant xml_fraction(xmlNodePtr node, const char *name) {
xmlChar *propValue = xmlGetProp(node, BAD_CAST name);
if (propValue != NULL) {
int num, den = 100;
double fval = atof((const char *)propValue);
num = (int)(fval * den + 0.5);
xmlFree(propValue);
return frac_make(num, den);
}
return frac_make(0, 1);
}
static void xml_readtext(xmlNodePtr node, struct locale **lang, xmlChar ** text)
{
xmlChar *propValue = xmlGetProp(node, BAD_CAST "locale");
@ -167,9 +180,6 @@ construction ** consPtr)
con->maxsize = xml_ivalue(node, "maxsize", -1);
con->minskill = xml_ivalue(node, "minskill", -1);
con->reqsize = xml_ivalue(node, "reqsize", 1);
con->defense_bonus = xml_ivalue(node, "defense_bonus", 0);
con->close_combat_bonus = xml_ivalue(node, "close_combat_bonus", 0);
con->ranged_bonus = xml_ivalue(node, "ranged_bonus", 0);
propValue = xmlGetProp(node, BAD_CAST "building");
if (propValue != NULL) {
@ -248,7 +258,7 @@ static int parse_buildings(xmlDocPtr doc)
btype->maxcapacity = xml_ivalue(node, "maxcapacity", btype->maxcapacity);
btype->maxsize = xml_ivalue(node, "maxsize", btype->maxsize);
btype->magres = xml_ivalue(node, "magres", btype->magres);
btype->magres = frac_make(xml_ivalue(node, "magres", 0), 100);
btype->magresbonus = xml_ivalue(node, "magresbonus", btype->magresbonus);
btype->fumblebonus = xml_ivalue(node, "fumblebonus", btype->fumblebonus);
btype->auraregen = xml_fvalue(node, "auraregen", btype->auraregen);
@ -301,9 +311,6 @@ static int parse_buildings(xmlDocPtr doc)
else if (strcmp((const char *)propValue, "age") == 0) {
btype->age = (void(*)(struct building *))fun;
}
else if (strcmp((const char *)propValue, "protection") == 0) {
btype->protection = (int(*)(const struct building *, const struct unit *, building_bonus))fun;
}
else if (strcmp((const char *)propValue, "taxes") == 0) {
btype->taxes = (double(*)(const struct building *, int))fun;
}
@ -588,7 +595,7 @@ static armor_type *xml_readarmor(xmlXPathContextPtr xpath, item_type * itype)
unsigned int flags = ATF_NONE;
int ac = xml_ivalue(node, "ac", 0);
double penalty = xml_fvalue(node, "penalty", 0.0);
double magres = xml_fvalue(node, "magres", 0.0);
variant magres = xml_fraction(node, "magres");
if (xml_bvalue(node, "laen", false))
flags |= ATF_LAEN;
@ -613,7 +620,7 @@ static weapon_type *xml_readweapon(xmlXPathContextPtr xpath, item_type * itype)
int offmod = xml_ivalue(node, "offmod", 0);
int defmod = xml_ivalue(node, "defmod", 0);
int reload = xml_ivalue(node, "reload", 0);
double magres = xml_fvalue(node, "magres", 0.0);
variant magres = xml_fraction(node, "magres");
if (xml_bvalue(node, "armorpiercing", false))
flags |= WTF_ARMORPIERCING;
@ -905,22 +912,6 @@ static int parse_rules(xmlDocPtr doc)
return 0;
}
static int gcd(int num, int den) {
const int primes[] = { 3, 5, 7, 11, 0 };
int i=0, g = 1, p = 2;
while (p && p<=den && p<=num) {
if (num % p == 0 && den % p == 0) {
num /= p;
den /= p;
g *= p;
}
else {
p = primes[i++];
}
}
return g;
}
static int parse_resources(xmlDocPtr doc)
{
xmlXPathContextPtr xpath = xmlXPathNewContext(doc);
@ -955,12 +946,6 @@ static int parse_resources(xmlDocPtr doc)
rtype->flags |= flags;
xmlFree(name);
name = xmlGetProp(node, BAD_CAST "material");
if (name) {
rmt_create(rtype, (const char *)name);
xmlFree(name);
}
/* reading eressea/resources/resource/function */
xpath->node = node;
result = xmlXPathEvalExpression(BAD_CAST "function", xpath);
@ -993,18 +978,18 @@ static int parse_resources(xmlDocPtr doc)
}
xmlXPathFreeObject(result);
if (xml_bvalue(node, "material", false)) {
rmt_create(rtype);
}
/* reading eressea/resources/resource/resourcelimit */
xpath->node = node;
result = xmlXPathEvalExpression(BAD_CAST "resourcelimit", xpath);
assert(result->nodesetval->nodeNr <= 1);
if (result->nodesetval->nodeNr != 0) {
resource_limit *rdata;
attrib *a = a_find(rtype->attribs, &at_resourcelimit);
resource_limit *rdata = rtype->limit = calloc(1, sizeof(resource_limit));
xmlNodePtr limit = result->nodesetval->nodeTab[0];
if (a == NULL)
a = a_add(&rtype->attribs, a_new(&at_resourcelimit));
rdata = (resource_limit *)a->data.v;
rtype->flags |= RTF_LIMITED;
xpath->node = limit;
xmlXPathFreeObject(result);
@ -1041,15 +1026,7 @@ static int parse_resources(xmlDocPtr doc)
rdata->modifiers[k].flags = RMF_SKILL;
}
else if (strcmp((const char *)propValue, "material") == 0) {
int g, num, den = 100;
double fval = xml_fvalue(node, "value", 0);
/* TODO: extract into a function for reading fractions? */
num = (int)(fval * den + 0.5);
g = gcd(num, den);
num /= g;
den /= g;
rdata->modifiers[k].value.sa[0] = (short)num;
rdata->modifiers[k].value.sa[1] = (short)den;
rdata->modifiers[k].value = xml_fraction(node, "value");
rdata->modifiers[k].flags = RMF_SAVEMATERIAL;
}
else if (strcmp((const char *)propValue, "require") == 0) {
@ -1071,7 +1048,7 @@ static int parse_resources(xmlDocPtr doc)
/* reading eressea/resources/resource/resourcelimit/function */
result = xmlXPathEvalExpression(BAD_CAST "function", xpath);
if (result->nodesetval != NULL)
if (result->nodesetval != NULL) {
for (k = 0; k != result->nodesetval->nodeNr; ++k) {
xmlNodePtr node = result->nodesetval->nodeTab[k];
pf_generic fun;
@ -1100,8 +1077,8 @@ static int parse_resources(xmlDocPtr doc)
xmlFree(propValue);
}
}
}
xmlXPathFreeObject(result);
/* reading eressea/resources/resource/resourcelimit/function */
xpath->node = node;
result = xmlXPathEvalExpression(BAD_CAST "resourcelimit/function", xpath);
@ -1129,7 +1106,6 @@ static int parse_resources(xmlDocPtr doc)
/* make sure old items (used in requirements) are available */
init_resources();
init_itemtypes();
return 0;
}
@ -1634,7 +1610,7 @@ static int parse_races(xmlDocPtr doc)
rc->def_damage = strdup((const char *)propValue);
xmlFree(propValue);
rc->magres = xml_ivalue(node, "magres", rc->magres);
rc->magres = frac_make(xml_ivalue(node, "magres", 100), 100);
rc->healing = (int)(xml_fvalue(node, "healing", rc->healing) * 100); /* TODO: store as int in XML */
rc->maxaura = (int)(xml_fvalue(node, "maxaura", rc->maxaura) * 100); /* TODO: store as int in XML */
rc->regaura = (float)xml_fvalue(node, "regaura", rc->regaura);

View file

@ -611,7 +611,7 @@ void setup_guard(guard_fixture *fix, bool armed) {
if (armed) {
item_type *itype;
itype = it_get_or_create(rt_get_or_create("sword"));
new_weapontype(itype, 0, 0.0, NULL, 0, 0, 0, SK_MELEE, 2);
new_weapontype(itype, 0, frac_zero, NULL, 0, 0, 0, SK_MELEE, 2);
i_change(&u->items, itype, 1);
set_level(u, SK_MELEE, 2);
}
@ -1481,7 +1481,7 @@ static void test_armedmen(CuTest *tc) {
test_setup();
u = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0));
it_sword = test_create_itemtype("sword");
wtype = new_weapontype(it_sword, 0, 0.5, 0, 0, 0, 0, SK_MELEE, 1);
wtype = new_weapontype(it_sword, 0, frac_make(1, 2), 0, 0, 0, 0, SK_MELEE, 1);
CuAssertIntEquals(tc, 0, armedmen(u, false));
CuAssertIntEquals(tc, 0, armedmen(u, true));
set_level(u, SK_MELEE, 1);

View file

@ -1135,27 +1135,29 @@ static int farcasting(unit * magician, region * r)
/* allgemeine Magieresistenz einer Einheit,
* reduziert magischen Schaden */
double magic_resistance(unit * target)
variant magic_resistance(unit * target)
{
attrib *a;
curse *c;
const curse_type * ct_goodresist = 0, *ct_badresist = 0;
const resource_type *rtype;
const race *rc = u_race(target);
double probability = rc_magres(rc);
variant v, prob = rc_magres(rc);
const plane *pl = rplane(target->region);
if (rc == get_race(RC_HIRNTOETER) && !pl) {
probability /= 2;
prob.sa[1] *= 2;
}
assert(target->number > 0);
/* Magier haben einen Resistenzbonus vom Magietalent * 5% */
probability += effskill(target, SK_MAGIC, 0) * 0.05;
prob = frac_add(prob, frac_make(effskill(target, SK_MAGIC, 0), 20));
/* Auswirkungen von Zaubern auf der Einheit */
c = get_curse(target->attribs, ct_find("magicresistance"));
if (c) {
probability += 0.01 * curse_geteffect(c) * get_cursedmen(target, c);
/* TODO: legacy. magicresistance-effect is an integer-percentage stored in a double */
int effect = curse_geteffect_int(c) * get_cursedmen(target, c);
prob = frac_add(prob, frac_make(effect, 100));
}
/* Unicorn +10 */
@ -1163,7 +1165,7 @@ double magic_resistance(unit * target)
if (rtype) {
int n = i_get(target->items, rtype->itype);
if (n) {
probability += n * 0.1 / target->number;
prob = frac_add(prob, frac_make(n, target->number * 10));
}
}
@ -1180,13 +1182,15 @@ double magic_resistance(unit * target)
if (mage != NULL) {
if (ct_goodresist && c->type == ct_goodresist) {
if (alliedunit(mage, target->faction, HELP_GUARD)) {
probability += curse_geteffect(c) * 0.01;
/* TODO: legacy. magicresistance-effect is an integer-percentage stored in a double */
prob = frac_add(prob, frac_make(curse_geteffect_int(c), 100));
ct_goodresist = 0; /* only one effect per region */
}
}
else if (ct_badresist && c->type == ct_badresist) {
if (!alliedunit(mage, target->faction, HELP_GUARD)) {
probability -= curse_geteffect(c) * 0.01;
/* TODO: legacy. magicresistance-effect is an integer-percentage stored in a double */
prob = frac_sub(prob, frac_make(curse_geteffect_int(c), 100));
ct_badresist = 0; /* only one effect per region */
}
}
@ -1202,11 +1206,18 @@ double magic_resistance(unit * target)
const struct building_type *btype = building_is_active(b) ? b->type : NULL;
/* gesegneter Steinkreis gibt 30% dazu */
if (btype)
probability += btype->magresbonus * 0.01;
if (btype) {
/* TODO: legacy. building-bonus is an integer-percentage */
prob = frac_add(prob, frac_make(btype->magresbonus, 100));
}
}
return (probability<0.9) ? probability : 0.9;
/* resistance must never be more than 90% */
v = frac_make(9, 10);
if (frac_sign(frac_sub(prob, v)) > 0) { /* prob < 90% */
return v; /* at most 90% */
}
return prob;
}
/* ------------------------------------------------------------- */
@ -1223,12 +1234,12 @@ double magic_resistance(unit * target)
bool
target_resists_magic(unit * magician, void *obj, int objtyp, int t_bonus)
{
double probability = 0.0;
variant v02p, v98p, prob = frac_make(t_bonus, 100);
attrib *a = NULL;
if (magician == NULL)
return true;
if (obj == NULL)
if (magician == NULL || obj == NULL) {
return true;
}
switch (objtyp) {
case TYP_UNIT:
@ -1248,43 +1259,56 @@ target_resists_magic(unit * magician, void *obj, int objtyp, int t_bonus)
pa = sk;
}
/* Contest */
probability = 0.05 * (10 + pa - at);
probability += magic_resistance((unit *)obj);
/* Contest, probability = 0.05 * (10 + pa - at); */
prob = frac_add(prob, frac_make(10 + pa - at, 20));
prob = frac_add(prob, magic_resistance((unit *)obj));
break;
}
case TYP_REGION:
/* Bonus durch Zauber */
/* Bonus durch Zauber
probability +=
0.01 * get_curseeffect(((region *)obj)->attribs, C_RESIST_MAGIC, 0);
0.01 * get_curseeffect(((region *)obj)->attribs, C_RESIST_MAGIC, 0); */
a = ((region *)obj)->attribs;
break;
case TYP_BUILDING:
/* Bonus durch Zauber */
/* Bonus durch Zauber
probability +=
0.01 * get_curseeffect(((building *)obj)->attribs, C_RESIST_MAGIC, 0);
/* Bonus durch Typ */
probability += 0.01 * ((building *)obj)->type->magres;
0.01 * get_curseeffect(((building *)obj)->attribs, C_RESIST_MAGIC, 0); */
a = ((building *)obj)->attribs;
/* Bonus durch Typ
probability += 0.01 * ((building *)obj)->type->magres; */
prob = frac_add(prob, ((building *)obj)->type->magres);
break;
case TYP_SHIP:
/* Bonus durch Zauber */
probability +=
0.01 * get_curseeffect(((ship *)obj)->attribs, C_RESIST_MAGIC, 0);
a = ((ship *)obj)->attribs;
break;
}
probability = MAX(0.02, probability + t_bonus * 0.01);
probability = MIN(0.98, probability);
if (a) {
const struct curse_type *ct_resist = ct_find(oldcursename(C_RESIST_MAGIC));
curse * c = get_curse(a, ct_resist);
int effect = curse_geteffect_int(c);
prob = frac_add(prob, frac_make(effect, 100));
}
/* ignore results < 2% and > 98% */
v02p = frac_make(1, 50);
v98p = frac_make(49, 50);
if (frac_sign(frac_sub(prob, v02p)) < 0) {
prob = v02p;
}
else if (frac_sign(frac_sub(prob, v98p)) > 0) {
prob = v98p;
}
/* gibt true, wenn die Zufallszahl kleiner als die chance ist und
* false, wenn sie gleich oder größer ist, dh je größer die
* Magieresistenz (chance) desto eher gibt die Funktion true zurück */
return chance(probability);
return rng_int() % prob.sa[1] < prob.sa[0];
}
/* ------------------------------------------------------------- */

View file

@ -315,7 +315,7 @@ extern "C" {
bool is_magic_resistant(struct unit *magician, struct unit *target, int
resist_bonus);
/* Mapperfunktion für target_resists_magic() vom Typ struct unit. */
extern double magic_resistance(struct unit *target);
variant magic_resistance(struct unit *target);
/* gibt die Chance an, mit der einem Zauber widerstanden wird. Je
* größer, desto resistenter ist da Opfer */
bool target_resists_magic(struct unit *magician, void *obj, int objtyp,

View file

@ -414,15 +414,15 @@ static void test_magic_resistance(CuTest *tc) {
test_setup();
rc = test_create_race("human");
u = test_create_unit(test_create_faction(rc), test_create_region(0, 0, 0));
CuAssertDblEquals(tc, rc->magres/100.0, magic_resistance(u), 0.01);
rc->magres = 100;
CuAssertDblEquals_Msg(tc, "magic resistance is capped at 0.9", 0.9, magic_resistance(u), 0.01);
CuAssertTrue(tc, frac_equal(rc->magres, magic_resistance(u)));
rc->magres = frac_one;
CuAssert(tc, "magic resistance is capped at 0.9", frac_equal(magic_resistance(u), frac_make(9, 10)));
rc = test_create_race("braineater");
rc->magres = 100;
rc->magres = frac_one;
u_setrace(u, rc);
CuAssertDblEquals_Msg(tc, "brain eaters outside astral space have 50% magres", 0.5, magic_resistance(u), 0.01);
CuAssert(tc, "brain eaters outside astral space have 50% magres", frac_equal(magic_resistance(u), frac_make(1, 2)));
u->region->_plane = get_astralplane();
CuAssertDblEquals_Msg(tc, "brain eaters in astral space have full magres", 0.9, magic_resistance(u), 0.01);
CuAssert(tc, "brain eaters in astral space have full magres", frac_equal(magic_resistance(u), frac_make(9, 10)));
test_cleanup();
}

View file

@ -412,32 +412,32 @@ const faction * viewer, bool see_unit)
if (money) {
if (n >= size)
return -1;
report_resource(result + n, "rm_money", money, -1);
report_resource(result + n, "money", money, -1);
++n;
}
if (peasants) {
if (n >= size)
return -1;
report_resource(result + n, "rm_peasant", peasants, -1);
report_resource(result + n, "peasant", peasants, -1);
++n;
}
if (horses) {
if (n >= size)
return -1;
report_resource(result + n, "rm_horse", horses, -1);
report_resource(result + n, "horse", horses, -1);
++n;
}
if (saplings) {
if (n >= size)
return -1;
report_resource(result + n, mallorn ? "rm_mallornsapling" : "rm_sapling",
report_resource(result + n, mallorn ? "mallornsapling" : "sapling",
saplings, -1);
++n;
}
if (trees) {
if (n >= size)
return -1;
report_resource(result + n, mallorn ? "rm_mallorn" : "rm_tree", trees,
report_resource(result + n, mallorn ? "mallorn" : "tree", trees,
-1);
++n;
}
@ -469,7 +469,7 @@ const faction * viewer, bool see_unit)
if (level >= 0 && visible >= 0) {
if (n >= size)
return -1;
report_resource(result + n, res->type->name, visible, level);
report_resource(result + n, res->type->rtype->_name, visible, level);
n++;
}
res = res->next;

View file

@ -2851,7 +2851,8 @@ static int dc_age(struct curse *c)
while (*up != NULL) {
unit *u = *up;
int hp;
double damage = c->effect * u->number;
variant dmg = frac_make(u->number, 1);
double damage = c->effect;
if (u->number <= 0 || target_resists_magic(mage, u, TYP_UNIT, 0)) {
up = &u->next;
@ -2859,7 +2860,9 @@ static int dc_age(struct curse *c)
}
/* Reduziert durch Magieresistenz */
damage *= (1.0 - magic_resistance(u));
dmg = frac_mul(dmg, frac_sub(frac_make(1,1), magic_resistance(u)));
damage *= dmg.sa[0];
damage /= dmg.sa[1];
hp = change_hitpoints(u, -(int)damage);
ADDMSG(&u->faction->msgs, msg_message((hp>0)?"poison_damage":"poison_death", "region unit", r, u));

View file

@ -71,7 +71,7 @@ static void test_all_spy_message(CuTest *tc) {
set_factionstealth(fix.victim, fix.spy->faction);
itype = it_get_or_create(rt_get_or_create("sword"));
new_weapontype(itype, 0, 0.0, NULL, 0, 0, 0, SK_MELEE, 2);
new_weapontype(itype, 0, frac_zero, NULL, 0, 0, 0, SK_MELEE, 2);
i_change(&fix.victim->items, itype, 1);
spy_message(99, fix.spy, fix.victim);

View file

@ -6,6 +6,7 @@
#include <string.h>
#include <stdlib.h>
#include <util/log.h>
#include <util/variant.h>
#pragma warning(disable: 4210)
@ -85,6 +86,7 @@ int RunAllTests(int argc, char *argv[])
ADD_SUITE(unicode);
ADD_SUITE(strings);
ADD_SUITE(log);
ADD_SUITE(variant);
ADD_SUITE(rng);
/* items */
ADD_SUITE(xerewards);

View file

@ -230,7 +230,7 @@ building * test_create_building(region * r, const building_type * btype)
assert(r);
if (!btype) {
building_type *bt_castle = test_create_buildingtype("castle");
bt_castle->protection = building_protection;
bt_castle->flags |= BTF_FORTIFICATION;
btype = bt_castle;
}
b = new_building(btype, r, default_locale);

View file

@ -28,6 +28,7 @@ log.test.c
# translation.test.c
umlaut.test.c
unicode.test.c
variant.test.c
# xml.test.c
)
@ -56,6 +57,7 @@ strings.c
translation.c
umlaut.c
unicode.c
variant.c
xml.c
)
FOREACH(_FILE ${_FILES})

80
src/util/variant.c Normal file
View file

@ -0,0 +1,80 @@
#include <platform.h>
#include "variant.h"
#include <assert.h>
#include <limits.h>
const variant frac_zero = { .sa = { 0, 1 } };
const variant frac_one = { .sa = { 1, 1 } };
static int gcd(int a, int b) {
const int primes[] = { 3, 5, 7, 11, 13, 17, 19, 23, 0 };
int i = 0, g = 1, p = 2;
while (p && p <= a && p <= b) {
if (a % p == 0 && b % p == 0) {
a /= p;
b /= p;
g *= p;
}
else {
p = primes[i++];
}
}
return g;
}
static int lcm(int a, int b) {
int x;
if (a == b) return a;
x = (a * b);
x = (x > 0 ? x : -x) / gcd(a, b);
return x;
}
bool frac_equal(variant a, variant b) {
return frac_sign(frac_sub(a, b)) == 0;
}
variant frac_make(int num, int den)
{
variant v;
int g = gcd(num, den);
num /= g;
den /= g;
assert(num >= SHRT_MIN && num <= SHRT_MAX);
assert(den >= SHRT_MIN && den <= SHRT_MAX);
v.sa[0] = (short)num;
v.sa[1] = (short)den;
return v;
}
variant frac_add(variant a, variant b)
{
int num, den;
den = lcm(a.sa[1], b.sa[1]);
num = a.sa[0] * den / a.sa[1] + b.sa[0] * den / b.sa[1];
return frac_make(num, den);
}
variant frac_sub(variant a, variant b)
{
b.sa[0] = -b.sa[0];
return frac_add(a, b);
}
variant frac_mul(variant a, variant b)
{
return frac_make(a.sa[0] * b.sa[0], a.sa[1] * b.sa[1]);
}
variant frac_div(variant a, variant b)
{
return frac_make(a.sa[0] * b.sa[1], a.sa[1] * b.sa[0]);
}
int frac_sign(variant a) {
if (a.sa[0] == 0) return 0;
if (a.sa[0] > 0 && a.sa[1] > 0) return 1;
if (a.sa[0] < 0 && a.sa[1] < 0) return 1;
return -1;
}

View file

@ -1,5 +1,10 @@
#pragma once
#ifndef STRUCT_VARIANT_H
#define STRUCT_VARIANT_H
#include <stdbool.h>
#ifdef __cplusplus
extern "C" {
#endif
@ -19,6 +24,17 @@ extern "C" {
VAR_FLOAT
} variant_type;
extern const variant frac_zero;
extern const variant frac_one;
variant frac_make(int num, int den);
variant frac_add(variant a, variant b);
variant frac_sub(variant a, variant b);
variant frac_mul(variant a, variant b);
variant frac_div(variant a, variant b);
int frac_sign(variant a);
bool frac_equal(variant a, variant b);
#ifdef __cplusplus
}
#endif

40
src/util/variant.test.c Normal file
View file

@ -0,0 +1,40 @@
#include <platform.h>
#include "variant.h"
#include <CuTest.h>
static void test_fractions(CuTest *tc) {
variant a, b;
a = frac_make(120, 12000);
CuAssertIntEquals(tc, 1, a.sa[0]);
CuAssertIntEquals(tc, 100, a.sa[1]);
b = frac_make(23, 2300);
a = frac_add(a, b);
CuAssertIntEquals(tc, 1, a.sa[0]);
CuAssertIntEquals(tc, 50, a.sa[1]);
a = frac_mul(a, b);
CuAssertIntEquals(tc, 1, a.sa[0]);
CuAssertIntEquals(tc, 5000, a.sa[1]);
a = frac_div(b, b);
CuAssertIntEquals(tc, 1, a.sa[0]);
CuAssertIntEquals(tc, 1, a.sa[1]);
a = frac_sub(a, a);
CuAssertIntEquals(tc, 0, a.sa[0]);
a = frac_sub(frac_one, a);
CuAssertIntEquals(tc, 1, a.sa[0]);
CuAssertIntEquals(tc, 1, a.sa[1]);
a = frac_mul(a, frac_zero);
CuAssertIntEquals(tc, 0, a.sa[0]);
CuAssertIntEquals(tc, 1, frac_sign(frac_make(-1, -1)));
CuAssertIntEquals(tc, 1, frac_sign(frac_make(1, 1)));
CuAssertIntEquals(tc, -1, frac_sign(frac_make(-1, 1)));
CuAssertIntEquals(tc, -1, frac_sign(frac_make(1, -1)));
CuAssertIntEquals(tc, 0, frac_sign(frac_make(0, 1)));
}
CuSuite *get_variant_suite(void)
{
CuSuite *suite = CuSuiteNew();
SUITE_ADD_TEST(suite, test_fractions);
return suite;
}

View file

@ -80,7 +80,6 @@ damage_unit(unit * u, const char *dam, bool physical, bool magic)
int *hp, hpstack[20];
int h;
int i, dead = 0, hp_rem = 0, heiltrank;
double magres = magic_resistance(u);
assert(u->number);
if (fval(u_race(u), RCF_ILLUSIONARY) || u_race(u) == get_race(RC_SPELL)) {
@ -105,10 +104,14 @@ damage_unit(unit * u, const char *dam, bool physical, bool magic)
/* Schaden */
for (i = 0; i < u->number; i++) {
int damage = dice_rand(dam);
if (magic)
damage = (int)(damage * (1.0 - magres));
if (physical)
if (magic) {
variant magres = magic_resistance(u);
magres = frac_sub(frac_make(1, 1), magres);
damage = damage * magres.sa[0] / magres.sa[1];
}
if (physical) {
damage -= nb_armor(u, i);
}
hp[i] -= damage;
}