[Script] Système modulaire + followers

Répondre
Partager Rechercher
Suite au tuto sur la gestion du rez je post maintenant un script d'exemple d'utilisation.

Il s'agit donc d'un système de modules avec un follower comme exemple. Un follower est un objet qui suit un avatar où qu'il soit dans la sim (d'où le nom follower/suiveur ).

Le système permet de lancer des followers sur plusieurs personnes à la fois. Il permet également de créer ses propres followers facilement puisqu'il est modulaire.

Note : C'est un système très basique à titre d'exemple, je précise également que lancer ce genre d'objet sur un avatar sans son consentement est contraire au TOS de Second Life (sauf dans le cas de sims de combat prévues pour ).



Installation

Commencez par créer un objet (peut importe) et attachez en HUD sur l'attachement qui vous plaira.

Dans votre HUD, créez un premier script, nommez-le par exemple Rez Handler et placez-y ce code :

Code PHP:

// !! NOTE !! Le script a été mis à jour le 19/12/09 et fonctionne un peu différemment de l'ancienne version.


//----------------------------------------------------------------------------------
//                              LIBRARY FUNCTIONS
//----------------------------------------------------------------------------------



// -- Fonction de "correction" de vecteurs de position pour ne pas aller offworld ou au dessus de 4096m --
// @ param [vector] position à corriger
// @ return [vector] retourne le vecteur corrigé

vector CorrectVectorPosvector p ) {
    
    if( 
p.256.0 p.256.0;
    if( 
p.0.0 p.0.0;   
    if( 
p.256.0 p.256.0;
    if( 
p.0.0 p.0.0;
    if( 
p.4096.0 p.4096.0;
    
    return 
p;
    
}




// -- Fonction permettant de vérifier si l'objet est autorisé à rez à cette position --
// @ param [vector] position à vérifier
// @ return [bool]  retourne true si il est autorisé, false dans le cas contraire

integer ParcelCheckvector p ) {
    
    
integer flags llGetParcelFlags);
    
    if( 
flags PARCEL_FLAG_ALLOW_CREATE_OBJECTS || 
       (
flags PARCEL_FLAG_ALLOW_CREATE_GROUP_OBJECTS && 
            
llList2Key(llGetObjectDetails(llGetKey(), [OBJECT_GROUP]), 0) == llList2Key(llGetParcelDetails(p, [PARCEL_DETAILS_GROUP]), 0)) )
    return 
TRUE;
    
    return 
FALSE;    
    
}




// -- Fonction qui génere un canal au hasard (négatif) --
// @ return [integer] retourne le canal

integer GetRandomChannel() {
    return ~(integer)
llFrand( (float)DEBUG_CHANNEL );   
}




//----------------------------------------------------------------------------------
//                               SCRIPT FUNCTIONS
//----------------------------------------------------------------------------------



// -- Fonction llRezObject protégée qui vérifie si le rez est possible et envoie des données à l'objet
// de façon automatique --
// @ param [string] nom de l'objet dans l'inventaire
// @ param [vector] position du rez
// @ param [vector] vélocité de l'objet rezzé
// @ param [rotation] rotation de l'objet
// @ param [integer] canal de l'objet pour transmettre les données
// @ param [integer] type de rez, position locale/rotation locale ou non
// @ param [string] les données à envoyer

SafeRezObjectstring namevector posvector velrotation rotinteger chaninteger rezTypestring data ) {
    
    
    
// Est-ce que l'objet est bien un objet et présent dans l'inventaire ? si non, on envoie une erreur au owner.
    
if( llGetInventoryType(name) != INVENTORY_OBJECT ) {
        
llOwnerSay"Erreur :: " name " n'est pas un objet ou n'est pas présent dans l'inventaire." );
        return;   
    }
    
    
// on stock temporairement la pos/rot de l'objet/avatar
    
vector myPos llGetPos();
    
rotation myRot llGetRot();
    
    
vector rezPos myPos pos;
    
    
// on calcule le type de rez demandé
    
if( rezType POS_TYPE_REGION )
        
rezPos pos;
    else if( 
rezType POS_TYPE_LOCAL_ROTATED )
        
rezPos myPos pos myRot;
    if( 
rezType ROT_TYPE_LOCAL )
        
rot *= myRot;
    
    
    
// si la distance de rez est plus de 10 mètres, on la réduit au max possible
    // pour éviter une erreur de rez silencieuse
    
if( llVecDist(myPosrezPos) > 10.0 )
        
rezPos myPos llVecNorm(rezPos-myPos) * 10.0;    
    
    
    
// Si il y a possibilité de rez à la position   
    
if( CorrectVectorPos(rezPos) == rezPos && ParcelCheck(rezPos) ) {
        
        
// Si le canal n'est pas 0 et que les données à envoyer ne sont pas vides, on crée une connexion
        
if( chan != && data != "" ) {          
            if( !
CreateConnection(chandata) )
                return;    
        }
        
llRezObjectnamerezPosvelrotchan );       
        
    
// Sinon on vérifie la présence d'un proxy dans la région           
    
} else if( IsProxyAvailable() ) {
        
        
// Si le canal n'est pas 0 et que les données à envoyer ne sont pas vides, on crée une connexion
        
if( chan != && data != "" ) {          
            if( !
CreateConnection(chandata) )
                return;    
        }     
        
llGiveInventorygProxyKeyname );
        
llSleep0.2 );
        
llRegionSaygProxyChanname PRIM_SEP + (string)vel PRIM_SEP + (string)rot PRIM_SEP + (string)chan );   
    }
     
    
}



// -- Vérifie si un proxy est disponible --
// @ return [bool] true : disponible, false : non disponible

integer IsProxyAvailable() {
    return ( 
PROXY_ACTIVE && llKey2Name(gProxyKey) != "" );
}




// -- Crée une connexion et stock les données dans une mémoire tampon en attendant le rez --
// @ param [integer] canal du transfert
// @ param [string] les données à envoyer
// @ return [bool] true : la connexion est établie, false : echec de la création d'une connexion

integer CreateConnectioninteger chanstring data ) {
    
    if( (
gListenChan != []) > 64 )
        return 
FALSE;
       
    
gListenData += data;
    
gListenChan += chan;
    
gListenID += llListenchan""NULL_KEY"get" );
    return 
TRUE;
    
}





// -- Envoie les données mises en mémoire sur le canal concerné --
// @ param [integer] le canal du transfert

FlushDatainteger chan ) {
    
    
integer fd llListFindListgListenChan, [chan] );
    
    
// si le canal possède bien des données à envoyer
    
    
if( ~fd ) {   
        
llListenRemovellList2Integer(gListenIDfd) );
        
llRegionSaychanllList2String(gListenDatafd) );
        
gListenID llDeleteSubListgListenIDfdfd );
        
gListenChan llDeleteSubListgListenChanfdfd );
        
gListenData llDeleteSubListgListenDatafdfd );         
    }    
    
}



//------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------





//--------------------------------------------------------------------------------------
//                                          CONSTANTS
//--------------------------------------------------------------------------------------
//----------------------------------------------
//                INTERNAL COMM
//----------------------------------------------
//----------------
//      ME
//----------------
integer IC_REZ_REQUEST = -1621184001;
integer IC_REZ_CONNECTION = -250865153;
integer IC_REZ_FLUSH = -605179777;
integer IC_REZ_CLEAR = -2105587073;
//----------------
//SCRIPT ADDRESSES
//----------------

//----------------
//    GLOBAL
//----------------
integer IC_GLOBAL_REZ_RETCONNECTION = -1204281601;

//----------------------------------------------
//                  PARAMETERS
//----------------------------------------------
// activer ou désactiver la fonction du proxy.
integer PROXY_ACTIVE FALSE;
// le délais de rafraichissement de timer de vérification
float PROXY_REFRESH 5.0;
// le nom du proxy dans l'inventaire
string PROXY_NAME "MyProxy";
// le temps de vie du proxy
float PROXY_LIFE 600.0// 10 minutes
// rez d'un autre proxy X secondes avant que l'ancien se supprime 
float PROXY_TIME_REZ 20.0;
// offset de rez du proxy
vector PROXY_REZ_OFFSET = <0.00.02.0>;
//----------------------------------------------
//                   REZ TYPE
//----------------------------------------------
// rez par position relative à la région
integer POS_TYPE_REGION 0x01;
// rez par position locale selon la rotation de l'objet/l'avatar
integer POS_TYPE_LOCAL_ROTATED 0x02;
// rez par rotation locale
integer ROT_TYPE_LOCAL 0x04;
//----------------------------------------------
//                     UTIL
//----------------------------------------------
string PRIM_SEP "|";
string SUB_SEP ":";

//--------------------------------------------------------------------------------------
//                           GLOBAL VARIABLES | State : Default
//--------------------------------------------------------------------------------------
//----------------------------------------------
//                  MEMORY
//----------------------------------------------
list gListenData;
list 
gListenChan;
list 
gListenID;
//----------------------------------------------
//                  PROXY
//----------------------------------------------
key gProxyKey;
integer gProxyChan;
//----------------------------------------------
//                  OTHERS
//----------------------------------------------
key gOwnerKey;


default
{
    
    
on_rezinteger r ) {
        
state clearconnections;   
    }
    
    
    
state_entry() {
        
gOwnerKey llGetOwner();  
        if( 
PROXY_ACTIVE )
            
llSetTimerEvent0.1 );
          
    }
    
    
    
changedinteger c ) {
        
        if( 
CHANGED_REGION )
            
state clearconnections;   
    }
    
    
    
link_messageinteger linkinteger addressstring datakey data2 ) {
        
// Si l'adresse correspond à une requête de rez, on reforme le packet pour l'envoyer à la fonction
        
if( address == IC_REZ_REQUEST ) {
            list 
packet llParseString2Listdata, [PRIM_SEP], [] );
            
SafeRezObject(
                            
llList2String(packet0), // name
                            
(vector)llList2String(packet1), // pos
                            
(vector)llList2String(packet2), // vel
                            
(rotation)llList2String(packet3), // rot
                            
(integer)llList2String(packet4), // chan
                            
(integer)llList2String(packet5), // rezType
                            
(string)data2 // data
                          
);   
        } 
        
        
// Si l'adresse est une demande de création de connexion
        
else if( address == IC_REZ_CONNECTION 
            
llMessageLinkedLINK_SETIC_GLOBAL_REZ_RETCONNECTION, (string)data2, (string)CreateConnection((integer)data, (string)data2) );
        
        
// Si l'adresse correspond à une requête d'envoi de données
        
else if( address == IC_REZ_FLUSH )
            
FlushData( (integer)data );   
        
        
// Demande de clearconnections
        
else if( address == IC_REZ_CLEAR )
            
state clearconnections;
    }
    
    
    
listeninteger chanstring namekey idstring msg ) {
        if( 
llGetOwnerKey(id) == gOwnerKey ) {
            
FlushDatachan );
            if( 
name == PROXY_NAME )
                    
gProxyKey id;
        }
    }
    
    
    
timer() {
        
         
// si aucun proxy détecté ou en fin de vie, on en rez un autre
         
if( llKey2Name(gProxyKey) == "" || (llGetTime() + PROXY_TIME_REZ) >= PROXY_LIFE  ) {
              
integer rand GetRandomChannel();
              
SafeRezObjectPROXY_NAMEPROXY_REZ_OFFSETZERO_VECTORZERO_ROTATIONrand0, (string)PROXY_LIFE );   
              
gProxyChan rand
              
llResetTime();
         }
            
         
llSetTimerEventPROXY_REFRESH );
    }


}





// State permettant de désactiver tous les listens du script rapidement
// ainsi qu'éffacer la mémoire.

state clearconnections
{
    
       
state_entry() {
            
gListenData = [];
            
gListenChan = [];
            
gListenID = [];        
            
state default;
       }   
    


Créez un second script Module Storage et mettez ce code :


Code PHP:


//----------------------------------------------------------------------------------
//                              EXTERNAL FUNCTIONS
//----------------------------------------------------------------------------------


//----------------------------------
//    OWN EXTERNAL FUNCTIONS
//----------------------------------



//----------------------------------
//   SCRIPTS EXTERNAL FUNCTIONS
//----------------------------------


SafeRezObjectstring namevector posvector velrotation rotinteger chaninteger rezTypestring data ) {
    
llMessageLinkedLINK_SET, -1621184001
                                               
name "|" 
                                               (string)
pos "|" 
                                               (string)
vel "|" 
                                               (string)
rot "|" 
                                               (string)
chan "|" +
                                               (string)
rezTypedata 
                    
);         
}


//----------------------------------
//   GLOBAL EXTERNAL FUNCTIONS
//----------------------------------



//----------------------------------------------------------------------------------
//                              LIBRARY FUNCTIONS
//----------------------------------------------------------------------------------


// -- Fonction qui génere un canal au hasard (négatif) --
// @ return [integer] retourne le canal

integer GetRandomChannel() {
    return ~(integer)
llFrand( (float)DEBUG_CHANNEL );   
}



//----------------------------------------------------------------------------------
//                               SCRIPT FUNCTIONS
//----------------------------------------------------------------------------------

// -- Supprime tous les modules de la mémoire --

ClearMemory() {
    
    
gModuleListCmd = [];
    
gModuleListInv = [];
    
gModuleListOff = [];
    
gModuleListRot = [];
}




// -- Charge l'inventaire pour les modules --

ReloadInventory() {
    
    
    
// on compte le nombre d'items dans l'inventaire (tous les types)
    
integer invCount llGetInventoryNumberINVENTORY_ALL );
    
string invName;
    
string cmdName;
    list 
invParsed;
    
integer i;
    
    
// on compte le nombre de modules avant le reload
    
integer modCountB = ( gModuleListCmd != [] );
    
    while( 
invCount ) {
        
        
// on prend le nom correspondant au numéro i dans la liste
        
invName llGetInventoryNameINVENTORY_ALLi++ );
        
        
// les modules commencent tous par M\
        
if( llGetSubString(invName01) == "M\\" ) {
            
            
// on parse le nom en une list, les séparateurs sont \
            // exemple : M\commande_chat\<0,0,9>\<0,0,0,1>
            //           0       1          2        3
            
invParsed llParseString2ListinvName, ["\\"], [] );
            
            
// on prend la commande de chat dans la list
            
cmdName llList2StringinvParsed);
            
            
// on regarde si la commande de chat n'existe pas déjà
            
if( !~ llListFindList(gModuleListCmd, [cmdName]) ) {
            
                
gModuleListCmd += cmdName// commande chat
                
gModuleListInv += invName// nom entier dans l'inventaire
                
gModuleListOff += (vector)llList2StringinvParsed); // offset de rez
                
gModuleListRot += (rotation)llList2StringinvParsed); // rotation de rez
            
            
}
                  
        }
           
    } 
    
    
// on compte le nombre de modules après le reload
    
integer modCountA = ( gModuleListCmd != [] );
    
// on compte le nombre de nouveaux modules installés
    
integer modAdded modCountA modCountB;
    
    
// si il y a des nouveaux modules
    
if( modAdded )    
        
llOwnerSay"Il y a " + (string)modAdded " nouveau(x) module(s) installé(s). Total = " + (string)modCountA );  
    
}




// -- initialise le listen --

Init() {
    
    
// on sauvegarde la key du owner
    
gOwnerKey llGetOwner();
    
// on désactive la dernière écoute si il y en a
    
llListenRemovegListenID );
    
// et on la réactive
    
gListenID llListenCHANNEL_COMMAND""gOwnerKey"" );
}




//-----------------------------------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------------------------------------





//--------------------------------------------------------------------------------------
//                                          CONSTANTS
//--------------------------------------------------------------------------------------
//----------------------------------------------
//                INTERNAL COMM
//----------------------------------------------
//----------------
//      ME
//----------------

//----------------
//SCRIPT ADRESSES
//----------------

//----------------
//    GLOBAL
//----------------
// adresse pour lancer un module interne (script)
integer IC_GLOBAL_LAUNCH_MODULE = -1779072513;
// adresse pour stopper les modules internes
integer IC_GLOBAL_END_MODULE    = -39668585;
//----------------------------------------------
//                     UTIL
//----------------------------------------------
string PRIM_SEP "|";
string SUB_SEP ":";
//----------------------------------------------
//                   REZ TYPE
//----------------------------------------------
// rez par position relative à la région
integer POS_TYPE_REGION 0x01;
// rez par position locale selon la rotation de l'objet/l'avatar
integer POS_TYPE_LOCAL_ROTATED 0x02;
// rez par rotation locale
integer ROT_TYPE_LOCAL 0x04;
//----------------------------------------------
//                VOICE PARAMETERS
//----------------------------------------------
// le canal pour les commandes ( 0 par défaut )
integer CHANNEL_COMMAND 0;
// on active ou non le trigger char ( qui permet de taper des commandes comme ça : !kill blackshade )
integer TRIGCHAR_ENABLED FALSE;
// quel caractère utiliser pour le trigchar ?
string TRIGCHAR "!";
//----------------------------------------------
//                CHANNEL END
//----------------------------------------------
// channel pour stopper les modules (objets)
integer CHANNEL_END = -1584311041;
//--------------------------------------------------------------------------------------
//                                    GLOBAL VARIABLES
//--------------------------------------------------------------------------------------
//----------------------------------------------
//               OWNER INFOS    
//----------------------------------------------
key gOwnerKey;
//----------------------------------------------
//                 LISTEN 
//----------------------------------------------
integer gListenID;
//----------------------------------------------
//              MODULE STORAGE    
//----------------------------------------------
list gModuleListCmd;
list 
gModuleListInv;
list 
gModuleListOff;
list 
gModuleListRot;
//----------------------------------------------
//                VOICE MEMORY    
//----------------------------------------------
list gTargets;
// module selectionné
integer gCurModType;
string gCurModInv;
vector gCurModOff;
rotation gCurModRot;


default
{
   
   
on_rezinteger p ) {
        
// on initialise au rez
        
Init();    
   } 


   
state_entry() {
        
// on initialise après le reset du script ou de sa création
        
Init(); 
   }
   
   
   
touch_startinteger num ) {
    
       
// si le owner touche le prim, on recharge entièrement les modules
       
if( llDetectedKey(0) == gOwnerKey ) {
            
ClearMemory();
            
ReloadInventory();    
       }    
       
   }
   
   
   
   
changedinteger c ) {
        
// on reload les modules dès que l'inventaire change
        
if( CHANGED_INVENTORY )
            
ReloadInventory();    
   }
   
   
   
   
   
listeninteger chanstring namekey idstring data ) {
       
       
// si il y a un caractère obligatoire à mettre en premier pour déclencher une commande
       
if( TRIGCHAR_ENABLED ) {
            
// si le premier caractère est bien celui du script
            
if( llGetSubString(data00) == TRIGCHAR )
                
data llDeleteSubStringdata0);
            
// sinon on stoppe le processus d'analyse de la commande
            
else
                return;
       }
       
       
      
// commande spéciale pour stopper tous les modules 
      
if( data == "end" ) {
          
llMessageLinkedLINK_SETIC_GLOBAL_END_MODULE""NULL_KEY );
          
llRegionSayCHANNEL_END"die" );
          return;
      }
       
       
       
// on cherche la position du premier espace dans la commande
       
integer fiSpos llSubStringIndexdata" " );
       
       
// si il y a bien au moins un espace dans la commande
       
if( ~ fiSpos ) {
            
            
integer fdModule llListFindListgModuleListCmd, [llGetSubString(data0fiSpos 1)] );
            
            
// si il y a bien un module avec cette commande
            
if( ~ fdModule ) {
                
                
// on sauvegarde le/les target(s)
                
gTargets llParseString2ListllToLower(llGetSubString(datafiSpos 1, -1)), [" "], [] );
                
                
// on sauvegarde les paramètres du module
                
gCurModInv llList2StringgModuleListInvfdModule );
                
gCurModType = ( llGetInventoryType(gCurModInv) == INVENTORY_OBJECT );
                
                
// on sauvegarde l'offset de rez et la rotation seulement si il s'agit d'un objet
                
if( gCurModType ) {
                    
gCurModOff llList2VectorgModuleListOfffdModule );
                    
gCurModRot llList2RotgModuleListRotfdModule );
                }
                
                
// on lance un sensor
                
llSensor""NULL_KEYAGENT96.0PI );
                      
            }
            
       } 
       
   }
   
   
   
   
sensorinteger num ) {
       
       
integer i;
       
integer ii;
       
string curTrgt;
       
// on compte le nombre de targets dans la commande
       
integer targetCount = ( gTargets != [] );
       
       while( 
targetCount ) {
            
           
// on prend la target numéro i dans la list
           
curTrgt llList2StringgTargetsi++ );
           
ii 0
           
           while( 
ii num ) {
               
               
// si le nom correspond 
               
if( ~ llSubStringIndex(llToLower(llDetectedName(ii)), curTrgt) ) {
                   
                   
// si c'est un module objet
                   
if( gCurModType  )
                        
SafeRezObjectgCurModInvgCurModOffZERO_VECTORgCurModRotGetRandomChannel(), 0, (string)llDetectedKey(ii) );                // sinon c'est un module interne (script)
                   
else
                        
llMessageLinkedLINK_SETIC_GLOBAL_LAUNCH_MODULEgCurModInvllDetectedKey(ii) );
                   
                    
jump outwtrgt;
               }
               
               ++
ii;
           }  
           
           @
outwtrgt;
       }
       
   }
   
   
   
   
no_sensor() {
        
        
// il y a personne dans les 96 mètres
        
llOwnerSay"Il n'y a personne dans les 96 mètres" );   
   }




Votre système est désormais prêt à recevoir des modules ! Des modules sont des objets ou des scripts qui possèdent une commande (en chat) pour les lancer sur un ou plusieurs avatars.

Nous allons créer notre follower avec comme commande follow



Création du follower


Commencez par créer un cylindre avec comme taille 1.3 en X, 1.3 en Y et 4.0 en Z.

Mettez-lui une couleur avec un peu de transparence et surtout, mettez-le Phantom .

Créez un script dans votre cylindre que vous nommerez : Boot et placez ce code :

Code PHP:


//----------------------------------------------------------------------------------
//                              EXTERNAL FUNCTIONS
//----------------------------------------------------------------------------------


//----------------------------------
//    OWN EXTERNAL FUNCTIONS
//----------------------------------



//----------------------------------
//   SCRIPTS EXTERNAL FUNCTIONS
//----------------------------------



//----------------------------------
//   GLOBAL EXTERNAL FUNCTIONS
//----------------------------------



//----------------------------------------------------------------------------------
//                              LIBRARY FUNCTIONS
//----------------------------------------------------------------------------------





//----------------------------------------------------------------------------------
//                               SCRIPT FUNCTIONS
//----------------------------------------------------------------------------------






//-----------------------------------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------------------------------------





//--------------------------------------------------------------------------------------
//                                          CONSTANTS
//--------------------------------------------------------------------------------------
//----------------------------------------------
//                INTERNAL COMM
//----------------------------------------------
//----------------
//      ME
//----------------

//----------------
//SCRIPT ADRESSES
//----------------

//----------------
//    GLOBAL
//----------------
integer IC_GLOBAL_TARGET_KEY = -1877491457;
//----------------------------------------------
//                     UTIL
//----------------------------------------------
string PRIM_SEP "|";
string SUB_SEP ":";
//----------------------------------------------
//                CHANNEL END
//----------------------------------------------
// channel pour stopper les modules (objets)
integer CHANNEL_END = -1584311041;
//--------------------------------------------------------------------------------------
//                                    GLOBAL VARIABLES
//--------------------------------------------------------------------------------------
//----------------------------------------------
//               OWNER INFOS     
//----------------------------------------------
key gOwnerKey;
//----------------------------------------------
//                  LISTEN     
//----------------------------------------------
integer gListenTargetID;
integer gChannelTarget;


default
{

   
on_rezinteger channel ) {
        
        
// on active le module seulement si il a pas un channel 0
        
if( channel != ) {
            
// on sauvegarde la key du owner
            
gOwnerKey llGetOwner();
            
// on sauvegarde le canal donné
            
gChannelTarget channel;
            
// on écoute sur le canal donné (pour reçevoir la key)
            
gListenTargetID llListenchannel""NULL_KEY"" );
            
// on écoute sur le canal "end"
            
llListenCHANNEL_END""NULL_KEY"die" );
            
// on demande la key de l'avatar ciblé
            
llRegionSaychannel"get" );    
                
        }    
   }
   
   
   
listeninteger chanstring namekey idstring msg ) {
        
        
// si le owner du message n'est pas owner, on refuse d'analyser son message
        
if( llGetOwnerKey(id) != gOwnerKey )
            return;    
        
        
// on reçoit la key de l'avatar
        
if( chan == gChannelTarget ) {
            
// on envoit la key aux autres scripts
            
llMessageLinkedLINK_SETIC_GLOBAL_TARGET_KEY"", (key)msg );
            
// on désactive l'écoute sur ce canal car il devient inutile
            
llListenRemovegListenTargetID );
        }
        
        
// on reçoit sur le canal "end", on supprime le module
        
else if( chan == CHANNEL_END 
            
llDie();
       
   }



Il permet le transfert de données entre votre HUD et le follower (pour obtenir la key de la cible par exemple)

Créez un second script nommé Follower avec comme code :

Code PHP:



//----------------------------------------------------------------------------------
//                              EXTERNAL FUNCTIONS
//----------------------------------------------------------------------------------


//----------------------------------
//    OWN EXTERNAL FUNCTIONS
//----------------------------------



//----------------------------------
//   SCRIPTS EXTERNAL FUNCTIONS
//----------------------------------



//----------------------------------
//   GLOBAL EXTERNAL FUNCTIONS
//----------------------------------



//----------------------------------------------------------------------------------
//                              LIBRARY FUNCTIONS
//----------------------------------------------------------------------------------


safe_posJump(vector target_pos)
{
// An alternative to the warpPos trick without all the overhead.
// Trickery discovered by Uchi Desmoulins and Gonta Maltz.  More exact value provided by Fake Fitzgerald.  Safe movement modification provided by Alias Turbo.
      
vector start_pos llGetPos();
    
llSetPrimitiveParams([PRIM_POSITION, <1.304382E+191.304382E+190.0>, PRIM_POSITIONtarget_posPRIM_POSITIONstart_posPRIM_POSITIONtarget_pos]);
}



//----------------------------------------------------------------------------------
//                               SCRIPT FUNCTIONS
//----------------------------------------------------------------------------------






//-----------------------------------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------------------------------------





//--------------------------------------------------------------------------------------
//                                          CONSTANTS
//--------------------------------------------------------------------------------------
//----------------------------------------------
//                INTERNAL COMM
//----------------------------------------------
//----------------
//      ME
//----------------

//----------------
//SCRIPT ADRESSES
//----------------

//----------------
//    GLOBAL
//----------------
integer IC_GLOBAL_TARGET_KEY = -1877491457;
//----------------------------------------------
//                     UTIL
//----------------------------------------------
string PRIM_SEP "|";
string SUB_SEP ":";

//--------------------------------------------------------------------------------------
//                                    GLOBAL VARIABLES
//--------------------------------------------------------------------------------------
//----------------------------------------------
//             TARGET INFOS     
//----------------------------------------------
key gTargetKey;


default
{

   
   
link_messageinteger linkinteger addressstring datakey data2 ) {
        
       
// on reçoit la key de l'avatar
       
if( address == IC_GLOBAL_TARGET_KEY ) {
           
// on l'enregistre
           
gTargetKey data2;
           
// on active le timer
           
llSetTimerEvent1.0 );
       }
       
   }
   
   
   
   
timer() {
       
       
// si l'avatar n'est plus dans la sim, on supprime le follower
       
if( llGetAgentSize(gTargetKey) == ZERO_VECTOR )
            
llDie();
       
       
// on sauvegarde les infos de l'avatar dans une list (ça peut etre la position, la rotation etc)
       // dans notre cas on a seulement besoin de sa position
       
list details llGetObjectDetailsgTargetKey, [OBJECT_POS] );
       
       
// on utilise PosJump pour bouger le follower
       // qui permet d'aller à des distances illimitées
       // et est beaucoup plus rapide que warpPos
       
safe_posJumpllList2Vector(details0) );   
       
   }




Maintenant que notre follower possède ses scripts propres à son fonctionnement, il nous faut l'installer dans notre HUD.

Les paramètres d'un module se placent dans le nom de l'objet . Voici la convention à respecter :

M\nom_commande_de_chat\<0.0, 0.0, 9.0>\<0.0, 0.0, 0.0, 1.0>

Les \ sont des séparateurs entre chaque paramètres.

Les modules commencent tous avec un M\

nom_commande_de_chat : ici on place le nom de la commande pour lancer notre module
<0.0, 0.0, 9.0> : ce paramètre est un vecteur pour le rez ( position locale ). Pour ce vecteur il s'agit d'une position à 9 mètres au dessus de vous.
<0.0, 0.0, 0.0, 1.0> : la rotation qu'aura notre module au rez. Pour une rotation nulle on met : <0.0, 0.0, 0.0, 1.0> ou encore : <0, 0, 0, 1>.


Nous allons donc nommer notre cylindre avec comme nom :

M\follow\<0,0,9>\<0,0,0,1>

Prenez une copie et placez l'objet dans votre HUD. Vous devriez avoir une confirmation qu'il s'est bien installé :

Citation :
module inst basic: Il y a 1 nouveau(x) module(s) installé(s). Total = 1
Pour lancer le follower il faut utiliser sa commande en chat ( follow dans notre cas ) avec un ou plusieurs noms partiels d'avatars. Exemple si c'était pour le lancer sur Philip Linden (je ne vous le conseil pas ) il faut taper en chat :

Citation :
follow philip
ou encore simplement :

Citation :
follow phil
Un autre exemple pour le lancer sur moi et 2 fois sur philip linden :

Citation :
follow philip philip blackshade
ou encore

Citation :
follow phil phil black

Pour l'arrêter il faut utiliser la commande end en chat.

Citation :
end

Améliorations

Le système est très basique mais vous pouvez l'améliorer comme vous le souhaitez, quelques exemples :

- Utiliser un Simscaner à la place d'un sensor de 96 mètres grâce notamment au viewer Emerald qui envoie les keys des avatars présents sur la sim à l'aide de votre avatar sur le canal -777777777.

- Faire un système de dialog pour choisir sa cible, un très bon exemple le script de bestmomo ici : https://forums.jeuxonline.info/showthread.php?t=1051053

- Faire un système de dialog pour choisir son module à lancer (pareil que l'exemple précèdent ).



Si vous avez des suggestions ou vous ne comprenez pas quelque chose, n'hésitez pas à demander.
Répondre

Connectés sur ce fil

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