forked from github/server
Merge pull request #663 from ennorehling/develop
ongoing refactoring towards the noxml branch
This commit is contained in:
commit
2137c51509
73 changed files with 642 additions and 907 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -39,3 +39,6 @@ tmp/
|
|||
tests/config.lua
|
||||
tests/reports/
|
||||
tests/data/185.dat
|
||||
/quicklist/
|
||||
/cutest/
|
||||
/critbit/
|
||||
|
|
|
@ -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>
|
||||
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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">
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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">
|
||||
|
|
|
@ -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">
|
||||
|
|
|
@ -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"/>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
<?xml version="1.0"?>
|
||||
<resource name="mallornseed" limited="yes">
|
||||
<resource name="mallornseed">
|
||||
<item weight="10" score="100"/>
|
||||
</resource>
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
<?xml version="1.0"?>
|
||||
<resource name="seed" limited="yes">
|
||||
<resource name="seed">
|
||||
<item weight="10" score="50"/>
|
||||
</resource>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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">
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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 -->
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -1,3 +0,0 @@
|
|||
<?xml version="1.0" ?>
|
||||
<items>
|
||||
</items>
|
|
@ -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")
|
||||
|
|
|
@ -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")
|
||||
|
||||
|
|
|
@ -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")
|
||||
|
|
54
src/battle.c
54
src/battle.c
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -47,7 +47,6 @@
|
|||
|
||||
#include <attributes/attributes.h>
|
||||
#include <triggers/triggers.h>
|
||||
#include <items/itemtypes.h>
|
||||
|
||||
#include <util/log.h>
|
||||
#include <util/unicode.h>
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -5,10 +5,7 @@ xerewards.test.c
|
|||
)
|
||||
|
||||
SET(_FILES
|
||||
artrewards.c
|
||||
demonseye.c
|
||||
itemtypes.c
|
||||
seed.c
|
||||
speedsail.c
|
||||
weapons.c
|
||||
xerewards.c
|
||||
|
|
|
@ -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");
|
||||
}
|
|
@ -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
|
|
@ -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();
|
||||
}
|
|
@ -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
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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
|
|
@ -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 */
|
||||
|
|
|
@ -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)
|
||||
static const int castle_bonus[6] = { 0, 1, 3, 5, 8, 12 };
|
||||
static const int watch_bonus[3] = { 0, 1, 2 };
|
||||
|
||||
int building_protection(const building_type * btype, int stage)
|
||||
{
|
||||
int i = 0;
|
||||
int bsize = buildingeffsize(b, false);
|
||||
const construction *cons = b->type->construction;
|
||||
if (!cons) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < bsize; i++)
|
||||
{
|
||||
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");
|
||||
|
|
|
@ -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;
|
||||
|
@ -85,8 +78,8 @@ extern "C" {
|
|||
extern struct selist *buildingtypes;
|
||||
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 cmp_castle_size(const struct building *b, const struct building *a);
|
||||
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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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: */
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
88
src/magic.c
88
src/magic.c
|
@ -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];
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------- */
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
80
src/util/variant.c
Normal 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;
|
||||
}
|
|
@ -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
40
src/util/variant.test.c
Normal 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;
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue