NPC verwandelt sich in Leibeigenen

» Siedler Map Source Forum » Siedler DEdK Script Forum » NPC verwandelt sich in Leibeigenen

Seiten: 1

Messoras
#1
25.09.2017 00:10
Beiträge: 84

NPC verwandelt sich in Leibeigenen

Hallo zusammen, ich habe nach einiger Zeit doch mal wieder zu Siedler 5 zurück gefunden und skripte auch schon wieder eifrig.
Dabei habe ich folgendes Problem:
Ich lasse einen Sägewerker aus dem Sägewerk kommen, der als NPC dient. Er kommt ganz normal heraus, doch sobald er stehen bleibt und untätig (also die Tasklist auf Idle gesetzt) wird, verwandelt er sich auf einmal in einen Leibeigenen.
Sobald er anfängt wieder irgendwo hin zu laufen oder ähnliches, wird er wieder zum Sägewerker. Ich habe den Verdacht, dass die Tasklist nicht 100% kompatibel ist.

Hier ist mein Code:

Erstmal die Funktionen, die ich mir zur Hilfe gebastelt habe (Wiederverwertung ftw):

function CreateCustomNPC(_name,_trigger,_callback)

    -- callback prüfen
    assert(type(_callback)=="function","CustomNPC: Falsche oder keine Callbackfunktion. Funktion erlaubt")

    -- name prüfen
    assert(type(_name)=="string","CustomNPC: Falscher oder kein Name. String erlaubt")

    -- trigger prüfen
    assert(type(_trigger)=="string" or type(_trigger)=="table" or type(_trigger)=="function", 
        "CustomNPC: Falscher oder kein Trigger. String, Funktion oder Table erlaubt")

    -- NPC erstellen ( Ausrufezeichen )
    local npc  = { name = _name, callback = _callback }
    CreateNPC(npc)

    -- Implementierung des Triggers ( Entity/Entities oder Funktion )
    TriggerNPCJob = function(_nameloc, _triggerloc, _callbackloc, _npcloc)
        if type(_triggerloc) == "table" then
            for i = 1, _triggerloc.n do
                if IsNear(_triggerloc[i],_nameloc,300) then
                    _callbackloc()
                    DestroyNPC(_npcloc)
                    return true
                end
            end
        elseif type(_triggerloc) == "string" then
            if IsNear(_triggerloc,_nameloc,300) then
                _callbackloc()
                DestroyNPC(_npcloc)
                return true
            end
        elseif type(_triggerloc) == "function" then
            if _triggerloc() then
                _callbackloc()
                DestroyNPC(_npcloc)
                return true
            end
        elseif not _triggerloc then
            Message("Trigger is nil")
            return true
        end
    end

    StartSimpleJob("TriggerNPCJob",_name,_trigger,_callback,npc)

end
function GhostMove(_unit, _target)
    
    -- unit prüfen
    assert(type(_unit)=="string","CustomNPC: Falscher oder kein Einheitenname. String erlaubt.")

    -- target prüfen
    assert(type(_target)=="string","CustomNPC: Falscher oder kein Zielname. String erlaubt.")

    -- Blocking deaktivieren
    Logic.SetTaskList(GetID(_unit), TaskLists.TL_LEAVE_KEEP)
    local p = GetPosition(_target)

    -- Zielposition überschreiben
    Logic.MoveEntity(GetID(_unit), p.X, p.Y)

    -- Blocking wieder aktivieren
    StartSimpleJob("ArrivedJob",_unit,_target)

end
function NewNPCFromHouse(_npcName, _entityType, _playerID, _housePos, _targetPos)

    -- npcName prüfen
    assert(type(_npcName)=="string","CustomNPC: Falscher oder kein NPCname. String erlaubt.")

    -- entityType prüfen
    assert(type(_entityType)=="number","CustomNPC: Falscher oder kein Zielname. EntityType ( -> Nummer ) erlaubt.")

    -- playerID prüfen
    assert(type(_playerID)=="number","CustomNPC: Falsche oder keine PlayerID. Number erlaubt.")

    -- housePos prüfen
    assert(type(_housePos)=="string","CustomNPC: Falscher oder kein Gebäudename. String erlaubt.")

    -- target prüfen
    assert(type(_targetPos)=="string","CustomNPC: Falscher oder kein Zielname. String erlaubt.")

    -- Entity erstellen
    local pos = GetPosition(_housePos)
    Logic.SetEntityName( Logic.CreateEntity( _entityType, pos.X, pos.Y, 0, _playerID),_npcName )

    -- bewegen
    GhostMove(_npcName, _targetPos)
end
function ArrivedJob (_unit, _target)

    if IsNear(_unit,_target,50) then
        -- Blocking aktivieren und NPC abwarten lassen
        Logic.SetTaskList(GetID(_unit), TaskLists.TL_NPC_IDLE)
		return true
    end

end



Und hier jetzt der Aufruf:

NewNPCFromHouse("sawyer_1",Entities.PU_Sawmillworker,2,"sawmill","sawyer_1_pos")
CreateCustomNPC("sawyer_1","messoras_child",SawyerBriefing1)



Gibt's eventuell ein Problem mit der Untätigkeit eines Arbeiters?
Sprich: Darf ich

Logic.SetTaskList(GetID("sawyer_1"), TaskLists.TL_NPC_IDLE)

benutzen?

Genau das gleiche hat mit einer Prinzessin funktioniert!

Danke im Voraus.

LG,
Messoras

____________________
Six feet of earth make us all equal.

Spielt Siedler 5 online mit mir, dank des neuen Siedler 5 MP Projekts von Kimichura.

mcb
#2
25.09.2017 01:15
Beiträge: 1472

Das liegt wahrscheinlich an der Serf-TaskList. Normalerweise gebe ich einfach einen normalen Befehl, sobald das Entity am Ziel angekommen ist um genau das zu verhindern. Bei dem Sawmillworker könnte NPC_Idle helfen, ich hatte damit aber auch schon Probleme (irgendwann ist er aus Arbeitsplatzmangel zum DZ raus...)
Am einfachsten wäre wohl ein HiResJob der das jeden Tick neu setzt. Oder du nimmst einen AfraidSawmillworker und setzt einfach eine normale Idle-Animation (sollte funktionieren, die haben dasselbe Model).

Messoras
#3
25.09.2017 11:08
Beiträge: 84

Ich müsste also meine ArrivedJob Funktion in etwa wie folgt verändern:

function ArrivedJob (_unit, _target)

	if IsNear(_unit,_target,50) then
		-- Blocking aktivieren und NPC abwarten lassen
		Logic.SetTaskList(GetID(_unit), TaskLists.TL_NPC_IDLE)
		--Leibeigenen Bug fixen
		local entID = GetEntityID(_unit)
		local ent = S5Hook.GetEntityMem(entID)
		local idleanim = GetEntityType(entID).[idle_anim_oder_so?]
		SetInt(ent[31][0][4],idleanim)
		return true
	end

end


Frage: Wie kriege ich die richtige Konstante für die Idle Animation der entsprechenden Einheit?

#EDIT:
Ich habe eben bemerkt, dass der Sägewerker auch, wenn ich diese Arrived Funktion benutze, um ihn in einem Haus verschwinden zu lassen, bevor er sich auflöst, kurz zum Leibeigenen wird:

function ArrivedJobDeath (_unit, _target)

    if IsNear(_unit,_target,50) then
        -- Unit entfernen
		DestroyEntity(_unit)
		return true
    end

end


Außerdem hat er sich ein mal nicht in einen Leibeigenen verwandelt und stand ganz normal als Sägewerker herum, wie er es sollte.

LG,
Messoras

____________________
Six feet of earth make us all equal.

Spielt Siedler 5 online mit mir, dank des neuen Siedler 5 MP Projekts von Kimichura.

Dieser Beitrag wurde von Messoras am 25.09.2017 um 11:31 editiert.

mcb
#4
25.09.2017 11:52
Beiträge: 1472

Eine Liste der Animationen findest du hier (zusammen mit der ältesten Version der Animationsfunktionen) : http://www.siedler-maps.de/forum/Siedler-DEdK-Script-Forum/SCV2-19696.htm
Eine größere Funktion für Animationen ist hier bei: http://www.siedler-maps.de/for...Script-Forum/mcbEMan-21315.htm

Aber was du suchst ist wohl einfach:

S5Hook.GetEntityMem(GetID(id))[31][0][4]:SetInt(386)



Zum falschen Model: Das passiert wie gesagt nicht immer. Ich benutze immer einen HiRes-Job für solche Sachen, da hatte ich nie Probleme mit.

Messoras
#5
25.09.2017 12:48
Beiträge: 84

Für das aktuelle scheint das gut zu passen, aber ich würde meine Comfort Funktion gerne erweitern, so dass die Units automatisch gefixt werden, und das vlt ohne für 100 verschiedene Einheiten ints zu switchen.
Ich werde mich mal durch die erweiterte Animationsfunktion forsten und schauen, ob ich da was passendes finde.

LG,
Messoras

____________________
Six feet of earth make us all equal.

Spielt Siedler 5 online mit mir, dank des neuen Siedler 5 MP Projekts von Kimichura.

Messoras
#6
25.09.2017 13:12
Beiträge: 84

Ich denke ich kann diese Tabelle evtl nutzen, um den Fix allgemein zu machen.
Ich würde also meinen ArrivedJob wiefolgt ändern:

function ArrivedJob (_unit, _target)

	if IsNear(_unit,_target,50) then
		-- Blocking aktivieren und NPC abwarten lassen
		Logic.SetTaskList(GetID(_unit), TaskLists.TL_NPC_IDLE)
		--Leibeigenen Bug fixen
		local entID = GetEntityID(_unit)
		local ent = S5Hook.GetEntityMem(entID)
		local idleanim = animTable.GetEntityType(entID).idle1
		SetInt(ent[31][0][4],idleanim)
		return true
	end

end



Wobei dann natürlich das Problem wäre dem aus GetEntityType ermittelten int die richtige Konstante zuzuweisen, um die entsprechende Nummer aus der Tabelle zu finden.
Oder ich muss wirklich einen Switch für jede Nummer machen und sagen

local t = GetEntityType(entID)
if      t==PU_Miner          then idleanim = animTable.PU_Miner.idle1
elseif  t==PU_Sawmillworker  then idleanim = animTable.PU_Sawmiller.idle1
...


Und ich hab ganz vergessen, dass es in lua nichtmal ne Switch Funktion gibt q.q

LG,
Messoras

____________________
Six feet of earth make us all equal.

Spielt Siedler 5 online mit mir, dank des neuen Siedler 5 MP Projekts von Kimichura.

Peter-FS
#7
25.09.2017 13:57
Beiträge: 1086

Ich habe das so gelöst, dient nur als Anregung, keine fertige Funktion

	if Logic.GetCurrentTaskList(id) ~= "TL_LEAVE_KEEP" then
	    if Logic.IsLeader(id) == 1 then
			Logic.SetTaskList(id, TaskLists.TL_MILITARY_IDLE)
		elseif Logic.GetEntityTypeName(Logic.GetEntityType(id))=="PU_Thief" then
			Logic.SetTaskList(id, TaskLists.TL_THIEF_IDLE)
		elseif Logic.GetEntityTypeName(Logic.GetEntityType(id))=="CU_EngineerIdle" then
			Logic.SetTaskList(id, TaskLists.TL_ENGINEER_IDLE)    
		elseif Logic.IsSettler(id) == 1 then
			Logic.SetTaskList(id, TaskLists.TL_NPC_IDLE)

		else
			Logic.SetTaskList(id, TaskLists.TL_TRAIN2_TAVERN1)
		end



____________________
Man muss nicht alles wissen, man muss nur wissen wo es steht!

mcb
#8
25.09.2017 17:39
Beiträge: 1472

Die Tabelle ist so aufgebaut, das du sie aus dem Lua-Script heraus nutzen kannst. Am einfachsten währe wohl:

local anim = animTable[Logic.GetEntityTypeName(Logic.GetEntityType(GetID(id)))].idle1
assert(anim)


(Du müstest noch die Zeile mit dem SetInt fixen, die funktioniert so nicht )

PS: Das was in Lua einem switch am nächsten kommt ist wohl das hier:

local foo = 5
local t = {[1] = function()
      foo = 3
   end, [5] = function()
      foo = foo + 2
   end,
}
t[someinput]()



Edit: Hatte ein Logic.GetEntityTypeName vergessen

Dieser Beitrag wurde von mcb am 25.09.2017 um 17:56 editiert.

Messoras
#9
27.09.2017 08:30
Beiträge: 84

Sooo, danke für eure Beiträge. Ich werde das ganze jetzt mal so testen:

function AnimationJob (id,anim)
	if IsAlive(GetID(id)) and Logic.GetCurrentTaskList(GetID(id))==TaskLists.TL_NPC_IDLE then
		S5Hook.GetEntityMem(GetID(id))[31][0][4]:SetInt(anim)
	else
		return true
	end

end
function ArrivedJobDeath (_unit, _target)

    if IsNear(_unit,_target,50) then
        -- Unit entfernen
		DestroyEntity(_unit)
		return true
    end

end



#EDIT: Scheint zu funktionieren, allerdings wird der AnimationJob immer sehr schnell beendet. Meist schon einen Tick nachdem der NPC stehen bleibt.

LG,
Messoras

____________________
Six feet of earth make us all equal.

Spielt Siedler 5 online mit mir, dank des neuen Siedler 5 MP Projekts von Kimichura.

Dieser Beitrag wurde von Messoras am 27.09.2017 um 10:31 editiert.

mcb
#10
27.09.2017 19:28
Beiträge: 1472

Du musst die Animation auch nur ein mal setzen. Die Comfortfunktion bei mir im Script benutze ich zum animieren von Heldenfähigkeiten, dabei muss ich natürlich neue Befehle jeden Tick wieder überschreiben

Seiten: 1

SiteEngine v1.5.0 by nevermind, ©2005-2007
Design by SpiderFive (www.siedler-games.de) - English translation by juja

Impressum