Das ist die alte Armeen Seite. Dient zur Zeit als Backup, wird aber noch zu einem Fortgeschrittenen Tutorial bzgl. Armeen umgestaltet
Um eine Armee zu erstellen, reicht es nicht aus, im Siedler5-Editor einfach die Truppen auf die Karte zu setzen. Man würde die Soldaten zwar im Spiel sehen, aber das wären nur nutzlose Teile, weil man sie weder befehligen noch sonst etwas mit ihnen tun kann.
Eine Armee, egal, ob für den menschlichen oder Computerspieler, muss immer im Script erzeugt werden. Da jede Armee auch, genau wie jeder Spieler, eine eindeutige ID haben muss, ist die Anzahl der nutzbaren Armeen (pro Spieler-ID) begrenzt auf 10, da als ID nur die Ziffern von 0 bis 9 zulässig sind. D.h. jeder Spieler kann 10 Armeen haben.
Wenn Ihr also dem menschlichen Spieler eine Armee basteln wollt, müsstet Ihr die playerID 1 vergeben. Aber dazu am Ende noch eine andere Möglichkeit.
Hier wird eine einfache Armee erstellt, welche aus mehreren Trupps des gleichen Soldatentyps besteht.
function CreateArmyOne() -- Erzeugt eine so genannte Tabelle, die alle für das Spiel benötigten Daten über die Armee aufnimmt. -- Diese wird lokal erzeugt, da sie (zumindest in diesem Beispiel) nicht in anderen Funktionen benötigt wird. local armyOne = { -- Füllen der Tabelle mit den relevanten Informationen player = 2, -- ID des Spielers, für den die Armee bestimmt ist id = 1, -- Eine zulässige und pro Spieler einmalige(!) ID für die Armee, von 0 bis 9 strength = 8, -- Anzahl der Hauptmänner, die zur Armee gehören position = GetPosition("armyOne"), -- Die Position, an der die Armee erzeugt werden soll (eine XD_ScriptEntity, welche in diesem Fall den Namen "armyOne" trägt) rodeLength = 4000 -- Bestimmt den Aktionsradius, innerhalb dessen die Armee selbständig angreift }; -- ruft die Comfort-Function "SetupArmy" des Spieles auf, um die Armee mit den Daten aus der Tabelle zu erzeugen SetupArmy(armyOne); -- Die Armee existiert nun, aber hat noch keine Truppen. -- Also wird eine Tabelle erzeugt, in der festgelegt, wird, welche und wie viele Trupps zu der Armee gehören -- ein Trupp ist ein Hauptmann und die entsprechende Anzahl Soldaten local troopDescription = { maxNumberOfSoldiers = 4, -- Anzahl der Soldaten pro Hauptmann minNumberOfSoldiers = 0, -- Die Anzahl der Soldaten, bei der der Hauptmann zur nächsten Kaserne geht und Soldaten auffüllt experiencePoints = LOW_EXPERIENCE, -- Der Erfahrungsgrad, den die Armee bei der Erzeugung hat (LOW_EXPERIENCE, MEDIUM_EXPERIENCE, HIGH_EXPERIENCE, VERYHIGH_EXPERIENCE) leaderType = Entities.PU_LeaderSword1 -- Der Truppentyp. Dies sollte möglichst etwas mit "Leader" im Namen sein }; -- EnlargeArmy wird 8x aufgerufen, um der Armee 8 dieser Trupps hinzuzufügen. Dadurch hat die Armee, wie oben angegeben, 8 Hauptmänner for i = 1, 8 do EnlargeArmy(armyOne,troopDescription); end -- Optional kann man einen Job starten, der die Armee nun kontrolliert. Diesem sollte man die Armee als Parameter übergeben -- Stattdessen könnte auch einfach Defend(armyOne) (Verteidigung) stehen oder Advance(armyOne) (Angriff) --StartSimpleJob("ControlArmyOne") end
function CreateArmyOne() local armyOne = { player = 2, id = 1, strength = 8, position = GetPosition("armyOne"), rodeLength = 4000 }; SetupArmy(armyOne); local troopDescription = { maxNumberOfSoldiers = 4, minNumberOfSoldiers = 0, experiencePoints = LOW_EXPERIENCE, leaderType = Entities.PU_LeaderSword1 }; for i = 1, 8 do EnlargeArmy(armyOne,troopDescription); end StartSimpleJob("ControlArmyOne") end
Wenn Ihr also die Zahl bei maxNumberOfSoldiers auf 8 ändert, werden pro Hauptmann 8 statt 4 Soldaten erzeugt. Die oben stehende Funktion würde also nun 8 Hauptmänner mit je 4 Soldaten vom Typ Schwertkämpfer Stufe 1 mit niedriger Erfahrungsstufe erzeugen.
Wenn jetzt in derselben Armee auch noch Bogenschützen und Lanzenträger vorhanden sein sollen, muss nur der Teil mit der Beschreibungstabelle angepasst werden. Im obigen Fall heißt die Tabelle troopDescription. Nun spricht nichts dagegen, der Armee mehrere Tabellen mit jeweils verschiedenen Truppen zu übergeben. Dann muss aber jede Tabelle einen anderen Namen haben.
function CreateArmyOne() local armyOne = { player = 2, id = 1, strength = 18, position = GetPosition("armyOne"), rodeLength = 4000 }; SetupArmy(armyOne); local troopDescription1 = { maxNumberOfSoldiers = 4, minNumberOfSoldiers = 0, experiencePoints = MEDIUM_EXPERIENCE, leaderType = Entities.PU_LeaderSword1 }; for i = 1, 8 do EnlargeArmy(armyOne,troopDescription1); end local troopDescription2 = { maxNumberOfSoldiers = 6, minNumberOfSoldiers = 0, experiencePoints = LOW_EXPERIENCE, leaderType = Entities.PU_LeaderBow1 }; for i = 1, 6 do EnlargeArmy(armyOne,troopDescription2); end local troopDescription3 = { maxNumberOfSoldiers = 8, minNumberOfSoldiers = 0, experiencePoints = LOW_EXPERIENCE, leaderType = Entities.PU_LeaderPoleArm3 }; for i = 1, 4 do EnlargeArmy(armyOne,troopDescription3); end StartSimpleJob("ControlArmyOne") end
Also haben wir jetzt folgende Tabellen:
Da nun 18 Hauptmänner erstellt wurden, muss die Strength der Armee auf 18 gesetzt werden.
Wenn dem Spieler Einheiten gegeben werden sollen, braucht man dazu keine Armee erstellen. Der Spieler kann auch mit normalen Truppen umgehen, die keiner Armee gehören. Wenn man ihm also einfach nur Trupps zuweist, wird dadurch wird keine der ArmeeIDs belegt.
In diesem Beispiel wird ein großer Trupp guter Bogenschützen, sowie drei kleine Trupps mittelmäßiger Schwertkämpfer erstellt.
function CreateSupportTroops() local armyOne = { player = 1 }; -- Armee für Spieler 1 local troopDescription1 = { maxNumberOfSoldiers = 8, minNumberOfSoldiers = 0, experiencePoints = HIGH_EXPERIENCE, leaderType = Entities.PU_LeaderBow3, position = GetPosition( "supporttroops" ) }; local nBowID = CreateTroop(armyOne,troopDescription1); local troopDescription2 = { maxNumberOfSoldiers = 4, minNumberOfSoldiers = 0, experiencePoints = LOW_EXPERIENCE, leaderType = Entities.PU_LeaderSword1, position = GetPosition( "supporttroops" ) }; for i = 1, 3 do CreateTroop(armyOne,troopDescription2); end end
Die ID der Bogenschützentruppe wurde in nBowID
gespeichert. Dies braucht man nicht zu tun, wenn man dieser Truppe keine anschliessenden Befehle geben will. Mit dieser ID könnte man den Trupp Beispielsweise vom Spawnpunkt aus zum Hauptquartier des Spielers laufen lassen. Da die Truppen aber schon dem Spieler gehören, kann dieser natürlich jederzeit andere Befehle erteilen.
Move( nBowID, "Player_HQ" )
Eine weiter Möglichkeit ist, das man eine Armee in einer Tabelle einließt und sie dann bewegt
function CreateGhostArmy() local troopDescription1 = { minNumberOfSoldiers = 0, maxNumberOfSoldiers = 4, experiencePoints = VERYHIGH_EXPERIENCE, leaderType = Entities.PU_LeaderHeavyCavalry2, position = GetPosition("Barbaren") } army1 = {} for i = 1, 10 do table.insert (army1, CreateTroop( {player=5}, troopDescription1)) end MoveGhostArmy() end
In diesem Fall wird eine Armee für den Player 5 verzeugt
Jetzt nur noch den Zielpunkt
function MoveGhostArmy() for i = 1, table.getn(army1) do Move(army1[i], "BarbarenKill", 300) end end
Hier wird eine Armee mit Parameterübergabe für den Gegner erstellt die sich zu einen Zielpunkt bewegt
CreateTroopsAndMove(_PlayerID, _Position, _LeaderType, _Troops, _Target)
function CreateTroopsAndMove(_PlayerID, _Position, _LeaderType, _Troops, _Target) _Position = GetPosition(_Position) for i = 1, _Troops do Move(GlobalMissionScripting.CreateGroup(_PlayerID, _LeaderType, 8, _Position.X , _Position.Y , 0), _Target) end end
Aufruf der Function
CreateTroopsAndMove(4, "armyOne", GetBow(2), 5, "posArmyOne")
Um einen anderen Armee-Typ auszuwählen, kann man auch
GetPoleArm()
GetSword()
GetBow()
GetHeavyCavalry()
GetLightCavalry()
GetCannon()
angeben. Hier ist die Einstellung von 0-3 Möglich
Eine weiter Möglichkeit Armeen mit Parameterübergabe für den Gegner zu erstellen die sich zu einen Zielpunkt bewegt ist
CreateArmyTroops( _player, _position, _leaderType , _troops, _move)
function CreateArmyTroops( _player, _position, _leaderType , _troops, _move) local army = { player = _player, } local troopDescription = { maxNumberOfSoldiers = 8, minNumberOfSoldiers = 0, experiencePoints = HIGH_EXPERIENCE, leaderType = _leaderType, position = _position, } for i = 1,_troops do army[i] = CreateTroop( army , troopDescription ) end for i = 1,_troops do Move( army[i], _move) end end
Aufruf der Function
CreateArmyTroops( 4, GetPosition("wacheOne"), Entities.CU_Evil_LeaderBearman1, 2, "posWache")
Der Vorteil ist, das man nicht für jede erstellte Armee den Code neu schreiben muss, und so eine Megne Script-Code spart.
Mit diesem Code kommt man ganz ohne Army ID aus
Man kann diese Functionen auch in einem Counter Aufruf verpacken.
Hier werden all 60 sek. zwei Armeen erstellt, solange der turmTwo noch existiert
Aufruf mit: StartSimpleJob(„ArmyOneTurmTwo“)
function ArmyOneTurmTwo() if IsExisting ("turmTwo") and Counter.Tick2( "angriff", 60) then Message("Ein Horde Banditen wird euer Dorfzentrum gleich angreifen.") CreateArmyTroops( 4, GetPosition("startArmyOne"), Entities.CU_Evil_LeaderBearman1, 2, "Dorfzentrum") CreateTroopsAndMove(4, "startArmyOne", GetCannon(2), 3, "Dorfzentrum") StartSimpleJob("CheckArmyOneTurmTwo") return true end end
function CheckArmyOneTurmTwo() if not IsDead("turmTwo") then StartSimpleJob("ArmyOneTurmTwo") return true end end
Mit der Handhabung von Armeen gibt es leider ein paar Probleme. Diese werden hier aufgelistet.
Manchmal möchte man wissen, wann eine Armee vernichtet wurde, um daraufhin eine Aktion auszulösen. Dazu wird ein Job gestartet, welcher IsDead( army ) abfragt. Allerdings ist diese Bedingung direkt nach der Erstellung der Armee erfüllt, da von der Erzeugung per Script, bis zum Erscheinen im Spiel, ein wenig Zeit vergeht.
Hierzu gibt es einen modifizierten Abfragecode, der das Problem behebt. Damit er korrekt funktioniert, muss er direkt nachdem die Armee erstellt wurde als Job gestartet werden.
Hier wird armyOne
als Army Table verwendet. Die Message wird nur zu Testzwecken ausgegeben. Sie kann durch die auszuführende Aktion ersetzt werden.
function ControlArmyOne() if not armyOne.created then armyOne.created = not IsDead(armyOne); return false; end if IsDead(armyOne) then Message( "armyOne is dead!" ); return true; end end
Dieser Code bewirkt, daß armyOne nicht als Dead gilt, solange sie noch nicht erzeugt wurde.
Armeen funktionieren nicht richtig, wenn kein KI Spieler für die entsprechende SpielerID erstellt wurde.
Wenn dieser KI-Spieler aber kein Gebäude besitzt, stürzt das Spiel ab. Dieses Gebäude muss kein Spielergebäude sein, sondern kann auch ein Zelt, ein Turm, ein Leuchtturm usw. sein
„Funktioniert nicht richtig“ bedeutet in dem Fall, das sämtliche Armeen ohne KI sofort als tot erklärt werden und deshalb jegliche Armee-Kontrolle unmöglich ist. Die Truppen stehen zwar immer noch dort rum, tun aber nichts. In Verbindung mit einem SpawnGenerator entstehen dann unendlich viele Soldaten, wodurch das Spiel früher oder später hängen bleibt oder abstürzt.
Die KI wird übrigens auch mit der Funktion MapEditor_SetupAi() aktiviert.
Wichtig: Je nach „strength“-Wert, der beim Erstellen eines Computergegners (= KI) angegeben wurde, werden für diese KI unterschiedlich viele Slots für Armeen erstellt. Armeen mit einer der entsprechenden IDs werden von der KI kontrolliert; egal ob sie per Script erstellt wurden oder die KI sie selbst ausgebildet hat.
Zur Vermeidung von Problemen sollten diese IDs für die Erstellung von Armeen per Script nicht verwendet werden.
Stärke | Reservierte IDs |
---|---|
1 | 1 bis 2 |
2 | 1 bis 4 |
3 | 1 bis 6 |
Die KI erteilt Armeen mit einer anderen ID keine Befehle; diese können per Skriptbefehlen kontrolliert werden.
Mehr dazu hier: http://www.siedler-portal.de/vb3/showthread.php?t=3896