diff --git a/res/core/spells.xml b/res/core/spells.xml index cb7fcf911..59d06a522 100644 --- a/res/core/spells.xml +++ b/res/core/spells.xml @@ -10,14 +10,12 @@ <!-- shared spells --> <spell name="create_roi" ship="true" rank="5" index="130"> - <function name="cast" value="lua_castspell"/> <resource name="aura" amount="50" cost="fixed"/> <resource name="money" amount="3000" cost="fixed"/> <resource name="permaura" amount="1" cost="fixed"/> </spell> <spell name="create_aots" ship="true" rank="5" index="125"> - <function name="cast" value="lua_castspell"/> <resource name="aura" amount="50" cost="fixed"/> <resource name="money" amount="3000" cost="fixed"/> <resource name="permaura" amount="1" cost="fixed"/> @@ -25,12 +23,10 @@ <!-- draig spells --> <spell name="earn_silver#draig" ship="true" variable="true" rank="5" index="159"> - <function name="cast" value="lua_castspell"/> <resource name="aura" amount="1" cost="level"/> </spell> <spell name="create_firesword" ship="true" rank="5" index="148"> - <function name="cast" value="lua_castspell"/> <resource name="aura" amount="100" cost="fixed"/> <resource name="p10" amount="1" cost="fixed"/> <resource name="sword" amount="1" cost="fixed"/> @@ -38,19 +34,16 @@ </spell> <spell name="create_trollbelt" ship="true" rank="5" index="48"> - <function name="cast" value="lua_castspell"/> <resource name="aura" amount="20" cost="fixed"/> <resource name="permaura" amount="1" cost="fixed"/> </spell> <!-- gwyrrd spells --> <spell name="earn_silver#gwyrrd" ship="true" variable="true" rank="5" index="159"> - <function name="cast" value="lua_castspell"/> <resource name="aura" amount="1" cost="level"/> </spell> <spell name="create_magicherbbag" ship="true" rank="5" index="165"> - <function name="cast" value="lua_castspell"/> <resource name="aura" amount="30" cost="fixed"/> <resource name="permaura" amount="1" cost="fixed"/> <resource name="p2" amount="1" cost="fixed"/> @@ -58,18 +51,15 @@ <!-- illaun spells --> <spell name="earn_silver#illaun" ship="true" variable="true" rank="5" index="159"> - <function name="cast" value="lua_castspell"/> <resource name="aura" amount="1" cost="level"/> </spell> <spell name="create_dreameye" ship="true" rank="5" index="149"> - <function name="cast" value="lua_castspell"/> <resource name="dragonhead" amount="1" cost="fixed"/> <resource name="permaura" amount="5" cost="fixed"/> </spell> <spell name="create_invisibility_sphere" ship="true" rank="5" index="178"> - <function name="cast" value="lua_castspell"/> <resource name="aura" amount="150" cost="fixed"/> <resource name="money" amount="30000" cost="fixed"/> <resource name="permaura" amount="3" cost="fixed"/> @@ -77,12 +67,10 @@ <!-- cerddor spells --> <spell name="earn_silver#cerddor" ship="true" variable="true" rank="5" index="159"> - <function name="cast" value="lua_castspell"/> <resource name="aura" amount="1" cost="level"/> </spell> <spell name="create_roqf" ship="true" rank="5" index="63"> - <function name="cast" value="lua_castspell"/> <resource name="aura" amount="20" cost="fixed"/> <resource name="money" amount="1000" cost="fixed"/> <resource name="permaura" amount="1" cost="fixed"/> @@ -90,25 +78,21 @@ <!-- tybied spells --> <spell name="earn_silver#tybied" ship="true" variable="true" rank="5" index="159"> - <function name="cast" value="lua_castspell"/> <resource name="aura" amount="1" cost="level"/> </spell> <spell name="create_antimagic" ship="true" rank="5" index="38"> - <function name="cast" value="lua_castspell"/> <resource name="aura" amount="50" cost="fixed"/> <resource name="money" amount="3000" cost="fixed"/> </spell> <spell name="create_rop" ship="true" rank="5" index="1"> - <function name="cast" value="lua_castspell"/> <resource name="aura" amount="100" cost="fixed"/> <resource name="permaura" amount="1" cost="fixed"/> <resource name="money" amount="4000" cost="fixed"/> </spell> <spell name="create_bagofholding" ship="true" rank="5" index="155"> - <function name="cast" value="lua_castspell"/> <resource name="aura" amount="30" cost="fixed"/> <resource name="permaura" amount="1" cost="fixed"/> <resource name="money" amount="5000" cost="fixed"/> @@ -116,7 +100,6 @@ <!-- gray magic --> <spell name="create_runesword" ship="true" rank="5" index="135"> - <function name="cast" value="lua_castspell"/> <resource name="aura" amount="100" cost="fixed"/> <resource name="permaura" amount="1" cost="fixed"/> <resource name="money" amount="1000" cost="fixed"/> @@ -124,20 +107,17 @@ </spell> <spell name="create_chastitybelt" ship="true" rank="5" index="134"> - <function name="cast" value="lua_castspell"/> <resource name="aura" amount="50" cost="fixed"/> <resource name="permaura" amount="1" cost="fixed"/> <resource name="money" amount="3000" cost="fixed"/> </spell> <spell name="create_focus" ship="true" rank="5" index="2"> - <function name="cast" value="lua_castspell"/> <resource name="aura" amount="100" cost="fixed"/> <resource name="permaura" amount="1" cost="fixed"/> </spell> <spell name="create_ror" ship="true" rank="5" index="3"> - <function name="cast" value="lua_castspell"/> <resource name="aura" amount="100" cost="fixed"/> <resource name="permaura" amount="1" cost="fixed"/> </spell> diff --git a/res/e3a/spells.xml b/res/e3a/spells.xml index 74eb89146..80d9e6260 100644 --- a/res/e3a/spells.xml +++ b/res/e3a/spells.xml @@ -10,14 +10,12 @@ <!-- shared spells --> <spell name="create_roi" ship="true" rank="5" index="130"> - <function name="cast" value="lua_castspell"/> <resource name="aura" amount="50" cost="fixed"/> <resource name="money" amount="3000" cost="fixed"/> <resource name="permaura" amount="1" cost="fixed"/> </spell> <spell name="create_aots" ship="true" rank="5" index="125"> - <function name="cast" value="lua_castspell"/> <resource name="aura" amount="50" cost="fixed"/> <resource name="money" amount="3000" cost="fixed"/> <resource name="permaura" amount="1" cost="fixed"/> @@ -39,7 +37,6 @@ </spell> <spell name="earn_silver#illaun" ship="true" variable="true" rank="5" index="159"> <!-- Wahrsagen --> - <function name="cast" value="lua_castspell"/> <resource name="aura" amount="1" cost="level"/> </spell> <spell name="flee" rank="5" index="20" variable="true" combat="1"> @@ -106,7 +103,6 @@ </spell> <spell name="create_dreameye" ship="true" rank="5" index="149"> <!-- Erschaffe ein Traumauge --> - <function name="cast" value="lua_castspell"/> <resource name="dragonhead" amount="1" cost="fixed"/> <resource name="permaura" amount="5" cost="fixed"/> </spell> @@ -119,7 +115,6 @@ </spell> <spell name="earn_silver#draig" ship="true" variable="true" rank="5" index="159"> <!-- Kleine Flüche --> - <function name="cast" value="lua_castspell"/> <resource name="aura" amount="1" cost="level"/> </spell> <spell name="fireball" rank="5" index="4" variable="true" combat="2"> @@ -189,7 +184,6 @@ </spell> <spell name="create_firesword" ship="true" rank="5" index="148"> <!-- Erschaffe ein Flammenschwert --> - <function name="cast" value="lua_castspell"/> <resource name="aura" amount="100" cost="fixed"/> <resource name="oil" amount="10" cost="fixed"/> <resource name="sword" amount="1" cost="fixed"/> @@ -205,7 +199,6 @@ <!-- new cerddor --> <spell name="earn_silver#cerddor" ship="true" variable="true" rank="5" index="159"> <!-- Gaukeleien --> - <function name="cast" value="lua_castspell"/> <resource name="aura" amount="1" cost="level"/> </spell> <spell name="song_of_healing" rank="5" index="10" variable="true" combat="3"> @@ -269,7 +262,6 @@ </spell> <spell name="create_roqf" ship="true" rank="5" index="63"> <!-- Miriams flinke Finger --> - <function name="cast" value="lua_castspell"/> <resource name="aura" amount="20" cost="fixed"/> <resource name="money" amount="1000" cost="fixed"/> <resource name="permaura" amount="1" cost="fixed"/> @@ -304,12 +296,11 @@ <!-- new gwyrrd --> <spell name="blessedharvest" rank="5" index="25" ship="true" far="true" variable="true"> <!-- Segen der Erde --> - <function name="cast" value="lua_castspell"/> + <function name="cast" value="cast_blessedharvest"/> <resource name="aura" amount="1" cost="level"/> </spell> <spell name="earn_silver#gwyrrd" ship="true" variable="true" rank="5" index="159"> <!-- Viehheilung --> - <function name="cast" value="lua_castspell"/> <resource name="aura" amount="1" cost="level"/> </spell> <spell name="stonegolem" rank="4" index="32" variable="true"> @@ -394,21 +385,18 @@ <!-- new tybied - spells known to all schools --> <spell name="create_potion_p2" ship="true" rank="5" variable="true"> <!-- Wasser des Lebens --> - <function name="cast" value="lua_castspell"/> <resource name="aura" amount="2" cost="linear"/> <resource name="h4" amount="1" cost="linear"/><!-- Baumringel --> <resource name="h6" amount="1" cost="linear"/><!-- Gurgelkraut --> </spell> <spell name="create_potion_p0" ship="true" rank="5" variable="true"> <!-- Siebenmeilentee --> - <function name="cast" value="lua_castspell"/> <resource name="aura" amount="2" cost="linear"/> <resource name="h12" amount="1" cost="linear"/><!-- Windbeutel --> <resource name="h17" amount="1" cost="linear"/><!-- Höhlenglimm --> </spell> <spell name="create_potion_p9" ship="true" rank="5" variable="true"> <!-- Pferdeglück --> - <function name="cast" value="lua_castspell"/> <resource name="aura" amount="3" cost="linear"/> <resource name="h0" amount="1" cost="linear"/><!-- Flachwurz --> <resource name="h8" amount="1" cost="linear"/><!-- Blasenmorchel --> @@ -416,7 +404,6 @@ </spell> <spell name="create_potion_peasantblood" ship="true" rank="5" variable="true"> <!-- Bauernblut --> - <function name="cast" value="lua_castspell"/> <resource name="aura" amount="3" cost="linear"/> <resource name="h14" amount="1" cost="linear"/><!-- Alraune --> <resource name="h6" amount="1" cost="linear"/><!-- Gurgelkraut --> @@ -426,7 +413,6 @@ <spell name="create_potion_ointment" ship="true" rank="5" variable="true"> <!-- Wundsalbe --> - <function name="cast" value="lua_castspell"/> <resource name="aura" amount="4" cost="linear"/> <resource name="h4" amount="1" cost="linear"/><!-- Baumringel --> <resource name="h15" amount="1" cost="linear"/><!-- Steinbeißer --> @@ -435,7 +421,6 @@ </spell> <spell name="create_potion_p3" ship="true" rank="5" variable="true"> <!-- Schaffenstrunk --> - <function name="cast" value="lua_castspell"/> <resource name="aura" amount="4" cost="linear"/> <resource name="h12" amount="1" cost="linear"/><!-- Windbeutel --> <resource name="h6" amount="1" cost="linear"/><!-- Gurgelkraut --> @@ -444,7 +429,6 @@ </spell> <spell name="create_potion_p14" ship="true" rank="5" variable="true"> <!-- Heiltrank --> - <function name="cast" value="lua_castspell"/> <resource name="aura" amount="5" cost="linear"/> <resource name="h0" amount="1" cost="linear"/><!-- Flachwurz --> <resource name="h8" amount="1" cost="linear"/><!-- Blasenmorchel --> @@ -454,7 +438,6 @@ </spell> <spell name="create_potion_p13" ship="true" rank="5" variable="true"> <!-- Elixier der Macht --> - <function name="cast" value="lua_castspell"/> <resource name="aura" amount="5" cost="linear"/> <resource name="h14" amount="1" cost="linear"/><!-- Alraune --> <resource name="h8" amount="1" cost="linear"/><!-- Blasenmorchel --> @@ -472,39 +455,33 @@ <!-- common spells: randomly given, one per level --> <spell name="create_trollbelt" ship="true" rank="5" index="48"> - <function name="cast" value="lua_castspell"/> <resource name="aura" amount="20" cost="fixed"/> <resource name="permaura" amount="1" cost="fixed"/> </spell> <spell name="create_antimagic" ship="true" rank="5" index="38"> - <function name="cast" value="lua_castspell"/> <resource name="aura" amount="50" cost="fixed"/> <resource name="money" amount="3000" cost="fixed"/> </spell> <spell name="create_rop" ship="true" rank="5" index="1"> - <function name="cast" value="lua_castspell"/> <resource name="aura" amount="100" cost="fixed"/> <resource name="permaura" amount="1" cost="fixed"/> <resource name="money" amount="4000" cost="fixed"/> </spell> <spell name="create_bagofholding" ship="true" rank="5" index="155"> - <function name="cast" value="lua_castspell"/> <resource name="aura" amount="30" cost="fixed"/> <resource name="permaura" amount="1" cost="fixed"/> <resource name="money" amount="5000" cost="fixed"/> </spell> <spell name="create_focus" ship="true" rank="5" index="2"> - <function name="cast" value="lua_castspell"/> <resource name="aura" amount="100" cost="fixed"/> <resource name="permaura" amount="1" cost="fixed"/> </spell> <spell name="create_ror" ship="true" rank="5" index="3"> - <function name="cast" value="lua_castspell"/> <resource name="aura" amount="100" cost="fixed"/> <resource name="permaura" amount="1" cost="fixed"/> </spell> @@ -518,7 +495,7 @@ </spell> <spell name="raindance" rank="5" index="26" ship="true" far="true" variable="true"> <!-- Regentanz --> - <function name="cast" value="lua_castspell"/> + <function name="cast" value="cast_blessedharvest"/> <resource name="aura" amount="1" cost="level"/> </spell> <spell name="irongolem" rank="4" index="33" variable="true"> diff --git a/res/e3a/strings.xml b/res/e3a/strings.xml index 054cabfaa..eb9f48cf3 100644 --- a/res/e3a/strings.xml +++ b/res/e3a/strings.xml @@ -210,7 +210,7 @@ <string name="concealing_aura"> <text locale="de">Dieser Zauber wird die gesamte Ausrüstung der Zieleinheit für einige Zeit vor den Blicken anderer verschleiern. Der Zauber schützt nicht vor Dieben und Spionen.</text> <text locale="en">This spell will hide the whole equipment of a target unit from the looks of others. It will not protect against thieves or spies.</text> - </string> + </string> <string name="raindance"> <text locale="de">Durch dieses uralte Tanzritual ruft der Zauberkundige die Kräfte des Lebens und der Fruchtbarkeit an. Die darauf folgenden Regenfälle begünstigen das Wachstum und erhöhen die Ernteerträge einiger Bauern der Region bis der Regen wieder nachlässt.</text> <text locale="en">This ancient rite calls upon the forces of life and fertility. For the next few weeks, the peasants' harvest will be extraordinary good.</text> diff --git a/res/eressea/spells.xml b/res/eressea/spells.xml index 1d762f4bd..6b2e43a15 100644 --- a/res/eressea/spells.xml +++ b/res/eressea/spells.xml @@ -10,14 +10,12 @@ <!-- shared spells --> <spell name="create_roi" ship="true" rank="5" index="130"> - <function name="cast" value="lua_castspell"/> <resource name="aura" amount="50" cost="fixed"/> <resource name="money" amount="3000" cost="fixed"/> <resource name="permaura" amount="1" cost="fixed"/> </spell> <spell name="create_aots" ship="true" rank="5" index="125"> - <function name="cast" value="lua_castspell"/> <resource name="aura" amount="50" cost="fixed"/> <resource name="money" amount="3000" cost="fixed"/> <resource name="permaura" amount="1" cost="fixed"/> @@ -494,12 +492,10 @@ <!-- draig spells --> <spell name="earn_silver#draig" ship="true" variable="true" rank="5" index="159"> - <function name="cast" value="lua_castspell"/> <resource name="aura" amount="1" cost="level"/> </spell> <spell name="create_firesword" ship="true" rank="5" index="148"> - <function name="cast" value="lua_castspell"/> <resource name="aura" amount="100" cost="fixed"/> <resource name="p10" amount="1" cost="fixed"/> <resource name="sword" amount="1" cost="fixed"/> @@ -507,7 +503,6 @@ </spell> <spell name="create_trollbelt" ship="true" rank="5" index="48"> - <function name="cast" value="lua_castspell"/> <resource name="aura" amount="20" cost="fixed"/> <resource name="permaura" amount="1" cost="fixed"/> </spell> @@ -520,12 +515,10 @@ </spell> <spell name="earn_silver#gwyrrd" ship="true" variable="true" rank="5" index="159"> - <function name="cast" value="lua_castspell"/> <resource name="aura" amount="1" cost="level"/> </spell> <spell name="create_magicherbbag" ship="true" rank="5" index="165"> - <function name="cast" value="lua_castspell"/> <resource name="aura" amount="30" cost="fixed"/> <resource name="permaura" amount="1" cost="fixed"/> <resource name="p2" amount="1" cost="fixed"/> @@ -533,18 +526,15 @@ <!-- illaun spells --> <spell name="earn_silver#illaun" ship="true" variable="true" rank="5" index="159"> - <function name="cast" value="lua_castspell"/> <resource name="aura" amount="1" cost="level"/> </spell> <spell name="create_dreameye" ship="true" rank="5" index="149"> - <function name="cast" value="lua_castspell"/> <resource name="dragonhead" amount="1" cost="fixed"/> <resource name="permaura" amount="5" cost="fixed"/> </spell> <spell name="create_invisibility_sphere" ship="true" rank="5" index="178"> - <function name="cast" value="lua_castspell"/> <resource name="aura" amount="150" cost="fixed"/> <resource name="money" amount="30000" cost="fixed"/> <resource name="permaura" amount="3" cost="fixed"/> @@ -558,12 +548,10 @@ </spell> <spell name="earn_silver#cerddor" ship="true" variable="true" rank="5" index="159"> - <function name="cast" value="lua_castspell"/> <resource name="aura" amount="1" cost="level"/> </spell> <spell name="create_roqf" ship="true" rank="5" index="63"> - <function name="cast" value="lua_castspell"/> <resource name="aura" amount="20" cost="fixed"/> <resource name="money" amount="1000" cost="fixed"/> <resource name="permaura" amount="1" cost="fixed"/> @@ -583,25 +571,21 @@ <!-- tybied spells --> <spell name="earn_silver#tybied" ship="true" variable="true" rank="5" index="159"> - <function name="cast" value="lua_castspell"/> <resource name="aura" amount="1" cost="level"/> </spell> <spell name="create_antimagic" ship="true" rank="5" index="38"> - <function name="cast" value="lua_castspell"/> <resource name="aura" amount="50" cost="fixed"/> <resource name="money" amount="3000" cost="fixed"/> </spell> <spell name="create_rop" ship="true" rank="5" index="1"> - <function name="cast" value="lua_castspell"/> <resource name="aura" amount="100" cost="fixed"/> <resource name="permaura" amount="1" cost="fixed"/> <resource name="money" amount="4000" cost="fixed"/> </spell> <spell name="create_bagofholding" ship="true" rank="5" index="155"> - <function name="cast" value="lua_castspell"/> <resource name="aura" amount="30" cost="fixed"/> <resource name="permaura" amount="1" cost="fixed"/> <resource name="money" amount="5000" cost="fixed"/> @@ -609,7 +593,6 @@ <!-- gray magic --> <spell name="create_runesword" ship="true" rank="5" index="135"> - <function name="cast" value="lua_castspell"/> <resource name="aura" amount="100" cost="fixed"/> <resource name="permaura" amount="1" cost="fixed"/> <resource name="money" amount="1000" cost="fixed"/> @@ -617,20 +600,17 @@ </spell> <spell name="create_chastitybelt" ship="true" rank="5" index="134"> - <function name="cast" value="lua_castspell"/> <resource name="aura" amount="50" cost="fixed"/> <resource name="permaura" amount="1" cost="fixed"/> <resource name="money" amount="3000" cost="fixed"/> </spell> <spell name="create_focus" ship="true" rank="5" index="2"> - <function name="cast" value="lua_castspell"/> <resource name="aura" amount="100" cost="fixed"/> <resource name="permaura" amount="1" cost="fixed"/> </spell> <spell name="create_ror" ship="true" rank="5" index="3"> - <function name="cast" value="lua_castspell"/> <resource name="aura" amount="100" cost="fixed"/> <resource name="permaura" amount="1" cost="fixed"/> </spell> diff --git a/scripts/eressea/e3/init.lua b/scripts/eressea/e3/init.lua index e376eaadc..f7402268c 100644 --- a/scripts/eressea/e3/init.lua +++ b/scripts/eressea/e3/init.lua @@ -1,4 +1,3 @@ -require 'eressea.e3.rules' require 'eressea.spells' eressea.log.debug("rules for game E3") diff --git a/scripts/eressea/e3/rules.lua b/scripts/eressea/e3/rules.lua deleted file mode 100644 index e49e03438..000000000 --- a/scripts/eressea/e3/rules.lua +++ /dev/null @@ -1,35 +0,0 @@ --- the "raindance" spell -function raindance(r, mage, level, force) - if (create_curse(mage, r, "blessedharvest", force, 1+force*2, 100 * force)) then - -- slightly crooked way of reporting an action to everyone in the region - local msg = message.create("raindance_effect") - msg:set_unit("mage", mage) - if (msg:report_action(r, mage, 3)) then - local msg2 = message.create("raindance_effect") - msg2:set_unit("mage", nil) - msg2:report_action(r, mage, 4) - end - end - return level -end - --- the "blessed harvest" spell -function blessedharvest(r, mage, level, force) - if create_curse(mage, r, "blessedharvest", force, 1+force*2, 50 * force) then - -- slightly crooked way of reporting an action to everyone in the region - local msg = message.create("harvest_effect") - msg:set_unit("mage", mage) - if (msg:report_action(r, mage, 3)) then - local msg2 = message.create("harvest_effect") - msg2:set_unit("mage", nil) - msg2:report_action(r, mage, 4) - end - for idx, rn in ipairs(r.adj) do - -- nur landregionen haben moral>=0 - if r.morale>=0 then - create_curse(mage, r, "blessedharvest", force, force*2, 50 * force) - end - end - end - return level -end diff --git a/scripts/run-tests-e2.lua b/scripts/run-tests-e2.lua index 4a2b3e59e..27617592f 100644 --- a/scripts/run-tests-e2.lua +++ b/scripts/run-tests-e2.lua @@ -17,6 +17,7 @@ require 'eressea.path' require 'tests.e2' require 'lunit' +rng.inject(0) rules = require('eressea.' .. config.rules) result = lunit.main() return result.errors + result.failed diff --git a/scripts/run-tests-e3.lua b/scripts/run-tests-e3.lua index 47bcca60b..0aefb5d3a 100644 --- a/scripts/run-tests-e3.lua +++ b/scripts/run-tests-e3.lua @@ -17,6 +17,7 @@ require 'eressea.xmlconf' require 'tests.e3' require 'lunit' +rng.inject(0) eressea.settings.set("rules.alliances", "0") rules = require('eressea.' .. config.rules) result = lunit.main() diff --git a/scripts/tests/common.lua b/scripts/tests/common.lua index 08a7ca94f..e612a17d7 100644 --- a/scripts/tests/common.lua +++ b/scripts/tests/common.lua @@ -218,6 +218,9 @@ function test_gmtool() local r1 = region.create(1, 0, "plain") local r2 = region.create(1, 1, "plain") local r3 = region.create(1, 2, "plain") + if not gmtool then + return + end gmtool.open() gmtool.select(r1, true) gmtool.select_at(0, 1, true) diff --git a/scripts/tests/e2/init.lua b/scripts/tests/e2/init.lua index 46afc966a..7fbc0eb95 100644 --- a/scripts/tests/e2/init.lua +++ b/scripts/tests/e2/init.lua @@ -1,3 +1,4 @@ +require 'tests.e2.spells' require 'tests.e2.buildings' require 'tests.e2.production' require 'tests.e2.adamantium' @@ -7,7 +8,6 @@ require 'tests.e2.e2features' require 'tests.e2.movement' require 'tests.e2.destroy' require 'tests.e2.guard' -require 'tests.e2.spells' require 'tests.e2.stealth' require 'tests.e2.items' require 'tests.items' @@ -20,3 +20,4 @@ require 'tests.magicbag' require 'tests.process' require 'tests.xmas' require 'tests.production' +require 'tests.spells' diff --git a/scripts/tests/e2/spells.lua b/scripts/tests/e2/spells.lua index 107b20232..fc1e3bc3b 100644 --- a/scripts/tests/e2/spells.lua +++ b/scripts/tests/e2/spells.lua @@ -8,6 +8,7 @@ function setup() eressea.settings.set("nmr.timeout", "0") eressea.settings.set("NewbieImmunity", "0") eressea.settings.set("rules.food.flags", "4") + eressea.settings.set("rules.peasants.growth.factor", "0") end function test_shapeshift() @@ -26,3 +27,78 @@ function test_shapeshift() s = u2:show() assert_equal("1 Goblin", string.sub(s, string.find(s, "1 Goblin"))) end + +function test_raindance() + local r = region.create(0, 0, "plain") + local f = faction.create("halfling", "noreply@eressea.de", "de") + local u = unit.create(f, r) + local err = 0 + r:set_resource("peasant", 100) + r:set_resource("money", 0) + u.magic = "gwyrrd" + u.race = "dwarf" + u:set_skill("magic", 20) + u.aura = 200 + err = err + u:add_spell("raindance") + assert_equal(0, err) + + u:clear_orders() + u:add_order("ZAUBERE STUFE 1 Regentanz") + assert_equal(0, r:get_resource("money")) + + process_orders() + assert_equal(200, r:get_resource("money")) + assert_equal(0, u:get_item("money")) + + u:clear_orders() + u:add_order("ARBEITEN") + process_orders() + assert_equal(10, u:get_item("money")) -- only peasants benefit + assert_equal(400, r:get_resource("money")) + -- this is where the spell ends + process_orders() + process_orders() + assert_equal(600, r:get_resource("money")) +end + +function test_earn_silver() + local r = region.create(0, 0, "mountain") + local f = faction.create("human") + local u = unit.create(f, r) + + eressea.settings.set("rules.food.flags", "4") + eressea.settings.set("magic.fumble.enable", "0") + eressea.settings.set("rules.peasants.growth", "0") + eressea.settings.set("rules.economy.repopulate_maximum", "0") + + u.magic = "gwyrrd" + u.race = "elf" + u:set_skill("magic", 10) + u.aura = 100 + local err = u:add_spell("earn_silver#gwyrrd") + assert_equal(0, err) + + u:clear_orders() + u:add_order("ZAUBERE STUFE 1 Viehheilung") + r:set_resource("money", 350) + r:set_resource("peasant", 0) + process_orders() -- get 50 silver + assert_equal(50, u:get_item("money")) + assert_equal(300, r:get_resource("money")) + + u:clear_orders() -- get 100 silver + u:add_order("ZAUBERE STUFE 2 Viehheilung") + process_orders() + assert_equal(150, u:get_item("money")) + assert_equal(200, r:get_resource("money")) + + u:clear_orders() -- get 150 silver + u:add_order("ZAUBERE STUFE 3 Viehheilung") + process_orders() + assert_equal(300, u:get_item("money")) + assert_equal(50, r:get_resource("money")) + + process_orders() -- not enough + assert_equal(350, u:get_item("money")) + assert_equal(0, r:get_resource("money")) +end diff --git a/scripts/tests/e3/init.lua b/scripts/tests/e3/init.lua index 06e03d9b4..fc0586f89 100644 --- a/scripts/tests/e3/init.lua +++ b/scripts/tests/e3/init.lua @@ -5,11 +5,12 @@ require 'tests.e3.rules' require 'tests.e3.parser' require 'tests.e3.morale' require 'tests.e3.items' +require 'tests.e3.production' +require 'tests.spells' require 'tests.economy' require 'tests.orders' require 'tests.common' require 'tests.items' require 'tests.magicbag' require 'tests.process' -require 'tests.e3.production' require 'tests.production' diff --git a/scripts/tests/e3/spells.lua b/scripts/tests/e3/spells.lua index df9408fbd..24f97c221 100644 --- a/scripts/tests/e3/spells.lua +++ b/scripts/tests/e3/spells.lua @@ -9,39 +9,32 @@ function setup() eressea.settings.set("rules.peasants.growth", "0") end -function test_blessedharvest_lasts_n_turn() +function test_raindance() local r = region.create(0, 0, "plain") local f = faction.create("halfling", "noreply@eressea.de", "de") local u = unit.create(f, r) - local err = 0 r:set_resource("peasant", 100) r:set_resource("money", 0) - u:add_item("money", 1000) u.magic = "gwyrrd" u.race = "dwarf" u:set_skill("magic", 20) u.aura = 200 - err = err + u:add_spell("raindance") - err = err + u:add_spell("blessedharvest") + local err = u:add_spell("raindance") assert_equal(0, err) u:clear_orders() u:add_order("ZAUBERE STUFE 3 Regentanz") assert_equal(0, r:get_resource("money"), 0) - local m = 0 - local p = 100 - process_orders() assert_equal(200, r:get_resource("money")) u:clear_orders() u:add_order("ARBEITEN") process_orders() process_orders() + assert_equal(500, r:get_resource("money")) process_orders() - assert_equal(800, r:get_resource("money")) - process_orders() - assert_equal(900, r:get_resource("money")) + assert_equal(600, r:get_resource("money")) end function test_magic() @@ -64,3 +57,46 @@ function test_magic() -- there used to be a SEGFAULT when writing reports here: -- write_reports() end + +-- E3: earn 50 per every TWO levels of spell +function test_earn_silver() + local r = region.create(0, 0, "mountain") + local f = faction.create("human") + local u = unit.create(f, r) + + eressea.settings.set("rules.food.flags", "4") + eressea.settings.set("magic.fumble.enable", "0") + eressea.settings.set("rules.peasants.growth", "0") + eressea.settings.set("rules.economy.repopulate_maximum", "0") + + u.magic = "gwyrrd" + u.race = "elf" + u:set_skill("magic", 10) + u.aura = 100 + local err = u:add_spell("earn_silver#gwyrrd") + assert_equal(0, err) + + u:clear_orders() + u:add_order("ZAUBERE STUFE 1 Viehheilung") + r:set_resource("money", 200) + r:set_resource("peasant", 0) + process_orders() -- get 50 silver + assert_equal(50, u:get_item("money")) + assert_equal(150, r:get_resource("money")) + + u:clear_orders() -- get 50 silver + u:add_order("ZAUBERE STUFE 2 Viehheilung") + process_orders() + assert_equal(100, u:get_item("money")) + assert_equal(100, r:get_resource("money")) + + u:clear_orders() -- get 75 silver + u:add_order("ZAUBERE STUFE 3 Viehheilung") + process_orders() + assert_equal(175, u:get_item("money")) + assert_equal(25, r:get_resource("money")) + + process_orders() -- not enough + assert_equal(200, u:get_item("money")) + assert_equal(0, r:get_resource("money")) +end diff --git a/scripts/tests/production.lua b/scripts/tests/production.lua index b470a2652..8727762d1 100644 --- a/scripts/tests/production.lua +++ b/scripts/tests/production.lua @@ -6,6 +6,7 @@ function setup() eressea.game.reset() eressea.settings.set("rules.food.flags", "4") -- food is free eressea.settings.set("NewbieImmunity", "0") + eressea.settings.set("study.random_progress", "0") end local function create_faction(race) diff --git a/scripts/tests/spells.lua b/scripts/tests/spells.lua new file mode 100644 index 000000000..e3c0a3021 --- /dev/null +++ b/scripts/tests/spells.lua @@ -0,0 +1,83 @@ +require 'lunit' +module("tests.spells", package.seeall, lunit.testcase) + +function setup() + eressea.free_game() + eressea.settings.set("nmr.removenewbie", "0") + eressea.settings.set("nmr.timeout", "0") + eressea.settings.set("NewbieImmunity", "0") + eressea.settings.set("rules.food.flags", "4") + eressea.settings.set("rules.encounters", "0") + eressea.settings.set("magic.regeneration.enable", "0") +end + +function test_create_bogus() + local r = region.create(0, 0, "plain") + local f = faction.create("human") + local u = unit.create(f, r, 1) + u.race = "elf" + u:set_skill("magic", 10) + u.magic = 'gwyrrd' + u:clear_orders() + u:add_order("ZAUBERE 'Erschaffe Katastrophe'") + process_orders() + assert_equal(f.messages[3], 'error173') -- HACKity HACK +end + +function test_create_roi() + local r = region.create(0, 0, "plain") + local f = faction.create("human") + local u = unit.create(f, r, 1) + u.race = "elf" + u:set_skill("magic", 10) + u.magic = 'gwyrrd' + u.aura = 100 + u:add_item("money", 3000) + u:add_spell("create_roi") + u:clear_orders() + u:add_order("ZAUBERE 'Erschaffe einen Ring der Unsichtbarkeit'") + local amax = u.aura_max + process_orders() + assert_equal(1, u:get_item("roi")) + assert_equal(50, u.aura) + assert_equal(amax - 1, u.aura_max) +end + +function test_create_aots() + local r = region.create(0, 0, "plain") + local f = faction.create("human") + local u = unit.create(f, r, 1) + u.race = "elf" + u:set_skill("magic", 10) + u.magic = 'gwyrrd' + u.aura = 100 + u:add_item("money", 3000) + u:add_spell("create_aots") + u:clear_orders() + u:add_order("ZAUBERE 'Erschaffe ein Amulett des wahren Sehens'") + local amax = u.aura_max + process_orders() + assert_equal(1, u:get_item("aots")) + assert_equal(50, u.aura) + assert_equal(amax - 1, u.aura_max) +end + +function test_create_dreameye() + local r = region.create(0, 0, "plain") + local f = faction.create("human") + local u = unit.create(f, r, 1) + u.race = "elf" + u:set_skill("magic", 10) + u.magic = 'gwyrrd' + u.aura = 100 + u:add_item("dragonhead", 1) + u:add_spell("create_dreameye") + u:clear_orders() + u:add_order("ZAUBERE 'Erschaffe ein Traumauge'") + local amax = u.aura_max + process_orders() + assert_equal(1, u:get_item("dreameye")) + assert_equal(100, u.aura) + assert_equal(amax - 5, u.aura_max) +end + diff --git a/src/battle.c b/src/battle.c index fce3d3049..19f30e59c 100644 --- a/src/battle.c +++ b/src/battle.c @@ -1205,11 +1205,12 @@ terminate(troop dt, troop at, int type, const char *damage, bool missile) if (type != AT_COMBATSPELL && type != AT_SPELL) { if (rule_damage & DAMAGE_CRITICAL) { double kritchance = (sk * 3 - sd) / 200.0; + int maxk = 4; kritchance = MAX(kritchance, 0.005); kritchance = MIN(0.9, kritchance); - while (chance(kritchance)) { + while (maxk-- && chance(kritchance)) { da += dice_rand(damage); } } @@ -1749,15 +1750,9 @@ void do_combatmagic(battle * b, combatmagic_t was) fighter *fig = co->magician.fig; const spell *sp = co->sp; - level = co->level; - if (!sp->cast) { - log_error("spell '%s' has no function.\n", sp->sname); - } - else { - level = sp->cast(co); - if (level > 0) { - pay_spell(fig->unit, sp, level, 1); - } + level = cast_spell(co); + if (level > 0) { + pay_spell(fig->unit, sp, level, 1); } } } @@ -1771,7 +1766,7 @@ static int cast_combatspell(troop at, const spell * sp, int level, double force) castorder co; create_castorder_combat(&co, at.fighter, sp, level, force); - level = sp->cast(&co); + level = cast_spell(&co); free_castorder(&co); if (level > 0) { pay_spell(at.fighter->unit, sp, level, 1); @@ -1840,12 +1835,7 @@ static void do_combatspell(troop at) return; } - if (!sp->cast) { - log_error("spell '%s' has no function.\n", sp->sname); - } - else { - level = cast_combatspell(at, sp, level, power); - } + level = cast_combatspell(at, sp, level, power); } /* Sonderattacken: Monster patzern nicht und zahlen auch keine @@ -1860,9 +1850,6 @@ static void do_extra_spell(troop at, const att * a) if (!sp) { log_error("no such spell: '%s'", a->data.sp->name); } - else if (sp->cast == NULL) { - log_error("spell '%s' has no function.", sp->sname); - } else { assert(a->level > 0); cast_combatspell(at, sp, a->level, a->level); diff --git a/src/bind_faction.c b/src/bind_faction.c index d16f15936..f9321f6b5 100644 --- a/src/bind_faction.c +++ b/src/bind_faction.c @@ -268,6 +268,23 @@ static int tolua_faction_setkey(lua_State * L) return 0; } +static int tolua_faction_get_messages(lua_State * L) +{ + faction *self = (faction *)tolua_tousertype(L, 1, 0); + int i = 1; + mlist *ml; + if (!self->msgs) { + return 0; + } + lua_newtable(L); + for (ml = self->msgs->begin; ml; ml = ml->next, ++i) { + lua_pushnumber(L, i); + lua_pushstring(L, ml->msg->type->name); + lua_rawset(L, -3); + } + return 1; +} + static int tolua_faction_count_msg_type(lua_State *L) { faction *self = (faction *)tolua_tousertype(L, 1, 0); const char *str = tolua_tostring(L, 2, 0); @@ -637,6 +654,7 @@ void tolua_faction_open(lua_State * L) /* tech debt hack, siehe https://paper.dropbox.com/doc/Weihnachten-2015-5tOx5r1xsgGDBpb0gILrv#:h=Probleme-mit-Tests-(Nachtrag-0 */ tolua_function(L, TOLUA_CAST "count_msg_type", tolua_faction_count_msg_type); + tolua_variable(L, TOLUA_CAST "messages", tolua_faction_get_messages, NULL); tolua_function(L, TOLUA_CAST "get_key", tolua_faction_getkey); tolua_function(L, TOLUA_CAST "set_key", tolua_faction_setkey); diff --git a/src/bind_unit.c b/src/bind_unit.c index b95f43d4a..1d6579b0e 100644 --- a/src/bind_unit.c +++ b/src/bind_unit.c @@ -193,6 +193,13 @@ static int tolua_unit_set_id(lua_State * L) return 0; } +static int tolua_unit_get_auramax(lua_State * L) +{ + unit *self = (unit *)tolua_tousertype(L, 1, 0); + lua_pushinteger(L, max_spellpoints(self->region, self)); + return 1; +} + static int tolua_unit_get_hpmax(lua_State * L) { unit *self = (unit *)tolua_tousertype(L, 1, 0); @@ -512,15 +519,10 @@ static void unit_castspell(unit * u, const char *name, int level) if (sp) { spellbook *book = unit_get_spellbook(u); if (spellbook_get(book, sp)) { - if (!sp->cast) { - log_error("spell '%s' has no function.\n", sp->sname); - } - else { - castorder co; - create_castorder(&co, u, 0, sp, u->region, level, (double)level, 0, 0, 0); - sp->cast(&co); - free_castorder(&co); - } + castorder co; + create_castorder(&co, u, 0, sp, u->region, level, (double)level, 0, 0, 0); + cast_spell(&co); + free_castorder(&co); } } } @@ -1038,6 +1040,7 @@ void tolua_unit_open(lua_State * L) tolua_variable(L, TOLUA_CAST "race", &tolua_unit_get_race, tolua_unit_set_race); tolua_variable(L, TOLUA_CAST "hp_max", &tolua_unit_get_hpmax, 0); + tolua_variable(L, TOLUA_CAST "aura_max", &tolua_unit_get_auramax, 0); tolua_function(L, TOLUA_CAST "show", &tolua_bufunit); } diff --git a/src/bindings.c b/src/bindings.c index 1d6270b35..2ea6f1657 100755 --- a/src/bindings.c +++ b/src/bindings.c @@ -92,6 +92,20 @@ TOLUA_PKG(locale); TOLUA_PKG(log); TOLUA_PKG(game); +int tolua_toid(lua_State * L, int idx, int def) +{ + int no = 0; + int type = lua_type(L, idx); + if (type == LUA_TNUMBER) { + no = (int)tolua_tonumber(L, idx, def); + } + else { + const char *str = tolua_tostring(L, idx, NULL); + no = str ? atoi36(str) : def; + } + return no; +} + int log_lua_error(lua_State * L) { const char *error = lua_tostring(L, -1); @@ -217,7 +231,7 @@ static int tolua_setkey(lua_State * L) return 0; } -static int tolua_rng_int(lua_State * L) +static int tolua_random(lua_State * L) { lua_pushinteger(L, rng_int()); return 1; @@ -976,6 +990,12 @@ static void parse_inifile(lua_State * L, const dictionary * d, const char *secti } } +static int lua_rng_default(lua_State *L) { + UNUSED_ARG(L); + random_source_inject_constant(0); + return 0; +} + void tolua_bind_open(lua_State * L); int tolua_bindings_open(lua_State * L, const dictionary *inifile) @@ -997,6 +1017,14 @@ int tolua_bindings_open(lua_State * L, const dictionary *inifile) tolua_module(L, NULL, 0); tolua_beginmodule(L, NULL); { + tolua_module(L, TOLUA_CAST "rng", 1); + tolua_beginmodule(L, TOLUA_CAST "rng"); + { + tolua_function(L, TOLUA_CAST "inject", lua_rng_default); + tolua_function(L, TOLUA_CAST "random", tolua_random); + } + tolua_endmodule(L); + tolua_function(L, TOLUA_CAST "rng_int", tolua_random); tolua_cclass(L, TOLUA_CAST "alliance", TOLUA_CAST "alliance", TOLUA_CAST "", NULL); tolua_beginmodule(L, TOLUA_CAST "alliance"); @@ -1086,7 +1114,6 @@ int tolua_bindings_open(lua_State * L, const dictionary *inifile) tolua_function(L, TOLUA_CAST "get_key", tolua_getkey); tolua_function(L, TOLUA_CAST "set_key", tolua_setkey); tolua_function(L, TOLUA_CAST "translate", &tolua_translate); - tolua_function(L, TOLUA_CAST "rng_int", tolua_rng_int); tolua_function(L, TOLUA_CAST "spells", tolua_get_spells); tolua_function(L, TOLUA_CAST "read_xml", tolua_read_xml); } tolua_endmodule(L); diff --git a/src/bindings.h b/src/bindings.h index 354bb199a..5cb64a038 100755 --- a/src/bindings.h +++ b/src/bindings.h @@ -18,6 +18,7 @@ extern "C" { struct _dictionary_; struct selist; + int tolua_toid(struct lua_State *L, int idx, int def); int tolua_sqlite_open(struct lua_State *L); int tolua_bindings_open(struct lua_State *L, const struct _dictionary_ *d); int tolua_itemlist_next(struct lua_State *L); diff --git a/src/economy.c b/src/economy.c index 1a4cc5b18..48653d0aa 100644 --- a/src/economy.c +++ b/src/economy.c @@ -2658,8 +2658,7 @@ expandwork(region * r, request * work_begin, request * work_end, int maxwork) const curse_type *blessedharvest_ct = ct_find("blessedharvest"); if (blessedharvest_ct) { int happy = - (int)curse_geteffect(get_curse(r->attribs, blessedharvest_ct)); - happy = MIN(happy, jobs); + (int)(jobs * curse_geteffect(get_curse(r->attribs, blessedharvest_ct))); earnings += happy; } } diff --git a/src/helpers.c b/src/helpers.c index 59695e9b4..ab59ea60c 100644 --- a/src/helpers.c +++ b/src/helpers.c @@ -18,12 +18,15 @@ without prior permission by the authors of Eressea. #include <util/attrib.h> #include <util/base36.h> #include <util/bsdstring.h> +#include <util/event.h> #include <util/functions.h> #include <util/log.h> #include <util/parser.h> #include <util/resolve.h> +#include <kernel/callbacks.h> #include <kernel/config.h> +#include <kernel/callbacks.h> #include <kernel/equipment.h> #include <kernel/faction.h> #include <kernel/spell.h> @@ -156,23 +159,12 @@ static void push_param(lua_State * L, char c, spllprm * param) } /** callback to use lua for spell functions */ -static int lua_callspell(castorder * co) +static int lua_callspell(castorder * co, const char *fname) { lua_State *L = (lua_State *)global.vm_state; - const char *fname = co->sp->sname; unit *caster = co_get_caster(co); region * r = co_get_region(co); int result = -1; - const char *hashpos = strchr(fname, '#'); - char fbuf[64]; - - if (hashpos != NULL) { - ptrdiff_t len = hashpos - fname; - assert(len < (ptrdiff_t) sizeof(fbuf)); - memcpy(fbuf, fname, len); - fbuf[len] = '\0'; - fname = fbuf; - } lua_getglobal(L, fname); if (lua_isfunction(L, -1)) { @@ -455,41 +447,39 @@ use_item_lua(unit *u, const item_type *itype, int amount, struct order *ord) return result; } -int tolua_toid(lua_State * L, int idx, int def) + +/* compat code for old data files */ +static int caldera_read(trigger *t, struct gamedata *data) { - int no = 0; - int type = lua_type(L, idx); - if (type == LUA_TNUMBER) { - no = (int)tolua_tonumber(L, idx, def); - } - else { - const char *str = tolua_tostring(L, idx, NULL); - no = str ? atoi36(str) : def; - } - return no; + UNUSED_ARG(t); + read_building_reference(data); + return AT_READ_FAIL; } +struct trigger_type tt_caldera = { + "caldera", + NULL, NULL, NULL, NULL, + caldera_read +}; + void register_tolua_helpers(void) { + tt_register(&tt_caldera); at_register(&at_direction); at_register(&at_building_action); - register_function((pf_generic)lua_callspell, TOLUA_CAST "lua_castspell"); - register_function((pf_generic)lua_initfamiliar, - TOLUA_CAST "lua_initfamiliar"); - register_function((pf_generic)lua_getresource, - TOLUA_CAST "lua_getresource"); - register_function((pf_generic)lua_changeresource, - TOLUA_CAST "lua_changeresource"); - register_function((pf_generic)lua_equipmentcallback, - TOLUA_CAST "lua_equip"); + callbacks.cast_spell = lua_callspell; - register_function((pf_generic)lua_wage, TOLUA_CAST "lua_wage"); - register_function((pf_generic)lua_maintenance, - TOLUA_CAST "lua_maintenance"); + register_function((pf_generic)lua_initfamiliar, "lua_initfamiliar"); + register_function((pf_generic)lua_getresource, "lua_getresource"); + register_function((pf_generic)lua_changeresource, "lua_changeresource"); + register_function((pf_generic)lua_equipmentcallback, "lua_equip"); + + register_function((pf_generic)lua_wage, "lua_wage"); + register_function((pf_generic)lua_maintenance, "lua_maintenance"); item_use_fun = use_item_lua; res_produce_fun = produce_resource_lua; res_limit_fun = limit_resource_lua; - register_item_give(lua_giveitem, TOLUA_CAST "lua_giveitem"); + register_item_give(lua_giveitem, "lua_giveitem"); } diff --git a/src/helpers.h b/src/helpers.h index d77765187..d0bbcc58b 100644 --- a/src/helpers.h +++ b/src/helpers.h @@ -14,9 +14,9 @@ without prior permission by the authors of Eressea. extern "C" { #endif - struct lua_State; - void register_tolua_helpers(void); - int tolua_toid(struct lua_State *L, int idx, int def); + struct lua_State; + + void register_tolua_helpers(void); #ifdef __cplusplus } diff --git a/src/kernel/CMakeLists.txt b/src/kernel/CMakeLists.txt index b8423ae03..fe560af7a 100644 --- a/src/kernel/CMakeLists.txt +++ b/src/kernel/CMakeLists.txt @@ -6,6 +6,7 @@ alliance.test.c ally.test.c build.test.c building.test.c +# callbacks.test.c command.test.c config.test.c # connection.test.c @@ -16,7 +17,7 @@ group.test.c item.test.c messages.test.c order.test.c -# pathdinder.test.c +# pathfinder.test.c plane.test.c pool.test.c race.test.c @@ -38,6 +39,7 @@ alliance.c ally.c build.c building.c +callbacks.c command.c config.c connection.c diff --git a/src/kernel/build.h b/src/kernel/build.h index 323003efd..39916365a 100644 --- a/src/kernel/build.h +++ b/src/kernel/build.h @@ -60,13 +60,7 @@ extern "C" { } extra; struct construction *improvement; - /* next level, if upgradable. if more than one of these items - * can be built (weapons, armour) per turn, must not be NULL, - * but point to the same type again: - * const_sword.improvement = &const_sword - * last level of a building points to NULL, as do objects of - * an unlimited size. - */ + /* next level, if upgradable. */ } construction; void free_construction(struct construction *cons); diff --git a/src/kernel/building.c b/src/kernel/building.c index cdd33b022..bb97f57b8 100644 --- a/src/kernel/building.c +++ b/src/kernel/building.c @@ -192,7 +192,6 @@ const char *buildingtype(const building_type * btype, const building * b, int bs } if (btype->construction && btype->construction->extra.name) { if (b) { - assert(b->type == btype); bsize = adjust_size(b, bsize); } for (con = btype->construction; con; con = con->improvement) { @@ -704,7 +703,7 @@ default_wage(const region * r, const faction * f, const race * rc, int in_turn) else { wage = wagetable[esize][2]; } - if (rule_blessed_harvest() == HARVEST_WORK) { + if (r->attribs && rule_blessed_harvest() == HARVEST_WORK) { /* E1 rules */ wage += curse_geteffect(get_curse(r->attribs, ct_find("blessedharvest"))); } diff --git a/src/kernel/callbacks.c b/src/kernel/callbacks.c new file mode 100644 index 000000000..c1d52352a --- /dev/null +++ b/src/kernel/callbacks.c @@ -0,0 +1,5 @@ +#include <platform.h> +#include "callbacks.h" + +struct callback_struct callbacks = { 0 }; + diff --git a/src/kernel/callbacks.h b/src/kernel/callbacks.h new file mode 100644 index 000000000..f42d25d3f --- /dev/null +++ b/src/kernel/callbacks.h @@ -0,0 +1,37 @@ +/* +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_KRNL_CALLBACKS_H +#define H_KRNL_CALLBACKS_H + +#ifdef __cplusplus +extern "C" { +#endif + + struct castorder; + + struct callback_struct { + int (*cast_spell)(struct castorder *co, const char *fname); + }; + + extern struct callback_struct callbacks; +#ifdef __cplusplus +} +#endif +#endif /* H_KRNL_CALLBACKS_H */ + diff --git a/src/kernel/equipment.test.c b/src/kernel/equipment.test.c index afd53849e..1e6bf1819 100644 --- a/src/kernel/equipment.test.c +++ b/src/kernel/equipment.test.c @@ -23,7 +23,7 @@ void test_equipment(CuTest * tc) enable_skill(SK_MAGIC, true); it_horses = test_create_itemtype("horse"); CuAssertPtrNotNull(tc, it_horses); - sp = create_spell("testspell", 0); + sp = create_spell("testspell"); CuAssertPtrNotNull(tc, sp); CuAssertPtrEquals(tc, 0, get_equipment("herpderp")); diff --git a/src/kernel/jsonconf.c b/src/kernel/jsonconf.c index b4ce122c5..9f96ea9d7 100644 --- a/src/kernel/jsonconf.c +++ b/src/kernel/jsonconf.c @@ -588,15 +588,12 @@ static void json_spells(cJSON *json) { for (child = json->child; child; child = child->next) { if (child->type == cJSON_Object) { spell *sp; - cJSON * item = cJSON_GetObjectItem(child, "index"); - sp = create_spell(child->string, item ? item->valueint : 0); + cJSON * item; + sp = create_spell(child->string); for (item = child->child; item; item = item->next) { if (strcmp(item->string, "index") == 0) { continue; } - else if (strcmp(item->string, "cast") == 0) { - sp->cast = (spell_f)get_function(item->valuestring); - } else if (strcmp(item->string, "syntax") == 0) { sp->syntax = strdup(item->valuestring); } diff --git a/src/kernel/spell.c b/src/kernel/spell.c index 900f98ff0..0abb487f7 100644 --- a/src/kernel/spell.c +++ b/src/kernel/spell.c @@ -33,7 +33,30 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include <stdlib.h> #include <string.h> -static critbit_tree cb_fumbles; + +static critbit_tree cb_spell_fun; +void add_spellcast(const char *sname, spell_f fun) +{ + size_t len; + char data[64]; + + len = cb_new_kv(sname, strlen(sname), &fun, sizeof(fun), data); + assert(len <= sizeof(data)); + cb_insert(&cb_spell_fun, data, len); +} + +spell_f get_spellcast(const char *sname) +{ + void * match; + spell_f result = NULL; + + if (cb_find_prefix(&cb_spell_fun, sname, strlen(sname) + 1, &match, 1, 0)) { + cb_get_kv(match, &result, sizeof(result)); + } + return result; +} + +static critbit_tree cb_fumble_fun; void add_fumble(const char *sname, fumble_f fun) { size_t len; @@ -41,7 +64,7 @@ void add_fumble(const char *sname, fumble_f fun) len = cb_new_kv(sname, strlen(sname), &fun, sizeof(fun), data); assert(len <= sizeof(data)); - cb_insert(&cb_fumbles, data, len); + cb_insert(&cb_fumble_fun, data, len); } fumble_f get_fumble(const char *sname) @@ -49,7 +72,7 @@ fumble_f get_fumble(const char *sname) void * match; fumble_f result = NULL; - if (cb_find_prefix(&cb_fumbles, sname, strlen(sname) + 1, &match, 1, 0)) { + if (cb_find_prefix(&cb_fumble_fun, sname, strlen(sname) + 1, &match, 1, 0)) { cb_get_kv(match, &result, sizeof(result)); } return result; @@ -71,7 +94,8 @@ static void free_spell_cb(void *cbdata) { } void free_spells(void) { - cb_clear(&cb_fumbles); + cb_clear(&cb_fumble_fun); + cb_clear(&cb_spell_fun); cb_clear(&cb_spells); selist_foreach(spells, free_spell_cb); selist_free(spells); @@ -85,7 +109,7 @@ void add_spell(struct selist **slistp, spell * sp) } } -spell * create_spell(const char * name, unsigned int id) +spell * create_spell(const char * name) { spell * sp; char buffer[64]; @@ -100,7 +124,6 @@ spell * create_spell(const char * name, unsigned int id) sp = (spell *)calloc(1, sizeof(spell)); len = cb_new_kv(name, len, &sp, sizeof(sp), buffer); if (cb_insert(&cb_spells, buffer, len) == CB_SUCCESS) { - sp->id = id ? id : hashstring(name); sp->sname = strdup(name); add_spell(&spells, sp); return sp; @@ -144,31 +167,6 @@ spell *find_spell(const char *name) return sp; } -spell *find_spellbyid(unsigned int id) -{ - selist *ql; - int qi; - - if (id == 0) - return NULL; - for (qi = 0, ql = spells; ql; selist_advance(&ql, &qi, 1)) { - spell *sp = (spell *)selist_get(ql, qi); - if (sp->id == id) { - return sp; - } - } - for (qi = 0, ql = spells; ql; selist_advance(&ql, &qi, 1)) { - spell *sp = (spell *)selist_get(ql, qi); - unsigned int hashid = hashstring(sp->sname); - if (hashid == id) { - return sp; - } - } - - log_warning("cannot find spell by id: %u\n", id); - return NULL; -} - struct spellref *spellref_create(spell *sp, const char *name) { spellref *spref = malloc(sizeof(spellref)); diff --git a/src/kernel/spell.h b/src/kernel/spell.h index ae5322c9a..17a565fa6 100644 --- a/src/kernel/spell.h +++ b/src/kernel/spell.h @@ -34,14 +34,12 @@ extern "C" { typedef void(*fumble_f)(const struct castorder * co); typedef struct spell { - unsigned int id; char *sname; char *syntax; char *parameter; int sptyp; int rank; /* Reihenfolge der Zauber */ struct spell_component *components; - spell_f cast; } spell; typedef struct spellref { @@ -52,15 +50,17 @@ extern "C" { void add_fumble(const char *sname, fumble_f fun); fumble_f get_fumble(const char *sname); + void add_spellcast(const char *sname, spell_f fun); + spell_f get_spellcast(const char *sname); + struct spellref *spellref_create(struct spell *sp, const char *name); void spellref_free(struct spellref *spref); struct spell *spellref_get(struct spellref *spref); int sp_antimagiczone(struct castorder *co); - struct spell * create_spell(const char * name, unsigned int id); + struct spell * create_spell(const char * name); struct spell * find_spell(const char *name); - struct spell * find_spellbyid(unsigned int i); void add_spell(struct selist **slistp, spell * sp); void free_spells(void); diff --git a/src/kernel/spell.test.c b/src/kernel/spell.test.c index 739be35da..e5a37fd65 100644 --- a/src/kernel/spell.test.c +++ b/src/kernel/spell.test.c @@ -19,7 +19,7 @@ static void test_create_a_spell(CuTest * tc) CuAssertPtrEquals(tc, 0, spells); CuAssertPtrEquals(tc, 0, find_spell("testspell")); - sp = create_spell("testspell", 0); + sp = create_spell("testspell"); CuAssertPtrEquals(tc, sp, find_spell("testspell")); CuAssertPtrNotNull(tc, spells); test_cleanup(); @@ -37,8 +37,8 @@ static void test_create_duplicate_spell(CuTest * tc) CuAssertPtrEquals(tc, 0, find_spell("testspell")); - sp = create_spell("testspell", 0); - CuAssertPtrEquals(tc, 0, create_spell("testspell", 0)); + sp = create_spell("testspell"); + CuAssertPtrEquals(tc, 0, create_spell("testspell")); CuAssertPtrNotNull(tc, sl); CuAssertStrEquals(tc, "create_spell: duplicate name '%s'", sl->s); CuAssertPtrEquals(tc, 0, sl->next); @@ -47,28 +47,6 @@ static void test_create_duplicate_spell(CuTest * tc) test_cleanup(); } -static void test_create_spell_with_id(CuTest * tc) -{ - spell *sp; - struct log_t *log; - strlist *sl = 0; - - test_setup(); - test_log_stderr(0); - log = test_log_start(LOG_CPERROR, &sl); - - CuAssertPtrEquals(tc, 0, find_spellbyid(42)); - sp = create_spell("testspell", 42); - CuAssertPtrEquals(tc, sp, find_spellbyid(42)); - CuAssertPtrEquals(tc, 0, create_spell("testspell", 47)); - CuAssertPtrEquals(tc, 0, find_spellbyid(47)); - CuAssertPtrNotNull(tc, sl); - CuAssertStrEquals(tc, "create_spell: duplicate name '%s'", sl->s); - CuAssertPtrEquals(tc, 0, sl->next); - test_log_stop(log, sl); - test_cleanup(); -} - static void test_spellref(CuTest *tc) { spellref *ref; @@ -79,25 +57,31 @@ static void test_spellref(CuTest *tc) CuAssertPtrEquals(tc, NULL, ref->sp); CuAssertStrEquals(tc, "hodor", ref->name); CuAssertPtrEquals(tc, NULL, spellref_get(ref)); - sp = create_spell("hodor", 0); + sp = create_spell("hodor"); CuAssertPtrNotNull(tc, sp); CuAssertPtrEquals(tc, sp, spellref_get(ref)); spellref_free(ref); test_cleanup(); } -void my_fumble(const struct castorder *co) { +void fumble_foo(const struct castorder *co) { + UNUSED_ARG(co); +} + +void fumble_bar(const struct castorder *co) { UNUSED_ARG(co); } static void test_fumbles(CuTest *tc) { test_setup(); - CuAssertTrue(tc, NULL==get_fumble("hodor")); - add_fumble("hodor", my_fumble); - CuAssertTrue(tc, my_fumble==get_fumble("hodor")); + CuAssertTrue(tc, NULL==get_fumble("foo")); + add_fumble("foone", fumble_foo); + add_fumble("foozle", fumble_bar); + CuAssertTrue(tc, fumble_foo==get_fumble("foone")); + CuAssertTrue(tc, fumble_bar==get_fumble("foozle")); + CuAssertTrue(tc, NULL==get_fumble("foo")); test_cleanup(); - CuAssertTrue(tc, NULL==get_fumble("hodor")); } CuSuite *get_spell_suite(void) @@ -107,6 +91,5 @@ CuSuite *get_spell_suite(void) SUITE_ADD_TEST(suite, test_fumbles); SUITE_ADD_TEST(suite, test_create_a_spell); SUITE_ADD_TEST(suite, test_create_duplicate_spell); - SUITE_ADD_TEST(suite, test_create_spell_with_id); return suite; } diff --git a/src/kernel/spellbook.test.c b/src/kernel/spellbook.test.c index 8b997557b..37f20cced 100644 --- a/src/kernel/spellbook.test.c +++ b/src/kernel/spellbook.test.c @@ -33,7 +33,7 @@ void test_named_spellbooks(CuTest * tc) CuAssertPtrNotNull(tc, sb); CuAssertStrEquals(tc, "spells", sb->name); - sp = create_spell("testspell", 0); + sp = create_spell("testspell"); spellbook_add(sb, sp, 1); CuAssertPtrNotNull(tc, sb->spells); diff --git a/src/kernel/xmlreader.c b/src/kernel/xmlreader.c index f9e62dc43..9f671d44c 100644 --- a/src/kernel/xmlreader.c +++ b/src/kernel/xmlreader.c @@ -279,11 +279,8 @@ parse_function(xmlNodePtr node, pf_generic * funPtr, xmlChar ** namePtr) xmlChar *propValue = xmlGetProp(node, BAD_CAST "value"); assert(propValue != NULL); fun = get_function((const char *)propValue); - if (fun != NULL) { - xmlFree(propValue); - - propValue = xmlGetProp(node, BAD_CAST "name"); - } + xmlFree(propValue); + propValue = xmlGetProp(node, BAD_CAST "name"); *namePtr = propValue; *funPtr = fun; return 0; @@ -1311,7 +1308,6 @@ static int parse_spellbooks(xmlDocPtr doc) static int parse_spells(xmlDocPtr doc) { - pf_generic cast = 0; xmlXPathContextPtr xpath = xmlXPathNewContext(doc); xmlXPathObjectPtr spells; @@ -1328,14 +1324,12 @@ static int parse_spells(xmlDocPtr doc) int k; spell_component *component; spell *sp; - unsigned int index; static int modes[] = { 0, PRECOMBATSPELL, COMBATSPELL, POSTCOMBATSPELL }; /* spellname */ - index = xml_ivalue(node, "index", 0); propValue = xmlGetProp(node, BAD_CAST "name"); assert(propValue != NULL); - sp = create_spell((const char *)propValue, index); + sp = create_spell((const char *)propValue); xmlFree(propValue); if (!sp) { continue; @@ -1388,44 +1382,9 @@ static int parse_spells(xmlDocPtr doc) sp->sptyp |= REGIONSPELL; k = xml_ivalue(node, "combat", 0); - if (k >= 0 && k <= 3) + if (k >= 0 && k <= 3) { sp->sptyp |= modes[k]; - - /* reading eressea/spells/spell/function */ - - xpath->node = node; - result = xmlXPathEvalExpression(BAD_CAST "function", xpath); - - if (result->nodesetval->nodeNr == 0) { - cast = get_function(sp->sname); - if (!cast) { - log_error("no spell cast function registered for '%s'\n", sp->sname); - } } - else { - for (k = 0; k != result->nodesetval->nodeNr; ++k) { - xmlNodePtr node = result->nodesetval->nodeTab[k]; - pf_generic fun; - - parse_function(node, &fun, &propValue); - assert(propValue != NULL); - if (strcmp((const char *)propValue, "cast") == 0) { - if (fun) { - cast = fun; - } - else { - log_error("unknown function name '%s' for spell '%s'\n", (const char *)propValue, sp->sname); - } - } - else { - log_error("unknown function type '%s' for spell '%s'\n", (const char *)propValue, sp->sname); - } - xmlFree(propValue); - } - } - sp->cast = (spell_f)cast; - xmlXPathFreeObject(result); - /* reading eressea/spells/spell/resource */ xpath->node = node; result = xmlXPathEvalExpression(BAD_CAST "resource", xpath); diff --git a/src/magic.c b/src/magic.c index 5a6672db5..a20fbc477 100644 --- a/src/magic.c +++ b/src/magic.c @@ -23,10 +23,12 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include "skill.h" #include "study.h" +#include "helpers.h" #include "laws.h" #include <kernel/ally.h> #include <kernel/building.h> +#include <kernel/callbacks.h> #include <kernel/curse.h> #include <kernel/faction.h> #include <kernel/item.h> @@ -339,23 +341,16 @@ sc_mage *get_mage(const unit * u) static int read_seenspell(attrib * a, void *owner, struct gamedata *data) { storage *store = data->store; - int i; spell *sp = 0; char token[32]; READ_TOK(store, token, sizeof(token)); - i = atoip(token); - if (i != 0) { - sp = find_spellbyid((unsigned int)i); + if (data->version < UNIQUE_SPELLS_VERSION) { + READ_INT(store, 0); /* ignore mtype */ } - else { - if (data->version < UNIQUE_SPELLS_VERSION) { - READ_INT(store, 0); /* ignore mtype */ - } - sp = find_spell(token); - if (!sp) { - log_warning("read_seenspell: could not find spell '%s'\n", token); - } + sp = find_spell(token); + if (!sp) { + log_warning("read_seenspell: could not find spell '%s'\n", token); } if (!sp) { return AT_READ_FAIL; @@ -898,9 +893,7 @@ void pay_spell(unit * u, const spell * sp, int cast_level, int range) bool knowsspell(const region * r, const unit * u, const spell * sp) { /* Ist überhaupt ein gültiger Spruch angegeben? */ - if (!sp || sp->id == 0) { - return false; - } + assert(sp); /* steht der Spruch in der Spruchliste? */ return u_hasspell(u, sp) != 0; } @@ -1433,7 +1426,7 @@ static void do_fumble(castorder * co) case 5: case 6: /* Spruch gelingt, aber alle Magiepunkte weg */ - co->level = sp->cast(co); + co->level = cast_spell(co); set_spellpoints(u, 0); ADDMSG(&u->faction->msgs, msg_message("patzer4", "unit region spell", u, r, sp)); @@ -1444,7 +1437,7 @@ static void do_fumble(castorder * co) case 9: default: /* Spruch gelingt, alle nachfolgenden Sprüche werden 2^4 so teuer */ - co->level = sp->cast(co); + co->level = cast_spell(co); ADDMSG(&u->faction->msgs, msg_message("patzer5", "unit region spell", u, r, sp)); countspells(u, 3); @@ -2900,7 +2893,7 @@ void magic(void) fumbled = true; } else { - co->level = sp->cast(co); + co->level = cast_spell(co); if (co->level <= 0) { /* Kosten nur für real benötige Stufe berechnen */ continue; @@ -3003,6 +2996,30 @@ spell *unit_getspell(struct unit *u, const char *name, const struct locale * lan return 0; } +int cast_spell(struct castorder *co) +{ + const char *fname = co->sp->sname; + const char *hashpos = strchr(fname, '#'); + char fbuf[64]; + spell_f fun; + + const spell *sp = co->sp; + if (hashpos != NULL) { + ptrdiff_t len = hashpos - fname; + assert(len < (ptrdiff_t) sizeof(fbuf)); + memcpy(fbuf, fname, len); + fbuf[len] = '\0'; + fname = fbuf; + } + + fun = get_spellcast(sp->sname); + if (!fun) { + log_warning("no spell function for %s, try callback", sp->sname); + return callbacks.cast_spell(co, fname); + } + return fun(co); +} + static critbit_tree cb_spellbooks; spellbook * get_spellbook(const char * name) diff --git a/src/magic.h b/src/magic.h index d3e45089e..6c905ea68 100644 --- a/src/magic.h +++ b/src/magic.h @@ -286,6 +286,7 @@ extern "C" { /* H�nge c-order co an die letze c-order von cll an */ void free_castorders(struct castorder *co); /* Speicher wieder freigeben */ + int cast_spell(struct castorder *co); /* Pr�froutinen f�r Zaubern */ int countspells(struct unit *u, int step); diff --git a/src/magic.test.c b/src/magic.test.c index a3a199e42..380001035 100644 --- a/src/magic.test.c +++ b/src/magic.test.c @@ -4,7 +4,7 @@ #include "teleport.h" #include "give.h" -#include <kernel/config.h> +#include <kernel/building.h> #include <kernel/race.h> #include <kernel/faction.h> #include <kernel/order.h> @@ -14,13 +14,16 @@ #include <kernel/spellbook.h> #include <kernel/unit.h> #include <kernel/pool.h> -#include <selist.h> + +#include <util/attrib.h> #include <util/language.h> #include <CuTest.h> +#include <selist.h> #include <tests.h> #include <stdlib.h> +#include <string.h> void test_updatespells(CuTest * tc) { @@ -32,7 +35,7 @@ void test_updatespells(CuTest * tc) test_create_race("human"); f = test_create_faction(0); - sp = create_spell("testspell", 0); + sp = create_spell("testspell"); CuAssertPtrNotNull(tc, sp); book = create_spellbook("spells"); @@ -65,7 +68,7 @@ void test_spellbooks(CuTest * tc) CuAssertStrEquals(tc, "herp", herp->name); CuAssertStrEquals(tc, "derp", derp->name); - sp = create_spell(sname, 0); + sp = create_spell(sname); spellbook_add(herp, sp, 1); CuAssertPtrNotNull(tc, sp); entry = spellbook_get(herp, sp); @@ -168,7 +171,7 @@ void test_getspell_unit(CuTest * tc) set_level(u, SK_MAGIC, 1); lang = test_create_locale(); - sp = create_spell("testspell", 0); + sp = create_spell("testspell"); locale_setstring(lang, mkname("spell", sp->sname), "Herp-a-derp"); CuAssertPtrEquals(tc, 0, unit_getspell(u, "Herp-a-derp", lang)); @@ -197,7 +200,7 @@ void test_getspell_faction(CuTest * tc) set_level(u, SK_MAGIC, 1); lang = test_create_locale(); - sp = create_spell("testspell", 0); + sp = create_spell("testspell"); locale_setstring(lang, mkname("spell", sp->sname), "Herp-a-derp"); CuAssertPtrEquals(tc, 0, unit_getspell(u, "Herp-a-derp", lang)); @@ -227,7 +230,7 @@ void test_getspell_school(CuTest * tc) set_level(u, SK_MAGIC, 1); lang = test_create_locale(); - sp = create_spell("testspell", 0); + sp = create_spell("testspell"); locale_setstring(lang, mkname("spell", sp->sname), "Herp-a-derp"); CuAssertPtrEquals(tc, 0, unit_getspell(u, "Herp-a-derp", lang)); @@ -254,7 +257,7 @@ void test_set_pre_combatspell(CuTest * tc) u = test_create_unit(f, r); enable_skill(SK_MAGIC, true); set_level(u, SK_MAGIC, 1); - sp = create_spell("testspell", 0); + sp = create_spell("testspell"); sp->sptyp |= PRECOMBATSPELL; unit_add_spell(u, 0, sp, 1); @@ -286,7 +289,7 @@ void test_set_main_combatspell(CuTest * tc) u = test_create_unit(f, r); enable_skill(SK_MAGIC, true); set_level(u, SK_MAGIC, 1); - sp = create_spell("testspell", 0); + sp = create_spell("testspell"); sp->sptyp |= COMBATSPELL; unit_add_spell(u, 0, sp, 1); @@ -318,7 +321,7 @@ void test_set_post_combatspell(CuTest * tc) u = test_create_unit(f, r); enable_skill(SK_MAGIC, true); set_level(u, SK_MAGIC, 1); - sp = create_spell("testspell", 0); + sp = create_spell("testspell"); sp->sptyp |= POSTCOMBATSPELL; unit_add_spell(u, 0, sp, 1); @@ -348,7 +351,7 @@ void test_hasspell(CuTest * tc) f->magiegebiet = M_TYBIED; u = test_create_unit(f, r); enable_skill(SK_MAGIC, true); - sp = create_spell("testspell", 0); + sp = create_spell("testspell"); sp->sptyp |= POSTCOMBATSPELL; unit_add_spell(u, 0, sp, 2); @@ -377,8 +380,8 @@ void test_multi_cast(CuTest *tc) { struct locale * lang; test_setup(); - sp = create_spell("fireball", 0); - sp->cast = cast_fireball; + add_spellcast("fireball", cast_fireball); + sp = create_spell("fireball"); CuAssertPtrEquals(tc, sp, find_spell("fireball")); lang = test_create_locale(); @@ -460,6 +463,27 @@ static void test_familiar_mage(CuTest *tc) { test_cleanup(); } +static void test_illusioncastle(CuTest *tc) +{ + building *b; + building_type *btype, *bt_icastle; + const attrib *a; + test_setup(); + btype = test_create_buildingtype("castle"); + bt_icastle = test_create_buildingtype("illusioncastle"); + b = test_create_building(test_create_region(0, 0, NULL), bt_icastle); + b->size = 1; + make_icastle(b, btype, 10); + a = a_find(b->attribs, &at_icastle); + CuAssertPtrNotNull(tc, a); + CuAssertPtrEquals(tc, btype, (void *)icastle_type(a)); + CuAssertPtrEquals(tc, bt_icastle, (void *)b->type); + CuAssertStrEquals(tc, "castle", buildingtype(btype, b, b->size)); + btype->construction->extra.name = strdup("site"); + CuAssertStrEquals(tc, "site", buildingtype(btype, b, b->size)); + test_cleanup(); +} + CuSuite *get_magic_suite(void) { CuSuite *suite = CuSuiteNew(); @@ -477,6 +501,7 @@ CuSuite *get_magic_suite(void) SUITE_ADD_TEST(suite, test_hasspell); SUITE_ADD_TEST(suite, test_magic_resistance); SUITE_ADD_TEST(suite, test_max_spellpoints); + SUITE_ADD_TEST(suite, test_illusioncastle); DISABLE_TEST(suite, test_familiar_mage); return suite; } diff --git a/src/platform.h b/src/platform.h index 104ff28d7..97d254e2d 100644 --- a/src/platform.h +++ b/src/platform.h @@ -14,6 +14,7 @@ #define NO_STRDUP #define NO_MKDIR #define _CRT_SECURE_NO_WARNINGS +#define _USE_MATH_DEFINES #pragma warning(disable: 4710 4820) #pragma warning(disable: 4100) // unreferenced formal parameter #pragma warning(disable: 4456) // declaration hides previous @@ -47,4 +48,10 @@ char * strdup(const char *s); int mkdir(const char *pathname, int mode); #endif +/* do not use M_PI, use one of these instead: */ +#define PI_F 3.1415926535897932384626433832795F +#define PI_D 3.1415926535897932384626433832795 +#define PI_L 3.1415926535897932384626433832795L + + #endif diff --git a/src/reports.c b/src/reports.c index 353ed09fe..9af18c1d2 100644 --- a/src/reports.c +++ b/src/reports.c @@ -386,7 +386,7 @@ const char **illusion) if (illusion) { *illusion = NULL; - if (is_building_type(b->type, "illusioncastle")) { + if (b->attribs && is_building_type(b->type, "illusioncastle")) { const attrib *a = a_find(b->attribs, &at_icastle); if (a != NULL) { *illusion = buildingtype(icastle_type(a), b, b->size); diff --git a/src/spells.c b/src/spells.c index 8bf30de88..c515c0144 100644 --- a/src/spells.c +++ b/src/spells.c @@ -1104,8 +1104,9 @@ static int sp_blessedharvest(castorder * co) if (create_curse(mage, &r->attribs, ct_find("blessedharvest"), co->force, duration, 1.0, 0)) { - message *seen = msg_message("harvest_effect", "mage", mage); - message *unseen = msg_message("harvest_effect", "mage", NULL); + const char * effect = co->sp->sname[0]=='b' ? "harvest_effect" : "raindance_effect"; + message *seen = msg_message(effect, "mage", mage); + message *unseen = msg_message(effect, "mage", NULL); report_effect(r, mage, seen, unseen); msg_release(seen); msg_release(unseen); @@ -2930,10 +2931,6 @@ static int dc_read_compat(struct attrib *a, void *target, gamedata *data) } return AT_READ_FAIL; /* we don't care for the attribute. */ } - -attrib_type at_deathcloud_compat = { - "zauber_todeswolke", NULL, NULL, NULL, NULL, dc_read_compat -}; #endif /* ------------------------------------------------------------- */ @@ -6444,6 +6441,54 @@ int sp_break_curse(castorder * co) return cast_level; } +static int sp_flee(castorder *co) { + if (co->force <= 0) { + return 0; + } + return flee_spell(co, 4); +} + +static int sp_song_of_fear(castorder *co) { + if (co->force <= 0) { + return 0; + } + return flee_spell(co, 3); +} + +static int sp_aura_of_fear(castorder *co) { + if (co->force <= 0) { + return 0; + } + return flee_spell(co, 5); +} + +static int sp_armor_shield(struct castorder * co) { + return armor_spell(co, 3, 20); +} + +static int sp_bark_skin(struct castorder * co) { + return armor_spell(co, 4, 1); +} + +static int sp_kampfzauber(castorder *co) { + const spell * sp = co->sp; + if (co->force <= 0) { + return 0; + } + else if (strcmp(sp->sname, "fireball") == 0) { + return damage_spell(co, 0, 0); + } + else if (strcmp(sp->sname, "hail") == 0) { + return damage_spell(co, 2, 4); + } + else if (strcmp(sp->sname, "meteor_rain") == 0) { + return damage_spell(co, 1, 1); + } + else { + return damage_spell(co, 10, 10); + } +} + /* ------------------------------------------------------------- */ int sp_becomewyrm(castorder * co) { @@ -6451,182 +6496,6 @@ int sp_becomewyrm(castorder * co) return 0; } -typedef struct spelldata { - const char *sname; - spell_f cast; - fumble_f fumble; -} spelldata; - -static spelldata spell_functions[] = { - /* M_GWYRRD */ - { "stonegolem", sp_create_stonegolem, 0 }, - { "irongolem", sp_create_irongolem, 0 }, - { "treegrow", sp_hain, fumble_ents }, - { "rustweapon", sp_rosthauch, 0 }, - { "cold_protection", sp_kaelteschutz, 0 }, - { "ironkeeper", sp_ironkeeper, 0 }, - { "magicstreet", sp_magicstreet, 0 }, - { "windshield", sp_windshield, 0 }, - { "mallorntreegrow", sp_mallornhain, fumble_ents }, - { "goodwinds", sp_goodwinds, 0 }, - { "healing", sp_healing, 0 }, - { "reelingarrows", sp_reeling_arrows, 0 }, - { "gwyrrdfumbleshield", sp_fumbleshield, 0 }, - { "transferauradruide", sp_transferaura, 0 }, - { "earthquake", sp_earthquake, 0 }, - { "stormwinds", sp_stormwinds, 0 }, - { "homestone", sp_homestone, 0 }, - { "wolfhowl", sp_wolfhowl, 0 }, - { "igjarjuk", sp_igjarjuk, 0 }, - { "versteinern", sp_petrify, 0 }, - { "strongwall", sp_strong_wall, 0 }, - { "gwyrrddestroymagic", sp_destroy_magic, 0 }, - { "treewalkenter", sp_treewalkenter, 0 }, - { "treewalkexit", sp_treewalkexit, 0 }, - { "holyground", sp_holyground, 0 }, - { "summonent", sp_summonent, 0 }, - { "blessstonecircle", sp_blessstonecircle, 0 }, - { "barkskin", sp_armorshield, 0 }, - { "summonfireelemental", sp_drought, 0 }, - { "maelstrom", sp_maelstrom, 0 }, - { "magic_roots", sp_mallorn, 0 }, - { "great_drought", sp_great_drought, 0 }, - /* M_DRAIG */ - { "sparklechaos", sp_sparkle, 0 }, - { "magicboost", sp_magicboost, 0 }, - { "bloodsacrifice", sp_bloodsacrifice, 0 }, - { "berserk", sp_berserk, 0 }, - { "fumblecurse", sp_fumblecurse, patzer_fumblecurse }, - { "summonundead", sp_summonundead, patzer_peasantmob }, - { "combatrust", sp_combatrosthauch, 0 }, - { "transferaurachaos", sp_transferaura, 0 }, - { "firewall", sp_firewall, patzer_peasantmob }, - { "plague", sp_plague, patzer_peasantmob }, - { "chaosrow", sp_chaosrow, 0 }, - { "summonshadow", sp_summonshadow, patzer_peasantmob }, - { "undeadhero", sp_undeadhero, 0 }, - { "auraleak", sp_auraleak, 0 }, - { "draigfumbleshield", sp_fumbleshield, 0 }, - { "forestfire", sp_forest_fire, patzer_peasantmob }, - { "draigdestroymagic", sp_destroy_magic, 0 }, - { "unholypower", sp_unholypower, 0 }, - { "deathcloud", sp_deathcloud, patzer_peasantmob }, - { "summondragon", sp_summondragon, patzer_peasantmob }, - { "summonshadowlords", sp_summonshadowlords, patzer_peasantmob }, - { "chaossuction", sp_chaossuction, patzer_peasantmob }, - /* M_ILLAUN */ - { "sparkledream", sp_sparkle, 0 }, - { "shadowknights", sp_shadowknights, 0 }, - { "flee", sp_flee, 0 }, - { "puttorest", sp_puttorest, 0 }, - { "icastle", sp_icastle, 0 }, - { "transferauratraum", sp_transferaura, 0 }, - { "shapeshift", sp_illusionary_shapeshift, 0 }, - { "dreamreading", sp_dreamreading, 0 }, - { "tiredsoldiers", sp_tiredsoldiers, 0 }, - { "reanimate", sp_reanimate, 0 }, - { "analysedream", sp_analysedream, 0 }, - { "disturbingdreams", sp_disturbingdreams, 0 }, - { "sleep", sp_sleep, 0 }, - { "wisps", 0, 0 }, /* TODO: this spell is gone */ - { "gooddreams", sp_gooddreams, 0 }, - { "illaundestroymagic", sp_destroy_magic, 0 }, - { "clone", sp_clonecopy, 0 }, - { "bad_dreams", sp_baddreams, 0 }, - { "mindblast", sp_mindblast_temp, 0 }, - { "orkdream", sp_sweetdreams, 0 }, - /* M_CERDDOR */ - { "appeasement", sp_denyattack, 0 }, - { "song_of_healing", sp_healing, 0 }, - { "generous", sp_generous, 0 }, - { "song_of_fear", sp_flee, 0 }, - { "courting", sp_recruit, 0 }, - { "song_of_confusion", sp_chaosrow, 0 }, - { "heroic_song", sp_hero, 0 }, - { "transfer_aura_song", sp_transferaura, 0 }, - { "analysesong_unit", sp_analysesong_unit, 0 }, - { "cerddorfumbleshield", sp_fumbleshield, 0 }, - { "calm_monster", sp_calm_monster, 0 }, - { "seduction", sp_seduce, 0 }, - { "headache", sp_headache, 0 }, - { "sound_out", sp_pump, 0 }, - { "bloodthirst", sp_berserk, 0 }, - { "frighten", sp_frighten, 0 }, - { "analyse_object", sp_analysesong_obj, 0 }, - { "cerddor_destroymagic", sp_destroy_magic, 0 }, - { "migration", sp_migranten, 0 }, - { "summon_familiar", sp_summon_familiar, 0 }, - { "raise_mob", sp_raisepeasants, 0 }, - { "song_resist_magic", sp_song_resistmagic, 0 }, - { "melancholy", sp_depression, 0 }, - { "song_suscept_magic", sp_song_susceptmagic, 0 }, - { "song_of_peace", sp_song_of_peace, 0 }, - { "song_of_slavery", sp_charmingsong, 0 }, - { "big_recruit", sp_bigrecruit, 0 }, - { "calm_riot", sp_rallypeasantmob, 0 }, - { "incite_riot", sp_raisepeasantmob, 0 }, - /* M_TYBIED */ - { "analyze_magic", sp_analysemagic, 0 }, - { "concealing_aura", sp_itemcloak, 0 }, - { "tybiedfumbleshield", sp_fumbleshield, 0 }, -#ifdef SHOWASTRAL_NOT_BORKED - { "show_astral", sp_showastral, 0}, -#endif - { "resist_magic", sp_resist_magic_bonus, 0 }, - { "keeploot", sp_keeploot, 0 }, - { "enterastral", sp_enterastral, 0 }, - { "leaveastral", sp_leaveastral, 0 }, - { "auratransfer", sp_transferaura, 0 }, - { "shockwave", sp_stun, 0 }, - { "antimagiczone", sp_antimagiczone, 0 }, - { "destroy_magic", sp_destroy_magic, 0 }, - { "pull_astral", sp_pullastral, 0 }, - { "fetch_astral", sp_fetchastral, 0 }, - { "steal_aura", sp_stealaura, 0 }, - { "airship", sp_flying_ship, 0 }, - { "break_curse", sp_break_curse, 0 }, - { "eternal_walls", sp_eternizewall, 0 }, - { "protective_runes", sp_magicrunes, 0 }, - { "fish_shield", sp_reduceshield, 0 }, - { "combat_speed", sp_speed, 0 }, - { "view_reality", sp_viewreality, 0 }, - { "double_time", sp_speed2, 0 }, - { "armor_shield", sp_armorshield, 0 }, - { "living_rock", sp_movecastle, 0 }, - { "astral_disruption", sp_disruptastral, 0 }, - { "sacrifice_strength", sp_permtransfer, 0 }, - /* M_GRAY */ - /* Definitionen von Create_Artefaktspruechen */ - { "wyrm_transformation", sp_becomewyrm, 0 }, - /* Monstersprueche */ - { "fiery_dragonbreath", sp_dragonodem, 0 }, - { "icy_dragonbreath", sp_dragonodem, 0 }, - { "powerful_dragonbreath", sp_dragonodem, 0 }, - { "drain_skills", sp_dragonodem, 0 }, - { "aura_of_fear", sp_flee, 0 }, - { "immolation", sp_immolation, 0 }, - { "firestorm", sp_immolation, 0 }, - { "coldfront", sp_immolation, 0 }, - { "acidrain", sp_immolation, 0 }, - { 0, 0, 0 } -}; - -static void register_spelldata(void) -{ - int i; - char zText[32]; - strcpy(zText, "fumble_"); - for (i = 0; spell_functions[i].sname; ++i) { - spelldata *data = spell_functions + i; - if (data->cast) { - register_function((pf_generic)data->cast, data->sname); - } - if (data->fumble) { - add_fumble(data->sname, data->fumble); - } - } -} - /* ------------------------------------------------------------- */ /* Name: Plappermaul * Stufe: 4 @@ -6720,24 +6589,200 @@ static int sp_readmind(castorder * co) return cast_level; } -void register_magicresistance(void); +typedef struct spelldata { + const char *sname; + spell_f cast; + fumble_f fumble; +} spelldata; + +static spelldata spell_functions[] = { + /* M_GWYRRD */ + { "stonegolem", sp_create_stonegolem, 0 }, + { "irongolem", sp_create_irongolem, 0 }, + { "treegrow", sp_hain, fumble_ents }, + { "rustweapon", sp_rosthauch, 0 }, + { "cold_protection", sp_kaelteschutz, 0 }, + { "ironkeeper", sp_ironkeeper, 0 }, + { "magicstreet", sp_magicstreet, 0 }, + { "windshield", sp_windshield, 0 }, + { "mallorntreegrow", sp_mallornhain, fumble_ents }, + { "goodwinds", sp_goodwinds, 0 }, + { "healing", sp_healing, 0 }, + { "reelingarrows", sp_reeling_arrows, 0 }, + { "gwyrrdfumbleshield", sp_fumbleshield, 0 }, + { "transferauradruide", sp_transferaura, 0 }, + { "earthquake", sp_earthquake, 0 }, + { "stormwinds", sp_stormwinds, 0 }, + { "homestone", sp_homestone, 0 }, + { "wolfhowl", sp_wolfhowl, 0 }, + { "igjarjuk", sp_igjarjuk, 0 }, + { "versteinern", sp_petrify, 0 }, + { "strongwall", sp_strong_wall, 0 }, + { "gwyrrddestroymagic", sp_destroy_magic, 0 }, + { "treewalkenter", sp_treewalkenter, 0 }, + { "treewalkexit", sp_treewalkexit, 0 }, + { "holyground", sp_holyground, 0 }, + { "summonent", sp_summonent, 0 }, + { "blessstonecircle", sp_blessstonecircle, 0 }, + { "barkskin", sp_bark_skin, 0 }, + { "summonfireelemental", sp_drought, 0 }, + { "maelstrom", sp_maelstrom, 0 }, + { "magic_roots", sp_mallorn, 0 }, + { "great_drought", sp_great_drought, 0 }, + /* M_DRAIG */ + { "sparklechaos", sp_sparkle, 0 }, + { "magicboost", sp_magicboost, 0 }, + { "bloodsacrifice", sp_bloodsacrifice, 0 }, + { "berserk", sp_berserk, 0 }, + { "fumblecurse", sp_fumblecurse, patzer_fumblecurse }, + { "summonundead", sp_summonundead, patzer_peasantmob }, + { "combatrust", sp_combatrosthauch, 0 }, + { "transferaurachaos", sp_transferaura, 0 }, + { "firewall", sp_firewall, patzer_peasantmob }, + { "plague", sp_plague, patzer_peasantmob }, + { "chaosrow", sp_chaosrow, 0 }, + { "summonshadow", sp_summonshadow, patzer_peasantmob }, + { "undeadhero", sp_undeadhero, 0 }, + { "auraleak", sp_auraleak, 0 }, + { "draigfumbleshield", sp_fumbleshield, 0 }, + { "forestfire", sp_forest_fire, patzer_peasantmob }, + { "draigdestroymagic", sp_destroy_magic, 0 }, + { "unholypower", sp_unholypower, 0 }, + { "deathcloud", sp_deathcloud, patzer_peasantmob }, + { "summondragon", sp_summondragon, patzer_peasantmob }, + { "summonshadowlords", sp_summonshadowlords, patzer_peasantmob }, + { "chaossuction", sp_chaossuction, patzer_peasantmob }, + /* M_ILLAUN */ + { "sparkledream", sp_sparkle, 0 }, + { "shadowknights", sp_shadowknights, 0 }, + { "flee", sp_flee, 0 }, + { "puttorest", sp_puttorest, 0 }, + { "icastle", sp_icastle, 0 }, + { "transferauratraum", sp_transferaura, 0 }, + { "shapeshift", sp_illusionary_shapeshift, 0 }, + { "dreamreading", sp_dreamreading, 0 }, + { "tiredsoldiers", sp_tiredsoldiers, 0 }, + { "reanimate", sp_reanimate, 0 }, + { "analysedream", sp_analysedream, 0 }, + { "disturbingdreams", sp_disturbingdreams, 0 }, + { "sleep", sp_sleep, 0 }, + { "wisps", 0, 0 }, /* TODO: this spell is gone */ + { "gooddreams", sp_gooddreams, 0 }, + { "illaundestroymagic", sp_destroy_magic, 0 }, + { "clone", sp_clonecopy, 0 }, + { "bad_dreams", sp_baddreams, 0 }, + { "mindblast", sp_mindblast_temp, 0 }, + { "orkdream", sp_sweetdreams, 0 }, + /* M_CERDDOR */ + { "appeasement", sp_denyattack, 0 }, + { "song_of_healing", sp_healing, 0 }, + { "generous", sp_generous, 0 }, + { "song_of_fear", sp_song_of_fear, 0 }, + { "courting", sp_recruit, 0 }, + { "song_of_confusion", sp_chaosrow, 0 }, + { "heroic_song", sp_hero, 0 }, + { "transfer_aura_song", sp_transferaura, 0 }, + { "analysesong_unit", sp_analysesong_unit, 0 }, + { "cerddorfumbleshield", sp_fumbleshield, 0 }, + { "calm_monster", sp_calm_monster, 0 }, + { "seduction", sp_seduce, 0 }, + { "headache", sp_headache, 0 }, + { "sound_out", sp_pump, 0 }, + { "bloodthirst", sp_berserk, 0 }, + { "frighten", sp_frighten, 0 }, + { "analyse_object", sp_analysesong_obj, 0 }, + { "cerddor_destroymagic", sp_destroy_magic, 0 }, + { "migration", sp_migranten, 0 }, + { "summon_familiar", sp_summon_familiar, 0 }, + { "raise_mob", sp_raisepeasants, 0 }, + { "song_resist_magic", sp_song_resistmagic, 0 }, + { "melancholy", sp_depression, 0 }, + { "song_suscept_magic", sp_song_susceptmagic, 0 }, + { "song_of_peace", sp_song_of_peace, 0 }, + { "song_of_slavery", sp_charmingsong, 0 }, + { "big_recruit", sp_bigrecruit, 0 }, + { "calm_riot", sp_rallypeasantmob, 0 }, + { "incite_riot", sp_raisepeasantmob, 0 }, + /* M_TYBIED */ + { "analyze_magic", sp_analysemagic, 0 }, + { "concealing_aura", sp_itemcloak, 0 }, + { "tybiedfumbleshield", sp_fumbleshield, 0 }, +#ifdef SHOWASTRAL_NOT_BORKED + { "show_astral", sp_showastral, 0 }, +#endif + { "resist_magic", sp_resist_magic_bonus, 0 }, + { "keeploot", sp_keeploot, 0 }, + { "enterastral", sp_enterastral, 0 }, + { "leaveastral", sp_leaveastral, 0 }, + { "auratransfer", sp_transferaura, 0 }, + { "shockwave", sp_stun, 0 }, + { "antimagiczone", sp_antimagiczone, 0 }, + { "destroy_magic", sp_destroy_magic, 0 }, + { "pull_astral", sp_pullastral, 0 }, + { "fetch_astral", sp_fetchastral, 0 }, + { "steal_aura", sp_stealaura, 0 }, + { "airship", sp_flying_ship, 0 }, + { "break_curse", sp_break_curse, 0 }, + { "eternal_walls", sp_eternizewall, 0 }, + { "protective_runes", sp_magicrunes, 0 }, + { "fish_shield", sp_reduceshield, 0 }, + { "combat_speed", sp_speed, 0 }, + { "view_reality", sp_viewreality, 0 }, + { "double_time", sp_speed2, 0 }, + { "armor_shield", sp_armor_shield, 0 }, + { "living_rock", sp_movecastle, 0 }, + { "astral_disruption", sp_disruptastral, 0 }, + { "sacrifice_strength", sp_permtransfer, 0 }, + /* M_GRAY */ + /* Definitionen von Create_Artefaktspruechen */ + { "wyrm_transformation", sp_becomewyrm, 0 }, + /* Monstersprueche */ + { "fiery_dragonbreath", sp_dragonodem, 0 }, + { "icy_dragonbreath", sp_dragonodem, 0 }, + { "powerful_dragonbreath", sp_dragonodem, 0 }, + { "drain_skills", sp_dragonodem, 0 }, + { "aura_of_fear", sp_aura_of_fear, 0 }, + { "immolation", sp_immolation, 0 }, + { "firestorm", sp_immolation, 0 }, + { "coldfront", sp_immolation, 0 }, + { "acidrain", sp_immolation, 0 }, + { "blabbermouth", sp_babbler, NULL }, + { "summon_familiar", sp_summon_familiar, NULL }, + { "meteor_rain", sp_kampfzauber, NULL }, + { "fireball", sp_kampfzauber, NULL }, + { "hail", sp_kampfzauber, NULL }, + { "readmind", sp_readmind, NULL }, + { "blessedharvest", sp_blessedharvest, NULL }, + { "raindance", sp_blessedharvest, NULL }, + { 0, 0, 0 } +}; + +static void register_spelldata(void) +{ + int i; + for (i = 0; spell_functions[i].sname; ++i) { + spelldata *data = spell_functions + i; + if (data->cast) { + add_spellcast(data->sname, data->cast); + } + if (data->fumble) { + add_fumble(data->sname, data->fumble); + } + } +} void register_spells(void) { register_borders(); - at_register(&at_deathcloud_compat); +#ifdef COMPAT_DEATHCLOUD + at_deprecate("zauber_todeswolke", dc_read_compat); +#endif /* init_firewall(); */ ct_register(&ct_firewall); ct_register(&ct_deathcloud); - register_function((pf_generic)sp_blessedharvest, "cast_blessedharvest"); - register_function((pf_generic)sp_summon_familiar, "cast_familiar"); - register_function((pf_generic)sp_babbler, "cast_babbler"); - register_function((pf_generic)sp_readmind, "cast_readmind"); - register_function((pf_generic)sp_kampfzauber, "combat_spell"); - register_spelldata(); register_unitcurse(); diff --git a/src/spells.h b/src/spells.h index 65270a164..275f41f7a 100644 --- a/src/spells.h +++ b/src/spells.h @@ -27,6 +27,7 @@ extern "C" { struct unit; struct message; + void register_magicresistance(void); void register_spells(void); void set_spelldata(struct spell *sp); diff --git a/src/spells/combatspells.c b/src/spells/combatspells.c index 8544a4a2d..08f38c8ea 100644 --- a/src/spells/combatspells.c +++ b/src/spells/combatspells.c @@ -47,31 +47,6 @@ #define EFFECT_HEALING_SPELL 5 -/* Some spells with a fixed, known ID (in XML). - * TODO: this method of identifying spells is error-prone, - * do not use it for new spells. */ -enum { - SPL_FIREBALL = 4, - SPL_HAGEL = 5, - SPL_CHAOSROW = 18, - SPL_FLEE = 20, - SPL_SONG_OF_FEAR = 21, - SPL_BERSERK = 22, - SPL_BLOODTHIRST = 23, - SPL_WINDSHIELD = 59, - SPL_HERO = 76, - SPL_METEORRAIN = 108, - SPL_REDUCESHIELD = 109, - SPL_ARMORSHIELD = 110, - SPL_DRAIG_FUMBLESHIELD = 143, - SPL_GWYRRD_FUMBLESHIELD = 144, - SPL_CERDDOR_FUMBLESHIELD = 145, - SPL_TYBIED_FUMBLESHIELD = 146, - SPL_SHADOWKNIGHTS = 147, - SPL_SHOCKWAVE = 163, - SPL_AURA_OF_FEAR = 175 -}; - /* ------------------------------------------------------------------ */ /* Kampfzauberfunktionen */ @@ -134,44 +109,23 @@ static double get_force(double power, int formel) } /* Generischer Kampfzauber */ -int sp_kampfzauber(struct castorder * co) +int damage_spell(struct castorder * co, int dmg, int strength) { fighter * fi = co->magician.fig; int level = co->level; - double power = co->force; const spell * sp = co->sp; + double power = co->force; battle *b = fi->side->battle; troop at, dt; message *m; /* Immer aus der ersten Reihe nehmen */ - int force, enemies; - int killed = 0; - const char *damage; + int enemies, killed = 0; + int force = lovar(get_force(power, strength)); + const char *damage = spell_damage(dmg); - if (power <= 0) - return 0; at.fighter = fi; at.index = 0; - switch (sp->id) { - /* lovar halbiert im Schnitt! */ - case SPL_FIREBALL: - damage = spell_damage(0); - force = lovar(get_force(power, 0)); - break; - case SPL_HAGEL: - damage = spell_damage(2); - force = lovar(get_force(power, 4)); - break; - case SPL_METEORRAIN: - damage = spell_damage(1); - force = lovar(get_force(power, 1)); - break; - default: - damage = spell_damage(10); - force = lovar(get_force(power, 10)); - } - enemies = count_enemies(b, fi, FIGHT_ROW, BEHIND_ROW - 1, SELECT_ADVANCE); if (enemies == 0) { message *m = @@ -257,13 +211,7 @@ int sp_stun(struct castorder * co) if (power <= 0) return 0; - switch (sp->id) { - case SPL_SHOCKWAVE: - force = lovar(get_force(power, 1)); - break; - default: - assert(0); - } + force = lovar(get_force(power, 1)); enemies = count_enemies(b, fi, FIGHT_ROW, BEHIND_ROW, SELECT_ADVANCE); if (!enemies) { @@ -956,6 +904,7 @@ int sp_chaosrow(struct castorder * co) message *m; const char *mtype; int qi, k = 0; + bool chaosrow = strcmp(sp->sname, "chaosrow") == 0; if (!count_enemies(b, fi, FIGHT_ROW, NUMROWS, SELECT_ADVANCE | SELECT_FIND)) { m = msg_message("battle::out_of_range", "mage spell", fi->unit, sp); @@ -964,10 +913,7 @@ int sp_chaosrow(struct castorder * co) return 0; } - if (sp->id == SPL_CHAOSROW) - power *= 40; - else - power = get_force(power, 5); + power = chaosrow ? (power * 40) : get_force(power, 5); fgs = fighters(b, fi->side, FIGHT_ROW, NUMROWS, FS_ENEMY); scramble_fighters(fgs); @@ -1019,7 +965,7 @@ int sp_chaosrow(struct castorder * co) } selist_free(fgs); - if (sp->id == SPL_CHAOSROW) { + if (chaosrow) { mtype = (k > 0) ? "sp_chaosrow_effect_1" : "sp_chaosrow_effect_0"; } else { @@ -1034,33 +980,20 @@ int sp_chaosrow(struct castorder * co) /* Gesang der Furcht (Kampfzauber) */ /* Panik (Pr�kampfzauber) */ -int sp_flee(struct castorder * co) +int flee_spell(struct castorder * co, int strength) { fighter * fi = co->magician.fig; int level = co->level; - double power = co->force; const spell * sp = co->sp; battle *b = fi->side->battle; unit *mage = fi->unit; selist *fgs, *ql; - int force, n, qi; - int panik = 0; + int n, qi, panik = 0; message *msg; + double power = co->force; + int force; - switch (sp->id) { - case SPL_FLEE: - force = (int)get_force(power, 4); - break; - case SPL_SONG_OF_FEAR: - force = (int)get_force(power, 3); - break; - case SPL_AURA_OF_FEAR: - force = (int)get_force(power, 5); - break; - default: - force = (int)get_force(power, 10); - } - + force = (int)get_force(power, strength); if (!count_enemies(b, fi, FIGHT_ROW, AVOID_ROW, SELECT_ADVANCE | SELECT_FIND)) { msg = msg_message("sp_flee_effect_0", "mage spell", mage, sp); message_all(b, msg); @@ -1116,16 +1049,8 @@ int sp_hero(struct castorder * co) int targets = 0; message *m; - switch (sp->id) { - case SPL_HERO: - df_bonus = (int)(power / 5); - force = MAX(1, lovar(get_force(power, 4))); - break; - - default: - df_bonus = 1; - force = MAX(1, (int)power); - } + df_bonus = (int)(power / 5); + force = MAX(1, lovar(get_force(power, 4))); allies = count_allies(fi->side, FIGHT_ROW, BEHIND_ROW, SELECT_ADVANCE, ALLY_ANY); @@ -1170,19 +1095,9 @@ int sp_berserk(struct castorder * co) int targets = 0; message *m; - switch (sp->id) { - case SPL_BERSERK: - case SPL_BLOODTHIRST: - at_bonus = MAX(1, level / 3); - df_malus = 2; - force = (int)get_force(power, 2); - break; - - default: - at_bonus = 1; - df_malus = 0; - force = (int)power; - } + at_bonus = MAX(1, level / 3); + df_malus = 2; + force = (int)get_force(power, 2); allies = count_allies(fi->side, FIGHT_ROW, BEHIND_ROW - 1, SELECT_ADVANCE, ALLY_ANY); @@ -1327,16 +1242,9 @@ int sp_windshield(struct castorder * co) int enemies; message *m; - switch (sp->id) { - case SPL_WINDSHIELD: - force = (int)get_force(power, 4); - at_malus = level / 4; - break; + force = (int)get_force(power, 4); + at_malus = level / 4; - default: - force = (int)power; - at_malus = 2; - } enemies = count_enemies(b, fi, BEHIND_ROW, BEHIND_ROW, SELECT_ADVANCE); if (!enemies) { m = msg_message("battle::out_of_range", "mage spell", fi->unit, sp); @@ -1429,7 +1337,7 @@ static void do_meffect(fighter * af, int typ, int effect, int duration) me->duration = duration; } -int sp_armorshield(struct castorder * co) +int armor_spell(struct castorder * co, int per_level, int time_multi) { fighter * fi = co->magician.fig; int level = co->level; @@ -1445,16 +1353,8 @@ int sp_armorshield(struct castorder * co) /* gibt R�stung +effect f�r duration Treffer */ - switch (sp->id) { - case SPL_ARMORSHIELD: - effect = level / 3; - duration = (int)(20 * power * power); - break; - - default: - effect = level / 4; - duration = (int)(power * power); - } + effect = level / per_level; + duration = (int)(time_multi * power * power); do_meffect(fi, SHIELD_ARMOR, effect, duration); return level; } @@ -1475,16 +1375,9 @@ int sp_reduceshield(struct castorder * co) /* jeder Schaden wird um effect% reduziert bis der Schild duration * Trefferpunkte aufgefangen hat */ - switch (sp->id) { - case SPL_REDUCESHIELD: - effect = 50; - duration = (int)(50 * power * power); - break; + effect = 50; + duration = (int)(50 * power * power); - default: - effect = level * 3; - duration = (int)get_force(power, 5); - } do_meffect(fi, SHIELD_REDUCE, effect, duration); return level; } @@ -1503,20 +1396,9 @@ int sp_fumbleshield(struct castorder * co) msg_release(m); /* der erste Zauber schl�gt mit 100% fehl */ + duration = 100; + effect = MAX(1, 25 - level); - switch (sp->id) { - case SPL_DRAIG_FUMBLESHIELD: - case SPL_GWYRRD_FUMBLESHIELD: - case SPL_CERDDOR_FUMBLESHIELD: - case SPL_TYBIED_FUMBLESHIELD: - duration = 100; - effect = MAX(1, 25 - level); - break; - - default: - duration = 100; - effect = 10; - } do_meffect(fi, SHIELD_BLOCK, effect, duration); return level; } diff --git a/src/spells/combatspells.h b/src/spells/combatspells.h index cf07c2a89..78da949e8 100644 --- a/src/spells/combatspells.h +++ b/src/spells/combatspells.h @@ -23,12 +23,10 @@ extern "C" { int sp_fumbleshield(struct castorder * co); int sp_shadowknights(struct castorder * co); int sp_combatrosthauch(struct castorder * co); - int sp_kampfzauber(struct castorder * co); int sp_healing(struct castorder * co); int sp_keeploot(struct castorder * co); int sp_reanimate(struct castorder * co); int sp_chaosrow(struct castorder * co); - int sp_flee(struct castorder * co); int sp_berserk(struct castorder * co); int sp_tiredsoldiers(struct castorder * co); int sp_reeling_arrows(struct castorder * co); @@ -51,6 +49,10 @@ extern "C" { int sp_undeadhero(struct castorder * co); int sp_immolation(struct castorder * co); + int flee_spell(struct castorder * co, int strength); + int damage_spell(struct castorder * co, int dmg, int strength); + int armor_spell(struct castorder * co, int per_level, int time_multi); + #ifdef __cplusplus } #endif diff --git a/src/tests.c b/src/tests.c index a9b4878b6..19deb91ea 100644 --- a/src/tests.c +++ b/src/tests.c @@ -356,7 +356,7 @@ void test_create_castorder(castorder *co, unit *u, int level, float force, int r spell * test_create_spell(void) { spell *sp; - sp = create_spell("testspell", 0); + sp = create_spell("testspell"); sp->components = (spell_component *)calloc(4, sizeof(spell_component)); assert_alloc(sp->components); diff --git a/src/util/rand.c b/src/util/rand.c index f5c8a28bc..441461068 100644 --- a/src/util/rand.c +++ b/src/util/rand.c @@ -36,23 +36,27 @@ int lovar(double xpct_x2) return (rng_int() % n + rng_int() % n) / 1000; } -/* NormalRand aus python, random.py geklaut, dort ist Referenz auf -* den Algorithmus. mu = Mittelwert, sigma = Standardabweichung. -* http://de.wikipedia.org/wiki/Standardabweichung#Diskrete_Gleichverteilung.2C_W.C3.BCrfel -*/ +/* gaussian distribution + * taken from http://c-faq.com/lib/gaussian.html + */ + double normalvariate(double mu, double sigma) { - static const double NV_MAGICCONST = 1.7155277699214135; - double z; - for (;;) { - double u1 = rng_double(); - double u2 = 1.0 - rng_double(); - z = NV_MAGICCONST * (u1 - 0.5) / u2; - if (z * z / 4.0 <= -log(u2)) { - break; - } + static double U, V; + static int phase = 0; + double Z; + + if (phase == 0) { + U = (rng_int() + 1.) / (RNG_RAND_MAX + 2.); + V = rng_int() / (RNG_RAND_MAX + 1.); + Z = sqrt(-2 * log(U)) * sin(2 * PI_D * V); } - return mu + z * sigma; + else { + Z = sqrt(-2 * log(U)) * cos(2 * PI_D * V); + } + phase = 1 - phase; + + return mu + Z *sigma; } int ntimespprob(int n, double p, double mod) @@ -73,7 +77,7 @@ bool chance(double x) { if (x >= 1.0) return true; - return rng_double() < x; + return (1-rng_double()) < x; } typedef struct random_source {