Scriptcode

Diesen Funktionscode benötigst du im lokalen Skript um Hexer nutzen zu können:
-- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
-- *
-- Hexerei-Mod
-- Autor: totalwarANGEL
-- Local Enviornment
-- Version 1.3
-- *
-- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *

-- Dieses Skript erstellt Hexenmeister aus Helden. Diese Helden haben dann keine aktive Fähigkeit mehr,
-- können dafür aber bis zu 4 Zauber gleichzeitig mit sich tragen und gegen Feinde sprechen oder sich
-- selbst damit heilen.
-- Als Ableitung des Hexers wurde jetzt der Krieger hinzugefügt.

-- Die Fähigkeitsstufen und Zauber werden auch an das globale Skript gesandt. Man kann durch Zugriff auf
-- die globale Table "g_SpellcasterList" im globalen Skript einige Werte abfragen (für Quests)
-- * g_SpellcasterList[<name>].Spells[<index>]
--        == "" bedeutet leer, ansonsten steht da der Name des Zaubers (Name ~= Titel)
-- * g_SpellcasterList[<name>].Stats.Learnpoints
--        gibt die Anzahl der Lernpunkte zurück
-- * g_SpellcasterList[<name>].Stats.CurrentMana
--        gibt die aktuellen Zauberpunkte zurück
-- * g_SpellcasterList[<name>].Stats.MaximalMana
--        gibt die maximalen Zauberpunkte zurück
-- * g_SpellcasterList[<name>].Stats.CurrentTime
--        gibt den aktuellen Zähler des Zykluses an, bis Mana regeriert wird
--        (ist manchmal 0 bei erreichten maximalen Mana)
-- * g_SpellcasterList[<name>].Stats.MaximalTime
--        gibt die maximale Zeit an, die vergehen muss, bis Mana regeneriert wird.
-- * g_SpellcasterList[<name>].Stats.Distance
--        gibt die Entfernung zurück, aus der Zauber gewirkt werden können

-- * * * * * * * * * * * * * * * * * * * * 
-- Spellcaster - Daten
-- * * * * * * * * * * * * * * * * * * * * 

-- Diese Tabelle Speichert alle Hexer, die erstellt wurden. Ein Hexer wird über einen
-- Stringkey indiziert bzw. überschrieben bzw. gelöscht.
g_SpellcasterList          = {}

-- Klasse für Hexenmeister. Hier dran bitte nur was ändern, wenn man auch weiß was man
-- da tut. Also das gesamte Skript verstanden hat und selbst nachts um 3 aus dem Bett
-- geholt werden könnte um weiter dran zu arbeiten. ;)
Spellcaster                 = {
    Name                    = "default";
    HomeEntity            = nil;
    HomeDistance            = 2000;
    Menu                    = 1;
    Using                   = nil;
    Stats                = {
        Mana                = {Current = 5, Max = 5, Teach = 3};
        Time                = {Recharge = 300, Timer = 300, Teach = 16};
        Range            = {Distance = 3000, Teach = 500};
        Learnpoints        = 0;
    };

    Spells                = {
        Learned            = {};
        Slot1             = nil;
        Slot2             = nil;
        Slot3             = nil;
        Slot4             = nil;
    };

    -- Achtung: Nur für Nutzung durch den aktuellen Spieler gedacht. KIs haben keine Manatränke!
    -- Sollte der Spieler eine andere SpielerID bekommen sollte Amount null gesetzt werden. Es ist
    -- zwar prinzipiell möglich jedem Helden eigene Tränke zu geben, doch sehe ich keine Möglichkeit
    -- Manatränke untereinander auszutauschen (fehlende Buttons). Deshalb ist das jetzt so geregelt
    -- und bleibt auch vorerst so.
    Potion                 = {
        Amount             = 0;
        GoldCost         = 500;
        HerbCost         = 10;
    };

    -- Perks werden per Variablenwertänderung gelernt! Perks sind hard coded! Keine neuen einfügen!
    -- Sind eigentlich nur dafür gedacht KI-Hexer etwas stärker zu machen. Können aber auch genutzt
    -- werden um bei mehreren menschlichen Hexern besondere Stärken des einzelnen hervorzuheben.
    -- Perks können ebenso bei der Erzeugung bereits über :new zugewiesen werden. Sie sind für den
    -- Spieler nur durch ihren Effekt sichtbar (mangelnde Anzeigefläche).
    Perks                 = {
        Alchemist        = false;    -- Erlaubt es Manatränke herzustellen
        BeastMaster      = false;    -- Hexer beschwören die doppelte Anzahl an Tieren
        BigGameHunter    = false;    -- Dreifacher Schaden gegen Raubtiere
        FortressBraker   = false;    -- Doppelter Zauberschaden gegen Gebäude
        GoodAlchemist    = false;    -- Reduziert Kosten für die Trankherstellung
        TalentedMage     = false;    -- Doppelte Manaregeneration per Zyklus
        MasterMage       = false;    -- Dreifache Manaregeneration per Zyklus
        SharpEyes        = false;    -- Erhöht die Zauberdistanz prozentual (15%)
        Warlock          = false;    -- Erhöht prozentual (15%) die Gebietsgröße
    };

    -- Speichert Widgetnamen! Unverändert lassen!
    Training                = {
        Recharge            = {
            Mother        = "/InGame/Root/Normal/AlignTopLeft/KnightCommands/Trebuchet",
            Button        = "/InGame/Root/Normal/AlignTopLeft/KnightCommands/Trebuchet/Button",
            Timer        = "/InGame/Root/Normal/AlignTopLeft/KnightCommands/Trebuchet/Time",
        };
        Spellpoints        = {
            Mother        = "/InGame/Root/Normal/AlignTopLeft/KnightCommands/StartAttack",
            Button        = "/InGame/Root/Normal/AlignTopLeft/KnightCommands/StartAttack/Button",
            Timer        = "/InGame/Root/Normal/AlignTopLeft/KnightCommands/StartAttack/Time",
        };
        Effectivity        = {
            Mother        = "/InGame/Root/Normal/AlignTopLeft/KnightCommands/Bless",
            Button       = "/InGame/Root/Normal/AlignTopLeft/KnightCommands/Bless/Button",
            Timer        = "/InGame/Root/Normal/AlignTopLeft/KnightCommands/Bless/Time",
        };
    };
}

-- * * * * * * * * * * * * * * * * * * * * 
-- Krieger - Klasse
-- * * * * * * * * * * * * * * * * * * * * 

-- Der Krieger ist anders als der Hexer. Er hat nicht eine Vielzahl von Zaubern zur Auswahl, sondern
-- eine spezielle Fähigkeit. Dafür ist der Krieger ein mächtiger Held, der nicht so einfach umzuhauen ist.
-- Er kann Angriff, Verteidigung und Regeneration durch lernen verbessern und Manatränke nutzen um damit
-- seine Wunden zu kurieren.

Warrior = {}

Warrior.Precast     = {
    ExtraPay        = {
        Description    = {
            Title    = {de = "Sonderzahlung", en = "Extra Payment"};
            Text    = {de = "Der Krieger zahlt allen Soldaten einen Bonus aus seinem Privatvermögen aus.",
                       en = "All soldiers get an extra payment from the private means of the warrior."};
        };
        Icon        = {1,8};
        Action        = function(hero)
            local pID = GUI.GetPlayerID();
            Sound.FXPlay2DSound("ui\\menu_left_gold");
            GUI.SendScriptCommand([[Logic.AddBuff(]]..pID..[[,Buffs.Buff_ExtraPayment)]]);
        end;
    };
    Slander        = {
        Description    = {
            Title    = {de = "Verleumdung", en = "Slander"};
            Text    = {de = "Der Krieger verbreitet Lügen über einen Herrscher unter dem Volke. Dadurch schädigt er den Ruf des Herrschers.",
                       en = "The warrior try to spread lies about the ruler under his people. This will damage the repupatition of this ruler."};
        };
        Icon        = {11,1};
        Action        = function(hero)
            local eID = GetID(hero.Name);
            local pID = GUI.GetPlayerID();
            local tID = GetTerritoryUnderEntity(eID);
            local tP  = Logic.GetTerritoryPlayerID(tID);
            if tP ~= pID and Logic.GetNumberOfEmployedWorkers(tP) > 1 then
                Sound.FXPlay2DSound("ui\\menu_left_settler_scared");
                GUI.SendScriptCommand([[
                    Logic.AddBuff(]]..tP..[[,Buffs.Buff_NoPayment)
                    Logic.AddBuff(]]..tP..[[,Buffs.Buff_HighTaxes)
                ]]);
                return;
            end
            local lang = Network.GetDesiredLanguage();
            Message((lang == "de" and "Verleumdung fehlgeschlagen!") or "Defamation failed!");
            hero.Stats.Mana.Current = hero.Stats.Mana.Max;
        end;
    };
}

-- Default für die Fähigkeit des Kriegers. Kann natürlich im Nachhinein noch geändert werden.
Warrior.Ability    = {
    Description        = Warrior.Precast.Slander.Description;
    Action            = Warrior.Precast.Slander.Action;
    Icon            = Warrior.Precast.Slander.Icon;
};

-- Schaden, der dem Krieger von der entsprechenden Einheit zugefügt wird. Alle nicht gelisteten EntityTypes
-- verursachen den Default-Schaden 30
Warrior.DamageList                    = {
    [Entities.A_AS_BearBlack]         = 60;
    [Entities.A_AS_Tiger]             = 35;
    [Entities.A_ME_Bear]             = 48;
    [Entities.A_ME_Bear_black]         = 60;
    [Entities.A_ME_Wolf]             = 19;
    [Entities.A_NA_Lion_Female]     = 26;
    [Entities.A_NA_Lion_Male]         = 30;
    [Entities.A_NE_PolarBear]         = 60;
    [Entities.U_MilitaryBow]         = 20;
    [Entities.U_MilitarySword]         = 20;
    [Entities.U_MilitaryTrap]         = 200;
    [Entities.U_MilitaryCatapult]     = 200;
    [Entities.U_Trebuchet]             = 400;
}

-- Preise, die der Krieger für seine Jagdtbeute erzielen kann
Warrior.TrophyPrices                = {
    [Entities.A_AS_BearBlack]         = 300;    -- 100%
    [Entities.A_AS_Tiger]             = 210;    -- 70%
    [Entities.A_ME_Bear]             = 150;    -- 50%
    [Entities.A_ME_Bear_black]         = 300;    -- 100%
    [Entities.A_ME_Wolf]             = 60;    -- 20%
    [Entities.A_NA_Lion_Female]     = 120;    -- 40%
    [Entities.A_NA_Lion_Male]         = 165;    -- 55%
    [Entities.A_NE_PolarBear]         = 240;    -- 80%
}
Warrior.AlreadyHuntedEntities = {}
Warrior.SummonedAnimals = {}

Warrior.Perks           = {
    Inquisitor            = false;  -- Der Krieger bekommt 15% Magieresistenz und 15% Schadensbonus gegen Magier
                                  -- (wird getrennt berechnet zu GoodAttacker und GoodDefender)
    GoodAttacker        = false;  -- Der Krieger bekommt 15% Aufschlag auf den Angriff (nur gegen Menschen)
    GoodDefender        = false;  -- Der Krieger erleidet 15% weniger Kampfschaden (ohne Magie)
    MeditationMaster     = false;  -- Der Krieger regeneriert 15% mehr Trefferpunkte pro Zyklus
    PredatorsScare        = false;  -- Der Krieger fügt Raubtieren doppelten Schaden zu
    TrophyHunter        = false;  -- Der Krieger erhält Gold für jedes erschlagene Raubtier
                                  -- (beschworene Tiere zählen nicht)
    BootyCollector        = false;  -- Der Held hat eine 50% Chance für getötete Soldaten Eisen einzusammeln
};

function Warrior:newWarrior(_name)
    local commander = Spellcaster:new(_name);
    commander.isWarrior = true;

    commander.Stats.Mana = {Current = 6, Max = 6, Teach = 0};
    commander.Stats.DEF  = {Current = 2000, Max = 2000, Teach = 500};
    commander.Stats.ATK  = {Current = 35, Teach = 25};
    commander.Stats.REG  = {Current = 4, Teach = 2};

    commander = TableCopyAppend(commander,Warrior);

    return commander;
end

function Warrior:setAbility(_action,_icon,_desc)
    self.Ability.Description = _desc;
    self.Ability.Action         = _action;
    self.Ability.Icon         = _icon;
end

-- * * * * * * * * * * * * * * * * * * * * 
-- Spellcaster - Memberfunktionen
-- * * * * * * * * * * * * * * * * * * * * 

-- Erstellt einen neuen Hexer. Der Hexer wird automatisch eingetragen und die Basis wird
-- auf den Marktplatz gesetzt. Hat dieser Spieler keinen Marktplatz, so muss man manuel
-- eine andere Basis eintragen.
function Spellcaster:new(_name,_homeEntity,_homeDistance,_startMana,_alchemist,_goodAlchemist,_beastmaster,_bigGameHunter,
                         _fortressBreaker,_TalentedMage,_masterMage,_sharpEyes,_warlock)
    -- Spellcaster erzeugen
    local spellcaster = TableCopyAppend({},self);
    spellcaster.Name = _name;
    local pID = Logic.EntityGetPlayer(GetID(_name));
    spellcaster.HomeEntity = Logic.GetMarketplace(pID);
    spellcaster.HomeDistance = (_homeDistance ~= nil and _homeDistance) or spellcaster.HomeDistance;
    spellcaster.HomeEntity = (_homeEntity ~= nil and _homeEntity) or spellcaster.HomeEntity;
    spellcaster.Stats.Mana.Current = (_startMana ~= nil and _startMana) or spellcaster.Stats.Mana.Current;
    spellcaster.Stats.Mana.Max = (_startMana ~= nil and _startMana) or spellcaster.Stats.Mana.Max;

    -- Perks einstellen
    spellcaster.Perks.Alchemist      = _alchemist == true;
    spellcaster.Perks.BeastMaster    = _beastmaster == true;
    spellcaster.Perks.BigGameHunter  = _bigGameHunter == true;
    spellcaster.Perks.FortressBraker = _fortressBreaker == true;
    spellcaster.Perks.GoodAlchemist  = _goodAlchemist == true;
    spellcaster.Perks.TalentedMage   = _TalentedMage == true;
    spellcaster.Perks.MasterMage     = _masterMage == true;
    spellcaster.Perks.SharpEyes      = _sharpEyes == true;
    spellcaster.Perks.Warlock        = _warlock == true;

    -- Initalisierung des Mods, sofern nicht schon passiert
    spellcaster:init();

    -- Refferenz auf Spells erstellen
    spellcaster.Spells:updateSpells();

    -- Speichern des Hexers
    g_SpellcasterList[_name] = spellcaster;
    return spellcaster;
end

-- Erstellt einen Beastmaster. Wölfe beschwören sowie "SharpEyes", "BeastMaster" und "BigGameHunter" sind
-- von Anfang an gelernt/vorhanden.
function Spellcaster:newBeastmaster(_name,_homeEntity,_homeDistance,_startMana)
    local spellcaster = Spellcaster:new(_name,_homeEntity,_homeDistance,_startMana,false,false,true,true,false,false,false,true,false);
    spellcaster.Spells:AttachSpell(spellcaster,1,"SummonWolves");
    return spellcaster;
end

-- Erstellt einen Warlock. Blitzschlag sowie "Warlock", "TalentedMage" und "FortressBreaker" sind
-- von Anfang an gelernt/vorhanden.
function Spellcaster:newWarlock(_name,_homeEntity,_homeDistance,_startMana)
    local spellcaster = Spellcaster:new(_name,_homeEntity,_homeDistance,_startMana,false,false,false,false,true,true,false,false,true);
    spellcaster.Spells:AttachSpell(spellcaster,1,"Lightning");
    return spellcaster;
end

-- Erstellt einen Heiler. Große Heilung sowie "SharpEyes", "TalentedMage" und "Alchemist" sind
-- von Anfang an gelernt/vorhanden.
function Spellcaster:newHealer(_name,_homeEntity,_homeDistance,_startMana)
    local spellcaster = Spellcaster:new(_name,_homeEntity,_homeDistance,_startMana,true,false,false,false,false,true,false,true,false);
    if spellcaster.Stats.Mana.Current < Spells.SuperHealing.Cost then
        spellcaster.Stats.Mana.Current = Spells.SuperHealing.Cost;
        spellcaster.Stats.Mana.Max = Spells.SuperHealing.Cost;
    end
    spellcaster.Spells:AttachSpell(spellcaster,1,"SuperHealing");
    return spellcaster;
end

-- Erstellt einen Paten. Der Pate hat automatisch alles gelernt, was es zu lernen gibt.
function Spellcaster:newGotfather(_name,_homeEntity,_homeDistance,_startMana)
    local spellcaster = Spellcaster:new(_name,_homeEntity,_homeDistance,_startMana,true,true,true,true,true,true,true,true,true);
    for k,v in pairs (Spells) do
        if type(v) == "table" and v.Name then
            spellcaster:learnSpell(v.Name);
        end
    end
    spellcaster.Spells:AttachSpell(spellcaster,1,"Healing");
    spellcaster.Spells:AttachSpell(spellcaster,2,"Lightning");
    spellcaster.Spells:AttachSpell(spellcaster,3,"Thunderstorm");
    spellcaster.Spells:AttachSpell(spellcaster,4,"SummonTigers");
    return spellcaster;
end

-- Schaltet einen Zauber für einen Hexer frei, trägt ihn aber NICHT in das Zauberbuch ein. Der Spieler
-- kann am Marktplatz den Zauber zuweisen. Achtung: KI's sind zu blöd dafür. Ihnen muss man die Zauber
-- direkt ins Zauberbuch reinschreiben. Die Funktion dafür heißt Spells:AttachSpell. Spells ist im Hexer
-- als <hero>.Spells refferenziert.
function Spellcaster:learnSpell(...)
    local Arg = {...};
    for i=1,#Arg do
        if Spells[Arg[i]] then
            if not IstDrin(Arg[i],self.Spells.Learned) then
                self.Spells.Learned[#self.Spells.Learned+1] = Arg[i];
            end
        end
    end
end

-- Lässt den Spieler am Marktplatz durch die gelernten Zauber switchen
function Spellcaster:switchSpell(_slot)
    local lang = (Network.GetDesiredLanguage() == "de" and "de") or "en";
    if #self.Spells.Learned == 0 then
        Message((lang == "de" and "Keine Zauber gelernt!") or "You're magician haven't lern spells");
        return;
    end

    -- Indexgültigkeit prüfen
    if self.Spells["Slot".._slot] == nil then
        self.Spells["Slot".._slot] = {};
    end
    if self.Spells["Slot".._slot].Index == nil then
        self.Spells["Slot".._slot].Index = 0;
    end
    self.Spells["Slot".._slot].Index = self.Spells["Slot".._slot].Index +1;
    if self.Spells["Slot".._slot].Index > #self.Spells.Learned then
        self.Spells["Slot".._slot] = nil;
        return;
    end

    -- Prüfen, ob der Zauber schon angehangen wurde
    local saveIndex = self.Spells["Slot".._slot].Index;
    local spell = self.Spells.Learned[saveIndex];
    local spellAttached = false;
    for i=1,4 do
        if self.Spells["Slot"..i] and self.Spells["Slot"..i].Name == spell then
            spellAttached = true;
            break;
        end
    end

    -- Zauber anhängen oder zum nächsten gehen
    if spellAttached then
        self:switchSpell(_slot);
        return;
    end
    Spells:AttachSpell(self,_slot,self.Spells.Learned[saveIndex]);
    self.Spells["Slot".._slot].Index = saveIndex;
end

-- Rückgabe aller verfügbaren Zauber an der HomeEntity
function Spellcaster:getAvailableSpells()
    local lang = (Network.GetDesiredLanguage() == "de" and "de") or "en";
    local spells = "";
    local first = true;
    for k,v in pairs(self.Spells.Learned) do
        local isAttached = false;
        for i=1,4 do
            if self.Spells["Slot"..i] and self.Spells["Slot"..i].Name == v then
                isAttached = true;
                break;
            end
        end
        if not isAttached then
            if first then
                first = false;
            else
                spells = spells .. ", ";
            end
            spells = spells .. Spells[v].Title[lang];
        end
    end
    return spells;
end

-- Aktualisiert die Referenz auf die Table "Spells".
function Spellcaster.Spells:updateSpells()
    for k,v in pairs(Spells) do
        self[k] = v;
    end
end

-- Führt die Zauber der Kategorie "Direct" aus
function Spellcaster:direct(_spell)
    local lang = (Network.GetDesiredLanguage() == "de" and "de") or "en";
    if self.Stats.Mana.Current >= _spell.Cost then
        self.Stats.Mana.Current = self.Stats.Mana.Current - _spell.Cost;
        _spell:action(self);
        self.Using = nil;
    else
        Message(Umlaute((lang == "de" and "Nicht genügend Zauberpunkte!") or "Not enough spell points!"));
    end
end

-- Führt einen Zauber aus, der Positionsgebunden ist
function Spellcaster:executeExplicitPositionAbility(_X, _Y, _spell,_entity)
    local lang = (Network.GetDesiredLanguage() == "de" and "de") or "en";
    local pos = {X= _X, Y= _Y};
    local sel = GUI.GetSelectedEntity();
    local distance = self.Stats.Range.Distance;
    if self.Perks.SharpEyes then
        distance = distance + (distance/100)*15;
    end
    if IsValidPosition(pos) and distance >= GetDistance(pos,self.Name) then
        -- Zielhilfe für des Klickens unkundige. Der Zauber "rastet" auf der Entity under der Maus "ein".
        if _entity and (Logic.IsBuilding(_entity) == 1 or Logic.IsEntityInCategory(_entity,EntityCategories.Wall) == 1) then
            pos = GetPosition(_entity);
        end
        if Spells:isInCategory(self.Using,"Summon") then
            self:summon(pos.X,pos.Y,_spell);
        elseif Spells:isInCategory(self.Using,"RangedEffect") then
            self:rangedEffect(pos.X,pos.Y,_spell);
        end
    else
        Message(Umlaute((lang == "de" and "Zu weit entfernt!") or "Too far away!"));
    end
    if sel == GetID(self.Name) then
        g_EscapeHasBeenPressed = true;
    end
    GUI.SendCommandStationaryDefend(GetID(self.Name));
end

-- Führt die Zauber der Kategorie "Summon" aus
function Spellcaster:summon(_X, _Y, _spell)
    self.Stats.Mana.Current = self.Stats.Mana.Current - _spell.Cost;
    _spell:effect(_X, _Y, self);
    self.Using = nil;
end

-- Führt die Zauber der Kategorie "RangedEffect" aus
function Spellcaster:rangedEffect(_X, _Y, _spell)
    local pos = {X= _X, Y= _Y};
    local tID = Logic.GetTerritoryAtPosition(_X,_Y);
    local dmg = _spell.Damage;
    local range = _spell.Range;
    if self.Perks.Warlock then
        range = range + math.ceil((range/100)*15);
    end
    local enemies = {}

    -- Tiere ermitteln
    local animal = SucheAufTerritorium(0,tID,0,EntityCategories.AttackableAnimal);
    for i=1,#animal do
        if GetDistance(pos,animal[i]) <= range then
            enemies[#enemies+1] = animal[i];
        end
    end

    -- Feinde ermitteln
    for i=1,8 do
        if i ~= Logic.EntityGetPlayer(GetID(self.Name)) and Diplomacy_GetRelationBetween(i,Logic.EntityGetPlayer(GetID(self.Name))) == -2 then
            local localEntities = GetPlayerEntities(i,0);
            for j=1,#localEntities do
                if Logic.IsEntityInCategory(localEntities[j],EntityCategories.AttackableBuilding) == 1
                or Logic.IsEntityInCategory(localEntities[j],EntityCategories.AttackableSettler) == 1
                or Logic.IsEntityInCategory(localEntities[j],EntityCategories.Military) == 1
                or Logic.IsEntityInCategory(localEntities[j],EntityCategories.Worker) == 1
                or Logic.IsEntityInCategory(localEntities[j],EntityCategories.Wall) == 1 then
                    if GetDistance(pos,localEntities[j]) <= range then
                        enemies[#enemies+1] = localEntities[j];
                    end
                end
            end
        end
    end

    -- Feinde verwunden
    for i=1,#enemies do
        -- Aufschlag für Tiere
        if Logic.IsEntityInCategory(enemies[i],EntityCategories.AttackableAnimal) == 1 then
            if self.Perks.BigGameHunter then
                dmg = dmg * 3;
            end
        end
        -- Abschlag für Gebäude
        if Logic.IsBuilding(enemies[i]) == 1 then
            if self.Perks.FortressBraker then
                dmg = dmg/5;
            else
                dmg = dmg/10;
            end
        end
        GUI.SendScriptCommand([[Spellcaster_HurtEntity(]]..enemies[i]..[[,]]..dmg..[[)]]);

        -- Krieger müssen gesondert Schaden erhalten
        local eName   = Logic.GetEntityName(enemies[i]);
        local warrior = g_SpellcasterList[eName] and g_SpellcasterList[eName].isWarrior;
        if warrior then
            local mdmg = (dmg*3);
            -- Perk "Inquisitor"
            if g_SpellcasterList[eName].Perks.Inquisitor then
                mdmg = math.ceil(mdmg - ((mdmg/100) * 15));
            end
            g_SpellcasterList[eName].Stats.DEF.Current = g_SpellcasterList[eName].Stats.DEF.Current - mdmg;
            if g_SpellcasterList[eName].Stats.DEF.Current < 0 then
                g_SpellcasterList[eName].Stats.DEF.Current = 0;
            end
        end
    end

    self.Stats.Mana.Current = self.Stats.Mana.Current - _spell.Cost;
    _spell:effect(_X,_Y);
    self.Using = nil;
end

-- Schreibt die GUI um und setzt Variablen
function Spellcaster:init()        
    --~~~~~~~~~~~~~~~~~~
    -- Schadensfunktion
    --~~~~~~~~~~~~~~~~~~

    GUI.SendScriptCommand([[
        SetHealth = SetHealth or function(_entity,_percentage,_buildingOnFire)
            local eID = GetID(_entity)
            if Logic.IsEntityAlive(eID) == false then
                return
            end
            if Logic.IsBuilding(eID) == 1 and type(_buildingOnFire) == "number" then
                Logic.DEBUG_SetBuildingOnFire(eID,_buildingOnFire)
            end
            local maxHealth = Logic.GetEntityMaxHealth(eID)
            local health = Logic.GetEntityHealth(eID)
            local percentage = math.floor(((maxHealth * _percentage)/100) +0.5)
            percentage = health - percentage
            if percentage < 0 then
                Logic.HealEntity(eID,-percentage)
            elseif health > 0 then
                Logic.HurtEntity(eID,percentage)
            end 
        end

        Spellcaster_HurtEntity = HurtEntityEx or function(eID,damage,aID)
            if IsExisting(eID)then
                local leader = 0
                if Logic.IsEntityInCategory(eID,EntityCategories.Soldier) == 1 then
                    leader = Logic.SoldierGetLeaderEntityID(eID)
                end
                if Logic.IsEntityInCategory(eID,EntityCategories.Leader) == 1 then
                    leader = eID
                end

                if leader ~= nil and leader ~= 0 then
                    local soldiers = {Logic.GetSoldiersAttachedToLeader(leader)}
                    if soldiers[1] == nil then soldiers[1] = 0 end

                    if soldiers[1] > 0 then
                        local victim = 0
                        local lowestHealth = 1000
                        for i=1,#soldiers do
                            local currentHealth = Logic.GetEntityHealth(soldiers[i])
                            if currentHealth < lowestHealth and currentHealth > 0 then
                                lowestHealth = currentHealth
                                victim = soldiers[i]
                            end
                        end

                        local damageVictim = soldiers[#soldiers]
                        if victim ~= nil and victim ~= 0 then
                            damageVictim = victim
                        end

                        local hpEntity = 0
                        local overkill = damage
                        if IsExisting(damageVictim)then
                            hpEntity = Logic.GetEntityHealth(damageVictim)
                            overkill = damage - hpEntity
                            if hpEntity <= damage then
                                if aID and hpEntity > 0 then
                                    GameCallback_EntityKilled(eID,
                                                              Logic.EntityGetPlayer(eID),
                                                              aID,
                                                              Logic.EntityGetPlayer(aID),
                                                              Logic.GetEntityType(eID),
                                                              Logic.GetEntityType(aID));

                                    local x,y,z = Logic.EntityGetPos(eID)
                                    Logic.ExecuteInLuaLocalState("GameCallback_Feedback_EntityKilled("..
                                                                 ""..eID..","..
                                                                 ""..Logic.EntityGetPlayer(eID)..","..
                                                                 ""..aID..","..
                                                                 ""..Logic.EntityGetPlayer(aID)..","..
                                                                 ""..Logic.GetEntityType(eID)..","..
                                                                 ""..Logic.GetEntityType(aID)..","..
                                                                 ""..x..","..y..")")
                                end
                                Logic.HurtEntity(damageVictim,hpEntity)
                            else
                                Logic.HurtEntity(damageVictim,damage)
                            end
                        end
                        if overkill > 0 then
                            HurtEntityEx(leader,overkill,aID)
                        end
                    end
                else
                    local hpEntity = Logic.GetEntityHealth(eID)
                    if hpEntity <= damage then
                        if aID and hpEntity > 0 then
                            GameCallback_EntityKilled(eID,
                                                      Logic.EntityGetPlayer(eID),
                                                      aID,
                                                      Logic.EntityGetPlayer(aID),
                                                      Logic.GetEntityType(eID),
                                                      Logic.GetEntityType(aID))

                            local x,y,z = Logic.EntityGetPos(eID)
                            Logic.ExecuteInLuaLocalState("GameCallback_Feedback_EntityKilled("..
                                                         ""..eID..","..
                                                         ""..Logic.EntityGetPlayer(eID)..","..
                                                         ""..aID..","..
                                                         ""..Logic.EntityGetPlayer(aID)..","..
                                                         ""..Logic.GetEntityType(eID)..","..
                                                         ""..Logic.GetEntityType(aID)..","..
                                                         ""..x..","..y..")")
                        end
                        Logic.HurtEntity(eID,hpEntity)
                    else
                        Logic.HurtEntity(eID,damage)
                    end
                end
            end
        end
    ]]);

    --~~~~~~~~~~~~~~
    -- Tötungsbonis
    --~~~~~~~~~~~~~~

    if not GameCallback_Feedback_EntityKilled_OrigWARRIOR then
        GameCallback_Feedback_EntityKilled_OrigWARRIOR = GameCallback_Feedback_EntityKilled;
    end
    GameCallback_Feedback_EntityKilled = function(_KilledID, _KilledPID, _KillerID, _KillerPID, _KilledType, _KillerType, _KilledPosX, _KilledPosY)
        GameCallback_Feedback_EntityKilled_OrigWARRIOR(_KilledID, _KilledPID, _KillerID, _KillerPID, _KilledType, _KillerType, _KilledPosX, _KilledPosY);

        local warrior = g_SpellcasterList[Logic.GetEntityName(_KillerID)];
        if warrior and warrior.isWarrior then
            -- Perk "TrophyHunter"
            if warrior.Perks.TrophyHunter then
                local sID = Logic.GetSpawnerEntity(_KilledID);
                if  Warrior.TrophyPrices[_KilledType] and not Warrior.AlreadyHuntedEntities[_KilledID]  and not Warrior.SummonedAnimals[sID]
                and IsExisting(Logic.GetHeadquarters(_KillerPID))then
                    Warrior.AlreadyHuntedEntities[_KilledID] = true;
                    GUI.SendScriptCommand("AddGood(Goods.G_Gold,"..Warrior.TrophyPrices[_KilledType]..",".._KillerPID..")");
                    GUI_FeedbackWidgets.SharedAdd(g_FeedbackWidgets.CityQueue,
                                                  "ui\\menu_left_gold",
                                                  Warrior.TrophyPrices[_KilledType],
                                                  nil,
                                                  {13,8},
                                                  {1,8});
                end
            end

            -- Perk "BootyCollector"
            if warrior.Perks.BootyCollector then
                if  Logic.IsEntityInCategory(_KilledID,EntityCategories.Soldier) == 1 
                and IsExisting(Logic.GetStoreHouse(_KillerPID)) then
                    local chance = math.random(1,100);
                    if chance <= 50 then
                        GUI.SendScriptCommand("AddGood(Goods.G_Iron,1,".._KillerPID..")");
                        GUI_FeedbackWidgets.SharedAdd(g_FeedbackWidgets.CityQueue,
                                                  "ui\\menu_left_gold",
                                                  1,
                                                  nil,
                                                  g_TexturePositions.Entities[_KillerType],
                                                  {2,4});
                    end
                end
            end
        end
    end

    --~~~~~~~~~~~~~
    -- Fortbildung
    --~~~~~~~~~~~~~

    if not GameCallback_GUI_SelectionChanged_OrigSPELLCASTER then
        GameCallback_GUI_SelectionChanged_OrigSPELLCASTER = GameCallback_GUI_SelectionChanged;
    end
    GameCallback_GUI_SelectionChanged = function(a,b)
        GameCallback_GUI_SelectionChanged_OrigSPELLCASTER(a,b)

        XGUIEng.ShowAllSubWidgets("/InGame/Root/Normal/AlignTopLeft/KnightCommands",1)
        XGUIEng.ShowWidget("/InGame/Root/Normal/AlignTopLeft/KnightCommands",1)

        local eID = GUI.GetSelectedEntity();

        local hero;
        for k,v in pairs(g_SpellcasterList) do
            if eID == GetID(v.Name) then
                if v.MilitaryFeedbackKey then
                    g_EscapeHasBeenPressed = true;
                end
                if v.Menu == 2 then
                    XGUIEng.ShowWidget("/InGame/Root/Normal/AlignBottomRight/DialogButtons/Knight/ClaimTerritory",1);
                end
                XGUIEng.ShowWidget(v.Training.Recharge.Mother,1);
                XGUIEng.ShowWidget(v.Training.Spellpoints.Mother,1);
                XGUIEng.ShowWidget(v.Training.Effectivity.Mother,1);
                return
            end
        end

        XGUIEng.ShowWidget("/InGame/Root/Normal/AlignTopLeft/KnightCommands/StartAttack",0);
        XGUIEng.ShowWidget("/InGame/Root/Normal/AlignTopLeft/KnightCommands/Trebuchet",0);
        XGUIEng.ShowWidget("/InGame/Root/Normal/AlignTopLeft/KnightCommands/Bless",0);
    end

    if not GameCallback_Feedback_KnightTitleChanged_OrigSPELLCASTER then
        GameCallback_Feedback_KnightTitleChanged_OrigSPELLCASTER = GameCallback_Feedback_KnightTitleChanged;
            GameCallback_Feedback_KnightTitleChanged = function(_PlayerID, _NewTitle, _OldTitle)
            GameCallback_Feedback_KnightTitleChanged_OrigSPELLCASTER();

            for k,v in pairs(g_SpellcasterList)do
                if not v.Status.DoNotGainLP then
                    v.Stats.Learnpoints = v.Stats.Learnpoints +3;
                end
            end
        end
    end

    function Mission_SupportButtonClicked(a)
        local eID = GUI.GetSelectedEntity();
        for k,v in pairs(g_SpellcasterList) do
            if eID == GetID(v.Name) then
                if v.isWarrior then
                        if a == 0 then
                            v.Stats.ATK.Current = v.Stats.ATK.Current + v.Stats.ATK.Teach;
                            v.Stats.Learnpoints = v.Stats.Learnpoints -1;
                        elseif a == 2 then
                            v.Stats.DEF.Current = v.Stats.DEF.Current + v.Stats.DEF.Current;
                            v.Stats.DEF.Max = v.Stats.DEF.Max + v.Stats.DEF.Max;
                            v.Stats.Learnpoints = v.Stats.Learnpoints -1;
                        elseif a == 1 then
                            v.Stats.REG.Current = v.Stats.REG.Current + v.Stats.REG.Teach;
                            v.Stats.Learnpoints = v.Stats.Learnpoints -1;
                        end
                    else
                        if a == 0 then
                            v.Stats.Mana.Current = v.Stats.Mana.Current + v.Stats.Mana.Teach;
                            v.Stats.Mana.Max = v.Stats.Mana.Max + v.Stats.Mana.Teach;
                            v.Stats.Learnpoints = v.Stats.Learnpoints -1;
                        elseif a == 2 then
                            v.Stats.Time.Recharge = v.Stats.Time.Recharge - v.Stats.Time.Teach;
                            v.Stats.Time.Timer = v.Stats.Time.Timer - v.Stats.Time.Teach;
                            v.Stats.Learnpoints = v.Stats.Learnpoints -1;
                        elseif a == 1 then
                            v.Stats.Range.Distance = v.Stats.Range.Distance + v.Stats.Range.Teach;
                            v.Stats.Learnpoints = v.Stats.Learnpoints -1;
                        end
                    end
                break;
            end
        end
    end

    function Mission_SupportUpdateButton()
        local eIDs = {GUI.GetSelectedEntities()}
        local found = false;
        for k,v in pairs(g_SpellcasterList) do
            if #eIDs == 1 and eIDs[1] == GetID(v.Name) then
                XGUIEng.SetWidgetPositionAndSize(v.Training.Recharge.Mother,170,17,100,100)
                XGUIEng.SetWidgetPositionAndSize(v.Training.Spellpoints.Mother,245,20,100,100)
                XGUIEng.SetWidgetPositionAndSize(v.Training.Effectivity.Mother,320,26,100,100)

                SetIcon(v.Training.Recharge.Button,{11,2})
                SetIcon(v.Training.Effectivity.Button,{7,6})
                SetIcon(v.Training.Spellpoints.Button,{7,1,1});
                if v.isWarrior then
                    SetIcon(v.Training.Recharge.Button,{7,4})
                    SetIcon(v.Training.Spellpoints.Button,{7,2})
                    SetIcon(v.Training.Effectivity.Button,{11,8});
                end

                local x,y = GUI.GetEntityInfoScreenPosition(eIDs[1])
                local screensize = {GUI.GetScreenSize()}

                if x ~= 0 and y ~= 0 and x > -200 and y > -200 and x < (screensize[1] + 50) and y < (screensize[2] + 200) then
                    local widget = "/InGame/Root/Normal/AlignTopLeft/KnightCommands"
                    XGUIEng.SetWidgetSize(widget,480,160)
                    local widgetsize = {XGUIEng.GetWidgetScreenSize(widget)}
                    XGUIEng.SetWidgetScreenPosition(widget,x-(widgetsize[1]*0.6),y-widgetsize[2])

                    if v.Stats.Learnpoints > 0 then
                        XGUIEng.DisableButton(v.Training.Recharge.Button,0);
                        XGUIEng.DisableButton(v.Training.Spellpoints.Button,0);
                        XGUIEng.DisableButton(v.Training.Effectivity.Button,0);
                    else
                        XGUIEng.DisableButton(v.Training.Recharge.Button,1);
                        XGUIEng.DisableButton(v.Training.Spellpoints.Button,1);
                        XGUIEng.DisableButton(v.Training.Effectivity.Button,1);
                        XGUIEng.ShowWidget(v.Training.Recharge.Mother,0);
                        XGUIEng.ShowWidget(v.Training.Spellpoints.Mother,0);
                        XGUIEng.ShowWidget(v.Training.Effectivity.Mother,0);
                    end
                else
                    local widget = "/InGame/Root/Normal/AlignTopLeft/KnightCommands"
                    XGUIEng.SetWidgetScreenPosition(widget,-1000,-1000)
                end

                found = true;
                break;
            end
        end
        if not found then
            XGUIEng.ShowWidget("/InGame/Root/Normal/AlignTopLeft/KnightCommands/StartAttack",0);
            XGUIEng.ShowWidget("/InGame/Root/Normal/AlignTopLeft/KnightCommands/Trebuchet",0);
            XGUIEng.ShowWidget("/InGame/Root/Normal/AlignTopLeft/KnightCommands/Bless",0);
        end
    end

    function Mission_SupportUpdateTimer()
        local widget = XGUIEng.GetCurrentWidgetID();
        XGUIEng.ShowWidget(widget,0);
    end    

    --~~~~~~~~~~~~~~~
    -- Menükontrolle
    --~~~~~~~~~~~~~~~

    if not g_SpellcasterControlJob then
        g_SpellcasterControlJob = StartSimpleHiResJob("SPELLCASTER_HERO_LOOP");
    end

    if not GUI_Knight.StartAbilityMouseOver_OrigSPELLCASTER then
        GUI_Knight.StartAbilityMouseOver_OrigSPELLCASTER = GUI_Knight.StartAbilityMouseOver;
            GUI_Knight.StartAbilityMouseOver = function()
            local lang = (Network.GetDesiredLanguage() == "de" and "de") or "en";
            local wID =  XGUIEng.GetCurrentWidgetID();
            local eID = GUI.GetSelectedEntity();

            for k,v in pairs(g_SpellcasterList) do
                if eID == GetID(v.Name) then
                    if not v.isWarrior then
                        if v.Menu == 1 then
                            local descTitle = (lang == "de" and "Zauberbuch betrachten") or "Consider spellbook";
                            local descText  = (lang == "de" and "Öffnet das Zauberbuch dieses Zauberers.") or "Open the grimoire of this magician.";
                            UserSetTextNormal(descTitle,descText);
                        elseif v.Menu == 2 then
                            local descTitle = (lang == "de" and "Zurück zur Selektion") or "Back to selection";
                            local descText  = (lang == "de" and "Schließt das Zauberbuch dieses Zauberers.") or "Close the grimoire of this magician.";
                            UserSetTextNormal(descTitle,descText);
                        end
                    else
                        if eID == GetID(v.Name) and v.isWarrior then
                            UserSetTextNormal(v.Ability.Description.Title[lang],v.Ability.Description.Text[lang]);
                            return;
                        end
                    end
                    return;
                end
            end
            GUI_Knight.StartAbilityMouseOver_OrigSPELLCASTER();
        end
    end

    if not GUI_Knight.StartAbilityClicked_OrigSPELLCASTER then
        GUI_Knight.StartAbilityClicked_OrigSPELLCASTER = GUI_Knight.StartAbilityClicked;
            GUI_Knight.StartAbilityClicked = function(_Ability)
            local eID = GUI.GetSelectedEntity();
            for k,v in pairs(g_SpellcasterList) do
                if eID == GetID(v.Name) then
                    if not v.isWarrior then
                        if v.Menu == 1 then
                            XGUIEng.ShowWidget("/InGame/Root/Normal/AlignBottomRight/DialogButtons/Knight/ClaimTerritory",1);
                            v.Menu = 2;
                        elseif v.Menu == 2 then
                            if Logic.GetKnightID(GUI.GetPlayerID()) ~= GetID(v.Name) then
                                XGUIEng.ShowWidget("/InGame/Root/Normal/AlignBottomRight/DialogButtons/Knight/ClaimTerritory",0);
                            end
                            v.Menu = 1;
                        end
                    else
                        assert(type(v.Ability.Action) == "function");
                        if v.Stats.Mana.Current == v.Stats.Mana.Max then
                            v.Stats.Mana.Current = 0;
                            v.Ability.Action(v);
                        end
                    end
                    return;
                end
            end
            GUI_Knight.StartAbilityClicked_OrigSPELLCASTER(_Ability);
        end
    end

    if not GUI_Knight.StartAbilityUpdate_OrigSPELLCASTER then
        GUI_Knight.StartAbilityUpdate_OrigSPELLCASTER = GUI_Knight.StartAbilityUpdate;
        GUI_Knight.StartAbilityUpdate = function()
            local wID = XGUIEng.GetCurrentWidgetID();
            local eID = GUI.GetSelectedEntity();

            for k,v in pairs(g_SpellcasterList) do
                if eID == GetID(v.Name) then
                    if not v.isWarrior then
                        XGUIEng.DisableButton(wID,0);
                        if v.Menu == 1 then
                            SetIcon(wID,{16,10});
                        elseif v.Menu == 2 then
                            SetIcon(wID,{16,5});
                        end
                        found = true;
                    else
                        if v.Stats.Mana.Current == v.Stats.Mana.Max then 
                            XGUIEng.DisableButton(wID,0);
                        else
                            XGUIEng.DisableButton(wID,1);
                        end
                        SetIcon(wID,v.Ability.Icon);
                    end
                    return;
                end
            end
            GUI_Knight.StartAbilityUpdate_OrigSPELLCASTER();
        end
    end

    --~~~~~~~~
    -- Slot 1
    --~~~~~~~~

    if not GUI_Knight.ClaimTerritoryMouseOver_OrigSPELLCASTER then
        GUI_Knight.ClaimTerritoryMouseOver_OrigSPELLCASTER = GUI_Knight.ClaimTerritoryMouseOver;
        GUI_Knight.ClaimTerritoryMouseOver = function()
            local lang = (Network.GetDesiredLanguage() == "de" and "de") or "en";
            local wID =  XGUIEng.GetCurrentWidgetID();
            local eID = GUI.GetSelectedEntity();

            for k,v in pairs(g_SpellcasterList) do
                if eID == GetID(v.Name) then
                    if v.Menu == 2 then
                        if v.Spells.Slot1 then
                            local cost, mana, max, type;
                            if lang == "de" then
                                cost = v.Spells.Slot1.Cost;
                                mana = v.Stats.Mana.Current;
                                max  = v.Stats.Mana.Max;
                                type = "Typ: "..((Spells:isInCategory(v.Spells.Slot1.Name,"RangedEffect") and "Bereichsschaden")
                                                or (Spells:isInCategory(v.Spells.Slot1.Name,"Summon") and "Beschwörungsmagie") or "Direktzauber");
                                desc = type.." {cr}Kosten: "..cost.." {cr}Zauberpunkte: "..mana.."/"..max.." {cr}";
                            else
                                cost = v.Spells.Slot1.Cost;
                                mana = v.Stats.Mana.Current;
                                max  = v.Stats.Mana.Max;
                                type = "Type: "..((Spells:isInCategory(v.Spells.Slot1.Name,"RangedEffect") and "Area Damage")
                                                or (Spells:isInCategory(v.Spells.Slot1.Name,"Summon") and "Summoning") or "Direct Spell");
                                desc = type.." {cr}Costs: "..cost.." {cr}Spell Points: "..mana.."/"..max.." {cr}";
                            end
                            UserSetTextBuy(v.Spells.Slot1.Title[lang],desc .. v.Spells.Slot1.Text[lang],nil,{},false);
                        else
                            if IsNear(v.Name,v.HomeEntity,v.HomeDistance) then
                                UserSetTextBuy((lang == "de" and "Verfügbare Zauber:") or "Available spells:",v:getAvailableSpells(),nil,{},false);
                            else
                                UserSetTextBuy("",(lang == "de" and "Kein Zauber verfügbar!") or "No active spell!",nil,{},false);
                            end
                        end
                        return;
                    end
                end
            end
            GUI_Knight.ClaimTerritoryMouseOver_OrigSPELLCASTER()
        end
    end

    if not GUI_Knight.ClaimTerritoryClicked_OrigSPELLCASTER then
        GUI_Knight.ClaimTerritoryClicked_OrigSPELLCASTER = GUI_Knight.ClaimTerritoryClicked;
        GUI_Knight.ClaimTerritoryClicked = function()
            local lang = (Network.GetDesiredLanguage() == "de" and "de") or "en";
            local eID = GUI.GetSelectedEntity();
            for k,v in pairs(g_SpellcasterList) do
                if eID == GetID(v.Name) then
                    if v.Menu == 2 then
                        if IsNear(v.Name,v.HomeEntity,v.HomeDistance) then
                            v:switchSpell(1);
                        else
                            if v.Spells.Slot1 then
                                if v.Spells:isInCategory(v.Spells.Slot1.Name,"Direct") then
                                    v:direct(v.Spells.Slot1);
                                else
                                    v.Spells.Slot1:action(v);
                                end
                                return;
                            end
                            Message(Umlaute((lang == "de" and "Kein Zauber verfügbar!") or "No spells available"));
                        end
                        return;
                    end
                end
            end
            GUI_Knight.ClaimTerritoryClicked_OrigSPELLCASTER(_Ability);
        end
    end

    if not GUI_Knight.ClaimTerritoryUpdate_OrigSPELLCASTER then
        GUI_Knight.ClaimTerritoryUpdate_OrigSPELLCASTER = GUI_Knight.ClaimTerritoryUpdate;
        GUI_Knight.ClaimTerritoryUpdate = function()
            local wID = XGUIEng.GetCurrentWidgetID();
            local eID = GUI.GetSelectedEntity();

            for k,v in pairs(g_SpellcasterList) do
                if eID == GetID(v.Name) then
                    if v.Menu == 2 then
                        XGUIEng.ShowWidget(wID,1);
                        XGUIEng.DisableButton(wID,0);
                        if v.Spells.Slot1 then
                            if type(v.Spells.Slot1.Icon) == "table" then
                                SetIcon(wID,v.Spells.Slot1.Icon);
                            else
                                UserSetTexture(wID,v.Spells.Slot1.Icon);
                            end
                        else
                            SetIcon(wID,{16,16});
                        end
                        return;
                    end
                end
            end
            GUI_Knight.ClaimTerritoryUpdate_OrigSPELLCASTER()
            SetIcon(wID,{12,3});
        end
    end

    --~~~~~~~~~~~~~~
    -- Slot 2 und 3
    --~~~~~~~~~~~~~~

    if not GUI_Military.StandGroundClicked_OrigSPELLCASTER then
        GUI_Military.StandGroundClicked_OrigSPELLCASTER = GUI_Military.StandGroundClicked;
        GUI_Military.StandGroundClicked = function()
            local lang = (Network.GetDesiredLanguage() == "de" and "de") or "en";
            for k,v in pairs(g_SpellcasterList) do
                local eID = GUI.GetSelectedEntity();
                if eID == GetID(v.Name) then
                    if v.Menu == 2 then
                        if IsNear(v.Name,v.HomeEntity,v.HomeDistance) then
                            v:switchSpell(2);
                        else
                            if v.Spells.Slot2 then
                                if v.Spells:isInCategory(v.Spells.Slot2.Name,"Direct") then
                                    v:direct(v.Spells.Slot2);
                                else
                                    v.Spells.Slot2:action(v);
                                end
                                return;
                            end
                            Message(Umlaute((lang == "de" and "Kein Zauber verfügbar!") or "No spells available!"));
                        end
                        return;
                    end
                end
            end
            GUI_Military.StandGroundClicked_OrigSPELLCASTER();
        end

        GUI_Military.StandGroundUpdate = function()
            local wNa = "/InGame/Root/Normal/AlignBottomRight/DialogButtons/Military/Attack"
            local wID = XGUIEng.GetCurrentWidgetID();
            local eID = GUI.GetSelectedEntity();

            for k,v in pairs(g_SpellcasterList) do
                if eID == GetID(v.Name) then
                    if v.Menu == 1 then
                        SetIcon(wNa,{11,2});
                        SetIcon(wID,{12,2});
                        if IsNear(v.Name,v.HomeEntity,v.HomeDistance)then
                            if v.Perks.Alchemist then
                                XGUIEng.DisableButton(wNa,0);
                            else
                                XGUIEng.DisableButton(wNa,1); 
                            end
                        else
                            XGUIEng.DisableButton(wNa,0);
                        end
                        return;
                    else
                        XGUIEng.DisableButton(wNa,0);
                        XGUIEng.DisableButton(wID,0);
                        if v.Spells.Slot2 then
                            if type(v.Spells.Slot2.Icon) == "table" then
                                SetIcon(wID,v.Spells.Slot2.Icon);
                            else
                                UserSetTexture(wID,v.Spells.Slot2.Icon);
                            end
                        else
                            SetIcon(wID,{16,16});
                        end

                        if v.Spells.Slot3 then
                            if type(v.Spells.Slot3.Icon) == "table" then
                                SetIcon(wNa,v.Spells.Slot3.Icon);
                            else
                                UserSetTexture(wNa,v.Spells.Slot3.Icon);
                            end
                        else
                            SetIcon(wNa,{16,16});
                        end

                        return;
                    end
                end
            end
            XGUIEng.DisableButton(wNa,0);
            SetIcon(wNa,{12,4});
            SetIcon(wID,{12,2});
        end
    end

    --~~~~~~~~
    -- Slot 3
    --~~~~~~~~

    function GUI_Military.AttackClicked()
        local lang = (Network.GetDesiredLanguage() == "de" and "de") or "en";
        local eID = GUI.GetSelectedEntity();
        for k,v in pairs(g_SpellcasterList) do
            if eID == GetID(v.Name) then
                if v.Menu == 1 then
                    if IsNear(v.Name,v.HomeEntity,v.HomeDistance) then
                        local costs = {v.Potion.GoldCost,v.Potion.HerbCost};
                        if v.Perks.GoodAlchemist then
                            costs[1] = costs[1] - math.floor((costs[1]/100)*20);
                            costs[2] = costs[2] - math.floor((costs[2]/100)*20);
                        end
                        if  GetPlayerResources(Goods.G_Gold,GUI.GetPlayerID()) >= v.Potion.GoldCost
                        and GetPlayerResources(Goods.G_Herb,GUI.GetPlayerID()) >= v.Potion.HerbCost then
                            GUI.SendScriptCommand("AddGood(Goods.G_Gold,"..(costs[1]*(-1))..","..GUI.GetPlayerID()..")");
                            GUI.SendScriptCommand("AddGood(Goods.G_Herb,"..(costs[2]*(-1))..","..GUI.GetPlayerID()..")");
                            Spellcaster.Potion.Amount = Spellcaster.Potion.Amount +1;
                        else
                            Message((lang == "de" and "Nicht genügend Rohstoffe um Manatränke herzustellen!") or "Not enough resources to"..
                                    " produce mana potions!");
                        end
                    else
                        if Spellcaster.Potion.Amount > 0 then
                            v.Stats.Mana.Current = v.Stats.Mana.Max;
                            Spellcaster.Potion.Amount = Spellcaster.Potion.Amount -1;
                            local X,Y,Z = Logic.EntityGetPos(GetID(v.Name))
                            GUI.SendScriptCommand("Logic.CreateEffect(EGL_Effects.E_LvlUp,"..X..","..Y..",0)");
                        else
                            Message((lang == "de" and "Keine Manatränke mehr vorhanden!") or "You do not have any mana potions!");
                        end
                    end
                    return;
                else
                    if IsNear(v.Name,v.HomeEntity,v.HomeDistance) then
                            v:switchSpell(3);
                        else
                        if v.Spells.Slot3 then
                            if v.Spells:isInCategory(v.Spells.Slot3.Name,"Direct") then
                                v:direct(v.Spells.Slot3);
                            else
                                v.Spells.Slot3:action(v);
                            end
                            return;
                        end
                        Message(Umlaute((lang == "de" and "Kein Zauber verfügbar!") or "No spell available!"));
                    end
                    return;
                end
            end
        end
        Sound.FXPlay2DSound( "ui\\menu_click")
        GUI.ActivateExplicitAttackCommandState()
    end

    --~~~~~~~~
    -- Slot 4
    --~~~~~~~~

    if not GUI_Military.DismountClicked_OrigSPELLCASTER then
        GUI_Military.DismountClicked_OrigSPELLCASTER = GUI_Military.DismountClicked;
        GUI_Military.DismountClicked = function()
            local lang = (Network.GetDesiredLanguage() == "de" and "de") or "en";
            local eID = GUI.GetSelectedEntity();
            for k,v in pairs(g_SpellcasterList) do
                if eID == GetID(v.Name) then
                    if v.Menu == 2 then
                        if IsNear(v.Name,v.HomeEntity,v.HomeDistance) then
                            v:switchSpell(4);
                        else
                            if v.Spells.Slot4 then
                                if v.Spells:isInCategory(v.Spells.Slot4.Name,"Direct") then
                                    v:direct(v.Spells.Slot4);
                                else
                                    v.Spells.Slot4:action(v);
                                end
                                return;
                            end
                            Message(Umlaute((lang == "de" and "Kein Zauber verfügbar!") or "No spell available!"));
                        end
                        return;
                    end
                end
            end
            GUI_Military.DismountClicked_OrigSPELLCASTER();
        end
    end

    if not GUI_Military.DismountUpdate_OrigSPELLCASTER then
        GUI_Military.DismountUpdate_OrigSPELLCASTER = GUI_Military.DismountUpdate;
        GUI_Military.DismountUpdate = function()
            local wID = XGUIEng.GetCurrentWidgetID();
            local eID = GUI.GetSelectedEntity();

            for k,v in pairs(g_SpellcasterList) do
                if eID == GetID(v.Name) then
                    if v.Menu == 2 then
                        XGUIEng.DisableButton(wID,0);
                        if v.Spells.Slot4 then
                            if type(v.Spells.Slot4.Icon) == "table" then
                                SetIcon(wID,v.Spells.Slot4.Icon);
                            else
                                UserSetTexture(wID,v.Spells.Slot4.Icon);
                            end
                        else
                            SetIcon(wID,{16,16});
                        end
                        return;
                    end
                end
            end
            GUI_Military.DismountUpdate_OrigSPELLCASTER();
            SetIcon(wID,{12,1});
        end
    end    

    --~~~~~~~~~~~~~~~~~
    -- Slot 2, 3 und 4
    --~~~~~~~~~~~~~~~~~

    if not GUI_MultiSelection.IconMouseOver_OrigSPELLCASTER then
        GUI_MultiSelection.IconMouseOver_OrigSPELLCASTER = GUI_MultiSelection.IconMouseOver;
        GUI_MultiSelection.IconMouseOver = function()
            local lang = (Network.GetDesiredLanguage() == "de" and "de") or "en";
            local CurrentWidgetID = XGUIEng.GetCurrentWidgetID()    
            local CurrentMotherID = XGUIEng.GetWidgetsMotherID(CurrentWidgetID)
            local CurrentMotherName = XGUIEng.GetWidgetNameByID(CurrentMotherID)
            local Index = tonumber(CurrentMotherName)
            local EntityID = g_MultiSelection.EntityList[Index]
            local eType = Logic.GetEntityType(EntityID)
            local eTypeName = Logic.GetEntityTypeName(eType)

            for k,v in pairs(g_SpellcasterList)do
                if EntityID == GetID(v.Name) then
                    local gender = KnightGender[eType];
                    local active;
                    if not v.isWarrior then
                        if lang == "de" then
                            active = (gender == nil and "Magier") or (gender == "male" and "Magier") or "Magierin";
                        else
                            active = (gender == nil and "Magician") or (gender == "male" and "Magician") or "Sorceress";
                        end

                        local first = true;
                        for i=1,4 do
                            if v.Spells["Slot"..i] and v.Spells["Slot"..i].Title then
                                if first then
                                    active = (lang == "de" and "Aktive Zauber:") or "Active spells:";
                                    first = false;
                                end
                                active = active .. "{cr}- "..v.Spells["Slot"..i].Title[lang];
                            end
                        end
                    else
                        if lang == "de" then
                            active = (gender == nil and "Krieger") or (gender == "male" and "Krieger") or "Kriegerin";
                        else
                            active = "Warrior";
                        end
                    end
                    UserSetTextNormal(XGUIEng.GetStringTableText("Names/" .. eTypeName),active,nil)
                    return;
                end
            end
            GUI_MultiSelection.IconMouseOver_OrigSPELLCASTER();
        end
    end

    if not GUI_Tooltip.SetNameAndDescription_OrigSPELLCASTER then
        GUI_Tooltip.SetNameAndDescription_OrigSPELLCASTER = GUI_Tooltip.SetNameAndDescription
        GUI_Tooltip.SetNameAndDescription = function(_TooltipNameWidget, _TooltipDescriptionWidget, _OptionalTextKeyName, _OptionalDisabledTextKeyName, _OptionalMissionTextFileBoolean)
            GUI_Tooltip.SetNameAndDescription_OrigSPELLCASTER(_TooltipNameWidget, _TooltipDescriptionWidget, _OptionalTextKeyName, _OptionalDisabledTextKeyName, _OptionalMissionTextFileBoolean)
            local lang = (Network.GetDesiredLanguage() == "de" and "de") or "en";
            local wID = XGUIEng.GetCurrentWidgetID();
            local eID = GUI.GetSelectedEntity();

            for k,v in pairs(g_SpellcasterList) do
                if eID == GetID(v.Name) then
                    if v.Menu == 1 then
                        if XGUIEng.GetWidgetPathByID(wID) == "/InGame/Root/Normal/AlignBottomRight/DialogButtons/Military/Attack" then
                            if IsNear(v.Name,v.HomeEntity,v.HomeDistance) then
                                local costs = {v.Potion.GoldCost,v.Potion.HerbCost};
                                if v.Perks.GoodAlchemist then
                                    costs[1] = costs[1] - math.floor((costs[1]/100)*20);
                                    costs[2] = costs[2] - math.floor((costs[2]/100)*20);
                                end
                                local costString = "Benötigtes Gold: "..costs[1].."{cr}Benötigte Kräuter: "..costs[2].."{cr}";
                                local amount = "Verfügbar: "..Spellcaster.Potion.Amount.." {cr}";
                                UserSetTextNormal("Manatrank herstellen",costString .. amount .. "Alle hergestellten Manatränke werden zu Eurem"..
                                                    " Reservoir addiert. Alle Eure Zauberer nutzen das selbe Reservoir.");
                                if lang ~= "de" then
                                    costString = "Needed money: "..costs[1].."{cr}Needed herbs: "..costs[2].."{cr}";
                                    amount = "Available: "..Spellcaster.Potion.Amount.." {cr}";
                                    UserSetTextNormal("Produce Mana Potion",costString .. amount .. "All produces mana potions will be added to"..
                                                        " the players potion stock. All of your magicians use the same stock.");
                                end
                            else
                                local desc = {title = "", text = ""};
                                if v.isWarrior then
                                    desc.title = (lang == "de" and "Magische Heilung") or "Magical Cure";
                                    desc.text = (lang == "de" and "Manatränke stellen bei einem Krieger die Lebenskraft anstelle der Zauberpunkte"..
                                                " wieder her. Helden nutzen das selbe Reservoir.") or "For a warrior mana potions regain the health"..
                                                " instad of the spell points. All heroes are using the same stock";
                                else
                                    desc.title = (lang == "de" and "Manatrank trinken") or "Drink Mana Potion";
                                    desc.text = (lang == "de" and "Manatränke stellen sofort alle Zauberpunkte des Zauberers wieder her. Alle Zauberer"..
                                                " nutzen das selbe Reservoir.") or "Mana potions can refill all spell points of a magician. All heroes"..
                                                " are using the same stock.";
                                end

                                local amount = "Verfügbar: "..Spellcaster.Potion.Amount.." {cr}";
                                UserSetTextNormal(desc.title,amount .. desc.text);
                            end
                        end
                    else
                        if XGUIEng.GetWidgetPathByID(wID) == "/InGame/Root/Normal/AlignBottomRight/DialogButtons/Military/StandGround" then
                            if IsNear(v.Name,v.HomeEntity,v.HomeDistance) then
                                UserSetTextNormal((lang == "de" and "Verfügbare Zauber:") or "Available spells:",v:getAvailableSpells());
                            else
                                UserSetTextNormal("",(lang == "de" and "Kein Zauber verfügbar!") or "No active spell!");
                            end
                            if v.Spells.Slot2 then
                                local cost, mana, max, type;
                                if lang == "de" then
                                    cost = v.Spells.Slot2.Cost;
                                    mana = v.Stats.Mana.Current;
                                    max  = v.Stats.Mana.Max;
                                    type = "Typ: "..((Spells:isInCategory(v.Spells.Slot2.Name,"RangedEffect") and "Bereichsschaden")
                                                    or (Spells:isInCategory(v.Spells.Slot2.Name,"Summon") and "Beschwörungsmagie") or "Direktzauber");
                                    desc = type.." {cr}Kosten: "..cost.." {cr}Zauberpunkte: "..mana.."/"..max.." {cr}";
                                else
                                    cost = v.Spells.Slot2.Cost;
                                    mana = v.Stats.Mana.Current;
                                    max  = v.Stats.Mana.Max;
                                    type = "Type: "..((Spells:isInCategory(v.Spells.Slot2.Name,"RangedEffect") and "Area Damage")
                                                    or (Spells:isInCategory(v.Spells.Slot2.Name,"Summon") and "Summoning") or "Direct Spell");
                                    desc = type.." {cr}Costs: "..cost.." {cr}Spell Points: "..mana.."/"..max.." {cr}";
                                end
                                UserSetTextNormal(v.Spells.Slot2.Title[lang],desc .. v.Spells.Slot2.Text[lang]);
                            end

                        elseif XGUIEng.GetWidgetPathByID(wID) == "/InGame/Root/Normal/AlignBottomRight/DialogButtons/Military/Attack" then
                            if IsNear(v.Name,v.HomeEntity,v.HomeDistance) then
                                UserSetTextNormal((lang == "de" and "Verfügbare Zauber:") or "Available spells:",v:getAvailableSpells());
                            else
                                UserSetTextNormal("",(lang == "de" and "Kein Zauber verfügbar!") or "No active spell!");
                            end
                            if v.Spells.Slot3 then
                                local cost, mana, max, type;
                                if lang == "de" then
                                    cost = v.Spells.Slot3.Cost;
                                    mana = v.Stats.Mana.Current;
                                    max  = v.Stats.Mana.Max;
                                    type = "Typ: "..((Spells:isInCategory(v.Spells.Slot3.Name,"RangedEffect") and "Bereichsschaden")
                                                    or (Spells:isInCategory(v.Spells.Slot3.Name,"Summon") and "Beschwörungsmagie") or "Direktzauber");
                                    desc = type.." {cr}Kosten: "..cost.." {cr}Zauberpunkte: "..mana.."/"..max.." {cr}";
                                else
                                    cost = v.Spells.Slot3.Cost;
                                    mana = v.Stats.Mana.Current;
                                    max  = v.Stats.Mana.Max;
                                    type = "Type: "..((Spells:isInCategory(v.Spells.Slot3.Name,"RangedEffect") and "Area Damage")
                                                    or (Spells:isInCategory(v.Spells.Slot3.Name,"Summon") and "Summoning") or "Direct Spell");
                                    desc = type.." {cr}Costs: "..cost.." {cr}Spell Points: "..mana.."/"..max.." {cr}";
                                end
                                UserSetTextNormal(v.Spells.Slot3.Title[lang],desc .. v.Spells.Slot3.Text[lang]);
                            end

                        elseif XGUIEng.GetWidgetPathByID(wID) == "/InGame/Root/Normal/AlignBottomRight/DialogButtons/Military/Dismount" then
                            if IsNear(v.Name,v.HomeEntity,v.HomeDistance) then
                                UserSetTextNormal((lang == "de" and "Verfügbare Zauber:") or "Available spells:",v:getAvailableSpells());
                            else
                                UserSetTextNormal("",(lang == "de" and "Kein Zauber verfügbar!") or "No active spell!");
                            end
                            if v.Spells.Slot4 then
                                local cost, mana, max, type;
                                if lang == "de" then
                                    cost = v.Spells.Slot4.Cost;
                                    mana = v.Stats.Mana.Current;
                                    max  = v.Stats.Mana.Max;
                                    type = "Typ: "..((Spells:isInCategory(v.Spells.Slot4.Name,"RangedEffect") and "Bereichsschaden")
                                                    or (Spells:isInCategory(v.Spells.Slot4.Name,"Summon") and "Beschwörungsmagie") or "Direktzauber");
                                    desc = type.." {cr}Kosten: "..cost.." {cr}Zauberpunkte: "..mana.."/"..max.." {cr}";
                                else
                                    cost = v.Spells.Slot4.Cost;
                                    mana = v.Stats.Mana.Current;
                                    max  = v.Stats.Mana.Max;
                                    type = "Type: "..((Spells:isInCategory(v.Spells.Slot4.Name,"RangedEffect") and "Area Damage")
                                                    or (Spells:isInCategory(v.Spells.Slot4.Name,"Summon") and "Summoning") or "Direct Spell");
                                    desc = type.." {cr}Costs: "..cost.." {cr}Spell Points: "..mana.."/"..max.." {cr}";
                                end
                                UserSetTextNormal(v.Spells.Slot4.Title[lang],desc .. v.Spells.Slot4.Text[lang]);
                            end
                        end
                    end

                    local currentLP = v.Stats.Learnpoints;
                    local costString = "Benötigte Lernpunkte: 1 {cr}Verfügbare Lernpunkte: "..currentLP.." {cr}"
                    if wID == XGUIEng.GetWidgetID(v.Training.Recharge.Button) then
                        local descTitle = (lang == "de" and "Regeneration") or "Regeneration";
                        local descText  = (lang == "de" and costString.."Senkt die benötigte Zeit um Zauberpunkte zu regenerieren.") or costString..""..
                                            "Decrease the time needed for generating new spell points.";
                        if v.isWarrior then
                            descTitle = (lang == "de" and "Angriffskraft") or "Attack Strength";
                            descText  = (lang == "de" and costString.."Erhöht die Angriffskraft des Kriegers.") or costString..""..
                                            "Increase the attack strength of the warrior.";
                        end
                        UserSetTextNormal(descTitle,descText);

                    elseif wID == XGUIEng.GetWidgetID(v.Training.Spellpoints.Button) then
                        local descTitle = (lang == "de" and "Zauberpunkte") or "Spell Points";
                        local descText  = (lang == "de" and costString.."Steigert das Maximum an Zauberpunkten des Zauberer.") or costString..""..
                                            "Increase the maximum of spell points of this magician.";
                        if v.isWarrior then
                            descTitle = (lang == "de" and "Verteidigungsfähigkeit") or "Defence Skills";
                            descText  = (lang == "de" and costString.."Erhöht die Verteidigung des Kriegers.") or costString..""..
                                            "Improve the defence skill of the warrior.";
                        end
                        UserSetTextNormal(descTitle,descText);

                    elseif wID == XGUIEng.GetWidgetID(v.Training.Effectivity.Button) then
                        local descTitle = (lang == "de" and "Reichweite") or "Distance";
                        local descText  = (lang == "de" and costString.."Erhöht die maximale Distanz aus der Zauber gewirkt werden können.") or costString..""..
                                            "Increase the discance the magician can cast a spell.";
                        if v.isWarrior then
                            descTitle = (lang == "de" and "Heilrate") or "Healing rate";
                            descText  = (lang == "de" and costString.."Erhöht die Anzahl an Lebensenergie, die regeneriert wird.") or costString..""..
                                            "Increase the amount on health a warrior can regain.";
                        end
                        UserSetTextNormal(descTitle,descText);
                    end
                end
            end
        end
    end

    --~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    -- Passisve Fähigkeit Roter Prinz
    --~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    -- Auf Grund von Inkompatiblität zum Hero-Mod.

    g_RPupgradeWoodCosts                  = {
        [Entities.B_Bakery]              = {4,2},
        [Entities.B_Dairy]               = {4,2},
        [Entities.B_Butcher]             = {4,2},
        [Entities.B_SmokeHouse]          = {4,2},
        [Entities.B_Soapmaker]           = {4,2},
        [Entities.B_BroomMaker]          = {4,2},
        [Entities.B_Pharmacy]            = {4,2},
        [Entities.B_Weaver]              = {4,2},
        [Entities.B_Tanner]              = {4,2},
        [Entities.B_Baths]               = {7,2},
        [Entities.B_Tavern]              = {7,2},
        [Entities.B_Theatre]             = {7,2},
        [Entities.B_SwordSmith]          = {8,2},
        [Entities.B_BowMaker]            = {8,2},
        [Entities.B_Barracks]            = {8,2},
        [Entities.B_BarracksArchers]     = {8,2},
        [Entities.B_SiegeEngineWorkshop] = {8,2},
        [Entities.B_Blacksmith]          = {7,2},
        [Entities.B_CandleMaker]         = {7,2},
        [Entities.B_Carpenter]           = {7,2},
        [Entities.B_BannerMaker]         = {7,2},

        [Entities.B_HerbGatherer]        = {2,1},
        [Entities.B_Woodcutter]          = {2,1},
        [Entities.B_StoneQuarry]         = {2,1},
        [Entities.B_IronMine]            = {2,1},
        [Entities.B_HuntersHut]          = {2,1},
        [Entities.B_FishingHut]          = {2,1},
        [Entities.B_CattleFarm]          = {3,1},
        [Entities.B_GrainFarm]           = {3,1},
        [Entities.B_SheepFarm]           = {3,1},
        [Entities.B_Beekeeper]           = {3,1},
    }

    if not GUI_BuildingButtons.GetUpgradeCosts_OrigSPELLCASTER then
        GUI_BuildingButtons.GetUpgradeCosts_OrigSPELLCASTER = GUI_BuildingButtons.GetUpgradeCosts;
        GUI_BuildingButtons.GetUpgradeCosts = function()
            local pID = GUI.GetPlayerID();
            if Logic.GetEntityType(Logic.GetKnightID(pID)) == Entities.U_KnightRedPrince then
                local EntityID = GUI.GetSelectedEntity()
                local UpgradeLevel = Logic.GetUpgradeLevel(EntityID)+1
                local StoneCost = Logic.GetBuildingUpgradeCostByGoodType(EntityID , Goods.G_Stone, 0);
                local GoldCost = Logic.GetBuildingUpgradeCostByGoodType(EntityID , Goods.G_Gold, 0);
                local WoodCost;

                if g_RPupgradeWoodCosts[Logic.GetEntityType(EntityID)] ~= nil then
                    local baseCosts = g_RPupgradeWoodCosts[Logic.GetEntityType(EntityID)][1];
                    local incrCosts = g_RPupgradeWoodCosts[Logic.GetEntityType(EntityID)][2];
                    WoodCost = baseCosts + (incrCosts*UpgradeLevel);
                else
                    WoodCost = Logic.GetBuildingUpgradeCostByGoodType(EntityID , Goods.G_Wood, 0);
                end

                local Costs = {Goods.G_Gold, GoldCost, Goods.G_Stone, StoneCost, Goods.G_Wood, WoodCost};
                return Costs;
            else
                return GUI_BuildingButtons.GetUpgradeCosts_OrigSPELLCASTER()
            end
        end

        function GameCallback_Feedback_TaxCollectionFinished(_PlayerID, _TotalTaxAmountCollected, _AdditionalTaxesByAbility)
            if _PlayerID == GUI.GetPlayerID() then
                if  Logic.GetCurrentTurn() > 10 then
                    if _TotalTaxAmountCollected > 0 then
                        local AmountWithoutAdditional = _TotalTaxAmountCollected - _AdditionalTaxesByAbility
                        GUI_FeedbackWidgets.GoldAdd(AmountWithoutAdditional, nil)
                        if _AdditionalTaxesByAbility > 0 then
                            GUI_FeedbackWidgets.GoldAdd(_AdditionalTaxesByAbility, Logic.GetKnightID(_PlayerID))
                            StartKnightVoiceForPermanentSpecialAbility(Entities.U_KnightPlunder)
                        else
                            if Logic.GetEntityType(Logic.GetKnightID(_PlayerID)) == Entities.U_KnightRedPrince then
                                local cityWorkers = Logic.GetNumberOfEmployedCityWorkers(_PlayerID)
                                local spouses = Logic.GetNumberOfSpouses(_PlayerID)
                                local bonusOnTax = (cityWorkers)+(spouses*5)
                                StartKnightVoiceForPermanentSpecialAbility(Entities.U_KnightRedPrince)
                                GUI.SendScriptCommand("AddGood(Goods.G_Gold,"..bonusOnTax..",".._PlayerID..")")
                                GUI_FeedbackWidgets.GoldAdd(bonusOnTax,nil,{6,8})
                            end
                        end
                    end

                    local SoldierAmount = Logic.GetCurrentSoldierCount(_PlayerID)
                    local PaymentLevel    = PlayerSoldierPaymentLevel[_PlayerID]
                    local PayPerSoldier = SoldierPay[PaymentLevel]
                    local AmountToPay = SoldierAmount * PayPerSoldier
                    if AmountToPay > 0 then
                        AmountToPay = AmountToPay * -1
                        GUI_FeedbackWidgets.GoldAdd(AmountToPay, nil, {1, 7})
                    end
                end
            end
        end

        function GUI_BuildingButtons.UpgradeClicked()
            local EntityID = GUI.GetSelectedEntity();

            if Logic.CanCancelUpgradeBuilding(EntityID) then
                Sound.FXPlay2DSound("ui\\menu_click");
                GUI.CancelBuildingUpgrade(EntityID);
                XGUIEng.ShowAllSubWidgets("/InGame/Root/Normal/BuildingButtons",1);
                return
            end

            local Costs = GUI_BuildingButtons.GetUpgradeCosts();
            local CanBuyBoolean, CanNotBuyString = AreCostsAffordable(Costs);
            local pID = GUI.GetPlayerID();

            if CanBuyBoolean == true then
                Sound.FXPlay2DSound("ui\\menu_click");
                GUI.UpgradeBuilding(EntityID, UpgradePart);

                if Logic.GetEntityType(Logic.GetKnightID(pID)) == Entities.U_KnightRedPrince then
                    if g_RPupgradeWoodCosts[Logic.GetEntityType(EntityID)] ~= nil then
                        local normCosts = Logic.GetBuildingUpgradeCostByGoodType(EntityID , Goods.G_Wood, 0);
                        local baseCosts = g_RPupgradeWoodCosts[Logic.GetEntityType(EntityID)][1];
                        local incrCosts = g_RPupgradeWoodCosts[Logic.GetEntityType(EntityID)][2];
                        local UpgradeLevel = Logic.GetUpgradeLevel(EntityID)+1;
                        local fullCosts = baseCosts + (incrCosts*UpgradeLevel);
                        local toSubtract = fullCosts - normCosts;

                        if toSubtract > 0 then
                            GUI.SendScriptCommand("RemoveResourcesFromPlayer(Goods.G_Wood,"..toSubtract..","..pID..")");
                        end
                    end
                end
                StartKnightVoiceForPermanentSpecialAbility(Entities.U_KnightWisdom);

                if XGUIEng.GetCurrentWidgetID() ~= 0 then
                    SaveButtonPressed(XGUIEng.GetCurrentWidgetID());
                end
            else
                Message(CanNotBuyString);
            end
        end
    end

    --~~~~~~~~~~~~~~~~~~~~~~~~~~~
    -- Passisve Fähigkeit Sabatt
    --~~~~~~~~~~~~~~~~~~~~~~~~~~~
    -- Auf Grund von Inkompatiblität zum Hero-Mod.

    if not ComputePrice_OrigSPELLCASTER then
        ComputePrice_OrigSPELLCASTER = ComputePrice;
        ComputePrice = function(BuildingID,OfferID,PlayerID,TraderType)
            if Logic.GetEntityType(Logic.GetKnightID(GUI.GetPlayerID())) ~= Entities.U_KnightSabatta then
                return ComputePrice_OrigSPELLCASTER(BuildingID,OfferID,PlayerID,TraderType)
            else
                local TraderPlayerID = Logic.EntityGetPlayer(BuildingID)
                local Type = Logic.GetGoodOfOffer(BuildingID, OfferID, PlayerID, TraderType)
                local BasePrice = (MerchantSystem.BasePrices[Type] or 3)
                local TraderAbility = 1.25
                BasePrice = math.ceil(BasePrice / TraderAbility)

                local OfferCount = Logic.GetOfferCount(BuildingID, OfferID, PlayerID, TraderType)
                if OfferCount > 8 then OfferCount = 8 end

                local Modifier = math.ceil(BasePrice / 4)
                local Result = BasePrice + (Modifier * OfferCount)

                return Result
            end
        end
    end

    if not GUI_Trade.ComputeSellingPrice_OrigSPELLCASTER then
        GUI_Trade.ComputeSellingPrice_OrigSPELLCASTER = GUI_Trade.ComputeSellingPrice;
        GUI_Trade.ComputeSellingPrice = function(_TargetPlayerID, _GoodType, _GoodAmount)
            if Logic.GetEntityType(Logic.GetKnightID(GUI.GetPlayerID())) ~= Entities.U_KnightSabatta then
                return GUI_Trade.ComputeSellingPrice_OrigSPELLCASTER(_TargetPlayerID, _GoodType, _GoodAmount);
            else
                if _GoodType == Goods.G_Gold then
                    return 0
                end
                local Waggonload = MerchantSystem.Waggonload
                local BasePrice  = MerchantSystem.BasePrices[_GoodType]
                local GoodsSoldToTargetPlayer = 0
                if  g_Trade.SellToPlayers[_TargetPlayerID] ~= nil
                and g_Trade.SellToPlayers[_TargetPlayerID][_GoodType] ~= nil then
                    GoodsSoldToTargetPlayer = g_Trade.SellToPlayers[_TargetPlayerID][_GoodType]
                end
                local Modifier = math.ceil(BasePrice / 4)
                local MaxPriceToSubtractPerWaggon = BasePrice - Modifier
                local WaggonsToSell = math.ceil(_GoodAmount / Waggonload)
                local WaggonsSold = math.ceil(GoodsSoldToTargetPlayer / Waggonload)
                local PriceToSubtract = 0
                for i = 1, WaggonsToSell do
                    PriceToSubtract = PriceToSubtract + math.min(WaggonsSold * Modifier, MaxPriceToSubtractPerWaggon)
                    WaggonsSold = WaggonsSold + 1
                end
                return ((WaggonsToSell * BasePrice) - PriceToSubtract)*1.2
            end
        end

        function GUI_Trade.SellClicked()
            Sound.FXPlay2DSound( "ui\\menu_click")
            if g_Trade.GoodAmount == 0 then
                return
            end
            local PlayerID = GUI.GetPlayerID()
            local ButtonIndex = tonumber(XGUIEng.GetWidgetNameByID(XGUIEng.GetWidgetsMotherID(XGUIEng.GetCurrentWidgetID())))
            local TargetID = g_Trade.TargetPlayers[ButtonIndex]
            local PlayerSectorType = PlayerSectorTypes.Civil
            if g_Trade.GoodType == Goods.G_Gold then
                PlayerSectorType = PlayerSectorTypes.Thief
            end
            local IsReachable = CanEntityReachTarget(TargetID, Logic.GetStoreHouse(PlayerID), Logic.GetStoreHouse(TargetID),nil, PlayerSectorType)
            if IsReachable == false then
                local MessageText = XGUIEng.GetStringTableText("Feedback_TextLines/TextLine_GenericUnreachable")
                Message(MessageText)
                return
            end
            if g_Trade.GoodType == Goods.G_Gold then

            elseif Logic.GetGoodCategoryForGoodType(g_Trade.GoodType) == GoodCategories.GC_Resource then
                local SpaceForNewGoods = Logic.GetPlayerUnreservedStorehouseSpace(TargetID)
                if SpaceForNewGoods < g_Trade.GoodAmount then
                    local MessageText = XGUIEng.GetStringTableText("Feedback_TextLines/TextLine_TargetFactionStorehouseSpace")
                    Message(MessageText)
                    return
                end

            else
                if Logic.GetNumberOfTradeGatherers(PlayerID) >= 1 then
                    local MessageText = XGUIEng.GetStringTableText("Feedback_TextLines/TextLine_TradeGathererUnderway")
                    Message(MessageText)
                    return
                end
                if Logic.CanFitAnotherMerchantOnMarketplace(Logic.GetMarketplace(TargetID)) == false then
                    local MessageText = XGUIEng.GetStringTableText("Feedback_TextLines/TextLine_TargetFactionMarketplaceFull")
                    Message(MessageText)
                    return
                end
            end
            local Price
            if Logic.PlayerGetIsHumanFlag(TargetID) then
                Price = 0
            else
                Price = GUI_Trade.ComputeSellingPrice(TargetID, g_Trade.GoodType, g_Trade.GoodAmount)
                Price = Price / g_Trade.GoodAmount
            end
            GUI.StartTradeGoodGathering(PlayerID, TargetID, g_Trade.GoodType, g_Trade.GoodAmount, Price)
            GUI_FeedbackSpeech.Add("SpeechOnly_CartsSent", g_FeedbackSpeech.Categories.CartsUnderway, nil, nil)
            StartKnightVoiceForPermanentSpecialAbility(Entities.U_KnightTrading)
            StartKnightVoiceForPermanentSpecialAbility(Entities.U_KnightSabatta)
            if Price ~= 0 then
                if g_Trade.SellToPlayers[TargetID] == nil then
                    g_Trade.SellToPlayers[TargetID] = {}
                end

                if g_Trade.SellToPlayers[TargetID][g_Trade.GoodType] == nil then
                    g_Trade.SellToPlayers[TargetID][g_Trade.GoodType] = g_Trade.GoodAmount
                else
                    g_Trade.SellToPlayers[TargetID][g_Trade.GoodType] = g_Trade.SellToPlayers[TargetID][g_Trade.GoodType] + g_Trade.GoodAmount
                end
            end
        end
    end

    if not GUI_Merchant.OfferClicked_OrigSPELLCASTER then
        GUI_Merchant.OfferClicked_OrigSPELLCASTER = GUI_Merchant.OfferClicked;
        GUI_Merchant.OfferClicked = function(_ButtonIndex)
            if Logic.GetEntityType(Logic.GetKnightID(GUI.GetPlayerID())) ~= Entities.U_KnightSabatta then
                GUI_Merchant.OfferClicked_OrigSPELLCASTER(_ButtonIndex)
            else
                local CurrentWidgetID       = XGUIEng.GetCurrentWidgetID()
                local PlayerID              = GUI.GetPlayerID()
                local BuildingID            = g_Merchant.ActiveMerchantBuilding
                if BuildingID == 0 then
                    return
                end
                local PlayersMarketPlaceID  = Logic.GetMarketplace(PlayerID)
                local TraderPlayerID        = Logic.EntityGetPlayer(BuildingID)
                local TraderType            = g_Merchant.Offers[_ButtonIndex].TraderType
                local OfferIndex            = g_Merchant.Offers[_ButtonIndex].OfferIndex
                local GoodType              = 0
                local OfferGoodAmount       = 0
                local OfferAmount           = 0
                local AmountPrices          = 0

                local CanBeBought = true
                if TraderType == g_Merchant.GoodTrader then
                    GoodType, OfferGoodAmount, OfferAmount, AmountPrices = Logic.GetGoodTraderOffer(BuildingID,OfferIndex,PlayerID)
                    if Logic.GetGoodCategoryForGoodType(GoodType) == GoodCategories.GC_Resource then
                        local SpaceForNewGoods =  Logic.GetPlayerUnreservedStorehouseSpace(PlayerID)
                        if SpaceForNewGoods < OfferGoodAmount then
                            CanBeBought = false
                            local MessageText = XGUIEng.GetStringTableText("Feedback_TextLines/TextLine_MerchantStorehouseSpace")
                            Message(MessageText)
                            return
                        end
                    elseif Logic.GetGoodCategoryForGoodType(GoodType) == GoodCategories.GC_Animal then
                        CanBeBought = true
                    else
                        if Logic.CanFitAnotherMerchantOnMarketplace(PlayersMarketPlaceID) == false then
                            CanBeBought = false
                            local MessageText = XGUIEng.GetStringTableText("Feedback_TextLines/TextLine_MerchantMarketplaceFull")
                            Message(MessageText)
                            return
                        end
                    end
                elseif TraderType == g_Merchant.EntertainerTrader then
                    if Logic.CanFitAnotherEntertainerOnMarketplace(PlayersMarketPlaceID) == false then
                        CanBeBought = false
                        local MessageText = XGUIEng.GetStringTableText("Feedback_TextLines/TextLine_MerchantMarketplaceFull")
                        Message(MessageText)
                        return
                    end
                elseif TraderType == g_Merchant.MercenaryTrader then
                    GoodType, OfferGoodAmount, OfferAmount, AmountPrices = Logic.GetMercenaryOffer(BuildingID,OfferIndex,PlayerID)
                    local CurrentSoldierCount = Logic.GetCurrentSoldierCount(PlayerID)
                    local CurrentSoldierLimit = Logic.GetCurrentSoldierLimit(PlayerID)
                    local SoldierSize         = OfferGoodAmount
                    if GoodType == Entities.U_Thief then
                        SoldierSize = 1
                    end
                    if (CurrentSoldierCount + SoldierSize) > CurrentSoldierLimit then
                        CanBeBought = false
                        local MessageText = XGUIEng.GetStringTableText("Feedback_TextLines/TextLine_SoldierLimitReached")
                        Message(MessageText)
                        return
                    end
                end

                if CanBeBought == true then
                    local Price              = ComputePrice( BuildingID, OfferIndex, PlayerID, TraderType )
                    local GoldAmountInCastle = GetPlayerGoodsInSettlement(Goods.G_Gold, PlayerID )
                    local PlayerSectorType   = PlayerSectorTypes.Civil
                    local IsReachable        = CanEntityReachTarget(PlayerID, Logic.GetStoreHouse(TraderPlayerID), Logic.GetStoreHouse(PlayerID), nil, PlayerSectorType)
                    if IsReachable == false then
                        local MessageText = XGUIEng.GetStringTableText("Feedback_TextLines/TextLine_GenericUnreachable")
                        Message(MessageText)
                        return
                    end

                    if Price <= GoldAmountInCastle then
                        if Logic.GetGoodCategoryForGoodType(GoodType) == GoodCategories.GC_Animal then
                            local AnimalType = Entities.A_X_Sheep01
                            if GoodType == Goods.G_Cow then
                                AnimalType = Entities.A_X_Cow01
                            end
                            for i=1,5 do
                                GUI.CreateEntityAtBuilding(BuildingID, AnimalType, 0)
                            end
                        end

                        GUI.ChangeMerchantOffer(BuildingID,PlayerID,OfferIndex,Price)
                        GUI.BuyMerchantOffer(BuildingID,PlayerID,OfferIndex)
                        Sound.FXPlay2DSound( "ui\\menu_click")

                        StartKnightVoiceForPermanentSpecialAbility(Entities.U_KnightSabatta)
                    else
                        local MessageText = XGUIEng.GetStringTableText("Feedback_TextLines/TextLine_NotEnough_G_Gold")
                        Message(MessageText)
                    end
                else
                    GUI.Note("Debug: An error occur!")
                end
            end
        end
    end

    --~~~~~~~~~~~
    -- Sonstiges
    --~~~~~~~~~~~

    -- Feedback-Stimmen
    g_MilitaryFeedback.Knights[Entities.U_KnightRedPrince]        = "H_Knight_RedPrince"
    g_HeroAbilityFeedback.Knights[Entities.U_KnightRedPrince]    = "RedPrince"
    g_MilitaryFeedback.Knights[Entities.U_KnightSabatta]        = "H_Knight_Sabatt"
    g_HeroAbilityFeedback.Knights[Entities.U_KnightSabatta]        = "Sabatta"
    g_MilitaryFeedback.Soldiers[Entities.U_MilitaryBow_Khana]    = "Military_Bow"
    g_MilitaryFeedback.Soldiers[Entities.U_MilitarySword_Khana]    = "Military_Sword"

    -- Abschalten der aktiven Fähigkeitsansage, wenn der Hauptheld ein Hexer ist
    if not StartKnightVoiceForActionSpecialAbility_OrigSPELLCASTER then
        StartKnightVoiceForActionSpecialAbility_OrigSPELLCASTER = StartKnightVoiceForActionSpecialAbility;
        StartKnightVoiceForActionSpecialAbility = function(_type)
            local kID = Logic.GetEntityName(Logic.GetKnightID(GUI.GetPlayerID()));
            if not g_SpellcasterList[eName] then
          StartKnightVoiceForActionSpecialAbility_OrigSPELLCASTER(_type);
        end
        end
    end
    -- Abschalten der passiven Fähigkeitsansage, wenn der Hauptheld ein Hexer ist
    if not StartKnightVoiceForPermanentSpecialAbility_OrigSpellcasterAddOn then
        StartKnightVoiceForPermanentSpecialAbility_OrigSpellcasterAddOn = StartKnightVoiceForPermanentSpecialAbility;
        StartKnightVoiceForPermanentSpecialAbility = function(_KnightType)
            local eName = Logic.GetEntityName(Logic.GetKnightID(GUI.GetPlayerID()));
            if not g_SpellcasterList[eName] then
                StartKnightVoiceForPermanentSpecialAbility_OrigSpellcasterAddOn(_KnightType)
            end
        end
    end

    -- Trefferpunktekontrolle für Krieger
    if not Warrior_HealthControler then
        Warrior_HealthControler = function()
            for k,v in pairs(g_SpellcasterList) do
                if v.isWarrior and IsExisting(v.Name) then
                    local eID = GetID(v.Name)
                    if Logic.KnightGetResurrectionProgress(eID) == 1 then
                        if v.Stats.DEF.Current < v.Stats.DEF.Max then
                            local difference = v.Stats.DEF.Max - v.Stats.DEF.Current;
                            local toRefill     = v.Stats.REG.Current;
                            -- Perk "MeditationMaster"
                            if v.Perks.MeditationMaster then
                                toRefill = math.ceil(toRefill + ((toRefill/100) * 15));
                            end

                            if difference < toRefill then
                                v.Stats.DEF.Current = v.Stats.DEF.Max;
                            else
                                v.Stats.DEF.Current = v.Stats.DEF.Current + toRefill;
                            end
                        end
                    else
                        v.Stats.DEF.Current = v.Stats.DEF.Max;
                    end

                    local percentage;
                    if v.ChuckNorris then
                        percentage = math.ceil((v.Stats.DEF.Current / v.Stats.DEF.Max) * 100);
                    else
                        percentage = math.floor((v.Stats.DEF.Current / v.Stats.DEF.Max) * 100);
                    end
                    GUI.SendScriptCommand([[
                        MakeVulnerable(]]..eID..[[)
                        SetHealth(]]..eID..[[,]]..percentage..[[)
                        MakeInvulnerable(]]..eID..[[)
                    ]]);
                end
            end
        end
        Trigger.RequestTrigger(Events.LOGIC_EVENT_EVERY_SECOND, nil, "Warrior_HealthControler", 1);
    end

    -- Verwundungsevent für Krieger
    if not Warrior_EntityHurtEntityControler then
        Warrior_EntityHurtEntityControler = function()
            local att = {Event.GetEntityID1()};
            local def = {Event.GetEntityID2()};

            for i=1,#att do
                for j=1,#def do
                    local eNameAttacker = Logic.GetEntityName(att[i]);
                    local eNameDefender = Logic.GetEntityName(def[j]);
                    local attackerIsSpellcaster = false;
                    local defenderIsSpellcaster = false;
                    local attackerIsWarrior = false;
                    local defenderIsWarrior = false;
                    local attacker = g_SpellcasterList[eNameAttacker];
                    local defender = g_SpellcasterList[eNameDefender];

                    if attacker and not attacker.isWarrior then
                        attackerIsSpellcaster = true;
                    end
                    if defender and not defender.isWarrior then
                        defenderIsSpellcaster = true;
                    end
                    if attacker and attacker.isWarrior then
                        attackerIsWarrior = true;
                    end
                    if defender and defender.isWarrior then
                        defenderIsWarrior = true;
                    end

                    if attackerIsWarrior then
                        local dmg = attacker.Stats.ATK.Current;
                        if defenderIsWarrior then
                            -- Perk "GoodDefender"
                            if defender.Perks.GoodDefender then
                                dmg = math.ceil(dmg - ((dmg/100) * 15));
                            end

                            defender.Stats.DEF.Current = defender.Stats.DEF.Current - dmg;
                            if defender.Stats.DEF.Current < 0 then
                                defender.Stats.DEF.Current = 0;
                            end
                        else
                            -- Perk "PredatorsScare"
                            if  Logic.IsEntityInCategory(def[j],EntityCategories.AttackableAnimal) == 1
                            and attacker.Perks.PredatorsScare then
                                dmg = dmg * 2;
                            end
                            -- Perk "GoodAttacker"
                            if  Logic.IsEntityInCategory(def[j],EntityCategories.AttackableAnimal) == 0
                            and attacker.Perks.GoodAttacker then
                                dmg = math.ceil(dmg + ((dmg/100) * 15));
                            end
                            -- Perk "Inquisitor"
                            if defenderIsSpellcaster and attacker.Perks.Inquisitor then
                                dmg = math.ceil(dmg + ((dmg/100) * 15));
                            end

                            GUI.SendScriptCommand([[Spellcaster_HurtEntity(]]..def[j]..[[,]]..dmg..[[,]]..att[i]..[[)]]);
                        end
                    end

                    if defenderIsWarrior and not attackerIsWarrior then
                        local eType = Logic.GetEntityType(att[i]);
                        local dmg    = Warrior.DamageList[eType] or 30;
                        -- Perk "GoodDefender"
                        if defender.Perks.GoodDefender then
                            dmg = math.ceil(dmg - ((dmg/100) * 15));
                        end

                        defender.Stats.DEF.Current = defender.Stats.DEF.Current - dmg;
                        if defender.Stats.DEF.Current < 0 then
                            defender.Stats.DEF.Current = 0;
                        end
                    end
                end
            end
        end
        Trigger.RequestTrigger(Events.LOGIC_EVENT_ENTITY_HURT_ENTITY, nil, "Warrior_EntityHurtEntityControler", 1);
    end
end

-- Gibt Feinde aus für die KI
function Spellcaster:getEnemiesForKI(_distance)
    local pID = Logic.EntityGetPlayer(GetID(self.Name));
    local tID = GetTerritoryUnderEntity(GetID(self.Name));
    local enemies = {};

    for j=1,8 do
        if j ~= pID and Diplomacy_GetRelationBetween(pID,j) == -2 then
            local localEntities = GetPlayerEntities(j,0);
            for j=1,#localEntities do
                if  Logic.IsEntityInCategory(localEntities[j],EntityCategories.Military) == 1 
                and not Logic.IsKnight(localEntities[j]) then
                    if GetDistance(self.Name,localEntities[j]) <= _distance then
                        enemies[#enemies+1] = localEntities[j];
                    end
                end
                if Logic.IsKnight(localEntities[j]) then
                    if GetDistance(self.Name,localEntities[j]) <= _distance then
                        table.insert(enemies,1,localEntities[j]);
                    end
                end
            end
        end
    end
    if #enemies == 0 then
        local animal = SucheAufTerritorium(0,tID,0,EntityCategories.AttackableAnimal);
        for i=1,#animal do
            if GetDistance(self.Name,animal[i]) <= _distance then
                enemies[#enemies+1] = animal[i];
            end
        end
    end
    return enemies;
end

-- Steuerung des Skriptes und Verwaltung der KI-Hexer
function SPELLCASTER_HERO_LOOP()
    local eID = GUI.GetSelectedEntity();
    local eIDs = {GUI.GetSelectedEntities()}
    local GUIState = GUI.GetCurrentStateName();

    for k,v in pairs(g_SpellcasterList) do        
        -- Manaregeneration (Komatöse Helden haben halbes Mana nach erwachen)
        if Logic.KnightGetResurrectionProgress(GetID(v.Name)) == 1 then
            if v.Stats.Mana.Current < v.Stats.Mana.Max then
                v.Stats.Time.Timer = v.Stats.Time.Timer -1;
                if v.Stats.Time.Timer < 1 then
                    local toRegain = (v.Perks.MasterMage and 3) or (v.Perks.TalentedMage and 2) or 1;
                    v.Stats.Mana.Current = v.Stats.Mana.Current +toRegain;
                    if v.Stats.Mana.Current > v.Stats.Mana.Max then
                        v.Stats.Mana.Current = v.Stats.Mana.Max
                    end
                    v.Stats.Time.Timer = v.Stats.Time.Recharge;
                end
            end
        else
            v.Stats.Mana.Current = math.floor(v.Stats.Mana.Max/2);
        end
        if eID == GetID(v.Name) then
            -- Zuerst den Key für Feedback Speech zwischenspeichern und dann abschalten
            if not v.MilitaryFeedbackKey and v.Menu == 2 and v.Using ~= nil then
                v.MilitaryFeedbackKey = g_MilitaryFeedback.Knights[Logic.GetEntityType(eID)];
                g_MilitaryFeedback.Knights[Logic.GetEntityType(eID)] = nil;
            end

            -- Prüfen ob Escape gedrückt wurde (Variable wird vom Spiel bereitgestellt)
            if g_EscapeHasBeenPressed == true then
                if v.MilitaryFeedbackKey then
                    g_MilitaryFeedback.Knights[Logic.GetEntityType(eID)] = v.MilitaryFeedbackKey;
                    v.MilitaryFeedbackKey = nil;
                end
                GUI.ActivateSelectionState();
                g_EscapeHasBeenPressed = false;
                v.Using = nil;
            end
            -- Beschwörungen und Bereichseffekte benötigen eine State-Abfrage und die Maus-Pos
            if v.Menu == 2 and v.Using ~= nil then
                -- Ein komatöser Held kann nicht mehr Zaubern
                if Logic.KnightGetResurrectionProgress(eID) ~= 1 then
                    v.Using = nil;
                end
                if (GUIState == "WalkCommand" or GUIState == "AttackCommand") and g_LastTurnGUIState == "ExplicitAttackCommand" then
                    local mouse = {GUI.Debug_GetMapPositionUnderMouse()};
                    v:executeExplicitPositionAbility(mouse[1],mouse[2],v.Spell,GUI.GetMouseOverEntity());

                    for kk,vv in pairs(g_SpellcasterList) do
                        if IstDrin(GetID(vv.Name),eIDs) then
                            GUI.SendCommandStationaryDefend(GetID(vv.Name));
                        end
                    end
                end
            end
        end

        -- Schreibt ein Abbild des Hexers ins globale Skript. So kann man angehangene Zauber und Fähigkeitsstufen
        -- für Questziele benutzen.
        GUI.SendScriptCommand([[
            g_SpellcasterList = g_SpellcasterList or {}

            g_SpellcasterList["]]..v.Name..[["] = {
                Spells = {
                    "]]..((v.Spells.Slot1 ~= nil and v.Spells.Slot1.Name) or "")..[[",
                    "]]..((v.Spells.Slot2 ~= nil and v.Spells.Slot2.Name) or "")..[[",
                    "]]..((v.Spells.Slot3 ~= nil and v.Spells.Slot3.Name) or "")..[[",
                    "]]..((v.Spells.Slot4 ~= nil and v.Spells.Slot4.Name) or "")..[[",
                },
                Stats = {
                    Learnpoints    = ]]..v.Stats.Learnpoints..[[,
                    CurrentMana = ]]..v.Stats.Mana.Current..[[,
                    MaximalMana = ]]..v.Stats.Mana.Max..[[,
                    CurrentTime = ]]..v.Stats.Time.Timer..[[,
                    MaximalTime = ]]..v.Stats.Time.Recharge..[[,
                    Distance    = ]]..v.Stats.Range.Distance..[[,
                },
                Potion = ]]..Spellcaster.Potion.Amount..[[,
            }
        ]]);

        -- Kontrolliert (oder versucht es wenigstens) KI-gesteuerte Zauberer zu verwalten. Wer verbesserungsvorschläge
        -- hat, immer her damit!

        if not v.isWarrior then
            local KIeID = GetID(v.Name);
            local KIpID = Logic.EntityGetPlayer(KIeID);
            local health = Logic.GetEntityHealth(KIeID);
            local spellSpoke = false;
            if KIpID ~= GUI.GetPlayerID() and Logic.GetTime() % 3 == 0 then
                if Logic.KnightGetResurrectionProgress(KIeID) == 1 then                
                    -- Selbstheilung des Zauberers
                    if health <= 350 and not spellSpoke then
                        for i=1,4 do
                            if v.Spells["Slot"..i] and (v.Spells["Slot"..i].Name == "Healing" or v.Spells["Slot"..i].Name == "SuperHealing") then
                                if v.Stats.Mana.Current >= v.Spells["Slot"..i].Cost then
                                    v.Stats.Mana.Current = v.Stats.Mana.Current - v.Spells["Slot"..i].Cost;
                                    v.Spells["Slot"..i]:action(v);
                                    spellSpoke = true;
                                    break;
                                end
                            end
                        end
                    end

                    -- Verteidigungszauber
                    if not spellSpoke then
                        for i=1,4 do
                            if  v.Spells["Slot"..i] and v.Spells:isInCategory(v.Spells["Slot"..i].Name,"Direct")
                            and not string.find(v.Spells["Slot"..i].Name,"Satisfaction")                            
                            and not string.find(v.Spells["Slot"..i].Name,"Healing")then                            
                                local enemies = v:getEnemiesForKI(1200);
                                if #enemies >= 25 or Logic.IsEntityInCategory(enemies[1],EntityCategories.AttackableAnimal) == 1 then
                                    if v.Stats.Mana.Current >= v.Spells["Slot"..i].Cost then
                                        local useSpell = true;
                                        if v.Spells["Slot"..i].Name == "Thunderstorm" and v.UsingThunderstorm and v.UsingThunderstorm > 0 then
                                            useSpell = false;
                                        end

                                        if useSpell then
                                            v.Stats.Mana.Current = v.Stats.Mana.Current - v.Spells["Slot"..i].Cost;
                                            v.Spells["Slot"..i]:action(v);
                                            spellSpoke = true;
                                        end

                                          -- Delay für Gewitter
                                        if v.Spells["Slot"..i].Name == "Thunderstorm" and (not v.UsingThunderstorm or v.UsingThunderstorm <= 0) then
                                            v.UsingThunderstorm = 150;
                                        end
                                        break;
                                    end
                                end
                            end
                        end
                    end
                    if v.UsingThunderstorm then
                        v.UsingThunderstorm = v.UsingThunderstorm -1;
                    end

                    -- Angriff auf feindliche Soldaten
                    if not spellSpoke then
                        for i=1,4 do
                            if v.Spells["Slot"..i] and v.Spells:isInCategory(v.Spells["Slot"..i].Name,"RangedEffect") then
                                v.Using = v.Spells["Slot"..i].Name;
                                local enemies = v:getEnemiesForKI(v.Stats.Range.Distance);
                                if  #enemies >= 25 or Logic.IsKnight(enemies[1]) or (Logic.IsEntityInCategory(enemies[1],EntityCategories.AttackableAnimal) == 1
                                and v.Using ~= "BellOfHeaven" and Logic.GetEntityHealth(enemies[1]) > 0) then
                                    if v.Stats.Mana.Current >= v.Spells["Slot"..i].Cost then
                                        local X,Y,Z = Logic.EntityGetPos(enemies[math.random(1,#enemies)])
                                        if Logic.IsKnight(enemies[1])then
                                        X,Y,Z = Logic.EntityGetPos(enemies[1]);
                                        end
                                        v:executeExplicitPositionAbility(X,Y,v.Spells["Slot"..i],nil)
                                        spellSpoke = true;
                                        break;
                                    end
                                end
                                break;
                            end
                        end
                    end

                    -- Beschworung von Tigern und Wölfen
                    if not spellSpoke then
                        for i=1,4 do
                            if v.Spells["Slot"..i] and (v.Spells["Slot"..i].Name == "SummonWolves" or v.Spells["Slot"..i].Name == "SummonTigers") then
                                v.Using = v.Spells["Slot"..i].Name;
                                local enemies = v:getEnemiesForKI(v.Stats.Range.Distance);
                                if #enemies >= 55 then
                                    if v.Stats.Mana.Current >= v.Spells["Slot"..i].Cost then
                                        local X,Y,Z = Logic.EntityGetPos(enemies[math.random(1,#enemies)])
                                        v:executeExplicitPositionAbility(X,Y,v.Spells["Slot"..i],nil)
                                        spellSpoke = true;
                                        break;
                                    end
                                end
                                break;
                            end
                        end
                    end
                end
            end
        end
    end
    g_LastTurnGUIState = GUIState;
end

-- * * * * * * * * * * * * * * * * * * * * 
-- Spells
-- * * * * * * * * * * * * * * * * * * * * 

Spells = {}

-- Fügt einen Zauber zum Slot hinzu (kopiert ihn). Ist auch die einzige Möglichkeit einem KI-Hexer einen
-- Zauber zu verpassen, da die KI keinen Kathalog durchblättern kann. _hero ist das Objekt (nicht der Name
-- sondern das erstellte Objekt!), _slot ein Integer zw. 1 u. 4 und Spell der Name des Zaubers.
function Spells:AttachSpell(_hero,_slot,_spell)
    assert(type(_hero) == "table" and type(_slot) == "number" and type(_spell) == "string");
    if Spells[_spell] then
        _hero.Spells["Slot".._slot] = TableCopyAppend({},Spells[_spell]);
        if not IstDrin(_spell,_hero.Spells.Learned) then
            _hero.Spells.Learned[#_hero.Spells.Learned+1] = _spell;
        end
    end
end

-- Prüft ob ein Zauber in einer Kategorie ist
function Spells:isInCategory(_spell,_category)
    return IstDrin(_spell,SpellCategories[_category]);
end

-- erzeugt einen Zauber. Alle werte, die die Zauberkategorie erwartet, müssen namentlich vorhanden sein.
function Spells:CreateSpell(_desc)
    local lang = (Network.GetDesiredLanguage() == "de" and "de") or "en";
    assert(_desc.Category == "RangedEffect" or _desc.Category == "Summon" or _desc.Category == "Direct");
    assert(type(_desc.Icon) == "string" or type(_desc.Icon) == "table");
    if type(_desc.Title) == "table" then
        _desc.Title = _desc.Title[lang];
    end
    assert(type(_desc.Title) == "string");
    if type(_desc.Text) == "table" then
        _desc.Text = _desc.Text[lang];
    end
    assert(type(_desc.Text) == "string");
    assert(type(_desc.Cost) == "number");

    if _desc.category == "RangedEffect" then
        assert(type(_desc.Damage) == "number");
        assert(type(_desc.Range) == "number");
    end
    if _desc.category == "Summon" then
        assert(type(_desc.Amount) == "number");
        assert(type(_desc.Range) == "number");
    end

    Spells[_desc.Name] = TableCopyAppend({},_desc);
    table.insert(SpellCategories[_desc.Category],1,_desc.Name);
    for k,v in pairs(g_SpellcasterList) do
        v.Spells:updateSpells();
    end
end

SpellCategories  = {
    Summon       = {"SummonWolves","SummonTigers","SummonTrebuchet"};
    RangedEffect = {"Lightning","Sunfire","Fountain","CallHornet","Frost"};
    Direct       = {"Healing","SuperHealing","BellOfHeaven","Satisfaction","Thunderstorm"},
}

--~~~~~~~~~~~~~~~~~~
-- Ranged Abilities
--~~~~~~~~~~~~~~~~~~
-- Diese Zauber lösen Gebietsschaden an einer frei wählbaren Position aus.

-- Blitzschlag

Spells.Lightning = {
    Name    = "Lightning";
    -- Icon    = "spellcasters_lightning.png";
    Icon    = {13,11},
    Cost    = 4;
    Damage    = 300;
    Range    = 300;
    Title    = {de = "Blitzschlag"; en = "Lightning Strike";};
    Text    = {de = "Der Zauberer beschwört einen einzelnen Blitz, der auf ein Ziel gerichtet werden kann.";
               en = "The magician summons a lightning that is thrown on any target.";};
};

function Spells.Lightning:action(_hero)
    local lang = (Network.GetDesiredLanguage() == "de" and "de") or "en";
    if _hero.Stats.Mana.Current >= self.Cost then
        GUI.ActivateExplicitAttackCommandState();
        _hero.Using = "Lightning";
        _hero.Spell = self;
    else
        Message(Umlaute((lang == "de" or "Nicht genügend Zauberpunkte!") or "Not enough spell points!"));
    end
end

function Spells.Lightning:effect(_X,_Y)
    GUI.SendScriptCommand([[Logic.Lightning(]].._X..[[,]].._Y..[[)]]);
end

-- Sonnenfeuer

Spells.Sunfire = {
    Name    = "Sunfire";
    -- Icon    = "spellcasters_fire.png";
    Icon    = {13,9};
    Cost    = 1;
    Damage    = 15;
    Range    = 900;
    Title    = {de = "Sonnenfeuer"; en = "Sunfire";};
    Text    = {de = "Niemand sollte die Macht der Sonne unterschätzen. Sie scheint schwach zu sein, doch hat sie Potenzial!";
               en = "Nobody should underestimate the power of the sun. It seems to be weak but it have potential!";};
};

function Spells.Sunfire:action(_hero)
    local lang = (Network.GetDesiredLanguage() == "de" and "de") or "en";
    if _hero.Stats.Mana.Current >= self.Cost then
        GUI.ActivateExplicitAttackCommandState();
        _hero.Using = "Sunfire";
        _hero.Spell = self;
    else
        Message(Umlaute((lang == "de" or "Nicht genügend Zauberpunkte!") or "Not enough spell points!"));
    end
end

function Spells.Sunfire:effect(_X,_Y)
    for i=1,10 do
        local xUp = math.random(-250,250);
        local yUp = math.random(-250,250);
        GUI.SendScriptCommand([[Logic.CreateEffect(EGL_Effects.FXFirebreath,]]..(_X+xUp+200)..[[,]]..(_Y+yUp+200)..[[,0)]]);
        GUI.SendScriptCommand([[Logic.CreateEffect(EGL_Effects.FXFirebreath,]]..(_X+xUp)..[[,]]..(_Y+yUp)..[[,0)]]);
    end
end

-- Geysir erschaffen

Spells.Fountain    = {
    Name    = "Fountain";
    -- Icon    = "spellcasters_fountain.png";
    Icon    = {13,12};
    Damage    = 100;
    Range    = 300;
    Cost    = 3;
    Title    = {de = "Kochendes Wasser"; en = "Boiling Water";};
    Text    = {de = "Wassersäulen schießen aus dem Boden empor und verbrühen die Feinde Eures Zauberer.";
               en = "Pilars of water shoot upwards from the ground and scald the foes of your magician."};
};

function Spells.Fountain:action(_hero)
    local lang = (Network.GetDesiredLanguage() == "de" and "de") or "en";
    if _hero.Stats.Mana.Current >= self.Cost then
        GUI.ActivateExplicitAttackCommandState();
        _hero.Using = "Fountain";
        _hero.Spell = self;
    else
        Message(Umlaute((lang == "de" or "Nicht genügend Zauberpunkte!") or "Not enough spell points!"));
    end
end

function Spells.Fountain:effect(_X,_Y)
    GUI.SendScriptCommand([[
        g_Spellcaster_Geyser = g_Spellcaster_Geyser or {}
        local time = Logic.GetTime()
        local index = #g_Spellcaster_Geyser+1

        g_Spellcaster_Geyser[index] = {}
        for i=-130,130,260 do
            g_Spellcaster_Geyser[index][i] = {}
            for j=-130,130,260 do
                g_Spellcaster_Geyser[index][i][j] = Logic.CreateEntity(Entities.XD_ScriptEntity,(]].._X..[[+i),(]].._Y..[[+j),0,0)
                Logic.SetModel(g_Spellcaster_Geyser[index][i][j],Models.Effects_E_Geyser)
                Logic.SetVisible(g_Spellcaster_Geyser[index][i][j],true)
            end
        end

        StartSimpleJobEx(function(time,index)
            if Logic.GetTime() > time+2 then
                for i=-130,130,260 do
                    for j=-130,130,260 do
                        DestroyEntity(g_Spellcaster_Geyser[index][i][j])
                    end
                end
                return true
            end
        end,Logic.GetTime(),index)
    ]]);
end

-- Hornissen erschaffen

Spells.CallHornet    = {
    Name    = "CallHornet";
    Icon    = {14,3};
    Damage    = 100;
    Range    = 200;
    Cost    = 1;
    Title    = {de = "Hornissen rufen"; en = "Call of the Hornets"};
    Text    = {de = "Den Zorn der Hornissen werden sich die Feinde nicht entziehen können!";
               en = "The enemies can not escape from the warth of this angry hornets!"};
};

function Spells.CallHornet:action(_hero)
    local lang = (Network.GetDesiredLanguage() == "de" and "de") or "en";
    if _hero.Stats.Mana.Current >= self.Cost then
        GUI.ActivateExplicitAttackCommandState();
        _hero.Using = "CallHornet";
        _hero.Spell = self;
    else
        Message(Umlaute((lang == "de" or "Nicht genügend Zauberpunkte!") or "Not enough spell points!"));
    end
end

function Spells.CallHornet:effect(_X,_Y)
    GUI.SendScriptCommand([[
        local effectID = Logic.CreateEffect(EGL_Effects.FX_Bees,]].._X..[[,]].._Y..[[,0)
        local time = Logic.GetTime()

        StartSimpleJobEx(function(time,effectID)
            if Logic.GetTime() > time+5 then
                Logic.DestroyEffect(effectID)
                return true
            end
        end,Logic.GetTime(),effectID)
    ]]);
end

-- Frosthauch

Spells.Frost    = {
    Name    = "Frost";
    Icon    = {13,14};
    Damage    = 75;
    Range    = 500;
    Cost    = 2;
    Title    = {de = "Frosthauch"; en = "Nordic Breath"};
    Text    = {de = "Der Zauberer beschwört den eisigen Blizzardhauch aus dem hohen Norden.";
               en = "Your magician summons the shouting cold breath of the north."};
};

function Spells.Frost:action(_hero)
    local lang = (Network.GetDesiredLanguage() == "de" and "de") or "en";
    if _hero.Stats.Mana.Current >= self.Cost then
        GUI.ActivateExplicitAttackCommandState();
        _hero.Using = "Frost";
        _hero.Spell = self;
    else
        Message(Umlaute((lang == "de" or "Nicht genügend Zauberpunkte!") or "Not enough spell points!"));
    end
end

function Spells.Frost:effect(_X,_Y)
    GUI.SendScriptCommand([[
        local effectIDs = {
            Logic.CreateEntity(Entities.E_NE_BlowingSnow01,]].._X..[[,]].._Y..[[,270,0),
            Logic.CreateEntity(Entities.E_NE_BlowingSnow01,]].._X..[[,]].._Y..[[,180,0),
            Logic.CreateEntity(Entities.E_NE_BlowingSnow01,]].._X..[[,]].._Y..[[,90,0),
            Logic.CreateEntity(Entities.E_NE_BlowingSnow01,]].._X..[[,]].._Y..[[,0,0),
        }
        local time = Logic.GetTime()

        StartSimpleJobEx(function(time,effectIDs)
            if Logic.GetTime() > time+5 then
                for i=1,#effectIDs do
                    DestroyEntity(effectIDs[i])
                end
                return true
            end
        end,Logic.GetTime(),effectIDs)
    ]]);
end

--~~~~~~~~~~~~~~~~~~
-- Summon Abilities
--~~~~~~~~~~~~~~~~~~
-- Diese Zauber beschwören Tiere oder Einheiten an einer wählbaren Position.

-- Wölfe beschwören

Spells.SummonWolves    = {
    Name    = "SummonWolves";
    Icon    = {13,8};
    Cost    = 1;
    Amount    = 1;
    Title    = {de = "Wölfe beschwören"; en = "Summon Wolves"};
    Text    = {de = "Der Zauberer beschwört Wölfe, die 5 Minuten verbleiben. Aber er kann das Biest nicht kontrollieren.";
               en = "The magician summon some wolves. They existing for 5 minutes. But you can't controll the beast!"};
};

function Spells.SummonWolves:action(_hero)
    local lang = (Network.GetDesiredLanguage() == "de" and "de") or "en";
    if _hero.Stats.Mana.Current >= self.Cost then
        GUI.ActivateExplicitAttackCommandState();
        _hero.Using = "SummonWolves";
        _hero.Spell = self;
    else
        Message(Umlaute((lang == "de" or "Nicht genügend Zauberpunkte!") or "Not enough spell points!"));
    end
end

function Spells.SummonWolves:effect(_X,_Y,_hero)
    local amount = self.Amount;
    if _hero.Perks.BeastMaster == true then
        amount = amount * 2;
    end
    for i=1, amount do
        GUI.SendScriptCommand([[
            local ID = Logic.CreateEntity(Entities.S_WolfPack,]].._X..[[,]].._Y..[[,0,0)
            Logic.ExecuteInLuaLocalState("Warrior.SummonedAnimals["..ID.."] = true")
            StartSimpleJobEx( function(time,ID)
                if Logic.GetTime() > time+300 then
                    local animals = {Logic.GetSpawnedEntities(ID)}
                    for i=1,#animals do
                        if IsExisting(animals[i]) then
                            Logic.HurtEntity(animals[i],Logic.GetEntityHealth(animals[i]))
                        end
                    end
                    return true;
                end
            end, Logic.GetTime(),ID)
        ]]);
    end
end

-- Tiger beschwören

Spells.SummonTigers    = {
    Name    = "SummonTigers";
    Icon    = {1,8,1};
    Cost    = 3;
    Amount    = 4;
    Title    = {de = "Tiger beschwören"; en = "Summon Tigers"};
    Text    = {de = "Der Magier beschwört Tiger, die 5 Minuten verbleiben. Tiger können nicht kontrolliert werden.";
               en = "The magician summon some tigers. They existing for 5 minutes. But keep in mind: nobody can control the beast!"};
};

function Spells.SummonTigers:action(_hero)
    local lang = (Network.GetDesiredLanguage() == "de" and "de") or "en";
    if _hero.Stats.Mana.Current >= self.Cost then
        GUI.ActivateExplicitAttackCommandState();
        _hero.Using = "SummonTigers";
        _hero.Spell = self;
    else
        Message(Umlaute((lang == "de" or "Nicht genügend Zauberpunkte!") or "Not enough spell points!"));
    end
end

function Spells.SummonTigers:effect(_X,_Y,_hero)
    local amount = self.Amount;
    if _hero.Perks.BeastMaster == true then
        amount = amount * 2;
    end
    for i=1, amount do
        GUI.SendScriptCommand([[
            local ID = Logic.CreateEntity(Entities.S_TigerPack_AS,]].._X..[[,]].._Y..[[,0,0)
            Logic.ExecuteInLuaLocalState("Warrior.SummonedAnimals["..ID.."] = true")
            StartSimpleJobEx( function(time,ID)
                if Logic.GetTime() > time+300 then
                    local animals = {Logic.GetSpawnedEntities(ID)}
                    for i=1,#animals do
                        if IsExisting(animals[i]) then
                            Logic.HurtEntity(animals[i],Logic.GetEntityHealth(animals[i]))
                        end
                    end
                    return true;
                end
            end, Logic.GetTime(),ID)
        ]]);
    end
end

-- Trebuchet erschaffen

Spells.SummonTrebuchet    = {
    Name    = "SummonTrebuchet";
    Icon    = {9,1};
    Cost    = 11;
    Amount    = 1;
    Title    = {de = "Trebuchet erschaffen"; en = "Create a Trebuchet"};
    Text    = {de = "Der Zauberer beschwört ein Trebuchet, dass 5 Minuten verbleibt. Geht die Munition vorzeitig aus,"..
                    " verschwindet es früher.";
               en = "The magician create a trebuchet that will be materialized for 5 minutes. If the ammunition is empty"..
                    " the trebuchet disappears immedaitly."};
};

function Spells.SummonTrebuchet:action(_hero)
    local lang = (Network.GetDesiredLanguage() == "de" and "de") or "en";
    if _hero.Stats.Mana.Current >= self.Cost then
        GUI.ActivateExplicitAttackCommandState();
        _hero.Using = "SummonTrebuchet";
        _hero.Spell = self;
    else
        Message(Umlaute((lang == "de" or "Nicht genügend Zauberpunkte!") or "Not enough spell points!"));
    end
end

function Spells.SummonTrebuchet:effect(_X,_Y,_hero)
    local pID = Logic.EntityGetPlayer(GetID(_hero.Name))

    GUI.SendScriptCommand([[
        local trebuchetID = Logic.CreateEntity(Entities.U_Trebuchet,]].._X..[[,]].._Y..[[,math.random(1,359),]]..pID..[[)
        Logic.CreateEffect(EGL_Effects.E_DestructionSmoke,]].._X..[[,]].._Y..[[,0)
        Logic.CreateEffect(EGL_Effects.FXGarland,]].._X..[[,]].._Y..[[,0)

        StartSimpleJobEx( function(trebuchetID,time)
            if not IsExisting(trebuchetID) then
                return true
            end
            if Logic.GetTime() > time+300 or Logic.GetAmmunitionAmount(trebuchetID) == 0 then
                Logic.CreateEffect(EGL_Effects.E_DestructionSmoke,]].._X..[[,]].._Y..[[,0)
                Logic.CreateEffect(EGL_Effects.FXGarland,]].._X..[[,]].._Y..[[,0)
                DestroyEntity(trebuchetID)
                return true
            end
        end,trebuchetID,Logic.GetTime())
    ]]);
end

--~~~~~~~~~~~~~~~~~~
-- Direct Abilities
--~~~~~~~~~~~~~~~~~~
-- Diese Zauber haben keine Effekt-Methode und werden an der Position des Helden ausgelöst

-- Kleine Heilung

Spells.Healing    = {
    Name    = "Healing";
    Icon    = {2,10};
    Cost    = 1;
    Title    = {de = "Heilung"; en = "Cure"};
    Text    = {de = "Der Zauberer heilt seine Wunden vollständig.";
               en = "The magician heals their wounds completely."};
};

function Spells.Healing:action(_hero)
    local heroID = GetID(_hero.Name)
    local health = Logic.GetEntityHealth(heroID);
    local maxhealth = Logic.GetEntityMaxHealth(heroID);
    local pos = GetPosition(heroID);
    GUI.SendScriptCommand([[
        Logic.HealEntity(]]..heroID..[[,]]..(maxhealth-health)..[[)
        local effectID = Logic.CreateEffect(EGL_Effects.E_HealingFX,]]..pos.X..[[,]]..pos.Y..[[,0)
        StartSimpleJobEx(function(effectID,time)
            if Logic.GetTime() > time+1 then
                Logic.DestroyEffect(effectID)
                return true
            end
        end,effectID,Logic.GetTime())
    ]]);
    GUI.SendCommandStationaryDefend(heroID);
end

-- Große Heilung

Spells.SuperHealing    = {
    Name        = "SuperHealing";
    -- Icon        = "spellcasters_healing.png";
    Icon        = {2,10};
    Distance    = 3000;
    Cost        = 6;
    Title        = {de = "Große Heilung"; en = "Mighty Cure"};
    Text        = {de = "Die große Heilung ist ein mächtiger Zauber, der ungebrenzt viele Helden zu heilen vermag.";
                   en = "The mighty cure is a powerful spell that can heal as many as friendly heroes surrounding the magician."};
};

function Spells.SuperHealing:action(_hero)
    local hero = GetID(_hero.Name);
    local pID = Logic.EntityGetPlayer(GetID(_hero.Name));
    local heroesToHeal = {}

    -- Alle gültigen Heilungsziele ermitteln
    for i=1,8 do
            local heroes = {}
            Logic.GetKnights(i,heroes);
            for j=1,#heroes do
                if GetDistance(hero,heroes[j]) <= self.Distance then
                    heroesToHeal[#heroesToHeal+1] = heroes[j];
                end
            end
    end

    -- Gefundene Helden heilen
    for i=1,#heroesToHeal do
        local health = Logic.GetEntityHealth(heroesToHeal[i]);
        local maxhealth = Logic.GetEntityMaxHealth(heroesToHeal[i]);
        local pos = GetPosition(heroesToHeal[i]);
        GUI.SendScriptCommand([[
            Logic.HealEntity(]]..heroesToHeal[i]..[[,]]..(maxhealth-health)..[[)
            local effectID = Logic.CreateEffect(EGL_Effects.E_HealingFX,]]..pos.X..[[,]]..pos.Y..[[,0)
            StartSimpleJobEx(function(effectID,time)
                if Logic.GetTime() > time+1 then
                    Logic.DestroyEffect(effectID)
                    return true
                end
            end,effectID,Logic.GetTime())
        ]]);
        GUI.SendCommandStationaryDefend(heroesToHeal[i]);
    end
end

-- Glocke des Himmels

Spells.BellOfHeaven    = {
    Name    = "BellOfHeaven";
    Icon    = {4,14};
    Cost    = 12;
    Range    = 750;
    Title    = {de = "Heilige Glocke"; en = "Holy Bell"};
    Text    = {de = "Die heilige Glocke wurde von oben entsandt um den Krieg zu beenden und die Feinde in Schmetterlinge zu verwandeln.";
               en = "The holy bell was send from above to end the war and to transform the agrressors into butterflys."};
};

function Spells.BellOfHeaven:action(_hero)
    local soldiers = {}
    for i=1,8 do
        local localSoldiers = GetPlayerEntities(i,0);
        for j=1,#localSoldiers do
            if  i ~= Logic.EntityGetPlayer(GetID(_hero.Name)) and Diplomacy_GetRelationBetween(i,Logic.EntityGetPlayer(GetID(_hero.Name))) == -2
            and Logic.IsEntityInCategory(localSoldiers[j],EntityCategories.Soldier) == 1
            and GetDistance(_hero.Name,localSoldiers[j]) <= self.Range then
                soldiers[#soldiers+1] = localSoldiers[j];
            end
        end
    end

    for i=1,#soldiers do
        GUI.SendScriptCommand([[
            local pos = GetPosition(]]..soldiers[i]..[[)
            Logic.CreateEffect(EGL_Effects.E_DieHero,pos.X,pos.Y,0)
            ReplaceEntity(]]..soldiers[i]..[[,Entities["A_Butterfly0"..math.random(1,6)])
        ]]);
    end
    Sound.FXPlay2DSound("ui\\menu_start_sermon");
end

-- Zufriedenheit

Spells.Satisfaction    = {
    Name    = "Satisfaction";
    Icon    = {16,2};
    Cost    = 9;
    Title    = {de = "Segnung"; en = "Blessing"};
    Text    = {de = "Der Zauberer macht alle Siedler in der Stadt zufrieden und heilt Krankheiten. Manchmal die Rettung in der Not.";
               en = "The magician make all settlers satisfied and cure their illnesses. Sometimes, it will be the savior in need."};
};

function Spells.Satisfaction:action(_hero)
    local pID = Logic.EntityGetPlayer(GetID(_hero.Name));
    local city = {Logic.GetPlayerEntitiesInCategory(pID,EntityCategories.CityBuilding)};
    local rim  = {Logic.GetPlayerEntitiesInCategory(pID,EntityCategories.OuterRimBuilding)};
    local pos = GetPosition(_hero.Name);
    local buildings = Array_Append(city,rim);

    for i=1,#buildings do
        GUI.SendScriptCommand([[
            Logic.SetNeedState(]]..buildings[i]..[[,Needs.Medicine,1)
            Logic.SetNeedState(]]..buildings[i]..[[,Needs.Nutrition,1)
            Logic.SetNeedState(]]..buildings[i]..[[,Needs.Hygiene,1)
            Logic.SetNeedState(]]..buildings[i]..[[,Needs.Clothes,1)
            Logic.SetNeedState(]]..buildings[i]..[[,Needs.Entertainment,1)
        ]]);
    end
    GUI.SendScriptCommand([[
        local effectID = Logic.CreateEffect(EGL_Effects.E_Knight_Song_Aura,]]..pos.X..[[,]]..pos.Y..[[,0)
        StartSimpleJobEx(function(effectID,time)
            if Logic.GetTime() > time+1 then
                Logic.DestroyEffect(effectID)
                return true
            end
        end,effectID,Logic.GetTime())
    ]]);
    GUI.SendCommandStationaryDefend(GetID(_hero.Name));
    Sound.FXPlay2DSound("units\\spouse_sexy_cheer3");
end

-- Gewitter

Spells.Thunderstorm    = {
    Name    = "Thunderstorm";
    Icon    = {2,1,1};
    Cost    = 12;
    Time    = 90;
    Range    = 250;
    LRange    = 2500;
    Damage    = 150;
    Title    = {de = "Himmlische Strafe"; en = "Divine Punishment"};
    Text    = {de = "Mächtiger Verteidigungsspruch. Der Zauberer beschwört mehrere Blitze, die um ihn herum einschlagen.";
               en = "A powerful defensive spell. The magician conjures multiple lightning bolts strike around them."};
};

function Spells.Thunderstorm:action(_hero)
    local pos = GetPosition(_hero.Name);

    StartSimpleJobEx( function(starttime,self,hero)
        local pos = GetPosition(hero.Name)
        -- Zauber ist beendet
        if Logic.GetTime() > starttime + self.Time or Logic.KnightGetResurrectionProgress(GetID(hero.Name)) ~= 1 then
            return true
        end
        if Logic.GetTime() > starttime then
            -- Feinde schädigen
            if math.random(1,100) <= 45 then
                local lPos = {X= pos.X + math.random(((-1)*self.LRange)/2,self.LRange/2), Y= pos.Y + math.random(((-1)*self.LRange)/2,self.LRange/2)};
                _hero:rangedEffect(lPos.X,lPos.Y,self);
                -- Zurücksetzen des überschüssigen Abzug
                _hero.Stats.Mana.Current = _hero.Stats.Mana.Current + self.Cost;
            end
        end

    end,Logic.GetTime(),self,_hero)
    GUI.SendCommandStationaryDefend(GetID(_hero.Name));
end

-- Ausnahmsweise, da mit RangedEffect gekoppelt!
function Spells.Thunderstorm:effect(_X,_Y)
    GUI.SendScriptCommand([[Logic.Lightning(]].._X..[[,]].._Y..[[)]]);
end
Zurück zu Hexerei | Drucken | Tags
Sofern nicht anders angegeben, steht der Inhalt dieser Seite unter Lizenz Creative Commons Attribution-ShareAlike 3.0 License