Inhaltsverzeichnis

GetAllHeroes

Diese Funktion benennt automatisch alle (zum Zeitpunkt des Aufrufs) auf der (Singleplayer) Map vorhandenen Helden von Player 1, und erzeugt zu jedem Helden eine globale Tabelle (Table), die jeweils folgende Werte beinhaltet:

Verwendung

Damit von beginn an alle Helden benannt werden und die anderen Informationen zur Verfügung stehen, sollte der Funktionsaufruf

GetAllHeroes()

unbedingt in der FMA (FirstMapAction) erfolgen!

Ein erneuter Aufruf der Funktion ist immer dann, und nur dann erforderlich, wenn per

CreateEntity (_playerId,_entity,_position,_name) 

ein neuer Held/ eine neue Heldin „erschaffen“ wurde, bzw. wenn ein Held/ eine Heldin per

DestroyEntity (_entity) 

aus dem Spiel „entfernt“ wurde.

Beispiele

  1. Entity Scriptname ⇒ _name
    Jeder vorhandene Held/ jede vorhandene Heldin wird gemäß den in der 'herotable' angegebenen Namen benannt und man kann somit fortan per Scriptname auf sie zugreifen:
    if IsNear ("Dario", "Pilgrim", 300) then
       ...
    end
  2. Entity Id ⇒ _name.id
    Die jeweilige Id eines Helden/ einer Heldin wird im zugehörigen Table gespeichert und man kann wiefolgt darauf zugreifen:
    MakeInvulnerable (Dario.id) 
  3. Entity Typ-Id ⇒ _name.typeId
    Die jeweilige Typ-Id eines Helden/ einer Heldin wird im zugehörigen Table gespeichert und man kann wiefolgt darauf zugreifen:
    AreEntitiesInArea (1, Ari.typeId, _position, _range, 1) 
  4. Entity Typename ⇒ _name.typeName
    Der jeweilige Entity Typename eines Helden/ einer Heldin wird im zugehörigen Table gespeichert und man kann wiefolgt darauf zugreifen:
    Message (Erec.typeName) 
  5. Entity X-Pos, Y-Pos ⇒ _name.pos.X, _name.pos.Y
    Die jeweilige (aktuelle) X- & Y-Koordinate eines Helden/ einer Heldin wird im zugehörigen Table gespeichert und man kann wiefolgt darauf zugreifen:
    Move ("Varg", {X = Helias.pos.X, Y = Helias.pos.Y}) 

Hierbei handelt es sich natürlich um willkürlich gewählte Beispiele, die lediglich den Zugriff auf die entsprechenden Daten veranschaulichen sollen und nicht unbedingt eine sinnvolle Art der Anwendung darstellen.

Einschränkungen/ Fehlerüberprüfung

Da es von der Spiellogik her nicht vorgesehen (obwohl möglich) ist, dass mehrere Helden desselben Typs zur gleichen Zeit (für Player 1) existieren, wird dies in der Funktion geprüft und sie nur dann ausgeführt, wenn kein Held mehrfach vorkommt.

Wer eine Map hat, wo dies (absichtlich) dennoch der Fall ist, der kann die Funktion nicht verwenden!

Sinn & Zweck

Funktionen sind ja predistiniert dafür, um uns immer wiederkehrende Aufgaben abzunehmen/ zu erleichtern. Und da eigentlich jede Map mind. einen Helden beinhaltet …!

Die Funktion dient rein der Bequemlichkeit und verhindert das versehentliche mehrfache Setzen/ Erstellen von Helden - sonst nichts!

Natürlich lassen sich alle Aufgaben auch mit Hilfe der entsprechenden Comfort- & Logic-Funktionen

umsetzen.

Code

Hier nun der benötigte Scriptcode:

function GetAllHeroes()
    local heroIds={}
--# Table mit den Entitytypnamen und den zu verwendenden Scriptnamen 
	local herotable = {
        {"PU_Hero1", "Dario"},
        {"PU_Hero1a", "Dario"},
        {"PU_Hero1b", "Dario"},
        {"PU_Hero1c", "Dario"},
        {"PU_Hero2", "Pilgrim"},
        {"PU_Hero3", "Salim"},
        {"PU_Hero4", "Erec"},
        {"PU_Hero5", "Ari"},
        {"PU_Hero6", "Helias"},
        {"CU_BlackKnight", "Kerberos"},
        {"CU_Mary_de_Mortfichet", "MarydeMortfichet"},
        {"CU_Barbarian_Hero", "Varg"},
        {"CU_Evil_Queen", "Kala"},
        {"PU_Hero10", "Drake"},
        {"PU_Hero11", "Yuki"}
    }
--# Metatable
	local metaPosHeroes = {
        __index = function(_table, key)
            if key=="pos" then 
                return GetPosition(_table.id)
            end
        end
    }
--# eigentliche Funktion zum Erstellen der globalen Indizes für jeden Hero
    local SetupHeroTable = function(_id,_name)
		Logic.SetEntityName(_id,_name)
		_G[_name] = {
			id         = _id,
			typeId     = Logic.GetEntityType(_id),
			typeName   = Logic.GetEntityTypeName(Logic.GetEntityType(_id)),
			_metatable = true,
		}
		setmetatable(_G[_name], metaPosHeroes)
    end
	Logic.GetHeroes(1,heroIds)
--# Abschnitt zur Fehlerprüfung: Heroes mehrfach vorhanden?
	local tmp_EntityTypeIds={}
	for k,v in pairs(heroIds) do
		table.insert(tmp_EntityTypeIds,Logic.GetEntityType(v))
	end
	table.sort(tmp_EntityTypeIds)
	local error_count=0
	local dario_count=0
	for k,v in pairs(tmp_EntityTypeIds) do
		local a,b=next(tmp_EntityTypeIds,k)
		if v==b then
			Message("Error: Held vom Typ "..Logic.GetEntityTypeName(v).." ist mehrfach vorhanden!")
			error_count=error_count+1
		end
		for i=1,4 do
			if v==Entities[herotable[i][1]] then
				dario_count=dario_count+1
			end
		end
	end
	if dario_count>1 then
		Message("Error: Held Dario ist "..dario_count.." mal vorhanden!")
		error_count=error_count+1
	end
--# wenn keine Fehler aufgetreten sind, dann Indexe anlegen
	if error_count==0 then
		for i=1,table.getn(heroIds) do
			local typ=Logic.GetEntityType(heroIds[i])
			local hFound = false;
			for j=1,table.getn(herotable) do
				if typ==Entities[herotable[j][1]] then
					hFound=true;
					SetupHeroTable(heroIds[i],herotable[j][2])
				end
			end
			if not hFound then
				local tmp_name=Logic.GetEntityTypeName(typ)
				Message("Error: Es existiert ein unbekannter Held vom Entity-Typ: "..tmp_name)
			end
		end
--# früher vorhandene und nicht mehr existierende Indexe löschen
		for i=1,table.getn(herotable) do
			if (not IsExisting(herotable[i][2])) then
				_G[herotable[i][2]]=nil
			end
		end
	end
end
 
--# Funktionen zum wiederherstellen der Metatables/-verknüpfungen nach dem Laden eines Savegames 
Mission_OnSaveGameLoadedOrig = Mission_OnSaveGameLoaded;
function Mission_OnSaveGameLoaded()
    Mission_OnSaveGameLoadedOrig();
    ResetMetatables(_G, {});
end
 
function ResetMetatables(_table, _visited)
    if not _visited[_table] then
        _visited[_table] = true;
        for k, v in pairs(_table) do
            if type(v) == "table" then
                ResetMetatables(v, _visited);
                if v._metatable == true then
                    setmetatable( v, { __index = function(_table, _key) if _key == "pos" then return GetPosition(_table.id); end end } );
                end
            end
        end
    end
end

Anmerkung: Die zu vergebenden Scriptnamen im 'herotable' können natürlich nach eigenem Wunsch angepasst werden.

Forumsbeitrag

Wer Fragen, Anregungen und/ oder Probleme zu/ mit der Funktion hat, der kann diese auch gerne im entsprechenden Forumsbeitrag im siedler-portal posten.