Events - Einschneidende Ereignisse nach Bauplan erstellen

Einleitung

Du kennst sicher schon die Erdbeben, die von Zeit zu Zeit in einer Map auftauchen. Dies ist leider das einzige Event, das funktionsfähig im Spiel vorkommt. Dabei hat Blue Byte ein komplexes Eventsystem vorgesehen mit dem man Ereignisse und Quests erstellen und verknüpfen kann. Es gibt neben den Erdbeben einige andere Events, die jedoch nicht korrekt funktionieren.

Ich möchte hier eine kleine Anleitung geben, wie du dir ein Event erstellen kannst. Wenn du dich dazu an einige wenige Regeln hälst, gewinnst du ein mächtiges Werkzeug zur Unterhaltung der Spielerschaft!

Events werden im globalen Skript angelegt!

Wie funktioniert ein Event?

Events laufen stets nach dem selben Schema ab. Zuerst wird das Event initialisiert. Das passiert, sobald die Startfunktion aufgerufen wird. Dann prüft das System ob die Bedingungen erfüllt sind, damit das Ereignis ausgelöst wird. Ist das der Fall, wird die Trigger-Funktion aufgerufen. Ihre Aufgabe ist es Aktionen auszuführen, die für den korreckten Ablauf des Events unverzichtbar sind. Zum Beispiel kann sie ein Wetterereignis zuschalten. Danach wird für die Laufzeit die Run-Funktion jede Sekunde aufgerufen. Hier geschehen die eigentlichen Konsequenzen für den Spieler. Nach Ablauf der Zeit kann das Event entweder terminieren oder sich schlafen legen, um erneut ausgelöst zu werden.

Aufbau eines Events

Ein Event besteht immer aus einer Table und einer Startfunktion. In der Startfunktion werden die notwendigen Einstellungen durch den Benutzer vorgenommen. Die Table hält die Daten und Methoden des Events. Notwendige Daten sind der Name des Events, welcher identisch sein muss mit dem Bezeichner der Table, die Data-Table, in der die eigentlichen Daten für das Event stehen und eine leer initialisierte Table Player, die jedoch weggelassen werden kann, wenn das Event nicht für spezielle Spieler ausgelöst werden soll.

In folgender Tabelle siehst du eine Übersicht der Funktionen und für was sie zuständig sind:

Initialize: Callback nach der Initialisierung
Condition: Bedingung um das Event zu triggern
Trigger: Funktion, die beim Start aufgerufen wird
Run: Loop-Funktion, die während des Event sekündlich aufgerufen wird

Es können beliebig viel weitere Daten und Methoden hinzugefügt werden!

Das leere Gerüst eines Events sieht demzufolge so aus:

function Event_AddExample(PlayerList, TimeStartList, Duration, Repeat)
    Example.Data.Duration = Duration;
    Example.Data.Repeat = (Repeat ~= nil and Repeat) or false;
    if type(TimeStartList) == "table" then
        EventSystem_AddForPlayers(Example, PlayerList)
        for i=1, #TimeStartList do
            Example.Players[PlayerList[i]].TimeStart = TimeStartList[i]
        end
    else
        Example.Data.TimeStart = TimeStartList
        EventSystem_AddForPlayers(Example, PlayerList)
    end
end

Example = {
    Name = "Example";
    Players = {};

    Data = {
        State = EventState.Waiting;
        TimeStart = 240;
        Duration = 120;
        Repeat = true;
    };

    Initialize = function()
    end,

    Condition = function()
        return true;
    end,

    Trigger = function()
    end,

    Run = function()
    end,
}

Beispiel für ein Event

Dieses Event löst eine Seuche aus, sobald die Monsunzeit beginnt. Also ein Tropenfieber. Sobald die Zeit abgelaufen ist, oder die Regenzeit endet, terminiert das Event.

function Event_AddFever(PlayerList, TimeStartList, Duration, MaxBuildings, Chance, Repeat)
    if not g_PatchIdentifierExtra1 then
        return
    end
    Fever.Data.Duration = Duration;
    Fever.Data.MaxBuildings = MaxBuildings or 5;
    Fever.Data.Chance = Chance or 40;
    Fever.Data.Repeat = (Repeat ~= nil and Repeat) or false;
    if type(TimeStartList) == "table" then
        EventSystem_AddForPlayers(Fever, PlayerList)
        for i=1, #TimeStartList do
            Fever.Players[PlayerList[i]].TimeStart = TimeStartList[i]
        end
    else
        Fever.Data.TimeStart = TimeStartList
        EventSystem_AddForPlayers(Fever, PlayerList)
    end
end

Fever = {
    Name = "Fever";
    Players = {};

    Data = {
        State = EventState.Waiting;
        TimeStart = 240;
        Duration = 120;
        MaxBuildings = 0;
        Chance = 40;
        Repeat = true;
    };
    GlobalDelay = 600;

    Initialize = function()
    end;

    Condition = function()
        local pID = Fever.Data.PlayerID;
        local city =  { Logic.GetPlayerEntitiesInCategory(pID,EntityCategories.CityBuilding) }
        local rim  =  { Logic.GetPlayerEntitiesInCategory(pID,EntityCategories.OuterRimBuilding) }
        city = Array_Append(city,rim);
        local month = Logic.GetCurrentMonth();
        local time = Logic.GetTime();
        local condition = Logic.GetWeatherDoesShallowWaterFlood(month) and Fever.Data.TimeStart < time and #city > 0
        return condition;
    end;

    Trigger = function()
    end;

    Run = function()
        local isTimeElapsed = Fever.Data.TimeStart + Fever.Data.Duration < Logic.GetTime();
        if isTimeElapsed or not Logic.GetWeatherDoesShallowWaterFlood() then
            Fever.Data.State = EventState.Over;
            if Fever.Data.Repeat then
                Fever.Data.State = EventState.Waiting;
            end
            Fever.Data.TimeStart = Logic.GetTime() + Fever.GlobalDelay;
            return;
        end
        Fever.Spread();
        Fever.Display();
    end;

    Spread = function()
        local pID = Fever.Data.PlayerID;
        local chance = math.random(1,100);
        if chance < 41 then
            local city =  { Logic.GetPlayerEntitiesInCategory(pID,EntityCategories.CityBuilding) }
            local rim  =  { Logic.GetPlayerEntitiesInCategory(pID,EntityCategories.OuterRimBuilding) }
            city = Array_Append(city,rim);

            if #city > 0 and Fever.Data.MaxBuildings > 0 then
                local currentIll = 0;
                for i=1,#city do
                    if Logic.GetNeedState(city[i],Needs.Medicine) == 0 then
                        currentIll = currentIll +1;
                    end
                end
                if currentIll < Fever.Data.MaxBuildings then
                    local randVictim = math.random(1,#city);
                    local eID = city[randVictim];
                    local eType = Logic.GetEntityType(eID);
                    local eTName = Logic.GetEntityTypeName(eType);
                    if not string.find(eTName,"Pharmacy") then
                        Fever.Data.Buildings = Fever.Data.Buildings +1;
                        Logic.SetNeedState(eID,Needs.Medicine,0);
                    end
                end
            end
        end
    end;

    Display = function()
        if Logic.GetTime() % 8 == 0 then
            Logic.ExecuteInLuaLocalState([[
                Fever_SequenceID = Display.AddEnvironmentSettingsSequence("AS_PermanentMonsoon.xml");
                Display.PlayEnvironmentSettingsSequence(Fever_SequenceID, 50.0)
            ]])
        end
    end;
}
Sofern nicht anders angegeben, steht der Inhalt dieser Seite unter Lizenz Creative Commons Attribution-ShareAlike 3.0 License