Bienvenue sur JeuxOnLine - MMO, MMORPG et MOBA !
Les sites de JeuxOnLine...
 

Panneau de contrôle

Recherche | Retour aux forums

JOL Archives

[NWScript]Système de conversation par mot-clef (long)

Par Machin le 6/7/2002 à 3:47:44 (#1766152)

Bon, voila, j'ai terminé le script permettant de reproduire une conversation grâce à des mots-clef. Ca à l'air de marcher correctement.

J'ai mis ca sous la forme d'un fichier à inclure.


Pour les explications voire après :)




//::///////////////////////////////////////////////
//:: Name Systeme de conversation par mot-clef
//:: FileName st_kwconv
//:://////////////////////////////////////////////
/*
Fichier a inclure dans les scripts

Les fonctions proposees permettent de reproduire un systeme
de conversation par mot-clef, de maniere similaire a T4C par
exemple.

Bugs/Problemes connus :
- Impossible de mettre d'accents dans les textes
- La discution est possible meme quand le jeu est en mode pause


Remarques toujours bienvenues :)
fedaril@yahoo.com
*/
//:://////////////////////////////////////////////
//:: Created By: Fed(Machin)
//:: Created On: 26/06/2002
//:://////////////////////////////////////////////

/*****************
*** constantes ***
*****************/

// distance maximale entre un PJ et le PNJ pour pouvoir discuter
float MAX_DISTANCE = 10.0f;
// nombre de rounds au-dela desquels un time-out survient
int ROUND_TIMEOUT = 2;



/*******************************
*** prototypes des fonctions ***
*******************************/

/*
* Ajoute un mof-clef. Ce mot clef sera ensuite reconnu par le PNJ
* Rqs :
* - Toutes les valeurs doivent etre differentes
* - Il ne faut utiliser que des valeurs superieures a 10, pour
* eviter d'interferer avec le systeme de conversation par defaut des PNJs, et
* differentes de 1000 et 1001, ces deux valeurs etant reservees pour
* des usages internes (voir fonction DoKeyWordDiscution)
* - L'ordre est important. L'existence de mots-clef est testee dans le meme
* ordre que leur definition
*/
void AddKeyWord(string sKeyWord, int nValue, object oPNJ = OBJECT_SELF);


/*
* Initialise le systeme de conversation
*/
void InitKeyWordConversation(object oPNJ = OBJECT_SELF);

/*
* Termine la conversation en cours
* Doit etre appele une fois tous les mots-clef definis
*/
void EndKeyWordConversation(object oPNJ = OBJECT_SELF);

/*
*
* fonction a executer lorsqu'un evenement onConversation survient
* Idealement place dans les evenements definis par l'utilisateur
* Valeurs de retour :
* - Si la dicussion viens juste d'etre engagee, retourne 1000
* - Si un mot clef a ete reconnu, alors retourne la valeur associee
* a ce mot clef
* - Si aucun mot-clef n'est reconnu, retourne 1001
*/
int DoKeyWordConversation(object oPNJ = OBJECT_SELF);


/*
* Retourne l'objet du PJ en discution
*/
object GetPCSpeakWith(object oPNJ = OBJECT_SELF);



/*
* Fonction a executer lorsqu'un evenement onHeartBeat survient
* Idealement place dans les evenements definis par l'utilisateur
* Assure la detection de time-out lors de la discution (si un PJ
* ne dit rien pendant un certain temps) et du depart du PJ (si ce dernier
* s'eloigne trop du PNJ)
* Valeurs de retour :
* - 0 si aucune conversation n'est en cours
* - 1 si une conversation est en cours
* - 2 si un time-out a ete detecte
* - 3 si le depart du PJ a ete detecte
*/
int DoHeartBeatKeyWordConversation(object oPNJ = OBJECT_SELF);



/************************************
*** implementations des fonctions ***
************************************/


void AddKeyWord(string sKeyWord, int nValue, object oPNJ = OBJECT_SELF)
{
SetListenPattern(oPNJ, "**" + sKeyWord + "**", nValue);
}

void InitKeyWordConversation(object oPNJ = OBJECT_SELF)
{
SetLocalObject(oPNJ, "oInterlocuteur", OBJECT_INVALID);

// par forcement necessaire
SetListening(oPNJ, TRUE);
SetListenPattern(oPNJ, "**", 1001);
}

void EndKeyWordConversation(object oPNJ = OBJECT_SELF)
{
object oInterlocuteur = GetLocalObject(oPNJ, "oInterlocuteur");

DeleteLocalInt(oInterlocuteur, "bEnConversation");

SetLocalObject(oPNJ, "oInterlocuteur", OBJECT_INVALID);
DeleteLocalInt(oPNJ, "nRoundCout");
}

int DoKeyWordConversation(object oPNJ = OBJECT_SELF)
{
object oSpeaker = GetLastSpeaker();
object oCurrentSpeaker = GetLocalObject(oPNJ, "oInterlocuteur");
int nPattern = GetListenPatternNumber();

//SendMessageToPC(oSpeaker, "GetKeyWordValue : " + IntToString(nPattern));

// -1 signifie que la conversation a ete engagee par un click d'un joueur sur l'objet
if (nPattern == -1)
{
if (!GetIsObjectValid(oCurrentSpeaker))
{
// verifie l'etat du flg en conversartion
// note : par defaut, si la variable n'existe pas, FAUX (=0)
// est retourne
if (!GetLocalInt(oSpeaker, "bEnConversation"))
{
SetLocalInt(oSpeaker, "bEnConversation", TRUE);
SetLocalObject(oPNJ, "oInterlocuteur", oSpeaker);

// initialise le compteur de round
SetLocalInt(oPNJ, "nRoundCount", 0);

// le PNJ fait face au PJ
SetFacingPoint(GetPosition(oSpeaker));

// et le salue
return 1000;
} else
{
FloatingTextStringOnCreature("Vous etes deja en discution avec quelqu'un", oSpeaker, FALSE);
}
} else
{
if (oCurrentSpeaker == oSpeaker)
{
FloatingTextStringOnCreature("Vous etes deja en discution avec cette personne", oSpeaker, FALSE);
} else
{
FloatingTextStringOnCreature("La personne est occupee", oSpeaker, FALSE);
}
}
} else
{
if (oCurrentSpeaker == oSpeaker)
{
// reinitialise le compteur de round
//SendMessageToPC(oSpeaker, "en conversation");
SetLocalInt(oPNJ, "nRoundCount", 0);
} else
{
//SendMessageToPC(oSpeaker, "hors conversation");
return -1;
}
}

return nPattern;
}

object GetPCSpeakWith(object oPNJ = OBJECT_SELF)
{
return GetLocalObject(oPNJ, "oInterlocuteur");
}

int DoHeartBeatKeyWordConversation(object oPNJ = OBJECT_SELF)
{
object oCurrentSpeaker = GetLocalObject(oPNJ, "oInterlocuteur");

if (GetIsObjectValid(oCurrentSpeaker))
{
int nNbRound = GetLocalInt(oPNJ, "nRoundCount");

//SendMessageToPC(oCurrentSpeaker, "NbRound = " + IntToString(nNbRound));

if (nNbRound > ROUND_TIMEOUT)
{
return 2;
} else
if (GetDistanceBetween(oPNJ, oCurrentSpeaker) > MAX_DISTANCE)
{
return 3;
} else
{
//SendMessageToPC(oCurrentSpeaker, "Incrementing NbRound");

SetLocalInt(oPNJ, "nRoundCount", nNbRound + 1);

return 1;
}
}

return 0;
}





Le système intervient pendant trois événements :

- OnSpawn : ou sont faites les initialisations nécessaires (AddKeyWord et InitKeyWordConversation)
- OnConversation : declenché à chaque fois que le PNJ entendra quelquechose (grâce a SetListening(TRUE)). Ici il s'agit de savoir ce que le PNJ à entendu et de réaliser les traitements voulus (lui faire prononcer une réponse, par exemple). Les fonctions utiles ici sont DoKeyWordConversation et GetPCSpeakWith
- OnHeartBeat : ou sont vérifiées deux choses : que le PJ ne s'éloigne pas trop du PNJ, et que le PJ parle régulierement au PNJ. Le seule fonction utile dans ce cas est DoHearBeatKeyWordConversation


Vu que je parie que tout ca n'est pas trop clair (jamais été trop doué pour les expliquer les choses) voici un petit exemple de mise en oeuvre. Il s'agit d'un PNJ qui pose une énigme au PJ et qui le félicite s'il donne la bonne réponse.


Evénement OnSpawn :


#include "NW_I0_GENERIC"

#include "st_kwconv"

void main()
{
SetSpawnInCondition(NW_FLAG_HEARTBEAT_EVENT);
SetSpawnInCondition(NW_FLAG_ON_DIALOGUE_EVENT);

SetListeningPatterns();
WalkWayPoints();

AddKeyWord("Au revoir", 1005);
AddKeyWord("Adieu", 1006);
AddKeyWord("Enigme", 1007);
AddKeyWord("Oui", 1008);
AddKeyWord("Miroir", 1009);
AddKeyWord("Non", 1010);

InitKeyWordConversation();

}



Evénement OnUserDefined :



#include "st_kwconv"

void main()
{
int n = GetUserDefinedEventNumber();


switch (n)
{
// HEARTBEAT
case 1001:
{
int n = DoHeartBeatKeyWordConversation();

switch (n)
{
case 2:
SpeakString("Vous semblez avoir mieux a faire, je vous laisse donc. Au revoir");
EndKeyWordConversation();
break;

case 3:
SpeakString("Ne me saluez surtout pas, malotru !", TALKVOLUME_SHOUT);
EndKeyWordConversation();
break;
}
}
break;

// CONVERSATION
case 1004:
{
int nPattern = DoKeyWordConversation();

if (nPattern != -1)
{
switch(nPattern)
{
// Au revoir & Adieu
case 1005:
case 1006:
ActionSpeakString("Au revoir");
// termine la dicution
EndKeyWordConversation();
break;

// Oui & Enigme
case 1007:
case 1008:
ActionSpeakString("Ecoutez bien : Je reflechis, mais je ne pense pas. Qui suis-je ?");
break;

// Miroir
case 1009:
ActionSpeakString("Bravo, vous etes brillant mon ami");
break;

// non
case 1010:
ActionSpeakString("Arretez donc de me faire perdre mon temps dans ce cas!");
EndKeyWordConversation();
break;

// conversation engagee
case 1000:
ActionSpeakString("Salutations, aventurier. Vous etes venu pour l'enigme?");
break;


// mot-clef inconnu
case 1001:
ActionSpeakString("Je ne comprends pas ce que vous dites");
break;
}
}
}
break;
}
}




PS : Désolé, n'ayant pas possibilité d'hébergement, j'ai du vous le copier/coller directement...

Edit : mise à jour du script

Par Lumina le 6/7/2002 à 7:07:20 (#1766365)

Merci Machin !
Super !

Par Kray le 6/7/2002 à 7:50:13 (#1766399)

Vraiment excellentissime... J'applaudis... Pour les accents, je vois pas trop le problème en fait :doute:

Pour le PJ qui parle à deux PNJs, on peut faire... Hum.

Sur OnConversation de chaque PNJ:

void main()
{
object oPC = GetPCSpeakWith(OBJECT_SELF);
string sPrefixe = "IS_ON_DIAL_";
SetLocalInt(oPC,sPrefixe+GetName(oPC),1);
}
Dans la fonction EndKeyWordConversation() :
void EndKeyWordConversation(object oPNJ = OBJECT_SELF)
{
object oPC = GetPCSpeakWith(OBJECT_SELF);
string sPrefixe = "IS_ON_DIAL_";
SetLocalInt(oPC,sPrefixe+GetName(oPC),0);
SetLocalObject(oPNJ, "oInterlocuteur", OBJECT_INVALID);
DeleteLocalInt(oPNJ, "nRoundCout");
}
Et enfin un test sur la variable IS_ON_DIAL_Name sur le OnUserDefined... Nan? C'est juste une idée :doute:

Et je suis fatigué aussi :baille:

Par Gargantuel le 6/7/2002 à 10:27:37 (#1766651)

Pour les accents il y a une solution.

Effectivement on ne peut pas taper d'accent dans l'éditeur mais ouvrez notepad, tapez votre texte avec vos accents et faites un copier-coller dans l'éditeur.

Y a par a dire, ce script est super. Ca me rappelle Ultima Online *nostalgie* :)

Par Nikkau le 6/7/2002 à 10:54:28 (#1766716)

Bravo, t'as dut y passer un peu de temps quand même mais ça valait le coup :)

Par Machin le 7/7/2002 à 0:18:33 (#1769843)

Merci pour vos commentaires, ca fait plaisir :)
J'y ai passe un bon moment en effet, mais c'est le meilleur moyen d'apprendre ;)
Quand aux accents, j'ai lu quelque part sur ce forum qu'il était déconseillé d'en utiliser. Ca amène quelques bugs étranges.
Je ne prefere pas jouer avec le feu pour le moment, et attendre un eventuel patch.


J'en ai profité pour apporter une modification qui empeche les PJs d'entrer en discution avec plusieurs PNJs.

J'ai aussi remarqué un autre bug plus ennuyant : les PNJs réagissent même lorsque le jeu est en pause. Et visiblement, il n'y a aucun moyen de savoir si le jeu est en pause au moment de l'execution du script.

Par Caepolla le 7/7/2002 à 3:11:53 (#1770290)

Impresionnant. Merci beaucoup. :)

JOL Archives 1.0.1
@ JOL / JeuxOnLine