[script] [Résolu] ( Montrer || Cacher ) les NPCs à heure fixée par variable

Répondre
Partager Rechercher
J'ai besoin d'un script pour une campagne DM qui cacherait tous les PNJs de mes zones à heures données pour les rendre visible plus tard. Typiquement, masquer les passants à 20h et faire apparaître les gardes de nuit. À 6h du matin, mouvement inverse, apparition des passants, disparition de la garde.

J'y arrive déjà en mettant un script sur l'événement heartbeat de chaque npc. Le script vérifie l'heure, la compare avec une heure fixée "en dur" dans le script, et si nécessaire modifie l'état ScriptHidden du NPC grâce à la fonction SetScriptHidden.

Ça fonctionne. Mais, chaque 6s pour chaque NPC, si j'en ai 30, c'est pas terrible pour le CPU et puis c'est pas très pratique.

Je demande s'il est possible de faire un script avec les contraintes suivantes :
- Lancement à chaque heure côté module : donc 24 fois par jour dans le jeu
- Vérification d'une variable pour chaque NPC du module
- Attribution d'une variable disparition et d'une variable apparition pour les NPCs : de type entier, entre 0 et 23 par ex
- Masquage / Apparition des NPCs selon l'heure

De sorte que je puisse dire : untel apparaît de x à x, tel autre de x à x, juste en modifiant les variables qui leur sont assignées. À terme, ça permettrait - en ajoutant des fonctionnalités au script - en plus de fermer les portes et de les ouvrir selon les heures, non ?

Merci d'avance pour vos avis / aides.
Faire une grosse boucle de recherche, qui va vérifier tous les PNJs pour chaque zone, ça risque d'être plus lourd qu'un petit bout de code qui ne vérifie qu'une variable sur son porteur. Enfin, je suppose.
Merci Deyonara.

Donc il vaut mieux le faire avec un script sur chacun en gardant les variables à ton avis.

Ça multiplie un peu les scripts mais je peux vivre avec.
Si tu voyais ce que le script "nw_c2_default1" exécute, tu verrais que ton petit bout de code n'est qu'une goutte dans l'océan. ^^

Par contre, est-ce qu'ils réapparaissent bien ? Un PNJ classé "Script hidden" exécute-t-il bien le script de son événement "OnHeartbeat" ?
Oui, en fait la propriété ScriptHidden n'affecte que deux choses, l'apparence et l'IA.

La première est simplement le rendu par le moteur graphique. Avec une zone chargée en NPC, je peux passer de 10 FPS à 40 selon qu'ils sont scriptHidden ou pas.

La seconde est comme tu le sais activable malgré le scriptHidden. J'ai pas plus testé que ça cet aspect, mais je présume qu'ils n'attaquent pas cachés quand même.

Donc les événements se déroulent normalement pour les objets.

Je préfère de loin cette option comparée à la destruction / création d'objets.
spawn system
J'ai vu qu'il y avait la possibilité de désactiver l'IA, etc. Mais je n'avais pas vu qu'on pouvait carrément rendre le PNJ inexistant sans le créer/détruire. Belle innovation de NWN2.

Sur NWN1 j'étais fan de ce système qi marchait très bien malgré son placement en onheartbeat :

NWN Spawn System.txt


Je le poste entier dsl, j'ai pas su retrouver le lien sur le vault. Ce script fonctionnait plutôt très bien sauf pour le campement aléatoire que je n'ai jamais trop su faire fonctionner. Il permet de faire spawner des gardes, des badauds comme des créatures de rencontre. De les faire repoper aussi. On peut créer des magasins et établissements ouverts à certains horaires. On peut choisir dans la liste des animations les actions qui seront utilisées et ce, de façon aléatoire ou pas. Un prêtre priera, un badaud marchera et saluera, etc.
Pour éviter le lag, je m'étais limité à un nombre de créatures par serveur et j'équilibrais selon les horaires sur l'ensemble des maps.
Ce script me permettait par exemple d'avoir des mort-vivants la nuit dans le cimetière et des rats la journée. d'avoir des bucherons en forêt le jour, en ville au couchant et en auberge la soirée.
Je n'ai jamais atteint de limite de lag due à ce script.

Les créatures étaient tirées de la palette obligatoirement.

Peut-êrte qu'il y a matière à combiner entre ces idées et les nouvelles possibilités de NWN2?

-------

Sinon j'ai une question importante : Quand tu parles d'un déclenchement par heure du script par le module donc seulement 24 par jour. Tu parles quand même d'un script placé dans le onheartbeat du module ou d'un nouvel emplacement que je n'ai pas remarqué?


yz
Non, il n'y a pas d'événement par heure.

Pour gérer le "24 fois par jour", je pense vérifier si la minute est bien 0 et les secondes entre 0 et 10.

J'ai fait des tests et remarqué que heartbeat ne tombe pas précisément sur des intervales de 6 sec, il y a des décalages.
je ferais comme ceci en me servant des script : (script déclenché par un événement définit par l'utilisateur)
et du onHeartbeat de la zone.

le onheartbeat de la zone envois 2 events sur la zone à 6h et à 20h

la zone renvois pour chaque event reçu de son onheaartbeat selon que c'est celui de 6h ou de 20h 2 event a tous les pnj de la zone.
( 2 event un pour rendre invisible l'autre pour rendre visible à 6h et inversement quand c'est 20h selon que le tag de tes png soit garde_ ou manant_ par exemple)

pis ainsi quand les pnj recoivent les event déclenché par la zone sur leurs propres (script déclenché par un événement définit par l'utilisateur)
tu peut personnalisé la sortie/entrée de chaque pnj, rajouter un petit temp pour pas qu'il disparaissent tous en même temps, faire des sortie différente etc..

on pourait directement du onheartbeat envoyer des events au pnj certe, mais je trouve plus propre de faire ca par l'intermédiaire du "script déclenché par un événement définit par l'utilisateur" de la zone. ( ce qui permet entre autre a ce moment la de faire un scan de tous les pnj de la zone sans toucher a ton onheartbeat qui restera simple)

ca te sera utile si plus tard tu veut diversifier le système et ainsi envoyer d'autres event depuis la zone a ces heures là...

en gros ca donne :
-le onhearbeat de la zone dit a la zone réalise mon event perso 1001 a 6h et réalise mon event perso 1002 a 20h.
- la zone a chaque event recu dit a tous les pnj de la zone devenez visible(1003)/invisible(1004)
-et chaque pnj recevra les events de la zone(1003 et 1004 donc), et réagiront eux meme a ces évents.

tu garde la possiblité de paramétré des différence donc sur chaque pnj, histoire qu'il disparaissent pas tous exactement a la meme heure, on encore que certain fasse semblant d'ouvrir une porte d'autre sorte de la ville.. etc..
Citation :
Publié par Laban
Non, il n'y a pas d'événement par heure.
Pour faire un événement de type "heure" pour tes zones, tu peux utiliser une variable locale sur le module et la vérifier :
Code PHP:

void main()
{
    
int nHeure GetTimeHour();
    
object oModule GetModule();

    if(
nHeure != GetLocalInt(oModule,"EVENEMENT_HEURE"))
    {
        
SetLocalInt(oModule,"EVENEMENT_HEURE",nHeure);

        
// Mettre ici le truc à faire quand l'heure a changé.
    
}

Il y aura forcément un décalage de 2 ou 3 secondes entre l'événement et le passage à l'heure suivante, mais ça n'est pas extrêmement dramatique.
Merci pour vos retours.

Je n'y connais rien encore aux évènements utilisateurs, mais il me semble en effet qu'il s'agit d'un moyen astucieux pour gérer la question au niveau module.

Le post de Jorimad est un peu confus et le script d'Anthraxcite un peu complexe pour moi en l'état.

Peut-être pourriez-vous m'expliquer comment créer un script qui génère 24 événements perso à partir d'un timer et quel template de script utiliser pour affecter des comportements à un PNJ en fonction de tel ou tel événement perso.
ben je ne peut pas m'empêcher de te renvoyer a ce qu'a fait deyonara ici :
https://nwn2.jeuxonline.info/article...dOnUserDefined

le principe et tout con, n'importe ou dans tes script tu peut créer un event utilisateur !

c'est un type de variable : event

ensuite tu signale l'événement a un de tes objet du module ou meme au module lui même avec SignalEvent( object, event)

ce qui va déclencher "le script déclenché par un événement définit par l'utilisateur" de l'objet... ( OnUserDefinedEvent dans nwn1)
mais dans ce script il faut récupéré l'event avec une structure de code toute bête que tu retrouvera dans le lien donner ci-dessus.

pour un timer sur le module on doit pouvoir faire ça avec le script de deyo plus haut !)
en y rajoutant par exemple 2 ligne :
Code PHP:

void main()
{
    
int nHeure GetTimeHour();
    
object oModule GetModule();
   
    if(
nHeure != GetLocalInt(oModule,"EVENEMENT_HEURE"))
    {
        
SetLocalInt(oModule,"EVENEMENT_HEURE",nHeure);
        
// pour chaque heure tu aurra un évenement envoyer sur le module de 3000  
        //à 3024)    
event etimer EventUserDefined(3000 nheure);
       
// envois de l'événement au module
SignaleEvent(oModule,etimer);


    }

( l'un dans l'autre tu a 1 onhearbeat des plus légérs la ! )



tu verra le principe est simple et ma fois bien pratique..
dans un de ses script "OnUserDefinedEvent" tu réception ton event comme écrit dans l'article :
celui du module pour poursuivre l'exemple !
Code PHP:

voidmain() 
{
int nEvent GetUserDefinedEventNumber();

    
// S'il s'agit de l'événement XXXX :
    
if(nEvent == 3006)  // 3000 + 6 heure = debout tous le monde
    
{

    
// et la tu peut aussi te servir de signalEvent sur d'autre objet de ton module 
    // et vi ^^
    // donc par exemple je créer ici mon événement du réveil 
    //
    // j'imagine que l'event 3010 sera l'event qui dira au zone debout ! (on peut 
    // garde le numéro 3006 aussi tant qu'on l'envois pas 2 fois en meme temps a un 
    // meme objet !)
  
event eDebout EventUserDefined(3010); // j change le numéro mais dans la réalité 
    //garder le numéro 3006 serait bien sachant qu'il correspond à debout c'est 6h
    // j'envois l'événement a une zone
 
Signalevent(tagdemazoneeDebout); // ou le resref ? ligne a confirmer pour l'objet zone... 
   // et je peut aussi envoyer toute sorte d'évenement qui se produise a 6 h 
   // pour aléger le onhearbeat par exemple on peut trouver ici :
   // une boucle qui parcour tes zones pour leur dire debout c'est 6 heure.
   // et sur tes zone on trouvera ici par exemple une boucle qui va dire a tout tes pnj 
   // debout il est 6h les garde au dodo !
   // + n'importe quel autre code...
}
else if (
nEvent XXXX)
   { 
//...
    
}


je crois qu'obsidian recommande de partir de 3000 pour être tranquilles vie a vie des N° d'events certain étant utiliser dans les script de base !

-ne pas oublier en commentaire de toujours définir textuellment a quoi correspond le N° de l'événement pour s'y retrouver !

je trouve bien de garder une certaine logique et ton exemple et très bien pour çà.
le module posséde un timer sur son onhearbeat celui ci di Debout à 6 h sur son 'OnUserDefinedEvent', ils scan les zone et leur dit a leur tour debout !
chaque zone scan ses pnj et leur dit a leur tour debout
chaque pnj devient visible quand ils recoivent l'événement debout !

ca parait bête mais tu aurra des petit script au lieu d'avoir un gros script un peu uzine a gaz
le OnUserDefinedEvent permet de géré au mieu son module, sachant qu'un SignalEvent sur un objet déclenchera son OnUserDefinedEvent..
( script déclenché par un événement définit par l'utilisateur dans nwn2 ^^)
Hé bien voilà qui me plaît bien en fait. Merci Jorimad.

Je vais de ce pas expérimenter ce système qui me semble répondre aux contraintes à l'exception des variables, puisqu'en fait il faudra faire un script pour chaque comportement.

- un script apparition à 6h et disparition à 20h
- un script apparition à 20h et disparition à 6h

A moins qu'on utilise un seul événement ("Changement d'heure") et qu'un script générique placé sur le OnUserDefinedEvent compare la variable affectée au module ("timer") aux variables internes de l'objet à chaque changement d'heure. Mais ce serait sans doute plus lourd.
D'ailleurs maintenant que j'y pense, il vaut mieux avoir un script sur le module qui gère la variable locale pour définir si l'heure a changé, et laisser les autres scripts du module juste vérifier si la variable et l'heure du modue correspondent :
Code PHP:

// "OnHeartbeat" du module :

void main()
{
    
int nHour GetTimeHour();
    if(
nHour != GetLocalInt(OBJECT_SELF,"HEURE_ACTUELLE"))
        
SetLocalInt(OBJECT_SELF,"HEURE_ACTUELLE",nHOUR);

Code PHP:

// "OnHeartbeat" de l'objet à faire réagir :

void main()
{
    
int nHour GetTimeHour();
    if(
GetTimeHour() != GetLocalInt(GetModule(),"HEURE_ACTUELLE")
    {
        if(
nHour==6)
        {
            
// Ce que tu veux faire à 6 heures
        
}

        else if(
nHour==20)
        {
            
// Ce que tu veux faire à 20 heures
        
}
    }

Merci Grande Deyonara, Prêtresse du Dieu Nwscript, mais en fait j'ai l'impression qu'au lieu de faire une vérification de l'heure dans le HeartBeat de la créature, on le fait au niveau module.

Ce qui me plaît bien dans l'événement c'est qu'il ne se lance qu'une fois par heure, au lieu de 10 fois par minutes. C'est idiot sans doute de ma part, mais je trouve ça plus efficace.

Est-ce qu'on ne pourrait pas imaginer un fonctionnement suivant

1. Le module envoie un Event unique (genre 3000 "Changement d'heure") quand l'heure change et modifie la variable TimerHour.

2. Le script standard des créatures sur onUserDefinedEvent vérifie si la valeur d'une de leurs variables d'apparition / disparition est égale à la variable TimerHour. Si oui, le script modifie leur état.


De telle sorte qu'un seul onHeartBeat tourne, celui du module, et qu'un seul événement par heure déclenche un script pour chaque créature à condition que leurs variables soient affectées. Ça me semble bien léger et modulable, ça, non ?

Par contre, que se passe-t'il si on vérifie une variable non affectée ? Il y a des fonctions comme isset() ou null() dans le nwscript pour vérifier ça ? Vous me direz, pas de variables, pas de onUserDefinedEvent... M'enfin, comme ça, juste pour savoir ?
Bon j'ai rien dit, ça m'apprendra à vouloir faire des trucs au réveil.

Le mieux est de gérer l'heure directement sur chaque PNJ, et de lancer un événement si ça correspond à un changement d'heure :
Code PHP:

void main()
{
    
int nHour GetTimeHour();
    
object oMoiMeme OBJECT_SELF;

    if(
nHour != GetLocalInt(oMoiMeme,"HEURE_ACTUELLE"))
    {
        
SetLocalInt(oMoiMeme,"HEURE_ACTUELLE",nHOUR);

        
// Hop on envoie le signal "changement d'heure"
        
SignalEvent(oMoiMeme,EventUserDefined(3001));
    }

Et on gère le machin du truc dans le script UserDefined de chaque PNJ :
Code PHP:

void main()
{
    
object oMoiMeme OBJECT_SELF;

    
int nEvent GetUserDefinedEventNumber();
    if(
nEvent == 3001)
    {
        
int nHour GetLocalInt(oMoiMeme,"HEURE_ACTUELLE");
        if(
nHour == 6)
        {
            
// Hop il est 6 heures
        
}
        else if(
nHour == 20)
        {
            
// Hop il est 20 heures
        
}
    }

Oui voilà.

Mais tu penses que plusieurs scripts sans variables sont mieux qu'un script unique avec des variables assignées à la créature ?

Ou alors ça ne te semble pas possible ?
Voila ce qui se passe avec ces deux scripts :

Le script dans le "OnHeartbeat" du PNJ vérifie si l'heure du module a changé. Si c'est le cas, elle est enregistrée et un signal est envoyé pour déclencher l'événement "OnUserDefined". Quoi qu'il advienne, ce signal ne sera envoyé qu'une seule fois par "heure" pour chaque PNJ.

Le script dans le "OnUserDefined" du PNJ vérifie quelle est l'heure enregistrée et agira en fonction.


Tu auras deux contraintes différentes, au choix :

Premier cas : Définir l'heure de départ du module, soit 6h ou 20h. Ceci afin de déclencher l'événement des PNJs directement et éviter que ça soit incohérent jusqu'à la première heure clé atteinte.

Second cas : Régler le paramètre "Script dissimulé" sur les paramètres de chaque PNJ directement dans l'éditeur, selon l'heure de départ du module.


Sinon oui, une variable est indispensable pour comparer l'heure en cours, et l'heure enregistrée, afin de déterminer si celle-ci a changé.
Bon, j'ai du mal m'exprimer. J'ai bien compris ce que font les scripts que tu as rédigé avec grâce et humour, comme d'accoutumée.

J'observe simplement qu'il faudra avoir plusieurs scripts comme :

Code PHP:

laban_appear_6_to_20 // script associé aux PNJs apparaissant de 6h à 20h
laban_appear_20_to_6 // script associé aux PNJs apparaissant de 20h à 6h
// etc. : un script par comportement 
Ce qui est bien et bon comme dirait Jean-Claude. Mais je me demandais comment faire pour avoir un seul script :

Code PHP:

laban_appear // script associé à tous les PNJs 

et que ce script agisse en fonction de variables associées au PNJ, comme par exemple pour un personnage apparaissant de 6h à 20h :
Code PHP:

int appear=6// définit l'heure d'apparition
int disappear=20// définit l'heure de disparition 
Le script "laban_appear", lancé au changement d'heure via "OnUserDefined", vérifierait pour chaque PNJ si son apparition ou sa disparition est programmée pour cette heure là. De sorte qu'un seul script gèrerait tout et qu'il suffirait d'affecter des variables différentes aux PNJs pour les voir apparaître et disparaître selon des heures différentes.
Normalement tu peux faire un script commun pour le "OnUserDefined". Reste juste à choisir la méthode pour reconnaître qui doit faire quoi. Ca peut être dans le Tag, dans une variable locale (ce que je préfère, personellement), ou n'importe quoi d'autre.

Dans l'idée ça donne ça :
Code PHP:

void main()
{
    
int nEvent GetUserDefinedEventNumber();
    if(
nEvent == 3001)
    {
        
object oMoiMeme OBJECT_SELF;

        
int nHour GetLocalInt(oMoiMeme,"HEURE_ACTUELLE");
        if(
nHour == || nHour == 20)
        {
            
int nType GetLocalInt(oMoiMeme,"HEURE_APPARITION");
            if(
nType == nHour)
            {
                
// Hop c'est mon heure, j'apparais...
            
}
            else
            {
                
// ... sinon, je disparais
            
}
        }
    }

D'accord, et donc quelque chose comme ça fonctionnerait aussi ?

Code PHP:

void main()
{
    
int nEvent GetUserDefinedEventNumber();
    if(
nEvent == 3001)
    {
        
object oMoiMeme OBJECT_SELF;
        
int nHour GetLocalInt(oMoiMeme,"HEURE_ACTUELLE");
        
int nAppear GetLocalInt(oMoiMeme,"HEURE_APPARITION");
        
int nDisappear GetLocalInt(oMoiMeme,"HEURE_DISPARITION");

        if (
nHour == nAppear)
        {
                 
// Hop c'est mon heure, j'apparais...
                  
SetScriptHidden(oMoiMemefalse);
        }
         else if (
nHour == nDisappear)
        {
                 
// Hop c'est mon heure, je disparais...
                  
SetScriptHidden(oMoiMemetrue);
        }

    } 
Parce que coder en dur 6 ou 20 supprime la souplesse du code non ?
Tout à fait, et c'est même mieux.

La méthode que tu as choisie est plus générique. Tu peux ainsi créer des PNJs qui peuvent apparaître/disparaître pendant 1h, à n'importe quelle heure de la journée.


Ne reste plus qu'à savoir si un PNJ "Script Hidden" peut voir son événement "OnUserDefined" se déclencher.
En effet, mais j'ai plutôt bon espoir de ce côté, puisque le onHeartBeat fonctionne de façon certaine.

Un détail :

Code PHP:

       int nHour GetLocalInt(oMoiMeme,"HEURE_ACTUELLE"); 

Ne fonctionne pas dans le cas d'une variable module, n'est ce pas ? Ou alors les variables modules sont-elles accessibles pour chaque objet du module ?

Quelle serait la méthode pour récupérer la variable "HEURE_ACTUELLE" stockée par le onHeartBeat du module sinon ?
L'objet à viser par le GetLocal pour une variable sur le module est simplement GetModule(donc GetLocalInt(GetModule(),"nomvariable")). Pour savoir si c'est une nouvelle heure, dans le cas du script que j'ai cité qui s'exécute toute les minutes il suffit de regarder que les minutes de l'heure du mod soit égale à 0. L'exécution se fait toute les minutes et non toutes les six secondes et ne passe pas par des DelayCommand, c'est donc aussi efficace qu'un ohb sauf que ça se déclenche moins souvent.
Oui alors par contre, et comme de bien entendu, une créature qui est cachée via script hidden ne répond plus aux événements OnUserDefinedEvent.

Donc c'est un peu pour rien qu'on a regardé tout ça, à moins qu'un contournement ne soit possible.

Je vais me pencher sur une solution onHeartBeat avec les variables dans ce cas.
Répondre

Connectés sur ce fil

 
1 connecté (0 membre et 1 invité) Afficher la liste détaillée des connectés