Aller au contenu principal

Projet 05 : Gang encounter

Dans les projets précédents, tu as géré des entités uniques : un piéton isolé, un garde du corps ou une voiture. Dans le Projet 05, tu franchis un cap en orchestrant plusieurs acteurs simultanément. Tu vas donner vie à une confrontation de territoire avec trois membres de gang qui montent la garde, se mettent en alerte à ton approche, ouvrent le feu si tu sors une arme et retournent au calme si tu bats en retraite.


La mission

Concevoir une rencontre de gang dynamique répondant à six exigences fondamentales :

  1. Gérer dynamiquement une escouade de trois membres de gang à l'aide d'une collection générique List<Ped>.
  2. Faire apparaître les acteurs en ligne défensive face au joueur dans une posture de sentinelle.
  3. Détecter l'état d'armement du joueur et sa proximité spatiale en temps réel.
  4. Déclencher une riposte hostile si le joueur dégaine une arme à moins de 8 mètres, ou s'il s'approche à moins de 4 mètres les mains nues.
  5. Implémenter un véritable retour au calme physique : si le joueur bat en retraite au-delà de 18 mètres, interrompre le combat et reprendre la posture de garde.
  6. Purger automatiquement les handles d'entités détruites et garantir une suppression propre lors d'un rechargement ou d'une réinitialisation manuelle.

Spécifications, contraintes

  • Hygiène des collections dynamiques : purger les entités mortes ou supprimées à chaque frame via CleanInvalidRefs() avec List.RemoveAll pour prévenir les exceptions d'accès mémoire.
  • Détection rigoureuse de l'armement : évaluer conjointement player.IsArmed(WeaponCheckFlags.All) et player.Weapons.Current.Hash != WeaponHash.Unarmed pour distinguer une arme à feu d'un téléphone ou de poings nus.
  • Retour physique au calme : changer une variable interne ne suffit pas ; il est impératif d'appeler member.Task.ClearAll() puis de relancer le scénario "WORLD_HUMAN_GUARD_STAND".
  • Contrôle comportemental absolu : activer member.BlockPermanentEvents = true sur chaque PNJ afin que la panique ambiante native ne vienne pas écraser la logique de ton script.
  • Zéro fuite d'entité : supprimer tous les membres vivants ou morts dans ClearGang() lors du déchargement.

Étapes de réalisation

  1. Déclarer la collection : initialise une liste privée private readonly List<Ped> _gangMembers = new List<Ped>(); dans ta classe.
  2. Brancher les événements : dans le constructeur, enregistre des gestionnaires pour Tick, Aborted et KeyDown.
  3. Purger les handles obsolètes : en tête de OnTick, invoque CleanInvalidRefs() pour retirer de la liste les PNJ devenus nuls ou inexistants.
  4. Instancier l'escouade : si _gangMembers.Count == 0, appelle la méthode SpawnGang().
  5. Évaluer la menace du joueur : détermine si le joueur tient actuellement une arme létale en main.
  6. Parcourir les membres de l'escouade : pour chaque PNJ vivant de la liste :
    • Maintenir BlockPermanentEvents = true.
    • Calculer la distance au joueur avec player.Position.DistanceTo(member.Position).
    • Si le joueur est armé à moins de 8 mètres ou à moins de 4 mètres désarmé, ordonner member.Task.Combat(player).
    • Si la distance dépasse 18 mètres et que le membre combat, effacer les tâches et lancer member.Task.StartScenarioInPlace("WORLD_HUMAN_GUARD_STAND", 0, false).
  7. Bâtir la routine d'apparition : dans SpawnGang, itère 3 fois, calcule les positions latérales avec player.RightVector, donne des pistolets, lance le scénario de sentinelle et ajoute chaque acteur à la liste.
  8. Programmer la purge et le reset : dans ClearGang, parcours la liste, supprime chaque entité existante et vide la collection. Associe la touche Keys.NumPad9 à la réinitialisation et appelle ClearGang dans OnAborted.

APIs, outils à explorer

  • System.Collections.Generic.List<Ped> : collection dynamique standard pour administrer un groupe d'acteurs de taille variable.
  • List<T>.RemoveAll(Predicate<T> match) : supprime sur place tous les éléments satisfaisant une condition donnée.
  • Ped.IsArmed(WeaponCheckFlags flags) : méthode native vérifiant si un piéton tient une arme.
  • Ped.Task.StartScenarioInPlace(string scenarioName, int unkDelay, bool playIntroClip) : ordonne à une entité d'exécuter un scénario d'animation d'ambiance.
  • Ped.Task.ClearAll() : interrompt immédiatement la file de tâches actives et en attente.
  • Vector3.DistanceTo(Vector3 target) : calcule la distance euclidienne 3D entre deux coordonnées dans le monde.

Critères de validation

Ton mod est validé dès que :

  • Approche désarmée à 10 mètres : le gang reste en formation de garde et observe sans tirer.
  • Arme dégainée à 7 mètres : les trois membres de gang dégainent et ouvrent le feu immédiatement.
  • Approche à 3 mètres les mains nues : la proximité critique déclenche les tirs de défense.
  • Repli au-delà de 18 mètres : les tirs cessent, le gang annule ses tâches de combat et reprend sa posture de sentinelle.
  • Retour désarmé à 10 mètres : le gang reste calme et ne tire pas sans nouvelle provocation.
  • Appui sur Pavé numérique 9 ou rechargement avec Inser : le gang disparaît complètement sans laisser de cadavres sur le bitume.

Solution, explications

Partner
Solution vérifiée et explications du code

Le sujet, les contraintes et les étapes de réalisation restent 100% libres pour t'exercer par toi-même. Le code source de référence vérifié et les explications détaillées de production sont réservés aux membres du tier Partner.