La Bibliothèque de Neverwinter Nights
Aide et informations diverses sur Neverwinter Nights ainsi que D&D3.
La date/heure actuelle est 05/07/2025 12:17:07


  Page 2 sur 2 ¤ Aller à la page Précédente  1, 2

Voir le sujet précédent ¤ Voir le sujet suivant 
Auteur Message
Tzeentsh
Ecuyer
Inscrit le: 01 Déc 2002
Messages: 41
Répondre en citant
Posté le : 09/03/2004 21:49:26 Sujet du message :

Les portes ont une queue d'action, ça j'en suis sur, donc par extension je pensais que les plaçables en avaient également... Very Happy
 
Revenir en haut Voir le profil de l'utilisateur Envoyer un message privé Ignorer l'utilisateur
 
lendraste
Grand Maître Chanteur du Conseil
Inscrit le: 20 Fév 2003
Messages: 1403
Localisation: Quelque part ailleurs
Répondre en citant
Posté le : 09/03/2004 22:17:06 Sujet du message :


nunch a écrit :
Salut Lendraste,
mon module est congestionné par les DelayCommand(), au point que le temps arrête de s'y écouler.
Je pense que la queue d'action pourrait résoudre mes problèmes. Pourrais-tu nous faire profiter de tes scripts s'il-te-plait ?
Je pourrais essayer de synthétiser une solution à partir de ce que j'ai déjà fait, mais j'aimerai d'abord savoir à quoi tu utilises tes DelayCommand ?
_________________
Lendraste de Loreval
Qui cherche la Vérité cherche celui qui la détient, car elle n'existe pas à l'état naturel.
La cité des mensonges - 1
 
Revenir en haut Voir le profil de l'utilisateur Envoyer un message privé MSN Messenger Numéro ICQ Ignorer l'utilisateur
 
nunch
Grand Sage du Conseil
Inscrit le: 23 Mai 2003
Messages: 966
Localisation: Dans la gueule du Lyon
Répondre en citant
Posté le : 10/03/2004 12:09:31 Sujet du message :


Lendraste a écrit :
Je pourrais essayer de synthétiser une solution à partir de ce que j'ai déjà fait, mais j'aimerai d'abord savoir à quoi tu utilises tes DelayCommand ?
Et bien je souhaite sauvegarder des informations sur les joueurs connectés au module (leurs XP, état de santé, etc.).
Au départ je voulais sauvegarder cette information dans la base de données de Bioware à la déconnexion du joueur. Mais voilà, lors de l'événement OnModuleLeave l'utilisation des fonctions SetCampaignXXX() n'est pas possible.
Comme solution alternative (n'ayant pas d'autres bases de données comme MySQL), j'ai donc décidé de sauvegarder les infos régulièrement en cours de jeu. Ainsi à la connexion d'un joueur, j'appelle une fonction de sauvegarde qui se rappelle elle-même régulièrement grâce à DelayCommande().
Ainsi gros problème: quand il y a cinquante joueurs, ça fait tout autant de DelayCommand() appelés régulièrement, sans compter les autres utilisés à l'occasion dans divers scripts du module. Et comme l'a dit un concepteur du jeu récemment dans un forum sur le site de Bioware, trop de DelayCommand() revient à trop utiliser l'événement OnHeartBeat, avec comme effet secondaire de bloquer l'écoulement du temps.

Aujourd'hui j'ai de toute façon l'intention de rajouter une base MySQL car je trouve que les fonctions SetCampaignXXX() ne sont pas assez fiables. En effet je les utilise également à d'autre fins (comme la gestion du contenu des coffres de banque) et il arrive quand même que des infos soient perdues de temps en temps en cas de plantage du module.
Je pourrais donc aussi sauvegarder l'état du personnage à la déconnexion.

Mais je pense que la queue d'action reste un concept très utile et intelligent à toute autre fin et je peux essayer de l'implémenter moi-même. Voilà, comme tu l'utilises depuis déjà un certain temps, je pense que tu as déjà dû contourner ou résoudre les problèmes et les bugs, et rendre disponible tes fonctions épargnerait un bien dur labeur aux autres scripteurs.
Dernière édition par nunch le 10/03/2004 12:22:56; édité 2 fois
 
Revenir en haut Voir le profil de l'utilisateur Envoyer un message privé Visiter le site web du posteur MSN Messenger Ignorer l'utilisateur
 
nunch
Grand Sage du Conseil
Inscrit le: 23 Mai 2003
Messages: 966
Localisation: Dans la gueule du Lyon
Répondre en citant
Posté le : 10/03/2004 12:18:47 Sujet du message :

J'en rajoute un peu: Smile

Lendraste a écrit :
A noter que, quoiqu'il arrive, il n'y aura jamais plus d'une action en attente dans la queue d'action, à moins que des évènements n'en ajoute. Ceci est d'ailleurs intéressant. Tandis que s'éxécute l'action courante du programme d'action, il est possible qu'un autre script introduise des actions supplémentaires. Lorsque CustomizedAction s'exécutera, elle placera la nouvelle action du programme à la suite dans la queue. Ce qui signifie que des actions introduites par des évènements étrangers pourront être joué quand même
Voilà un problème de mise en oeuvre que je ne sais pas comment résoudre pour le moment. Tu dis qu'il n'y aura jamais plus d'une action en attente dans la queue. Si je programme dix actions consécutives, il y en aura une dans la queue mais dans ce cas où seront les neuf autres ? Le langage de script ne permettant pas de gérer des structures de données comme les tableaux ou les listes chaînées, comment alors créer et gérer la liste des 9 actions restantes ?
 
Revenir en haut Voir le profil de l'utilisateur Envoyer un message privé Visiter le site web du posteur MSN Messenger Ignorer l'utilisateur
 
lendraste
Grand Maître Chanteur du Conseil
Inscrit le: 20 Fév 2003
Messages: 1403
Localisation: Quelque part ailleurs
Répondre en citant
Posté le : 10/03/2004 13:36:07 Sujet du message :


nunch a écrit :
Voilà un problème de mise en oeuvre que je ne sais pas comment résoudre pour le moment. Tu dis qu'il n'y aura jamais plus d'une action en attente dans la queue. Si je programme dix actions consécutives, il y en aura une dans la queue mais dans ce cas où seront les neuf autres ? Le langage de script ne permettant pas de gérer des structures de données comme les tableaux ou les listes chaînées, comment alors créer et gérer la liste des 9 actions restantes ?
Il me faut un peu de temps pour rationnaliser les scripts toujours en cours de développement chez moi. J'ai pas mal avancé sur les différentes actions "jouable" dans un programme d'action, mais il me reste quelques petites trouvailles à mettre en place. Concrêtement, cela se passe de la façon suivante :
Plutôt que de gérer la queue d'action directement, j'ai créé un système qui implémente les actions dans la queue une par une. Ces actions sont regroupées dans ce que j'appelle un programme d'action. Le programme d'action peut être écrit en pur code NWN Script ou en fichier 2DA. Ce qui coince un peu, au jour d'aujourd'hui, est la syntaxe de ce programme d'action, qui est quelque chose de très primitif et de très séquentiel. J'ai commencé à réaliser une application pour programmer simplement les programmes d'actions, mais je n'ai pas encore fini. Se familiariser avec la syntaxe prends un peu de temps. Toutefois, la liste des actions possibles dans un programme d'action est bien plus important que la liste des actions standards, puisque tout ce qui est intéressant pour faire des cutscenes (le principal usage que je fais d'un programme d'action) s'y trouve développé : donc les mouvements de caméra, les effets, les fades et j'en passe.
Voici un exemple de programme d'action (au format 2DA) pour comprendre le principe :
Code :

2DA V2.0

          Label          ActID   Subject          Params
0         "Program Name" 0       ****             "Programme de test"
1         Invi           103     SELF             INV
2         Blackscreen    102     SELF             FTB|0.25
3         Jump           4       SELF             OBT:WP_SC01|JMP
4         Wait           2       SELF             3
5         Blackscreen    102     SELF             FFB|0.01
6         Camera         101     SELF             SET|135.0|10.0|80.0|40
7         Wait           2       SELF             5
8         Talk           1       OBT:PNJ_COW1     Bonjour
9         Wait           2       SELF             2
10        Talk           1       OBT:PNJ_THECOW   Salut
11        Wait           2       SELF             5
12        BlackScreen    102     SELF             FTB|0.01
13        Wait           2       SELF             5
14        Jump           4       SELF             OBT:WP_SCFINAL|JMP
15        Camera         101     SELF             SET|270.0|2.0|80.0
16        Invi           103     SELF             UNI
17        Wait           2       SELF             3
18        BlackScreen    102     SELF             FFB|0.01


Ce programme d'action ne comportant pas plus de 75 actions ne sert pas à grand chose en tant que tel. Mais lorsque les actions de branchement et de condition seront développées (en cours), le nombre d'instruction d'un programme d'action ne sera plus significatif par rapport au nombre d'action joué. On pourra mettre le tout en boucle infinie sans risquer la moindre surcharge.

Je commente un peu mon programme d'action.
Label : cette colonne sert simplement d'indicateur et n'a pas de fonction véritable
ActID : la valeur numérique placée ici correspond à un type d'action jouable par l'interpréteur du programme d'action. L'action identifiée par cette valeur a un impact sur la lecture des paramètres qui suivent.
Subject : cela désigne le sujet de l'action. SELF correspond à celui qui joue l'action. Mais il existe un moyen d'identifier d'autres objets. Par exemple OBT:PNJ_COW1 signifie Object By Tag "PNJ_COW1". J'ai choisi cette syntaxe pour tout repérage d'objet : <méthode>:<identifiant>.
Params : contient les paramètres attendu par l'action. S'il y a plusieurs paramètres, ils sont séparés par un |. Par exemple, si on prend la ligne 12, on utilise l'action liée au "noircissement" de l'écran qui accepte 2 paramètres, le premier est la méthode (FTB pour Fade To Black, FFB pour Fade From Black) et le second le taux (qui correspond à la vitesse, les valeurs sont issues des constantes liées aux fonctions FadeToBlack et FadeFromBlack)

Même ce qui n'est pas une "action" à priori (comme le Fade) est joué par l'interpréteur du programme d'action comme une action (la fonction ActionDoCommand est super pratique pour ça Smile ), donc sera logé dans la queue d'action quand ce sera son tour d'être joué. On pourra parfaitement faire jouer le déclenchement d'un autre script dans la queue d'action (je n'ai pas encore fait cette fonction, mais elle est très simplement basée sur un ActionDoCommand réalisant un ExecuteScript avec les paramètres adéquats). L'interpréteur du programme d'action stocke des valeurs clé comme le pointeur d'instruction qui permet de savoir à quelle étape du programme d'action on en est (c'est ainsi qu'on peut faire des branchements, en créant des "actions" qui modifieront la position du pointeur et permettront donc de sauter en avant ou en arrière dans le programme d'action).

L'idée du fichier 2DA est la facilité qui s'y rattache. De plus, le gros intérêt de jouer un programme d'action depuis un fichier 2DA est le dynamisme, puisqu'on peut modifier le fichier 2DA pendant que le module tourne, ce qui permet de faire des ajustements "en live". Pour la vitesse et la performance, je conseille d'utiliser une méthode de pré-chargement quelconque pour placer le programme d'action en mémoire à l'aide de "tableaux" virtuellement instanciés par la génération automatiquement numéroté de nom de variable (seule méthodes connues à ce jour pour faire des tableaux). Le gros des fonctions permettant de créer un programme d'action en mémoire est déjà réalisé. Et puis on peut directement développer le codage en mémoire d'un programme d'action en appelant les instructions d'ajout de commande dans un programme d'action (pour ça aussi, les fonctions existe déjà).

L'interpréteur de programme d'action existe lui aussi. Il permet de jouer intégralement le petit programme d'action que j'ai posté plus haut, mais gère également un grand nombre d'action possible, notamment toute les actions normalement réalisable par une créature.

En attendant que je sorte l'ensemble des scripts de mon module de développement, est-ce que je réponds à ta question ?
_________________
Lendraste de Loreval
Qui cherche la Vérité cherche celui qui la détient, car elle n'existe pas à l'état naturel.
La cité des mensonges - 1
 
Revenir en haut Voir le profil de l'utilisateur Envoyer un message privé MSN Messenger Numéro ICQ Ignorer l'utilisateur
 
nunch
Grand Sage du Conseil
Inscrit le: 23 Mai 2003
Messages: 966
Localisation: Dans la gueule du Lyon
Répondre en citant
Posté le : 10/03/2004 17:19:43 Sujet du message :

Si j'ai bien compris:
En fonction de l'ActID lu dans le 2DA ou dans le tableau, on a un switch/case qui détermine quelle action exécuter et quels sont les paramètres. Donc une bonne partie des fonctions consistera à gérer le tableau et en extraire les paramètres qui vont bien.
 
Revenir en haut Voir le profil de l'utilisateur Envoyer un message privé Visiter le site web du posteur MSN Messenger Ignorer l'utilisateur
 
lendraste
Grand Maître Chanteur du Conseil
Inscrit le: 20 Fév 2003
Messages: 1403
Localisation: Quelque part ailleurs
Répondre en citant
Posté le : 10/03/2004 17:40:35 Sujet du message :


nunch a écrit :
Si j'ai bien compris:
En fonction de l'ActID lu dans le 2DA ou dans le tableau, on a un switch/case qui détermine quelle action exécuter et quels sont les paramètres. Donc une bonne partie des fonctions consistera à gérer le tableau et en extraire les paramètres qui vont bien.
En schématisant, c'est ça Smile
_________________
Lendraste de Loreval
Qui cherche la Vérité cherche celui qui la détient, car elle n'existe pas à l'état naturel.
La cité des mensonges - 1
 
Revenir en haut Voir le profil de l'utilisateur Envoyer un message privé MSN Messenger Numéro ICQ Ignorer l'utilisateur
 
Tzeentsh
Ecuyer
Inscrit le: 01 Déc 2002
Messages: 41
Répondre en citant
Posté le : 14/03/2004 17:43:51 Sujet du message :

J'avais raison Lendraste (mais cela a surement été rajouté après tes tests), les objets plaçables possèdent une queue d'action.

Par contre les créatures mortes mais non détruites n'en possèdent pas. Very Happy
 
Revenir en haut Voir le profil de l'utilisateur Envoyer un message privé Ignorer l'utilisateur
 
Mr-XXS
Ecuyer
Inscrit le: 15 Mar 2004
Messages: 49
Répondre en citant
Posté le : 16/03/2004 14:48:48 Sujet du message :

Apres tests, le ActionWait semble avoir une limite de 40 minutes, a 41 minutes, ca ne marche plus. C'est a dire environs 2400 secondes.
(Pour les tests, j'ai utilisé la fonction ##dm_settime x x x x qui "vide" apparement (en executant) les queues d'actions de tout ce qui aurait dû s'executer avant la nouvelle heure.)
 
Revenir en haut Voir le profil de l'utilisateur Envoyer un message privé Visiter le site web du posteur MSN Messenger Ignorer l'utilisateur
 
lendraste
Grand Maître Chanteur du Conseil
Inscrit le: 20 Fév 2003
Messages: 1403
Localisation: Quelque part ailleurs
Répondre en citant
Posté le : 16/03/2004 15:32:40 Sujet du message :


Mr-XXS a écrit :
Apres tests, le ActionWait semble avoir une limite de 40 minutes, a 41 minutes, ca ne marche plus. C'est a dire environs 2400 secondes.
(Pour les tests, j'ai utilisé la fonction ##dm_settime x x x x qui "vide" apparement (en executant) les queues d'actions de tout ce qui aurait dû s'executer avant la nouvelle heure.)
Merci pour cette information très intéressante. J'étais justement en train d'intégrer mes dernières fonctions d'attentes dans mon système, je vais pouvoir ajouter une gestion de cette contrainte pour les longues durées Smile
_________________
Lendraste de Loreval
Qui cherche la Vérité cherche celui qui la détient, car elle n'existe pas à l'état naturel.
La cité des mensonges - 1
 
Revenir en haut Voir le profil de l'utilisateur Envoyer un message privé MSN Messenger Numéro ICQ Ignorer l'utilisateur
 
olfleouf
Acolyte
Inscrit le: 21 Nov 2003
Messages: 35
Répondre en citant
Posté le : 20/03/2004 22:43:04 Sujet du message :

Bravo pour ce sujet très interessant et instructif, c'est dingue tout les trucs que l'on peut apprendre sur un tel post Very Happy

J'aurais cependant quelques questions à poser en tant que gros débutant, car si le principe des queus d'action m'intéresse beaucoup je me vois mal pour l'instant l'utiliser car j'y connais pas grand chose Confused

Par exemple combien de temps dur chaque action? Si on met un ActionAttack, combien faut-il de temps pour qu'il passe à l'action suivante? De même pour les autres, il attend quelle soit finie? Pour les actions à temps variable (combat), comment le jeu gère-t-il tout ca?

Ainsi est-il possible d'obliger un pj à exécuter la même action durant un temps précis, sans delaycommand? (avec l'exemple de le faire attaquer durant 3 round, ce que je ne parviens pas à faire).

Je précise que j'ai essayé de faire cela avec des créatures vidés des scripts se déclenchant automatiquement (oHB, onPerception)
 
Revenir en haut Voir le profil de l'utilisateur Envoyer un message privé Visiter le site web du posteur Ignorer l'utilisateur
 
lendraste
Grand Maître Chanteur du Conseil
Inscrit le: 20 Fév 2003
Messages: 1403
Localisation: Quelque part ailleurs
Répondre en citant
Posté le : 21/03/2004 12:18:35 Sujet du message :


olfleouf a écrit :
Par exemple combien de temps dur chaque action? Si on met un ActionAttack, combien faut-il de temps pour qu'il passe à l'action suivante? De même pour les autres, il attend quelle soit finie? Pour les actions à temps variable (combat), comment le jeu gère-t-il tout ca?

Ainsi est-il possible d'obliger un pj à exécuter la même action durant un temps précis, sans delaycommand? (avec l'exemple de le faire attaquer durant 3 round, ce que je ne parviens pas à faire).
ActionAttack est une action assez chiante à gérer puisqu'elle s'empare de la queue d'action sans vraiment laisser la possibilité d'en reprendre le contrôle à moins qu'un évènement extérieur le permette, c'est-à-dire en la forçant à se vider par ClearAllActions(TRUE). Je n'ai donc pas trouvé, à ce jour, d'autres moyens de forcer mon système à reprendre le contrôle de la queue d'action que m'appuyer sur un DelayCommand (qui semble pour la circonstance, la solution la plus simple à défaut d'être la plus fiable). Je suis en train de réfléchir à l'utilisation d'une autre queue d'action dite "pilote" pour accomplir la même chose, l'idée étant d'interrompre les actions virtuellement infinie pour demander au programme d'action de reprendre. Je n'ai pas encore creusé la question, mais je ne suis pas sûr qu'une ActionAttack autorise la reprise normale d'une activité stockée dans la queue d'action lorsqu'elle se termine "normalement".
Je ne peux donc entièrement répondre à ta question pour l'heure et dans les jours suivants car je suis trop occupé sur un autre sujet pour me plonger dedans. J'espère que quelqu'un d'autre le pourra.
_________________
Lendraste de Loreval
Qui cherche la Vérité cherche celui qui la détient, car elle n'existe pas à l'état naturel.
La cité des mensonges - 1
 
Revenir en haut Voir le profil de l'utilisateur Envoyer un message privé MSN Messenger Numéro ICQ Ignorer l'utilisateur
 
nunch
Grand Sage du Conseil
Inscrit le: 23 Mai 2003
Messages: 966
Localisation: Dans la gueule du Lyon
Répondre en citant
Posté le : 18/06/2004 22:20:51 Sujet du message :

Je me permets une petite nécromancie pour proposer une réflexion sur une solution aux DelayCommand().
Actuellement le jeu est limité en nombre de DelayCommand() simultanés. Quand la limite est atteinte, tout nouveau DelayCommand() rencontré est ignoré.
Sur mon module, qui utilise l'ATS, le DelayCommand() est utilisé pour recréer les blocs de minerai à différents endroits. Ces blocs étant un certain nombre, j'ai pu effectivement atteindre rapidement la limite du jeu et certains blocs ne sont donc jamais créés.
J'ai tenté de m'inspirer du principe de la queue d'actions infinie pour résoudre le problème. Attention, ce que je propose est limité et n'a été que légèrement testé; je ne sais donc pas encore tous les problèmes qui pourraient survenir avec cette solution.

Le principe est de coder les commandes avec leurs paramètres sous forme de chaîne de texte dans une variable locale à un objet. Cette chaîne peut contenir plusieurs commandes à la suite, et chaque commande a un délai associé.
Sur l'objet, une fonction spéciale (ExecuteNextCommand() - sous forme d'action dans la queue) fait les opérations suivantes:
- elle recupère la chaîne de commandes dans la variable locale
- elle examine le délai de chaque commande
- si le délai d'une commande est supérieur à 0, alors le délai est diminué de 1 et la commande est réencodée avec le nouveau délai.
- si le délai d'une commande est égal à 0 alors la commande est exécutée et n'est pas remise dans la chaine.
- la nouvelle chaîne de commandes est replacée dans la variable locale.
- une action d'attente d'une seconde est placée dans la queue d'actions de l'objet
- la fonction spéciale se replace elle-même dans la queue d'actions (ainsi elle est appelée en boucle de façon infinie).

J'ai également écrit une deuxième fonction (AddCommandToQueue()) qui sert à ajouter une commande à la chaine de commandes et ceci de façon atomique. Cette fonction doit donc être placée dans la queue d'actions du même objet que celui utilisé précédemment.
Enfin, j'ai deux autres fonctions: une pour encoder une commande donnée, et une pour la décoder (CreateObject).

Voici les scripts. J'ai décidé d'appeler l'objet qui gère et exécute les actions "Maître du Temps", abrégé MDT, resref "maitredutemps".

NWScript :
//---------------------------- ------------------------------ -------------------
// Script des definitions de variables et fonctions pour le Maitre du Temps
//---------------------------- ------------------------------ -------------------
// Le Maitre du Temps cherche des commandes a executer dans une queue a interv-
// alles reguliers. Chaque commande peut avoir un delai d'attente avant son ex-
// ecution.
// * Si le Maitre du Temps selectionne une commande dont le delai n'est pas
// ecoule, alors la commande est replacee a la fin de la queue avec un temps d'
// attente diminue d'une valeur arbitraire (generalement 1).
// * Si le Maitre du Temps selectionne une commande dont le delai est a zero,
// alors il l'execute et la supprime de la queue.
// * En resume, le Maitre du Temps palie a la limitation des DelayCommand().
//---------------------------- ------------------------------ -------------------
#include "nw_i0_plot"

// Il s'ecoulera X seconde(s) entre chaque parcours de la liste des commandes
const float VB_MDT_WAIT_TIME = 1.0;

// Nom de la variable contenant la queue de commandes
const string VB_MDT_QUEUE = "VB_MDT_QUEUE";
const string VB_MDT_TAG = "maitredutemps";
const string VB_MDT_RESREF = "maitredutemps";

// Format d'une commande dans la queue:
// Nom de la fonction a executer;Delai en secondes;Parametre 1;...;Parametre n;
// Exemple: CreateObject;10;1;kobold;WP_SP AWN_KOBOLD;

// Format de la queue:
// Commande 1*Commande 2*...*Commande n-1*Commande n*
// Exemple: CreateObject;10;1;kobold;WP_SP AWN_KOBOLD;*CreateObject;5;1;g oblin;WP_SPAWN_GOBLIN;1;new_go blin;*

// Les parametres de type location ne peuvent etre utilises que si cette
// location correspond a un waypoint. Dans ce cas c'est le tag du waypoint qui
// est utilise.

//---------------------------- ------------------------------ -------------------
// Commandes supportees
//---------------------------- ------------------------------ -------------------

// EncodeCreateObject
string EncodeCreateObject(int nDelay, int nObjectType, string sTemplate,
                          string sTagLocation, int bUseAppearAnimation=FALSE,
                          string sNewTag="")
{
    string EncodedFunction = "CreateObject;";

    EncodedFunction = EncodedFunction + IntToString(nDelay) + ";";
    EncodedFunction = EncodedFunction + IntToString(nObjectType) + ";";
    EncodedFunction = EncodedFunction + sTemplate + ";";
    EncodedFunction = EncodedFunction + sTagLocation + ";";
    EncodedFunction = EncodedFunction + IntToString(bUseAppearAnimation) + ";";
    EncodedFunction = EncodedFunction + sNewTag + ";";

    return EncodedFunction;
}

// DecodeCreateObject
void DecodeCreateObject(string sParameters)
{
    int nNextParameter = 0;
    int nStringLength = GetStringLength(sParameters);

    // Premier parametre
    nNextParameter = FindSubString(sParameters, ";");
    int sObjectType = StringToInt(GetStringLeft(sParameters, nNextParameter));
    nStringLength = nStringLength - (nNextParameter+1);
    sParameters = GetStringRight(sParameters, nStringLength);

    // Second parametre
    nNextParameter = FindSubString(sParameters, ";");
    string sTemplate = GetStringLeft(sParameters, nNextParameter);
    nStringLength = nStringLength - (nNextParameter+1);
    sParameters = GetStringRight(sParameters, nStringLength);

    // Troisieme parametre
    nNextParameter = FindSubString(sParameters, ";");
    string sTagLocation = GetStringLeft(sParameters, nNextParameter);
    location lLocation = GetLocation(GetWaypointByTag(sTagLocation));
    nStringLength = nStringLength - (nNextParameter+1);

    // Quatrieme parametre
    int bUseAppearAnimation = FALSE;
    if(nStringLength > 0)
    {
        sParameters = GetStringRight(sParameters, nStringLength);
        nNextParameter = FindSubString(sParameters, ";");
        bUseAppearAnimation = StringToInt(GetStringLeft(sParameters, nNextParameter));
        nStringLength = nStringLength - (nNextParameter+1);
    }

    // Cinquieme parametre
    string sNewTag = "";
    if(nStringLength > 0)
    {
        sParameters = GetStringRight(sParameters, nStringLength);
        nNextParameter = FindSubString(sParameters, ";");
        sNewTag = GetStringLeft(sParameters, nNextParameter);
    }

    CreateObject(sObjectType, sTemplate, lLocation, bUseAppearAnimation, sNewTag);
}

//---------------------------- ------------------------------ -------------------
// Fonctions de gestion de la queue
//---------------------------- ------------------------------ -------------------

// AddCommandToQueue
void AddCommandToQueue(string sCommand)
{
    string sQueue = GetLocalString(OBJECT_SELF,VB_MDT_QUEUE);
    sQueue = sQueue + sCommand + "*";
    SetLocalString(OBJECT_SELF,VB_MDT_QUEUE,sQueue);
}

// ExecuteNextCommand
void ExecuteNextCommand()
{
    string sQueue = GetLocalString(OBJECT_SELF,VB_MDT_QUEUE);
    string sNewQueue = "";
    string sCommand = "";
    string sNewCommand = "";
    int nNextCommand = 0;
    int nQueueLength = GetStringLength(sQueue);

    while(nQueueLength > 0)
    {
        nNextCommand = FindSubString(sQueue, "*");
        sCommand = GetStringLeft(sQueue, nNextCommand);
        // Analyse de la commande, decompte du delai
        {
            int nNextParameter = 0;
            int nCommandLength = GetStringLength(sCommand);
            int nDelai;
            string sFunction = "";

            // Lecture de la fonction
            nNextParameter = FindSubString(sCommand, ";");
            sFunction = GetStringLeft(sCommand, nNextParameter);
            nCommandLength = nCommandLength - (nNextParameter+1);
            sCommand = GetStringRight(sCommand, nCommandLength);
            // Lecture du delai
            nNextParameter = FindSubString(sCommand, ";");
            nDelai = StringToInt(GetStringLeft(sCommand, nNextParameter));
            nCommandLength = nCommandLength - (nNextParameter+1);
            sCommand = GetStringRight(sCommand, nCommandLength);
            // Traitement du delai
            if(nDelai==0)
            {
                if(sFunction=="CreateObject")
                    DecodeCreateObject(sCommand);
            }
            else
            {
                nDelai = nDelai - 1;
                sNewCommand = sFunction + ";" + IntToString(nDelai) + ";" + sCommand;
                sNewQueue = sNewQueue + sNewCommand + "*";
            }
        }
        nQueueLength = nQueueLength - (nNextCommand+1);
        sQueue = GetStringRight(sQueue, nQueueLength);
    }

    SetLocalString(OBJECT_SELF,VB_MDT_QUEUE,sNewQueue);

    AssignCommand(OBJECT_SELF,ActionWait(VB_MDT_WAIT_TIME));
    AssignCommand(OBJECT_SELF,ActionDoCommand(ExecuteNextCommand()));
}

// void main() { }
Note : le code affiché ci-dessus n'est pas rendu tel qu'il devrait l'être réellement, en particulier des sauts de lignes sont automatiquement insérés pour éviter de casser la mise en page. En le copiant/collant, vous résoudrez ce problème.


A la création du MDT, le script OnSpawn amorçe la pompe:
NWScript :
//---------------------------- ------------------------------ -------------------
// Script OnSpawn du Maitre du Temps
//---------------------------- ------------------------------ -------------------
#include "vb_mdt_inc"

void main()
{
    ActionDoCommand(SetLocalString(OBJECT_SELF,VB_MDT_QUEUE,""));
    ActionDoCommand(ExecuteNextCommand());
    ActionWait(5.0);
    string sCommand = EncodeCreateObject(10,OBJECT_TYPE_CREATURE,"test_mdt","WP_TEST_MDT");
    ActionDoCommand(AddCommandToQueue(sCommand));
}
Note : le code affiché ci-dessus n'est pas rendu tel qu'il devrait l'être réellement, en particulier des sauts de lignes sont automatiquement insérés pour éviter de casser la mise en page. En le copiant/collant, vous résoudrez ce problème.


Enfin, voici ce que pourrait faire un autre objet pour ajouter des commandes à la queue:
NWScript :
#include "vb_mdt_inc"

void main()
{
object oMaitreDuTemps = GetObjectByTag(VB_MDT_TAG,0);

string sCommand = EncodeCreateObject(20,OBJECT_TYPE_CREATURE,"test_mdt","WP_TEST_MDT",FALSE,"test1");
AssignCommand(oMaitreDuTemps,ActionDoCommand(AddCommandToQueue(sCommand)));

sCommand = EncodeCreateObject(20,OBJECT_TYPE_CREATURE,"test_mdt","WP_TEST_MDT",FALSE,"test2");
AssignCommand(oMaitreDuTemps,ActionDoCommand(AddCommandToQueue(sCommand)));

ActionWait(10.0);
ActionDoCommand(DestroyObject(OBJECT_SELF));
}
Note : le code affiché ci-dessus n'est pas rendu tel qu'il devrait l'être réellement, en particulier des sauts de lignes sont automatiquement insérés pour éviter de casser la mise en page. En le copiant/collant, vous résoudrez ce problème.


Dans ce cas, l'objet place 2 créations de créatures dans la chaine avec un délai de 20 secondes, il attend 10 secondes et se détruit. Ca a pour effet de faire se démultiplier les objets (un, puis deux, quatre, huite, etc.). C'est intéressant à voir mais à terme ça fait ramer la machine (la mienne en tout cas).

Je peux fournir le module d'exemple qui contient les scripts ci-dessus. Demandez-le moi en MP avec votre e-mail mais n'esperez pas une réponse très rapide (je serai absent du 21/06 au 23/06).
Pour lancer le module de test:
- Lancer le jeu en tant que Client MJ
- Créer une nouvelle partie Multijoueur avec le module. Vous êtes donc MJ.
- Créer le Maître du Temps en le sélectionnant dans l'arborescence des objets (créatures/personnalisés/spéciale/personnalisé 1/Maitre du Temps) et le placer à côté de soi dans la zone.
- Patientez quelques secondes et vous verrez des nains apparaître et se démultiplier. Dans la fenêtre des dialogues, j'affiche à chaque nouvelle seconde la chaine de commandes.

J'attends vos réactions. Pour l'instant la plus grosse limitation de cette méthode est la gestion des commandes avec des paramètres de type object ou location, qui ne peuvent pas être encodés en texte comme on peut le faire avec les int avec la fonction IntToString().
 
Revenir en haut Voir le profil de l'utilisateur Envoyer un message privé Visiter le site web du posteur MSN Messenger Ignorer l'utilisateur
 
lendraste
Grand Maître Chanteur du Conseil
Inscrit le: 20 Fév 2003
Messages: 1403
Localisation: Quelque part ailleurs
Répondre en citant
Posté le : 18/06/2004 23:20:05 Sujet du message :


nunch a écrit :
J'attends vos réactions. Pour l'instant la plus grosse limitation de cette méthode est la gestion des commandes avec des paramètres de type object ou location, qui ne peuvent pas être encodés en texte comme on peut le faire avec les int avec la fonction IntToString().
Nécromancie fort à propos. Ca me rappelle d'ailleurs que je voulais "post-iter" ce sujet. Merci.

Pour ce qui est de réagir à ta solution pardonne moi si je ne te donne pas de réponse immédiate. Je ne l'ai pas lu en détail. En revanche je réponds au problème que tu évoques et que j'ai pallié depuis assez longtemps. On peut parfaitement utiliser des chaines et des valeurs numérique pour faire référence à des objets ou des locations. Il convient juste de retenir qu'on ne peut le faire de manière directe. Mais pour l'exemple, un tag qui est un chaine de caractère est en gééral suffisant pour retrouver un objet grace à des commandes comme GetObjectByTag ou GetNearestObjectByTag. On pourrait aussi se débrouiller pour sauvergarder un objet par un GetLocalObject ou un RetrieveCampaignObject pour peu qu'on l'ait préalablement sauvé. Mais dans ce cas la chaine du nom de la variable est suffisante, à condition d'avoir à notre disposition une référence à un objet ou se trouve cette variable (à moins de faire systématiquement référence à GetModule).
Pour les locations c'est un peu la même chose. Une chaine pour désigner le tag de la zone, les coordonnées X, y et z en float ainsi que le facing et hop, on peut reconstruire une location.

Ma solution actuelle intègre un jeu de commandes qui me permet de désigner un objet ou une location en utilisant ces technique là. Parmi ce que j'ai dit se trouve d'ailleurs une idée nouvelle à laquelle je n'avais pas pensé et dont je risque d'avoir besoin bientôt, l'utilisation des variables locales et de campagne.

Globalement, je ne pense pas qu'il y ait de problème majeur à mettre tout cela en place Smile . Mais déjà, tu as fait, ce me semble, du beau travail Wink
_________________
Lendraste de Loreval
Qui cherche la Vérité cherche celui qui la détient, car elle n'existe pas à l'état naturel.
La cité des mensonges - 1
 
Revenir en haut Voir le profil de l'utilisateur Envoyer un message privé MSN Messenger Numéro ICQ Ignorer l'utilisateur
 
nunch
Grand Sage du Conseil
Inscrit le: 23 Mai 2003
Messages: 966
Localisation: Dans la gueule du Lyon
Répondre en citant
Posté le : 20/06/2004 16:37:32 Sujet du message :


Citation :
Pour ce qui est de réagir à ta solution pardonne moi si je ne te donne pas de réponse immédiate. Je ne l'ai pas lu en détail. En revanche je réponds au problème que tu évoques et que j'ai pallié depuis assez longtemps. On peut parfaitement utiliser des chaines et des valeurs numérique pour faire référence à des objets ou des locations. Il convient juste de retenir qu'on ne peut le faire de manière directe.
Alors là tu m'intéresse beaucoup. Parce que si l'un des paramètres d'une commande est un type object représentant un PJ, on ne peut pas le remplacer par une chaine de TAG.


Citation :
Ma solution actuelle intègre un jeu de commandes qui me permet de désigner un objet ou une location en utilisant ces technique là. Parmi ce que j'ai dit se trouve d'ailleurs une idée nouvelle à laquelle je n'avais pas pensé et dont je risque d'avoir besoin bientôt, l'utilisation des variables locales et de campagne.
Je suis impatient de voir ce que tu as fait. Smile


Citation :
Globalement, je ne pense pas qu'il y ait de problème majeur à mettre tout cela en place Smile . Mais déjà, tu as fait, ce me semble, du beau travail Wink
Merci! Quand j'aurais à nouveau un peu de temps, je verrais si je ne peux pas améliorer ce que j'ai fait.
Sinon j'ai fait quelques tests supplémentaires, notamment pour les besoins de mon module. Au chargement, j'enchaine plus de 80 commandes dans la queue à la suite (ce qui correspond aux créations de blocs de minerais), chacune devant être ensuite executée à une seconde d'intervalle. Ca se déroule à peu près correctement mais du temps est tout de même perdu dans le décodage et le traitement des chaînes de caractère, ce qui peut être gênant sur des machines lentes ou quand il y a encore plus de commandes simultanées. Donc comme je le disais, à améliorer.
 
Revenir en haut Voir le profil de l'utilisateur Envoyer un message privé Visiter le site web du posteur MSN Messenger Ignorer l'utilisateur
 
Montrer les messages depuis :
Page 2 sur 2 ¤ Aller à la page Précédente  1, 2


Vous ne pouvez pas poster de nouveaux sujets dans ce forum
Vous ne pouvez pas répondre aux sujets dans ce forum
Vous ne pouvez pas éditer vos messages dans ce forum
Vous ne pouvez pas supprimer vos messages dans ce forum
Vous ne pouvez pas voter dans les sondages de ce forum


Sauter vers:
FAQ | Rechercher | Liste des Membres | Groupes d'utilisateurs | S'enregistrer | Profil | Se connecter pour vérifier ses messages privés | Connexion
Powered by phpBB 2.* [m] © 2001, 2002 phpBB Group
Theme rewritten in beautiful XHTML code by Baldurien.
Thème "La Bibliothèque de Neverwinter" crée par Kruger
Traduction par : phpBB-fr.com
Page generated in 34.86ms