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

Panneau de contrôle

Recherche | Retour aux forums

JOL Archives

[Script] Barmaid

Par Daynos le 14/10/2002 à 14:36:39 (#2333370)

Posté par [xkill]sniper!

Bonjour,
Voici un autre script de Barmaid qui ne fonctionne pas trop mal.
Il est basé sur un script posté sur http://nwn.lyoness.com/files/scripts/barmaidscript2.txt
Je travaille encore à son amélioration. En fait, à la base c'était aussi un exercice de "scripting" pour découvrir les subtilités de ce beau langage.....

Tout d'abord, vous creez une Taverne. Puis vous y placez une serveuse (ou un serveur !). Vous modifiez le script OnSpanw pour déclencher le HeartBeat (1001) et Conversation(1004)
Vous placez des chaises que vous nommez "Chair" (ou autrement si vous le souhaitez, mais il faudra modifier le script à un endroit.

Ensuite, vous placez ce script dans le UserDefined de la serveuse.
Vous noterez que les commentaires sont en anglais ! Au début je voulais aussi le poster sur un forum en anglais !

Quelques explications :
Ce script s'éxécute par morceaux. (au rythme des Heartbeat). Si l'éxécution de l'état est un peu longue, j'ajoute un break en fin de case ( le but est d'attendre le prochain heartbeat pour effectuer la suite, d'où le besoin de conserver le contexte)

à chaque état, il sauvegarde son contexte dans des variables locales SetLocalxxxx(...);
à chaque entrée, il relit son état pour continuer la où il s'était arrêté au Heartbeat précédent.
On peut "tuner" le système en regroupant plus ou moins des actions au sein d'une étape. En fait, j'ai l'impression que cela dépend de la taille de la taverne. Si le trajet de la barmaid est long, elle semblera active en permanance, si la piece est petite, les 6 secondes entre chaque Hearbeat vous donneront l'impression qu'elle ne fait rien ! (dans ce cas, regroupez des états)

Comme l'indique le commentaire ci-dessous
La serveuse cherche un client (nème NPC le plus proche)
Vérifie qu'il ne s'agit pas d'un "Barkeeper" (ça marche sans lui ! :-) )
Se déplace vers le client.
Lui demande ce qu'il souhaite consommer (vous pouvez customiser les répliques dans la fonction usr_Rndspeak( int type );
Le client s'assoie (à améliorer !), réponds
La serveuse retourne au bar passer la commande,
Elle revient servir,
Le client remercie


THEORIQUEMENT IL DEVRAIT QUITTER SA CHAISE , MAIS CA MARCHE PAS !!!
Si qqn sait pourquoi ... :-)
c'est la ligne dans le case 7:

AssignCommand( oCustomer ,ActionMoveAwayFromObject(oNearestChair , FALSE , 3.0f) );


Vous pouvez aussi ajouter des répliques pour chaque catégorie de Question/Réponse. (il suffit de changer le random de chaque type de question réponse) et d'ajouter des case ...

Toute remarque ou modification est la bienvenue.

[ le 17/7 : Améliorations apportées au code. En fait, en lisant une très bonne FAQ, j'ai compris ce qui cloche ....
Quand je tape

AssignCommand( oCustomer ,ActionSit( oNearestChair ) );
ActionSpeakString(usr_Rndspeak(1)) ;
// immediatly stores the answer
CustAnswer =usr_Rndspeak(2);
SetLocalString(OBJECT_SELF , "CUSTANSW" ,CustAnswer);
AssignCommand( oCustomer ,SpeakString(CustAnswer) );

J'ai l'impression de séquencer la réponse du customer après celle de la serveuse. Faux ! pour plusieurs raisons.
imaginons que la serveuse a 3 actions dans sa file d'attente. Le ActionspeakString vient en 4 eme position et ne s'éxécute pas de suite. Par contre, le customer est vierge de toute action. Donc, le AssignCommand(oCustomer, ...) (qui ext éxécuté de suite, demande au customer de parler, alors que la serveuse n'a pas encore posé sa question.

Le code "correct" est

// demande au client de s'asseoir (le force !)
AssignCommand( oCustomer ,ActionSit( oNearestChair ) );
// prochaine action de la serveuse, parler
ActionSpeakString(usr_Rndspeak(1)) ;
// immediatly stores the answer
CustAnswer =usr_Rndspeak(2);
SetLocalString(OBJECT_SELF , "CUSTANSW" ,CustAnswer);
// prochaine action de la serveuse : ordonner au client de répondre !
// L'utilisation de ActionDoCommand synchronise le démarrage de l'action du client. -
// idealement, les changements d'etat doivent aussi se faire quand les actions de la serveuse sont terminés donc "enveloppés" dans des ActionDoCommand();
ActionDoCommand( AssignCommand( oCustomer ,SpeakString(CustAnswer) )) ;



Le script modifié le 17-7

//------------------------------------------------------------
// Script de Barmaid.
// Barmaid States
// 0 -> Rnd Walk, wanders for Client.
// 1 -> Client Found . Moves to he nearest (rnd) customer.
// 2 -> Client sits, Ask for Command
// 3 -> Client answers
// 4 -> Moves to the bar to get the Drinks
// 5 -> Announce the comand
// 6 -> Moves back to the custommer to deliver.
// 7 -> Deliver
//------------------------------------------------------------


string usr_Rndspeak( int type );

//----------------------------------------------------------
//
// Main routine.
//
//
//----------------------------------------------------------
object oCustomer; //= GetLocalObject(OBJECT_SELF, "CUSTOMER");
object oBar = GetWaypointByTag("WP_Bar"); //This waypoint is where she gets drinks from

void main()
{
int nRandom;
// Get from context the Last chair seen !
object oNearestChair = GetLocalObject (OBJECT_SELF, "CHAIR" );
object oCustomer = GetLocalObject(OBJECT_SELF, "CUSTOMER");
int state = GetLocalInt(OBJECT_SELF, "BARMAID_STATE");
// customer answer
string CustAnswer= GetLocalString(OBJECT_SELF , "CUSTANSW" );

// Barmaid state from context

// Get the User Defined Event that triggered this script

int nUser = GetUserDefinedEventNumber();

// Debug !
object oPlayer = GetNearestCreature( CREATURE_TYPE_PLAYER_CHAR , PLAYER_CHAR_IS_PC);

SetCommandable(TRUE ,oCustomer);
switch(nUser)
{
case 1001 : // UD HeartBeat

switch( state )
{
case 0 : // Wander for customers

ClearAllActions(); // too many actions ?

oCustomer = GetNearestCreature( CREATURE_TYPE_PLAYER_CHAR, PLAYER_CHAR_NOT_PC, OBJECT_SELF, Random(5));
// SendMessageToPC(oPlayer, "Customer "+ObjectToString(oCustomer));

// search the Nearest Chair from Customer
oNearestChair = GetNearestObjectByTag( "Chair", oCustomer);

// SendMessageToPC(oPlayer, "Chair "+ObjectToString(oNearestChair));
// If Customer Found is Not he barKeeper
// && not him/herself
// && a valid object
// && not already sitted

if ( (oCustomer != GetObjectByTag("Barkeeper")) &&
(oCustomer != OBJECT_SELF) &&
GetIsObjectValid(oCustomer) &&
oCustomer != GetSittingCreature(oNearestChair))
{
// Move to Customer and ask what he/she wants

SetLocalInt (OBJECT_SELF, "BARMAID_STATE", 1);
SetLocalObject (OBJECT_SELF, "CUSTOMER",oCustomer );
SetLocalObject (OBJECT_SELF, "CHAIR",oNearestChair );

SetCommandable(TRUE ,oCustomer);
// Barmaid moves near Customer
}
else
{
// State is still 0 , and no Customer Found.
// Next HeartBeat will find a cusotmer *
ActionRandomWalk();
// SendMessageToPC(oPlayer, "Pas trouve");
return;
}

case 1:
ActionMoveToObject(oCustomer, FALSE,2.0f);
ActionDoCommand( SetLocalInt(OBJECT_SELF, "BARMAID_STATE", 2));

case 2:
// Ask a Rnd question: Type 1
ActionDoCommand( AssignCommand( oCustomer ,ActionDoCommand(ActionSit( oNearestChair )) ));
ActionSpeakString(usr_Rndspeak(1)) ;
// immediatly stores the answer
CustAnswer =usr_Rndspeak(2);
SetLocalString(OBJECT_SELF , "CUSTANSW" ,CustAnswer);
// ce assign command pour synchroniser la question et la reponse.

ActionDoCommand(AssignCommand( oCustomer ,SpeakString(CustAnswer)));
ActionDoCommand(SetLocalInt(OBJECT_SELF, "BARMAID_STATE", 4));

case 4:

ActionDoCommand(ActionMoveToObject(oBar));
ActionDoCommand(SetLocalInt(OBJECT_SELF, "BARMAID_STATE", 5));
// break;
case 5:
ActionDoCommand( ActionSpeakString( "Il me faut "+ CustAnswer));
ActionDoCommand(SetLocalInt(OBJECT_SELF, "BARMAID_STATE", 6));
break; // Waits 6 sec for the command (the next HeartBeat)

case 6:
ActionDoCommand (ActionMoveToObject(oCustomer));
ActionDoCommand (ActionSpeakString( usr_Rndspeak(3)));
ActionPlayAnimation(ANIMATION_PLACEABLE_ACTIVATE,1.0f, 1.0f);
AssignCommand(OBJECT_SELF,SetLocalInt(OBJECT_SELF, "BARMAID_STATE", 7));
break;

case 7: //Type 3 : deliver

// No More Busy !
AssignCommand(OBJECT_SELF,SetLocalInt(OBJECT_SELF, "BARMAID_STATE", 0));

// customer thanks.
// Waits 10 sec & leave the chair !
AssignCommand(OBJECT_SELF,AssignCommand( oCustomer ,SpeakString( usr_Rndspeak(4))));
AssignCommand(OBJECT_SELF,AssignCommand( oCustomer ,ActionWait(2.0f)));
AssignCommand(OBJECT_SELF,AssignCommand( oCustomer ,ActionMoveAwayFromObject(oNearestChair , FALSE , 3.0f)));


break;



} // switch (state)

break; //case 1001

case 1004:
// This is just in here so you can interrupt her if you want to talk to her
SetLocalObject (OBJECT_SELF, "CUSTOMER", OBJECT_INVALID);
SetLocalInt (OBJECT_SELF, "BARMAID_STATE", 0);
break;
}
}



//--------------------------------------------
// user Random Speak string !
//--------------------------------------------
string usr_Rndspeak( int type )
{
string toSpeak =";
int Rnd;
switch ( type )
{
case 1: // barmaid questions
Rnd = Random(3);
switch(Rnd)
{
case 0:
toSpeak = "Que prendrez-vous ?";
break;
case 1:
toSpeak = "Que desirez-vous ?";
break;
case 2:
toSpeak = "Et pour vous ce sera?";
break;
}
break;

case 2: // custommer answer
Rnd = Random(5); // be sure to set n to max case+1
switch(Rnd)
{
case 0:
toSpeak = "Deux bieres bien fraiches";
break;
case 1:
toSpeak = "Une cervelle de singe";
break;
case 2:
toSpeak = "Un roti de sanglier, bien cuit";
break;
case 3:
toSpeak = "Un poulet grille";
break;
case 4:
toSpeak = "Un poulet grille";
break;
}
break;

case 3:
Rnd = Random(4);
switch(Rnd)
{
case 0:
toSpeak = "Tenez, voici votre commande";
break;
case 1:
toSpeak = "Et voila, c'est pret.";
break;
case 2:
toSpeak = "Aussitot commande, aussitot servi";
break;
case 3:
toSpeak = "Vous etes servi";
break;

}
break;

case 4:
Rnd = Random(3);
switch(Rnd)
{
case 0:
toSpeak = "Merci bien";
break;
case 1:
toSpeak = "Ah ! enfin";
break;
case 2:
toSpeak = "Hum... ca a l'air delicieux";
break;
}
break;
}

return toSpeak;
}






Ce que j'ai appris en faisant ce code.

a) Attention au scripts qui durent plus de 6 secondes dans le HeartBeat ! ça fait des trucs bizarres. (problème de réentrance!)
b) SpeakString et ActionSpeakString c'est pas pareil ! SpeakString c'est immédiat , l'autre se place dans la file d'attente du personnage (utile pour synchroniser)
c)
AssignCommand( oCustomer ,SpeakString( usr_Rndspeak(4)) );

fonctionne alors que
AssignCommand( oCustomer ,ActionSpeakString( usr_Rndspeak(4)) );
Non ?!


Voila ! c'est tout.

:)

à mon avis, LA REFERENCE pour tout scripteur :) http://www.reapers.org/nwn/reference/

Posté par Lumina

Par Daynos le 14/10/2002 à 14:39:28 (#2333385)

Pour que le personnage se leve de la chaise, je pense que tu dois faire "ClearAllActions()".

posté par Adalorn

Par Daynos le 14/10/2002 à 14:40:39 (#2333391)

eh non, ActionSit(oChair) fait s'asseoir le perso sur oChair, mais après, ce n'est plus une action. Lorsqu'il reste assis, c'est comme s'il restait sans bouger debout, normalement, il suffit de le faire bouger pourqu'il se lève (essaye ActionForceMoveToLocation)

JOL Archives 1.0.1
@ JOL / JeuxOnLine