Setupinteractiveobject

Beschreibung

Normaler Weise haben Interaktive Objekte immer ihr Handsymbol und es steht immer der selbe vordefinierte Text da. In DIE SIEDLER - Reich des Ostens kommen Handelsposten und auffüllbare Minen hinzu. Aber wie wäre es, wenn man den Text des Tooltip und das Bild auf dem Button selbst bestimmen könnte? Das wird nun möglich sein.

Des weiteren ist es seit der Version 3.0 möglich für die selbst gebauten Interaktiven Objekte Kosten und Belohnungen zu definieren, ähnlich wie bei den normalen Objekten.
Wichtig: Alles was nicht I_X_ im Namen hat, gilt für den Assistenten nicht als interaktives Objekt!

Aktuelle Version: 3.1

SetupInteractiveObject

Die Funktion SetupInteractiveObject setzt die Definition des Objektes fest. Sie wird im globalen Skript aufgerufen und kann sowohl normale interaktive Objekte als auch selbsterstellte mit allem Drum und Dran einstellen. Das Skript erkennt von selbst, welchen Fall es behandeln muss.

Als erstes Argument wird der Skriptname der Entity übergeben, der eine Aktion zugewiesen wird. Das zweite Argument ist ein Table mit den Vereinbarungen zu dem Objekt. Alle Einträge sind optional, also könnte der Table theoretisch auch leer sein, was aber wenig Sinn macht ;) . Bei einem weggelassenen Eintrag wird ein Standartwert verwendet.

Argumententabelle

Argument Beschreibung
title Zeichenkette mit dem im Tooltip anzuzeigenden Titel.
text Zeichenkette mit dem im Tooltip anzuzeigenden Text. Das könnte z.B. eine Information sein, was passiert, wenn der Schalter getätigt wird.
texture Wenn eine andere Textur für den Button genutzt werden soll, müssen hier die Koordinaten als Table übergeben werden. Für die 3 Koordinate gilt:
  • {x, y, 0} Textur aus dem Hauptspiel
  • {x, y, 1} Textur aus der Erweiterung
  • {x, y, 2} Externe Grafik (Beta-Stadium)
state Der Status gibt an, wie das Objekt benutzt werden kann:
  • 0 : Kann nur vom Ritter benutzt werden
  • 1 : Kann immer benutzt werden
  • 2 : kann nicht benutzt werden

Dies zeigt keine Wirkung bei selbstgebauten Objekten!

distance Die Auslösedistanz für das interaktive Objekt.
Bei selbstgebauten Objekten muss diese Variable nil sein, damit das Objekt immer benutzbar ist. Sonst kann es nur von einem Ritter benutzt werden.
rewardType Typ der gefundenen Belohnung.
rewardAmount Anzahl an Einheiten der gefundenen Belohnung.
costType1 Typ der ersten Resource, die zum aktivieren benötigt wird.
costType2 Typ der ersten Resource, die zum aktivieren benötigt wird.
costAmount1 Anzahl des ersten Rohstoffs zur Aktivierung.
costAmount2 Anzahl des zweiten Rohstoffs zur Aktivierung.
callback Eine Aktion beim betätigen des Schalters auslösen. Mit dem Callback kann man z.B. Tore öffnen. An die Funktion wird ein Table _table als Argument übergeben, der alles beinhaltet, was bei der Erstellung vereinbart wurde, plus den Namen des Objektes abzurufen mit _table.name . _table ist natürlich ein frei wählbarer Bezeichner und kann auch t oder xyz sein.

Beispiel

Ein kleines Beispiel einer Ruine, die über die Funktion initialisiert wird. Dabei ist es unerheblich ob "echtes" interaktives Objekt oder nicht.

SetupInteractiveObject("ruin1",{
    rewardType    = Goods.G_Gold,
    rewardAmount  = 300,
    callback      = function(t)
              Logic.DEBUG_AddNote("Ihr habt etwas Gold Gefunden!")
        end
})
Beispiel

Functionscode

Der Funktionscode ist geteilt in globales und lokales Skript.

Es müssen die jeweiligen Teile in die vorgesehene Skriptumgebung kopiert werden.

Globales Skript

IO.PlayerID = 1

function InteractiveObjectActivate(eName)
    if not IsExisting(eName) then
        return
    end
    Logic.InteractiveObjectSetAvailability(GetID(eName),true)
    for i = 1, 8 do
        Logic.InteractiveObjectSetPlayerState(GetID(eName),i,0)
    end
end
function InteractiveObjectDeactivate(eName) 
    if not IsExisting(eName) then
        return
    end
    Logic.InteractiveObjectSetAvailability(GetID(eName),false)
    for i = 1, 8 do
        Logic.InteractiveObjectSetPlayerState(GetID(eName),i,2)
    end
end

function GameCallback_OnObjectInteraction(eID,pID)
    OnInteractiveObjectOpened(eID,pID)
    OnTreasureFound(eID,pID)

    local eName = Logic.GetEntityName(eID)
    for k,v in pairs(IO)do
        if k == eName then
            if not IO[eName].Used then
                IO[eName].callback(IO[eName])
                IO[eName].Used = true
            end
        end
    end
end

function SetupInteractiveObject(eName,t)
    assert(IsExisting(eName))
    local eID = GetID(eName)

    if not t.title then
        t.title = "Interaktives Objekt"
    end
    if not t.text then
        t.text = "Dieses Objekt kann benutzt werden."
    end
    if not t.texture then
        t.texture = {14,10,0}
    end
    if not t.texture[3] then
        t.texture[3] = 0
    end
    if not t.state then
        t.state = 0
    end
    if not t.callback then
        t.callback = function()end
    end
    t.name = eName;

    if Logic.IsInteractiveObject(eID) == true then
        -- init object
        t.distance = t.distance or 1600
        t.time = t.time or 0  
        t.rewardType = t.rewardType or nil            
        t.rewardAmount = t.rewardAmount or nil                                        
        t.costType1 = t.costType1 or nil             
        t.costAmount1 = t.costAmount1 or nil
        t.costType2 = t.costType2 or nil             
        t.costAmount2 = t.costAmount2 or nil

        Logic.InteractiveObjectClearCosts(eID)
        Logic.InteractiveObjectClearRewards(eID)
        Logic.InteractiveObjectSetInteractionDistance(eID,t.distance)
        Logic.InteractiveObjectSetTimeToOpen(eID,t.time)
        Logic.InteractiveObjectAddRewards(eID,t.rewardType,t.rewardAmount)
        Logic.InteractiveObjectAddCosts(eID,t.costType1,t.costAmount1)
        Logic.InteractiveObjectAddCosts(eID,t.costType2,t.costAmount2)

        Logic.InteractiveObjectSetAvailability(eID,true)
        Logic.InteractiveObjectSetPlayerState(eID,IO.PlayerID,t.state)
        Logic.InteractiveObjectSetRewardResourceCartType(eID,Entities.U_ResourceMerchant)  
        Logic.InteractiveObjectSetRewardGoldCartType(eID,Entities.U_GoldCart)  
        Logic.InteractiveObjectSetCostGoldCartType(eID, Entities.U_GoldCart)    
        Logic.InteractiveObjectSetCostResourceCartType(eID,Entities.U_ResourceMerchant) 
        table.insert(HiddenTreasures,eID)
        --save object
        IO[eName] = t
        -- execute description
        Logic.ExecuteInLuaLocalState([[
            SetupInteractiveObject("]]..eName..[[",{
                Title       = "]]..t.title..[[",
                Text       = "]]..t.text..[[",
                Texture = {]]..t.texture[1]..[[,]]..t.texture[2]..[[,]]..t.texture[3]..[[},
            })
        ]])
    else
        t.distance = t.distance or 1600
        t.rewardType = t.rewardType or nil            
        t.rewardAmount = t.rewardAmount or nil                                        
        t.costType1 = t.costType1 or nil             
        t.costAmount1 = t.costAmount1 or nil
        t.costType2 = t.costType2 or nil             
        t.costAmount2 = t.costAmount2 or nil

        -- save object
        IO[eName] = t
        -- execute description
        Logic.ExecuteInLuaLocalState([[
            SetupInteractiveObject("]]..eName..[[",{
                Title        = "]]..t.title..[[",
                Text        = "]]..t.text..[[",
                Costs        = {]]..tostring(t.costType1)..[[,]]..tostring(t.costAmount1)..[[,]]..tostring(t.costType2)..[[,]]..tostring(t.costAmount2)..[[},
                Reward   = {]]..tostring(t.rewardType)..[[,]]..tostring(t.rewardAmount)..[[},
                Texture  = {]]..t.texture[1]..[[,]]..t.texture[2]..[[,]]..t.texture[3]..[[},
                Distance = ]]..t.distance..[[,
                Callback  = "CallbackInGlobalLua",
            })
        ]])
    end
end

Lokales Skript

function SetupInteractiveObject(eName,t)
    g_Interaction.ActiveObjectsOnScreen = g_Interaction.ActiveObjectsOnScreen or {}
    assert(IsExisting(eName),"SetupInteractiveObject: Dein Objekt '"..eName.."' existiert nicht auf der Karte!")
    local eID = GetEntityId(eName)

    if not IO.Control then
        ControlInteractiveObject()
        IO.Control = true
    end

    if not t.Title then
        t.Title = "Interaktives Objekt"
    end
    if not t.Text then
        t.Text = "Dieses Objekt kann benutzt werden."
    end
    if not t.Texture then
        t.Texture = {14, 10}
    end
    if not t.Costs then
        t.Costs = {}
    end
    if not t.Callback then
        t.Callback = function()end
    end

    IO[eName] = t
end

function RemoveInteractiveObject(eName)
    for k,v in pairs(IO) do
        if k == eName then
            IO[eName] = nil
        end
    end
end

function ControlInteractiveObject()
    GUI_Tooltip.SetNameAndDescription_OrigtwAIO = GUI_Tooltip.SetNameAndDescription
    GUI_Tooltip.SetNameAndDescription = function(_TooltipNameWidget, _TooltipDescriptionWidget, _OptionalTextKeyName, _OptionalDisabledTextKeyName, _OptionalMissionTextFileBoolean)
        if XGUIEng.GetWidgetPathByID(XGUIEng.GetCurrentWidgetID()) == "/InGame/Root/Normal/InteractiveObjects/1" 
        or XGUIEng.GetWidgetPathByID(XGUIEng.GetCurrentWidgetID()) == "/InGame/Root/Normal/InteractiveObjects/2" then
            GUI_Tooltip.SetNameAndDescription_OrigtwAIO(_TooltipNameWidget, _TooltipDescriptionWidget, _OptionalTextKeyName, _OptionalDisabledTextKeyName, _OptionalMissionTextFileBoolean)

            local number = tonumber(XGUIEng.GetWidgetNameByID(XGUIEng.GetCurrentWidgetID()))
            local objectID = g_Interaction.ActiveObjectsOnScreen[number]

            for k,v in pairs(IO) do
                if objectID == GetEntityId(k)then
                    XGUIEng.SetText(_TooltipNameWidget, Umlaute("{center}"..IO[k].Title))
                    XGUIEng.SetText(_TooltipDescriptionWidget, Umlaute(IO[k].Text))
                    local TTH = XGUIEng.GetTextHeight(_TooltipDescriptionWidget, true)
                    local W, H = XGUIEng.GetWidgetSize(_TooltipDescriptionWidget)
                    XGUIEng.SetWidgetSize(_TooltipDescriptionWidget, W, TTH)
                end
            end
        else
            GUI_Tooltip.SetNameAndDescription_OrigtwAIO(_TooltipNameWidget, _TooltipDescriptionWidget, _OptionalTextKeyName, _OptionalDisabledTextKeyName, _OptionalMissionTextFileBoolean)
        end
    end

    GUI_Interaction.InteractiveObjectUpdate_OrigtwAIO = GUI_Interaction.InteractiveObjectUpdate
    GUI_Interaction.InteractiveObjectUpdate = function()
        GUI_Interaction.InteractiveObjectUpdate_OrigtwAIO()
        local pID = GUI.GetPlayerID()

        for k,v in pairs(IO)do
            local eType = Logic.GetEntityType(GetEntityId(k))
            local eTypeName = Logic.GetEntityTypeName(eType)

            for j=1, #g_Interaction.ActiveObjectsOnScreen do
                local path = "/InGame/Root/Normal/InteractiveObjects/"..j
                if XGUIEng.IsWidgetExisting(path) == 1 then
                    local objectID = g_Interaction.ActiveObjectsOnScreen[j]
                    local entityName = Logic.GetEntityName(objectID)

                    if k == entityName then
                       UserSetButtonTexture(path,IO[k].Texture)
                    end
                end
            end
            if eTypeName then
                if  not(string.find(eTypeName,"I_X_")) and not(string.find(eTypeName,"Mine"))  then
                    if IO[k].Distance ~= nil and IO[k].Distance > 0 then
                        local pos = GetPosition(k)
                        local entities = {Logic.GetPlayerEntitiesInArea(pID,0,pos.X,pos.Y,IO[k].Distance,16)}

                        local found = false
                        if entities[1] > 0 then
                            for i=1,#entities do
                                if Logic.IsEntityInCategory(entities[i],EntityCategories.Hero) == 1 then
                                    found = true
                                end
                            end
                        end
                        if found and not IO[k].Used then
                            ScriptCallback_ObjectInteraction(pID,GetEntityId(k))
                        else
                            ScriptCallback_CloseObjectInteraction(pID,GetEntityId(k))
                        end
                    else
                        if not IO[k].Used then
                            ScriptCallback_ObjectInteraction(pID,GetEntityId(k))
                        else
                            ScriptCallback_CloseObjectInteraction(pID,GetEntityId(k))
                        end
                    end
                end
            end
        end
    end

    GUI_Interaction.InteractiveObjectMouseOver_OrigtwAIO = GUI_Interaction.InteractiveObjectMouseOver
    GUI_Interaction.InteractiveObjectMouseOver = function()
        local ButtonNumber = tonumber(XGUIEng.GetWidgetNameByID(XGUIEng.GetCurrentWidgetID()))
        local eID = g_Interaction.ActiveObjectsOnScreen[ButtonNumber]
        local eName = Logic.GetEntityName(eID)
        local pID = GUI.GetPlayerID()

        if Logic.IsInteractiveObject(eID) then
            GUI_Interaction.InteractiveObjectMouseOver_OrigtwAIO()
        else
            if IO[eName] and IO[eName].Used ~= true then
                local CurrentWidgetID = XGUIEng.GetCurrentWidgetID()
                local TooltipTextKey = "InteractiveObjectAvailable"

                local Costs = {}
                if IO[eName].Costs[1] ~= nil then
                    table.insert(Costs,IO[eName].Costs[1])
                    table.insert(Costs,IO[eName].Costs[2])
                end
                if IO[eName].Costs[3] ~= nil then
                    table.insert(Costs,IO[eName].Costs[3])
                    table.insert(Costs,IO[eName].Costs[4])
                end

                local CheckSettlement
                if Costs and Costs[1]
                and Logic.GetGoodCategoryForGoodType(Costs[1]) ~= GoodCategories.GC_Resource then
                    CheckSettlement = true
                end
                GUI_Tooltip.TooltipBuy(Costs, TooltipTextKey, nil, nil, CheckSettlement)
            end
        end
    end

    GUI_Interaction.InteractiveObjectClicked_OrigtwAIO = GUI_Interaction.InteractiveObjectClicked
    GUI_Interaction.InteractiveObjectClicked = function()
        GUI_Interaction.InteractiveObjectClicked_OrigtwAIO()
        local i = tonumber(XGUIEng.GetWidgetNameByID(XGUIEng.GetCurrentWidgetID()))
        local eID = g_Interaction.ActiveObjectsOnScreen[i]
        local pID = GUI.GetPlayerID()

        for k,v in pairs(IO)do
            if eID == GetEntityId(k)then
                local Reward = {}
                if IO[k].Reward and IO[k].Reward[1] ~= nil then
                    table.insert(Reward,IO[k].Reward[1])
                    table.insert(Reward,IO[k].Reward[2])
                end

                local CheckSettlement
                if IO[k].Costs and IO[k].Costs[1] then
                    if Logic.GetGoodCategoryForGoodType(IO[k].Costs[1]) ~= GoodCategories.GC_Resource then
                        CheckSettlement = true
                    end

                    local Costs = {}
                    if IO[k].Costs[1] ~= nil then
                        table.insert(Costs,IO[k].Costs[1])
                        table.insert(Costs,IO[k].Costs[2])
                    end
                    if IO[k].Costs[3] ~= nil then
                        table.insert(Costs,IO[k].Costs[3])
                        table.insert(Costs,IO[k].Costs[4])
                    end

                    local CanBuyBoolean, CanNotBuyString = AreCostsAffordable(Costs,CheckSettlement)
                    if CanBuyBoolean == true then
                        -- remove costs
                        if Costs[1] ~= nil then
                            if Logic.GetGoodCategoryForGoodType(Costs[1]) ~= GoodCategories.GC_Resource and Costs[1] ~= Goods.G_Gold then
                                local buildings = GetPlayerEntities(pID,0)
                                local goodAmount = Costs[2]
                                for i=1,#buildings do
                                    if Logic.IsBuilding(buildings[i]) == 1 and goodAmount > 0 then
                                        if Logic.GetBuildingProduct(buildings[i]) == Costs[1] then
                                            local goodAmountInBuilding = Logic.GetAmountOnOutStockByIndex(buildings[i],0)
                                            for j=1,goodAmountInBuilding do
                                                GUI.SendScriptCommand("Logic.RemoveGoodFromStock("..buildings[i]..","..Costs[1]..",1)")
                                                goodAmount = goodAmount -1
                                            end
                                        end
                                    end
                                end
                            else
                                GUI.SendScriptCommand("AddGood("..IO[k].Costs[1]..",-"..IO[k].Costs[2]..","..pID..")")
                            end
                        end
                        if Costs[3] ~= nil then 
                            if Logic.GetGoodCategoryForGoodType(Costs[3]) ~= GoodCategories.GC_Resource and Costs[3] ~= Goods.G_Gold then
                                local buildings = GetPlayerEntities(pID,0)
                                local goodAmount = Costs[4]
                                for i=1,#buildings do
                                    if Logic.IsBuilding(buildings[i]) == 1 and goodAmount > 0 then
                                        if Logic.GetBuildingProduct(buildings[i]) == Costs[3] then
                                            local goodAmountInBuilding = Logic.GetAmountOnOutStockByIndex(buildings[i],0)
                                            for j=1,goodAmountInBuilding do
                                                GUI.SendScriptCommand("Logic.RemoveGoodFromStock("..buildings[i]..","..Costs[3]..",1)")
                                                goodAmount = goodAmount -1
                                            end
                                        end
                                    end
                                end
                            else
                                GUI.SendScriptCommand("AddGood("..IO[k].Costs[3]..",-"..IO[k].Costs[4]..","..pID..")")
                            end
                        end
                        -- reward
                        if #Reward > 0 then
                            GUI.SendScriptCommand([[
                                local goodAmount = ]]..Reward[2]..[[
                                local goodType = ]]..Reward[1]..[[
                                local pos = GetPosition("]]..k..[[")
                                local resCat = Logic.GetGoodCategoryForGoodType(goodType)
                                local ID
                                if resCat == GoodCategories.GC_Resource then
                                    ID = Logic.CreateEntityOnUnblockedLand(Entities.U_ResourceMerchant, pos.X, pos.Y,0,]]..pID..[[)
                                elseif goodType == Goods.G_Medicine then
                                    ID = Logic.CreateEntityOnUnblockedLand(Entities.U_Medicus, pos.X, pos.Y,0,]]..pID..[[)
                                elseif goodType == Goods.G_Gold then
                                    ID = Logic.CreateEntityOnUnblockedLand(Entities.U_GoldCart, pos.X, pos.Y,0,]]..pID..[[)
                                else
                                    ID = Logic.CreateEntityOnUnblockedLand(Entities.U_Marketer, pos.X, pos.Y,0,]]..pID..[[)
                                end
                                Logic.HireMerchant(ID,]]..pID..[[,goodType,goodAmount,]]..pID..[[)
                            ]])
                        end
                        if Logic.IsInteractiveObject(eID) ~= true then
                            Sound.FXPlay2DSound( "ui\\menu_left_prestige")
                        end
                        -- do callback
                        if type(IO[k].Callback) == "string" then
                            GUI.SendScriptCommand("IO['"..k.."'].callback(IO['"..k.."'])")
                        else
                            IO[k].Callback(IO[k])
                        end
                        IO[k].Used = true
                    else
                        Message(CanNotBuyString)
                    end
                else
                    -- reward
                    if #Reward > 0 then
                        GUI.SendScriptCommand([[
                            local goodAmount = ]]..Reward[2]..[[
                            local goodType = ]]..Reward[1]..[[
                            local pos = GetPosition("]]..k..[[")
                            local resCat = Logic.GetGoodCategoryForGoodType(goodType)
                            local ID
                            if resCat == GoodCategories.GC_Resource then
                                ID = Logic.CreateEntityOnUnblockedLand(Entities.U_ResourceMerchant, pos.X, pos.Y,0,]]..pID..[[)
                            elseif goodType == Goods.G_Medicine then
                                ID = Logic.CreateEntityOnUnblockedLand(Entities.U_Medicus, pos.X, pos.Y,0,]]..pID..[[)
                            elseif goodType == Goods.G_Gold then
                                ID = Logic.CreateEntityOnUnblockedLand(Entities.U_GoldCart, pos.X, pos.Y,0,]]..pID..[[)
                            else
                                ID = Logic.CreateEntityOnUnblockedLand(Entities.U_Marketer, pos.X, pos.Y,0,]]..pID..[[)
                            end
                            Logic.HireMerchant(ID,]]..pID..[[,goodType,goodAmount,]]..pID..[[)
                        ]])
                    end
                    if Logic.IsInteractiveObject(eID) ~= true then
                        Sound.FXPlay2DSound( "ui\\menu_left_prestige")
                    end
                    -- do callback
                    if type(IO[k].Callback) == "string" then
                        GUI.SendScriptCommand("IO['"..k.."'].callback(IO['"..k.."'])")
                    else
                        IO[k].Callback(IO[k])
                    end
                    IO[k].Used = true
                end
            end
        end
    end
end

function UserSetButtonTexture(widget, coord, size, file)
    assert((type(widget) == "string" or type(widget) == "number"));

    local mapname = Framework.GetCurrentMapName();
    local wID = XGUIEng.GetWidgetID(widget);
    if coord[3] == nil then coord[3] = 0 end
    if size == nil then size = 64 end
    local path = "C:\\Settlers RoaE\\"..mapname.."\\"

    local state = 1;
    if XGUIEng.IsButton(wID) == 1 then
        state = 7;
    end

    if coord[3] == 0 then
        SetIcon(wID,coord);
    elseif coord[3] == 1 then
        SetIcon(wID,coord);
    elseif coord[3] == 2 then
        local screenSize = {GUI.GetScreenSize()};
        local sizeBase = {}
        if file == nil then 
            file = "icons.png";
            sizeBase[1] = 2000;
            sizeBase[2] = 1140;
        end

        if coord[1] == -1 and coord[2] == -1 then
            XGUIEng.SetMaterialAlpha(wID,state, 0);
        else
            XGUIEng.SetMaterialAlpha(wID,state, 255);

            local u0 = (coord[1] - 1) * (size * (sizeBase[1]/screenSize[1]));
            local v0 = (coord[2] - 1) * (size * (sizeBase[2]/screenSize[2]));
            local u1 = coord[1] * (size * (sizeBase[1]/screenSize[1]));
            local v1 = coord[2] * (size * (sizeBase[2]/screenSize[2]));

            XGUIEng.SetMaterialTexture(wID,state,path .. file);
            XGUIEng.SetMaterialUV(widget,state,u0,v0,u1,v1);
        end
    end
end

Demo-Map

<nicht vorhanden>

Zurück zu Funktionssammlungen | Drucken | Tags
Sofern nicht anders angegeben, steht der Inhalt dieser Seite unter Lizenz Creative Commons Attribution-ShareAlike 3.0 License