Benutzer-Werkzeuge

Webseiten-Werkzeuge


utilfunctions:vergiften

Inhaltsverzeichnis

Vergiften

Mit diesem Code kann man ein Gebiet verseuchen. Alle Entities die in die Nähe dieses Gebietes kommen, werden mit einer tödlichen Krankheit infiziert. Infizierte Einheiten werden innerhalb kürzester Zeit sterben. Außerdem ist diese Krankheit ansteckend, so dass eine infizierte Einheit andere Einheiten anstecken kann, wenn sie nur nahe genug kommt.

Code

-- Mit dieser Funktion kann eine Script Entity oder ein NPC als "Quelle" allen Übels erstellt werden.
-- Diese Entity wird nicht von der Krankheit befallen und hat einen größeren Ansteckungsradius als die infizierten Einheiten.
-- Der Funktion kann die ID oder der Name als Parameter übergeben werden.
function AddPoisonEntity(_entity)
    -- Erster Funktionsaufruf
    if not gvPoisonJobId then
        -- gvPoisonedEntities: Ein Table, welches alle infizierten Einheiten speichert
        -- gvPoisonJobId: Die ID des Jobs, der für den Effekt gebraucht wird
        gvPoisonedEntities, gvPoisonJobId = {}, StartSimpleJob("Poison")
    end
 
    -- Die ID der Quell-Einheit speichern
    -- Das true bedeutet, dass diese Einheit nicht von der Krankheit befallen werden kann.
    -- Außerdem hat sie dadurch einen größeren Ansteckungsradius
    table.insert(gvPoisonedEntities, {GetEntityId(_entity), true})
end
 
-- Der Job, der die Krankheit steuert
function Poison()
    -- Alle infizierten Einheiten durchgehen
    -- Von hinten anfangen, damit bereits gestorbene Einheiten problemlos aus de Table entfernt werden können
    for i = table.getn(gvPoisonedEntities), 1, -1 do
        -- Die ID und den Status (Quelle oder infiziert) merken
        local id, center = gvPoisonedEntities[i][1], gvPoisonedEntities[i][2]
 
        -- Wenn Einheit bereits tot...
        if IsDead(id) then
            -- ... aus dem Table der infizierten Einheiten löschen
            table.remove(gvPoisonedEntities, i)
            -- Für die Einheit wurde ein Counter benutzt, der kann jetzt gelöscht werden
            Counter["poison" .. id] = nil
 
        -- Einheit lebt noch
        else
            -- p: Das ist die aktuelle Position der Einheit
            -- c: Das ist der Ansteckungsradius der infizierten Einheit
            local p, c = GetPosition(id), 500
 
            -- Wenn die Einheit eine Quelle ist...
            if center then
                -- ... ist der Ansteckungsradius größer
                c = 1000
            end
 
            -- Alle 5 Sekunden sollen ein paar Effekte erstellt werden, die zeigen das die Einheit infizier ist
            if Counter.Tick2("poison" .. id, 5) then
                -- Das kann auch ein anderer Effet sein. Statt dem rosa Nebel von Mary ginge z.B. auch der grüne von Kala
                -- Der Effekt erscheint genau an der Position der Einheit
                Logic.CreateEffect(GGL_Effects.FXMaryPoison, p.X, p.Y, 2);
 
                -- Wenn es sich um eine Quelle handelt, ist der Ansteckungsradius größer,
                -- deshalb werden hier noch ein paar zusätzliche Nebel um die Einheit erstellt
                -- Diese Nebel erscheinen kreisförmig im die aktuelle Position
                if center then
                    -- r: Anfangswinkel, sollte immer bei 0 bleiben
                    -- s: Beeinflusst die Anzahl der zusätzlichen Nebel, 4 ist schon ganz gut. Die Zahl nicht zu groß wählen.
                    local r, s = 0, 4
 
                    -- Die Winkelangaben sind im Bogenmaß, also von 0 bis 2*PI
                    -- Es reicht die Positionen für einen Halbkreis zu berechnen und dann an der Mittellinie zu spiegeln
                    while r < math.pi do
                        -- Ein bisschen Mathematik...
                        -- Rechtwinklige Dreiecke in einem Halbkreis. Die Seiten des Dreickes sind a, b und c.
                        -- Seite c und Winkel alpha (r) ist gegeben. Daraus lassen sich die Seiten a und b berechnen.
                        -- (Siehe auch das Bild unten)
                        local a, b = c * math.sin(r), c * math.cos(r)
 
                        -- a und b sind genau die Abstände vom Mittelpunkt für die neuen Effekte.
                        -- Einmal zur aktuellen Position addiert und zum Spiegeln subtrahiert.
                        Logic.CreateEffect(GGL_Effects.FXMaryPoison, p.X + a, p.Y + b, 1)
                        Logic.CreateEffect(GGL_Effects.FXMaryPoison, p.X - a, p.Y - b, 1)
 
                        -- Den Winkel erhöhen
                        r = r + math.pi / s
                    end
                end
            end
 
            -- Alle Einheiten in der Nähe erfassen, liefert maximal 16 Einheiten
            -- 1 ist de SpielerID, 0 steht für alle Einheitentypen, p.X/p.Y ist die aktuelle Position,
            -- c der Ansteckungsradius und die 16 steht für maximal 16 Einheiten
            local data = {Logic.GetPlayerEntitiesInArea(1, 0, p.X, p.Y, c, 16)}
            -- data[1] enthält die Anzahl der in der Nähe befindlichen Einheiten
            local n = data[1]
 
            -- Alle diese Einheiten einzeln durchgehen
            for j = 2, n + 1 do
                -- Nur wenn es kein Gebäude ist weitermachen
                if Logic.IsBuilding(data[j]) == 0 then
                    -- Wenn die Einheit noch nicht infiziert ist...
                    if not GetPoisonedEntity(data[j]) then
                       -- infizieren;)
                       -- Wieder die ID speichern. Diesmal noch false setzen, da es keine Quelleinheit ist
                       table.insert(gvPoisonedEntities, {data[j], false})
                    end
                end
            end
 
            -- Zum Schluss noch die bereits infizierte Einheit verletzten, falls es keine Quelle ist
            if not center then
                -- Die 25 steht für die pro Sekunde abgezogenen Lebenspunkte. Das kann man erhöhen oder verringern wie man will.
                -- Bei zu niedrigen werden werden Helden aber nicht mehr sterben, weil sie sich selbst viel schneller heilen.
                Logic.HurtEntity(id, 25)
            end
        end
    end
end
 
-- Diese Funktion prüft ob eine Einheit bereits infiziert wurde und gibt dann true zurück, ansonsten nil
function GetPoisonedEntity(_id)
    -- Warum das so funktioniert steht im Lua-Maunal (auf Englisch;))
    return table.foreach(gvPoisonedEntities, function(__k, __v)
                                                if _id == __v[1] then
                                                    return true
                                                end
                                             end)
end

Bild

Gegeben:
A: Die aktuelle Position ist der Mittelpunkt in X/Y Koordinaten
c: Radius des Kreises
r: Winkel alpha

Gesucht:
B: X/Y Koordinaten des neuen Punktes auf dem Kreis um den Mittelpunkt
a,b: Die anderen Seiten des Dreiecks. Damit lassen sich dann die Koordinaten des Punktes B brechnen.

TODOs

Es gibt keine Funktionen mit denen man die ganze Prozedur stoppen kann oder nur einzelne Quell-Entities löschen kann.

utilfunctions/vergiften.txt · Zuletzt geändert: 2021/09/18 19:16 (Externe Bearbeitung)