scripting:tutorials:level2:bandit_camps
Unterschiede
Hier werden die Unterschiede zwischen zwei Versionen der Seite angezeigt.
Nächste Überarbeitung | Vorherige Überarbeitung | ||
scripting:tutorials:level2:bandit_camps [2023/11/10 13:19] – angelegt fritz_98 | scripting:tutorials:level2:bandit_camps [2024/05/20 13:03] (aktuell) – fritz_98 | ||
---|---|---|---|
Zeile 1: | Zeile 1: | ||
- | TODO | + | ======Banditenlager und Spawner====== |
- | Folgende | + | Im Artikel |
- | [[ s5lua_g: | + | Sobald man plant, kleinere Quests zu implementieren, |
- | [[ s5lua_g:g_funktionen:tickoffensiveaicontroller | + | Wie man diesen Anwendungsfall umsetzt, wird in diesem Artikel beschrieben. Dazu definieren wird uns zuerst grobe Eigenschaften des Truppenverbands (im Folgenden **Armee** genannt. In Ebene 3 (FIXME link einfügen) tauchen wir noch tiefer in die Armeesteuerung ab. Hier überlassen wir wieder einiges den Comfortfunktionen). \\ |
+ | Danach definieren wir, in welchem Maße die Armee respawnen soll und unter welchen Bedingungen der Spawn aufhört (beispielsweise durch Zerstörung des Banditenturms). \\ | ||
+ | Zum Schluss legen wir fest, wie sich die Armee verhalten soll: In welchem Radius patroulliert sie um den Spawnpunkt herum? Darf sie angreifen oder bleibt sie defensiv? | ||
+ | |||
+ | In diesem Artikel werden viele Parameter, notwendig und optional, genannt werden. Um die Auswirkungen dieser Parameter gut einschätzen zu können, bieten sich Experimente an. Die Beispiele auf dieser Seite können dafür eine gute Grundlage bilden. | ||
+ | |||
+ | **Achtung**: | ||
+ | Gleichzeitig gibt es Konflikte mit der Funktion [[ scripting: | ||
+ | |||
+ | ^ _Strength ^ Reservierte Armee-Ids ^ | ||
+ | | 0 | keine | | ||
+ | | 1 | 1 bis 2 | | ||
+ | | 2 | 1 bis 4 | | ||
+ | | 3 | 1 bis 6 | | ||
+ | |||
+ | ---- | ||
+ | |||
+ | =====Die Armee-Basisparameter===== | ||
+ | |||
+ | Die Armee-Basisparameter definieren den groben Rahmen, in dem sich die respawnende Armee bewegen soll. Dazu zählt, welchem Spieler sie gehört und wo und in welchem Radius sie sich bewegt. All diese Informationen werden in ein Table geschrieben und der Funktion '' | ||
+ | |||
+ | ^ Key ^ Value-Typ ^ Bedeutung ^ | ||
+ | | **player** | Player Id | Spieler-Id des Spielers, dem die Armee gehören soll | | ||
+ | | **id** | Ganze Zahl (0 - 9) | Id der Armee. Es darf pro Spieler-Id und Armee-Id maximal **eine** Armee geben. Somit ist die Anzahl der Armeen pro Spieler auf 10 beschränkt | | ||
+ | | **position** | Position (Table der Form '' | ||
+ | | **rodeLength** | Number | Radius um '' | ||
+ | | **beAgressive** | Boolean | Legt fest, ob die Armee auf dem Weg zu einem Angriffsziel Gegner angreifen soll (für ausschließlich defensive Armee irrelevant). **true** ist hier eigentlich immer sinnvoll | | ||
+ | |||
+ | Um ein Beispiel zu geben, platzieren wir ein '' | ||
+ | <code lua> | ||
+ | function FirstMapAction() | ||
+ | -- Die Armee soll in unserem Beispiel direkt zu Spielstart erscheinen | ||
+ | -- Natürlich kann sie auch erst zu einem späteren Zeitpunkt erschaffen werden | ||
+ | -- Wichtig ist nur, dass vor der Armeeerstellung der zugehörige KI-Spieler aktiviert wird! | ||
+ | |||
+ | -- Das Banditenlager hat keine Leibeigenen zur Verfügung, muss also nichts Besonderes können | ||
+ | -- Die KI muss nur aktiviert sein | ||
+ | SetupPlayerAi(2, | ||
+ | |||
+ | CreateArmyBandits() | ||
+ | end | ||
+ | |||
+ | function CreateArmyBandits() | ||
+ | -- Wir definieren das Armee-Table | ||
+ | -- Um die Armee später steuern zu können, muss dieses Table global sein! | ||
+ | ArmyBandits = { | ||
+ | player = 2, | ||
+ | -- wir wählen die Id 0 | ||
+ | -- bei mehreren Armeen für Spieler 2 müssen alle unterschiedliche Ids haben | ||
+ | id = 0, | ||
+ | position = GetPosition(" | ||
+ | rodeLength = 4000, | ||
+ | beAgressive = true | ||
+ | } | ||
+ | |||
+ | SetupArmy(ArmyBandits) | ||
+ | end | ||
+ | </ | ||
+ | |||
+ | **Tipp**: Du kannst deinen gewünschten Radius durch [[ scripting: | ||
+ | |||
+ | An dieser Stelle weiß das Spiel nur, dass eine Armee existieren soll. Sie enthält aber noch keine Truppen. | ||
+ | |||
+ | ---- | ||
+ | |||
+ | =====Das Respawnverhalten===== | ||
+ | |||
+ | Um die Armee selbstständig respawnen zu lassen, erweitern wir das Armee-Table um einige Parameter, um das Respawn-Verhalten zu definieren. Das erweiterte Armee-Table geben wir dann in die Funktion '' | ||
+ | |||
+ | ^ Key ^ Value-Typ ^ Bedeutung ^ | ||
+ | | **strength** | Integer ≤ 8 | Maximale Anzahl der Hauptmänner, | ||
+ | | **spawnTypes** | Table (Liste) | Liste von Tables, die jeweils den Leader-Typ und die Anzahl der Soldaten für diesen Leader festlegen. Die '' | ||
+ | | **endless** | Boolean | Die '' | ||
+ | | **spawnPos** | Position (Table der Form '' | ||
+ | | **spawnGenerator** | String oder Number | Skriptname oder Entity-Id der Entity, die den Respawn erlaubt. Ist die angegebene Entity zerstört, bricht der Respawn ab | | ||
+ | | **maxSpawnAmount** | Integer | Pro Spawn werden maximal '' | ||
+ | | **respawnTime** | Integer, durch 10 teilbar | Falls die Armee weniger als '' | ||
+ | | **noEnemy** | Boolean | Wenn '' | ||
+ | | **noEnemyDistance** | Number | Wenn '' | ||
+ | |||
+ | Um unser Beispiel zu erweitern, wollen wir der Armee alle 90 Sekunden zwei neue Truppen hinzufügen lassen, bis die Maximalstärke 8 erreicht ist. Die Armee soll zur Hälfte aus Axtkämpfern, | ||
+ | |||
+ | <code lua> | ||
+ | function CreateArmyBandits() | ||
+ | ArmyBandits = { | ||
+ | player = 2, | ||
+ | id = 0, | ||
+ | position = GetPosition(" | ||
+ | rodeLength = 4000, | ||
+ | beAgressive = true, | ||
+ | |||
+ | strength = 8, | ||
+ | -- Die Armee hat zwar die Maximalstärke 8, wir müssen allerdings nicht jede Truppe einzeln definieren | ||
+ | -- Da wir weiter unten " | ||
+ | -- Truppentypen anzugeben | ||
+ | -- Die Liste enthält Tables, die wiederum den Typ des Hauptmanns und die Anzahl seiner Soldaten angeben | ||
+ | -- Wird " | ||
+ | -- lang sein | ||
+ | spawnTypes = { | ||
+ | {Entities.CU_BanditLeaderSword1, | ||
+ | {Entities.CU_BanditLeaderBow1, | ||
+ | {Entities.CU_BanditLeaderSword1, | ||
+ | {Entities.PU_LeaderPoleArm1, | ||
+ | }, | ||
+ | endless = true, | ||
+ | |||
+ | -- Die Truppen sollen an der Position spawnen, die sie hinterher auch verteidigen | ||
+ | spawnPos = GetPosition(" | ||
+ | |||
+ | -- Fällt der Banditenturm, | ||
+ | spawnGenerator = " | ||
+ | |||
+ | -- Maximal 2 Truppen sollen auf ein mal gespawnt werden... | ||
+ | maxSpawnAmount = 2, | ||
+ | |||
+ | -- ...und das alle 90 Sekunden... | ||
+ | respawnTime = 90, | ||
+ | |||
+ | --...und das nur, wenn keine Gegner in der Nähe sind... | ||
+ | noEnemy = true, | ||
+ | |||
+ | --...die sich dem Spawnpunkt auf unter 2000 Scm nähern | ||
+ | noEnemyDistance = 2000 | ||
+ | } | ||
+ | |||
+ | -- SetupArmy ist weiterhin notwendig | ||
+ | SetupArmy(ArmyBandits) | ||
+ | |||
+ | SetupAITroopSpawnGenerator(" | ||
+ | end | ||
+ | </ | ||
+ | |||
+ | Zu Beginn wird die Armee einmal komplett gespawnt, also unabhängig von '' | ||
+ | |||
+ | ---- | ||
+ | |||
+ | =====Das Kampfverhalten===== | ||
+ | |||
+ | Damit die Armee eben dieses Kampfverhalten ausführen kann, erweitern wird erneut das Armee-Table mit weiteren Parametern, die unser gewünschtes Kampfverhalten beschreiben. Nach dem Armee- und Spawner-Setup starten wir einen [[ scripting: | ||
+ | |||
+ | Für das Armeeverhalten verwenden wir die Funktion '' | ||
+ | Das Armee-Table wird um folgende Key-Value-Paare erweitert: | ||
+ | ^Key^Value-Typ^Bedeutung^ | ||
+ | |**outerDefenseRange**|Zahl|Der Radius des äußeren Verteidigungsrings. Wenn die Armee maximale Stärke hat, verteidigt sie die angegebene Position '' | ||
+ | |**baseDefenseRange**|Zahl|Der Radius des inneren Verteidigungsrings. Die Armee verteidigt sich in diesem Umkreis an der Position '' | ||
+ | |**retreatStrength**|Integer < '' | ||
+ | |**AttackPos**|Table|Liste an Postionen, aus denen zufällig eine als Angriffsziel für die Armee gewählt wird| | ||
+ | |**AttackAllowed**|Boolean|Gibt an, ob die Armee angreifen darf. Falls **true**, wird sie bei voller Stärke eine der Positionen in '' | ||
+ | |**pulse**|Boolean|Wenn **true**, darf die KI kurzzeitig ihren Verteidiungsring verlassen, falls sie volle Stärke hat. Dadurch kann sie schwieriger von außerhalb des Rings beschossen werden| | ||
+ | |||
+ | Für unser Beispiel machen wir folgende Angaben (unter der Voraussetzung, | ||
+ | |||
+ | <code lua> | ||
+ | function CreateArmyBandits() | ||
+ | ArmyBandits = { | ||
+ | player = 2, | ||
+ | id = 0, | ||
+ | position = GetPosition(" | ||
+ | rodeLength = 4000, | ||
+ | beAgressive = true, | ||
+ | |||
+ | strength = 8, | ||
+ | spawnTypes = { | ||
+ | {Entities.CU_BanditLeaderSword1, | ||
+ | {Entities.CU_BanditLeaderBow1, | ||
+ | {Entities.CU_BanditLeaderSword1, | ||
+ | {Entities.PU_LeaderPoleArm1, | ||
+ | }, | ||
+ | endless = true, | ||
+ | spawnPos = GetPosition(" | ||
+ | spawnGenerator = " | ||
+ | maxSpawnAmount = 2, | ||
+ | respawnTime = 90, | ||
+ | noEnemy = true, | ||
+ | noEnemyDistance = 2000, | ||
+ | |||
+ | -- die baseDefenseRange entspricht der Konsistenz zuliebe genau der rodeLength, | ||
+ | -- die wir weiter oben angegeben haben | ||
+ | baseDefenseRange = 4000, | ||
+ | |||
+ | -- wenn die Armee volle Stärke hat, soll sie einen Umkreis von 6000 scm verteidigen... | ||
+ | outerDefenseRange = 6000, | ||
+ | |||
+ | -- ...und sich wieder zurückziehen, | ||
+ | retreatStrength = 3, | ||
+ | |||
+ | -- Angriffe sind erlaubt | ||
+ | AttackAllowed = true, | ||
+ | |||
+ | -- Die Armee soll entweder das Hauptquartier vom Spieler oder die Position eines (neutralen) | ||
+ | -- Dorfzentrums angreifen | ||
+ | AttackPos = { | ||
+ | GetPosition(" | ||
+ | GetPosition(" | ||
+ | }, | ||
+ | |||
+ | -- Die Truppen sollen außerdem für kurze Zeit außerhalb ihres Radius kämpfen dürfen | ||
+ | pulse = true | ||
+ | } | ||
+ | |||
+ | SetupArmy(ArmyBandits) | ||
+ | SetupAITroopSpawnGenerator(" | ||
+ | -- Den Armee-Kontrolljob findest du im Codebeispiel weiter unten | ||
+ | StartSimpleJob(" | ||
+ | end | ||
+ | </ | ||
+ | |||
+ | Der Kontrolljob '' | ||
+ | |||
+ | <code lua> | ||
+ | function ControlArmyBandits() | ||
+ | -- Die Kontrollfunktion soll nur alle 10 Sekunden aufgerufen werden | ||
+ | -- Dazu verwenden wir den Counter, der im letzten Kapitel vorgestellt wurde | ||
+ | -- Es ist zwar möglich, die Kontrollfunktion jede Sekunde aufzurufen - das | ||
+ | -- ist allerdings verschwendete Performance und lässt die Armee erratisch wirken, | ||
+ | -- da sie u.U. jede Sekunde neue Befehle erhält | ||
+ | if Counter.Tick2(" | ||
+ | |||
+ | -- Die Funktion IsAITroopGeneratorDead prüft, ob sowohl alle Truppen der Armee | ||
+ | -- als auch ihr Spawngebäude zerstört wurde | ||
+ | if IsAITroopGeneratorDead(ArmyBandits) then | ||
+ | -- Falls ja, beende den Kontrolljob | ||
+ | return true | ||
+ | else | ||
+ | -- Andernfalls führe das im Armee-Table definierte Verhalten aus | ||
+ | TickOffensiveAIController(ArmyBandits) | ||
+ | end | ||
+ | |||
+ | end | ||
+ | |||
+ | end | ||
+ | </ | ||
+ | |||
+ | ---- | ||
+ | |||
+ | Die " | ||
+ | |||
+ | [[ scripting: | ||
+ | [[ scripting: | ||
+ | [[ scripting: |
scripting/tutorials/level2/bandit_camps.1699622386.txt.gz · Zuletzt geändert: 2023/11/10 13:19 von fritz_98