Skriptsammlung

Aus TTT Wiki
Wechseln zu: Navigation, Suche

Inhaltsverzeichnis

Empfehlenswerte Skripte

Es gibt viele interessante Skripte, die für die ein oder andere Mission, dass letzte Quäntchen Immersion rausholen. Hier sollen aber nur allgemeingültige Skripte vorgestellt werden, die in fast jeder Mission genutzt werden.

Weitere Skripte befinden sich im Forum in der Skript-Zentrale oder im Hilfe-Bereich.

W-Teleporter

Für den technischen Ausfall.

Wenn ein Spieler in ArmA ein technisches Problem hat und den Server nachjoint, dann - und nur dann - kann er dank dem W-Teleporter sich zu seinem Buddy teleportieren, um sofort wieder weiterzumachen.

Dieses Skript wird so gut wie in jeder Mission genutzt.

https://forums.bistudio.com/forums/topic/169420-the-w-teleporter/ (Autor: fett_li)

description.ext

#include "W_Teleporter\dialog.hpp"
class CfgFunctions {
#include "W_Teleporter\CfgFunctions.hpp"
};

initPlayerLocal.sqf

[teleporter1] call FETT_fnc_W_addTeleport;

Spec_tfar

Wir nutzen TFAR und ein BFT-System. Man kann zwar über Module die Einstellungen vornehmen sowie dank Eden auch den Rufnamen (Callsign) einer Gruppe bearbeiten, aber das Skript nimmt einem diese Arbeit ab.

So werden im Editor den Einheiten in der init-Zeile eine Variable zugewiesen und in einer Skript-Datei die Funk-Frequenzen und Rufnamen eingestellt.

https://github.com/specop0/arma_scripts/tree/master/spec_tfar (Autor: SpecOp0)

description.ext

#include "W_Teleporter\dialog.hpp"
class CfgFunctions {
#include "W_Teleporter\CfgFunctions.hpp"
#include "spec_tfar\CfgFunctions.hpp"
};

init-Zeile jeder Einheit

Wir numerieren die vorhanden Trupps / Gruppen einfach mit Zahlen durch - z.B. aufsteigend von 0.
this setVariable ["Spec_var_TFARgroup", 0];

fn_initGroups

Im switch-case dann pro Gruppe bzw. Zahl die gewünschten Frequenzen und Rufnamen festlegen.
case 0 : {
    _swFreq = ["100"];
    _lrFreq = ["30","31","41","42","43","51","61"];
    _callsign = "Gelb";
};

Zuschauerkamera

Unter Vanilla gibt es eine Zuschauerkamera die genutzt werden kann.

initPlayerLocal.sqf

Hierzu muss etwa am W-Teleporter eine AddAction hinzugefügt werden.

teleporter addAction ["Zuschauermodus", {
    params ["_target","_caller"];
    _caller setPosASL (getPosASL spectator_cam_helper); // optional
    [_caller, true] remoteExecCall ["hideObjectGlobal", 2];
    ["Initialize", [_caller, [], true]] call BIS_fnc_EGSpectator;
}];

Hierbei werden die Zuschauer versteckt. Optional kann man die Zuschauer noch zu einem anderen Ort teleportieren.

onPlayerRespawn.sqf

Zusätzlich muss man beim Respawn die Zuschauerkamera beenden. Sonst kommt man aus dieser nur heraus, wenn man den Server verlässt.

["Terminate"] call BIS_fnc_EGSpectator;

Verbotene Skripte

  • Virtual Ammobox System (VAS)
  • Reskins (Vergrößerung Missionsdatei)
  • TPWCAS
  • Igiload
  • Sitzskript (in ACEX vorhanden)
  • automatische Respawnskripte (Warum? Darum!)
  • Selbstgeschriebene Wahnsinnsskripte - die Definition hiervon unterliegt dem QM

Allgemeine Tipps

Vor dem Skripten

  • Skriptfehler anzeigen lassen: Haken im ArmA-Sync bzw. Startup Parameter -showScriptErrors
  • Keine riesige Anzahl von Triggern (mehr als 50)
  • Nicht viel Code oder Abfragen im Trigger (Auslagern auf Skripts). Im Trigger selbst existieren Variablen wie thisList in dem sich alle Objekte (in einem Array) befinden, die im Trigger sind und ihn auslösen können.
  • Sich mit Lokalitäten auseinandersetzen: Warum klappt das im Editor aber nicht auf dem (Test)Server? Warum soll den Trigger als ServerOnly markieren oder 'if(isServer) then {...};' verwenden? Was machen die Bilder mit schwarzen A/E und bunten L/G im Wiki bei Befehlen ganz oben? Erklärungen gibt es dazu genug im Internet - z.B. http://killzonekid.com/arma-scripting-tutorials-locality/
    • Die Code-Beispiele sind dort veraltet, aber die Bilder gut erklärt. Es sollte in dem Beispiel remoteExec oder remoteExecCall genutzt werden (siehe Beispiel 9), wodurch ein PublicVariableEventhandler nicht nötig ist.
  • Bevor man Befehle sucht (oder gar Skripts schreiben will) nochmals überlegen ob es nicht mit den nativen Mitteln des Editors geht [z.B. KI Skill auf 0 setzen und Wegpunkt mit Behaviour Careless statt KI mit Befehlen deaktivieren ]
  • Wenn man Skripts schreibt und diese sehr ähnlich aussehen, kann man vermutlich ein Skript mit Parametern schreiben (dies kann auch nach hinten los gehen und zu Unübersichtlichkeit führen). Hierbei bitte params nutzen.
  • Die Wiki-Beiträge zu Befehlen sind (für die meisten bzw. neuen) Befehle gut dokumentiert. Hier werden erst die Parameter aufgelistet und erklärt. Abschließend sind dort aber Beispiele, zusätzliche Informationen und Notizen vorhanden, diese helfen einem genauso weiter - wenn nicht sogar mehr. Lest alles aufmerksam durch bevor ihr Google benutzt oder jemanden fragt. (Abgesehen davon sind oben unter dem Namen die Bilder zur Lokalität zu finden.)
  • Zeus-Modul erstellen mit eigener Profil GUID als "Owner" (wenn keine Zeus-Slot vorhanden)

Mission Checkliste

Bevor ihr die Mission an das QM überweist solltet ihr folgendes beachten bzw. im Hinterkopf behalten

  • Wo sind (Endlos) Schleifen (while, waitUntil, forEach)?
  • Wo wurden Skripts oder mehrere Befehle genutzt (z.B. im Trigger)?
  • Gibt es Code (etwa in einem Trigger) der nur 1x ausgeführt werden soll bzw. mit isServer versehen ist (z.B. createUnit, deleteVehicle, addMagazineCargoGlobal).
  • Objekte die nur als Dekoration dienen, als einfaches Objekt (simple Object) markieren (Haken rein). [1] Alternativ die Simulation deaktivieren, falls es zerstörbar bleiben oder eine addAction haben soll (Haken raus).
  • KI die nur als Dekoration dienen 'Skill' auf 0 setzen (ggf. 'this stop true' in init-Zeile)
  • Funktioniert alles im Editor?
  • Funktioniert alles auch auf einem dedizierten Server bzw. unseren Test-Server?
  • Funktioniert das Loadout? Zum Testen:
    1. ESC
    2. Debug Console reinklicken (großes Rechteck)
    3. [player] execVM "loadouts\textbackslash grenadier.sqf""
    4. Local Exec

Beim Skripten

Event Skripte

ArmA bietet bestimmte Event Skripte in denen man auch seine Skripte aufrufen kann.[2]

Skriptname Nutzen
init.sqf wird vom Server und jeden Spieler bei Missionsstart aufgerufen (auch beim JIP)
initServer.sqf wird vom Server bei Missionsstart aufgerufen
initPlayerLocal.sqf wird von jeden Spieler bei Missionsstart aufgerufen (auch beim JIP - hierbei gibt es die Variable didJIP)
onPlayerRespawn.sqf wird von jeden Spieler beim Respawn aufgerufen (auch beim Missionsstart)

Prüfen ob ein Objekt eine bestimmte Variable ist

if(_object == myGlobalVar1) then { .. };
Führt zu Fehlern falls das Objekt nicht existiert (nil ist). Daher:
if(!isNil "myGlobalVar1") then { if(_object == myGlobalVar1) then {..}; };
Oder
if(str _object == "myGlobalVar1") then { .. };
Falls mehrere Variablen möglich sind, kann anstatt
if(_object == myGlobalVar1 || _object == myGlobalVar2) then { .. };
ein Array genutzt werden:
if(str _object in ["myGlobalVar1","myGlobalVar2"]) then { .. };

Code in Anführungszeichen

player addAction ["title", "hint ""test""; "];
Ist langsam, da der Code erst interpretiert werden muss. Besser:
player addAction ["title", {hint "test";}]

SQF-Dateien aufrufen

execVM "myScript.sqf";
Sollte bei häufigen Aufrufen (und wenn sich der Code nicht verändert) als Funktion definiert werden.
myScriptAsFunction = compile preprocessFileLineNumbers "myScript.sqf";
[ ] call myScriptAsFunction;
Bei einmaligen Nutzen geht dies auch in einer Zeile bzw. kann ohne Funktionsnamen geschehen.
[ ] call compile preprocessFileLineNumbers "myScript.sqf";
Oder direkt als Funktion (in der description.ext) definieren:
class CfgFunctions {
    class myClass_uniqueName {
       tag = "myTag";
       class init {
          file = "subfolderName";
          class myScriptAsFunction {};
       };
    };
};
Die Datei 'subfolderName/fn_myScriptAsFunction.sqf' wird so zur Funktion 'myTag_fnc_myScriptAsFunction'. Hierbei beginnt die Datei immer mit einem 'fn_' und endet mit dem Klassennamen (hier 'myScriptAsFunction'). [3] Wenn man eine Funktion (auch mit compile) verändert wird die Änderung nicht direkt übernommen bzw. ein Restart der Mission ist nötig. Man muss die Funktion neu kompilieren.
"myTag_fnc_myScriptAsFunction" call BIS_fnc_recompile;

Nutzung von sleep

Wenn der Spieler raustabbt wird sleep sozusagen angehalten -> uiSleep benutzen (für den Server egal).

sleep geht nur in bestimmten Umgebungen (execVM, spawn) - es geht z.B. nicht bei Triggern, dort muss spawn genutzt werden.

Eventhandler nutzen

Werft immer einen Blick auf EventHandler. Diese führen (dann von euch definierten) Code aus, wenn das Event ausgelöst wird. Der Vorteil ist, dass ihr nicht andauerend (wie etwa im Trigger) eine Bedingungen abfragen müsst. [4] [5]

Abbruch in Bedingung / Abfragen mehrerer Bedingungen

ArmA testet alle Bedingungen komplett durch, auch wenn diese nicht mehr wahr werden kann. Deswegen muss im obigen Abschnitt beim Prüfen nach einer bestimmten Variable bei der isNil-Abfrage eine weitere if-Abfrage folgen. Falsch wäre folgendes:
if(!isNil "myGlobalVar1" && _object == myGlobalVar1) then {..};
Wenn 'myGlobalVar1' nicht existiert bzw. nil ist würde auch noch die zweite Bedingung abgefragt werden und dann einen Fehler generieren. Damit nach der ersten Abfrage abgebrochen wird muss dies mit eckigen Klammern extra angegeben werden.
if(!isNil "myGlobalVar1" && {_object == myGlobalVar1}) then {..};
Dieses geschieht bei vielen Programmiersprachen automatisch, in SQF nicht.

Fundgrube

Man kann an verschiedenen Orten Skripts finden. Jedes gefundene Skript sollte man aber immer mit Argwohn betrachten. Es folgt eine Auflistung von TTT-naher Ablagestellen (inklusive Eigenwerbung).

Spezielle Tipps

Es folgt eine Auflistung von Hinweisen, die einen gegebenenfalls weiterhelfen können. Die Punkte sind eher zum rumstöbern gedacht - im Gegensatz zu den vorangegangenen Abschnitten, dessen Inhalt sollte man verinnerlichen.

Die folgenden Tipps können veraltet sein bzw. durch neue Befehle oder Mods eventuell eleganter gelöst werden.

Blufor-Fraktion als Opfor-Fraktion spielen lassen

In der Gruppe als Führer (auch mit höchsten Rang) eine Opfor-Einheit platzieren (mit Spawn-Wahrscheinlichkeit 0). Sprich die einzelnen Gruppenmitglieder zur Opfor-Einheit als Gruppe hinzufügen / verbinden.

Alternativ kann man auch in der mission.sqm die Seite der Gruppe und Einheiten in der Gruppe ändern. Die mission.sqm sollte man natürlich mit Vorsicht und nur mit vorherigen Backup ändern.

Platzierte Einheiten bzw. Fraktion zählen

Möchte man schnell wissen wie viele Einheiten im Editor verbaut sind kann man natürlich einfach die Einheiten zählen lassen. Dies ist dadurch interessant, da man die Feindstärke abschätzen und ggf. anpassen kann.
hint format ["BLUEFOR: %1\nOPFOR: %2\nINDEPENDENT: %3", BLUFOR countSide allUnits,
    OPFOR countSide allUnits, INDEPENDENT countSide allUnits];

Intel Objekt bzw. Dokumente

Mit dem Intel Objekt (Empty -> Intel -> Documents) können bei Finden Informationen für eine ganze Seite bereit gestellt werden. Dafür in die init-Zeile:
if (isServer) then {
   // 3 verschiedene Beispiele für ein (mögliches) Bild 
   this setVariable ['RscAttributeDiaryRecord_texture','a3\structures_f_epc\Items\Documents\Data\document_secret_01_co.paa', true];
   this setVariable ['RscAttributeDiaryRecord_texture','a3\structures_f_epc\Items\Documents\Data\files_secret_ca.paa', true];
   this setVariable ['RscAttributeDiaryRecord_texture','bild.jpg', true];
   // Information der Dokumente
   [this,'RscAttributeDiaryRecord',['Ueberschrift der Dokumente','Genaue Information<\br>Mit HTML-Tags zur Formatierung','']] call bis_fnc_setServerVariable;
   // Für welche Seite sind diese Dokumente
   this setVariable ['recipients', WEST, true];
};
Merke: Wenn Intel aufgenommen wird ist die Position [0,0,0]

Objekt an anderes Objekt heften

Um Immersion o.ä. zu erzeugen möchte man ggf. Objekte aneinander heften. Beispeilsweise an Chemlight im Laderaum einer C-130 um ein Sprunglicht zu simulieren.
_chemlight = "Chemlight_green" createVehicle [0,0,0];
_chemlight attachTo [_plane,[0,0,1];

Objekt zufällige Position zuweisen

Möchte man zufällige Elemente in der Mission einbauen kommt man um Zufallsfunktion nicht herum. So kann man bei der Gruppe die Wahrscheinlichkeit der Platzierung einstellen (probability of presence) oder etwa Teile des Loadouts mit selectRandom variieren lassen.

Häufig möchte man ein Objekt (z.B. Heli-Wrack) an einer von mehreren vorgegebenen Positionen erscheinen lassen. Dies ist zwar auch in der createVehicle Funktion integriert, aber man kann auch einfach im Editor platziertes Objekt mit Markern auf der Karte gruppieren und es wird zufällig zu einem der Marker oder der ursprünglichen Position (im Editor) gestellt. Etwas fusselig dabei ist, dass beim Gruppieren die Marker nicht angezeigt werden und somit blind die Mitte des Markers zum Gruppieren getroffen werden muss. Am besten hierzu die Marker am Anfang direkt neben dem Objekt stellen.

Thermal- o. Nachtsicht deaktivieren

this disableTIEquipment true;
this disableNVGEquipment true;

Haus abschließen

Es gibt eine fest definierte Variable, mit der man eine Tür im Haus verschließen kann. Dies ist auch auf Objekte wie einen Zaun übertragbar.

house1 setVariable ['bis_disabled_Door_1', 1]
house1 setVariable ['bis_disabled_Door_2', 1]

Hierbei wird nur eine Tür (mit der internen Bezeichnung Door_1 oder Door_2) abgeschlossen. Außerdem muss die Variable natürlich jedem bekannt sein (obiges Beispiel für init-Zeile / Ausführung auf jedem Client).

Nicht zu vergssen ist, dass das Haus bzw. Objekt erst gefunden werden muss (z. B. mit nearestObject) - außer es wurde vom Missionsbauer platziert.

Terrain-Objekte entfernen

Terrain-Objekte wie Häuser oder Bäume kann man zwar nicht wirklich entfernen, aber verstecken - das hat aber den gleichen Effekt.
private _terrainObjects = nearestTerrainObjects [[5682.446,11060.217,0],[],15];
{
    hideObjectGlobal _x;
} forEach _terrainObjects;

Dies gehört in die initServer.sqf. Die Koordinaten kann man über das Kontextmenü im Editor erhalten oder ein Hilfsobjekt platzieren. Zusätzlich kann man die Objekttypen direkt im Aufruf von nearestTerrainObjects grob filtern oder man kann in der forEach-Schleife den Typ abfragen.

Texturen ändern

Für Schilder und dem Ladebild empfehlen sich Bilder im Verhältnis 2:1. Die beste Auflösung ist beispielsweise 1024 x 512.

Bei den Whiteboards haben wir zwar eine Auflösung im Verhältnis 1:1, aber wir benötigen einen zusätzlichen Rand. Beispielsweise muss das Bild in der Auflösung 512 x 367 sein und dann mit schwarzen Rändern auf 512 x 512 aufgebläht werden. Sonst wir das Bild in der Höhe gestaucht.

Um außerdem die Missionsdatei nicht aufzublähen empfiehlt sich ein Bild im JPG-Format mit etwas stärkerer Komprimierung zu nutzen (z.B. mit Paint.NET einstellbar). Die optimale Variante ist aber eine Umwandlung vom PNG in das PAA-Format (mit ArmA Tools -> TexView 2), da dann die Bilder auch bei einer größeren Entfernung angezeigt werden. Sonst kann es sein, dass die Textur erst schwarz ist und ab einer gewissen Nähe geladen bzw. angezeigt wird. Beim PAA-Format ist keine beliebige Auflösung möglich, sondern es müssen 2er Potenzen (64, 128, 256, 512, 1024, 2048, ..) genutzt werden.

Bei den folgenden Code-Beispielen handelt es sich um globale Befehle, die nur auf dem Server ausgeführt werden müssen. Dementsprechend umschließen mit

if (isServer) then { ... };

Tafeln u.ä.

this setObjectTextureGlobal [0, "images\tafel.jpg"];

Bei manchen Objekten im EDEN-Editor gibt es eine zusätzliches Textur-Attribut. Beispielsweise beim "Land_Noticeboard_F" heißt dies "Object Specific - Object: Noticeboard". Dort kann man dann unter "Textur #0" den Pfad eintragen und sieht das Bild sogar im Editor.

images\tafel.jpg

Flagge

this setFlagTexture "\a3\ui_f\data\Logos\arma3_expansion_ca.paa"

Fahrzeuge

Hier werden als Beispiel 3 Texturen vom Scorcher (Vanilla Artillerie) gesetzt.
this setObjectTextureGlobal [0, "texturen\BW_scorcher01.paa"];
this setObjectTextureGlobal [1, "texturen\BW_scorcher02.paa"];
this setObjectTextureGlobal [2, "texturen\BW_scorcher03.paa"];
https://forums.bistudio.com/topic/180646-list-of-all-hidden-texture-inits/

Sound-Dateien abspielen

Die meisten Sound-Befehle sind lokal, müssen also auf allen Clients ausgeführt werden. Außerdem müssen eigene Sounds oder Musik in der description.ext definiert werden.

Besonders bei Sounds sollte man auf die Lokalität achten! Sonst kann es passieren, dass bei 20 Spielern ein Sound 21 mal gleichzeitig abgespielt wird.

Sound-Dateien in description.ext definieren

https://community.bistudio.com/wiki/Description.ext#CfgMusic

https://community.bistudio.com/wiki/Description.ext#CfgSounds

Musik

playMusic "myMusic"
Es kann nur eine Musik geben siehe playMusic.

Sound

Mit playSound3D lässt sich ein Sound sozusagen von einem Objekt bzw. räumlich abspielen.
playSound3D ["A3\Sounds_F\sfx\alarmCar.wss", _car, false, getPosASL _car, 0.5]
Der Vorteil bei say3D ist, dass bei Tod der Unit der Sound abgebrochen wird (siehe Notes im Wiki).
_unit say3D "mySound"

Trigger

Trigger-Synchronisation

Wenn man Trigger z.B. mit Waypoints synchronisiert hat man ein starkes Mittel zur Hand. Dadurch ist ein Waypoint so lange nicht erfüllt, bis der Trigger gefeuert hat (alternativ Waypoint Condition: triggerActived triggerName). Dadurch kann man etwa Verstärkung simulieren oder ein Gebiet angreifen lassen, sobald der Spieler an einem bestimmten Punkt ist.

Die Synchronisation mit Einheiten funktioniert mit einem Headless Client ohne weitere Hilfsmittel nicht. Dort muss bei Wegpunkten in der Condition mit triggerActivated oder get/setVariable (und beim Trigger-Typ Switch mit Scripts) gearbeitet werden. Oder man nutzt einen Headless-Client-Framework, der alles für einen übernimmt.

KI Patrouille/Cycle abbrechen

Lässt man eine Gruppe mit einem Cycle-Waypoint patroullieren werden Waypoints nach dem Cycle-Waypoint nie erreicht. Synchronisiert man einen Trigger mit dem Cycle-Waypoint und setzt den Typ des Triggers auf Skip Waypoint, wird der Waypoint nach dem synchronisierten Waypoint aktiv (und die davor sozusagen gelöscht). Dies funktioniert auch mit anderen Waypoint-Typen, nur muss man daran denken, dass der Waypoint nach dem synchronisierten Waypoint aktiv wird.

Trigger-Bedingungen

Du willst einen beweglichen Trigger? Dann befestige ihn mit attachTo an ein (bewegliches) Objekt.

Anzahl von Spielern einer Seite
Als Condition / Bedingung. Hierbei muss die Activation die zu zählende Seite (oder Anybody) sein.
independent countSide thisList < 3
Spieler im Trigger
Als Condition / Bedingung. Hierbei muss die Activation die Seite des Spielers (oder Anybody) sein. Thema hier ist wieder Lokalität.
player in thisList

interessante ACE-Befehle

https://ace3mod.com/wiki/framework/

Rollen (Medic, Pio)

Medic
0 kein Medic / Sanitäter
1 Medic / Sanitäter
2 Doctor / Arzt
_unit setVariable ["ace_medical_medicClass", 1, true];
Reparieren oder Sprengstoff entschärfen
_unit setVariable ["ACE_IsEngineer", true, true];
_unit setVariable ["ACE_isEOD", true, true];
Medic Facility
_object setVariable ["ace_medical_isMedicalFacility", true];

Ergeben und Festnehmen

[_unit, true] call ACE_captives_fnc_setSurrendered;
[_unit, true] call ACE_captives_fnc_setHandcuffed;

Gun Bags

In unserem Repo sind als Rucksack ACE Gunbag vorhanden (2 Stück). In diesem kann man zwar auch normale Ausrüstung wie Munition hineinpacken. Über Skriptbefehle kann man aber tatsächlich Waffen und zusätzliche Ausrüstung hineinpacken.

In einem Loadout könnte dies so aussehen (erst die Items aus dem normalen Arsenal, dann das Scharfschützengewehr mit Skriptbefehlen).

player addBackpack "ace_gunbag";
player addItemToBackpack "ACE_ATragMX";
player addItemToBackpack "ACE_Kestrel4500";
for "_i" from 1 to 3 do {player addItemToBackpack "BWA3_10Rnd_127x99_G82";};
player addWeapon "ACE_Vector";

private _gunbag = backpackContainer player;
private _weapon = "BWA3_G82";
private _items =  ["ACE_optic_LRPS_PIP"];
private _magazines = [];
_gunbag setVariable ["ace_gunbag_gunbagWeapon", [_weapon, _items, _magazines], true];

Interaktion

Ziehen deaktivieren
[_ammoBox, false, [0,0,0], 0] call ace_dragging_fnc_setDraggable;
Tragen deaktivieren
[_ammoBox, false, [0,0,0], 0] call ace_dragging_fnc_setCarryable;
ACE Aktion erstellen
private _action = ["MyId", "My Name", "", {
        params ["_target","_caller", "_arguments"];
        /* code */
    }, {true},{},[_myArgumentA, _myArgumentB]] call ace_interact_menu_fnc_createAction;
An Objekt als Fremdinteraktion (MainActions) oder Selbstinteraktion hinzufügen. Um eine ACE Aktion im Fahrzeug aufzurufen, muss am Fahrzeug eine Selbstinteraktion hinzugefügt werden. [1]
[_object,0,["ACE_MainActions"], _action] call ace_interact_menu_fnc_addActionToObject;
[_object,1,["ACE_SelfActions"], _action] call ace_interact_menu_fnc_addActionToObject;
Spectator
[player] call ace_spectator_fnc_setSpectator;

ACE Medic-System für (eine) KI aktivieren

Über die Module kann man einstellen, dass das gewählte Medic-System für die ganze KI greift. Aber möglicherweise möchte man dies nur für eine spezielle KI aktivieren (z.B. Revive für einen Offizier). Dies geht bei dem Basic Medic-System relativ elegant.[6][7]
_unit setVariable ["ace_medical_enableRevive", 2, true];
Mit dem Advanced Medic-System ist dies nur mit Trickserei möglich. Man kann zum einen die erweiterten Wunden nutzen.[8][9]
_unit setVariable ["ace_medical_enableMedical", true, true];
[_unit] call ace_medical_fnc_init;
Damit das Revive-System greift muss man aber so tun, als ob die Einheit vom Zeus kontrolliert wird.[10][11]
_unit setVariable ["bis_fnc_moduleRemoteControl_owner", _unit, true];
Außerdem beim Modul Einstellen, dass "Ferngesteuerte KI-Einheiten" / "Remote Controlled AI" deaktivieren. Wenn dies deaktiviert ist, werden ferngesteuert KI-Einheiten als Spieler gewertet und gehen in den Revive-State.

Dies alles führt dann natürlich dazu, dass ein Zeus diese Einheit nicht übernehmen kann und bei ferngesteuerten KI-Einheiten bewusstlos wird.

Jetzt könnte man der Einheit auch Schaden zufügen.
[_unit, 0.3, "body", "stab"] call ace_medical_fnc_addDamageToUnit;
[_unit, 0.3, "hand_r", "vehiclecrash"] call ace_medical_fnc_addDamageToUnit;
[_unit, 0.3, "hand_l", "shell"] call ace_medical_fnc_addDamageToUnit;
[_unit, 0.8, "leg_r", "bullet"] call ace_medical_fnc_addDamageToUnit;
[_unit, 0.5, "leg_l", "falling"] call ace_medical_fnc_addDamageToUnit;

ACE Explosives scharf machen

Im Editor platzierte Minen sind automatisch durch ACE scharf gemacht. Können also entschärft werden. Möchte man aber andere Explosives (unter Things) oder andere Trigger nutzen, kann man auf das Wiki bezüglich des Explosive Framework zurückgreifen.

Hierbei gibt es zwar verschiedene Möglichkeiten (Cellphone, Command, DeadManSwitch, IRSensor, MK16_Transmitter, PressurPlate, Timer, Tripwire), aber die Funktion ist zum Verbinden mit dem Trigger einer Einheit (etwa KI) gedacht. Dementsprechend (je nach Art des Sprengstoffes) Cellphone oder DeadManSwitch am interessantesten (z.B. für IEDs), wenn die Einheit eine dieser Gegenstände im Inventar hat.

Mit ACE, die Waffen zu Beginn der Mission für alle auf "Sicher" stellen

Ihr fügt folgenden Befehl in eure "onPlayerRespawn.sqf"
[ACE_player, currentWeapon ACE_player, currentMuzzle ACE_player] call ace_safemode_fnc_lockSafety;

KI Aufgaben zuweisen (Patrouille etc.)

Es gibt diverse KI-Scripts, bei der die KI etwa patrouilliert und auch in Häuser hinein geht (man könnte genauso selbst Waypoints mit Placement-Radius nutzen). Oder es wird automatisch ein Bereich mit KI besetzt und verteidigt - hier gibt es auch die Module unter der Kategorie 'Sites' im Editor.

Jedoch gibt es auch einige Vanilla-Funktion oder Funkionen von Mods, die man für eine einfache Variante nutzen kann. Dazu den Befehl in die init-Zeile der Gruppe schreiben (mit isServer).

KI im Bereich patrouillieren lassen

Die KI patroulliert in dem angegebenen Radius (hier 1000m).
[group this, getPos this, 1000] call BIS_fnc_taskPatrol;

KI Bereich verteidigen lassen

Die KI verteidigt ein Gebiet, besetzt hierbei auch statische Geschütze und ggf. schickt Sie einen kleinen Teil der Gruppe auf Patrouille. Man sollte sich aber auch die Module unter 'Sites' angucken, da bei dieser die KI bzw. Fahrzeuge (Vanilla-Einheiten) gespawned werden.
[group this, getPos this] call BIS_fnc_taskDefend;

KI- Gruppen mit CBA-Funktionen steuern

Es ist auch möglich mit CBA Funktionen KI zu steuern. Aber Achtung die Funktionen sind nicht automatisch Headless- Client fähig. Sie müssen entweder Blacklisted werden oder Headless- Client fähig gemacht werden.

CBA Task Attack

Erstellt einen S&D Wegpunkt an der übermittelten Position.
[_group,_position,_radius,_deleteWaypoints] call CBA_fnc_taskAttack;
Parameter
  1. _group: Gruppe oder Objekt – Gruppe, die angreifen soll (oder eine Einheit aus dieser Gruppe)
  2. _position: Position – Position, die angegriffen wird.
  3. _radius (optional): Zahl – Radius um die Position herum, innerhalb dessen angegriffen werden soll.
  4. _deleteWP (optional): Wahrheitswert – true, wenn alle existierenden Wegpunkte gelöscht werden sollen
Beispielaufruf
[player, getpos (player findNearestEnemy player), 100, true] call CBA_fnc_taskAttack;
Die Gruppe des Spielers erhält so den Auftrag, die Position im Radius von 100 Metern um den nächsten Feind anzugreifen und löscht alle vorher vorhandenen Wegpunkte.

CBA Task Defend

Lässt die Gruppe Patrouille laufen und Gebäude wie auch statische Waffen besetzen. Wird die Gruppe angegriffen, bewegen sich die Einheiten ggf. aus den Gebäuden heraus.
[_group,_position,_radius,_threshold,_patrol,_hold] call CBA_fnc_taskDefend;
Parameter
  1. _group: Gruppe oder Objekt – Gruppe oder eine Einheit daraus, die verteidigen soll.
  2. _position (optional): Position – Zentrum des zu verteidigenden Gebiets.
  3. _radius (optional): Zahl – Radius um das Zentrum herum, innerhalb dessen verteidigt wird.
  4. _threshold (optional): Zahl – Minimale Zahl von Verteidigungspositionen innerhalb von Gebäuden, um sie zur Verteidigung zu nutzen.
  5. _patrol (optional): Zahl (0–1) oder Wahrheitswert – false, wenn niemand patrouillieren soll, ansonsten Anteil der Gruppenmitglieder, die patrouillieren.
  6. _hold (optional): Zahl (0–1) oder Wahrheitswert – Wahrscheinlichkeit, dass eine Einheit im Kampf das besetzte Gebäude verlässt
Beispielaufruf
[this] call CBA_fnc_taskDefend
Die Gruppe der Einheit, in deren Init-Zeile das steht, wird in einem Radius von 50m um die Einheit herum verteidigen.
[group player, getmarkerpos "Beispiel", 400, 2, 0.3] call CBA_fnc_taskDefend
Die Gruppe des Spielers wird den Auftrag erhalten, in einem Radius von 400 Metern um den Marker „Beispiel“ herum zu verteidigen.

Es werden Gebäude mit mindestens zwei Plätzen besetzt und die Chance für jeden Soldaten, zu Patrouillieren, liegt bei 30%.

CBA Task Patrol

Lässt Einheiten in einem Radius x mit y Wegpunkten im Kreis laufen. Verhalten mag mit Parametern deutlich komplexer werden.
[_group,_position,_radius,_wpCount,_wpType,_behaviour,_combatMode,_speedMode,_formation,_code,_timeOut] call CBA_fnc_taskPatrol;
Parameter
  1. _group: Gruppe oder Objekt – Gruppe oder eine Einheit daraus, die patrouillieren soll.
  2. _position (optional): Position – Zentrum des zu patrouillierenden Gebiets.
  3. _radius (optional): Zahl – Radius um das Zentrum herum, innerhalb dessen patrouilliert wird.
  4. _wpCount (optional): Zahl – Anzahl der gesetzten Wegpunkte, die abgelaufen werden.
  5. _wpType (optional): String – Art der gesetzten Wegpunkte.
  6. _behaviour (optional): String – Verhalten der KI (Wie bewegt sie sich?.
  7. _combatMode (optional): String – Kampfmodus der KI (Unter welchen Bedingungen greift sie an?).
  8. _speedMode (optional): String – Bewegungsgeschwindigkeit der KI.
  9. _formation (optional): String – Formation der Gruppe.
  10. _code (optional): Code – Code, der jedes Mal ausgeführt wird, wenn die KI einen Wegpunkt erreicht.
  11. _timeOut (optional): Array – Array der Form [Min,Med,Max], das die Wartezeit angibt, bevor die Gruppe weiter läuft
Beispielaufruf
[this, getmarkerPos "Beispiel", 300, 7, "MOVE", "AWARE", "YELLOW", "FULL", "STAG COLUMN", "this call CBA_fnc_searchNearby", [3,6,9]] call CBA_fnc_taskPatrol;
Die Einheiten werden in einem Radius von 300 Metern auf 7 Wegpunkten patrouillieren. Sie laufen dabei sehr schnell in gestaffelter Kolonne und durchsuchen bei jedem Wegpunkt zunächst ein nahes Gebäude, bevor sie weiterlaufen.

CBA Search Nearby

Lässt die Ki ein nahes Gebäude durchsuchen.
[_group] call CBA_fnc_serchNearby;
Parameter

_group: Gruppe oder Objekt – Gruppe oder eine Einheit daraus, für die die Funktion aufgerufen werden soll

Beispielaufruf

[player] call CBA_fnc_searchNearby;

KI-Verhalten erzwingen

Hier geht es darum KI-Verhalten zu erzwingen. Im Gegensatz dazu kann man auch das Verhalten über Waypoints steuern (niedrige Haltung mit Behaviour Stealth oder ignorieren von Gegnern mit Careless). Man sollte das Erzwingen von Verhalten mit Scriptbefehlen nur als letztes Mittel nutzen und versuchen dies mit den Elementen des Editors zu lösen.

Allgemein gibt es eine Liste von Aktionen mit der man der KI etwas befehlen kann. Jedoch gibt es für viele auch seperate Befehle (z.B. moveInDriver).

Möchte man etwa, dass die KI den Motor bei Erreichen eines Waypoint ausmacht kann man dies elegant über das Feld onActivation und action lösen.
this action ["engineOff", vehicle this];

Einheiten erschießen lassen

_aiToCommand doFire _targetToAttack;

Flughöhe erzwingen

_airVehicle flyInHeight _height;
Empfiehlt sich etwa als Code in den Waypoints (on Activation).

Haltung erzwingen

Nur als letztes Mittel nutzen. Beispielsweise sind KI mit der Behaviour Stealth den Großteil in liegender Haltung.
_unit setUnitPos "DOWN";
Für weitere Informationen siehe setUnitPos.

Animation abspielen

Es gibt mehere Befehle. Im Idealfall nutzt man aber playMove, da bei diesem der Effekt auf allen Clients zu sehen ist (dieser muss aber auf dem Rechner ausgeführt werden, dem die Einheit gehört - in der Regel der Server bei KI) und nicht eine Animation plötzlich abbricht.
_unit playMove "Acts_carFixingWheel";

Minen legen

Dies ist nicht möglich. Aber man kann tricksen indem man unter den Einheiten Minen platziert (und die KI dann weiterschickt). Dies kann man dann noch zur Perfektion mit Animationen oder erzwungenen Ducken erweitern.
_mine = createMine ["SLAMDirectionalMine", getPosATL _unit, [], 0];
_mine = setDir (getDir _unit);

Gruppe in Fahrzeug setzen

Wenn man eine Gruppe (von KI) in ein Fahrzeug setzen will, ohne den entsprechenden Wegpunkt zu nutzen, muss in die init-Zeile einer Person der Gruppe folgendes.
{_x moveInCargo vehicleName} forEach units group this;
Aber hier kommt wieder Lokalität/JIP-Probleme im Spiel - also besser über EDEN oder Waypoints lösen.

KI bei Tod in die Luft sprengen lassen

Mit Vanilla und EventHandler:
if(local this) then {
  this addEventHandler ["Killed", {
    params ["_unit"];
    private _bomb = "M_Mo_82mm_AT_LG" createVehicle (getPos _unit);
    deletevehicle _unit; // optional
  }];
};
Mit ACE Explosive scharf machen und hierbei den DeadManSwitch nutzen (muss im Inventar sein):
[triggerman_4, IED_4, "ACE_DeadManSwitch"] call ace_explosives_fnc_connectExplosive;

Verhalten der KI ändern

Wie in den allgemeinen Tipps sollte das nur als letztes Mittel genutzt werden. Versucht dies über das Verhalten bei Waypoints zu lösen. Sonst lässt sich das Verhalten der KI einschränken.
this disableAI "MOVE";
Für weitere Informationen siehe disableAI. Hierbei entstehen unschöne Nebeneffekte. Durch den obigen Befehl bleibt die KI nicht nur stehen, sondern dreht sich auch nicht um - greift also keine Feinde hinter ihr an. Da muss man etwa tricksen und die Bewegungsgeschwindigkeit der KI auf 0 setzen.
this forceSpeed 0;

Statische Verteidigung vs. KI

Häufig baut man für die KI eine Verteidigungsstellung, jedoch funktioniert dies nicht immer mit der KI. Beispielsweise werden (ohne AI Mods) die Feinde spät erkannt und erst HMG stellen eine ernste Bedrohung für die Spieler da.

Außerdem können einige (eingemauerte) statische SPZ nicht die gewünschte Wirkung erzielen. So sind die RHS BMP mit der KI teilweise buggy, feuern nicht oder der Commander steigt aus. Zusätzlich wird ein Fahrzeug möglicherweise nicht über eine Mauer oder Sichtschutz schießen, auch wenn dies ohne Probleme möglich ist. Deshalb sollten aufwändigere Verteidigungsanlagen als nur ein HMG in der Landschaft (auch HMG in erhöhten Bunker) getestet werden - dies liegt im Interesse des Missionsbauer.

Weiterführende Links

  1. https://github.com/specop0/arma_scripts/blob/master/createSimpleObject/simpleObjectCollectorEden.sqf
  2. https://community.bistudio.com/wiki/Event_Scripts
  3. https://community.bistudio.com/wiki/Functions_Library_\%28Arma_3\%29#Adding_a_Function
  4. https://community.bistudio.com/wiki/Arma_3:_Event_Handlers
  5. https://community.bistudio.com/wiki/addEventHandler
  6. fnc_setDead.sqf:29f
  7. fnc_handleDamage.sqf:137
  8. fnc_hasMedicalEnabled.sqf:21
  9. fnc_init.sqf
  10. fnc_isPlayer.sqf:22
  11. fnc_setDead.sqf:30