diff --git a/README.md b/README.md
index efd1318d9..7d9c4424d 100644
--- a/README.md
+++ b/README.md
@@ -18,3 +18,6 @@ This repository relies heavily on the use of submodules, and it pulls in most of
     ./s/build
 
 If you got this far and all went well, you have built a server (it is linked from the `game` subdirectory), and it will have passed some basic functionality tests.
+
+* [![Static Analysis](https://scan.coverity.com/projects/6742/badge.svg?flat=1)](https://scan.coverity.com/projects/6742/)
+* [![Build Status](https://api.travis-ci.org/eressea/server.svg?branch=develop)](https://travis-ci.org/eressea/server)
diff --git a/conf/e2/rules.xml b/conf/e2/rules.xml
index 9e40910e0..002c34960 100644
--- a/conf/e2/rules.xml
+++ b/conf/e2/rules.xml
@@ -15,7 +15,7 @@
       <item name="sword" amount="1"/>
       <item name="mallorn" amount="10"/>
       <item name="skillpotion" amount="5"/>
-      <item name="p2" amount="5"/>
+      <item name="lifepotion" amount="5"/>
       <item name="money" amount="20000"/>
       <skill name="perception" level="30"/>
       <skill name="melee" level="1"/>
diff --git a/conf/e3/config.json b/conf/e3/config.json
index 528d0a7f2..b5f9aed5c 100644
--- a/conf/e3/config.json
+++ b/conf/e3/config.json
@@ -93,7 +93,6 @@
         "rules.region_owners": true,
         "rules.cavalry.skill": 2,
         "rules.cavalry.mode": 1,
-        "rules.magic.multipotion": true,
         "rules.magic.wol_effect": 5,
         "rules.magic.factionlist": true,
         "rules.magic.wol_type": 2,
diff --git a/res/adamantium.xml b/res/adamantium.xml
index 563299e51..2e2311fcd 100644
--- a/res/adamantium.xml
+++ b/res/adamantium.xml
@@ -16,7 +16,7 @@
         <requirement type="adamantium" quantity="1"/>
         <requirement type="log" quantity="1"/>
       </construction>
-      <weapon cut="true" skill="melee" offmod="2" defmod="-2" magres="0.30">
+      <weapon cut="true" magical="true" skill="melee" offmod="2" defmod="-2" magres="0.30">
         <damage type="rider" value="3d4+15"/>
         <damage type="footman" value="3d4+15"/>
       </weapon>
diff --git a/res/core/common/potions.xml b/res/core/common/potions.xml
index bb4556eb7..fa3ce3478 100644
--- a/res/core/common/potions.xml
+++ b/res/core/common/potions.xml
@@ -34,7 +34,7 @@
     </item>
   </resource>
 
-  <resource name="p2" appearance="vial">
+  <resource name="lifepotion" appearance="vial">
     <item weight="0" score="30" use="yes">
       <potion level="1"/>
       <construction skill="alchemy" minskill="2">
@@ -167,7 +167,7 @@
     </item>
   </resource>
 
-  <resource name="p14" appearance="vial">
+  <resource name="healing" appearance="vial">
     <item weight="0" score="120" use="yes">
       <potion level="4"/>
       <construction skill="alchemy" minskill="8">
diff --git a/res/core/de/strings.xml b/res/core/de/strings.xml
index 896a7e009..98f047a39 100644
--- a/res/core/de/strings.xml
+++ b/res/core/de/strings.xml
@@ -1863,7 +1863,7 @@
   <string name="goliathwater">
     <text locale="de">Goliathwasser</text>
   </string>
-  <string name="p2">
+  <string name="lifepotion">
     <text locale="de">Wasser des Lebens</text>
   </string>
   <string name="p3">
@@ -1899,7 +1899,7 @@
   <string name="p13">
     <text locale="de">Elixier der Macht</text>
   </string>
-  <string name="p14">
+  <string name="healing">
     <text locale="de">Heiltrank</text>
   </string>
 
@@ -1909,7 +1909,7 @@
   <string name="goliathwater_p">
     <text locale="de">Goliathwasser</text>
   </string>
-  <string name="p2_p">
+  <string name="lifepotion_p">
     <text locale="de">Wasser des Lebens</text>
   </string>
   <string name="p3_p">
@@ -1945,7 +1945,7 @@
   <string name="p13_p">
     <text locale="de">Elixiere der Macht</text>
   </string>
-  <string name="p14_p">
+  <string name="healing_p">
     <text locale="de">Heiltränke</text>
   </string>
 
@@ -3592,7 +3592,7 @@
       <text locale="en">'First roast the Gurgelkraut quickly and add some Fjordwuchs to spice it up. Let it all boil slowly until almost all liquid has evaporated. Leave the mash overnight and finally squeeze it the next morning until a thick fluid drips out.' The liquid thus produced, 'Goliath Water' as we call it, is enough for 10 men and gives each man the carrying capacity of a horse for one week.</text>
       <text locale="de">Zuerst brate man das Gurgelkraut leicht an und würze das Zeug mit ein wenig Fjordwuchs. Man lasse alles so lange kochen, bis fast alle Flüssigkeit verdampft ist. Diesen Brei stelle man über Nacht raus. Am nächsten Morgen presse man den Brei aus. Die so gewonnene Flüssigkeit, Goliathwasser genannt, verleiht bis zu zehn Männern die Tragkraft eines Pferdes.</text>
     </string>
-    <string name="p2">
+    <string name="lifepotion">
       <text locale="en">The "Water of Life" allows living trees to be created from logs. A Knotroot and Elvendear are heated until one can just still keep one's finger in. This is then poured into a jar and allowed to cool slowly. The extract is sufficient for 10 pieces of wood.</text>
       <text locale="de">Das 'Wasser des Lebens' ist in der Lage, aus gefällten Baumstämmen wieder lebende Bäume zu machen. Dazu wird ein knotiger Saugwurz zusammen mit einem Elfenlieb erwärmt, so dass man gerade noch den Finger reinhalten kann. Dies gieße man in ein Gefäß und lasse es langsam abkühlen. Der Extrakt reicht für 10 Holzstämme.</text>
     </string>
@@ -3640,7 +3640,7 @@
       <text locale="en">One of the most rare and prized of all alchemist elixers, this potion grants the user a dragon's power for a few weeks. The potion increases the life-energy of a maximum of ten people fivefold. The effect is strongest right after drinking and slowly decreases over time. To brew this potion the alchemist needs an elvendear, a windbag, a piece of waterfinder and a spider ivy. Finally he dusts it with some minced bubblemorel and stirrs the powder into some dragon's blood. </text>
       <text locale="de">Eines der seltensten und wertvollsten alchemistischen Elixiere, verleiht dieser Trank dem Anwender für einige Wochen die Kraft eines Drachen. Der Trank erhöht die Lebensenergie von maximal zehn Personen auf das fünffache. Die Wirkung ist direkt nach der Einnahme am stärksten und klingt danach langsam ab. Zur Herstellung benötigt der Alchemist ein Elfenlieb, einen Windbeutel, ein Stück Wasserfinder und einen Grünen Spinnerich. Über dieses Mischung streue er schließlich einen zerriebenen Blasenmorchel und rühre dieses Pulver unter etwas Drachenblut.</text>
     </string>
-    <string name="p14">
+    <string name="healing">
       <text locale="en">For a healing potion one takes the peel of a windbag and some bugleweed, stirr in some chopped elvendear and sprinkle it with the blossoms of an ice begonia. This has to cook through for four days, while a gapgrowth has to be added on the second day. Then one carefully scoops off the top layer of liquid. One such potion gives four men (or one man four times) a 50% chance to survive otherwise lethal wounds. The potion is automatically used in case of injury.</text>
       <text locale="de">Für einen Heiltrank nehme man die Schale eines Windbeutels und etwas Gurgelkraut, rühre eine kleingehacktes Elfenlieb dazu und bestreue alles mit den Blüten einer Eisblume. Dies muß vier Tage lang gären, wobei man am zweiten Tag einen Spaltwachs dazutun muß. Dann ziehe man vorsichtig den oben schwimmenden Saft ab. Ein solcher Trank gibt vier Männern (oder einem Mann vier mal) im Kampf eine Chance von 50%, sonst tödliche Wunden zu überleben. Der Trank wird von ihnen automatisch bei Verletzung angewandt.</text>
     </string>
diff --git a/res/core/en/strings.xml b/res/core/en/strings.xml
index f818a3931..096dace78 100644
--- a/res/core/en/strings.xml
+++ b/res/core/en/strings.xml
@@ -1078,10 +1078,10 @@
   <string name="goliathwater_p">
     <text locale="en">goliath waters</text>
   </string>
-  <string name="p2">
+  <string name="lifepotion">
     <text locale="en">water of life</text>
   </string>
-  <string name="p2_p">
+  <string name="lifepotion_p">
     <text locale="en">waters of life</text>
   </string>
   <string name="p3">
@@ -1150,10 +1150,10 @@
   <string name="p13_p">
     <text locale="en">elixirs of power</text>
   </string>
-  <string name="p14">
+  <string name="healing">
     <text locale="en">healing potion</text>
   </string>
-  <string name="p14_p">
+  <string name="healing_p">
     <text locale="en">healing potions</text>
   </string>
 
diff --git a/res/core/fr/strings.xml b/res/core/fr/strings.xml
index 13e6beb25..d6c61e00c 100644
--- a/res/core/fr/strings.xml
+++ b/res/core/fr/strings.xml
@@ -1085,10 +1085,10 @@
   <string name="p1_p">
     <text locale="fr">breuvage de Goliath</text>
   </string>
-  <string name="p2">
+  <string name="lifepotion">
     <text locale="fr">élixir de vie</text>
   </string>
-  <string name="p2_p">
+  <string name="lifepotion_p">
     <text locale="fr">élixir de vie</text>
   </string>
   <string name="p3">
@@ -1157,10 +1157,10 @@
   <string name="p13_p">
     <text locale="fr">elixir d'endurance</text>
   </string>
-  <string name="p14">
+  <string name="healing">
     <text locale="fr">potion de survie</text>
   </string>
-  <string name="p14_p">
+  <string name="healing_p">
     <text locale="fr">potions de survie</text>
   </string>
 
diff --git a/res/core/messages.xml b/res/core/messages.xml
index 0c1ea60d9..b810b8a43 100644
--- a/res/core/messages.xml
+++ b/res/core/messages.xml
@@ -2800,7 +2800,7 @@
     <text locale="de">"$unit($unit) in $region($region) produziert $int($amount)$if($eq($wanted,$amount),""," von $int($wanted)") $resource($resource,$wanted)."</text>
     <text locale="en">"$unit($unit) in $region($region) produces $int($amount)$if($eq($wanted,$amount),""," of $int($wanted)") $resource($resource,$amount)."</text>
   </message>
-  <message name="buildbuilding" section="production">
+    <message name="buildbuilding" section="production">
     <type>
       <arg name="unit" type="unit"/>
       <arg name="size" type="int"/>
@@ -6783,14 +6783,22 @@
     <text locale="de">"$unit($unit) in $region($region): '$order($command)' - ${error}."</text>
     <text locale="en">"$unit($unit) in $region($region): '$order($command)' - ${error}."</text>
   </message>
+  <message name="usepotion" section="events">
+    <type>
+      <arg name="unit" type="unit"/>
+      <arg name="potion" type="resource"/>
+    </type>
+    <text locale="de">"$unit($unit) benutzt $resource($potion,1)."</text>
+    <text locale="en">"$unit($unit) uses $resource($potion,1)."</text>
+  </message>
   <message name="use_item" section="events">
     <type>
       <arg name="unit" type="unit"/>
       <arg name="item" type="resource"/>
       <arg name="amount" type="int"/>
     </type>
-    <text locale="de">"$unit($unit) benutzt $amount $resource($item,$amount)."</text>
-    <text locale="en">"$unit($unit) uses $amount $resource($item,$amount)."</text>
+    <text locale="de">"$unit($unit) benutzt $int($amount) $resource($item,$amount)."</text>
+    <text locale="en">"$unit($unit) uses $int($amount) $resource($item,$amount)."</text>
   </message>
   <message name="no_attack_after_advance" section="errors">
     <type>
@@ -6974,14 +6982,6 @@
     <text locale="de">"$unit($unit) verdient am Handel in $region($region) Steuern in Höhe von $int($amount) Silber."</text>
     <text locale="en">"$unit($unit) collected $int($amount) silver trade tax in $region($region)."</text>
   </message>
-  <message name="usepotion" section="events">
-    <type>
-      <arg name="unit" type="unit"/>
-      <arg name="potion" type="resource"/>
-    </type>
-    <text locale="de">"$unit($unit) benutzt $resource($potion,1)."</text>
-    <text locale="en">"$unit($unit) uses $resource($potion,1)."</text>
-  </message>
   <message name="pest" section="events">
     <type>
       <arg name="dead" type="int"/>
diff --git a/res/core/spells.xml b/res/core/spells.xml
index c4df3e429..fba087855 100644
--- a/res/core/spells.xml
+++ b/res/core/spells.xml
@@ -39,7 +39,7 @@
   <spell name="create_magicherbbag" ship="true" rank="5" index="165">
     <resource name="aura" amount="30" cost="fixed"/>
     <resource name="permaura" amount="1" cost="fixed"/>
-    <resource name="p2" amount="1" cost="fixed"/>
+    <resource name="lifepotion" amount="1" cost="fixed"/>
   </spell>
 
   <!-- illaun spells -->
diff --git a/res/core/weapons/firesword.xml b/res/core/weapons/firesword.xml
index dc3b47af5..0285db7ea 100644
--- a/res/core/weapons/firesword.xml
+++ b/res/core/weapons/firesword.xml
@@ -3,7 +3,7 @@
 <resources>
 <resource name="firesword">
   <item weight="100">
-    <weapon magres="0.3" cut="true" skill="melee" offmod="1" defmod="1">
+    <weapon magres="0.3" cut="true" magical="true" skill="melee" offmod="1" defmod="1">
       <function name="attack" value="attack_firesword"/>
       <damage type="rider" value="3d6+10"/>
       <damage type="footman" value="3d6+10"/>
diff --git a/res/core/weapons/laensword.xml b/res/core/weapons/laensword.xml
index 325d25d10..2746a6384 100644
--- a/res/core/weapons/laensword.xml
+++ b/res/core/weapons/laensword.xml
@@ -6,7 +6,7 @@
     <construction skill="weaponsmithing" minskill="8">
       <requirement type="laen" quantity="1"/>
     </construction>
-    <weapon cut="true" skill="melee" offmod="1" defmod="1" magres="0.30">
+    <weapon cut="true" magical="true" skill="melee" offmod="1" defmod="1" magres="0.30">
       <damage type="rider" value="3d6+10"/>
       <damage type="footman" value="3d6+10"/>
     </weapon>
diff --git a/res/e3a/items.xml b/res/e3a/items.xml
index 1d403cfb4..42d425b24 100644
--- a/res/e3a/items.xml
+++ b/res/e3a/items.xml
@@ -52,7 +52,7 @@
     </item>
   </resource>
 
-  <resource name="p14" appearance="vial">
+  <resource name="healing" appearance="vial">
     <!-- Heiltrank -->
     <item weight="0" score="120" use="yes">
       <potion level="4"/>
@@ -66,7 +66,7 @@
     </item>
   </resource>
 
-  <resource name="p2" appearance="vial">
+  <resource name="lifepotion" appearance="vial">
     <!-- Wasser des Lebens -->
     <item weight="0" score="30" use="yes">
       <potion level="1"/>
diff --git a/res/e3a/spellbooks/cerddor.xml b/res/e3a/spellbooks/cerddor.xml
index 9e1a3f835..b52fe5d6f 100644
--- a/res/e3a/spellbooks/cerddor.xml
+++ b/res/e3a/spellbooks/cerddor.xml
@@ -7,7 +7,7 @@
   <entry spell="create_potion_peasantblood" level="5" />
   <entry spell="create_potion_ointment" level="6" />
   <entry spell="create_potion_p3" level="7" />
-  <entry spell="create_potion_p14" level="8" />
+  <entry spell="create_potion_healing" level="8" />
   <entry spell="create_potion_p13" level="9" />
   <entry spell="create_roi" level="7" />
   <entry spell="create_aots" level="6" />
diff --git a/res/e3a/spellbooks/draig.xml b/res/e3a/spellbooks/draig.xml
index a0da7b449..2d29b44ca 100644
--- a/res/e3a/spellbooks/draig.xml
+++ b/res/e3a/spellbooks/draig.xml
@@ -7,7 +7,7 @@
   <entry spell="create_potion_peasantblood" level="5" />
   <entry spell="create_potion_ointment" level="6" />
   <entry spell="create_potion_p3" level="7" />
-  <entry spell="create_potion_p14" level="8" />
+  <entry spell="create_potion_healing" level="8" />
   <entry spell="create_potion_p13" level="9" />
   <entry spell="create_roi" level="7" />
   <entry spell="create_aots" level="6" />
diff --git a/res/e3a/spellbooks/gray.xml b/res/e3a/spellbooks/gray.xml
index a807963c2..998405b03 100644
--- a/res/e3a/spellbooks/gray.xml
+++ b/res/e3a/spellbooks/gray.xml
@@ -38,7 +38,7 @@
     <entry spell="create_potion_ointment" level="6" />
     <entry spell="create_potion_p0" level="3" />
     <entry spell="create_potion_p13" level="9" />
-    <entry spell="create_potion_p14" level="8" />
+    <entry spell="create_potion_healing" level="8" />
     <entry spell="create_potion_p2" level="2" />
     <entry spell="create_potion_p3" level="7" />
     <entry spell="create_potion_p9" level="4" />
diff --git a/res/e3a/spellbooks/gwyrrd.xml b/res/e3a/spellbooks/gwyrrd.xml
index 83fd4e99c..76cf7a154 100644
--- a/res/e3a/spellbooks/gwyrrd.xml
+++ b/res/e3a/spellbooks/gwyrrd.xml
@@ -7,7 +7,7 @@
   <entry spell="create_potion_peasantblood" level="5" />
   <entry spell="create_potion_ointment" level="6" />
   <entry spell="create_potion_p3" level="7" />
-  <entry spell="create_potion_p14" level="8" />
+  <entry spell="create_potion_healing" level="8" />
   <entry spell="create_potion_p13" level="9" />
   <entry spell="create_roi" level="7" />
   <entry spell="create_aots" level="6" />
diff --git a/res/e3a/spellbooks/illaun.xml b/res/e3a/spellbooks/illaun.xml
index 02c9b34d8..0392842c2 100644
--- a/res/e3a/spellbooks/illaun.xml
+++ b/res/e3a/spellbooks/illaun.xml
@@ -7,7 +7,7 @@
   <entry spell="create_potion_peasantblood" level="5" />
   <entry spell="create_potion_ointment" level="6" />
   <entry spell="create_potion_p3" level="7" />
-  <entry spell="create_potion_p14" level="8" />
+  <entry spell="create_potion_healing" level="8" />
   <entry spell="create_potion_p13" level="9" />
   <entry spell="create_roi" level="7" />
   <entry spell="create_aots" level="6" />
diff --git a/res/e3a/spells.xml b/res/e3a/spells.xml
index 25d123d43..f3edbd9f6 100644
--- a/res/e3a/spells.xml
+++ b/res/e3a/spells.xml
@@ -421,7 +421,7 @@
     <resource name="h20" amount="1" cost="linear"/><!-- Schneekristall -->
     <resource name="h9" amount="1" cost="linear"/><!-- Wasserfinder -->
   </spell>
-  <spell name="create_potion_p14" ship="true" rank="5" variable="true">
+  <spell name="create_potion_healing" ship="true" rank="5" variable="true">
     <!-- Heiltrank -->
     <resource name="aura" amount="5" cost="linear"/>
     <resource name="h0" amount="1" cost="linear"/><!-- Flachwurz -->
diff --git a/res/e3a/strings.xml b/res/e3a/strings.xml
index 2dd79abb6..4a089cb50 100644
--- a/res/e3a/strings.xml
+++ b/res/e3a/strings.xml
@@ -197,7 +197,7 @@
       <text locale="de">Braue Elixier der Macht</text>
       <text locale="en">brew elixir of power</text>
     </string>
-    <string name="create_potion_p14">
+    <string name="create_potion_healing">
       <text locale="de">Braue Heiltrank</text>
       <text locale="en">brew healing potion</text>
     </string>
@@ -264,7 +264,7 @@
       <text locale="en">Just like with the knowledge about death, the peasants feel uncomfortable with the knowledge about monsters. A few warriors though, who have already faced these creatures in combat, found that the monsters blood had an invigourating effect on them. There is talk about some warriors who bathed in the blood of the slain monsters to take up their strength. But this effect ends soon, and only occurs with fresh blood. As no one has time to quickly slay a wyrm before attacking their neighbors, a way had to be found to make the effect last longer. After lots of experiments that cost the life of lots of good warriors who had to constantly bring in fresh dragon blood, Manasouf the black finally found a way. Originally a closely guarded secret, the recipe is now known in all lands. First, the hardened dragon blood needs to be melted in hot tin. After that, the magician binds the spirit of the dragon to its blood once again. It can not find eternal rest until the last bit of blood has been used. </text>
       <text locale="de">Ebenso wie das Wissen über den Tod ist das Wissen über gewisse Monster bei der abergläubigen Bevölkerung nicht gerne gesehen. Einige wenige Krieger jedoch, die diesen Kreaturen schon mal im Kampf gegenüberstanden, haben entdeckt, dass deren Blut eine belebende Wirkung auf sie hatte. So soll es schon Krieger gegeben haben, die im Blut der erschlagenen Monster badeten, um deren Stärke in sich aufzunehmen. Diese Wirkung verfliegt jedoch rasch und wirkt nur bei frischen Blut. Da niemand vor dem Kampf gegen seinen Nachbarn die Zeit hat, schnell noch einen Wyrm zu erschlagen, musste ein Weg gefunden werden, die Wirkung haltbar zu machen. Manasouf dem Schwarzen gelang dies nach zahlreichen Experimenten, die das Leben vieler guter Männer kosteten, welche ständig neues Drachenblut für seine Versuche beschaffen mussten. Ursprünglich ein streng gehütetes Geheimnis ist das Rezept inzwischen im ganzen Land bekannt. Zunächst muss geronnenes Drachenblut in heißem Zinn verflüssigt werden. Anschließend wird der Geist des erschlagenen Drachen in der Geisterebene wieder an sein Blut gebunden und kann so lange nicht in Frieden ruhen, bis das letzte bisschen seines Blutes verbraucht wurde.</text>
     </string>
-    <string name="create_potion_p14">
+    <string name="create_potion_healing">
       <text locale="en">Some mages research death's secrets until they can bring the dead back to life. But those who are brought back are often only shadows of ther former self and turn against their erstwhile friends. But those mages that study life and its iteraction with death find a possibility to bring the deceased back as their original selves. A drawback is that this is only possible in the very first minutes after death. As even mages can not be everywhere at the same time, a way had to be found to give this ability to helpers. All healers who tried to learn this from the mages failed, though, until one of those healers was backstabbingly killed. In the moment of his death he used the knowledge gained and was able to have his murderer executed the following day. The potion he designed has to be blessed by a magician before usage at any given time. This potion gives four people (or one person four times) a 50% chance to survive an otherwise deadly wound. It is used automatically by the victom.</text>
       <text locale="de">Manche Magier erforschen den Tod, bis sie Verstorbene wieder ins Leben zurück bringen können. Diese sind jedoch meist bösartig und nur noch Schatten ihres früheren Selbst. Diejenigen jedoch, die sich intensiv mit dem Leben und seiner Kombination mit dem Tod beschäftigen, finden eine Möglichkeit, Verstorbene in ihrer wahren Gestalt zurück zu rufen. Dies ist allerdings nur wenige Minuten nach dem Tod möglich. Da selbst Magier nicht überall gleichzeitig sein können, musste ein Weg gefunden werden, diese Fähigkeit auf andere zu übertragen. Alle Versuche, dies Feldschern beizubringen, scheiterten jedoch, bis einer dieser Feldscher von einem Widersacher hinterrücks ermordet wurde. Im Moment seines Todes wandte er sein erworbenes Wissen an und konnte tags darauf den Übeltäter wegen Mordes hinrichten lassen. Der von ihm entwickelte magische Trank muss jedoch von einem der Magie des Lebens Kundigen gesegnet werden, um seine volle Wirkung zu entfalten. Ein solcher Trank gibt vier Männern (oder einem Mann viermal) im Kampf eine Chance von 50%, sonst tödliche Wunden zu überleben. Der Trank wird von ihnen automatisch bei Verletzung angewandt.</text>
     </string>
@@ -284,7 +284,7 @@
   </namespace>
 
   <namespace name="potion">
-    <string name="p2">
+    <string name="lifepotion">
       <text locale="en">The "Water of Life" allows living trees to be created from logs. A Knotroot and Elvendear are heated until one can just still keep one's finger in. This is then poured into a jar and allowed to cool slowly. The extract is sufficient for five trees to be grown from logs.</text>
       <text locale="de">Das 'Wasser des Lebens' ist in der Lage, aus gefällten Baumstämmen wieder lebende Bäume zu machen. Dazu wird ein knotiger Saugwurz zusammen mit einem Elfenlieb erwärmt, so dass man gerade noch den Finger reinhalten kann. Dies gieße man in ein Gefäß und lasse es langsam abkühlen. Der Extrakt reicht um aus fünf Holzstämmen neue Bäume wachsen zu lassen.</text>
     </string>
diff --git a/res/e3a/weapons.xml b/res/e3a/weapons.xml
index 5b57cbed0..3a75fe350 100644
--- a/res/e3a/weapons.xml
+++ b/res/e3a/weapons.xml
@@ -86,7 +86,7 @@
     <construction skill="weaponsmithing" minskill="8">
       <requirement type="laen" quantity="1"/>
     </construction>
-    <weapon cut="true" skill="melee" offmod="1" defmod="1" magres="0.30">
+    <weapon cut="true" magical="true" skill="melee" offmod="1" defmod="1" magres="0.30">
       <damage type="rider" value="2d9+4"/>
       <damage type="footman" value="2d9+4"/>
     </weapon>
diff --git a/res/eressea/spells.xml b/res/eressea/spells.xml
index 089ec1a6c..7680f2f3b 100644
--- a/res/eressea/spells.xml
+++ b/res/eressea/spells.xml
@@ -32,7 +32,7 @@
   <spell name="treegrow" rank="5" index="8" far="true" variable="true">
     <resource name="aura" amount="4" cost="level"/>
     <resource name="log" amount="1" cost="level"/>
-    <resource name="p2" amount="1" cost="fixed"/>
+    <resource name="lifepotion" amount="1" cost="fixed"/>
   </spell>
   <spell name="healing" rank="5" index="9" variable="true" combat="3">
     <resource name="aura" amount="1" cost="level"/>
@@ -101,12 +101,12 @@
   <spell name="stonegolem" rank="4" index="32" variable="true">
     <resource name="aura" amount="2" cost="level"/>
     <resource name="stone" amount="1" cost="level"/>
-    <resource name="p2" amount="1" cost="fixed"/>
+    <resource name="lifepotion" amount="1" cost="fixed"/>
   </spell>
   <spell name="irongolem" rank="4" index="33" variable="true">
     <resource name="aura" amount="2" cost="level"/>
     <resource name="iron" amount="1" cost="level"/>
-    <resource name="p2" amount="1" cost="fixed"/>
+    <resource name="lifepotion" amount="1" cost="fixed"/>
   </spell>
   <spell name="summonshadow" rank="5" index="34" variable="true">
     <resource name="aura" amount="3" cost="level"/>
@@ -433,7 +433,7 @@
   </spell>
   <spell name="puttorest" rank="5" index="168" variable="true">
     <resource name="aura" amount="3" cost="level"/>
-    <resource name="p2" amount="1" cost="fixed"/>
+    <resource name="lifepotion" amount="1" cost="fixed"/>
   </spell>
   <spell name="unholypower" rank="5" index="169" parameters="u+" los="true" variable="true">
     <resource name="aura" amount="10" cost="level"/>
@@ -455,7 +455,7 @@
     <resource name="aura" amount="100" cost="fixed"/>
     <resource name="permaura" amount="20" cost="fixed"/>
     <resource name="dragonblood" amount="5" cost="fixed"/>
-    <resource name="p2" amount="5" cost="fixed"/>
+    <resource name="lifepotion" amount="5" cost="fixed"/>
   </spell>
   <spell name="drain_skills" rank="5" index="174" combat="2">
     <resource name="aura" amount="4" cost="fixed"/>
@@ -466,7 +466,7 @@
   <spell name="mallorntreegrow" rank="5" index="177" far="true" variable="true">
     <resource name="aura" amount="6" cost="level"/>
     <resource name="mallorn" amount="1" cost="level"/>
-    <resource name="p2" amount="1" cost="fixed"/>
+    <resource name="lifepotion" amount="1" cost="fixed"/>
   </spell>
   <spell name="big_recruit" rank="5" index="179" variable="true">
     <resource name="aura" amount="20" cost="level"/>
@@ -515,7 +515,7 @@
   <spell name="create_magicherbbag" ship="true" rank="5" index="165">
     <resource name="aura" amount="30" cost="fixed"/>
     <resource name="permaura" amount="1" cost="fixed"/>
-    <resource name="p2" amount="1" cost="fixed"/>
+    <resource name="lifepotion" amount="1" cost="fixed"/>
   </spell>
 
   <!-- illaun spells -->
diff --git a/s/runtests b/s/runtests
index 7a39670dd..b74a4b785 100755
--- a/s/runtests
+++ b/s/runtests
@@ -4,12 +4,12 @@ set -e
 ROOT=$(git rev-parse --show-toplevel)
 [ -z $BUILD ] && BUILD=Debug ; export BUILD
 
-UNIT_TESTS=$BUILD/eressea/test_eressea
-RUN_TESTS=$BUILD/eressea/eressea
+UNIT_TESTS=$ROOT/$BUILD/eressea/test_eressea
+RUN_TESTS=$ROOT/$BUILD/eressea/eressea
 if [ "$1" = "-V" ]; then
 VALGRIND=$(which valgrind)
 if [ -n "$VALGRIND" ]; then
-SUPP=share/ubuntu-12_04.supp
+SUPP=$ROOT/share/ubuntu-12_04.supp
 UNIT_TESTS="$VALGRIND --quiet --suppressions=$SUPP --error-exitcode=1 --leak-check=no $UNIT_TESTS"
 RUN_TESTS="$VALGRIND --quiet --suppressions=$SUPP --error-exitcode=1 --leak-check=no $RUN_TESTS"
 fi
@@ -21,12 +21,11 @@ if [ ! -e $ROOT/$BUILD ]; then
 fi
 
 $UNIT_TESTS
-cd $ROOT
-[ -e eressea.ini ] || ln -sf conf/eressea.ini
-$RUN_TESTS -v1 scripts/run-tests.lua
-$RUN_TESTS -v1 scripts/run-tests-e2.lua
-$RUN_TESTS -v1 scripts/run-tests-e3.lua
+cd $ROOT/tests
+$RUN_TESTS -v1 ../scripts/run-tests.lua
+$RUN_TESTS -v1 ../scripts/run-tests-e2.lua
+$RUN_TESTS -v1 ../scripts/run-tests-e3.lua
 $RUN_TESTS --version
-rm -rf data reports orders.txt score score.alliances datum turn
+rm -rf reports orders.txt score score.alliances datum turn
 
 cd $OLDWPD
diff --git a/scripts/eressea/spells.lua b/scripts/eressea/spells.lua
index 5e04c4ed1..eb33dd95f 100644
--- a/scripts/eressea/spells.lua
+++ b/scripts/eressea/spells.lua
@@ -26,7 +26,7 @@ end
 
 -- Wasser des Lebens
 function create_potion_p2(r, mage, level, force)
-  return create_potion(mage, level, "p2", force)
+  return create_potion(mage, level, "lifepotion", force)
 end
 
 -- Siebenmeilentee
@@ -55,8 +55,8 @@ function create_potion_p3(r, mage, level, force)
 end
 
 -- Heiltrank
-function create_potion_p14(r, mage, level, force)
-  return create_potion(mage, level, "p14", force)
+function create_potion_healing(r, mage, level, force)
+  return create_potion(mage, level, "healing", force)
 end
 
 -- Elixier der Macht
diff --git a/scripts/eressea/xmasitems.lua b/scripts/eressea/xmasitems.lua
index dffea2675..9e22dea52 100644
--- a/scripts/eressea/xmasitems.lua
+++ b/scripts/eressea/xmasitems.lua
@@ -62,10 +62,11 @@ function use_snowglobe(u, amount, token, ord)
 end
 
 function use_snowman(u, amount)
-    if amount>0 and u.region.terrain == "glacier" then
-        local man = unit.create(u.faction, u.region, amount, "snowman")
+    if amount > 0 and u.region.terrain == "glacier" then
+        unit.create(u.faction, u.region, amount, "snowman")
         return amount
     end
+    -- print error76:
     return -4
 end
 
@@ -79,7 +80,8 @@ function use_xmastree(u, amount)
         msg:send_region(u.region)
         return amount
     end
-    return 0
+    -- print error76:
+    return -4
 end
 
 local self = {}
diff --git a/scripts/tests/e2/e2features.lua b/scripts/tests/e2/e2features.lua
index 2c9c42e5b..d9a7da4f8 100644
--- a/scripts/tests/e2/e2features.lua
+++ b/scripts/tests/e2/e2features.lua
@@ -9,6 +9,7 @@ function setup()
     eressea.settings.set("rules.ship.storms", "0")
     eressea.settings.set("rules.encounters", "0")
     eressea.settings.set("study.produceexp", "0")
+    eressea.settings.set("rules.peasants.growth.factor", "0")
 end
 
 function test_calendar()
@@ -19,7 +20,7 @@ end
 function test_herbalism()
 -- OBS: herbalism is currently an E2-only skill
     local r = region.create(0, 0, "plain")
-    local f = faction.create("human", "herbalism@eressea.de", "de")
+    local f = faction.create("human")
     local u = unit.create(f, r, 1)
 
     eressea.settings.set("rules.grow.formula", 0) -- plants do not grow
diff --git a/scripts/tests/e2/items.lua b/scripts/tests/e2/items.lua
index 2f2b13e88..ce7b76b40 100644
--- a/scripts/tests/e2/items.lua
+++ b/scripts/tests/e2/items.lua
@@ -28,7 +28,7 @@ end
 
 function test_nestwarmth_insect()
     local r = region.create(0, 0, "plain")
-    local f = faction.create("insect", "noreply@eressea.de", "de")
+    local f = faction.create("insect")
     local u = unit.create(f, r, 1)
     local flags = u.flags
     u:add_item("nestwarmth", 2)
@@ -38,13 +38,13 @@ function test_nestwarmth_insect()
     turn_process()
     assert_equal(flags+64, u.flags) -- UFL_WARMTH
     assert_equal(1, u:get_item("nestwarmth"))
-    assert_equal(1, f:count_msg_type('usepotion'))
+    assert_equal(1, f:count_msg_type('use_item'))
     turn_end()
 end
 
 function test_nestwarmth_other()
     local r = region.create(0, 0, "plain")
-    local f = faction.create("human", "noreply@eressea.de", "de")
+    local f = faction.create("human")
     local u = unit.create(f, r, 1)
     local flags = u.flags
     u:add_item("nestwarmth", 2)
@@ -60,7 +60,7 @@ end
 
 function test_meow()
     local r = region.create(0, 0, "plain")
-    local f = faction.create("human", "noreply@eressea.de", "de")
+    local f = faction.create("human")
     local u = unit.create(f, r, 1)
     u:add_item("aoc", 1)
     u:clear_orders()
@@ -74,7 +74,7 @@ end
 
 function test_aurapotion50()
     local r = region.create(0, 0, "plain")
-    local f = faction.create("human", "noreply@eressea.de", "de")
+    local f = faction.create("human")
     local u = unit.create(f, r, 1)
     u:add_item("aurapotion50", 1)
     u:set_skill('magic', 10);
@@ -92,7 +92,7 @@ end
 
 function test_bagpipe()
     local r = region.create(0, 0, "plain")
-    local f = faction.create("human", "noreply@eressea.de", "de")
+    local f = faction.create("human")
     local u = unit.create(f, r, 1)
     turn_begin()
     u:add_item("bagpipeoffear", 1)
@@ -109,9 +109,19 @@ function test_bagpipe()
     assert_equal(0, r:get_curse('depression'))
 end
 
+function test_monthly_healing()
+    local r = region.create(0, 0, "plain")
+    local f = faction.create("human")
+    local u = unit.create(f, r, 30)
+    assert_equal(600, u.hp)
+    u.hp = 100
+    process_orders()
+    assert_equal(130, u.hp)
+end
+
 function test_speedsail()
     local r = region.create(0, 0, "plain")
-    local f = faction.create("human", "noreply@eressea.de", "de")
+    local f = faction.create("human")
     local u = unit.create(f, r, 1)
     
     turn_begin()
@@ -128,9 +138,9 @@ function test_speedsail()
     assert_equal(1, u.ship:get_curse('shipspeed')) -- effect stays forever
 end
 
-function disable_test_foolpotion()
+function test_use_foolpotion()
     local r = region.create(0, 0, "plain")
-    local f = faction.create("human", "noreply@eressea.de", "de")
+    local f = faction.create("human")
     local u = unit.create(f, r, 1)
     turn_begin()
     u:add_item('p7', 2)
@@ -159,7 +169,7 @@ end
 
 function test_snowman()
     local r = region.create(0, 0, "glacier")
-    local f = faction.create("human", "noreply@eressea.de", "de")
+    local f = faction.create("human")
     local u = unit.create(f, r, 1)
     u:add_item("snowman", 1)
     u:clear_orders()
diff --git a/scripts/tests/e3/production.lua b/scripts/tests/e3/production.lua
index be63158cf..3469b06c4 100644
--- a/scripts/tests/e3/production.lua
+++ b/scripts/tests/e3/production.lua
@@ -53,7 +53,6 @@ function test_dwarf_no_mining_bonus()
     local r = region.create(0, 0, 'mountain')
     local f = create_faction('dwarf')
     local u = unit.create(f, r, 1)
-    u.name = 'Xolgrim'
 
     turn_begin()
     r:set_resource('iron', 100)
diff --git a/scripts/tests/e3/rules.lua b/scripts/tests/e3/rules.lua
index 0888aa0b9..5120fb747 100644
--- a/scripts/tests/e3/rules.lua
+++ b/scripts/tests/e3/rules.lua
@@ -783,12 +783,12 @@ function test_p2()
     r:set_resource("tree", 0)
     u:clear_orders()
     u:add_order("BENUTZE 'Wasser des Lebens'")
-    u:add_item("p2", 1)
+    u:add_item("lifepotion", 1)
     u:add_item("log", 10)
     u:add_item("mallorn", 10)
     process_orders()
     assert_equal(5, r:get_resource("tree"))
-    assert_equal(0, u:get_item("p2"))
+    assert_equal(0, u:get_item("lifepotion"))
     assert_equal(15, u:get_item("log") + u:get_item("mallorn"))
 end
 
@@ -803,7 +803,7 @@ function test_p2_move()
     u:add_order("BENUTZE 'Wasser des Lebens'")
     u:add_order("NACH OST")
     u:add_item("horse", 1)
-    u:add_item("p2", 1)
+    u:add_item("lifepotion", 1)
     u:add_item("log", 1)
     u:add_item("mallorn", 1)
     process_orders()
diff --git a/scripts/tests/economy.lua b/scripts/tests/economy.lua
index 719b1f764..3379b2ab7 100644
--- a/scripts/tests/economy.lua
+++ b/scripts/tests/economy.lua
@@ -9,6 +9,22 @@ function setup()
     eressea.settings.set("nmr.timeout", "0")
     eressea.settings.set("rules.food.flags", "4") -- FOOD_IS_FREE
     eressea.settings.set("rules.encounters", "0")
+    eressea.settings.set("rules.peasants.growth.factor", "0")
+end
+
+function test_work()
+    local r = region.create(0, 0, "plain")
+    r:set_resource('tree', 0)
+    r:set_resource('seed', 0)
+    r:set_resource('sapling', 0)
+    r:set_resource('peasant', 100)
+    r:set_resource('money', 0)
+    local f = faction.create("human")
+    local u = unit.create(f, r, 1)
+    u:add_order("ARBEITE")
+    process_orders()
+    assert_equal(10, u:get_item('money'))
+    assert_equal(100, r:get_resource('money'))
 end
 
 function test_bug_2361_forget_magic()
diff --git a/scripts/tests/items.lua b/scripts/tests/items.lua
index 153bfb803..60bbf100f 100644
--- a/scripts/tests/items.lua
+++ b/scripts/tests/items.lua
@@ -121,19 +121,90 @@ function test_antimagic()
     assert_equal(nil, r:get_curse('antimagiczone'))
 end
 
-function test_ointment()
+function test_use_healing_potion()
+    -- Heiltrank kann (auch) mit BENUTZE eingesetzt werden
     local r = region.create(0, 0, "plain")
     local f = faction.create("human")
-    local u = unit.create(f, r, 1)
-    local hp = u.hp
-    u.hp = 1
+    local u = unit.create(f, r, 30)
+    assert_equal(600, u.hp)
+    u.hp = 100
+    turn_begin()
+    u:add_item("healing", 1)
+    u:clear_orders()
+    u:add_order("BENUTZEN 1 Heiltrank")
+    turn_process()
+    assert_equal(530, u.hp)
+    assert_equal(0, u:get_item("healing"))
+    assert_equal(1, f:count_msg_type('use_item'))
+    turn_end()
+end
+
+function test_use_healing_potion_multi_units()
+    -- Heiltrank kann mehrere Einheiten heilen
+    local r = region.create(0, 0, "plain")
+    local f = faction.create("human")
+    local u1 = unit.create(f, r, 30)
+    local u = unit.create(f, r, 30)
+    assert_equal(600, u1.hp)
+    assert_equal(600, u.hp)
+    u.hp = 400
+    u1.hp = 400
+    turn_begin()
+    u:add_item("healing", 1)
+    u:clear_orders()
+    u:add_order("BENUTZEN 1 Heiltrank")
+    turn_process()
+    assert_equal(600, u.hp)
+    assert_equal(600, u1.hp)
+    assert_equal(0, u:get_item("healing"))
+    turn_end()
+end
+
+function test_use_multiple_healing_potions()
+    -- Einheit kann mehr als einen Heiltrank benutzen
+    local r = region.create(0, 0, "plain")
+    local f = faction.create("human")
+    local u = unit.create(f, r, 60)
+    assert_equal(1200, u.hp)
+    u.hp = 400
+    turn_begin()
+    u:add_item("healing", 2)
+    u:clear_orders()
+    u:add_order("BENUTZEN 2 Heiltrank")
+    turn_process()
+    assert_equal(1200, u.hp)
+    assert_equal(0, u:get_item("healing"))
+    turn_end()
+end
+
+function test_use_elixir()
+    local r = region.create(0, 0, "plain")
+    local f = faction.create("human")
+    local u = unit.create(f, r, 10)
+    assert_equal(200, u.hp)
+    u:add_item("p13", 1)
+    u:clear_orders()
+    u:add_order("BENUTZEN 1 Elixier~der~Macht")
+    process_orders()
+    -- potion makes hp 1000, monthly_healing takes away 400:
+    assert_equal(600, u.hp)
+    assert_equal(0, u:get_item("p13"))
+    assert_equal(1, f:count_msg_type('use_item'))
+end
+
+function test_use_ointment()
+    local r = region.create(0, 0, "plain")
+    local f = faction.create("human")
+    local u = unit.create(f, r, 30)
+    assert_equal(600, u.hp)
+    u.hp = 100
     u:add_item("ointment", 1)
     u:clear_orders()
     u:add_order("BENUTZEN 1 Wundsalbe")
     process_orders()
+    assert_equal(530, u.hp)
     assert_equal(0, u:get_item("ointment"))
-    assert_equal(1, f:count_msg_type('usepotion'))
-    assert_equal(hp, u.hp)
+    assert_equal(1, f:count_msg_type('use_item'))
 end
 
 function test_use_domore()
@@ -145,7 +216,7 @@ function test_use_domore()
     process_orders()
     assert_equal(10, u:effect("p3"))
     assert_equal(0, u:get_item("p3"))
-    assert_equal(1, f:count_msg_type('usepotion'))
+    assert_equal(1, f:count_msg_type('use_item'))
     u:clear_orders()
     u:set_skill('weaponsmithing', 3)
     u:add_item("iron", 2)
@@ -166,7 +237,7 @@ function test_bloodpotion_demon()
     process_orders()
     assert_equal(100, u:effect('peasantblood'))
     assert_equal(0, u:get_item("peasantblood"))
-    assert_equal(1, f:count_msg_type('usepotion'))
+    assert_equal(1, f:count_msg_type('use_item'))
     assert_equal("demon", u.race)
 end
 
@@ -180,6 +251,6 @@ function test_bloodpotion_other()
     process_orders()
     assert_equal(0, u:effect('peasantblood'))
     assert_equal(0, u:get_item("peasantblood"))
-    assert_equal(1, f:count_msg_type('usepotion'))
+    assert_equal(1, f:count_msg_type('use_item'))
     assert_equal("smurf", u.race)
 end
diff --git a/scripts/tests/process.lua b/scripts/tests/process.lua
index f6ea63933..1fc9a64f5 100644
--- a/scripts/tests/process.lua
+++ b/scripts/tests/process.lua
@@ -2,11 +2,10 @@ require "lunit"
 
 module("tests.process", package.seeall, lunit.testcase)
 
-local u, r, f, turn
+local u, r, f
 
 function setup()
     eressea.free_game()
-    turn = get_turn()
     r = region.create(0, 0, "plain")
     f = faction.create("human", "bernd@eressea.de", "de")
     u = unit.create(f, r, 1)
@@ -25,17 +24,31 @@ local function assert_file(filename, exists)
 end
 
 function test_process_turn()
+    turn_begin()
+    turn = get_turn()
+    turn_process()
+    turn_end()
+    assert_equal(turn, get_turn())
+    turn_begin()
+    assert_equal(turn+1, get_turn())
+    turn_process()
+    turn_end()
+end
+
+function test_write_reports()
+    turn_begin()
+    turn = get_turn()
     u:add_order("NUMMER PARTEI 777")
-    process_orders()
+    turn_process()
     assert_equal(0, init_reports())
     assert_equal(0, write_reports())
-    assert_equal(0, eressea.write_game("test.dat"))
-    assert_file("data/test.dat")
-    assert_file("reports/" .. get_turn() .. "-777.nr")
-    assert_file("reports/" .. get_turn() .. "-777.cr")
-    assert_file("reports/" .. get_turn() .. "-777.txt")
+    assert_file("reports/" .. turn .. "-777.nr")
+    assert_file("reports/" .. turn .. "-777.cr")
+    assert_file("reports/" .. turn .. "-777.txt")
     assert_file("reports/reports.txt")
     os.remove("reports")
-    os.remove("data")
-    assert_equal(turn+1, get_turn())
+    assert_equal(0, eressea.write_game("test.dat"))
+    assert_file("data/test.dat")
+    os.remove("data/test.dat")
+    turn_end()
 end
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 8a17a45e9..3c47385f1 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -86,13 +86,13 @@ ENDIF()
 
 set (ERESSEA_SRC
   vortex.c
-  calendar.c
   move.c
   piracy.c
   spells.c
   battle.c
   alchemy.c
   academy.c
+  chaos.c
   upkeep.c
   names.c
   lighthouse.c
@@ -121,7 +121,6 @@ set (ERESSEA_SRC
   randenc.c
   renumber.c
   volcano.c
-  chaos.c
   spy.c
   study.c
   summary.c
@@ -198,7 +197,6 @@ set(TESTS_SRC
   academy.test.c
   alchemy.test.c
   battle.test.c
-  calendar.test.c
   creport.test.c
   direction.test.c
   donations.test.c
diff --git a/src/alchemy.c b/src/alchemy.c
index 75212e34a..4b7e961a6 100644
--- a/src/alchemy.c
+++ b/src/alchemy.c
@@ -129,72 +129,6 @@ void herbsearch(unit * u, int max_take)
     }
 }
 
-static int begin_potion(unit * u, const item_type * itype, struct order *ord)
-{
-    static int config;
-    static bool rule_multipotion;
-
-    assert(itype);
-    if (config_changed(&config)) {
-        /* should we allow multiple different potions to be used the same turn? */
-        rule_multipotion = config_get_int("rules.magic.multipotion", 0) != 0;
-    }
-
-    if (!rule_multipotion) {
-        const item_type *use = ugetpotionuse(u);
-        if (use != NULL && use != itype) {
-            ADDMSG(&u->faction->msgs,
-                msg_message("errusingpotion", "unit using command",
-                u, use->rtype, ord));
-            return ECUSTOM;
-        }
-    }
-    return 0;
-}
-
-static void end_potion(unit * u, const item_type * itype, int amount)
-{
-    use_pooled(u, itype->rtype, GET_SLACK | GET_RESERVE | GET_POOLED_SLACK,
-        amount);
-    usetpotionuse(u, itype);
-
-    ADDMSG(&u->faction->msgs, msg_message("usepotion",
-        "unit potion", u, itype->rtype));
-}
-
-static int potion_water_of_life(unit * u, region *r, int amount) {
-    static int config;
-    static int tree_type, tree_count;
-    int wood = 0;
-
-    if (config_changed(&config)) {
-        tree_type = config_get_int("rules.magic.wol_type", 1);
-        tree_count = config_get_int("rules.magic.wol_effect", 10);
-    }
-    /* mallorn is required to make mallorn forests, wood for regular ones */
-    if (fval(r, RF_MALLORN)) {
-        wood = use_pooled(u, rt_find("mallorn"),
-            GET_SLACK | GET_RESERVE | GET_POOLED_SLACK, tree_count * amount);
-    }
-    else {
-        wood = use_pooled(u, rt_find("log"),
-            GET_SLACK | GET_RESERVE | GET_POOLED_SLACK, tree_count * amount);
-    }
-    if (r->land == 0)
-        wood = 0;
-    if (wood < tree_count * amount) {
-        int x = wood / tree_count;
-        if (wood % tree_count)
-            ++x;
-        if (x < amount)
-            amount = x;
-    }
-    rsettrees(r, tree_type, rtrees(r, tree_type) + wood);
-    ADDMSG(&u->faction->msgs, msg_message("growtree_effect",
-        "mage amount", u, wood));
-    return amount;
-}
-
 void show_potions(faction *f, int sklevel)
 {
     const potion_type *ptype;
@@ -211,13 +145,6 @@ void show_potions(faction *f, int sklevel)
     }
 }
 
-static int potion_healing(unit * u, int amount) {
-    int maxhp = unit_max_hp(u) * u->number;
-    u->hp = u->hp + 400 * amount;
-    if (u->hp > maxhp) u->hp = maxhp;
-    return amount;
-}
-
 static int potion_luck(unit *u, region *r, attrib_type *atype, int amount) {
     attrib *a = (attrib *)a_find(r->attribs, atype);
     UNUSED_ARG(u);
@@ -228,140 +155,50 @@ static int potion_luck(unit *u, region *r, attrib_type *atype, int amount) {
     return amount;
 }
 
-static int potion_power(unit *u, int amount) {
-    int hp = 10 * amount;
-
-    if (hp > u->number) {
-        hp = u->number;
-        amount = (hp + 9) % 10;
-    }
-    u->hp += hp * unit_max_hp(u) * 4;
-    return amount;
-}
-
-static int do_potion(unit * u, region *r, const item_type * itype, int amount)
+int use_potion(unit * u, const item_type * itype, int amount, struct order *ord)
 {
-    if (itype == oldpotiontype[P_LIFE]) {
-        return potion_water_of_life(u, r, amount);
-    }
-    else if (itype == oldpotiontype[P_HEILWASSER]) {
-        return potion_healing(u, amount);
-    }
-    else if (itype == oldpotiontype[P_PEOPLE]) {
-        return potion_luck(u, r, &at_peasantluck, amount);
+    region *r = u->region;
+
+    if (itype == oldpotiontype[P_PEOPLE]) {
+        amount = potion_luck(u, r, &at_peasantluck, amount);
     }
     else if (itype == oldpotiontype[P_HORSE]) {
-        return potion_luck(u, r, &at_horseluck, amount);
-    }
-    else if (itype == oldpotiontype[P_MACHT]) {
-        return potion_power(u, amount);
+        amount = potion_luck(u, r, &at_horseluck, amount);
     }
     else {
         change_effect(u, itype, 10 * amount);
     }
+    if (amount > 0) {
+        ADDMSG(&u->faction->msgs, msg_message("use_item",
+            "unit amount item", u, amount, itype->rtype));
+    }
     return amount;
 }
 
-int use_potion(unit * u, const item_type * itype, int amount, struct order *ord)
-{
-    if (oldpotiontype[P_HEAL] && itype == oldpotiontype[P_HEAL]) {
-        return EUNUSABLE;
-    }
-    else {
-        int result = begin_potion(u, itype, ord);
-        if (result)
-            return result;
-        amount = do_potion(u, u->region, itype, amount);
-        end_potion(u, itype, amount);
-    }
-    return 0;
-}
-
-typedef struct potiondelay {
-    unit *u;
-    region *r;
-    const item_type *itype;
-    int amount;
-} potiondelay;
-
-static void init_potiondelay(attrib * a)
-{
-    a->data.v = malloc(sizeof(potiondelay));
-}
-
-static void free_potiondelay(attrib * a) {
-    free(a->data.v);
-}
-
-static int age_potiondelay(attrib * a, void *owner)
-{
-    potiondelay *pd = (potiondelay *)a->data.v;
-    UNUSED_ARG(owner);
-    pd->amount = do_potion(pd->u, pd->r, pd->itype, pd->amount);
-    return AT_AGE_REMOVE;
-}
-
-attrib_type at_potiondelay = {
-    "potiondelay",
-    init_potiondelay,
-    free_potiondelay,
-    age_potiondelay, 0, 0
-};
-
-static attrib *make_potiondelay(unit * u, const item_type * itype, int amount)
-{
-    attrib *a = a_new(&at_potiondelay);
-    potiondelay *pd = (potiondelay *)a->data.v;
-    pd->u = u;
-    pd->r = u->region;
-    pd->itype = itype;
-    pd->amount = amount;
-    return a;
-}
-
-int
-use_potion_delayed(unit * u, const item_type * itype, int amount,
-struct order *ord)
-{
-    int result = begin_potion(u, itype, ord);
-    if (result)
-        return result;
-
-    a_add(&u->attribs, make_potiondelay(u, itype, amount));
-
-    end_potion(u, itype, amount);
-    return 0;
-}
-
 /*****************/
 /*   at_effect   */
 /*****************/
 
-static void a_initeffect(attrib * a)
+static void a_initeffect(variant *var)
 {
-    a->data.v = calloc(sizeof(effect_data), 1);
-}
-
-static void a_finalizeeffect(attrib * a) /*-V524 */
-{
-    free(a->data.v);
+    var->v = calloc(sizeof(effect_data), 1);
 }
 
 static void
-a_writeeffect(const attrib * a, const void *owner, struct storage *store)
+a_writeeffect(const variant *var, const void *owner, struct storage *store)
 {
-    effect_data *edata = (effect_data *)a->data.v;
+    effect_data *edata = (effect_data *)var->v;
     UNUSED_ARG(owner);
     WRITE_TOK(store, resourcename(edata->type->rtype, 0));
     WRITE_INT(store, edata->value);
 }
 
-static int a_readeffect(attrib * a, void *owner, struct gamedata *data)
+static int a_readeffect(variant *var, void *owner, struct gamedata *data)
 {
     struct storage *store = data->store;
     int power;
     const resource_type *rtype;
-    effect_data *edata = (effect_data *)a->data.v;
+    effect_data *edata = (effect_data *)var->v;
     char zText[32];
 
     UNUSED_ARG(owner);
@@ -386,7 +223,7 @@ static int a_readeffect(attrib * a, void *owner, struct gamedata *data)
 attrib_type at_effect = {
     "effect",
     a_initeffect,
-    a_finalizeeffect,
+    a_free_voidptr,
     DEFAULT_AGE,
     a_writeeffect,
     a_readeffect,
diff --git a/src/alchemy.h b/src/alchemy.h
index d183cacd0..b1dde1c44 100644
--- a/src/alchemy.h
+++ b/src/alchemy.h
@@ -41,7 +41,7 @@ extern "C" {
         P_LIFE,
         /* Stufe 2 */
         P_DOMORE,
-        P_HEILWASSER,
+        P_OINTMENT,
         P_BAUERNBLUT,
         /* Stufe 3 */
         P_WISE,                     /* 6 */
@@ -52,7 +52,6 @@ extern "C" {
         /* Stufe 4 */
         P_PEOPLE,
         P_WAHRHEIT,
-        P_MACHT,
         P_HEAL,
         MAX_POTIONS
     };
@@ -64,8 +63,6 @@ extern "C" {
     void herbsearch(struct unit *u, int max);
     int use_potion(struct unit *u, const struct item_type *itype,
         int amount, struct order *);
-    int use_potion_delayed(struct unit *u, const struct item_type *itype,
-        int amount, struct order *);
 
     int get_effect(const struct unit *u, const struct item_type *effect);
     int change_effect(struct unit *u, const struct item_type *effect,
diff --git a/src/attributes/CMakeLists.txt b/src/attributes/CMakeLists.txt
index fb077cfe9..c76f2458a 100644
--- a/src/attributes/CMakeLists.txt
+++ b/src/attributes/CMakeLists.txt
@@ -20,6 +20,7 @@ racename.c
 raceprefix.c
 reduceproduction.c
 stealth.c
+seenspell.c
 targetregion.c
 )
 FOREACH(_FILE ${_FILES})
diff --git a/src/attributes/attributes.c b/src/attributes/attributes.c
index a5911200c..cfa99fcfd 100644
--- a/src/attributes/attributes.c
+++ b/src/attributes/attributes.c
@@ -22,6 +22,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 
 #include "laws.h"
 #include "move.h"
+#include "magic.h"
 
 /* attributes includes */
 #include "follow.h"
@@ -29,7 +30,6 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #include "iceberg.h"
 #include "key.h"
 #include "stealth.h"
-#include "magic.h"
 #include "moved.h"
 #include "movement.h"
 #include "dict.h"
@@ -38,6 +38,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #include "racename.h"
 #include "raceprefix.h"
 #include "reduceproduction.h"
+#include "seenspell.h"
 #include "targetregion.h"
 
 /* kernel includes */
@@ -67,42 +68,45 @@ typedef struct obs_data {
     int timer;
 } obs_data;
 
-static void obs_init(struct attrib *a)
+static void obs_init(variant *var)
 {
-    a->data.v = malloc(sizeof(obs_data));
-}
-
-static void obs_done(struct attrib *a)
-{
-    free(a->data.v);
+    var->v = malloc(sizeof(obs_data));
 }
 
 static int obs_age(struct attrib *a, void *owner)
 {
     obs_data *od = (obs_data *)a->data.v;
+
+    UNUSED_ARG(owner);
     update_interval(od->f, (region *)owner);
     return --od->timer;
 }
 
-static void obs_write(const struct attrib *a, const void *owner, struct storage *store)
+static void obs_write(const variant *var, const void *owner,
+    struct storage *store)
 {
-    obs_data *od = (obs_data *)a->data.v;
+    obs_data *od = (obs_data *)var->v;
+
+    UNUSED_ARG(owner);
     write_faction_reference(od->f, store);
     WRITE_INT(store, od->skill);
     WRITE_INT(store, od->timer);
 }
 
-static int obs_read(struct attrib *a, void *owner, struct gamedata *data)
+static int obs_read(variant *var, void *owner, struct gamedata *data)
 {
-    obs_data *od = (obs_data *)a->data.v;
+    obs_data *od = (obs_data *)var->v;
 
+    UNUSED_ARG(owner);
     read_faction_reference(data, &od->f, NULL);
     READ_INT(data->store, &od->skill);
     READ_INT(data->store, &od->timer);
     return AT_READ_OK;
 }
 
-attrib_type at_observer = { "observer", obs_init, obs_done, obs_age, obs_write, obs_read };
+attrib_type at_observer = {
+    "observer", obs_init, a_free_voidptr, obs_age, obs_write, obs_read
+};
 
 static attrib *make_observer(faction *f, int perception)
 {
@@ -153,10 +157,11 @@ attrib_type at_unitdissolve = {
     "unitdissolve", NULL, NULL, NULL, a_writechars, a_readchars
 };
 
-static int read_ext(attrib * a, void *owner, gamedata *data)
+static int read_ext(variant *var, void *owner, gamedata *data)
 {
     int len;
 
+    UNUSED_ARG(var);
     READ_INT(data->store, &len);
     data->store->api->r_bin(data->store->handle, NULL, (size_t)len);
     return AT_READ_OK;
@@ -174,8 +179,8 @@ void register_attributes(void)
     at_register(&at_mage);
     at_register(&at_countdown);
     at_register(&at_curse);
-
     at_register(&at_seenspell);
+    at_register(&at_seenspells);
 
     /* neue REGION-Attribute */
     at_register(&at_moveblock);
diff --git a/src/attributes/dict.c b/src/attributes/dict.c
index 83a53dbeb..d3c5ac329 100644
--- a/src/attributes/dict.c
+++ b/src/attributes/dict.c
@@ -62,11 +62,11 @@ typedef struct dict_data {
     } data;
 } dict_data;
 
-static int dict_read(attrib * a, void *owner, gamedata *data)
+static int dict_read(variant * var, void *owner, gamedata *data)
 {
     storage *store = data->store;
     char name[NAMESIZE];
-    dict_data *dd = (dict_data *)a->data.v;
+    dict_data *dd = (dict_data *)var->v;
     int n;
 
     READ_STR(store, name, sizeof(name));
@@ -88,19 +88,19 @@ static int dict_read(attrib * a, void *owner, gamedata *data)
     return AT_READ_DEPR;
 }
 
-static void dict_init(attrib * a)
+static void dict_init(variant *var)
 {
     dict_data *dd;
-    a->data.v = malloc(sizeof(dict_data));
-    dd = (dict_data *)a->data.v;
+    var->v = malloc(sizeof(dict_data));
+    dd = (dict_data *)var->v;
     dd->type = TNONE;
 }
 
-static void dict_done(attrib * a)
+static void dict_done(variant *var)
 {
-    dict_data *dd = (dict_data *)a->data.v;
+    dict_data *dd = (dict_data *)var->v;
     free(dd->name);
-    free(a->data.v);
+    free(var->v);
 }
 
 static void upgrade_keyval(const dict_data *dd, int keyval[], int v) {
diff --git a/src/attributes/follow.c b/src/attributes/follow.c
index e0741646b..8c5e14526 100644
--- a/src/attributes/follow.c
+++ b/src/attributes/follow.c
@@ -28,7 +28,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 
 #include <storage.h>
 
-static int read_follow(attrib * a, void *owner, gamedata *data)
+static int read_follow(variant * var, void *owner, gamedata *data)
 {
     READ_INT(data->store, NULL);   /* skip it */
     return AT_READ_FAIL;
diff --git a/src/attributes/hate.c b/src/attributes/hate.c
index e6751bdfb..c260de335 100644
--- a/src/attributes/hate.c
+++ b/src/attributes/hate.c
@@ -39,14 +39,14 @@ static int verify_hate(attrib * a, void *owner)
 }
 
 static void
-write_hate(const attrib * a, const void *owner, struct storage *store)
+write_hate(const variant *var, const void *owner, struct storage *store)
 {
-    write_unit_reference((unit *)a->data.v, store);
+    write_unit_reference((unit *)var->v, store);
 }
 
-static int read_hate(attrib * a, void *owner, gamedata *data)
+static int read_hate(variant *var, void *owner, gamedata *data)
 {
-    if (read_unit_reference(data, (unit **)&a->data.v, NULL) <= 0) {
+    if (read_unit_reference(data, (unit **)&var->v, NULL) <= 0) {
         return AT_READ_FAIL;
     }
     return AT_READ_OK;
diff --git a/src/attributes/key.c b/src/attributes/key.c
index 61bbb4599..75958a6fb 100644
--- a/src/attributes/key.c
+++ b/src/attributes/key.c
@@ -29,8 +29,8 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #include <string.h>
 #include <assert.h>
 
-static void a_writekeys(const attrib *a, const void *o, storage *store) {
-    int i, *keys = (int *)a->data.v;
+static void a_writekeys(const variant *var, const void *o, storage *store) {
+    int i, *keys = (int *)var->v;
     int n = 0;
     if (keys) {
         assert(keys[0] < 4096 && keys[0]>0);
@@ -76,7 +76,7 @@ static int keys_size(int n) {
     return 4096;
 }
 
-static int a_readkeys(attrib * a, void *owner, gamedata *data) {
+static int a_readkeys(variant *var, void *owner, gamedata *data) {
     int i, n, *keys;
 
     READ_INT(data->store, &n);
@@ -135,26 +135,22 @@ static int a_readkeys(attrib * a, void *owner, gamedata *data) {
             }
         }
     }
-    a->data.v = keys;
+    var->v = keys;
     return AT_READ_OK;
 }
 
-static int a_readkey(attrib *a, void *owner, struct gamedata *data) {
-    int res = a_readint(a, owner, data);
+static int a_readkey(variant *var, void *owner, struct gamedata *data) {
+    int res = a_readint(var, owner, data);
     if (data->version >= KEYVAL_VERSION) {
         return AT_READ_FAIL;
     }
     return (res != AT_READ_FAIL) ? AT_READ_DEPR : res;
 }
 
-static void a_freekeys(attrib *a) {
-    free(a->data.v);
-}
-
 attrib_type at_keys = {
     "keys",
     NULL,
-    a_freekeys,
+    a_free_voidptr,
     NULL,
     a_writekeys,
     a_readkeys,
diff --git a/src/attributes/moved.c b/src/attributes/moved.c
index e34b9c5e8..abff4ac73 100644
--- a/src/attributes/moved.c
+++ b/src/attributes/moved.c
@@ -34,15 +34,15 @@ static int age_moved(attrib * a, void *owner)
 }
 
 static void
-write_moved(const attrib * a, const void *owner, struct storage *store)
+write_moved(const variant *var, const void *owner, struct storage *store)
 {
-    WRITE_INT(store, a->data.i);
+    WRITE_INT(store, var->i);
 }
 
-static int read_moved(attrib * a, void *owner, gamedata *data)
+static int read_moved(variant *var, void *owner, gamedata *data)
 {
-    READ_INT(data->store, &a->data.i);
-    if (a->data.i != 0)
+    READ_INT(data->store, &var->i);
+    if (var->i != 0)
         return AT_READ_OK;
     else
         return AT_READ_FAIL;
diff --git a/src/attributes/movement.c b/src/attributes/movement.c
index 1b5ba3f94..7b49291c2 100644
--- a/src/attributes/movement.c
+++ b/src/attributes/movement.c
@@ -29,23 +29,17 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #include <limits.h>
 #include <assert.h>
 
-static void
-write_movement(const attrib * a, const void *owner, struct storage *store)
+static int read_movement(variant *var, void *owner, gamedata *data)
 {
-    WRITE_INT(store, a->data.i);
-}
-
-static int read_movement(attrib * a, void *owner, gamedata *data)
-{
-    READ_INT(data->store, &a->data.i);
-    if (a->data.i != 0)
+    READ_INT(data->store, &var->i);
+    if (var->i != 0)
         return AT_READ_OK;
     else
         return AT_READ_FAIL;
 }
 
 attrib_type at_movement = {
-    "movement", NULL, NULL, NULL, write_movement, read_movement
+    "movement", NULL, NULL, NULL, a_writeint, read_movement
 };
 
 bool get_movement(attrib * const *alist, int type)
diff --git a/src/attributes/otherfaction.c b/src/attributes/otherfaction.c
index c9e56fe27..343460057 100644
--- a/src/attributes/otherfaction.c
+++ b/src/attributes/otherfaction.c
@@ -33,20 +33,20 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  * simple attributes that do not yet have their own file
  */
 
-void write_of(const struct attrib *a, const void *owner, struct storage *store)
+void write_of(const variant *var, const void *owner, struct storage *store)
 {
-    const faction *f = (faction *)a->data.v;
+    const faction *f = (faction *)var->v;
     WRITE_INT(store, f->no);
 }
 
-int read_of(struct attrib *a, void *owner, gamedata *data)
+int read_of(variant *var, void *owner, gamedata *data)
 {                               /* return 1 on success, 0 if attrib needs removal */
     int of;
 
     READ_INT(data->store, &of);
     if (rule_stealth_other()) {
-        a->data.v = findfaction(of);
-        if (a->data.v) {
+        var->v = findfaction(of);
+        if (var->v) {
             return AT_READ_OK;
         }
     }
diff --git a/src/attributes/seenspell.c b/src/attributes/seenspell.c
new file mode 100644
index 000000000..170cc33b4
--- /dev/null
+++ b/src/attributes/seenspell.c
@@ -0,0 +1,175 @@
+/*
+Copyright (c) 1998-2018,
+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.
+**/
+
+#ifdef _MSC_VER
+#include <platform.h>
+#endif
+#include <kernel/faction.h>
+#include <kernel/spell.h>
+#include <kernel/spellbook.h>
+#include <util/attrib.h>
+#include <util/gamedata.h>
+#include <util/log.h>
+#include <util/macros.h>
+
+#include "seenspell.h"
+
+#include <selist.h>
+#include <storage.h>
+
+#include <stdlib.h>
+#include <string.h>
+
+/* ------------------------------------------------------------- */
+/* Ausgabe der Spruchbeschreibungen
+ * Anzeige des Spruchs nur, wenn die Stufe des besten Magiers vorher
+ * kleiner war (u->faction->seenspells). Ansonsten muss nur geprüft
+ * werden, ob dieser Magier den Spruch schon kennt, und andernfalls der
+ * Spruch zu seiner List-of-known-spells hinzugefügt werden.
+ */
+
+static int read_seenspells(variant *var, void *owner, struct gamedata *data)
+{
+    selist *ql;
+    storage *store = data->store;
+    spell *sp = 0;
+    char token[32];
+
+    UNUSED_ARG(owner);
+    READ_TOK(store, token, sizeof(token));
+    while (token[0]) {
+        sp = find_spell(token);
+        if (!sp) {
+            log_info("read_seenspells: could not find spell '%s'\n", token);
+            return AT_READ_FAIL;
+        }
+        selist_push(&ql, sp);
+        READ_TOK(store, token, sizeof(token));
+    }
+    var->v = ql;
+    return AT_READ_OK;
+}
+
+static bool cb_write_spell(void *data, void *more) {
+    const spell *sp = (const spell *)data;
+    storage *store = (storage *)more;
+    WRITE_TOK(store, sp->sname);
+    return true;
+
+}
+static void
+write_seenspells(const variant *var, const void *owner, struct storage *store)
+{
+    UNUSED_ARG(owner);
+    selist_foreach_ex((selist *)var->v, cb_write_spell, store);
+    WRITE_TOK(store, "");
+}
+
+static int read_seenspell(variant *var, void *owner, struct gamedata *data)
+{
+    storage *store = data->store;
+    spell *sp = 0;
+    char token[32];
+
+    UNUSED_ARG(owner);
+    READ_TOK(store, token, sizeof(token));
+    if (data->version < UNIQUE_SPELLS_VERSION) {
+        READ_INT(store, 0); /* ignore mtype */
+    }
+    sp = find_spell(token);
+    if (!sp) {
+        log_info("read_seenspell: could not find spell '%s'\n", token);
+        return AT_READ_FAIL;
+    }
+    var->v = sp;
+    return AT_READ_DEPR;
+}
+
+static int cmp_spell(const void *a, const void *b) {
+    const spell *spa = (const spell *)a;
+    const spell *spb = (const spell *)b;
+    return strcmp(spa->sname, spb->sname);
+}
+
+static bool set_seen(attrib **alist, struct spell *sp) {
+    attrib *a = a_find(*alist, &at_seenspells);
+    selist *sl;
+    if (!a) {
+        a = a_add(alist, a_new(&at_seenspells));
+    }
+    sl = (selist *)a->data.v;
+    return selist_set_insert(&sl, sp, cmp_spell);
+}
+
+static void upgrade_seenspell(attrib **alist, attrib *abegin) {
+    attrib *a, *ak;
+
+    ak = a_find(*alist, &at_seenspells);
+    if (ak) alist = &ak;
+    for (a = abegin; a && a->type == abegin->type; a = a->next) {
+        set_seen(alist, (struct spell *)a->data.v);
+    }
+}
+
+static void free_seenspells(variant *var) {
+    selist *sl = (selist *)var->v;
+    selist_free(sl);
+}
+
+attrib_type at_seenspells = {
+    "seenspells", NULL, free_seenspells, NULL, write_seenspells, read_seenspells
+};
+
+attrib_type at_seenspell = {
+    "seenspell", NULL, NULL, NULL, NULL, read_seenspell, upgrade_seenspell
+};
+
+static bool already_seen(const faction * f, const spell * sp)
+{
+    attrib *a;
+
+    a = a_find(f->attribs, &at_seenspells);
+    if (a) {
+        selist *sl = (selist *)a->data.v;
+        return selist_set_find(&sl, NULL, sp, cmp_spell);
+    }
+    return false;
+}
+
+attrib_type at_reportspell = {
+    "reportspell", NULL
+};
+
+void show_spell(faction *f, const spellbook_entry *sbe)
+{
+    if (!already_seen(f, sbe->sp)) {
+        /* mark the spell as seen by this faction: */
+        if (set_seen(&f->attribs, sbe->sp)) {
+            /* add the spell to the report: */
+            attrib * a = a_new(&at_reportspell);
+            a->data.v = (void *)sbe;
+            a_add(&f->attribs, a);
+        }
+    }
+}
+
+void reset_seen_spells(faction *f, const struct spell *sp)
+{
+    a_removeall(&f->attribs, &at_seenspells);
+}
diff --git a/src/attributes/seenspell.h b/src/attributes/seenspell.h
new file mode 100644
index 000000000..cdfb36e48
--- /dev/null
+++ b/src/attributes/seenspell.h
@@ -0,0 +1,16 @@
+#ifndef H_SEENSPELL
+#define H_SEENSPELL
+
+struct attrib_type;
+struct spellbook_entry;
+struct faction;
+struct spell;
+
+void show_spell(struct faction * f, const struct spellbook_entry *sbe);
+void reset_seen_spells(struct faction * f, const struct spell *sp);
+
+extern struct attrib_type at_reportspell;
+extern struct attrib_type at_seenspells;
+extern struct attrib_type at_seenspell; /* upgraded */
+
+#endif
diff --git a/src/attributes/targetregion.c b/src/attributes/targetregion.c
index 29e76f557..7ef1fe84a 100644
--- a/src/attributes/targetregion.c
+++ b/src/attributes/targetregion.c
@@ -29,14 +29,14 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #include <storage.h>
 
 static void
-write_targetregion(const attrib * a, const void *owner, struct storage *store)
+write_targetregion(const variant *var, const void *owner, struct storage *store)
 {
-    write_region_reference((region *)a->data.v, store);
+    write_region_reference((region *)var->v, store);
 }
 
-static int read_targetregion(attrib * a, void *owner, gamedata *data)
+static int read_targetregion(variant *var, void *owner, gamedata *data)
 {
-    if (read_region_reference(data, (region **)&a->data.v, NULL) <= 0) {
+    if (read_region_reference(data, (region **)&var->v, NULL) <= 0) {
         return AT_READ_FAIL;
     }
     return AT_READ_OK;
diff --git a/src/battle.c b/src/battle.c
index b7482e48a..e82ba71a5 100644
--- a/src/battle.c
+++ b/src/battle.c
@@ -1130,6 +1130,21 @@ int calculate_armor(troop dt, const weapon_type *dwtype, const weapon_type *awty
     return ar;
 }
 
+static bool resurrect_troop(troop dt)
+{
+    fighter *df = dt.fighter;
+    unit *du = df->unit;
+    if (oldpotiontype[P_HEAL] && !fval(&df->person[dt.index], FL_HEALING_USED)) {
+        if (i_get(du->items, oldpotiontype[P_HEAL]) > 0) {
+            fset(&df->person[dt.index], FL_HEALING_USED);
+            i_change(&du->items, oldpotiontype[P_HEAL], -1);
+            df->person[dt.index].hp = u_race(du)->hitpoints * 5; /* give the person a buffer */
+            return true;
+        }
+    }
+    return false;
+}
+
 bool
 terminate(troop dt, troop at, int type, const char *damage, bool missile)
 {
@@ -1300,16 +1315,12 @@ terminate(troop dt, troop at, int type, const char *damage, bool missile)
         return false;
     }
 
-    if (oldpotiontype[P_HEAL] && !fval(&df->person[dt.index], FL_HEALING_USED)) {
-        if (i_get(du->items, oldpotiontype[P_HEAL]) > 0) {
-            message *m = msg_message("potionsave", "unit", du);
-            battle_message_faction(b, du->faction, m);
-            msg_release(m);
-            i_change(&du->items, oldpotiontype[P_HEAL], -1);
-            fset(&df->person[dt.index], FL_HEALING_USED);
-            df->person[dt.index].hp = u_race(du)->hitpoints * 5; /* give the person a buffer */
-            return false;
-        }
+    /* healing potions can avert a killing blow */
+    if (resurrect_troop(dt)) {
+        message *m = msg_message("potionsave", "unit", du);
+        battle_message_faction(b, du->faction, m);
+        msg_release(m);
+        return false;
     }
     ++at.fighter->kills;
 
diff --git a/src/battle.h b/src/battle.h
index 6494a6e27..fd31a0284 100644
--- a/src/battle.h
+++ b/src/battle.h
@@ -28,6 +28,7 @@ extern "C" {
 
     struct message;
     struct selist;
+    union variant;
 
     /** more defines **/
 #define FS_ENEMY 1
diff --git a/src/bind_region.c b/src/bind_region.c
index 8514bf639..a87b6f856 100644
--- a/src/bind_region.c
+++ b/src/bind_region.c
@@ -9,6 +9,7 @@
 
 #include "chaos.h"
 
+#include <kernel/calendar.h>
 #include <kernel/config.h>
 #include <kernel/curse.h>
 #include <kernel/region.h>
diff --git a/src/bindings.c b/src/bindings.c
index 811c1853e..35657b5be 100755
--- a/src/bindings.c
+++ b/src/bindings.c
@@ -3,6 +3,28 @@
 #endif
 
 #include "bindings.h"
+
+#include "kernel/calendar.h"
+#include "kernel/config.h"
+#include "kernel/alliance.h"
+#include "kernel/building.h"
+#include "kernel/curse.h"
+#include "kernel/equipment.h"
+#include "kernel/unit.h"
+#include "kernel/terrain.h"
+#include "kernel/messages.h"
+#include "kernel/region.h"
+#include "kernel/building.h"
+#include "kernel/plane.h"
+#include "kernel/race.h"
+#include "kernel/item.h"
+#include "kernel/order.h"
+#include "kernel/ship.h"
+#include "kernel/faction.h"
+#include "kernel/save.h"
+#include "kernel/spell.h"
+#include "kernel/spellbook.h"
+
 #include "bind_unit.h"
 #include "bind_storage.h"
 #include "bind_building.h"
@@ -13,33 +35,11 @@
 #include "bind_ship.h"
 #include "bind_gmtool.h"
 #include "bind_region.h"
+
 #include "helpers.h"
 #include "console.h"
 #include "reports.h"
 #include "study.h"
-#include "calendar.h"
-
-#include <kernel/config.h>
-
-#include <kernel/alliance.h>
-#include <kernel/building.h>
-#include <kernel/curse.h>
-#include <kernel/equipment.h>
-#include <kernel/unit.h>
-#include <kernel/terrain.h>
-#include <kernel/messages.h>
-#include <kernel/region.h>
-#include <kernel/building.h>
-#include <kernel/plane.h>
-#include <kernel/race.h>
-#include <kernel/item.h>
-#include <kernel/order.h>
-#include <kernel/ship.h>
-#include <kernel/faction.h>
-#include <kernel/save.h>
-#include <kernel/spell.h>
-#include <kernel/spellbook.h>
-
 #include "economy.h"
 #include "summary.h"
 #include "teleport.h"
diff --git a/src/creport.c b/src/creport.c
index fa17c426d..773628a82 100644
--- a/src/creport.c
+++ b/src/creport.c
@@ -30,6 +30,7 @@ without prior permission by the authors of Eressea.
 #include <attributes/otherfaction.h>
 #include <attributes/racename.h>
 #include <attributes/raceprefix.h>
+#include <attributes/seenspell.h>
 #include <attributes/stealth.h>
 
 /* gamecode includes */
@@ -41,25 +42,26 @@ without prior permission by the authors of Eressea.
 #include "teleport.h"
 
 /* kernel includes */
-#include <kernel/alliance.h>
-#include <kernel/ally.h>
-#include <kernel/connection.h>
-#include <kernel/building.h>
-#include <kernel/curse.h>
-#include <kernel/faction.h>
-#include <kernel/group.h>
-#include <kernel/item.h>
-#include <kernel/messages.h>
-#include <kernel/order.h>
-#include <kernel/plane.h>
-#include <kernel/race.h>
-#include <kernel/region.h>
-#include <kernel/resources.h>
-#include <kernel/ship.h>
-#include <kernel/spell.h>
-#include <kernel/spellbook.h>
-#include <kernel/terrain.h>
-#include <kernel/unit.h>
+#include "kernel/alliance.h"
+#include "kernel/ally.h"
+#include "kernel/calendar.h"
+#include "kernel/connection.h"
+#include "kernel/building.h"
+#include "kernel/curse.h"
+#include "kernel/faction.h"
+#include "kernel/group.h"
+#include "kernel/item.h"
+#include "kernel/messages.h"
+#include "kernel/order.h"
+#include "kernel/plane.h"
+#include "kernel/race.h"
+#include "kernel/region.h"
+#include "kernel/resources.h"
+#include "kernel/ship.h"
+#include "kernel/spell.h"
+#include "kernel/spellbook.h"
+#include "kernel/terrain.h"
+#include "kernel/unit.h"
 
 /* util includes */
 #include <util/attrib.h>
diff --git a/src/creport.h b/src/creport.h
index ed8f3bfbd..f4e0cd4bd 100644
--- a/src/creport.h
+++ b/src/creport.h
@@ -13,6 +13,7 @@
 #define H_GC_CREPORT
 
 #include <kernel/types.h>
+#include <stdbool.h>
 
 #ifdef __cplusplus
 extern "C" {
diff --git a/src/economy.c b/src/economy.c
index 82890888e..9774ab3eb 100644
--- a/src/economy.c
+++ b/src/economy.c
@@ -36,7 +36,6 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #include "monsters.h"
 #include "morale.h"
 #include "reports.h"
-#include "calendar.h"
 
 #include <attributes/reduceproduction.h>
 #include <attributes/racename.h>
@@ -45,23 +44,24 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #include <spells/unitcurse.h>
 
 /* kernel includes */
-#include <kernel/ally.h>
-#include <kernel/building.h>
-#include <kernel/curse.h>
-#include <kernel/equipment.h>
-#include <kernel/faction.h>
-#include <kernel/item.h>
-#include <kernel/messages.h>
-#include <kernel/order.h>
-#include <kernel/plane.h>
-#include <kernel/pool.h>
-#include <kernel/race.h>
-#include <kernel/region.h>
-#include <kernel/resources.h>
-#include <kernel/ship.h>
-#include <kernel/terrain.h>
-#include <kernel/terrainid.h>
-#include <kernel/unit.h>
+#include "kernel/ally.h"
+#include "kernel/building.h"
+#include "kernel/calendar.h"
+#include "kernel/curse.h"
+#include "kernel/equipment.h"
+#include "kernel/faction.h"
+#include "kernel/item.h"
+#include "kernel/messages.h"
+#include "kernel/order.h"
+#include "kernel/plane.h"
+#include "kernel/pool.h"
+#include "kernel/race.h"
+#include "kernel/region.h"
+#include "kernel/resources.h"
+#include "kernel/ship.h"
+#include "kernel/terrain.h"
+#include "kernel/terrainid.h"
+#include "kernel/unit.h"
 
 /* util includes */
 #include <util/attrib.h>
@@ -333,7 +333,7 @@ static int do_recruiting(recruitment * recruits, int available)
         for (req = rec->requests; req; req = req->next) {
             unit *u = req->unit;
             const race *rc = u_race(u); /* race is set in recruit() */
-            int number, dec;
+            int number;
             double multi = 2.0 * rc->recruit_multi;
 
             number = (int)(get / multi);
@@ -359,7 +359,7 @@ static int do_recruiting(recruitment * recruits, int available)
             }
             add_recruits(u, number, req->qty);
             if (number > 0) {
-                dec = (int)(number * multi);
+                int dec = (int)(number * multi);
                 if ((rc->ec_flags & ECF_REC_ETHEREAL) == 0) {
                     recruited += dec;
                 }
@@ -1006,7 +1006,7 @@ static void allocate_resource(unit * u, const resource_type * rtype, int want)
         }
     }
 
-    assert(sk != NOSKILL || "limited resource needs a required skill for making it");
+    assert(sk != NOSKILL || !"limited resource needs a required skill for making it");
     skill = effskill(u, sk, 0);
     if (skill == 0) {
         add_message(&u->faction->msgs,
@@ -1075,13 +1075,12 @@ leveled_allocation(const resource_type * rtype, region * r, allocation * alist)
 {
     const item_type *itype = resource2item(rtype);
     rawmaterial *rm = rm_get(r, rtype);
-    int need;
     bool first = true;
 
     if (rm != NULL) {
+        int need;
         do {
-            int avail = rm->amount;
-            int nreq = 0;
+            int avail = rm->amount, nreq = 0;
             allocation *al;
 
             if (avail <= 0) {
@@ -1093,7 +1092,7 @@ leveled_allocation(const resource_type * rtype, region * r, allocation * alist)
 
             assert(avail > 0);
 
-            for (al = alist; al; al = al->next)
+            for (al = alist; al; al = al->next) {
                 if (!fval(al, AFL_DONE)) {
                     int req = required(al->want - al->get, al->save);
                     assert(al->get <= al->want && al->get >= 0);
@@ -1112,6 +1111,7 @@ leveled_allocation(const resource_type * rtype, region * r, allocation * alist)
                             fset(al, AFL_LOWSKILL);
                     }
                 }
+            }
             need = nreq;
 
             if (avail > nreq) avail = nreq;
@@ -1190,15 +1190,13 @@ attrib_allocation(const resource_type * rtype, region * r, allocation * alist)
     assert(avail == 0 || nreq == 0);
 }
 
-typedef void(*allocate_function) (const resource_type *, struct region *,
-    struct allocation *);
-
-static allocate_function get_allocator(const struct resource_type *rtype)
-{
+static void allocate(const resource_type *rtype, region *r, allocation *data) {
     if (rtype->raw) {
-        return leveled_allocation;
+        leveled_allocation(rtype, r, data);
+    }
+    else {
+        attrib_allocation(rtype, r, data);
     }
-    return attrib_allocation;
 }
 
 void split_allocations(region * r)
@@ -1207,11 +1205,10 @@ void split_allocations(region * r)
     while (*p_alist) {
         allocation_list *alist = *p_alist;
         const resource_type *rtype = alist->type;
-        allocate_function alloc = get_allocator(rtype);
         const item_type *itype = resource2item(rtype);
         allocation **p_al = &alist->data;
 
-        alloc(rtype, r, alist->data);
+        allocate(rtype, r, alist->data);
 
         while (*p_al) {
             allocation *al = *p_al;
@@ -1432,10 +1429,10 @@ int make_cmd(unit * u, struct order *ord)
 
 /* ------------------------------------------------------------- */
 
-static void free_luxuries(struct attrib *a)
+static void free_luxuries(variant *var)
 {
-    item *itm = (item *)a->data.v;
-    a->data.v = NULL;
+    item *itm = (item *)var->v;
+    var->v = NULL;
     i_freeall(&itm);
 }
 
diff --git a/src/economy.h b/src/economy.h
index ec12ae0ca..6d58a1f9f 100644
--- a/src/economy.h
+++ b/src/economy.h
@@ -45,6 +45,7 @@ extern "C" {
     struct faction;
     struct order;
     struct message;
+    struct item_type;
     
     typedef struct econ_request {
         struct econ_request *next;
diff --git a/src/eressea.c b/src/eressea.c
index 95d190d70..03f194238 100644
--- a/src/eressea.c
+++ b/src/eressea.c
@@ -1,29 +1,28 @@
 #include <platform.h>
-#include "settings.h"
 #include "eressea.h"
 
-#include <kernel/config.h>
-#include <util/log.h>
+#include "kernel/calendar.h"
+#include "kernel/config.h"
+#include "kernel/curse.h"
+#include "kernel/building.h"
+#include "kernel/equipment.h"
+#include "kernel/item.h"
+#include "kernel/database.h"
 
-#include <modules/museum.h>
-#include <triggers/triggers.h>
-#include <util/language.h>
-#include <util/functions.h>
-#include <kernel/building.h>
-#include <kernel/curse.h>
-#include <kernel/equipment.h>
-#include <kernel/item.h>
-#include <kernel/database.h>
-#include <modules/gmcmd.h>
-#include <modules/xmas.h>
-#include <items/xerewards.h>
-#include <items/weapons.h>
+#include "util/functions.h"
+#include "util/language.h"
+#include "util/log.h"
+#include "util/message.h"
 
-#include <attributes/attributes.h>
-#include <util/message.h>
-#include <races/races.h>
+#include "modules/gmcmd.h"
+#include "modules/xmas.h"
+#include "modules/museum.h"
+#include "triggers/triggers.h"
+#include "items/xerewards.h"
+#include "items/weapons.h"
+#include "attributes/attributes.h"
+#include "races/races.h"
 
-#include "calendar.h"
 #include "chaos.h"
 #include "items.h"
 #include "creport.h"
diff --git a/src/give.c b/src/give.c
index 5d5673bd2..21e099394 100644
--- a/src/give.c
+++ b/src/give.c
@@ -158,18 +158,15 @@ static bool limited_give(const item_type * type)
 int give_quota(const unit * src, const unit * dst, const item_type * type,
     int n)
 {
-    double divisor;
-
     if (!limited_give(type)) {
         return n;
     }
     if (dst && src && src->faction != dst->faction) {
-        divisor = config_get_flt("rules.items.give_divisor", 1);
+        int divisor = config_get_int("rules.items.give_divisor", 1);
         assert(divisor <= 0 || divisor >= 1);
         if (divisor >= 1) {
             /* predictable > correct: */
-            int x = (int)(n / divisor);
-            return x;
+            return n / divisor;
         }
     }
     return n;
@@ -306,7 +303,6 @@ static bool rule_transfermen(void)
 message * give_men(int n, unit * u, unit * u2, struct order *ord)
 {
     ship *sh;
-    int k = 0;
     int error = 0;
     message * msg;
     int maxt = max_transfers();
@@ -391,7 +387,7 @@ message * give_men(int n, unit * u, unit * u2, struct order *ord)
     }
 
     if (has_skill(u, SK_ALCHEMY) || has_skill(u2, SK_ALCHEMY)) {
-        k = count_skill(u2->faction, SK_ALCHEMY);
+        int k = count_skill(u2->faction, SK_ALCHEMY);
 
         /* Falls die Zieleinheit keine Alchemisten sind, werden sie nun
          * welche. */
diff --git a/src/gmtool.c b/src/gmtool.c
index d74f1e46b..ffe189611 100644
--- a/src/gmtool.c
+++ b/src/gmtool.c
@@ -23,18 +23,19 @@
 #include <modules/museum.h>
 #include <modules/autoseed.h>
 
-#include <kernel/building.h>
-#include <kernel/faction.h>
-#include <kernel/item.h>
-#include <kernel/plane.h>
-#include <kernel/race.h>
-#include <kernel/region.h>
-#include <kernel/terrainid.h>
-#include <kernel/unit.h>
-#include <kernel/resources.h>
-#include <kernel/save.h>
-#include <kernel/ship.h>
-#include <kernel/terrain.h>
+#include "kernel/building.h"
+#include "kernel/calendar.h"
+#include "kernel/faction.h"
+#include "kernel/item.h"
+#include "kernel/plane.h"
+#include "kernel/race.h"
+#include "kernel/region.h"
+#include "kernel/terrainid.h"
+#include "kernel/unit.h"
+#include "kernel/resources.h"
+#include "kernel/save.h"
+#include "kernel/ship.h"
+#include "kernel/terrain.h"
 
 #include <attributes/attributes.h>
 #include <triggers/triggers.h>
@@ -53,7 +54,6 @@
 #include "console.h"
 #include "listbox.h"
 #include "wormhole.h"
-#include "calendar.h"
 #include "teleport.h"
 #include "xmlreader.h"
 
@@ -137,10 +137,10 @@ int umvwaddnstr(WINDOW *w, int y, int x, const char * str, int len) {
 
 static void init_curses(void)
 {
-    int fg, bg;
     initscr();
 
     if (has_colors() || force_color) {
+        int fg, bg;
         short bcol = COLOR_BLACK;
         short hcol = COLOR_MAGENTA;
         start_color();
@@ -316,11 +316,11 @@ static void paint_map(window * wnd, const state * st)
         int yp = (lines - vy - 1) * THEIGHT;
         for (vx = 0; vx != cols; ++vx) {
             map_region *mr = mr_get(&st->display, vx, vy);
-            int attr = 0;
-            int hl = 0;
             int xp = vx * TWIDTH + (vy & 1) * TWIDTH / 2;
             int nx, ny;
             if (mr) {
+                int attr = 0;
+                int hl = 0;
                 cnormalize(&mr->coord, &nx, &ny);
                 if (tagged_region(st->selected, nx, ny)) {
                     attr |= A_REVERSE;
@@ -336,9 +336,9 @@ static void paint_map(window * wnd, const state * st)
 map_region *cursor_region(const view * v, const coordinate * c)
 {
     coordinate relpos;
-    int cx, cy;
 
     if (c) {
+        int cx, cy;
         relpos.x = c->x - v->topleft.x;
         relpos.y = c->y - v->topleft.y;
         cy = relpos.y;
@@ -426,13 +426,14 @@ static void paint_info_region(window * wnd, const state * st)
 {
     WINDOW *win = wnd->handle;
     int size = getmaxx(win) - 2;
-    int line = 0, maxline = getmaxy(win) - 2;
+    int maxline = getmaxy(win) - 2;
     map_region *mr = cursor_region(&st->display, &st->cursor);
 
     UNUSED_ARG(st);
     werase(win);
     wxborder(win);
     if (mr && mr->r) {
+        int line = 0;
         const region *r = mr->r;
         if (r->land) {
             umvwaddnstr(win, line++, 1, (char *)r->land->name, size);
@@ -708,10 +709,10 @@ static void select_regions(state * st, int selectmode)
     doupdate();
     findmode = getch();
     if (findmode == 'n') {        /* none */
-        int i;
         sprintf(sbuffer, "%snone", status);
         statusline(st->wnd_status->handle, sbuffer);
         if (selectmode & MODE_SELECT) {
+            int i;
             for (i = 0; i != MAXTHASH; ++i) {
                 tag **tp = &st->selected->tags[i];
                 while (*tp) {
diff --git a/src/helpers.c b/src/helpers.c
index b5c4c05ba..d3ff9870f 100644
--- a/src/helpers.c
+++ b/src/helpers.c
@@ -1,4 +1,4 @@
-/* 
+/*
 +-------------------+
 |                   |  Enno Rehling <enno@eressea.de>
 | Eressea PBEM host |  Christian Schlittchen <corwin@amber.kn-bremen.de>
@@ -228,7 +228,7 @@ lua_changeresource(unit * u, const struct resource_type *rtype, int delta)
         if (lua_isfunction(L, -1)) {
             tolua_pushusertype(L, u, TOLUA_CAST "unit");
             lua_pushinteger(L, delta);
-            
+
             if (lua_pcall(L, 2, 1, 0) != 0) {
                 const char *error = lua_tostring(L, -1);
                 log_error("change(%s) calling '%s': %s.\n", unitname(u), fname, error);
@@ -249,19 +249,9 @@ lua_changeresource(unit * u, const struct resource_type *rtype, int delta)
 
 /** callback for an item-use function written in lua. */
 static int
-use_item_lua(unit *u, const item_type *itype, int amount, struct order *ord)
+lua_use_item(unit *u, const item_type *itype, const char * fname, int amount, struct order *ord)
 {
     lua_State *L = (lua_State *)global.vm_state;
-    int len, result = 0;
-    char fname[64];
-    int (*callout)(unit *, const item_type *, int, struct order *);
-
-    len = snprintf(fname, sizeof(fname), "use_%s", itype->rtype->_name);
-    if (len > 0 && (size_t)len < sizeof(fname)) {
-    callout = (int(*)(unit *, const item_type *, int, struct order *))get_function(fname);
-    if (callout) {
-        return callout(u, itype, amount, ord);
-    }
 
     lua_getglobal(L, fname);
     if (lua_isfunction(L, -1)) {
@@ -272,23 +262,52 @@ use_item_lua(unit *u, const item_type *itype, int amount, struct order *ord)
         if (lua_pcall(L, 4, 1, 0) != 0) {
             const char *error = lua_tostring(L, -1);
             log_error("use(%s) calling '%s': %s.\n", unitname(u), fname, error);
-            lua_pop(L, 1);
         }
         else {
-            result = (int)lua_tonumber(L, -1);
+            int result = (int)lua_tonumber(L, -1);
             lua_pop(L, 1);
+            return result;
         }
-        return result;
     }
     lua_pop(L, 1);
-    if (itype->flags & ITF_POTION) {
-        return use_potion(u, itype, amount, ord);
-    } else {
-        log_error("no such callout: %s", fname);
+    return 0;
+}
+
+static int
+use_item_callback(unit *u, const item_type *itype, int amount, struct order *ord)
+{
+    int len;
+    char fname[64];
+    int(*callout)(unit *, const item_type *, int, struct order *);
+
+    len = snprintf(fname, sizeof(fname), "use_%s", itype->rtype->_name);
+    if (len > 0 && (size_t)len < sizeof(fname)) {
+        int result;
+
+        /* check if we have a register_item_use function */
+        callout = (int(*)(unit *, const item_type *, int, struct order *))get_function(fname);
+        if (callout) {
+            return callout(u, itype, amount, ord);
+        }
+
+        /* check if we have a matching lua function */
+        result = lua_use_item(u, itype, fname, amount, ord);
+        if (result != 0) {
+            return result;
+        }
+
+        /* if the item is a potion, try use_potion, the generic function for 
+         * potions that add an effect: */
+        if (itype->flags & ITF_POTION) {
+            return use_potion(u, itype, amount, ord);
+        }
+        else {
+            log_error("no such callout: %s", fname);
+        }
+        log_error("use(%s) calling '%s': not a function.\n", unitname(u), fname);
     }
-    log_error("use(%s) calling '%s': not a function.\n", unitname(u), fname);
-    }
-    return result;
+
+    return 0;
 }
 
 /* compat code for old data files */
@@ -306,12 +325,12 @@ struct trigger_type tt_caldera = {
 };
 
 
-static int building_action_read(struct attrib *a, void *owner, gamedata *data)
+static int building_action_read(variant *var, void *owner, gamedata *data)
 {
     struct storage *store = data->store;
 
     UNUSED_ARG(owner);
-    UNUSED_ARG(a);
+    UNUSED_ARG(var);
 
     if (data->version < ATTRIBOWNER_VERSION) {
         READ_INT(data->store, NULL);
@@ -328,7 +347,7 @@ void register_tolua_helpers(void)
     at_deprecate("lcbuilding", building_action_read);
 
     callbacks.cast_spell = lua_callspell;
-    callbacks.use_item = use_item_lua;
+    callbacks.use_item = use_item_callback;
     callbacks.produce_resource = produce_resource_lua;
     callbacks.limit_resource = limit_resource_lua;
 
diff --git a/src/items.c b/src/items.c
index ba9f35388..e162d8fe2 100644
--- a/src/items.c
+++ b/src/items.c
@@ -16,6 +16,7 @@
 #include <spells/regioncurse.h>
 
 #include <kernel/curse.h>
+#include <kernel/config.h>
 #include <kernel/faction.h>
 #include <kernel/item.h>
 #include <kernel/messages.h>
@@ -302,43 +303,9 @@ struct order *ord)
     }
     use_pooled(u, itype->rtype, GET_SLACK | GET_RESERVE | GET_POOLED_SLACK,
         amount);
-    usetpotionuse(u, itype);
 
-    ADDMSG(&u->faction->msgs, msg_message("usepotion",
-        "unit potion", u, itype->rtype));
-    return 0;
-}
-
-static int heal(unit * user, int effect)
-{
-    int req = unit_max_hp(user) * user->number - user->hp;
-    if (req > 0) {
-        if (req > effect) req = effect;
-        effect -= req;
-        user->hp += req;
-    }
-    return effect;
-}
-
-static int
-use_healingpotion(struct unit *user, const struct item_type *itype, int amount,
-struct order *ord)
-{
-    int effect = amount * 400;
-    unit *u = user->region->units;
-    effect = heal(user, effect);
-    while (effect > 0 && u != NULL) {
-        if (u->faction == user->faction) {
-            effect = heal(u, effect);
-        }
-        u = u->next;
-    }
-    use_pooled(user, itype->rtype, GET_SLACK | GET_RESERVE | GET_POOLED_SLACK,
-        amount);
-    usetpotionuse(user, itype);
-
-    ADDMSG(&user->faction->msgs, msg_message("usepotion",
-        "unit potion", user, itype->rtype));
+    ADDMSG(&u->faction->msgs, msg_message("use_item",
+        "unit amount item", u, amount, itype->rtype));
     return 0;
 }
 
@@ -400,18 +367,120 @@ static int use_warmthpotion(unit *u, const item_type *itype,
         cmistake(u, ord, 163, MSG_EVENT);
         return ECUSTOM;
     }
-    use_pooled(u, itype->rtype, GET_SLACK | GET_RESERVE | GET_POOLED_SLACK,
-        amount);
-    usetpotionuse(u, itype);
+    use_pooled(u, itype->rtype, GET_DEFAULT, amount);
 
-    ADDMSG(&u->faction->msgs, msg_message("usepotion",
-        "unit potion", u, itype->rtype));
+    ADDMSG(&u->faction->msgs, msg_message("use_item",
+        "unit amount item", u, amount, itype->rtype));
     return 0;
 }
 
+static int potion_water_of_life(unit * u, region *r, int amount) {
+    static int config;
+    static int tree_type, tree_count;
+    int wood = 0;
+
+    if (config_changed(&config)) {
+        tree_type = config_get_int("rules.magic.wol_type", 1);
+        tree_count = config_get_int("rules.magic.wol_effect", 10);
+    }
+    /* mallorn is required to make mallorn forests, wood for regular ones */
+    if (fval(r, RF_MALLORN)) {
+        wood = use_pooled(u, rt_find("mallorn"), GET_DEFAULT, tree_count * amount);
+    }
+    else {
+        wood = use_pooled(u, rt_find("log"), GET_DEFAULT, tree_count * amount);
+    }
+    if (r->land == 0)
+        wood = 0;
+    if (wood < tree_count * amount) {
+        int x = wood / tree_count;
+        if (wood % tree_count)
+            ++x;
+        if (x < amount)
+            amount = x;
+    }
+    rsettrees(r, tree_type, rtrees(r, tree_type) + wood);
+    ADDMSG(&u->faction->msgs, msg_message("growtree_effect",
+        "mage amount", u, wood));
+    return amount;
+}
+
+static int use_water_of_life(unit *u, const item_type *itype,
+    int amount, struct order *ord)
+{
+    return potion_water_of_life(u, u->region, amount);
+}
+
+static int heal(unit * user, int effect)
+{
+    int req = unit_max_hp(user) * user->number - user->hp;
+    if (req > 0) {
+        if (req > effect) req = effect;
+        effect -= req;
+        user->hp += req;
+    }
+    return effect;
+}
+
+static int potion_healing(struct unit *user, int amount)
+{
+    int effect = amount * 400;
+    unit *u = user->region->units;
+    effect = heal(u, effect);
+    while (effect > 0 && u != NULL) {
+        if (u->faction == user->faction) {
+            effect = heal(u, effect);
+        }
+        u = u->next;
+    }
+    return amount;
+}
+
+static int use_healing_potion(unit *u, const item_type *itype,
+    int amount, struct order *ord)
+{
+    ADDMSG(&u->faction->msgs, msg_message("use_item",
+        "unit amount item", u, amount, itype->rtype));
+    return potion_healing(u, amount);
+}
+
+static int potion_ointment(unit * u, int amount) {
+    int effect = amount * 400;
+    effect = heal(u, effect);
+    return amount;
+}
+
+static int use_ointment(unit *u, const item_type *itype,
+    int amount, struct order *ord)
+{
+    ADDMSG(&u->faction->msgs, msg_message("use_item",
+        "unit amount item", u, amount, itype->rtype));
+    return potion_ointment(u, amount);
+}
+
+static int potion_power(unit *u, int amount) {
+    int hp = 10 * amount;
+
+    if (hp > u->number) {
+        hp = u->number;
+        amount = (hp + 9) % 10;
+    }
+    u->hp += hp * unit_max_hp(u) * 4;
+    return amount;
+}
+
+static int use_power_elixir(unit *u, const item_type *itype,
+    int amount, struct order *ord)
+{
+    ADDMSG(&u->faction->msgs, msg_message("use_item",
+        "unit amount item", u, amount, itype->rtype));
+    return potion_power(u, amount);
+}
+
 void register_itemfunctions(void)
 {
     /* have tests: */
+    register_item_use(use_water_of_life, "use_lifepotion");
     register_item_use(use_mistletoe, "use_mistletoe");
     register_item_use(use_tacticcrystal, "use_dreameye");
     register_item_use(use_studypotion, "use_studypotion");
@@ -422,9 +491,8 @@ void register_itemfunctions(void)
     register_item_use(use_birthdayamulet, "use_aoc");
     register_item_use(use_foolpotion, "use_p7");
     register_item_use(use_bloodpotion, "use_peasantblood");
-    register_item_use(use_healingpotion, "use_ointment");
+    register_item_use(use_ointment, "use_ointment");
+    register_item_use(use_healing_potion, "use_healing");
+    register_item_use(use_power_elixir, "use_p13");
     register_item_use(use_warmthpotion, "use_nestwarmth");
-
-    /* ungetestet: Wasser des Lebens */
-    register_item_use(use_potion_delayed, "use_p2");
 }
diff --git a/src/items.h b/src/items.h
index 2b839563d..f37444b74 100644
--- a/src/items.h
+++ b/src/items.h
@@ -12,11 +12,16 @@ without prior permission by the authors of Eressea.
 
 #ifndef H_KRNL_ITEMS
 #define H_KRNL_ITEMS
+
+#include <stdbool.h>
+
+struct unit;
+
 #ifdef __cplusplus
 extern "C" {
 #endif
 
-    extern void register_itemfunctions(void);
+    void register_itemfunctions(void);
 
 #ifdef __cplusplus
 }
diff --git a/src/jsonconf.c b/src/jsonconf.c
index cd9d991aa..c14ac9216 100644
--- a/src/jsonconf.c
+++ b/src/jsonconf.c
@@ -11,36 +11,36 @@ without prior permission by the authors of Eressea.
 */
 
 #include <platform.h>
-#include <kernel/config.h>
 #include "jsonconf.h"
 
 /* kernel includes */
-#include <kernel/building.h>
-#include <kernel/equipment.h>
-#include <kernel/item.h>
-#include <kernel/messages.h>
-#include <kernel/race.h>
-#include <kernel/region.h>
-#include <kernel/resources.h>
-#include <kernel/ship.h>
-#include <kernel/terrain.h>
-#include <kernel/spell.h>
-#include <kernel/spellbook.h>
+#include "kernel/building.h"
+#include "kernel/calendar.h"
+#include "kernel/config.h"
+#include "kernel/equipment.h"
+#include "kernel/item.h"
+#include "kernel/messages.h"
+#include "kernel/race.h"
+#include "kernel/region.h"
+#include "kernel/resources.h"
+#include "kernel/ship.h"
+#include "kernel/terrain.h"
+#include "kernel/spell.h"
+#include "kernel/spellbook.h"
 
 /* util includes */
-#include <util/attrib.h>
-#include <util/crmessage.h>
-#include <util/functions.h>
-#include <util/language.h>
-#include <util/log.h>
-#include <util/message.h>
-#include <util/nrmessage.h>
-#include <util/path.h>
-#include <util/strings.h>
-#include <util/xml.h>
+#include "util/attrib.h"
+#include "util/crmessage.h"
+#include "util/functions.h"
+#include "util/language.h"
+#include "util/log.h"
+#include "util/message.h"
+#include "util/nrmessage.h"
+#include "util/path.h"
+#include "util/strings.h"
+#include "util/xml.h"
 
 /* game modules */
-#include "calendar.h"
 #include "direction.h"
 #include "keyword.h"
 #include "move.h"
@@ -124,7 +124,7 @@ static void json_maintenance_i(cJSON *json, maintenance *mt) {
 static void json_maintenance(cJSON *json, maintenance **mtp) {
     cJSON *child;
     maintenance *mt;
-    int i, size = 1;
+    int size = 1;
 
     if (json->type == cJSON_Array) {
         size = cJSON_GetArraySize(json);
@@ -135,6 +135,7 @@ static void json_maintenance(cJSON *json, maintenance **mtp) {
     }
     *mtp = mt = (struct maintenance *) calloc(sizeof(struct maintenance), size + 1);
     if (json->type == cJSON_Array) {
+        int i;
         for (i = 0, child = json->child; child; child = child->next, ++i) {
             if (child->type == cJSON_Object) {
                 json_maintenance_i(child, mt + i);
@@ -932,6 +933,7 @@ static int include_json(const char *uri) {
     FILE *F;
     char name[PATH_MAX];
     const char *filename = uri_to_file(uri, name, sizeof(name));
+    int result = -1;
 
     F = fopen(filename, "r");
     if (F) {
@@ -952,15 +954,16 @@ static int include_json(const char *uri) {
             if (config) {
                 json_config(config);
                 cJSON_Delete(config);
+                result = 0;
             }
             else {
                 log_error("could not parse JSON from %s", uri);
-                return -1;
+                result = -1;
             }
         }
         fclose(F);
     }
-    return 0;
+    return result;
 }
 
 static int include_xml(const char *uri) {
diff --git a/src/jsonconf.test.c b/src/jsonconf.test.c
index 29c68e600..88630c833 100644
--- a/src/jsonconf.test.c
+++ b/src/jsonconf.test.c
@@ -17,7 +17,7 @@
 
 #include "util/language.h"
 
-#include "calendar.h"
+#include "kernel/calendar.h"
 #include "direction.h"
 #include "keyword.h"
 #include "move.h"
diff --git a/src/kernel/CMakeLists.txt b/src/kernel/CMakeLists.txt
index cb8373fa2..59b8cb806 100644
--- a/src/kernel/CMakeLists.txt
+++ b/src/kernel/CMakeLists.txt
@@ -7,6 +7,7 @@ ally.test.c
 build.test.c
 building.test.c
 # callbacks.test.c
+calendar.test.c
 command.test.c
 config.test.c
 # connection.test.c
@@ -49,6 +50,7 @@ ally.c
 build.c
 building.c
 callbacks.c
+calendar.c
 command.c
 config.c
 connection.c
diff --git a/src/kernel/alliance.c b/src/kernel/alliance.c
index 1aa3edd95..d5dda0143 100644
--- a/src/kernel/alliance.c
+++ b/src/kernel/alliance.c
@@ -11,19 +11,20 @@ without prior permission by the authors of Eressea.
 */
 
 #include <platform.h>
-#include <kernel/config.h>
 #include "alliance.h"
 
-#include <attributes/key.h>
-
 /* kernel includes */
-#include <kernel/building.h>
-#include <kernel/faction.h>
-#include <kernel/messages.h>
-#include <kernel/order.h>
-#include <kernel/region.h>
-#include <kernel/unit.h>
-#include <kernel/command.h>
+#include "calendar.h"
+#include "config.h"
+#include "building.h"
+#include "faction.h"
+#include "messages.h"
+#include "order.h"
+#include "region.h"
+#include "unit.h"
+#include "command.h"
+
+#include <attributes/key.h>
 
 /* util includes */
 #include <util/attrib.h>
diff --git a/src/kernel/ally.c b/src/kernel/ally.c
index dbb6aff3a..8f99f1f07 100644
--- a/src/kernel/ally.c
+++ b/src/kernel/ally.c
@@ -136,9 +136,9 @@ static int ally_mode(const ally * sf, int mode)
     return sf->status & mode;
 }
 
-static void init_npcfaction(struct attrib *a)
+static void init_npcfaction(variant *var)
 {
-    a->data.i = 1;
+    var->i = 1;
 }
 
 attrib_type at_npcfaction = {
diff --git a/src/kernel/build.c b/src/kernel/build.c
index 677cf96fc..60ac94e53 100644
--- a/src/kernel/build.c
+++ b/src/kernel/build.c
@@ -472,16 +472,15 @@ static int count_materials(unit *u, const construction *type, int n, int complet
         int c;
         for (c = 0; n > 0 && type->materials[c].number; c++) {
             const struct resource_type *rtype = type->materials[c].rtype;
-            int need, prebuilt;
             int canuse = get_pooled(u, rtype, GET_DEFAULT, INT_MAX);
             canuse = matmod(u, rtype, canuse);
 
             assert(canuse >= 0);
             if (type->reqsize > 1) {
-                prebuilt =
+                int prebuilt =
                     required(completed, type->reqsize, type->materials[c].number);
                 for (; n;) {
-                    need =
+                    int need =
                         required(completed + n, type->reqsize, type->materials[c].number);
                     if (need - prebuilt <= canuse)
                         break;
diff --git a/src/kernel/building.c b/src/kernel/building.c
index 35efa8579..0e98cef7a 100644
--- a/src/kernel/building.c
+++ b/src/kernel/building.c
@@ -16,7 +16,9 @@ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 **/
 
+#ifdef _MSC_VER
 #include <platform.h>
+#endif
 
 #include <kernel/config.h>
 #include "building.h"
@@ -150,10 +152,11 @@ building_type *bt_get_or_create(const char *name)
 int buildingcapacity(const building * b)
 {
     if (b->type->capacity >= 0) {
-        if (b->type->maxcapacity >= 0) {
-            return MIN(b->type->maxcapacity, b->size * b->type->capacity);
+        int cap = b->size * b->type->capacity;
+        if (b->type->maxcapacity > 0 && b->type->maxcapacity < cap) {
+            cap = b->type->maxcapacity;
         }
-        return b->size * b->type->capacity;
+        return cap;
     }
     if (building_finished(b)) {
         if (b->type->maxcapacity >= 0) {
@@ -313,9 +316,15 @@ int building_protection(const building_type * btype, int stage)
 {
     assert(btype->flags & BTF_FORTIFICATION);
     if (btype->maxsize < 0) {
-        return castle_bonus[MIN(stage, 5)];
+        if (stage > 5) {
+            stage = 5;
+        }
+        return castle_bonus[stage];
     }
-    return watch_bonus[MIN(stage, 2)];
+    if (stage > 2) {
+        stage = 2;
+    }
+    return watch_bonus[stage];
 }
 
 void write_building_reference(const struct building *b, struct storage *store)
@@ -664,17 +673,16 @@ building *largestbuilding(const region * r, cmp_building_cb cmp_gt,
     }
     return best;
 }
-/* Lohn bei den einzelnen Burgstufen f�r Normale Typen, Orks, Bauern,
- * Modifikation f�r St�dter. */
+/* Lohn bei den einzelnen Burgstufen f�r Normale Typen, Orks, Bauern */
 
-static const int wagetable[7][4] = {
-    { 10, 10, 11, -7 },             /* Baustelle */
-    { 10, 10, 11, -5 },             /* Handelsposten */
-    { 11, 11, 12, -3 },             /* Befestigung */
-    { 12, 11, 13, -1 },             /* Turm */
-    { 13, 12, 14, 0 },              /* Burg */
-    { 14, 12, 15, 1 },              /* Festung */
-    { 15, 13, 16, 2 }               /* Zitadelle */
+static const int wagetable[7][3] = {
+    { 10, 10, 11 },             /* Baustelle */
+    { 10, 10, 11 },             /* Handelsposten */
+    { 11, 11, 12 },             /* Befestigung */
+    { 12, 11, 13 },             /* Turm */
+    { 13, 12, 14 },             /* Burg */
+    { 14, 12, 15 },             /* Festung */
+    { 15, 13, 16 }              /* Zitadelle */
 };
 
 static int
@@ -682,7 +690,7 @@ default_wage(const region * r, const faction * f, const race * rc, int in_turn)
 {
     building *b = largestbuilding(r, cmp_wage, false);
     int esize = 0;
-    double wage;
+    int wage;
 
     if (b != NULL) {
         /* TODO: this reveals imaginary castles */
@@ -715,25 +723,28 @@ default_wage(const region * r, const faction * f, const race * rc, int in_turn)
     if (r->attribs) {
         attrib *a;
         curse *c;
+        variant vm;
 
         /* Godcurse: Income -10 */
         c = get_curse(r->attribs, &ct_godcursezone);
         if (c && curse_active(c)) {
-            wage = MAX(0, wage - 10);
+            wage = (wage < 10) ? 0 : (wage - 10);
         }
+        vm = frac_make(wage, 1);
 
         /* Bei einer D�rre verdient man nur noch ein Viertel  */
         c = get_curse(r->attribs, &ct_drought);
         if (c && curse_active(c)) {
-            wage /= curse_geteffect(c);
+            vm = frac_mul(vm, frac_make(1, curse_geteffect_int(c)));
         }
 
         a = a_find(r->attribs, &at_reduceproduction);
         if (a) {
-            wage = (wage * a->data.sa[0]) / 100;
+            vm = frac_mul(vm, frac_make(a->data.sa[0], 100));
         }
+        wage = vm.sa[0] / vm.sa[1];
     }
-    return (int)wage;
+    return wage;
 }
 
 static int
diff --git a/src/kernel/building.h b/src/kernel/building.h
index e162e041f..5a83fd0ca 100644
--- a/src/kernel/building.h
+++ b/src/kernel/building.h
@@ -21,6 +21,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 
 #include <kernel/types.h>
 #include <util/resolve.h>
+#include <util/variant.h>
 
 #include <stddef.h>
 #include <stdbool.h>
diff --git a/src/kernel/building.test.c b/src/kernel/building.test.c
index 8d5b86dc9..9c7013db3 100644
--- a/src/kernel/building.test.c
+++ b/src/kernel/building.test.c
@@ -1,5 +1,6 @@
 #include <platform.h>
 
+#include <kernel/calendar.h>
 #include <kernel/config.h>
 #include <kernel/race.h>
 #include <kernel/region.h>
diff --git a/src/calendar.c b/src/kernel/calendar.c
similarity index 99%
rename from src/calendar.c
rename to src/kernel/calendar.c
index 23562daa6..df9f6c204 100644
--- a/src/calendar.c
+++ b/src/kernel/calendar.c
@@ -10,6 +10,7 @@
 #include <stdlib.h>
 #include <stdio.h>
 
+int turn = 0;
 int first_month = 0;
 int weeks_per_month = 3;
 int months_per_year = 12;
diff --git a/src/calendar.h b/src/kernel/calendar.h
similarity index 97%
rename from src/calendar.h
rename to src/kernel/calendar.h
index af4bd6a4f..164a96bf4 100644
--- a/src/calendar.h
+++ b/src/kernel/calendar.h
@@ -17,6 +17,7 @@ extern "C" {
     extern int months_per_year;
     extern int *month_season;
     extern int first_month;
+    extern int turn;
 
     extern char **weeknames;
     extern char **weeknames2;
diff --git a/src/calendar.test.c b/src/kernel/calendar.test.c
similarity index 100%
rename from src/calendar.test.c
rename to src/kernel/calendar.test.c
diff --git a/src/kernel/config.c b/src/kernel/config.c
index 9a5ba0104..05690e301 100644
--- a/src/kernel/config.c
+++ b/src/kernel/config.c
@@ -29,7 +29,6 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #include "curse.h"
 #include "connection.h"
 #include "building.h"
-#include "calendar.h"
 #include "direction.h"
 #include "equipment.h"
 #include "faction.h"
@@ -98,8 +97,6 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #endif
 struct settings global;
 
-int turn = 0;
-
 const char *parameters[MAXPARAMS] = {
     "LOCALE",
     "ALLES",
@@ -147,39 +144,6 @@ const char *parameters[MAXPARAMS] = {
     "ALLIANZ"
 };
 
-FILE *debug;
-
-void
-parse(keyword_t kword, int(*dofun) (unit *, struct order *), bool thisorder)
-{
-    region *r;
-
-    for (r = regions; r; r = r->next) {
-        unit **up = &r->units;
-        while (*up) {
-            unit *u = *up;
-            order **ordp = &u->orders;
-            if (thisorder)
-                ordp = &u->thisorder;
-            while (*ordp) {
-                order *ord = *ordp;
-                if (getkeyword(ord) == kword) {
-                    if (dofun(u, ord) != 0)
-                        break;
-                    if (u->orders == NULL)
-                        break;
-                }
-                if (thisorder)
-                    break;
-                if (*ordp == ord)
-                    ordp = &ord->next;
-            }
-            if (*up == u)
-                up = &u->next;
-        }
-    }
-}
-
 int findoption(const char *s, const struct locale *lang)
 {
     void **tokens = get_translations(lang, UT_OPTIONS);
diff --git a/src/kernel/config.h b/src/kernel/config.h
index e0ad682c6..94abcb7f4 100644
--- a/src/kernel/config.h
+++ b/src/kernel/config.h
@@ -141,8 +141,6 @@ extern "C" {
     extern const char *parameters[];
     extern settings global;
 
-    extern int turn;
-
 #ifdef __cplusplus
 }
 #endif
diff --git a/src/kernel/connection.c b/src/kernel/connection.c
index 516cb6ead..6f73c94f2 100644
--- a/src/kernel/connection.c
+++ b/src/kernel/connection.c
@@ -225,7 +225,7 @@ border_type *find_bordertype(const char *name)
 void b_read(connection * b, gamedata * data)
 {
     storage * store = data->store;
-    int n, result = 0;
+    int n;
     switch (b->type->datatype) {
     case VAR_NONE:
     case VAR_INT:
@@ -240,9 +240,7 @@ void b_read(connection * b, gamedata * data)
     case VAR_VOIDPTR:
     default:
         assert(!"invalid variant type in connection");
-        result = 0;
     }
-    assert(result >= 0 || "EOF encountered?");
 }
 
 void b_write(const connection * b, storage * store)
diff --git a/src/kernel/curse.c b/src/kernel/curse.c
index 0f215dbee..d03ddb067 100644
--- a/src/kernel/curse.c
+++ b/src/kernel/curse.c
@@ -102,9 +102,9 @@ static void cunhash(curse * c)
 
 /* ------------------------------------------------------------- */
 /* at_curse */
-void curse_init(attrib * a)
+void curse_init(variant *var)
 {
-    a->data.v = calloc(1, sizeof(curse));
+    var->v = calloc(1, sizeof(curse));
 }
 
 int curse_age(attrib * a, void *owner)
@@ -133,9 +133,9 @@ void destroy_curse(curse * c)
     free(c);
 }
 
-void curse_done(attrib * a)
+void curse_done(variant * var)
 {
-    destroy_curse((curse *)a->data.v);
+    destroy_curse((curse *)var->v);
 }
 
 /** reads curses that have been removed from the code */
@@ -177,10 +177,10 @@ static int read_ccompat(const char *cursename, struct storage *store)
     return -1;
 }
 
-int curse_read(attrib * a, void *owner, gamedata *data)
+int curse_read(variant *var, void *owner, gamedata *data)
 {
     storage *store = data->store;
-    curse *c = (curse *)a->data.v;
+    curse *c = (curse *)var->v;
     int ur;
     char cursename[64];
     int n;
@@ -238,9 +238,9 @@ int curse_read(attrib * a, void *owner, gamedata *data)
     return AT_READ_OK;
 }
 
-void curse_write(const attrib * a, const void *owner, struct storage *store)
+void curse_write(const variant * var, const void *owner, struct storage *store)
 {
-    curse *c = (curse *)a->data.v;
+    curse *c = (curse *)var->v;
     const curse_type *ct = c->type;
     unit *mage = (c->magician && c->magician->number) ? c->magician : NULL;
 
diff --git a/src/kernel/curse.h b/src/kernel/curse.h
index 054387d59..36ace2895 100644
--- a/src/kernel/curse.h
+++ b/src/kernel/curse.h
@@ -221,9 +221,9 @@ extern "C" {
 
     void curses_done(void); /* de-register all curse-types */
 
-    void curse_write(const struct attrib *a, const void *owner,
+    void curse_write(const union variant *v, const void *owner,
         struct storage *store);
-    int curse_read(struct attrib *a, void *owner, struct gamedata *store);
+    int curse_read(union variant *v, void *owner, struct gamedata *store);
 
     /* ------------------------------------------------------------- */
     /* Kommentare:
@@ -291,8 +291,8 @@ extern "C" {
 
     curse *findcurse(int curseid);
 
-    void curse_init(struct attrib *a);
-    void curse_done(struct attrib *a);
+    void curse_init(union variant *a);
+    void curse_done(union variant *a);
     int curse_age(struct attrib *a, void *owner);
 
     double destr_curse(struct curse *c, int cast_level, double force);
diff --git a/src/kernel/faction.c b/src/kernel/faction.c
index 90649600f..36f467c6e 100755
--- a/src/kernel/faction.c
+++ b/src/kernel/faction.c
@@ -17,8 +17,11 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 **/
 
 #include <platform.h>
-#include <kernel/config.h>
+
 #include "faction.h"
+
+#include "calendar.h"
+#include "config.h"
 #include "alliance.h"
 #include "ally.h"
 #include "curse.h"
diff --git a/src/kernel/faction.test.c b/src/kernel/faction.test.c
index 904609be5..18a64ee90 100644
--- a/src/kernel/faction.test.c
+++ b/src/kernel/faction.test.c
@@ -2,6 +2,7 @@
 
 #include <kernel/ally.h>
 #include <kernel/alliance.h>
+#include <kernel/calendar.h>
 #include <kernel/faction.h>
 #include <kernel/item.h>
 #include <kernel/plane.h>
diff --git a/src/kernel/group.c b/src/kernel/group.c
index 54cd965da..48434ff5a 100755
--- a/src/kernel/group.c
+++ b/src/kernel/group.c
@@ -96,14 +96,14 @@ static group *find_group(int gid)
     return g;
 }
 
-static int read_group(attrib * a, void *owner, gamedata *data)
+static int read_group(variant *var, void *owner, gamedata *data)
 {
     struct storage *store = data->store;
     group *g;
     int gid;
 
     READ_INT(store, &gid);
-    a->data.v = g = find_group(gid);
+    var->v = g = find_group(gid);
     if (g != 0) {
         g->members++;
         return AT_READ_OK;
@@ -112,9 +112,9 @@ static int read_group(attrib * a, void *owner, gamedata *data)
 }
 
 static void
-write_group(const attrib * a, const void *owner, struct storage *store)
+write_group(const variant *var, const void *owner, struct storage *store)
 {
-    group *g = (group *)a->data.v;
+    group *g = (group *)var->v;
     WRITE_INT(store, g->gid);
 }
 
diff --git a/src/kernel/item.c b/src/kernel/item.c
index 74951895a..4483c51f0 100644
--- a/src/kernel/item.c
+++ b/src/kernel/item.c
@@ -206,11 +206,13 @@ resource_type *rt_get_or_create(const char *name) {
 
 static const char *it_aliases[][2] = {
     { "Runenschwert", "runesword" },
-    { "p12", "truthpotion" },
     { "p1", "goliathwater" },
+    { "p2", "lifepotion" },
     { "p4", "ointment" },
     { "p5", "peasantblood" },
     { "p8", "nestwarmth" },
+    { "p14", "healing" },
+    { "p12", "truthpotion" },
     { "diamond", "adamantium" },
     { "diamondaxe", "adamantiumaxe" },
     { "diamondplate", "adamantiumplate" },
@@ -225,13 +227,18 @@ static const char *it_alias(const char *zname)
         if (strcmp(it_aliases[i][0], zname) == 0)
             return it_aliases[i][1];
     }
-    return zname;
+    return NULL;
 }
 
 item_type *it_find(const char *zname)
 {
-    const char *name = it_alias(zname);
-    resource_type *result = rt_find(name);
+    resource_type *result = rt_find(zname);
+    if (!result) {
+        const char *name = it_alias(zname);
+        if (name) {
+            result = rt_find(name);
+        }
+    }
     return result ? result->itype : 0;
 }
 
@@ -555,7 +562,7 @@ static const char *resourcenames[MAX_RESOURCES] = {
     "laen", "fairyboot", "aoc", "pegasus",
     "elvenhorse", "charger", "dolphin", "roqf", "trollbelt",
     "aurafocus", "sphereofinv", "magicbag",
-    "magicherbbag", "dreameye", "p2"
+    "magicherbbag", "dreameye", "lifepotion"
 };
 
 const resource_type *get_resourcetype(resource_t type) {
@@ -636,8 +643,8 @@ struct order *), const char *name)
 static void init_oldpotions(void)
 {
     const char *potionnames[MAX_POTIONS] = {
-        "p0", "goliathwater", "p2", "p3", "ointment", "peasantblood", "p6",
-        "p7", "nestwarmth", "p9", "p10", "p11", "truthpotion", "p13", "p14"
+        "p0", "goliathwater", "lifepotion", "p3", "ointment", "peasantblood", "p6",
+        "p7", "nestwarmth", "p9", "p10", "p11", "truthpotion", "healing"
     };
     int p;
 
diff --git a/src/kernel/order.c b/src/kernel/order.c
index 8defd05c9..807541ac1 100644
--- a/src/kernel/order.c
+++ b/src/kernel/order.c
@@ -242,10 +242,10 @@ order *create_order(keyword_t kwd, const struct locale * lang,
         va_start(marker, params);
         sbs_init(&sbs, zBuffer, sizeof(zBuffer));
         while (*params) {
-            int i;
             const char *s;
             tok = strchr(params, '%');
             if (tok) {
+                int i;
                 if (tok != params) {
                     sbs_strncat(&sbs, params, tok - params);
                 }
diff --git a/src/kernel/region.c b/src/kernel/region.c
index 3f25f156b..40b6ad484 100644
--- a/src/kernel/region.c
+++ b/src/kernel/region.c
@@ -17,12 +17,13 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 **/
 
 #include <platform.h>
-#include <kernel/config.h>
 #include "region.h"
 
 /* kernel includes */
 #include "alliance.h"
 #include "building.h"
+#include "calendar.h"
+#include "config.h"
 #include "connection.h"
 #include "curse.h"
 #include "equipment.h"
@@ -181,14 +182,14 @@ void deathcounts(region * r, int fallen)
 /********************/
 /*   at_moveblock   */
 /********************/
-void a_initmoveblock(attrib * a)
+void a_initmoveblock(variant *var)
 {
-    a->data.v = calloc(1, sizeof(moveblock));
+    var->v = calloc(1, sizeof(moveblock));
 }
 
-int a_readmoveblock(attrib * a, void *owner, gamedata *data)
+int a_readmoveblock(variant *var, void *owner, gamedata *data)
 {
-    moveblock *m = (moveblock *)(a->data.v);
+    moveblock *m = (moveblock *)var->v;
     int i;
 
     READ_INT(data->store, &i);
@@ -197,9 +198,9 @@ int a_readmoveblock(attrib * a, void *owner, gamedata *data)
 }
 
 void
-a_writemoveblock(const attrib * a, const void *owner, struct storage *store)
+a_writemoveblock(const variant *var, const void *owner, struct storage *store)
 {
-    moveblock *m = (moveblock *)(a->data.v);
+    moveblock *m = (moveblock *)var->v;
     WRITE_INT(store, (int)m->dir);
 }
 
diff --git a/src/kernel/region.test.c b/src/kernel/region.test.c
index 4baa807c8..d54049b8e 100644
--- a/src/kernel/region.test.c
+++ b/src/kernel/region.test.c
@@ -16,7 +16,7 @@ void test_terraform(CuTest *tc) {
     item_type *itype;
 
     test_setup();
-    itype = test_create_itemtype("ointment");
+    itype = test_create_itemtype("oil");
     itype->rtype->flags |= (RTF_ITEM | RTF_POOLED);
     new_luxurytype(itype, 0);
 
diff --git a/src/kernel/save.c b/src/kernel/save.c
index a4bfdcbca..4408ab909 100644
--- a/src/kernel/save.c
+++ b/src/kernel/save.c
@@ -25,6 +25,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #include "alliance.h"
 #include "ally.h"
 #include "building.h"
+#include "calendar.h"
 #include "connection.h"
 #include "equipment.h"
 #include "faction.h"
@@ -495,7 +496,7 @@ unit *read_unit(gamedata *data)
     }
 
     READ_INT(data->store, &n);
-    setstatus(u, n);
+    unit_setstatus(u, (status_t)n);
     READ_INT(data->store, &u->flags);
     u->flags &= UFL_SAVEMASK;
     if ((u->flags & UFL_ANON_FACTION) && !rule_stealth_anon()) {
diff --git a/src/kernel/skills.c b/src/kernel/skills.c
index 8c4b4d2a6..24981728f 100644
--- a/src/kernel/skills.c
+++ b/src/kernel/skills.c
@@ -40,21 +40,16 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #include <string.h>
 
 /** skillmod attribut **/
-static void init_skillmod(attrib * a)
+static void init_skillmod(variant *var)
 {
-    a->data.v = calloc(sizeof(skillmod_data), 1);
-}
-
-static void finalize_skillmod(attrib * a)
-{
-    free(a->data.v);
+    var->v = calloc(sizeof(skillmod_data), 1);
 }
 
 /** temporary skill modification (NOT SAVED!). */
 attrib_type at_skillmod = {
     "skillmod",
     init_skillmod,
-    finalize_skillmod,
+    a_free_voidptr,
     NULL,
     NULL,                         /* can't write function pointers */
     NULL,                         /* can't read function pointers */
diff --git a/src/kernel/terrain.c b/src/kernel/terrain.c
index 5a46b7fe7..6a5b4652d 100644
--- a/src/kernel/terrain.c
+++ b/src/kernel/terrain.c
@@ -71,12 +71,12 @@ bool terrain_changed(int *cache) {
 void free_terrains(void)
 {
     while (registered_terrains) {
-        int n;
         terrain_type * t = registered_terrains;
         registered_terrains = t->next;
         free(t->_name);
         free(t->herbs);
         if (t->production) {
+            int n;
             for (n = 0; t->production[n].type; ++n) {
                 free(t->production[n].base);
                 free(t->production[n].divisor);
diff --git a/src/kernel/types.h b/src/kernel/types.h
index 9e9ed3b66..61f1268cc 100644
--- a/src/kernel/types.h
+++ b/src/kernel/types.h
@@ -20,9 +20,6 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #define ERESSEA_TYPES_H
 
 #include <settings.h>
-#include <util/variant.h>
-
-typedef short item_t;
 
 struct attrib;
 struct attrib_type;
@@ -77,15 +74,14 @@ typedef enum {
 
 /* ------------------ Status von Einheiten --------------------- */
 
-typedef unsigned char status_t;
-enum {
+typedef enum {
   ST_AGGRO,
   ST_FIGHT,
   ST_BEHIND,
   ST_CHICKEN,
   ST_AVOID,
   ST_FLEE
-};
+} status_t;
 
 /* ----------------- Parameter --------------------------------- */
 
diff --git a/src/kernel/unit.c b/src/kernel/unit.c
index 367ea4d97..9af46b28c 100644
--- a/src/kernel/unit.c
+++ b/src/kernel/unit.c
@@ -22,6 +22,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 
 #include "ally.h"
 #include "building.h"
+#include "calendar.h"
 #include "faction.h"
 #include "group.h"
 #include "connection.h"
@@ -506,13 +507,13 @@ int ualias(const unit * u)
     return a->data.i;
 }
 
-int a_readprivate(attrib * a, void *owner, gamedata *data)
+int a_readprivate(variant *var, void *owner, gamedata *data)
 {
     struct storage *store = data->store;
     char lbuf[DISPLAYSIZE];
     READ_STR(store, lbuf, sizeof(lbuf));
-    a->data.v = str_strdup(lbuf);
-    return (a->data.v) ? AT_READ_OK : AT_READ_FAIL;
+    var->v = str_strdup(lbuf);
+    return (var->v) ? AT_READ_OK : AT_READ_FAIL;
 }
 
 /*********************/
@@ -572,35 +573,6 @@ void usetprivate(unit * u, const char *str)
     a->data.v = str_strdup(str);
 }
 
-/*********************/
-/*   at_potionuser   */
-/*********************/
-/* Einheit BENUTZT einen Trank */
-attrib_type at_potionuser = {
-    "potionuser",
-    DEFAULT_INIT,
-    DEFAULT_FINALIZE,
-    DEFAULT_AGE,
-    NO_WRITE,
-    NO_READ
-};
-
-void usetpotionuse(unit * u, const item_type * ptype)
-{
-    attrib *a = a_find(u->attribs, &at_potionuser);
-    if (!a)
-        a = a_add(&u->attribs, a_new(&at_potionuser));
-    a->data.v = (void *)ptype;
-}
-
-const item_type *ugetpotionuse(const unit * u)
-{
-    attrib *a = a_find(u->attribs, &at_potionuser);
-    if (!a)
-        return NULL;
-    return (const item_type *)a->data.v;
-}
-
 /*********************/
 /*   at_target   */
 /*********************/
@@ -644,15 +616,15 @@ void usettarget(unit * u, const unit * t)
 /*   at_siege   */
 /*********************/
 
-void a_writesiege(const attrib * a, const void *owner, struct storage *store)
+void a_writesiege(const variant *var, const void *owner, struct storage *store)
 {
-    struct building *b = (struct building *)a->data.v;
+    struct building *b = (struct building *)var->v;
     write_building_reference(b, store);
 }
 
-int a_readsiege(attrib * a, void *owner, gamedata *data)
+int a_readsiege(variant *var, void *owner, gamedata *data)
 {
-    if (read_building_reference(data, (building **)&a->data.v, NULL) <= 0) {
+    if (read_building_reference(data, (building **)&var->v, NULL) <= 0) {
         return AT_READ_FAIL;
     }
     return AT_READ_OK;
@@ -1530,7 +1502,7 @@ unit *create_unit(region * r, faction * f, int number, const struct race *urace,
         attrib *a;
 
         /* erbt Kampfstatus */
-        setstatus(u, creator->status);
+        unit_setstatus(u, creator->status);
 
         /* erbt Gebaeude/Schiff */
         if (creator->region == r) {
@@ -1985,14 +1957,6 @@ bool has_horses(const unit * u)
     return false;
 }
 
-void setstatus(unit *u, int status)
-{
-    assert(status >= ST_AGGRO && status <= ST_FLEE);
-    if (u->status != status) {
-        u->status = (status_t)status;
-    }
-}
-
 #define MAINTENANCE 10
 int maintenance_cost(const struct unit *u)
 {
diff --git a/src/kernel/unit.h b/src/kernel/unit.h
index 91a3ec930..4d1cc4362 100644
--- a/src/kernel/unit.h
+++ b/src/kernel/unit.h
@@ -150,9 +150,6 @@ extern "C" {
     const char *uprivate(const struct unit *u);
     void usetprivate(struct unit *u, const char *c);
 
-    const struct item_type *ugetpotionuse(const struct unit *u);        /* benutzt u einein trank? */
-    void usetpotionuse(struct unit *u, const struct item_type *p);      /* u benutzt trank p (es darf halt nur einer pro runde) */
-
     bool ucontact(const struct unit *u, const struct unit *u2);
     void usetcontact(struct unit *u, const struct unit *c);
 
@@ -267,7 +264,6 @@ extern "C" {
     int getunit(const struct region * r, const struct faction * f, struct unit **uresult);
     int read_unitid(const struct faction *f, const struct region *r);
 
-    void setstatus(struct unit *u, int status);
     /* !< sets combatstatus of a unit */
     int besieged(const struct unit *u);
     bool has_horses(const struct unit *u);
diff --git a/src/laws.c b/src/laws.c
index 85b820323..cae1b2066 100644
--- a/src/laws.c
+++ b/src/laws.c
@@ -41,42 +41,33 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #include "prefix.h"
 #include "reports.h"
 #include "teleport.h"
-#include "calendar.h"
 #include "guard.h"
 #include "volcano.h"
 
-/* attributes includes */
-#include <attributes/racename.h>
-#include <attributes/raceprefix.h>
-#include <attributes/stealth.h>
-
-#include <spells/buildingcurse.h>
-#include <spells/regioncurse.h>
-#include <spells/unitcurse.h>
-
 /* kernel includes */
-#include <kernel/alliance.h>
-#include <kernel/ally.h>
-#include <kernel/callbacks.h>
-#include <kernel/connection.h>
-#include <kernel/curse.h>
-#include <kernel/building.h>
-#include <kernel/faction.h>
-#include <kernel/group.h>
-#include <kernel/item.h>
-#include <kernel/messages.h>
-#include <kernel/order.h>
-#include <kernel/plane.h>
-#include <kernel/pool.h>
-#include <kernel/race.h>
-#include <kernel/region.h>
-#include <kernel/resources.h>
-#include <kernel/ship.h>
-#include <kernel/spell.h>
-#include <kernel/spellbook.h>
-#include <kernel/terrain.h>
-#include <kernel/terrainid.h>
-#include <kernel/unit.h>
+#include "kernel/alliance.h"
+#include "kernel/ally.h"
+#include "kernel/calendar.h"
+#include "kernel/callbacks.h"
+#include "kernel/connection.h"
+#include "kernel/curse.h"
+#include "kernel/building.h"
+#include "kernel/faction.h"
+#include "kernel/group.h"
+#include "kernel/item.h"
+#include "kernel/messages.h"
+#include "kernel/order.h"
+#include "kernel/plane.h"
+#include "kernel/pool.h"
+#include "kernel/race.h"
+#include "kernel/region.h"
+#include "kernel/resources.h"
+#include "kernel/ship.h"
+#include "kernel/spell.h"
+#include "kernel/spellbook.h"
+#include "kernel/terrain.h"
+#include "kernel/terrainid.h"
+#include "kernel/unit.h"
 
 /* util includes */
 #include <util/attrib.h>
@@ -97,10 +88,20 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #include <util/umlaut.h>
 #include <util/unicode.h>
 
+/* attributes includes */
 #include <attributes/otherfaction.h>
+#include <attributes/racename.h>
+#include <attributes/raceprefix.h>
+#include <attributes/seenspell.h>
+#include <attributes/stealth.h>
+
+#include <spells/buildingcurse.h>
+#include <spells/regioncurse.h>
+#include <spells/unitcurse.h>
 
 #include <selist.h>
 #include <iniparser.h>
+
 /* libc includes */
 #include <assert.h>
 #include <stdio.h>
@@ -2306,13 +2307,7 @@ static void reshow_other(unit * u, struct order *ord, const char *s) {
         }
 
         if (sp) {
-            attrib *a = a_find(u->faction->attribs, &at_seenspell);
-            while (a != NULL && a->type == &at_seenspell && a->data.v != sp) {
-                a = a->next;
-            }
-            if (a != NULL) {
-                a_remove(&u->faction->attribs, a);
-            }
+            reset_seen_spells(u->faction, sp);
             found = true;
         }
 
@@ -2330,7 +2325,7 @@ static void reshow(unit * u, struct order *ord, const char *s, param_t p)
 {
     switch (p) {
     case P_ZAUBER:
-        a_removeall(&u->faction->attribs, &at_seenspell);
+        reset_seen_spells(u->faction, NULL);
         break;
     case P_POTIONS:
         if (!display_potions(u)) {
@@ -2443,22 +2438,22 @@ int status_cmd(unit * u, struct order *ord)
     s = gettoken(token, sizeof(token));
     switch (findparam(s, u->faction->locale)) {
     case P_NOT:
-        setstatus(u, ST_AVOID);
+        unit_setstatus(u, ST_AVOID);
         break;
     case P_BEHIND:
-        setstatus(u, ST_BEHIND);
+        unit_setstatus(u, ST_BEHIND);
         break;
     case P_FLEE:
-        setstatus(u, ST_FLEE);
+        unit_setstatus(u, ST_FLEE);
         break;
     case P_CHICKEN:
-        setstatus(u, ST_CHICKEN);
+        unit_setstatus(u, ST_CHICKEN);
         break;
     case P_AGGRO:
-        setstatus(u, ST_AGGRO);
+        unit_setstatus(u, ST_AGGRO);
         break;
     case P_VORNE:
-        setstatus(u, ST_FIGHT);
+        unit_setstatus(u, ST_FIGHT);
         break;
     case P_HELP:
         if (getparam(u->faction->locale) == P_NOT) {
@@ -2474,7 +2469,7 @@ int status_cmd(unit * u, struct order *ord)
                 msg_feedback(u, ord, "unknown_status", ""));
         }
         else {
-            setstatus(u, ST_FIGHT);
+            unit_setstatus(u, ST_FIGHT);
         }
     }
     return 0;
@@ -2725,10 +2720,10 @@ static void age_stonecircle(building *b) {
             curse *c = get_curse(rt->attribs, &ct_astralblock);
             if (!c) {
                 int sk = effskill(mage, SK_MAGIC, 0);
-                float effect = 100;
                 if (sk > 0) {
                     int vig = sk;
                     int dur = (sk + 1) / 2;
+                    float effect = 100;
                     /* the mage reactivates the circle */
                     c = create_curse(mage, &rt->attribs, &ct_astralblock,
                         vig, dur, effect, 0);
@@ -2945,7 +2940,7 @@ void maketemp_cmd(unit *u, order **olist)
         if (sh) {
             set_leftship(u2, sh);
         }
-        setstatus(u2, u->status);
+        unit_setstatus(u2, u->status);
 
         /* copy orders until K_END from u to u2 */
         ordp = &makeord->next;
@@ -3303,6 +3298,21 @@ static void copy_spells(const spellbook * src, spellbook * dst, int maxlevel)
     }
 }
 
+static void show_new_spells(faction * f, int level, const spellbook *book)
+{
+    if (book) {
+        selist *ql = book->spells;
+        int qi;
+
+        for (qi = 0; ql; selist_advance(&ql, &qi, 1)) {
+            spellbook_entry *sbe = (spellbook_entry *)selist_get(ql, qi);
+            if (sbe->level <= level) {
+                show_spell(f, sbe);
+            }
+        }
+    }
+}
+
 static void update_spells(void)
 {
     faction *f;
diff --git a/src/laws.test.c b/src/laws.test.c
index 5edde187d..4d641cc52 100644
--- a/src/laws.test.c
+++ b/src/laws.test.c
@@ -6,6 +6,7 @@
 
 #include <kernel/ally.h>
 #include <kernel/alliance.h>
+#include <kernel/calendar.h>
 #include <kernel/config.h>
 #include <kernel/building.h>
 #include <kernel/faction.h>
@@ -882,7 +883,7 @@ static void test_luck_message(CuTest *tc) {
 
     demographics();
 
-    CuAssertPtrEquals_Msg(tc, "unexpected message", (void *)NULL, r->msgs);
+    CuAssertPtrEquals_Msg(tc, "unexpected message", NULL, r->msgs);
 
     a = (attrib *)a_find(r->attribs, &at_peasantluck);
     if (!a)
diff --git a/src/magic.c b/src/magic.c
index 6855c307f..b64ec221a 100644
--- a/src/magic.c
+++ b/src/magic.c
@@ -101,20 +101,6 @@ const char *magic_school[MAXMAGIETYP] = {
     "common"
 };
 
-static void a_init_reportspell(struct attrib *a) {
-    a->data.v = calloc(1, sizeof(spellbook_entry));
-}
-
-static void a_finalize_reportspell(struct attrib *a) {
-    free(a->data.v);
-}
-
-attrib_type at_reportspell = {
-    "reportspell",
-    a_init_reportspell,
-    a_finalize_reportspell,
-    0, NO_WRITE, NO_READ
-};
 /**
  ** at_icastle
  ** TODO: separate castle-appearance from illusion-effects
@@ -140,10 +126,10 @@ typedef struct icastle_data {
     int time;
 } icastle_data;
 
-static int a_readicastle(attrib * a, void *owner, struct gamedata *data)
+static int a_readicastle(variant *var, void *owner, struct gamedata *data)
 {
     storage *store = data->store;
-    icastle_data *idata = (icastle_data *)a->data.v;
+    icastle_data *idata = (icastle_data *)var->v;
     char token[32];
 
     UNUSED_ARG(owner);
@@ -157,9 +143,9 @@ static int a_readicastle(attrib * a, void *owner, struct gamedata *data)
 }
 
 static void
-a_writeicastle(const attrib * a, const void *owner, struct storage *store)
+a_writeicastle(const variant *var, const void *owner, struct storage *store)
 {
-    icastle_data *data = (icastle_data *)a->data.v;
+    icastle_data *data = (icastle_data *)var->v;
     UNUSED_ARG(owner);
     WRITE_TOK(store, data->type->_name);
     WRITE_INT(store, data->time);
@@ -182,20 +168,15 @@ static int a_ageicastle(struct attrib *a, void *owner)
     return AT_AGE_KEEP;
 }
 
-static void a_initicastle(struct attrib *a)
+static void a_initicastle(variant *var)
 {
-    a->data.v = calloc(sizeof(icastle_data), 1);
-}
-
-static void a_finalizeicastle(struct attrib *a) /*-V524 */
-{
-    free(a->data.v);
+    var->v = calloc(sizeof(icastle_data), 1);
 }
 
 attrib_type at_icastle = {
     "zauber_icastle",
     a_initicastle,
-    a_finalizeicastle,
+    a_free_voidptr,
     a_ageicastle,
     a_writeicastle,
     a_readicastle
@@ -221,14 +202,14 @@ extern int dice(int count, int value);
  * Umwandlung von alt nach neu gebraucht werden */
  /* ------------------------------------------------------------- */
 
-static void init_mage(attrib * a)
+static void init_mage(variant *var)
 {
-    a->data.v = calloc(sizeof(sc_mage), 1);
+    var->v = calloc(sizeof(sc_mage), 1);
 }
 
-static void free_mage(attrib * a)
+static void free_mage(variant *var)
 {
-    sc_mage *mage = (sc_mage *)a->data.v;
+    sc_mage *mage = (sc_mage *)var->v;
     if (mage->spellbook) {
         spellbook_clear(mage->spellbook);
         free(mage->spellbook);
@@ -253,11 +234,11 @@ int get_spell_level_mage(const spell * sp, void * cbdata)
     return sbe ? sbe->level : 0;
 }
 
-static int read_mage(attrib * a, void *owner, struct gamedata *data)
+static int read_mage(variant *var, void *owner, struct gamedata *data)
 {
     storage *store = data->store;
     int i, mtype;
-    sc_mage *mage = (sc_mage *)a->data.v;
+    sc_mage *mage = (sc_mage *)var->v;
     char spname[64];
 
     UNUSED_ARG(owner);
@@ -301,10 +282,10 @@ static int read_mage(attrib * a, void *owner, struct gamedata *data)
 }
 
 static void
-write_mage(const attrib * a, const void *owner, struct storage *store)
+write_mage(const variant *var, const void *owner, struct storage *store)
 {
     int i;
-    sc_mage *mage = (sc_mage *)a->data.v;
+    sc_mage *mage = (sc_mage *)var->v;
 
     UNUSED_ARG(owner);
     WRITE_INT(store, mage->magietyp);
@@ -354,82 +335,8 @@ sc_mage *get_mage_depr(const unit * u)
     return NULL;
 }
 
-/* ------------------------------------------------------------- */
-/* Ausgabe der Spruchbeschreibungen
-* Anzeige des Spruchs nur, wenn die Stufe des besten Magiers vorher
-* kleiner war (u->faction->seenspells). Ansonsten muss nur geprüft
-* werden, ob dieser Magier den Spruch schon kennt, und andernfalls der
-* Spruch zu seiner List-of-known-spells hinzugefügt werden.
-*/
-
-static int read_seenspell(attrib * a, void *owner, struct gamedata *data)
-{
-    storage *store = data->store;
-    spell *sp = 0;
-    char token[32];
-
-    UNUSED_ARG(owner);
-    READ_TOK(store, token, sizeof(token));
-    if (data->version < UNIQUE_SPELLS_VERSION) {
-        READ_INT(store, 0); /* ignore mtype */
-    }
-    sp = find_spell(token);
-    if (!sp) {
-        log_info("read_seenspell: could not find spell '%s'\n", token);
-        return AT_READ_FAIL;
-    }
-    a->data.v = sp;
-    return AT_READ_OK;
-}
-
-static void
-write_seenspell(const attrib * a, const void *owner, struct storage *store)
-{
-    const spell *sp = (const spell *)a->data.v;
-    UNUSED_ARG(owner);
-    WRITE_TOK(store, sp->sname);
-}
-
-attrib_type at_seenspell = {
-    "seenspell", NULL, NULL, NULL, write_seenspell, read_seenspell
-};
-
 #define MAXSPELLS 256
 
-static bool already_seen(const faction * f, const spell * sp)
-{
-    attrib *a;
-
-    for (a = a_find(f->attribs, &at_seenspell); a && a->type == &at_seenspell;
-        a = a->next) {
-        if (a->data.v == sp)
-            return true;
-    }
-    return false;
-}
-
-void show_new_spells(faction * f, int level, const spellbook *book)
-{
-    if (book) {
-        selist *ql = book->spells;
-        int qi;
-
-        for (qi = 0; ql; selist_advance(&ql, &qi, 1)) {
-            spellbook_entry *sbe = (spellbook_entry *)selist_get(ql, qi);
-            if (sbe->level <= level) {
-                if (!already_seen(f, sbe->sp)) {
-                    attrib * a = a_new(&at_reportspell);
-                    spellbook_entry * entry = (spellbook_entry *)a->data.v;
-                    entry->level = sbe->level;
-                    entry->sp = sbe->sp;
-                    a_add(&f->attribs, a);
-                    a_add(&f->attribs, a_new(&at_seenspell))->data.v = sbe->sp;
-                }
-            }
-        }
-    }
-}
-
 /** update the spellbook with a new level
 * Written for E3
 */
@@ -592,13 +499,13 @@ void unset_combatspell(unit * u, spell * sp)
 {
     sc_mage *m;
     int nr = 0;
-    int i;
 
     m = get_mage_depr(u);
     if (!m)
         return;
 
     if (!sp) {
+        int i;
         for (i = 0; i < MAXCOMBATSPELLS; i++) {
             m->combatspells[i].sp = NULL;
         }
@@ -1682,13 +1589,13 @@ verify_targets(castorder * co, int *invalid, int *resist, int *success)
     const spell *sp = co->sp;
     region *target_r = co_get_region(co);
     spellparameter *sa = co->par;
-    int i;
 
     *invalid = 0;
     *resist = 0;
     *success = 0;
 
     if (sa && sa->length) {
+        int i;
         /* zuerst versuchen wir vorher nicht gefundene Objekte zu finden.
          * Wurde ein Objekt durch globalsuche gefunden, obwohl der Zauber
          * gar nicht global hätte suchen dürften, setzen wir das Objekt
@@ -2178,9 +2085,9 @@ bool is_familiar(const unit * u)
 }
 
 static void
-a_write_unit(const attrib * a, const void *owner, struct storage *store)
+a_write_unit(const variant *var, const void *owner, struct storage *store)
 {
-    unit *u = (unit *)a->data.v;
+    unit *u = (unit *)var->v;
     UNUSED_ARG(owner);
     write_unit_reference(u, store);
 }
@@ -2296,10 +2203,10 @@ static void * resolve_familiar(int id, void *data) {
     return data;
 }
 
-static int read_familiar(attrib * a, void *owner, struct gamedata *data)
+static int read_familiar(variant *var, void *owner, struct gamedata *data)
 {
     UNUSED_ARG(owner);
-    if (read_unit_reference(data, (unit **)&a->data.v, resolve_familiar) <= 0) {
+    if (read_unit_reference(data, (unit **)&var->v, resolve_familiar) <= 0) {
         return AT_READ_FAIL;
     }
     return AT_READ_OK;
@@ -2377,10 +2284,10 @@ static void * resolve_clone(int id, void *data) {
     return data;
 }
 
-static int read_clone(attrib * a, void *owner, struct gamedata *data)
+static int read_clone(variant *var, void *owner, struct gamedata *data)
 {
     UNUSED_ARG(owner);
-    if (read_unit_reference(data, (unit **)&a->data.v, resolve_clone) <= 0) {
+    if (read_unit_reference(data, (unit **)&var->v, resolve_clone) <= 0) {
         return AT_READ_FAIL;
     }
     return AT_READ_OK;
@@ -2400,10 +2307,10 @@ static void * resolve_mage(int id, void *data) {
     return data;
 }
 
-static int read_magician(attrib * a, void *owner, struct gamedata *data)
+static int read_magician(variant *var, void *owner, struct gamedata *data)
 {
     UNUSED_ARG(owner);
-    if (read_unit_reference(data, (unit **)&a->data.v, resolve_mage) <= 0) {
+    if (read_unit_reference(data, (unit **)&var->v, resolve_mage) <= 0) {
         return AT_READ_FAIL;
     }
     return AT_READ_OK;
diff --git a/src/magic.h b/src/magic.h
index 403dafdc6..98d2dabe8 100644
--- a/src/magic.h
+++ b/src/magic.h
@@ -20,6 +20,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #define H_KRNL_MAGIC
 
 #include <kernel/types.h>
+#include <util/variant.h>
 #include <stdbool.h>
 
 #ifdef __cplusplus
@@ -191,13 +192,11 @@ extern "C" {
 
     void regenerate_aura(void);
 
-    extern struct attrib_type at_seenspell;
     extern struct attrib_type at_mage;
     extern struct attrib_type at_familiarmage;
     extern struct attrib_type at_familiar;
     extern struct attrib_type at_clonemage;
     extern struct attrib_type at_clone;
-    extern struct attrib_type at_reportspell;
     extern struct attrib_type at_icastle;
 
     void make_icastle(struct building *b, const struct building_type *btype, int timeout);
@@ -243,7 +242,6 @@ extern "C" {
     int u_hasspell(const struct unit *u, const struct spell *sp);
     /* pr�ft, ob der Spruch in der Spruchliste der Einheit steht. */
     void pick_random_spells(struct faction *f, int level, struct spellbook * book, int num_spells);
-    void show_new_spells(struct faction * f, int level, const struct spellbook *book);
     bool knowsspell(const struct region *r, const struct unit *u,
         const struct spell * sp);
     /* pr�ft, ob die Einheit diesen Spruch gerade beherrscht, dh
diff --git a/src/main.c b/src/main.c
index f50f65472..ae6d2158c 100644
--- a/src/main.c
+++ b/src/main.c
@@ -20,6 +20,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #include <platform.h>
 #endif
 
+#include <kernel/calendar.h>
 #include <kernel/config.h>
 #include <kernel/database.h>
 #include <kernel/messages.h>
diff --git a/src/market.c b/src/market.c
index fd62ae353..87be18f95 100644
--- a/src/market.c
+++ b/src/market.c
@@ -53,11 +53,11 @@ static unsigned int get_markets(region * r, unit ** results, size_t size)
     return n;
 }
 
-static void free_market(attrib * a)
+static void free_market(variant *var)
 {
-    item *items = (item *)a->data.v;
+    item *items = (item *)var->v;
     i_freeall(&items);
-    a->data.v = 0;
+    var->v = NULL;
 }
 
 attrib_type at_market = {
diff --git a/src/modules/autoseed.c b/src/modules/autoseed.c
index 17ea1084f..374b6379c 100644
--- a/src/modules/autoseed.c
+++ b/src/modules/autoseed.c
@@ -81,58 +81,6 @@ const terrain_type *random_terrain(const terrain_type * terrains[],
     return terrain;
 }
 
-static int count_demand(const region * r)
-{
-    struct demand *dmd;
-    int c = 0;
-    if (r->land) {
-        for (dmd = r->land->demands; dmd; dmd = dmd->next)
-            c++;
-    }
-    return c;
-}
-
-static int
-recurse_regions(region * r, region_list ** rlist,
-    bool(*fun) (const region * r))
-{
-    if (!fun(r))
-        return 0;
-    else {
-        int len = 0;
-        direction_t d;
-        region_list *rl = calloc(sizeof(region_list), 1);
-        rl->next = *rlist;
-        rl->data = r;
-        (*rlist) = rl;
-        fset(r, RF_MARK);
-        for (d = 0; d != MAXDIRECTIONS; ++d) {
-            region *nr = rconnect(r, d);
-            if (nr && !fval(nr, RF_MARK))
-                len += recurse_regions(nr, rlist, fun);
-        }
-        return len + 1;
-    }
-}
-
-static bool f_nolux(const region * r)
-{
-    return (r->land && count_demand(r) != get_maxluxuries());
-}
-
-int fix_all_demand(region *rd) {
-    region_list *rl, *rlist = NULL;
-    recurse_regions(rd, &rlist, f_nolux);
-    for (rl = rlist; rl; rl = rl->next) {
-        region *r = rl->data;
-        freset(r, RF_MARK);         /* undo recursive marker */
-        if (!fix_demand(r)) {
-            return -1;
-        }
-    }
-    return 0;
-}
-
 /* nach 150 Runden ist Neustart erlaubt */
 #define MINAGE_MULTI 150
 newfaction *read_newfactions(const char *filename)
@@ -859,9 +807,9 @@ static void smooth_island(region_list * island)
     region_list *rlist = NULL;
     for (rlist = island; rlist; rlist = rlist->next) {
         region *r = rlist->data;
-        int n, nland = 0;
 
         if (r->land) {
+            int n, nland = 0;
             get_neighbours(r, rn);
             for (n = 0; n != MAXDIRECTIONS && nland <= 1; ++n) {
                 if (rn[n]->land) {
diff --git a/src/modules/gmcmd.c b/src/modules/gmcmd.c
index c911e3de4..401879cd6 100644
--- a/src/modules/gmcmd.c
+++ b/src/modules/gmcmd.c
@@ -34,6 +34,7 @@
 /* util includes */
 #include <util/attrib.h>
 #include <util/gamedata.h>
+#include <util/macros.h>
 
 #include <storage.h>
 
@@ -43,17 +44,19 @@
 #include <limits.h>
 #include <assert.h>
 
-static int read_permissions(attrib * a, void *owner, struct gamedata *data)
+static int read_permissions(variant *var, void *owner, struct gamedata *data)
 {
-    assert(!a);
+    attrib *a;
+    UNUSED_ARG(var);
     read_attribs(data, &a, owner);
     a_remove(&a, a);
     return AT_READ_OK;
 }
 
-static int read_gmcreate(attrib * a, void *owner, struct gamedata *data)
+static int read_gmcreate(variant *var, void *owner, struct gamedata *data)
 {
     char zText[32];
+    UNUSED_ARG(var);
     READ_TOK(data->store, zText, sizeof(zText));
     return AT_READ_OK;
 }
diff --git a/src/modules/museum.c b/src/modules/museum.c
index 0f9fe9923..9daa623ef 100644
--- a/src/modules/museum.c
+++ b/src/modules/museum.c
@@ -59,29 +59,22 @@ attrib_type at_museumexit = {
     "museumexit", NULL, NULL, NULL, a_writeshorts, a_readshorts
 };
 
-static void a_initmuseumgivebackcookie(attrib * a)
+static void a_initmuseumgivebackcookie(variant *var)
 {
-    a->data.v = calloc(1, sizeof(museumgivebackcookie));
+    var->v = calloc(1, sizeof(museumgivebackcookie));
 }
 
-static void a_finalizemuseumgivebackcookie(attrib * a)
+static void a_writemuseumgivebackcookie(const variant *var,
+    const void *owner, struct storage *store)
 {
-    free(a->data.v);
-}
-
-static void
-a_writemuseumgivebackcookie(const attrib * a, const void *owner,
-struct storage *store)
-{
-    museumgivebackcookie *gbc = (museumgivebackcookie *)a->data.v;
+    museumgivebackcookie *gbc = (museumgivebackcookie *)var->v;
     WRITE_INT(store, gbc->warden_no);
     WRITE_INT(store, gbc->cookie);
 }
 
-static int
-a_readmuseumgivebackcookie(attrib * a, void *owner, gamedata *data)
+static int a_readmuseumgivebackcookie(variant *var, void *owner, gamedata *data)
 {
-    museumgivebackcookie *gbc = (museumgivebackcookie *)a->data.v;
+    museumgivebackcookie *gbc = (museumgivebackcookie *)var->v;
     READ_INT(data->store, &gbc->warden_no);
     READ_INT(data->store, &gbc->cookie);
     return AT_READ_OK;
@@ -90,7 +83,7 @@ a_readmuseumgivebackcookie(attrib * a, void *owner, gamedata *data)
 attrib_type at_museumgivebackcookie = {
     "museumgivebackcookie",
     a_initmuseumgivebackcookie,
-    a_finalizemuseumgivebackcookie,
+    a_free_voidptr,
     NULL,
     a_writemuseumgivebackcookie,
     a_readmuseumgivebackcookie
@@ -100,30 +93,30 @@ attrib_type at_warden = {
     "itemwarden", NULL, NULL, NULL, a_writeint, a_readint
 };
 
-static void a_initmuseumgiveback(attrib * a)
+static void a_initmuseumgiveback(variant *var)
 {
-    a->data.v = calloc(1, sizeof(museumgiveback));
+    var->v = calloc(1, sizeof(museumgiveback));
 }
 
-static void a_finalizemuseumgiveback(attrib * a)
+static void a_finalizemuseumgiveback(variant *var)
 {
-    museumgiveback *gb = (museumgiveback *)a->data.v;
+    museumgiveback *gb = (museumgiveback *)var->v;
     i_freeall(&gb->items);
-    free(a->data.v);
+    free(gb);
 }
 
 static void
-a_writemuseumgiveback(const attrib * a, const void *owner,
+a_writemuseumgiveback(const variant *var, const void *owner,
 struct storage *store)
 {
-    museumgiveback *gb = (museumgiveback *)a->data.v;
+    museumgiveback *gb = (museumgiveback *)var->v;
     WRITE_INT(store, gb->cookie);
     write_items(store, gb->items);
 }
 
-static int a_readmuseumgiveback(attrib * a, void *owner, struct gamedata *data)
+static int a_readmuseumgiveback(variant *var, void *owner, struct gamedata *data)
 {
-    museumgiveback *gb = (museumgiveback *)a->data.v;
+    museumgiveback *gb = (museumgiveback *)var->v;
     READ_INT(data->store, &gb->cookie);
     read_items(data->store, &gb->items);
     return AT_READ_OK;
@@ -308,7 +301,6 @@ order * ord)
     attrib *a;
     region *r;
     unit *warden = findunit(atoi36("mwar"));
-    int unit_cookie;
 
     UNUSED_ARG(amount);
 
@@ -323,11 +315,11 @@ order * ord)
     r = findregion(a->data.sa[0], a->data.sa[1]);
     assert(r);
     a_remove(&u->attribs, a);
-    /* �bergebene Gegenst�nde zur�ckgeben */
+    /* Übergebene Gegenstände zurückgeben */
 
     a = a_find(u->attribs, &at_museumgivebackcookie);
     if (a) {
-        unit_cookie = a->data.i;
+        int unit_cookie = a->data.i;
         a_remove(&u->attribs, a);
 
         for (a = a_find(warden->attribs, &at_museumgiveback);
diff --git a/src/monsters.c b/src/monsters.c
index d1979414d..99f32cedb 100644
--- a/src/monsters.c
+++ b/src/monsters.c
@@ -18,7 +18,6 @@
  */
 
 #include <platform.h>
-#include <kernel/config.h>
 
 #include "monsters.h"
 
@@ -29,32 +28,27 @@
 #include "laws.h"
 #include "keyword.h"
 #include "study.h"
-
-/* attributes includes */
-#include <attributes/targetregion.h>
-#include <attributes/hate.h>
-
-#include <spells/regioncurse.h>
+#include "move.h"
 
 /* kernel includes */
-#include <kernel/build.h>
-#include <kernel/building.h>
-#include <kernel/curse.h>
-#include <kernel/equipment.h>
-#include <kernel/faction.h>
-#include <kernel/item.h>
-#include <kernel/messages.h>
-#include <kernel/order.h>
-#include <kernel/pathfinder.h>
-#include <kernel/pool.h>
-#include <kernel/race.h>
-#include <kernel/region.h>
-#include <kernel/ship.h>
-#include <kernel/terrain.h>
-#include <kernel/terrainid.h>
-#include <kernel/unit.h>
-
-#include <move.h>
+#include "kernel/build.h"
+#include "kernel/building.h"
+#include "kernel/calendar.h"
+#include "kernel/config.h"
+#include "kernel/curse.h"
+#include "kernel/equipment.h"
+#include "kernel/faction.h"
+#include "kernel/item.h"
+#include "kernel/messages.h"
+#include "kernel/order.h"
+#include "kernel/pathfinder.h"
+#include "kernel/pool.h"
+#include "kernel/race.h"
+#include "kernel/region.h"
+#include "kernel/ship.h"
+#include "kernel/terrain.h"
+#include "kernel/terrainid.h"
+#include "kernel/unit.h"
 
 /* util includes */
 #include <util/attrib.h>
@@ -68,6 +62,12 @@
 #include <util/rng.h>
 #include <util/strings.h>
 
+/* attributes includes */
+#include <attributes/targetregion.h>
+#include <attributes/hate.h>
+
+#include <spells/regioncurse.h>
+
 #include <selist.h>
 
 /* libc includes */
@@ -615,11 +615,11 @@ static void recruit_dracoids(unit * dragon, int size)
     change_money(dragon, -un->number * 50);
     equip_unit(un, get_equipment("new_dracoid"));
 
-    setstatus(un, ST_FIGHT);
+    unit_setstatus(un, ST_FIGHT);
     for (weapon = un->items; weapon; weapon = weapon->next) {
         const weapon_type *wtype = weapon->type->rtype->wtype;
         if (wtype && wtype->flags & WTF_MISSILE) {
-            setstatus(un, ST_BEHIND);
+            unit_setstatus(un, ST_BEHIND);
             break;
         }
     }
diff --git a/src/morale.c b/src/morale.c
index a8a7cc9d9..6155426ac 100644
--- a/src/morale.c
+++ b/src/morale.c
@@ -20,17 +20,18 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #include <platform.h>
 #include "morale.h"
 
-#include <spells/regioncurse.h>
-
-#include <kernel/config.h>
-#include <kernel/curse.h>
-#include <kernel/region.h>
-#include <kernel/faction.h>
-#include <kernel/race.h>
-#include <kernel/building.h>
+#include "kernel/calendar.h"
+#include "kernel/config.h"
+#include "kernel/curse.h"
+#include "kernel/region.h"
+#include "kernel/faction.h"
+#include "kernel/race.h"
+#include "kernel/building.h"
 
 #include <util/rand.h>
 
+#include <spells/regioncurse.h>
+
 #include <assert.h>
 
 static double popularity(void)
diff --git a/src/move.c b/src/move.c
index 069c6ff7d..00a787cac 100644
--- a/src/move.c
+++ b/src/move.c
@@ -20,7 +20,28 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #ifdef _MSC_VER
 #include <platform.h>
 #endif
-#include <kernel/config.h>
+
+/* kernel includes */
+#include "kernel/ally.h"
+#include "kernel/build.h"
+#include "kernel/building.h"
+#include "kernel/calendar.h"
+#include "kernel/config.h"
+#include "kernel/connection.h"
+#include "kernel/curse.h"
+#include "kernel/faction.h"
+#include "kernel/item.h"
+#include "kernel/messages.h"
+#include "kernel/order.h"
+#include "kernel/plane.h"
+#include "kernel/race.h"
+#include "kernel/region.h"
+#include "kernel/render.h"
+#include "kernel/ship.h"
+#include "kernel/terrain.h"
+#include "kernel/terrainid.h"
+#include "kernel/unit.h"
+
 #include "move.h"
 #include "guard.h"
 #include "laws.h"
@@ -44,28 +65,8 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #include <attributes/stealth.h>
 #include <attributes/targetregion.h>
 
-/* kernel includes */
-#include <kernel/ally.h>
-#include <kernel/build.h>
-#include <kernel/building.h>
-#include <kernel/connection.h>
-#include <kernel/curse.h>
-#include <kernel/faction.h>
-#include <kernel/item.h>
-#include <kernel/messages.h>
-#include <kernel/order.h>
-#include <kernel/plane.h>
-#include <kernel/race.h>
-#include <kernel/region.h>
-#include <kernel/render.h>
-#include <kernel/ship.h>
-#include <kernel/terrain.h>
-#include <kernel/terrainid.h>
-#include <kernel/unit.h>
-
 #include "teleport.h"
 #include "direction.h"
-#include "calendar.h"
 #include "skill.h"
 
 /* util includes */
@@ -138,14 +139,9 @@ get_followers(unit * target, region * r, const region_list * route_end,
     }
 }
 
-static void shiptrail_init(attrib * a)
+static void shiptrail_init(variant *var)
 {
-    a->data.v = calloc(1, sizeof(traveldir));
-}
-
-static void shiptrail_finalize(attrib * a)
-{
-    free(a->data.v);
+    var->v = calloc(1, sizeof(traveldir));
 }
 
 static int shiptrail_age(attrib * a, void *owner)
@@ -157,11 +153,11 @@ static int shiptrail_age(attrib * a, void *owner)
     return (t->age > 0) ? AT_AGE_KEEP : AT_AGE_REMOVE;
 }
 
-static int shiptrail_read(attrib * a, void *owner, struct gamedata *data)
+static int shiptrail_read(variant *var, void *owner, struct gamedata *data)
 {
     storage *store = data->store;
     int n;
-    traveldir *t = (traveldir *)(a->data.v);
+    traveldir *t = (traveldir *)var->v;
 
     UNUSED_ARG(owner);
     READ_INT(store, &t->no);
@@ -172,9 +168,9 @@ static int shiptrail_read(attrib * a, void *owner, struct gamedata *data)
 }
 
 static void
-shiptrail_write(const attrib * a, const void *owner, struct storage *store)
+shiptrail_write(const variant *var, const void *owner, struct storage *store)
 {
-    traveldir *t = (traveldir *)(a->data.v);
+    traveldir *t = (traveldir *)var->v;
 
     UNUSED_ARG(owner);
     WRITE_INT(store, t->no);
@@ -185,7 +181,7 @@ shiptrail_write(const attrib * a, const void *owner, struct storage *store)
 attrib_type at_shiptrail = {
     "traveldir_new",
     shiptrail_init,
-    shiptrail_finalize,
+    a_free_voidptr,
     shiptrail_age,
     shiptrail_write,
     shiptrail_read
@@ -289,7 +285,7 @@ static int ridingcapacity(const unit * u)
 int walkingcapacity(const struct unit *u)
 {
     int n, people, pferde_fuer_wagen, horses;
-    int wagen_ohne_pferde, wagen_mit_pferden, wagen_mit_trollen;
+    int wagen_mit_pferden;
     int vehicles = 0, vcap = 0;
     int animals = 0, acap = 0;
     const struct resource_type *rhorse = rt_find("horse");
@@ -317,6 +313,7 @@ int walkingcapacity(const struct unit *u)
     n = wagen_mit_pferden * vcap;
 
     if (u_race(u) == get_race(RC_TROLL)) {
+        int wagen_ohne_pferde, wagen_mit_trollen;
         /* 4 Trolle ziehen einen Wagen. */
         /* Unbesetzte Wagen feststellen */
         wagen_ohne_pferde = vehicles - wagen_mit_pferden;
@@ -687,7 +684,6 @@ static bool is_freezing(const unit * u)
 
 int check_ship_allowed(struct ship *sh, const region * r)
 {
-    int c = 0;
     const building_type *bt_harbour = bt_find("harbour");
 
     if (sh->region && r_insectstalled(r)) {
@@ -713,6 +709,7 @@ int check_ship_allowed(struct ship *sh, const region * r)
         return SA_COAST;
     }
     if (sh->type->coasts) {
+        int c;
         for (c = 0; sh->type->coasts[c] != NULL; ++c) {
             if (sh->type->coasts[c] == r->terrain) {
                 return SA_COAST;
diff --git a/src/names.c b/src/names.c
index d8abc077b..1bb6014a6 100644
--- a/src/names.c
+++ b/src/names.c
@@ -350,7 +350,6 @@ static void dracoid_name(unit * u)
 {
     static char name[NAMESIZE + 1];
     int mid_syllabels;
-    size_t sz;
 
     /* ignore u */
     UNUSED_ARG(u);
@@ -358,14 +357,14 @@ static void dracoid_name(unit * u)
 
     mid_syllabels = rng_int() % 4;
 
-    sz = str_strlcpy(name, drac_pre[rng_int() % DRAC_PRE], sizeof(name));
+    str_strlcpy(name, drac_pre[rng_int() % DRAC_PRE], sizeof(name));
     while (mid_syllabels > 0) {
         mid_syllabels--;
         if (rng_int() % 10 < 4)
             str_strlcat(name, "'", sizeof(name));
-        sz += str_strlcat(name, drac_mid[rng_int() % DRAC_MID], sizeof(name));
+        str_strlcat(name, drac_mid[rng_int() % DRAC_MID], sizeof(name));
     }
-    sz += str_strlcat(name, drac_suf[rng_int() % DRAC_SUF], sizeof(name));
+    str_strlcat(name, drac_suf[rng_int() % DRAC_SUF], sizeof(name));
     unit_setname(u, name);
 }
 
@@ -392,13 +391,13 @@ const char *abkz(const char *s, char *buf, size_t buflen, size_t maxchars)
     while (*p != 0) {
 
         result = unicode_utf8_to_ucs4(&ucs, p, &size);
-        assert(result == 0 || "damnit, we're not handling invalid input here!");
+        assert(result == 0 || !"damnit, we're not handling invalid input here!");
 
         /* Leerzeichen �berspringen */
         while (*p != 0 && !iswalnum((wint_t)ucs)) {
             p += size;
             result = unicode_utf8_to_ucs4(&ucs, p, &size);
-            assert(result == 0 || "damnit, we're not handling invalid input here!");
+            assert(result == 0 || !"damnit, we're not handling invalid input here!");
         }
 
         /* Counter erh�hen */
@@ -409,7 +408,7 @@ const char *abkz(const char *s, char *buf, size_t buflen, size_t maxchars)
         while (*p != 0 && iswalnum((wint_t)ucs)) {
             p += size;
             result = unicode_utf8_to_ucs4(&ucs, p, &size);
-            assert(result == 0 || "damnit, we're not handling invalid input here!");
+            assert(result == 0 || !"damnit, we're not handling invalid input here!");
         }
     }
 
@@ -423,7 +422,7 @@ const char *abkz(const char *s, char *buf, size_t buflen, size_t maxchars)
     bufp = buf;
 
     result = unicode_utf8_to_ucs4(&ucs, p, &size);
-    assert(result == 0 || "damnit, we're not handling invalid input here!");
+    assert(result == 0 || !"damnit, we're not handling invalid input here!");
 
     while (*p != 0 && c < maxchars) {
         /* Leerzeichen �berspringen */
@@ -431,7 +430,7 @@ const char *abkz(const char *s, char *buf, size_t buflen, size_t maxchars)
         while (*p != 0 && !iswalnum((wint_t)ucs)) {
             p += size;
             result = unicode_utf8_to_ucs4(&ucs, p, &size);
-            assert(result == 0 || "damnit, we're not handling invalid input here!");
+            assert(result == 0 || !"damnit, we're not handling invalid input here!");
         }
 
         /* alnums �bertragen */
@@ -443,7 +442,7 @@ const char *abkz(const char *s, char *buf, size_t buflen, size_t maxchars)
             ++c;
 
             result = unicode_utf8_to_ucs4(&ucs, p, &size);
-            assert(result == 0 || "damnit, we're not handling invalid input here!");
+            assert(result == 0 || !"damnit, we're not handling invalid input here!");
         }
 
         /* Bis zum n�chsten Leerzeichen */
@@ -451,7 +450,7 @@ const char *abkz(const char *s, char *buf, size_t buflen, size_t maxchars)
         while (c < maxchars && *p != 0 && iswalnum((wint_t)ucs)) {
             p += size;
             result = unicode_utf8_to_ucs4(&ucs, p, &size);
-            assert(result == 0 || "damnit, we're not handling invalid input here!");
+            assert(result == 0 || !"damnit, we're not handling invalid input here!");
         }
     }
 
diff --git a/src/orderfile.c b/src/orderfile.c
index a82b599a0..ed4860d77 100644
--- a/src/orderfile.c
+++ b/src/orderfile.c
@@ -2,10 +2,11 @@
 #include <kernel/config.h>
 #include "orderfile.h"
 
-#include <kernel/faction.h>
-#include <kernel/unit.h>
-#include <kernel/order.h>
-#include <kernel/messages.h>
+#include "kernel/calendar.h"
+#include "kernel/faction.h"
+#include "kernel/messages.h"
+#include "kernel/order.h"
+#include "kernel/unit.h"
 
 #include <util/base36.h>
 #include <util/message.h>
diff --git a/src/orderfile.test.c b/src/orderfile.test.c
index 500c68fdf..f5d4997ae 100644
--- a/src/orderfile.test.c
+++ b/src/orderfile.test.c
@@ -3,6 +3,7 @@
 
 #include "orderfile.h"
 
+#include <kernel/calendar.h>
 #include <kernel/faction.h>
 #include <util/message.h>
 
diff --git a/src/piracy.c b/src/piracy.c
index 888a7e53a..46977c3d8 100644
--- a/src/piracy.c
+++ b/src/piracy.c
@@ -34,20 +34,15 @@ typedef struct piracy_data {
     direction_t dir;
 } piracy_data;
 
-static void piracy_init(struct attrib *a)
+static void piracy_init(variant *var)
 {
-    a->data.v = calloc(1, sizeof(piracy_data));
-}
-
-static void piracy_done(struct attrib *a)
-{
-    free(a->data.v);
+    var->v = calloc(1, sizeof(piracy_data));
 }
 
 static attrib_type at_piracy_direction = {
     "piracy_direction",
     piracy_init,
-    piracy_done,
+    a_free_voidptr,
     DEFAULT_AGE,
     NO_WRITE,
     NO_READ
@@ -127,7 +122,6 @@ void piracy_cmd(unit * u)
         const faction *target;
         int value;
     } aff[MAXDIRECTIONS];
-    int saff = 0;
     int *il;
 
     assert(u->thisorder);
@@ -144,6 +138,7 @@ void piracy_cmd(unit * u)
     /* Wenn nicht, sehen wir, ob wir ein Ziel finden. */
 
     if (target_dir == NODIRECTION) {
+        int saff = 0;
         direction_t dir;
         /* Einheit ist also Kapit�n. Jetzt gucken, in wievielen
         * Nachbarregionen potentielle Opfer sind. */
diff --git a/src/prefix.c b/src/prefix.c
index f40a08091..84c026625 100644
--- a/src/prefix.c
+++ b/src/prefix.c
@@ -37,8 +37,8 @@ int add_raceprefix(const char *prefix)
 }
 
 void free_prefixes(void) {
-    int i;
     if (race_prefixes) {
+        int i;
         for (i = 0; race_prefixes[i]; ++i) {
             free(race_prefixes[i]);
         }
diff --git a/src/races/zombies.c b/src/races/zombies.c
index 74bf53a76..de3d81972 100644
--- a/src/races/zombies.c
+++ b/src/races/zombies.c
@@ -43,7 +43,6 @@ void make_undead_unit(unit * u)
 void age_undead(unit * u)
 {
     region *r = u->region;
-    int n = 0;
 
     /* untote, die einer partei angehoeren, koennen sich
      * absplitten, anstatt sich zu vermehren. monster
@@ -51,10 +50,9 @@ void age_undead(unit * u)
 
     if (u->number > UNDEAD_MIN && !is_monsters(u->faction)
         && rng_int() % 100 < UNDEAD_BREAKUP) {
-        int m;
+        int m, n = 0;
         unit *u2;
 
-        n = 0;
         for (m = u->number; m; m--) {
             if (rng_int() % 100 < UNDEAD_BREAKUP_FRACTION)
                 ++n;
diff --git a/src/report.c b/src/report.c
index 6543b153b..44b1bd6ad 100644
--- a/src/report.c
+++ b/src/report.c
@@ -39,10 +39,10 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #include <attributes/overrideroads.h>
 #include <attributes/otherfaction.h>
 #include <attributes/reduceproduction.h>
+#include <attributes/seenspell.h>
 
 /* gamecode includes */
 #include "alchemy.h"
-#include "calendar.h"
 #include "economy.h"
 #include "move.h"
 #include "upkeep.h"
@@ -50,30 +50,31 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #include "teleport.h"
 
 /* kernel includes */
-#include <kernel/ally.h>
-#include <kernel/connection.h>
-#include <kernel/build.h>
-#include <kernel/building.h>
-#include <kernel/curse.h>
-#include <kernel/faction.h>
-#include <kernel/group.h>
-#include <kernel/item.h>
-#include <kernel/messages.h>
-#include <kernel/objtypes.h>
-#include <kernel/order.h>
-#include <kernel/plane.h>
-#include <kernel/pool.h>
-#include <kernel/race.h>
-#include <kernel/region.h>
-#include <kernel/render.h>
-#include <kernel/resources.h>
-#include <kernel/ship.h>
-#include <kernel/spell.h>
-#include <kernel/spellbook.h>
-#include <kernel/terrain.h>
-#include <kernel/terrainid.h>
-#include <kernel/unit.h>
-#include <kernel/alliance.h>
+#include "kernel/ally.h"
+#include "kernel/calendar.h"
+#include "kernel/connection.h"
+#include "kernel/build.h"
+#include "kernel/building.h"
+#include "kernel/curse.h"
+#include "kernel/faction.h"
+#include "kernel/group.h"
+#include "kernel/item.h"
+#include "kernel/messages.h"
+#include "kernel/objtypes.h"
+#include "kernel/order.h"
+#include "kernel/plane.h"
+#include "kernel/pool.h"
+#include "kernel/race.h"
+#include "kernel/region.h"
+#include "kernel/render.h"
+#include "kernel/resources.h"
+#include "kernel/ship.h"
+#include "kernel/spell.h"
+#include "kernel/spellbook.h"
+#include "kernel/terrain.h"
+#include "kernel/terrainid.h"
+#include "kernel/unit.h"
+#include "kernel/alliance.h"
 
 /* util includes */
 #include <util/attrib.h>
@@ -303,7 +304,6 @@ void nr_spell_syntax(struct stream *out, spellbook_entry * sbe, const struct loc
         };
         starget *targetp;
         char cp = *params++;
-        int i, maxparam = 0;
         const char *locp;
         const char *syntaxp = sp->syntax;
 
@@ -358,6 +358,7 @@ void nr_spell_syntax(struct stream *out, spellbook_entry * sbe, const struct loc
                 WARN_STATIC_BUFFER();
         }
         else if (cp == 'k') {
+            int i, maxparam = 0;
             bool multi = false;
             if (params && *params == 'c') {
                 /* skip over a potential id */
diff --git a/src/reports.c b/src/reports.c
index 602edb83c..69e7a3555 100644
--- a/src/reports.c
+++ b/src/reports.c
@@ -21,7 +21,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #include "reports.h"
 
 #include "battle.h"
-#include "calendar.h"
+#include "kernel/calendar.h"
 #include "guard.h"
 #include "laws.h"
 #include "spells.h"
@@ -575,7 +575,6 @@ report_resources(const region * r, resource_report * result, int size,
     if (see_unit) {
         rawmaterial *res = r->resources;
         while (res) {
-            int maxskill = 0;
             const item_type *itype = resource2item(res->rtype);
             int minskill = itype->construction->minskill;
             skill_t skill = itype->construction->skill;
@@ -588,6 +587,7 @@ report_resources(const region * r, resource_report * result, int size,
             }
             else {
                 const unit *u;
+                int maxskill = 0;
                 for (u = r->units; visible != res->amount && u != NULL; u = u->next) {
                     if (u->faction == viewer) {
                         int s = effskill(u, skill, 0);
@@ -923,7 +923,7 @@ spskill(char *buffer, size_t size, const struct locale * lang,
     const struct unit * u, struct skill * sv, int *dh, int days)
 {
     char *bufp = buffer;
-    int i, effsk;
+    int effsk;
 
     if (!u->number)
         return 0;
@@ -953,7 +953,7 @@ spskill(char *buffer, size_t size, const struct locale * lang,
     }
 
     if (sv->id == SK_STEALTH && fval(u, UFL_STEALTH)) {
-        i = u_geteffstealth(u);
+        int i = u_geteffstealth(u);
         if (i >= 0) {
             if (wrptr(&bufp, &size, snprintf(bufp, size, "%d/", i)) != 0)
                 WARN_STATIC_BUFFER();
@@ -2113,11 +2113,17 @@ static void eval_resource(struct opstack **stack, const void *userdata)
     const struct locale *lang = report ? report->locale : default_locale;
     int j = opop(stack).i;
     const struct resource_type *res = (const struct resource_type *)opop(stack).v;
-    const char *c = LOC(lang, resourcename(res, j != 1));
-    size_t len = strlen(c);
+    const char *name = resourcename(res, j != 1);
+    const char *c = LOC(lang, name);
     variant var;
+    if (c) {
+        size_t len = strlen(c);
 
-    var.v = strcpy(balloc(len + 1), c);
+        var.v = strcpy(balloc(len + 1), c);
+    } else {
+        log_error("missing translation for %s in eval_resource", name);
+        var.v = NULL;
+    }
     opush(stack, var);
 }
 
@@ -2127,11 +2133,17 @@ static void eval_race(struct opstack **stack, const void *userdata)
     const struct locale *lang = report ? report->locale : default_locale;
     int j = opop(stack).i;
     const race *r = (const race *)opop(stack).v;
-    const char *c = LOC(lang, rc_name_s(r, (j == 1) ? NAME_SINGULAR : NAME_PLURAL));
-    size_t len = strlen(c);
+    const char *name = rc_name_s(r, (j == 1) ? NAME_SINGULAR : NAME_PLURAL);
+    const char *c = LOC(lang, name);
     variant var;
-
-    var.v = strcpy(balloc(len + 1), c);
+    if (c) {
+        size_t len = strlen(c);
+        var.v = strcpy(balloc(len + 1), c);
+    }
+    else {
+        log_error("missing translation for %s in eval_race", name);
+        var.v = NULL;
+    }
     opush(stack, var);
 }
 
@@ -2276,7 +2288,6 @@ static void eval_trail(struct opstack **stack, const void *userdata)
 {                               /* order -> string */
     const faction *report = (const faction *)userdata;
     const struct locale *lang = report ? report->locale : default_locale;
-    int i, end = 0, begin = 0;
     const arg_regions *aregs = (const arg_regions *)opop(stack).v;
     char buf[512];
     size_t size = sizeof(buf) - 1;
@@ -2288,6 +2299,7 @@ static void eval_trail(struct opstack **stack, const void *userdata)
 #endif
 
     if (aregs != NULL) {
+        int i, end = 0, begin = 0;
         end = aregs->nregions;
         for (i = begin; i < end; ++i) {
             region *r = aregs->regions[i];
diff --git a/src/reports.test.c b/src/reports.test.c
index ca0f98f57..cdc09c83c 100644
--- a/src/reports.test.c
+++ b/src/reports.test.c
@@ -1,7 +1,7 @@
 #include <platform.h>
 #include "reports.h"
 
-#include "calendar.h"
+#include "kernel/calendar.h"
 #include "keyword.h"
 #include "lighthouse.h"
 #include "laws.h"
diff --git a/src/spells.c b/src/spells.c
index 8334d19c0..8612c92ef 100644
--- a/src/spells.c
+++ b/src/spells.c
@@ -518,7 +518,7 @@ static unit * make_familiar(unit * mage, region *r, const race *rc, const char *
     unit *fam;
 
     fam = create_unit(r, mage->faction, 1, rc, 0, name, mage);
-    setstatus(fam, ST_FLEE);
+    unit_setstatus(fam, ST_FLEE);
     fset(fam, UFL_LOCKED);
 
     /* triggers: */
@@ -537,7 +537,6 @@ static int sp_summon_familiar(castorder * co)
     unit *mage = co->magician.u;
     int cast_level = co->level;
     const race *rc;
-    int dh;
     message *msg;
     char zText[2048];
 
@@ -553,7 +552,8 @@ static int sp_summon_familiar(castorder * co)
 
     if (fval(rc, RCF_SWIM) && !fval(rc, RCF_WALK)) {
         int coasts = is_coastregion(r);
-        int dir;
+        int dir, dh;
+
         if (coasts == 0) {
             cmistake(mage, co->order, 229, MSG_MAGIC);
             return 0;
@@ -2161,7 +2161,7 @@ static int sp_ironkeeper(castorder * co)
         create_unit(r, mage->faction, 1, get_race(RC_IRONKEEPER), 0, NULL, mage);
 
     /*keeper->age = cast_level + 2; */
-    setstatus(keeper, ST_AVOID);  /* kaempft nicht */
+    unit_setstatus(keeper, ST_AVOID);  /* kaempft nicht */
     setguard(keeper, true);
     fset(keeper, UFL_ISNEW);
     /* Parteitarnen, damit man nicht sofort wei�, wer dahinter steckt */
@@ -2857,12 +2857,12 @@ static curse *mk_deathcloud(unit * mage, region * r, double force, int duration)
     return c;
 }
 
-static int dc_read_compat(struct attrib *a, void *target, gamedata *data)
+static int dc_read_compat(variant *var, void *target, gamedata *data)
 /* return AT_READ_OK on success, AT_READ_FAIL if attrib needs removal */
 {
     struct storage *store = data->store;
 
-    UNUSED_ARG(a);
+    UNUSED_ARG(var);
     UNUSED_ARG(target);
     READ_INT(store, NULL);
     READ_FLT(store, NULL);
@@ -4630,7 +4630,7 @@ int sp_clonecopy(castorder * co)
     clone =
         create_unit(target_region, mage->faction, 1, get_race(RC_CLONE), 0, name,
             mage);
-    setstatus(clone, ST_FLEE);
+    unit_setstatus(clone, ST_FLEE);
     fset(clone, UFL_LOCKED);
 
     create_newclone(mage, clone);
diff --git a/src/spells/borders.c b/src/spells/borders.c
index 9ded973c8..c30726641 100644
--- a/src/spells/borders.c
+++ b/src/spells/borders.c
@@ -31,13 +31,13 @@ typedef struct wallcurse {
     connection *wall;
 } wallcurse;
 
-static int cw_read_depr(attrib * a, void *target, gamedata *data)
+static int cw_read_depr(variant *var, void *target, gamedata *data)
 {
     storage *store = data->store;
 
-    curse_init(a);
-    curse_read(a, store, target);
-    curse_done(a);
+    curse_init(var);
+    curse_read(var, store, target);
+    curse_done(var);
     READ_INT(store, NULL);
     return AT_READ_DEPR;
 }
diff --git a/src/spells/combatspells.c b/src/spells/combatspells.c
index ce737f570..4f7974018 100644
--- a/src/spells/combatspells.c
+++ b/src/spells/combatspells.c
@@ -9,7 +9,9 @@
  This program may not be used, modified or distributed
  without prior permission by the authors of Eressea.
  */
+#ifdef _MSC_VER
 #include <platform.h>
+#endif
 #include "combatspells.h"
 
 #include <spells/buildingcurse.h>
@@ -45,6 +47,7 @@
 
 /* libc includes */
 #include <assert.h>
+#include <math.h>
 #include <stdlib.h>
 #include <string.h>
 
@@ -131,8 +134,7 @@ int damage_spell(struct castorder * co, int dmg, int strength)
 
     enemies = count_enemies(b, fi, FIGHT_ROW, BEHIND_ROW - 1, SELECT_ADVANCE);
     if (enemies == 0) {
-        message *m =
-            msg_message("spell_out_of_range", "mage spell", fi->unit, sp);
+        m = msg_message("spell_out_of_range", "mage spell", fi->unit, sp);
         message_all(b, m);
         msg_release(m);
         return 0;
@@ -171,8 +173,7 @@ int sp_petrify(struct castorder * co)
 
     enemies = count_enemies(b, fi, FIGHT_ROW, BEHIND_ROW, SELECT_ADVANCE);
     if (!enemies) {
-        message *m =
-            msg_message("spell_out_of_range", "mage spell", fi->unit, sp);
+        m = msg_message("spell_out_of_range", "mage spell", fi->unit, sp);
         message_all(b, m);
         msg_release(m);
         return 0;
@@ -218,8 +219,7 @@ int sp_stun(struct castorder * co)
 
     enemies = count_enemies(b, fi, FIGHT_ROW, BEHIND_ROW, SELECT_ADVANCE);
     if (!enemies) {
-        message *m =
-            msg_message("spell_out_of_range", "mage spell", fi->unit, sp);
+        m = msg_message("spell_out_of_range", "mage spell", fi->unit, sp);
         message_all(b, m);
         msg_release(m);
         return 0;
@@ -298,7 +298,8 @@ int sp_combatrosthauch(struct castorder * co)
 
         for (w = 0; df->weapons[w].type != NULL; ++w) {
             weapon *wp = df->weapons;
-            int n = MIN(force, wp->used);
+            int n = force;
+            if (n < wp->used) n = wp->used;
             if (n) {
                 requirement *mat = wp->type->itype->construction->materials;
                 bool iron = false;
@@ -682,8 +683,7 @@ int sp_immolation(struct castorder * co)
     force = 99999;
 
     if (!count_enemies(b, fi, FIGHT_ROW, AVOID_ROW, SELECT_ADVANCE | SELECT_FIND)) {
-        message *m =
-            msg_message("spell_out_of_range", "mage spell", fi->unit, sp);
+        m = msg_message("spell_out_of_range", "mage spell", fi->unit, sp);
         message_all(b, m);
         msg_release(m);
         return 0;
@@ -731,7 +731,7 @@ static fighter *summon_allies(const fighter *fi, const race *rc, int number) {
     unit *u =
         create_unit(r, mage->faction, number, rc, 0, NULL, mage);
     leave(u, true);
-    setstatus(u, ST_FIGHT);
+    unit_setstatus(u, ST_FIGHT);
     
     u->hp = u->number * unit_max_hp(u);
     
@@ -791,13 +791,13 @@ int sp_shadowknights(struct castorder * co)
     region *r = b->region;
     unit *mage = fi->unit;
     attrib *a;
-    int force = MAX(1, (int)get_force(power, 3));
+    int force = (int)fmax(1, get_force(power, 3));
     message *msg;
 
     u =
         create_unit(r, mage->faction, force, get_race(RC_SHADOWKNIGHT), 0, NULL,
         mage);
-    setstatus(u, ST_FIGHT);
+    unit_setstatus(u, ST_FIGHT);
 
     u->hp = u->number * unit_max_hp(u);
 
@@ -890,7 +890,6 @@ int sp_chaosrow(struct castorder * co)
             continue;
         if (power <= 0.0)
             break;
-        /* force sollte wegen des MAX(0,x) nicht unter 0 fallen k�nnen */
 
         if (is_magic_resistant(mage, df->unit, 0))
             continue;
@@ -925,7 +924,7 @@ int sp_chaosrow(struct castorder * co)
             }
             k += df->alive;
         }
-        power = MAX(0, power - n);
+        power = fmax(0, power - n);
     }
     selist_free(fgs);
 
@@ -1020,7 +1019,8 @@ int sp_hero(struct castorder * co)
     message *m;
 
     df_bonus = (int)(power / 5);
-    force = MAX(1, lovar(get_force(power, 4)));
+    force = lovar(get_force(power, 4));
+    if (force < 1) force = 1;
 
     allies =
         count_allies(fi->side, FIGHT_ROW, BEHIND_ROW, SELECT_ADVANCE, ALLY_ANY);
@@ -1065,7 +1065,8 @@ int sp_berserk(struct castorder * co)
     int targets = 0;
     message *m;
 
-    at_bonus = MAX(1, level / 3);
+    at_bonus = level / 3;
+    if (at_bonus < 1) at_bonus = 1;
     df_malus = 2;
     force = (int)get_force(power, 2);
 
@@ -1114,14 +1115,14 @@ int sp_frighten(struct castorder * co)
     int targets = 0;
     message *m;
 
-    at_malus = MAX(1, level - 4);
+    at_malus = level - 4;
+    if (at_malus < 1) at_malus = 1;
     df_malus = 2;
     force = (int)get_force(power, 2);
 
     enemies = count_enemies(b, fi, FIGHT_ROW, BEHIND_ROW - 1, SELECT_ADVANCE);
     if (!enemies) {
-        message *m =
-            msg_message("spell_out_of_range", "mage spell", fi->unit, sp);
+        m = msg_message("spell_out_of_range", "mage spell", fi->unit, sp);
         message_all(b, m);
         msg_release(m);
         return 0;
@@ -1170,8 +1171,7 @@ int sp_tiredsoldiers(struct castorder * co)
 
     if (!count_enemies(b, fi, FIGHT_ROW, BEHIND_ROW,
         SELECT_ADVANCE | SELECT_FIND)) {
-        message *m =
-            msg_message("spell_out_of_range", "mage spell", fi->unit, sp);
+        m = msg_message("spell_out_of_range", "mage spell", fi->unit, sp);
         message_all(b, m);
         msg_release(m);
         return 0;
@@ -1280,7 +1280,7 @@ int sp_appeasement(struct castorder * co)
     }
     /* und bewachen nicht */
     setguard(mage, false);
-    setstatus(mage, ST_FLEE);
+    unit_setstatus(mage, ST_FLEE);
 
     /* wir tun so, als w�re die Person geflohen */
     fi->flags |= FIG_NOLOOT;
@@ -1367,7 +1367,8 @@ int sp_fumbleshield(struct castorder * co)
 
     /* der erste Zauber schl�gt mit 100% fehl  */
     duration = 100;
-    effect = MAX(1, 25 - level);
+    effect = 25 - level;
+    if (effect < 1) effect = 1;
 
     do_meffect(fi, SHIELD_BLOCK, effect, duration);
     return level;
@@ -1403,7 +1404,7 @@ int sp_reanimate(struct castorder * co)
     unit *mage = fi->unit;
     int healable, j = 0;
     double c = 0.50 + 0.02 * power;
-    double k = EFFECT_HEALING_SPELL * power;
+    int k = (int)(EFFECT_HEALING_SPELL * power);
     bool use_item = has_ao_healing(mage);
     message *msg;
 
@@ -1413,7 +1414,9 @@ int sp_reanimate(struct castorder * co)
     }
 
     healable = count_healable(b, fi);
-    healable = (int)MIN(k, healable);
+    if (healable > k) {
+        healable = k;
+    }
     while (healable--) {
         fighter *tf = select_corpse(b, fi);
         if (tf != NULL && tf->side->casualties > 0
@@ -1466,7 +1469,7 @@ int sp_keeploot(struct castorder * co)
     message_all(b, m);
     msg_release(m);
 
-    b->keeploot = (int)MAX(25, b->keeploot + 5 * power);
+    b->keeploot = (int)fmax(25, b->keeploot + 5 * power);
 
     return level;
 }
@@ -1497,10 +1500,14 @@ static int heal_fighters(selist * fgs, int *power, bool heal_monsters)
                     ++wound;
 
                 if (wound > 0 && wound < hp) {
-                    int heal = MIN(healhp, wound);
+                    int heal = healhp;
+                    if (heal > wound) {
+                        heal = wound;
+                    }
                     assert(heal >= 0);
                     df->person[n].hp += heal;
-                    healhp = MAX(0, healhp - heal);
+                    healhp -= heal;
+                    if (healhp < 0) healhp = 0;
                     ++healed;
                     if (healhp <= 0)
                         break;
@@ -1617,7 +1624,7 @@ int sp_undeadhero(struct castorder * co)
             else {
                 unit_setinfo(u, NULL);
             }
-            setstatus(u, du->status);
+            unit_setstatus(u, du->status);
             setguard(u, false);
             for (ilist = &du->items; *ilist;) {
                 item *itm = *ilist;
@@ -1653,7 +1660,9 @@ int sp_undeadhero(struct castorder * co)
     }
     selist_free(fgs);
 
-    level = MIN(level, undead);
+    if (level > undead) {
+        level = undead;
+    }
     if (undead == 0) {
         msg =
             msg_message("summonundead_effect_0", "mage region", mage, mage->region);
diff --git a/src/study.c b/src/study.c
index 09f228f45..46da90b74 100644
--- a/src/study.c
+++ b/src/study.c
@@ -21,11 +21,13 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #endif
 #include <kernel/config.h>
 #include "study.h"
+
 #include "laws.h"
 #include "move.h"
 #include "monsters.h"
 #include "alchemy.h"
 #include "academy.h"
+#include "kernel/calendar.h"
 
 #include <spells/regioncurse.h>
 
@@ -173,16 +175,16 @@ int study_cost(struct unit *u, skill_t sk)
 
 /* ------------------------------------------------------------- */
 
-static void init_learning(struct attrib *a)
+static void init_learning(variant *var)
 {
-    a->data.v = calloc(sizeof(teaching_info), 1);
+    var->v = calloc(sizeof(teaching_info), 1);
 }
 
-static void done_learning(struct attrib *a)
+static void done_learning(variant *var)
 {
-    teaching_info *teach = (teaching_info *)a->data.v;
+    teaching_info *teach = (teaching_info *)var->v;
     selist_free(teach->teachers);
-    free(a->data.v);
+    free(teach);
 }
 
 const attrib_type at_learning = {
@@ -475,10 +477,10 @@ typedef enum study_rule_t {
 static double study_speedup(unit * u, skill_t s, study_rule_t rule)
 {
 #define MINTURN 16
-    double learnweeks = 0;
-    int i;
     if (turn > MINTURN) {
         if (rule == STUDY_FASTER) {
+            double learnweeks = 0;
+            int i;
             for (i = 0; i != u->skill_size; ++i) {
                 skill *sv = u->skills + i;
                 if (sv->id == s) {
@@ -491,6 +493,8 @@ static double study_speedup(unit * u, skill_t s, study_rule_t rule)
             return 2.0; /* If the skill was not found it is the first study. */
         }
         if (rule == STUDY_AUTOTEACH) {
+            double learnweeks = 0;
+            int i;
             for (i = 0; i != u->skill_size; ++i) {
                 skill *sv = u->skills + i;
                 learnweeks += (sv->level * (sv->level + 1) / 2.0);
@@ -547,7 +551,6 @@ int study_cmd(unit * u, order * ord)
 {
     region *r = u->region;
     int p;
-    magic_t mtyp;
     int l;
     int studycost, days;
     double multi = 1.0;
@@ -621,6 +624,7 @@ int study_cmd(unit * u, order * ord)
     }
 
     if (sk == SK_MAGIC) {
+        magic_t mtyp;
         if (u->number > 1) {
             cmistake(u, ord, 106, MSG_MAGIC);
             return -1;
diff --git a/src/summary.c b/src/summary.c
index 79ffd1b6d..64bb055b5 100644
--- a/src/summary.c
+++ b/src/summary.c
@@ -16,7 +16,7 @@
 #include "summary.h"
 #include "laws.h"
 #include "monsters.h"
-#include "calendar.h"
+#include "kernel/calendar.h"
 
 #include <kernel/alliance.h>
 #include <kernel/faction.h>
@@ -178,9 +178,14 @@ static int count_umlaut(const char *s)
         ucs4_t ucs = *cp;
         if (ucs & 0x80) {
             size_t size;
-            ++result;
-            unicode_utf8_to_ucs4(&ucs, cp, &size);
+            int err;
+            err = unicode_utf8_to_ucs4(&ucs, cp, &size);
+            if (err != 0) {
+                log_error("illegal utf8 encoding %s at %s", s, cp);
+                return result;
+            }
             cp += size;
+            ++result;
         }
     }
     return result;
diff --git a/src/summary.test.c b/src/summary.test.c
index 5df4849c3..7b7df93b6 100644
--- a/src/summary.test.c
+++ b/src/summary.test.c
@@ -1,7 +1,7 @@
 #include <platform.h>
 
 #include "summary.h"
-#include "calendar.h"
+#include "kernel/calendar.h"
 
 #include <CuTest.h>
 #include "tests.h"
diff --git a/src/tests.c b/src/tests.c
index 18ecdef34..4b764b23f 100644
--- a/src/tests.c
+++ b/src/tests.c
@@ -3,7 +3,7 @@
 #include "keyword.h"
 #include "prefix.h"
 #include "reports.h"
-#include "calendar.h"
+#include "kernel/calendar.h"
 #include "vortex.h"
 
 #include <kernel/config.h>
diff --git a/src/travelthru.c b/src/travelthru.c
index 835d05024..fa6293f53 100644
--- a/src/travelthru.c
+++ b/src/travelthru.c
@@ -37,9 +37,8 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #include <assert.h>
 #include <string.h>
 
-static void travel_done(attrib *a) {
-    selist *ql = (selist *)a->data.v;
-    selist_free(ql);
+static void travel_done(variant *var) {
+    selist_free((selist *)var->v);
 }
 
 /*********************/
diff --git a/src/triggers/changerace.c b/src/triggers/changerace.c
index 5ab56b346..0f644c47b 100644
--- a/src/triggers/changerace.c
+++ b/src/triggers/changerace.c
@@ -111,7 +111,7 @@ trigger *trigger_changerace(struct unit * u, const struct race * prace,
     trigger *t = t_new(&tt_changerace);
     changerace_data *td = (changerace_data *)t->data.v;
 
-    assert(u_race(u) == u_irace(u) || "!changerace-triggers cannot stack!");
+    assert(u_race(u) == u_irace(u) || !"changerace-triggers cannot stack!");
     td->u = u;
     td->race = prace;
     td->irace = irace;
diff --git a/src/util/attrib.c b/src/util/attrib.c
index 8a90f3bca..9530e5154 100644
--- a/src/util/attrib.c
+++ b/src/util/attrib.c
@@ -21,6 +21,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 
 #include "gamedata.h"
 #include "log.h"
+#include "variant.h"
 #include "storage.h"
 #include "strings.h"
 
@@ -41,12 +42,13 @@ int read_attribs(gamedata *data, attrib **alist, void *owner) {
     }
     if (result == AT_READ_DEPR) {
         /* handle deprecated attributes */
-        attrib *a = *alist;
-        while (a) {
+        attrib **ap = alist;
+        while (*ap) {
+            attrib *a = *ap;
             if (a->type->upgrade) {
                 a->type->upgrade(alist, a);
             }
-            a = a->nexttype;
+            ap = &a->nexttype;
         }
     }
     return result;
@@ -61,57 +63,57 @@ void write_attribs(storage *store, attrib *alist, const void *owner)
 #endif
 }
 
-int a_readint(attrib * a, void *owner, struct gamedata *data)
+int a_readint(variant * var, void *owner, struct gamedata *data)
 {
     int n;
     READ_INT(data->store, &n);
-    if (a) a->data.i = n;
+    var->i = n;
     return AT_READ_OK;
 }
 
-void a_writeint(const attrib * a, const void *owner, struct storage *store)
+void a_writeint(const variant * var, const void *owner, struct storage *store)
 {
-    WRITE_INT(store, a->data.i);
+    WRITE_INT(store, var->i);
 }
 
-int a_readshorts(attrib * a, void *owner, struct gamedata *data)
+int a_readshorts(variant * var, void *owner, struct gamedata *data)
 {
     int n;
     READ_INT(data->store, &n);
-    a->data.sa[0] = (short)n;
+    var->sa[0] = (short)n;
     READ_INT(data->store, &n);
-    a->data.sa[1] = (short)n;
+    var->sa[1] = (short)n;
     return AT_READ_OK;
 }
 
-void a_writeshorts(const attrib * a, const void *owner, struct storage *store)
+void a_writeshorts(const variant * var, const void *owner, struct storage *store)
 {
-    WRITE_INT(store, a->data.sa[0]);
-    WRITE_INT(store, a->data.sa[1]);
+    WRITE_INT(store, var->sa[0]);
+    WRITE_INT(store, var->sa[1]);
 }
 
-int a_readchars(attrib * a, void *owner, struct gamedata *data)
+int a_readchars(variant * var, void *owner, struct gamedata *data)
 {
     int i;
     for (i = 0; i != 4; ++i) {
         int n;
         READ_INT(data->store, &n);
-        a->data.ca[i] = (char)n;
+        var->ca[i] = (char)n;
     }
     return AT_READ_OK;
 }
 
-void a_writechars(const attrib * a, const void *owner, struct storage *store)
+void a_writechars(const variant * var, const void *owner, struct storage *store)
 {
     int i;
 
     for (i = 0; i != 4; ++i) {
-        WRITE_INT(store, a->data.ca[i]);
+        WRITE_INT(store, var->ca[i]);
     }
 }
 
 #define DISPLAYSIZE 8192
-int a_readstring(attrib * a, void *owner, struct gamedata *data)
+int a_readstring(variant * var, void *owner, struct gamedata *data)
 {
     char buf[DISPLAYSIZE];
     char * result = 0;
@@ -133,19 +135,19 @@ int a_readstring(attrib * a, void *owner, struct gamedata *data)
             result = str_strdup(buf);
         }
     } while (e == ENOMEM);
-    a->data.v = result;
+    var->v = result;
     return AT_READ_OK;
 }
 
-void a_writestring(const attrib * a, const void *owner, struct storage *store)
+void a_writestring(const variant * var, const void *owner, struct storage *store)
 {
-    assert(a->data.v);
-    WRITE_STR(store, (const char *)a->data.v);
+    assert(var && var->v);
+    WRITE_STR(store, (const char *)var->v);
 }
 
-void a_finalizestring(attrib * a)
+void a_finalizestring(variant * var)
 {
-    free(a->data.v);
+    free(var->v);
 }
 
 #define MAXATHASH 61
@@ -308,11 +310,16 @@ static int a_unlink(attrib ** pa, attrib * a)
     return 0;
 }
 
+void a_free_voidptr(union variant *var)
+{
+    free(var->v);
+}
+
 static void a_free(attrib * a)
 {
     const attrib_type *at = a->type;
     if (at->finalize)
-        at->finalize(a);
+        at->finalize(&a->data);
     free(a);
 }
 
@@ -376,7 +383,7 @@ attrib *a_new(const attrib_type * at)
     assert(at != NULL);
     a->type = at;
     if (at->initialize)
-        at->initialize(a);
+        at->initialize(&a->data);
     return a;
 }
 
@@ -404,10 +411,10 @@ static critbit_tree cb_deprecated = { 0 };
 
 typedef struct deprecated_s {
     unsigned int hash;
-    int(*reader)(attrib *, void *, struct gamedata *);
+    int(*reader)(variant *, void *, struct gamedata *);
 } deprecated_t;
 
-void at_deprecate(const char * name, int(*reader)(attrib *, void *, struct gamedata *))
+void at_deprecate(const char * name, int(*reader)(variant *, void *, struct gamedata *))
 {
     deprecated_t value;
     
@@ -418,13 +425,15 @@ void at_deprecate(const char * name, int(*reader)(attrib *, void *, struct gamed
 
 static int a_read_i(gamedata *data, attrib ** attribs, void *owner, unsigned int key) {
     int retval = AT_READ_OK;
-    int(*reader)(attrib *, void *, struct gamedata *) = 0;
+    int(*reader)(variant *, void *, struct gamedata *) = 0;
     attrib_type *at = at_find_key(key);
-    attrib * na = 0;
+    attrib * na = NULL;
+    variant var, *vp = &var;
 
     if (at) {
         reader = at->read;
         na = a_new(at);
+        vp = &na->data;
     }
     else {
         void *match;
@@ -438,16 +447,20 @@ static int a_read_i(gamedata *data, attrib ** attribs, void *owner, unsigned int
         }
     }
     if (reader) {
-        int ret = reader(na, owner, data);
+        int ret = reader(vp, owner, data);
         if (na) {
             switch (ret) {
             case AT_READ_DEPR:
             case AT_READ_OK:
-                a_add(attribs, na);
+                if (na) {
+                    a_add(attribs, na);
+                }
                 retval = ret;
                 break;
             case AT_READ_FAIL:
-                a_free(na);
+                if (na) {
+                    a_free(na);
+                }
                 break;
             default:
                 assert(!"invalid return value");
@@ -508,7 +521,7 @@ void a_write(struct storage *store, const attrib * attribs, const void *owner) {
         if (na->type->write) {
             assert(na->type->hashkey || !"attribute not registered");
             WRITE_INT(store, na->type->hashkey);
-            na->type->write(na, owner, store);
+            na->type->write(&na->data, owner, store);
             na = na->next;
         }
         else {
@@ -526,7 +539,7 @@ void a_write_orig(struct storage *store, const attrib * attribs, const void *own
         if (na->type->write) {
             assert(na->type->hashkey || !"attribute not registered");
             WRITE_TOK(store, na->type->name);
-            na->type->write(na, owner, store);
+            na->type->write(&na->data, owner, store);
             na = na->next;
         }
         else {
diff --git a/src/util/attrib.h b/src/util/attrib.h
index 6043a960f..434c60013 100644
--- a/src/util/attrib.h
+++ b/src/util/attrib.h
@@ -20,27 +20,19 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #define ATTRIB_H
 
 #include <stdbool.h>
-
+#include "variant.h"
 #ifdef __cplusplus
 extern "C" {
 #endif
 
+    union variant;
     struct gamedata;
     struct storage;
     typedef void(*afun) (void);
 
     typedef struct attrib {
         const struct attrib_type *type;
-        union {
-            afun f;
-            void *v;
-            int i;
-            float flt;
-            char c;
-            short s;
-            short sa[2];
-            char ca[4];
-        } data;
+        union variant data;
         /* internal data, do not modify: */
         struct attrib *next;        /* next attribute in the list */
         struct attrib *nexttype;    /* skip to attribute of a different type */
@@ -52,12 +44,12 @@ extern "C" {
 
     typedef struct attrib_type {
         const char *name;
-        void(*initialize) (struct attrib *);
-        void(*finalize) (struct attrib *);
+        void(*initialize) (union variant *);
+        void(*finalize) (union variant *);
         int(*age) (struct attrib *, void *owner);
         /* age returns 0 if the attribute needs to be removed, !=0 otherwise */
-        void(*write) (const struct attrib *, const void *owner, struct storage *);
-        int(*read) (struct attrib *, void *owner, struct gamedata *);       /* return AT_READ_OK on success, AT_READ_FAIL if attrib needs removal */
+        void(*write) (const union variant *, const void *owner, struct storage *);
+        int(*read) (union variant *, void *owner, struct gamedata *);       /* return AT_READ_OK on success, AT_READ_FAIL if attrib needs removal */
         void(*upgrade) (struct attrib **alist, struct attrib *a);
         unsigned int flags;
         /* ---- internal data, do not modify: ---- */
@@ -66,7 +58,7 @@ extern "C" {
     } attrib_type;
 
     void at_register(attrib_type * at);
-    void at_deprecate(const char * name, int(*reader)(attrib *, void *, struct gamedata *));
+    void at_deprecate(const char * name, int (*reader)(variant *, void *, struct gamedata *));
     struct attrib_type *at_find(const char *name);
 
     void write_attribs(struct storage *store, struct attrib *alist, const void *owner);
@@ -80,25 +72,26 @@ extern "C" {
     attrib *a_new(const attrib_type * at);
     int a_age(attrib ** attribs, void *owner);
 
+    void a_free_voidptr(union variant *v);
     int a_read_orig(struct gamedata *data, attrib ** attribs, void *owner);
     void a_write_orig(struct storage *store, const attrib * attribs, const void *owner);
 
     int a_read(struct gamedata *data, attrib ** attribs, void *owner);
     void a_write(struct storage *store, const attrib * attribs, const void *owner);
 
-    int a_readint(struct attrib *a, void *owner, struct gamedata *);
-    void a_writeint(const struct attrib *a, const void *owner,
+    int a_readint(union variant *v, void *owner, struct gamedata *);
+    void a_writeint(const union variant *v, const void *owner,
         struct storage *store);
-    int a_readshorts(struct attrib *a, void *owner, struct gamedata *);
-    void a_writeshorts(const struct attrib *a, const void *owner,
+    int a_readshorts(union variant *v, void *owner, struct gamedata *);
+    void a_writeshorts(const union variant *v, const void *owner,
         struct storage *store);
-    int a_readchars(struct attrib *a, void *owner, struct gamedata *);
-    void a_writechars(const struct attrib *a, const void *owner,
+    int a_readchars(union variant *v, void *owner, struct gamedata *);
+    void a_writechars(const union variant *v, const void *owner,
         struct storage *store);
-    int a_readstring(struct attrib *a, void *owner, struct gamedata *);
-    void a_writestring(const struct attrib *a, const void *owner,
+    int a_readstring(union variant *v, void *owner, struct gamedata *);
+    void a_writestring(const union variant *v, const void *owner,
         struct storage *);
-    void a_finalizestring(struct attrib *a);
+    void a_finalizestring(union variant *v);
 
     void attrib_done(void);
 
diff --git a/src/util/attrib.test.c b/src/util/attrib.test.c
index 34427385f..d266196e6 100644
--- a/src/util/attrib.test.c
+++ b/src/util/attrib.test.c
@@ -117,18 +117,18 @@ static void test_attrib_nexttype(CuTest * tc)
 static void test_attrib_rwstring(CuTest *tc) {
     gamedata data;
     storage store;
-    attrib a = { 0 };
+    variant var = { 0 };
 
     test_setup();
-    a.data.v = str_strdup("Hello World");
+    var.v = str_strdup("Hello World");
     mstream_init(&data.strm);
     gamedata_init(&data, &store, RELEASE_VERSION);
-    a_writestring(&a, NULL, &store);
-    a_finalizestring(&a);
+    a_writestring(&var, NULL, &store);
+    a_finalizestring(&var);
     data.strm.api->rewind(data.strm.handle);
-    a_readstring(&a, NULL, &data);
-    CuAssertStrEquals(tc, "Hello World", (const char *)a.data.v);
-    a_finalizestring(&a);
+    a_readstring(&var, NULL, &data);
+    CuAssertStrEquals(tc, "Hello World", (const char *)var.v);
+    a_finalizestring(&var);
     mstream_done(&data.strm);
     gamedata_done(&data);
     test_teardown();
@@ -137,17 +137,17 @@ static void test_attrib_rwstring(CuTest *tc) {
 static void test_attrib_rwint(CuTest *tc) {
     gamedata data;
     storage store;
-    attrib a = { 0 };
+    variant var = { 0 };
 
     test_setup();
-    a.data.i = 42;
+    var.i = 42;
     mstream_init(&data.strm);
     gamedata_init(&data, &store, RELEASE_VERSION);
-    a_writeint(&a, NULL, &store);
-    a.data.i = 0;
+    a_writeint(&var, NULL, &store);
+    var.i = 0;
     data.strm.api->rewind(data.strm.handle);
-    a_readint(&a, NULL, &data);
-    CuAssertIntEquals(tc, 42, a.data.i);
+    a_readint(&var, NULL, &data);
+    CuAssertIntEquals(tc, 42, var.i);
     mstream_done(&data.strm);
     gamedata_done(&data);
     test_teardown();
@@ -156,19 +156,19 @@ static void test_attrib_rwint(CuTest *tc) {
 static void test_attrib_rwchars(CuTest *tc) {
     gamedata data;
     storage store;
-    attrib a = { 0 };
+    variant var = { 0 };
 
     test_setup();
-    a.data.ca[0] = 1;
-    a.data.ca[3] = 42;
+    var.ca[0] = 1;
+    var.ca[3] = 42;
     mstream_init(&data.strm);
     gamedata_init(&data, &store, RELEASE_VERSION);
-    a_writeint(&a, NULL, &store);
-    memset(a.data.ca, 0, 4);
+    a_writeint(&var, NULL, &store);
+    memset(var.ca, 0, 4);
     data.strm.api->rewind(data.strm.handle);
-    a_readint(&a, NULL, &data);
-    CuAssertIntEquals(tc, 1, a.data.ca[0]);
-    CuAssertIntEquals(tc, 42, a.data.ca[3]);
+    a_readint(&var, NULL, &data);
+    CuAssertIntEquals(tc, 1, var.ca[0]);
+    CuAssertIntEquals(tc, 42, var.ca[3]);
     mstream_done(&data.strm);
     gamedata_done(&data);
     test_teardown();
@@ -177,19 +177,19 @@ static void test_attrib_rwchars(CuTest *tc) {
 static void test_attrib_rwshorts(CuTest *tc) {
     gamedata data;
     storage store;
-    attrib a = { 0 };
-    a.data.sa[0] = -4;
-    a.data.sa[1] = 42;
+    variant var = { 0 };
+    var.sa[0] = -4;
+    var.sa[1] = 42;
 
     test_setup();
     mstream_init(&data.strm);
     gamedata_init(&data, &store, RELEASE_VERSION);
-    a_writeint(&a, NULL, &store);
-    memset(a.data.ca, 0, 4);
+    a_writeint(&var, NULL, &store);
+    memset(var.ca, 0, 4);
     data.strm.api->rewind(data.strm.handle);
-    a_readint(&a, NULL, &data);
-    CuAssertIntEquals(tc, -4, a.data.sa[0]);
-    CuAssertIntEquals(tc, 42, a.data.sa[1]);
+    a_readint(&var, NULL, &data);
+    CuAssertIntEquals(tc, -4, var.sa[0]);
+    CuAssertIntEquals(tc, 42, var.sa[1]);
     mstream_done(&data.strm);
     gamedata_done(&data);
     test_teardown();
diff --git a/src/util/event.c b/src/util/event.c
index 298f9d93e..d6aa6f338 100644
--- a/src/util/event.c
+++ b/src/util/event.c
@@ -127,32 +127,32 @@ typedef struct handler_info {
     trigger *triggers;
 } handler_info;
 
-static void init_handler(attrib * a)
+static void init_handler(variant *var)
 {
-    a->data.v = calloc(sizeof(handler_info), 1);
+    var->v = calloc(sizeof(handler_info), 1);
 }
 
-static void free_handler(attrib * a)
+static void free_handler(variant *var)
 {
-    handler_info *hi = (handler_info *)a->data.v;
+    handler_info *hi = (handler_info *)var->v;
     free_triggers(hi->triggers);
     free(hi->event);
     free(hi);
 }
 
 static void
-write_handler(const attrib * a, const void *owner, struct storage *store)
+write_handler(const variant *var, const void *owner, struct storage *store)
 {
-    handler_info *hi = (handler_info *)a->data.v;
+    handler_info *hi = (handler_info *)var->v;
     WRITE_TOK(store, hi->event);
     write_triggers(store, hi->triggers);
 }
 
-static int read_handler(attrib * a, void *owner, gamedata *data)
+static int read_handler(variant *var, void *owner, gamedata *data)
 {
     struct storage *store = data->store;
     char zText[128];
-    handler_info *hi = (handler_info *)a->data.v;
+    handler_info *hi = (handler_info *)var->v;
 
     READ_TOK(store, zText, sizeof(zText));
     hi->event = str_strdup(zText);
diff --git a/src/util/language.c b/src/util/language.c
index 689ccfcd7..b2447b695 100644
--- a/src/util/language.c
+++ b/src/util/language.c
@@ -186,7 +186,7 @@ const char *locale_string(const locale * lang, const char *key, bool warn)
             return value;
         }
     }
-    return 0;
+    return NULL;
 }
 
 void locale_setstring(locale * lang, const char *key, const char *value)
@@ -257,8 +257,9 @@ static lstr lstrs[MAXLOCALES];
 void ** get_translations(const struct locale *lang, int index)
 {
     assert(lang);
-    assert(lang->index < MAXLOCALES
-        || "you have to increase MAXLOCALES and recompile");
+    if (lang->index >= MAXLOCALES) {
+        log_fatal("you have to increase MAXLOCALES and recompile");
+    }
     if (lang->index < MAXLOCALES) {
         return lstrs[lang->index].tokens + index;
     }
diff --git a/src/util/unicode.c b/src/util/unicode.c
index 10d43f947..85a341ddf 100644
--- a/src/util/unicode.c
+++ b/src/util/unicode.c
@@ -108,9 +108,6 @@ int unicode_utf8_tolower(utf8_t * op, size_t outlen, const utf8_t * ip)
         }
     }
 
-    if (outlen <= 0) {
-        return ENOMEM;
-    }
     *op = 0;
     return 0;
 }
diff --git a/src/volcano.c b/src/volcano.c
index df70a864f..7bddd6097 100644
--- a/src/volcano.c
+++ b/src/volcano.c
@@ -74,12 +74,31 @@ static int nb_armor(const unit * u, int index)
     return av;
 }
 
-static int
-damage_unit(unit * u, const char *dam, bool physical, bool magic)
+static bool resurrect_unit(unit *u) {
+    if (oldpotiontype[P_HEAL]) {
+        bool heiltrank = false;
+        if (get_effect(u, oldpotiontype[P_HEAL]) > 0) {
+            change_effect(u, oldpotiontype[P_HEAL], -1);
+            heiltrank = true;
+        }
+        else if (i_get(u->items, oldpotiontype[P_HEAL]) > 0) {
+            i_change(&u->items, oldpotiontype[P_HEAL], -1);
+            change_effect(u, oldpotiontype[P_HEAL], 3);
+            heiltrank = true;
+        }
+        if (heiltrank && (rng_int() % 2)) {
+            return true;
+        }
+    }
+    return false;
+}
+
+static int damage_unit(unit * u, const char *dam, bool physical, bool magic)
 {
     int *hp, hpstack[20];
     int h;
-    int i, dead = 0, hp_rem = 0, heiltrank;
+    int healings;
+    int i, dead = 0, hp_rem = 0;
 
     assert(u->number);
     if (fval(u_race(u), RCF_ILLUSIONARY)) {
@@ -115,36 +134,31 @@ damage_unit(unit * u, const char *dam, bool physical, bool magic)
         hp[i] -= damage;
     }
 
+    /* does this unit have any healing potions or effects? */
+    healings = i_get(u->items, oldpotiontype[P_HEAL]) * 4;
+    healings += get_effect(u, oldpotiontype[P_HEAL]);
     /* Auswirkungen */
     for (i = 0; i < u->number; i++) {
         if (hp[i] <= 0) {
-            heiltrank = 0;
-
             /* Sieben Leben */
             if (u_race(u) == get_race(RC_CAT) && (chance(1.0 / 7))) {
                 hp[i] = u->hp / u->number;
                 hp_rem += hp[i];
-                continue;
             }
-
-            /* Heiltrank */
-            if (oldpotiontype[P_HEAL]) {
-                if (get_effect(u, oldpotiontype[P_HEAL]) > 0) {
-                    change_effect(u, oldpotiontype[P_HEAL], -1);
-                    heiltrank = 1;
-                }
-                else if (i_get(u->items, oldpotiontype[P_HEAL]) > 0) {
-                    i_change(&u->items, oldpotiontype[P_HEAL], -1);
-                    change_effect(u, oldpotiontype[P_HEAL], 3);
-                    heiltrank = 1;
-                }
-                if (heiltrank && (chance(0.50))) {
+            else if (healings > 0) {
+                --healings;
+                if (resurrect_unit(u)) {
+                    /* Heiltrank benutzen */
                     hp[i] = u->hp / u->number;
                     hp_rem += hp[i];
-                    continue;
+                }
+                else {
+                    ++dead;
                 }
             }
-            dead++;
+            else {
+                ++dead;
+            }
         }
         else {
             hp_rem += hp[i];
@@ -263,7 +277,7 @@ static bool stop_smoke_chance(void) {
     if (config_changed(&cache)) {
         percent = config_get_int("volcano.stop.percent", 12);
     }
-    return percent!=0 && (rng_int() % 100) < percent;
+    return percent != 0 && (rng_int() % 100) < percent;
 }
 
 static bool outbreak_chance(void) {
@@ -271,12 +285,12 @@ static bool outbreak_chance(void) {
     if (config_changed(&cache)) {
         percent = config_get_int("volcano.outbreak.percent", 8);
     }
-    return percent!=0 && (rng_int() % 100) < percent;
+    return percent != 0 && (rng_int() % 100) < percent;
 }
 
-void volcano_update(void) 
+void volcano_update(void)
 {
-    region *r; 
+    region *r;
     const struct terrain_type *t_active, *t_volcano;
 
     t_volcano = get_terrain("volcano");
diff --git a/src/volcano.h b/src/volcano.h
index 225a76143..c72801cce 100644
--- a/src/volcano.h
+++ b/src/volcano.h
@@ -19,6 +19,9 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 
 #ifndef H_GC_VOLCANO
 #define H_GC_VOLCANO
+
+#include <stdbool.h>
+
 #ifdef __cplusplus
 extern "C" {
 #endif
diff --git a/src/vortex.c b/src/vortex.c
index bb30524ef..69d767c1b 100644
--- a/src/vortex.c
+++ b/src/vortex.c
@@ -65,14 +65,14 @@ void register_special_direction(struct locale *lang, const char *name)
 /********************/
 /*   at_direction   */
 /********************/
-static void a_initdirection(attrib * a)
+static void a_initdirection(variant * var)
 {
-    a->data.v = calloc(1, sizeof(spec_direction));
+    var->v = calloc(1, sizeof(spec_direction));
 }
 
-static void a_freedirection(attrib * a)
+static void a_freedirection(variant *var)
 {
-    spec_direction *d = (spec_direction *)(a->data.v);
+    spec_direction *d = (spec_direction *)(var->v);
     free(d->desc);
     free(d->keyword);
     free(d);
@@ -86,10 +86,10 @@ static int a_agedirection(attrib * a, void *owner)
     return (d->duration > 0) ? AT_AGE_KEEP : AT_AGE_REMOVE;
 }
 
-static int a_readdirection(attrib * a, void *owner, struct gamedata *data)
+static int a_readdirection(variant *var, void *owner, struct gamedata *data)
 {
     struct storage *store = data->store;
-    spec_direction *d = (spec_direction *)(a->data.v);
+    spec_direction *d = (spec_direction *)(var->v);
     char lbuf[32];
 
     (void)owner;
@@ -105,9 +105,9 @@ static int a_readdirection(attrib * a, void *owner, struct gamedata *data)
 }
 
 static void
-a_writedirection(const attrib * a, const void *owner, struct storage *store)
+a_writedirection(const variant *var, const void *owner, struct storage *store)
 {
-    spec_direction *d = (spec_direction *)(a->data.v);
+    spec_direction *d = (spec_direction *)(var->v);
 
     (void)owner;
     WRITE_INT(store, d->x);
diff --git a/src/wormhole.c b/src/wormhole.c
index 2366a7e9c..197fc346d 100644
--- a/src/wormhole.c
+++ b/src/wormhole.c
@@ -91,20 +91,20 @@ static int wormhole_age(struct attrib *a, void *owner)
     return AT_AGE_KEEP;
 }
 
-static void wormhole_write(const struct attrib *a, const void *owner, struct storage *store)
+static void wormhole_write(const variant *var, const void *owner, struct storage *store)
 {
-    region *exit = (region *)a->data.v;
+    region *exit = (region *)var->v;
     write_region_reference(exit, store);
 }
 
-static int wormhole_read(struct attrib *a, void *owner, struct gamedata *data)
+static int wormhole_read(variant *var, void *owner, struct gamedata *data)
 {
     int id;
 
     if (data->version < ATTRIBOWNER_VERSION) {
         READ_INT(data->store, NULL);
     }
-    id = read_region_reference(data, (region **)&a->data.v, NULL);
+    id = read_region_reference(data, (region **)&var->v, NULL);
     return (id <= 0) ? AT_READ_FAIL : AT_READ_OK;
 }
 
diff --git a/src/xmlreader.c b/src/xmlreader.c
index a711b7dbd..66b04e611 100644
--- a/src/xmlreader.c
+++ b/src/xmlreader.c
@@ -29,7 +29,7 @@ without prior permission by the authors of Eressea.
 #include "kernel/spellbook.h"
 
 #include "alchemy.h"
-#include "calendar.h"
+#include "kernel/calendar.h"
 #include "guard.h"
 #include "keyword.h"
 #include "move.h"