"TEMPLATE" DE MISSION V2.1 © Pumpkin
- template.rar
- template de mission pour Operation Arrowhead
- template de mission pour Arma 2 "simple" (fonctionnalités spécifiques OA retirées)
- cette page html
Le but final est d'obtenir une mission-type, avec les "outils" les plus courants disponibles de suite, et ne nécessitant que peu de modifications. Les différents aspects d'une mission-type, comme les objectifs, les fins de missions sont également expliqués, ce qui fait que ce long texte peut aussi être une source d'informations pour les créateurs de missions "débutants".
La version 2.1 est modifiée selon :
Pour que le "template" soit pleinement fonctionnel, il faut un jeu patché en version 1.56 !
- Les dernières améliorations de ArmA2-OA
- Les difficultés classiques rencontrées par les créateurs de missions (merci à Tromplamort et Long Nez pour les tests)
- Les différents bugs constatés après utilisation en conditions réelles
Le "template" pour ArmA 2 simple n'a quasiment pas été modifié. Ont été modifié :
- La hierarchie des répertoires : ajout du répertoire "plr_respawn\", retrait des scripts "respawn" du répertoire "libs\"
- Certains scripts ont été mis à jour : init.sqf, Rearm_Cargo.sqf,...
- Le déclencheur permettant de régler le niveau des I.A.
Index :
(cliquez sur les labels pour accéder rapidement au sujet)
- RÉPERTOIRES & FICHIERS
- PRESENTATION
- DÉPART DE MISSION : MISE EN PLACE DES JOUEURS, MODULES ET MUNITIONS
- GESTION DES DIFFÉRENTES OBJECTIFS
- GESTION DES DIFFÉRENTES FINS
- LE FICHIER INIT.SQF
- LE FICHIER RESPAWN_HANDLER.SQF
- LE FICHIER STRINGTABLE.CSV
- LE FICHIER DESCRIPTION.EXT
- LA ZONE "INTRO"
- LA ZONE "GENERATION DE BATIMENTS SUR POSITION MARQUEUR"
- ZONE "SCRIPT DE PATROUILLE ALÉATOIRE SUR UNE PATROUILLE"
- ZONE "GENERATION DE PATROUILLE SUR UNE POSITION DE LOGIQUE DE JEU" (uniquement O.A. !)
- ZONE "GENERATION DE PATROUILLE SUR UNE POSITION DE "LOGIQUE DE JEU" + SCRIPT 'PATROLS.SQF'" (uniquement O.A. !)
- GENERATION DE GROUPE D'ATTAQUANTS (uniquement O.A. !)
- GENERATION DE GROUPE DE DEFENSEURS (uniquement O.A. !)
1. RÉPERTOIRES & FICHIERS :
Nota : les fichiers/répertoires suivi de (© Pumpkin) sont issus de mes travaux personnels.
Les scripts des répetoires lib\ et debug\ sont succeptibles de changer sans que l'archive du "template" soit modifiée. Les dernières versions sont éventuellement à récupérer sur ma page
- debug\ : répertoire contenant l'ensemble des scripts de débug (© Pumpkin) - A EFFACER EN TOTALITE DANS LA MISSION FINALE !!
- docs\ : quelques documentations annexes - A EFFACER EN TOTALITE DANS LA MISSION FINALE !!
- imgs\ : répertoire contenant les images pour briefing
- lib\ : répertoire de scripts/fonctions personnel (© Pumpkin) (voir le détail des scripts / fonctions ici )
- medkit\ : répertoire des scripts de gestion de kit de 1er secours (© Pumpkin)
- plr_respawn\ : répertoire des scripts de gestion du respawn, notamment la récupération des armes et du sac à dos (© Pumpkin)
- briefing.html : fichiers de débriefing (affiché en fin de mission)
- briefing.sqf : fichier de briefing (affichage en jeu)
- description.ext : définition des paramètres de la mission (image de chargement, type de respawn,...)
- init.sqf : fichier d'initialisation lancé au début de chaque mission
- intro.sqf : petite intro affichant le titre de la mission et un logo (© Pumpkin)
- mission.sqm : fichier de l'éditeur - NE PAS EDITER MANUELLEMENT ! (sauf experts)
- Patrols.sqf : script de patrouille aléatoire (© Pumpkin)
- respawn_handler.sqf : script appelé après mort du joueur - DOIT ÊTRE UNIQUE ! (tout fichier lié au respawn doit être appelé par respawn_handler.sqf)
- stringtable.csv : fichier stockant les différentes traductions de l'ensemble de la mission (dont le titre de la mission)
2. GÉNÉRALITÉS :
a. présentation de la mission "template"
La mission est découpée en "zone", chaque zone est indiquée par 2 marqueurs rouges : un marqueur de texte et un marqueur englobant la zone. Le marqueur de texte décrit la fonction des éléments dans la zone. Par exemple, la zone "intro" :
Le marqueur "lancement_intro" indique que la zone contient l(es) élément(s) nécessaire(s) au lancement de l'intro (le déclencheur qui lancera l'intro en début de partie), et le marqueur "lancement_intro_zone" indique la zone entourant les éléments. Dans ce cas simple, la zone ne contient qu'un élément.
Ces deux marqueurs sont évidemment à effacer dans la mission finale.b. déclencheurs de paramètrages
Il y a deux déclencheurs au beau milieu de la carte. L'un d'eux sert à récupérer la liste de toutes les unités enemis pour un script de débugage (voir l'entrée de menu "* head cam", si le mode de débugage est activé.)
A effacer également dans la mission finale.
L'autre sert à régler la compétence des IA, aussi bien les IA déjà présentes que celles générées (à condition de laisser le déclencheur en mode répétition). Suivant que vous ayez envie de vous la jouer "tir au pigeons" avec des "larves" comme ennemis ou que vous soyez plutôt du genre "suicidaire" et que vous vouliez vous mesurer à des "terminators"
Désactiver cette fonctionnalité en mettant "false" à la place de "true" dans le champ "condition". Les niveaux approximatifs sont :
- Novice : <0.25
- Débutant: >=0.25 & <=0.45
- Recrue : >0.45 & <=0.65
- Veteran : >0.65 & <=0.85
- Expert : >0.85
c. compatibilité Multi-joueurs des déclencheurs
Dans le cas de mission MP, il y a des cas où un déclencheur ne doit s'exécuter que sur le serveur. Le cas le plus typique, c'est lorsque le créateur de mission veut joindre une IA à l'équipe des joueurs humains, comme dans le cas du déclencheur au-dessus de l'équipe des joueurs
si le déclencheur ci-dessous n'avait que "this" dans le champs condition et que la mission était joué sur serveur dédié avec 3 joueurs, malgré l'activation à "une fois", il se déclencherai 4X ! : 1 X sur le serveur dédié + 1 X sur la machine des 3 joueurs = 4. Or on ne veut qu'un unique déclenchement. Et comme la mission est joué sur un serveur dédié, c'est lui qui doit gérer l'ensemble du scénario.
On va utilisé, pour limiter le lancement au serveur, la propriété de l'unité "logique de jeu" nommé ici "logictestserveur", car un logique de jeu est toujours local au serveur, traduisez en gros, n'a d'existence que sur le serveur. Donc, si l'on ajoute "... and (local logictestserveur)" au champ "condition" des déclencheurs qui ne doivent se déclenché QUE sur serveur, la condition n'étant pas remplie sur les machines des joueurs, le déclencheur ne s'activera QUE sur le serveur. La méthode a également l'avantage de fonctionner sous l'éditeur, puisque la machine du créateur de mission est automatiquement serveur dans ce cas.
this and (local logictestserveur)"this" pour une activation par BLUFOR et à la condition que l'unité "logictestserveur" existe sur la machine
[contact] join group (thislist select 0)le civil nommé "contact" rejoindra le groupe du 1er "BLUFOR" qui activera le déclencheur.On peut aussi déterminer un lancement sur les machines des joueurs et NON sur le serveur dédié, par la condition inverse, soit "... and (not (local logictestserveur))"
Autre exemple de bug classique : le lancement de script par déclencheur. Vous avez trouvé un script génial mais lorsque vous l'intégrez dans votre mission, ça capote, ça ne marche pas ou trés mal,... bref c'est la cata ! Et pourtant le script marche trés bien lorsque vous le testez sur l'éditeur. Ce sont généralement les symptômes d'un script non prévu pour le jeu en MP, et qui se lance plusieurs fois : il s'auto-parasite. Si le script en question est lancé via déclencheur, on peut utiliser la même technique.
Dans le template, j'ai utilisé mon script de "téléportation" (quelque chose d'un peu plus "élégant" qu'un simple "setpos"), que je lance par déclencheur, sans oublié d'ajouter le "...and (local logictestserveur)", qui garanti un lancement exclusif sur serveur. Avec le petit hélico, et en ayant pris soin de faire monter tout le monde à bord, je me suis dirigé vers ce déclencheur, derrière les hangars. Résultat : toutes les machines détectent la présence "BLUFOR" mais comme le "logique de jeu" n'a "d'existence" que sur le serveur, "(local logictestserveur)" ne sera vrai que sur le serveur, et donc lui seul s'occupera de "téléporter" ma fine équipe et l'hélicoptère, sans qu'un lancement sur une autre machine ne vienne parasité le script lancé par le serveur.
Ceux qui commence à se sentir une âme de scripteur peuvent aussi éventuellement mettre tout de suite en entête de script deux lignes qui font appel à mes fonctions :
_testclient = call compile preprocessFile "lib\Client_detection.sqf";Interdit le lancement sur serveur : le script fonctionnera uniquement sur une machine client (=de joueur) (et dans tous les cas en éditeur).
if (not _testclient) exitwith {};_testserver = call compile preprocessFile "lib\Server_detection.sqf";Interdit le lancement sur machine client (=de joueur) : le script fonctionnera uniquement sur serveur (et dans tous les cas en éditeur).
if (not _testserver) exitwith {};
3. DÉPART DE MISSION : MISE EN PLACE DES JOUEURS, MODULES ET MUNITIONS
a. le "respawn" (ou résurrection du joueur)
Les deux types de "respawn" les plus utilisés sont le respawn "INSTANT" et le respawn "BASE". La définition du respawn est à mettre dans le fichier "description.ext"fichier "description.ext"
... respawn="INSTANT"; //respawn="BASE"; // nécessite un marqueur 'respawn_west' et/ou 'respawn_vehicle_west' RespawnDelay = 10; // compte à rebour RespawnDialog = true; // montre le dialogue ...respawn="INSTANT" indique le type de respawn. Dans cet exemple, le respawn type "BASE" est désactivé (mis en remarque, en placant "//" devant la ligne). Le RespawnDelay représente le nombre de secondes avant résurrection et RespawnDialog permet d'activer/désactiver le petit dialogue avec score que l'on voit en attendant de revenir dans le jeu.
Dans le cas d'un respawn type "BASE", il faut un marqueur nommé impérativement "respawn_west", ou "respawn_east", "respawn_guerrila" ou encore "respawn_civilian", suivant le camp des joueurs. Un deuxième marqueur peut s'avérer indispensable si on veut faire réapparaitre les joueurs en véhicules, marqueur nommé "respawn_vehicle_west", "respawn_vehicle_east", "respawn_vehicle_guerrila", "respawn_vehicle_civilian". Pour plus d'infos sur le fichier "description.ext", se référer à la doc affiliée sur le wiki de bistudio.com.
b. les modules
Trois modules sont greffés sur les joueurs : sytème de 1ers soins et simulation de blessure alternative. Pour faire court, ils activent le système qui permet l'immobilisation du joueur blessé, trainer ou porter un blessé, l'assistance médicale d'urgence par un autre joueur,... bref, toute la gestion de joueur blessé. Tous les modules doivent être synchroniser à chacun des joueurs.
Note : le module défrichage a été supprimé, car, pour une raison inconnue, il semble qu'il génère un bug : les joueurs basculent en mode captif et sont ensuite ignorés des IA la seule preuve du bug est le fait que ce bug ait disparu après la suppression de ce module, et ce sur plusieurs missions "hors template". Le seule avantage de ce module est d'éventuellement alléger les lags en réseau, en supprimant le corps des joueurs morts, ce que fait le système de respawn du "template".
Un module supplémentaire, le module d'appui simple, permet l'utilisation de parachutage de ravitaillement et de renfort, d'appui aérien, d'artillerie et de mortier. Les variables dans le champ "initialisation" permettent d'activer/désactiver les différents type d'appui. Par défaut, tous les appuis sont activés. Pour les désactiver, il suffit de mettre "false" à la place de "true". (NOTA : ce module n'est disponible que sur Opération Arrowhead)
BIS_SSM_AmmoDrop_AVAILABLE_WEST = false;missionNamespace setVariable ["BIS_SSM_Mortar_ENABLED_WEST", false]; missionNamespace setVariable ["BIS_SSM_UnitsDrop_ENABLED_WEST", false]; missionNamespace setVariable ["BIS_SSM_AmmoDrop_ENABLED_WEST", false]; The settings above should give you artilleriy support with a delay of 60 seconds and airstrike support having an A-10 showing up. Accessoirement, on peut modifier le délai du support artillerie
BIS_SSM_UnitsDrop_AVAILABLE_WEST = false;
BIS_SSM_Airstrike_AVAILABLE_WEST = false;
BIS_SSM_Mortar_AVAILABLE_WEST = false;
BIS_SSM_Artillery_AVAILABLE_WEST = false;
BIS_SSM_CeaseFire_AVAILABLE_WEST = false;missionNamespace setVariable ["BIS_SSM_Artillery_DELAY", 60];ou encore le type d'avion et la bombe utilisés pour l'appui aérienmissionNamespace setVariable ["BIS_SSM_Airstrike_VEHICLE_WEST","F35B"]; missionNamespace setVariable ["BIS_SSM_Airstrike_DISPERSION_WEST","CruiseMissile 1"];
Pour plus de précisions à propos des modules, consultez la page des module de bistudio
c. les armes et munitions
Comme il est relativement pénible de mettre à disposition toutes les armes, un script de remplissage universel est greffé sur la caisse. Ce script rempli la caisse avec toutes les armes disponibles, quelque soit les addons supplémentaires ajoutés, officiel (BAF, PMC,...) ou non officiel (ACE2, ADO, Felin/R3F, Hexagon,...), le nombre des armes disponible est fonction de la nature de l'arme (grand nombre d'arme primaire, nombre réduit de lance-roquette,...), même chose pour le nombre de munition.
nul = [this] execVM "lib\Rearm_Cargo.sqf"
4. GESTION DES DIFFÉRENTES OBJECTIFS
La gestion des objectifs est LE gros morceau de la mission car elle fait intervenir des déclencheurs, le script "briefing.sqf", le fichier "briefing.html" et les marqueurs de la zone "positions des objectifs pour le briefing"
Contient :
- un élément "logique de jeu"
- le déclencheur (carré, le + haut) initialisant les "objectifs" (variables)
- 4 déclencheurs (ronds, à gauche) servant à valider les objectifs
- 3 déclencheurs (ronds, à droite) servant à basculer vers un autre objectif
La zone "positions des objectifs pour le briefing" contient :
- 4 marqueurs pour positionner les objectifs
a. le script "briefing.sqf"
C'est lui qui défini et permet l'affichage du briefing dans le jeu
script "briefing.sqf"
T1 = player createSimpleTask["nom_obj1"]; T1 setSimpleTaskDescription["Description de l'objectif 1. Les blablabla...", "Titre Objectif 1", "label du marqueur Objectif 1 sur carte"]; T1 setSimpleTaskDestination (getMarkerPos "objectif1"); player setCurrentTask T1;L'objectif décrit ci-dessus est le premier objectif. Il faut indiquer aux joueurs que cet objectif est celui en court, ce qui est fait par la ligne de commande
player setCurrentTask T1;pour créer un nouvel objectif, il faut :
Ce qui donne, pour l'objectif 2, dans la mission "template":
- Changer le "nom_obj1" de la 1ère ligne. Le nom n'a pas d'importance en soi dans notre cas, mais il est mal venu de laisser le même dans autres lignes dupliquées.
- Remplacer les "T1" en bleu par une variable de votre choix (dans le script "briefing.sqf", elles se nomment tout simplement "T2", "T3" et "T4").
- Changer les textes en rouges Description de l'objectif 1. ..." et "Titre Objectif 1", qui se retrouvent dans le briefing (voir flechages sur l'image gauche ci-dessous).
- Changer le texte "label du marqueur Objectif 1 sur carte" en orange, qui apparait sur la carte lorsque que le curseur est sur l'objectif (voir l'image gauche ci-dessous) et/ou en jeu sous la marque du point de passage (voir l'image droite ci-dessous)
- Changer le nom du marqueur de l'objectif "objectif1", qui est le nom du marqueur ci-dessous.
script "briefing.sqf"
T2 = player createSimpleTask["nom_obj2"]; T2 setSimpleTaskDescription["Description de l'objectif 2. Les blablabla...", "Titre Objectif 2", "label du marqueur Objectif 2 sur carte"]; T2 setSimpleTaskDestination (getMarkerPos "objectif2");La seconde partie du fichier "briefing.sqf" permet d'ajouter des entrées (= des notes) supplémentaires grâce à la commande "createDiaryRecord". Le nombre d'entrées n'est pas limité, le choix des 5 entrées ci-dessous est purement arbitraire.
script "briefing.sqf"
... player createDiaryRecord["Diary", ["Soutien","Soutien : à compléter. Les changements de lignes se font automatiquement."]]; player createDiaryRecord["Diary", ["Exécution","Exécution : à compléter. Les changements de lignes se font automatiquement."]]; player createDiaryRecord["Diary", ["Mission","Mission : à compléter. Les changements de lignes se font automatiquement."]]; player createDiaryRecord["Diary", ["Situation","Situation : à compléter. Les changements de lignes se font automatiquement."]]; player createDiaryRecord["Diary", ["Briefing","exemple de Briefing dans le journal..."]]; ...ces entrées sont visibles en jeu à l'affichage de la carte par "l'onglet Notes" (en ordre inverse)
b. les déclencheurs de gestion des différentes objectifs
- Le déclenchement des déclencheurs se fait grâce aux variables (nommées "objectif_T1", "objectif_T2",...) qui, lorsqu'elles basculent à "true" (= vrai), active les commandes du champs "sur activation". Pour rester "propre", il convient tout d'abord d'initialiser toutes les variables servant aux déclenchements des objectifs à "false" (= faux), ce qui est fait grâce au déclencheur carré, activé au début de la mission (cf. la condition "true")
- Lorsque "objectif_T1" passe à "true" (sous l'effet d'un autre déclencheur de votre cru, avec le champ "sur activation" contenant "objectif_T1 = true"), le déclencheur ci-dessous s'active :
Il commute le 1er objectif à l'état "succés" par la commande
T1 setTaskState "SUCCEEDED";La ligne suivante est un appel à un script de BIS pour afficher le texte "Tâche accomplie..." que l'on voit au haut de l'écran, en jeu.
nul = [objNull,objNull,T1, "SUCCEEDED"] execVM "CA\Modules\MP\data\scriptCommands\taskHint.sqf"Dans cette ligne, seuls importent les 2 arguments T1 et "SUCCEEDED", a faire varier selon l'objectif, bien entendu.
- Enfin, le dernier déclencheur, optionnel, permet de faire basculer automatiquement vers l'objectif suivant (en l'occurence l'objectif 2). A noter les délais mini, moyen et max de 1 seconde, qui laisse le temps au premier message "Tâche accomplie..." de s'afficher, puis d'afficher le suivant, "Tâche en cours..."
La 1ère commande rend l'objectif courant.
player setCurrenttask T2;Il change également l'emplacement du curseur/marqueur jaune, significatif de l'objectif en cours, sur l'emplacement de l'objectif 2, défini dans le fichier "briefing.sqf"
l'appel suivant est identique au déclencheur précédent, mis à par que l'état en paramètre est "CURRENT" au lieu de "SUCCEEDED"
nul = [objNull,objNull,T2, "CURRENT"] execVM "CA\Modules\MP\data\scriptCommands\taskHint.sqf";
La gestion des autres objectifs, "T2" et "T3", est strictement équivalente. Seul l'objectif 4 n'a pas de déclencheur-bascule associé, il peut être considéré, par exemple, comme une objectif secondaire.
Sans l'avoir intégrer dans la mission-"template", pour info : il est possible de créer un nouvel objectif via un déclencheur. Il suffit d'insérer dans le champ "sur activation", un code ressemblant à ceci, trés proche du code se trouvant dans "briefing.sqf" :
Il vous faudra également au moins créer un marqueur, nommé "objectif5" dans l'exemple ci-dessusT5 = player createSimpleTask["nom_obj5"]; T5 setSimpleTaskDescription["nouvel objectif secondaire 5", "Titre Objectif 5", "label du marqueur Objectif 5 sur carte"]; T5 setSimpleTaskDestination (getMarkerPos "objectif5"); nul = [objNull,objNull,T5, "CREATED"] execVM "CA\Modules\MP\data\scriptCommands\taskHint.sqf";Je vous laisse le soin de comprendre, sur la base des explications déjà données. Notez cependant l'argument "CREATED" pour le script "taskHint.sqf". On a déjà vu les arguments "SUCCEEDED" et "CURRENT" dans les 2 déclencheurs ci-dessus; il y en a 5 au total pouvant être utiliser comme argument par ce script :
- CREATED
- CURRENT
- SUCCEEDED
- FAILED
- CANCELED
Dernière remarque : j'ai placé des aides dans le fichier "description.ext" afin de vous permettre de mieux comprendre son fonctionnement, ce que l'on peut y mettre et comment le placer, comme par exemple une image dans le briefing (voir <img image='imgs\coltanminesketch.paa'...), cliquer sur un pseudo-lien pour désigner un endroit précis (cf. <marker name='marqueur_obj_1'>ici</marker>), avec l'effet de dézoom-déplacement-zoom que l'on connait bien.
5. GESTION DES DIFFÉRENTES FINS
Les conditions des differentes fins étant extrèmement variées et dépendant du créateur de mission, il est impossible d'intégrer "quelque chose" de standard dans une mission "template" comme celle-ci. Cependant, pour donner une exemple et assuré le lien entre les objectifs et les différentes fins, j'ai laissé quelques déclencheurs "de test" dans la mission (qui seront à effacer dans votre mission finale). Le déclencheur de gauche simule un succés total de la mission. Il met à "true" les variables "objectif_T1", "objectif_T2", "objectif_T3" et "objectif_T4". Le déclencheur du bas simule un succès partiel en mettant à "true" les variables "objectif_T1" et "objectif_T4". Ces deux déclencheurs de test activeront également certains ou tous déclencheurs d'objectif vu au-dessus. Il faut imaginer que ce sont des objectifs géographiquement éloignés et/ou de natures différentes (assassinat réussi, franchissementde zone,...) et donc, chaque variable "objectif_Tx" sera commuté à "true" par des déclencheurs dont les conditions de déclenchement seront trés différentes. Passer par des variables de déclenchement telles "objectif_Tx" facilite la gestion des objectifs et des fins car chaque variable fait double emploi et interagit sur les objectifs en même temps que les fins.
- Le déclencheur du haut est celui qui test l'echec de la mission. Il s'active lorsque le joueur pénètre dans la zone (= activation "BLUFOR" et donc le "this") et qu'aucune des variables "objectif_T[1 à 3]" n'est passé à "true" (couplage des tous les "(not objectif_T[1 à 3])" par "and"). Pour le tester en prévisualisation, il suffit de courir vers le nord de la piste de l'aérodrome dès l'entrée dans la mission. A noter l'activation "BLUFOR" pour déclenchement uniquement en présence des joueurs,
- Le déclencheur du milieu teste la réussite partielle de la mission. Il s'active lorsque le joueur pénètre dans la zone et qu'une ou plusieurs des variables "objectif_T1 à 3" est passé à "true", mais pas toutes. La variable "objectif_T4" n'est pas testée car elle est liée à un objectif considéré comme secondaire. Comme précédemment, le "this" permet de tester l'entrée des joueurs dans la zone; (objectif_T1 or objectif_T2 or objectif_T3) donne "true" si au moins une variable est "true"; le liaison entre les 2 évènement est faite par le and". Pour le tester en prévisualisation, il faut courir vers le sud de la piste dans un premier temps, jusqu'a ce qu'un message "simulation de succés mitigé..." apparaisse, puis courir au nord de la piste.
- Le déclencheur du haut est celui qui test l'echec de la mission. Il s'active lorsque le joueur pénètre dans la zone et qu'aucune des variables "objectif_Tx" n'est passé à "true". Pour le tester en prévisualisation, il suffit de courir vers le but de la piste de l'aérodrome dès l'entrée dans la mission
Lorsque vous passez dans l'un de ces 3 déclencheurs, vous obtenez le dialogue de fin habituel, avec les commentaires de succés, de réussite mitigée ou d'échec.
Ces commentaires sont définis dans le fichier "briefing.html". Il n'est pas difficile de faire le rapport entre ce qui est inscrit dans le fichier et le contenu des dialogues ci-dessus, je ne n'étend donc pas trop sur ce sujet. Notez seulement le rapport qu'il y a entre la balise "<a name="Debriefing:End1">" et le déclencheur de type "Fin n°1" (= succès total de la mission), la balise "<a name="Debriefing:End2">" et le déclencheur de type "Fin n°2" (= réussite mitigée), et enfin, entre la balise "<a name="Debriefing:Loser">" et le déclencheur de type "perdre"
fichier "briefing.html"
<html> <head> <title>titre de la mission</title> </head> <body> <br> <h2><a name="Debriefing:End1">réussite totale</a></h2> <br> <p>Vous avez réussi la mission !</p> <br> <hr> <br> <h2><a name="Debriefing:End2">réussite mitigée</a></h2> <br> <p>Votre réussite est mitigée !</p> <br> <hr> <br> <h2><a name="Debriefing:Loser">Echec de la mission</a></h2> <br> <p>Vous avez échouez !</p> <br> </body> </html> </div>
6. LE FICHIER "INIT.SQF"
Ce fichier est systematiquement lancé sur chaque machine au départ de la mission. En conséquence, tous les scripts et commandes devant être lancé au moins une fois peuvent l'être à partir de ce fichier.
fichier "init.sqf"
// INIT.SQF TEMPLATE © Pumpkin V2.06 // --------------------------- // -------------------------------------------------------------------------------------------------- // METTRE LES DOUBLES BARRE (//) DEVANT UNE LIGNE DE COMMANDE POUR LA DESACTIVER, NE PAS L'EFFACER !! // Pour test Client _testclient = call compile preprocessFile "lib\Client_detection.sqf"; // Pour test Serveur _testserver = call compile preprocessFile "lib\Server_detection.sqf"; // Messages d'erreur if (format["%1",_testclient]=="") then { sleep 1; hint "ERREUR INIT.SQF: script 'lib\Client_detection.sqf' absent"; sleep 2; }; if (format["%1",_testserver]==" ") then { sleep 1; hint "ERREUR INIT.SQF: script 'lib\Server_detection.sqf' absent"; sleep 2; }; // ------------------------------------------------------------------------------------------------ // PLACER ICI LES SCRIPTS DEVANT S'EXECUTER SUR LE SERVEUR ET SUR LE CLIENT (=la machine du joueur)
// ------------------------------------------------------------------------------------------------ // PLACER ICI LES SCRIPTS NE DEVANT S'EXECUTER QUE SUR LE SERVEUR // ( À L'INTÉRIEUR DES {...}; !!) if (_testserver) then { // Init permettant de diffuser en MP le texte des chats, = objet nommé "PUMPKINBroadcaster" nul = execVM "lib\Init_Speach_Broadcast.sqf"; // Script de destruction de cadavres enemis //nul = [east] execVM "lib\Clean_bodies.sqf"; // Init pour fonctions de debuggage "maison" en menu // seulement si serveur non dédié if (not isDedicated) then { nul = execVM "debug\initdebug.sqf"; }; }; // ------------------------------------------------------------------------------------------------ // PLACER ICI LES SCRIPTS NE DEVANT S'EXECUTER QUE SUR LE CLIENT (=la machine du joueur) // ( À L'INTÉRIEUR DES {...}; !!) if (_testclient) then { // =================================== // TOUTES LA DOCUMENTATION DU BRIEFING // Met en place le briefing nul = execVM "briefing.sqf"; // Documentation(s) accessible(s) en jeu nul = execVM "medkit\medkit_doc.sqf"; nul = execVM "lib\docs\Repair_veh_doc.sqf"; // =================================== // Temporisation de sécurité pour mission MP : pour connexion rapide (LAN), il vaut mieux vérifier de // l'existence du joueur, et temporiser, sans quoi les scripts destinés au joueur se lance "dans le vide" waituntil{player iskindof "man"}; sleep 0.3; waituntil{alive player}; sleep 0.3; // Acces "Admin" en MP [] spawn { while {true} do { waituntil { serverCommandAvailable "#shutdown" }; nul = execVM "debug\initdebug.sqf"; waituntil { not (serverCommandAvailable "#shutdown") }; nul = execVM "debug\closedebug.sqf"; }; }; // Affichage de la version (pas utile pour un sou, juste pour mon comfort personnel afin de savoir où j'en suis ;D ) [] spawn { cuttext ["init V2.06", "PLAIN DOWN"]; sleep 1; cuttext ["", "PLAIN"]; }; // Mise en place du scruteur d'évènement "mort du joueur"; lancera automatiquement la // récupération des armes (et du contenu du sac à dos pour OA) dès la mort du joueur player addEventHandler ["killed",{execVM "respawn_handler.sqf"}]; // Autoriser (ou non) le système de scrutation du contenu du sac à dos (ajout des menus "Arme", ...). "Event_Inventory.sqf" // est lancé ici, dans le fichier "init.sqf" et dans le "respawn_handler.sqf". Il faut activer/désactiver les 2 lancements. nul = execVM "plr_respawn\Event_Inventory.sqf"; // Init Systeme de soins scripté perso medkitnum = 103; // modification du nombre de medkit disponible par mission nul = execVM "medkit\medkit.sqf"; // Activation du menu de récupération des medkits nul = player execVM "medkit\recover_medkits_menu.sqf"; // Init script de reparation de vehicule //nul = [2,["Car","Motorcycle","Air"]] execVM "lib\repair_veh.sqf"; //nul = [2,["Car","Motorcycle","Plane"]] execVM "lib\repair_veh.sqf"; //nul = [0.7] execVM "lib\repair_veh.sqf"; nul = [] execVM "lib\repair_veh.sqf"; };
- En jeu multi-joueurs, certains scripts doivent être lancé uniquement par le serveur, et d'autres uniquement par la machine-client (autrement dit la machine du joueur). Toute la partie ci-dessous ne sert qu'à mettre en place un système de test pour savoir sur quelle machine le script "init.sqf" a été lancé et exécuter les scripts dédiés serveur et dédiés clients, comme les commentaires l'indiquent. NE PAS Y TOUCHER, et ne pas oublier d'installer le répertoire "lib\" et ses scripts, s'il n'existe pas.
// Pour test Client _testclient = call compile preprocessFile "lib\Client_detection.sqf"; // Pour test Serveur _testserver = call compile preprocessFile "lib\Server_detection.sqf"; // Messages d'erreur if (format["%1",_testclient]=="") then { sleep 1; hint "ERREUR INIT.SQF: script 'lib\Client_detection.sqf' absent"; sleep 2; }; if (format["%1",_testserver]=="") then { sleep 1; hint "ERREUR INIT.SQF: script 'lib\Server_detection.sqf' absent"; sleep 2; };Pour une mission solo, tout ceci n'aucune importance, mais pour une mission multi-joueur, il est impératif de faire le distinguo. Le fichier comporte donc 3 parties :
- La partie comportant les scripts communs au serveur/client OU pour mission solo. En l'occurence, il n'y a aucun script destiné à fonctionner à la fois sur le serveur et sur les clients.
// ------------------------------------------------------------------------------------------------ // PLACER ICI LES SCRIPTS DEVANT S'EXECUTER SUR LE SERVEUR ET SUR LE CLIENT (=la machine du joueur) ...
- La partie comportant les scripts du serveur uniquement
// ------------------------------------------------------------------------------------------------ // PLACER ICI LES SCRIPTS NE DEVANT S'EXECUTER QUE SUR LE SERVEUR if (_testserver) then { ... };Dans cette partie, on va trouver :
- Le lancement du script d'initialisation de mon propre système d'affichage de message en multi-joueurs, activé par défaut. J'utilise de plus en plus ce système de diffusion à tous les joueurs, de message de différents types (script de tir de barrage,...). S'il n'est pas utilisé, il ne ralentira rien, donc le désactiver ne fera rien gagner niveau performance, mais oublier de l'activer peut rendre "muettes" quelques uns de mes scripts. Donc, cher utilisateur du "template" et de mes scripts, laissez donc cette ligne active ;)
nul = execVM "lib\Init_Speach_Broadcast.sqf";
- Le lancement d'un script destiné à éliminer les "cadavres" des IA, sur les missions lourdes en IA, afin d'éviter un lag. Il est désactivé, car encore peu testé en condition réelle (si le coeur vous dit...), mais j'ai laissé l'appel à titre d'exemple
// Script de destruction de cadavres enemis
//nul = [east] execVM "lib\Clean_bodies.sqf";
- Enfin, une petite astuce me permettant de ne pas avoir à activer/désactiver tout le temps mes outils de debug : Placer sous la section "lancement par le serveur", un test afin de savoir si c'est la machine-serveur n'est pas un serveur dédié et, dans ce cas, lancer mes outils de débugage. Ainsi, sous éditeur ou en serveur LAN, mes deux "environnements" de test, j'ai accès aux outils, alors qu'ils ne seront pas accessible en serveur dédié.
// Init pour fonctions de debuggage "maison" en menu // seulement si serveur non dédié if (not isDedicated) then { nul = execVM "debug\initdebug.sqf"; };- La partie comportant les scripts du client uniquement. D'une façon générale, tout script faisant référence au "player", ou mettant en place une entrée dans le menu du "player" doit être placé ici, car l'entité "player" n'existe pas pour un serveur dédié.
// ------------------------------------------------------------------------------------------------ // PLACER ICI LES SCRIPTS NE DEVANT S'EXECUTER QUE SUR LE CLIENT (=la machine du joueur) if (_testserver) then { ... };
- Le reste des explication ne concernent que les commandes et scripts exécutés sur les machines-clientes. Première chose à faire : lancer les scripts de documentation qui apparaitrons sur l'écran d'information. En premier lieu, le script qui doit être impérativement lancé est le "briefing.sqf"", vu dans le paragraphe sur le briefing. On va préférer le placer sur les machines clients, car, s'il peut être lancer également sur le serveur, personne ne le lira ;) . En cas de
nul = execVM "briefing.sqf";- Ensuite, éventuellement, on peut lancer des scripts mettant en place des notes, journaux, et autres documentations consultable en jeu. Par exemple, ici, je lance la documentation explicant l'utilisation de mon système de trousse de secours, les medkits, ainsi que la façon de réparer un véhicule avec mon système de réparation "simpliste". Comme d'habitude, mettre // devant les lignes pour les inactiver (ou les effacer si votre décision de ne pas les utiliser est définitives... on est dans un pays libre après tout ;) )
// Documentation(s) accessible(s) en jeu nul = execVM "medkit\medkit_doc.sqf"; nul = execVM "lib\docs\Repair_veh_doc.sqf";- Les lignes suivantes sont une sécurité, assurant le lancement correct des commandes suivantes, qui nécessite impérativement "l'existence" de l'avatar du joueur. Elles n'aurait pas été vraiment nécessaires si je n'avais pas expérimenté des bugs de "non lancement" sur des parties "mixtes, en LAN et en WAN : l'initialisation pour les joueurs en WAN est "ralentie" du fait de leur connexion distante; par contre, en LAN, l'initialisation risque de se produire trop vite, empêchant notamment le respawn de fonctionner. Donc quelques petites lignes pour assurer le coup et attendre gentiment que le joueur humain sont "physiquement" présent :
// Temporisation de sécurité pour mission MP : pour connexion rapide (LAN), il vaut mieux vérifier de // l'existence du joueur, et temporiser, sans quoi les scripts destinés au joueur se lance "dans le vide" waituntil{player iskindof "man"}; sleep 0.3; waituntil{alive player}; sleep 0.3;
- Ici, je lance en parallèle un petit bout de script qui permet l'accès à mes outils de debugage en jeu et en serveur dédié. Il suffit pour cela de se connecter en tant qu'admin sur le serveur dédié. Pour désactiver l'accès à mes outils, les sempiternels // devant les "nul =". Libre à vous de lancer d'autres scripts, mais ATTENTION, prévoyez de les stopper en cas de logout (= déconnection admin), sinon ils seront relancer à chaque fois que vous vous connecterez en admin !
// Acces "Admin" en MP [] spawn { while {true} do { waituntil { serverCommandAvailable "#shutdown" }; nul = execVM "debug\initdebug.sqf"; waituntil { not (serverCommandAvailable "#shutdown") }; nul = execVM "debug\closedebug.sqf"; }; };- Ces lignes sont quasiment inutiles ! Elles sont juste là pour afficher la version du fichier "init.sqf", pour mon confort personnel ;) Vous pouvez les supprimer si elles vous gênent.
[] spawn { cuttext ["init V2.06", "PLAIN DOWN"]; sleep 1; cuttext ["", "PLAIN"]; };
- La commande suivante est aussi importante que le lancement du "briefing.sqf" : Il met en place l'exécution d'un script qui s'exécutera à chaque mort du joueur. Dans cette mission-template, le script "respawn_handler.sqf" lance -TOUS- les scripts qui doivent être lancé après la mort du joueur (on verra le script en détail plus bas). Autre remarque trés importante : il ne doit y avoir qu'une ligne du type ...addEventHandler ["killed",{..., sinon il risque d'y avoir conflit et les scripts lancés par "respawn_handler.sqf" ne se lanceront peut-être pas. Dans la théorie, BIS indique qu'on peut ajouté des "gestionnaires d'évènement" pour un même évènement ("killed" en l'occurrence). Dans les faits, j'ai constaté quelques couacs qui me font préférer la méthode "1 seul eventhandler", qui lance un seul script qui, lui, va lancer tous les scripts "d'après mort".
player addEventHandler ["killed",{_this execVM "respawn_handler.sqf"}];
- Ce ligne lance le script de système de gestion des kits de premiers soins. Il se trouve, ainsi que ses scripts associés, dans le répertoire "medkit\". Il permet au joueur de se soigner sans avoir recours à un infirmier. Par défaut le nombre de kit de 1er secours est de 5, mais la valeur medkitnum = 3 (désactivée) permet de modifier le nombre de kits. Le chiffre de 5 a été choisi car, si le système de blessure alternative est actif (voir les modules), cela permet, après une blessure grave, de recouvrir totalement sa santé si on utilise tous les kits. Associé au système de 1ers secours et de blessures alternatif, il permet notamment à un petit groupe de joueur, ou à un sniper, isolé par définition, de ne pas être trop "embêter" par des blessures successives.
medkitnum = 10; // modification du nombre de medkit disponible par mission nul = execVM "medkit\medkit.sqf";
- Partenaire du système de gestion des kits de premiers soins, le script permettant de récuperer la totalité du nombre de medkits en s'approchant d'un joueur-médecin
// Activation du menu de récupération des medkits nul = player execVM "medkit\recover_medkits_menu.sqf";
- Suit le lancement d'un système d'alternance d'arme par menu. Ceux qui connaissent la célèbre mission "Domination" connaissent le "sac à dos virtuel scripté" de Xeno. C'est à peu près l'équivalent : si le joueur met une arme dans le sac à dos, un menu apparait, permettant d'alterner l'arme du sac à dos et celle du joueur; particulièrement intéressant pour utiliser un mitrailleuse lourde qui interdit normalement l'utilisation du sac à dos, idem pour les lances-roquettes. Ceci est le lancement initial. Le script s'arrête à la mort du joueur, mais comme cette ligne de lancement est présente dans le "respawn_handle.sqf", le script est relancé à chaque résurrection.
// Autoriser (ou non) le système de scrutation du contenu du sac à dos (ajout des menus "Arme", ...). "Event_Inventory.sqf" // est lancé ici, dans le fichier "init.sqf" et dans le "respawn_handler.sqf". Il faut activer/désactiver les 2 lancements. nul = execVM "plr_respawn\Event_Inventory.sqf";
- Le dernier script lancé permet à un joueur de réparer les véhicules (cf. la section de ma page sur ce script). J'ai laissé différents exemples de lancement en commentaire, pour faciliter les/vos tests.
// Init script de reparation de vehicule //nul = [2,["Car","Motorcycle","Air"]] execVM "lib\repair_veh.sqf"; //nul = [2,["Car","Motorcycle","Plane"]] execVM "lib\repair_veh.sqf"; //nul = [0.7] execVM "lib\repair_veh.sqf"; nul = [] execVM "lib\repair_veh.sqf";
7. LE FICHIER "RESPAWN_HANDLER.SQF"
Comme indiqué ci-dessus, le script "respawn_handler.sqf" se lancera à chaque mort du joueur, une fois mis en place par la commande player addEventHandler ["killed",{_this execVM "respawn_handler.sqf"}]; dans le fichier init.sqf. Il faut distinguer deux phases : juste après la mort du joueur mais avant sa résurrection, et aprés sa résurrection. Certains script ne fonctionneront pas selon la phase à laquelle ils sont lancés.
fichier "respawn_handler.sqf"
// ---------- METTRE CI-DESSOUS LES SCRIPTS DEVANT S'EXECUTER AVANT LA REAPPARITION DU JOUEUR ---------- // recup. des armes dans la configuration juste avant la mort - A GARDER EN 1ERE POSITION IMPERATIVEMENT ! _isOperationArrowhead = "TK_CIV_Takistani_Base_EP1" isKindOf "civilian"; //test simple pour distinguer ArmA2 "normale" (jusqu'à V1.07) de Operation Arrowhead // choix du script à lancer en fonction de la version (compatible sac à dos ou non compatible) if ( _isOperationArrowhead ) then { nul = [ [50,50,300] ] execVM "plr_respawn\Respawn_player.sqf"; } else { nul = execVM "plr_respawn\Respawn_player_A2.sqf"; }; // sécurité avant la poursuite des opérations sur le "nouveau" joueur : attendre que le joueur soit en vie waituntil{alive player}; sleep 0.5; // ---------- METTRE CI-DESSOUS LES SCRIPTS DEVANT S'EXECUTER APRES LA REAPPARITION DU JOUEUR ---------- if ( _isOperationArrowhead ) then { // ajout de la gestion du sac à dos (pour OA uniquement). nul = execVM "plr_respawn\Event_Inventory.sqf"; }; // // Activation du menu de récupération des medkits nul = player execVM "medkit\recover_medkits_menu.sqf";
- Une petite astuce pour tester quel jeu est lancé...
_isOperationArrowhead = "TK_CIV_Takistani_Base_EP1" isKindOf "civilian";... pour pouvoir lancé le bon script de récupération des armes tel qu'avant la mort, le premier étant compatible OA+sac à dos ("plr_respawn\Recover_weapons.sqf"), le deuxième uniquement compatible Arma2 simple ("plr_respawn\Recover_weapons_A2.sqf", pour ceux qui n'aurait pas acheté l'extension...s'ils existent :) ). "Recover_weapons.sqf" rétabli non seulement les armes et munitions à l'identique, mais également le sac à dos et son contenu précédent (100 x merci à Madbull des R3F d'avoir trouvé le "St-Graal", autrement dit les 2 commandes qui permettent de scruter le contenu du sac à dos !). Le paramètre donné au script est un tableau permettant en pleine "mélasse", en cas de décès au beau milieu d'une foule d'ennemis furieux par exemple, d'être transporté dans une zone sûre, si cela est possible en fonction des paramètres donnés. En l'occurence, le script cherchera des ennemis dans un rayon de 30m, s'il en trouve, il élargira le cercle de recherche de 50m, et ainsi de suite, jusqu'à une distance maximale de 300m.if ( _isOperationArrowhead ) then { nul = [ [30,50,300] ] execVM "plr_respawn\Respawn_player.sqf"; } else { nul = execVM "plr_respawn\Respawn_player_A2.sqf"; };
- Suit l'attente de la résurrection, afin de lancer les autres scripts, qui doivent s'exécuter lorsque le joueur est vivant et réapparu.
waituntil{alive player};
sleep 0.5;
- Est tester ici quel type de jeu est lancé; si c'est OA, lancer la commande de gestion des menus/armes APRÈS la restoration des armes et du sac à dos.
if ( _isOperationArrowhead ) then { // ajout de la gestion du sac à dos (pour OA uniquement). nul = execVM "plr_respawn\Event_Inventory.sqf"; };
- Enfin, et si cette option n'a pas été désactivée dans le fichier "init.sqf", il faut rétablir le menu de recouvrement des medkits
// Activation du menu de récupération des medkits nul = player execVM "medkit\recover_medkits_menu.sqf";
Pour donner un exemple supplémentaire de l'adaptation du script "étranger" à cette mission-template, je prendrais l'exemple de mon script de ravitaillement. Le fichier "init.sqf" de la mission d'exemple du ravitaillement est celui-ci :
La 1ère ligne lance le script "AirSupply\initsupplymenu.sqf" qui installe les entrées liées au ravitaillement dans le menu du joueur. Comme il ne peut y avoir qu'un seul fichier "init.sqf", on prendra donc cette ligne pour la copier dans l'"init.sqf de la mission-template, ce qui donnera :nul = execVM "AirSupply\initsupplymenu.sqf"; player addeventhandler ["Killed", {execVM "AirSupply\initsupplymenu.sqf"}];fichier "init.sqf"
... // ------------------------------------------------------------------------------------------------ // PLACER ICI LES SCRIPTS NE DEVANT S'EXECUTER QUE SUR LE CLIENT (=la machine du joueur) if (_testclient) then { nul = execVM "AirSupply\initsupplymenu.sqf"; // Mise en place du scruteur d'évènement "mort du joueur" player addEventHandler ["killed",{_this execVM "respawn_handler.sqf"}]; ...La 2ème ligne met en place le "scruteur d'évènement" pour que, après la mort du joueur, le menu se ré-installe automatiquement. Mais, comme je l'ai dis plus haut, deux lignes de type "player addeventhandler ["Killed", {..." sont INTERDITES SIMULTANÉMENT. On placera donc la ré-installation du menu dans le fichier DÉJÀ appelé par le "scruteur d'évènement", autrement dit le fichier "respawn_handler.sqf". Comme c'est une entrée de menu à ré-installer, on attendra la résurrection du joueur (logique ! on ne va pas la ré-installer sur le mort ! ;) ). On placera donc l'appel au script dans la seconde partie de "respawn_handler.sqf".
fichier "respawn_handler.sqf"
... // ---------- METTRE CI-DESSOUS LES SCRIPTS DEVANT S'EXECUTER APRES LA REAPPARITION DU JOUEUR ---------- ... // ajout du menu "Check sac à dos" (pour OA uniquement) if ( _isOperationArrowhead ) then { if (Pumpkin_CheckBackpack) then { menu_checkbackpack = player addAction ["Check sac à dos", "lib\Recover_weapons.sqf", true, 0, false, true, "", "true"]; }; }; nul = execVM "AirSupply\initsupplymenu.sqf"; ...Moralité de l'exemple : Le copier-coller sauvage est une trés mauvaise idée lorsqu'on cherche à coupler les scripts récupérés ça et là !! :)
Petit ajout qui peut intéressé quelques joueur de team : j'ai voulu greffé tout mon système de script sur une mission Domination, pour voir s'il y avait imcompatibilité. Il s'avère que non, et l'intégration est très simple : renommer le fichier "init.sqf" d'origine et le lancer à la fin de mon propre fichier "init.sqf"
nul = execVM "init_dom.sqf";
8. LE FICHIER STRINGTABLE.CSV
Ce fichier permet la traduction automatique de texte, selon le pays du joueur. Sans s'étendre trop sur le sujet, j'ai mis ce fichier en place pour ceux qui en connaisse l'utilisation (ou ceux qui l'appendront :) ), et pour pouvoir au moins titrer la mission "internationalement". La 1ère ligne indique l'ordre des langues, la 2ème traduit le texte référencé par "STR_TTITRE_MISSION" dans les 8 langues. Je n'ai mis en place que l'anglais et le français. Cette traduction apparaitra sur l'écran de chargement (que l'on verra juste en dessous, dans le paragraphe "LE FICHIER DESCRIPTION.EXT") et lors de la petite intro.
LANGUAGE,"English","Czech","German","Polish","Russian","French","Spanish","Italian" STR_TTITRE_MISSION, "Loadscreen Title of the Mission ", "!", "!", "!", "!", "Titre de la Mission de l'écran de chargement", "!", "!"
9. LE FICHIER DESCRIPTION.EXT
loadScreen = "imgs\loading.jpg"; OnLoadMission = $STR_PKN_TITRE_CHARGMT; respawn="INSTANT"; //respawn="BASE"; // nécessite un marqueur 'respawn_west' et/ou 'respawn_vehicle_west' RespawnDelay = 10; // compte à rebour RespawnDialog = true; // montre le dialogue // définition des classes graphiques (textes,images,...) class TitreIntro { type = 0; idc = -1; x = 0.1; y = 0.4; w = 0.8; h = 0.4; colorText[ ] = {1, 0, 0, 1}; colorBackground[ ] = {0, 0, 0, 0}; style = 2+16+512; font = "TahomaB"; //font = "LucidaConsoleB"; //font = "Zeppelin32"; //font = "EtelkaMonospaceProBold" text = ""; lineSpacing = 1; sizeEx = 0.10; }; class LogoPicture { access = 0; type = 0; idc = -1; style = 48; colorBackground[ ] = {0, 0, 0, 0}; colorText[ ] = {1, 1, 1, 1}; font = "TahomaB"; sizeEx = 0; lineSpacing = 0; text = ""; }; class RscTitles { class TitreMission { idd = -1; movingEnable = 0; duration = 8; name = "TitreMission"; class controls { class titretxt : TitreIntro { text = $STR_PKN_TITRE_MISSION; }; }; }; class LogoMission { idd = -1; movingEnable = 0; duration = 8; name = "LogoMission"; class controls { class logoimg : LogoPicture { type = 0; idc = -1; x = 0.2; y = 0; w = 0.55; h = 0.7; text="imgs\logo_mission2.paa"; }; }; }; };Ce fichier défini une telle foule de chose, que je ne vais pas tout expliquer, loin de là. Si vous êtes intéressé, voir la doc affiliée sur le wiki de BIS. Je vais me limité à ce que j'ai placé, et encore !
- la 1ère ligne va définir l'image de l'écran de chargement. Pas la peine d'utiliser le format .PAA de BIS, les images Jpeg sont reconnues.
loadScreen = "imgs\loading.jpg";- la 2ème défini le titre de la mission, affichée sur l'écran de chargement. On retrouve la référence "$STR_PKN_TITRE_CHARGMT du fichier "description.ext". Donc inutile de modifier cette ligne pour changer le titre.
OnLoadMission = $STR_PKN_TITRE_CHARGMT;Je passe sur les définitions du respawn, déjà abordé. Ce qui suit, les "définition des classes graphiques" servent à définir les objets graphiques de l'intro, soit une image (le logo de l'intro) et un texte (le titre de la mission, reprit du fichier "description.ext"). Ces définitions sont trés lourdes (Et oui ! Tout ça juste pour pouvoir afficher un texte et une image !!), donc trés longues à expliquer. Je vais m'en tenir à l'essentiel, pour permettre une petite modification.
- Les lignes type :
x = 0.1;définissent une position sur écran, en % d'écran, 1 = 100%. L'exemple indique une position à 10% du bord gauche et 40% du bord haut de l'écran
y = 0.4;
- Les lignes type :
w = 0.8;définissent la dimension de l'objet graphique (texte, image,...), toujours en % d'écran. Dans l'exemple, l'objet à une largeur de 80% d'écran et une hauteur de 40% d'écran.
h = 0.4;
- Les couleurs sont définies par les 4 valeurs entre parenthèses. Par exemple, pour la couleur du texte :
colorText[ ] = {1, 0, 0, 1};Elles sont indiqué en %, 1 = 100%, le 1er chiffre pour la composante Rouge, le 2ème pour la Verte, la 3ème pour la Bleue. Le dernier chiffre représente la transparence de l'objet; 1 équivaut à 100% d'opacité. Dans l'exemple, le texte sera rouge vif.
- Arma 2 n'utilise que quelques polices de caractère. Je l'ai ai toutes notés, j'ai choisi "TahomaB" pour le titre et j'en ai désactivé les 3 autres:
font = "TahomaB";
//font = "LucidaConsoleB";
//font = "Zeppelin32";
//font = "EtelkaMonospaceProBold"
- Ceci est la référence au titre de la mission qui se trouve dans le fichier "description.ext". On peut remplacer cette référence par une chaine de caractère classique; mettre le titre dans le fichier "description.ext" permet juste une éventuelle internationalisation:
class TitreMission { ... text = $STR_PKN_TITRE_MISSION; ... };
- Dernières choses, le nom du fichier du logo affiché à l'intro :
Cette fois, c'est un fichier .PAA qui est utilisé, pour pouvoir avoir une transparence de l'image. Les fichiers Jpegs conviennent, mais dans ce cas, pas de transparence.class LogoMission { ... text="imgs\logo_mission2.paa"; ... };Petites remarques qui ont leur importance :
Donc méfiance lorsqu'on touche à ce fichier, ne le faites qu'après être sûr d'avoir une version saine de la mission sauvegardée quelque part.
- Toute modification dans le fichier "description.ext" n'est visible que l'on recharge la mission.
- Une erreur, même minime, dans ce fichier provoque le crash d'Arma 2, lorsqu'on essaye de charger la mission ou si l'on essaye de sauver une mission avec une erreur dans le fichier "description.ext"
10. LA ZONE "INTRO"
Contient :
- le déclencheur servant au déclenchement de l'intro en début de partie
Tout ce qui a de plus simple : le déclencheur, avec condition "true", pour être lancé systématiquement en début de partie, exécute le script "intro.sqf"
fichier "intro.sqf"
sleep 2; TitleRsc ["TitreMission","plain",1]; sleep 2; cutRsc ["LogoMission","plain",1];Simple aussi : attendre 2 secondes, afficher le titre par la commande "TitleRsc", attendre encore 2 secondes, afficher le logo par la commande "cutRsc". "TitreMission" et "LogoMission" sont les noms des deux ressources affichées et que l'on retrouve dans le fichier "description.ext". L'utilisation de "TitleRsc", puis de "cutRsc" permet la superposition du titre et de l'image; si on utilisé deux fois la même commande, l'image "chasserai", ferai disparaitre le titre.
11. LA ZONE "GENERATION DE BATIMENTS SUR POSITION MARQUEUR"
Contient :
- un marqueur servant au positionnement du batiment généré
- le déclencheur qui lance le script de génération de bâtiment
La possibilité de générer des groupements d'objets complexes sans avoir a placer tous les éléments les composants un par un dans l'éditeur est forcément intéressante, le procédé étant trés facile à mettre en oeuvre, moyennant un déclencheur et un marqueur.
Dans le champ "sur activation", on a une seule, mais trés longue ligne, qui va générer une composion d'objects (bâtiments, véhicules,...) à l'endroit du marqueur.
call { bati = [ [(getMarkerPos "position_nouveau_camp" select 0), (getMarkerPos "position_nouveau_camp" select 1), 0], 45, "Camp1_TK_EP1"] call (compile (preprocessFileLineNumbers "ca\modules\dyno\data\scripts\objectMapper.sqf")); }On voit que les commandes sont entourés de parenthéses, précédé par "call". L'utilité de procéder ainsi, en exécutant les commandes entre "call{ }, permet plus facilement le copier-coller (pour ceux qui aiment le charabia : les variables entre { } sont locales au "call", la variable "bati", par exemple, n'a pas besoin d'être renommé.)
call { ... }La ligne de commande ci-dessous est l'appel au script de BIS générant les compositions d'object et est, bien sûr, inaltérable.
bati = [ ... ] call (compile (preprocessFileLineNumbers "ca\modules\dyno\data\scripts\objectMapper.sqf"));Beaucoup plus intéressant pour le créateur de mission, les valeurs entre "[ ]" sont les arguments à passer au script
[(getMarkerPos "position_nouveau_camp" select 0), (getMarkerPos "position_nouveau_camp" select 1), 0], 45, "Camp1_TK_EP1"Pour pouvoir générer un autre batiment, il faut
- (getMarkerPos "position_nouveau_camp" select 0) est la coordonnée X de l'emplacement de la composition
- (getMarkerPos "position_nouveau_camp" select 1) est la coordonnée Y de l'emplacement de la composition
- 45 est l'angle de rotaton de la composition : elle sera pivotée de 45 degré
- "Camp1_TK_EP1" est le nom de la composition. Pour obtenir le nom des compositions, voir la page des compositions de Armatech / Armaholic. J'ai également une page répertoriant les noms des compositions >>ICI<< (mais pas forcément compléte et /ou parfaitement juste)
- copier le déclencheur
- créer un marqueur
- remplacer le nom "position_nouveau_camp" du marqueur par celui nouvellement créé
- modifier, si besoin est, l'angle de rotation dans les paramètres
- choisir, le cas échéant, une nouvelle composition
NOTE POUR ARMA 2 SANS OA : Malheureusement, je ne sais pas si le script "objectMapper.sqf" existe encore sous Arma 2 version 1.07 sans OA. Aprés patch de OA, je me retrouve avec une version du script qui ne fonctionne plus sous Arma 2 version 1.07 sans OA. Pour palier à cet inconvénient, j'ai intégré une vieille version du script, que j'ai renommé "objectMapper_A2.sqf", qui, elle, fonctionne trés bien. Le code à intégré dans le déclencheur est :
call { bati = [ [(getMarkerPos "position_nouveau_camp" select 0), (getMarkerPos "position_nouveau_camp" select 1), 0], 45, "bunkerMedium04"] execVM "objectMapper_A2.sqf"; }Et pensez aussi à n'utiliser que les compositions d'Arma 2 sans OA (des compositions comme "Camp1_TK_EP1" n'existe pas ! ;) )
12. ZONE "SCRIPT DE PATROUILLE ALÉATOIRE SUR UNE PATROUILLE"
Contient :
Le déclenchement se fait par le champ "initialisation" du chef de groupe. "this" ou le nom du chef de groupe comme 1er paramètre, le nom du déclencheur comme 2ème paramètre. Pour plus de détails, voir l'entête du script ou ma page d'explication sur le script- un groupe d'unité
- le déclencheur définissant la zone de patrouille
nul = [patchief,nango_pat] execVM "patrols.sqf"Le 1er paramètre, "patchief", est le nom du chef de groupe et aurait pu être remplacé par "this", car le script est greffé sur un homme du groupe. Mais cela montre que le script peut aussi se lancer par un déclencheur, avec comme 1er paramètre le nom de l'unité.Il est possible que le script de patrouille aléatoire évolue (nouvelles fonctionnalités, débuggage,...). Un petit coup d'oeil à la page dédiée au script n'est pas inutile ;)
13. ZONE "GENERATION DE PATROUILLE SUR UNE POSITION DE LOGIQUE DE JEU"
(Attention ! spécifique OA !)
Contient :
- un élément "logique de jeu"
- le déclencheur générant la patrouille
Remarques préalables importantes !
- La génération de groupe par script (voir le champ "sur act." du déclencheur) ne peut fonctionner que si un "HQ I.A" existe sur la carte. La méthode la plus simple pour le créer est de placer au moins une unité de la FACTION ennemie n'importe où sur la carte sur la carte (Pour les experts, voir la commande "createCenter")
- Il semble que, depuis le patch 1.55, les fonctions de BIS (BIS_fnc_spawnGroup, BIS_fnc_taskDefend,...) ne soient plus accessibles sans implanter le module "Fonctions" dans la mission. Et afin d'être pleinement compatible, il est préférable d'ajouter au champ "condition" : "... and (not isnil BIS_fnc_init)", afin de tester la fin de l'initialisation des fonctions de BIS.
Le but est de généré un groupe ennemi et de le faire patrouiller lorsque les joueurs entrent dans la zone du déclencheur, afin d'éviter de surcharger le jeu/ le serveur avec des unités inutiles (astuce mise en place dans la mission "Outgunned" de Dale). le "logique de jeu" nommé "position_pat_gen_01" sert à positionner la patrouille et la zone de patrouille. La génération du groupe et sa fonction de patrouille sont dû au "mini-script" dans le champ "sur activation" du déclencheur :
call { grp = [(getPos position_pat_gen_01), EAST, (configFile >> "CfgGroups" >> "East" >> "BIS_TK_INS" >> "Infantry" >> "TK_INS_Patrol")] call BIS_fnc_spawnGroup; [grp, (getPos position_pat_gen_01), 150] call bis_fnc_taskPatrol; }Execute le(s) commande(s) entre { }
call { ... }
grp = [(getPos position_pat_gen_01), EAST, (configFile >> "CfgGroups" >> "East" >> "BIS_TK_INS" >> "Infantry" >> "TK_INS_Patrol")] call BIS_fnc_spawnGroup;Le groupe généré sera (égale à) "grp", apparaitra à la position (getPos position_pat_gen_01), appartiendra au camp EAST sera composé tel que défini par les classes (configFile >> "CfgGroups" >> "East" >> "BIS_TK_INS" >> "Infantry" >> "TK_INS_Patrol").Pour déterminer ce qui doit suivre (configFile >> "CfgGroups" >>..., deux solutions :
Le tout entre [] composera les parametres pour la fonction BIS_fnc_spawnGroup, exécutée par le call. N'oubliez pas de faire la correspondance entre le 2ème paramètre "...,EAST,..." et la classe "...>> "East" >>..."
- soit vous vous chercher directement dans les fichiers de config "CA.PBO" (pour ArmA 2) et "CA_E.PBO" (pour OA), rechercher la classe "class CfgGroups" puis suivre l'arborescence, soit "East" + "BIS_TK_INS" + "Infantry", et enfin le nom de la classe du groupe "TK_INS_Patrol" (pour info, j'ai placé les fichiers "config.cpp" (format texte) contenant les classes "CfgGroups" dans le répertoire "docs\")
- soit vous vous reportez a la page de Tromplamort (que j'ai également intégré dans le répertoire "docs\"), qui indique beaucoup plus clairement l'arborescence des différentes classes.
[grp, (getPos position_pat_gen_01), 150] call bis_fnc_taskPatrol;Seconde ligne : le "grp" (1er paramètre), défini au-dessus, patrouillera autour de la position (getPos position_pat_gen_01), dans un rayon de 150 mètres. Cette fois, la fonction exécutée est bis_fnc_taskPatrol.L'avantage de cette "méga"-ligne de commande, c'est qu'elle peut être "copiée-collée" à volonté (voir "copier-coller" tout le déclencheur). On a juste besoin de changer la position, et éventuellement le type de groupe que l'on veut insérer. Pour changer la position, on créera un autre "logique de jeu" et on remplacera position_pat_gen_01 par le nom du "logique de jeu". On peut aussi utiliser un marqueur mais, dans ce cas la commande (getPos position_pat_gen_01) deviendra (getMarkerPos "nom_du_marqueur"). Plus subtil, on peut utiliser une position pour la génération du groupe, et une autre position pour indiquer la zone de patrouille : le groupe apparaitra à un endroit, se dirigera vers le 2ème endroit et commencera à patrouiller.
Les attentifs auront peut-être remarqué les pointillés autour du "logique de jeu". Il a une rayon de placement de 500m, ce qui permet d'injecter un élément aléatoire de plus : la patrouille étant générée à l'endroit du "logique de jeu", celui-ci se placant aléatoirement, on ne sait pas où sera généré la patrouille.
14. ZONE "GENERATION DE PATROUILLE SUR UNE POSITION DE "LOGIQUE DE JEU" + SCRIPT 'PATROLS.SQF'"
(Attention ! spécifique OA !)
Contient :
- un élément "logique de jeu"
- le déclencheur générant la patrouille
- le déclencheur indiquant la zone de patrouille
C'est un cumul entre les deux types de patrouilles expliquée ci-dessus : générer un patrouille lorsque les joueurs entre dans une zone (= un déclencheur) et embrayer sur le script de patrouille aléatoire, afin de faire patrouiller le groupe dans la zone définie par un deuxième déclencheur. Cela se fait facilement en remplacant la lignecall { grp = [(getPos position_pat_gen_01), EAST, (configFile >> "CfgGroups" >> "East" >> "BIS_TK_INS" >> "Infantry" >> "TK_INS_Patrol")] call BIS_fnc_spawnGroup; nul = [leader grp, zargabad_pat] execVM "patrols.sqf"; }[grp, (getPos position_pat_gen_01), 150] call bis_fnc_taskPatrol;par la lignenul = [leader grp, zargabad_pat] execVM "patrols.sqf";Autrement dit, utiliser le leader du groupe grp précédemment généré comme 1er argument, et le deuxième représente, comme expliqué précédemment, le déclencheur entourant la zone de patrouille. Cette méthode permet de multiplier les zones de patrouille potentielle et d'économiser un énorme temps-machine, puisque les patrouilles n'apparaissent qu'à l'approche des joueurs et que les scripts sont inactifs tant que la patrouille n'est pas générée.
On peut éventuellement utiliser le déclencheur générant la patrouille comme déclencheur indiquant la zone de patrouille, mais c'est une "petite" économie qui n'aurait pas beaucoup d'influence sur le jeu.
15. GENERATION DE GROUPE D'ATTAQUANTS
(Attention ! spécifique OA !)
Constitué :
Je ne rentre pas trop dans les détails, le système est quasiment identique à celui décrit au chapitre 13 : ZONE "GENERATION DE PATROUILLE SUR UNE POSITION DE LOGIQUE DE JEU". J'ai juste retardé l'apparition des attaquants à 30s après le début du jeu, afin de ne pas les avoir sur le dos de suite.- du déclencheur générant le groupe d'attaquants
- du marqueur indiquant la destination de attaquant
call { grp = [(getPos attaquants01), EAST, (configFile >> "CfgGroups" >> "East" >> "RU" >> "Infantry" >> "RU_InfSquad")] call BIS_fnc_spawnGroup; [grp, (getmarkerPos "attaque01")] call bis_fnc_taskAttack; }
grp = [(getPos attaquants01), EAST, (configFile >> "CfgGroups" >> "East" >> "RU" >> "Infantry" >> "RU_InfSquad")] call BIS_fnc_spawnGroup;Cette fois, c'est un groupe d'infanterie russe qui est généré : cf. EASTX2, classe "CfgGroups", sous-classes "East" (groupe du camp Est), puis "RU" (groupe RUsse), ensuite "Infantry" (groupe d'infanterie) et enfin "RU_InfSquad" (le nom du groupe). Ensuite vient la fonction de BIS qui provoque l'attaque de la part du groupe
[grp, (getmarkerPos "attaque01")] call bis_fnc_taskAttack;le 1er paramètre est toujours le groupe généré, le 2ème est la position sur laquelle doit se porter l'attaque, en l'occurence la position du marqueur "attaque01" (cf. texte "attaque ennemie")
16. GENERATION DE GROUPE DE DEFENSEURS
(Attention ! spécifique OA !)
Constitué :
Système similaire à celui décrit aux chapitres 13 et 14.- du déclencheur générant le groupe de defenseur
- du marqueur indiquant l'endroit à defendre
call { grp = [(getPos attaquants01), EAST, (configFile >> "CfgGroups" >> "East" >> "RU" >> "Infantry" >> "RU_InfSquad")] call BIS_fnc_spawnGroup; [grp, (getMarkerPos "defense01")] call bis_fnc_taskDefend; }
grp = [(getPos attaquants01), EAST, (configFile >> "CfgGroups" >> "East" >> "RU" >> "Infantry" >> "RU_InfSquad")] call BIS_fnc_spawnGroup;Toujours le même groupe d'infanterie russe généré, comme au chapitre 15.
[grp, (getMarkerPos "defense01")] call bis_fnc_taskDefend;le 1er paramètre est encore le groupe généré, le 2ème est la position que le groupe doit défendre. A noter que certain soldats du groupe resteront sur place, à attendre assis, tandis que les autres se rendront à l'emplacement à défendre, c'est-à-dire la position du marqueur "defense01" (cf. texte "défense ennemie"). Deuxième chose remarquable : il y a un "statique" à l'emplacement à défendre (un Kord mini-trépied); dès que les défenseurs arriveront sur place, un des soldats s'installera comme tireur dans le "statique".
(Plus qu'un petite place pour le mot de la fin :)
Bonne édition !