La Bibliothèque de Neverwinter Nights
Aide et informations diverses sur Neverwinter Nights ainsi que D&D3.
La date/heure actuelle est 19/04/2024 01:54:47


  Page 1 sur 2 ¤ Aller à la page 1, 2  Suivante

Voir le sujet précédent ¤ Voir le sujet suivant 
Auteur Message
Baldurien
L'homme qui chutait sur le macadam
Inscrit le: 12 Sep 2002
Messages: 14064
Localisation: Quadran Alpha
Répondre en citant
Posté le : 03/10/2002 23:29:09 Sujet du message : [Ressources] Vos scripts

Ce sujet a pour but de préparer une probable section Scripts , voilà : ici, vous pouvez ajouter vos propres scripts. Pour cela, utilisez la balise [ code ] (sans espace) des forums.


Je commence avec mon script de téléportation entre zones :


Code :


void TeleportObject( string sZone, string sWayPont )
{

  object oPlayer = GetPCSpeaker();
  object oArea = GetObjectByTag( sZone );
  float fOrientation = GetFacing( oPlayer );
  vector vPosition = GetPosition( GetObjectByTag( sWayPont ) );

  location lWhereToGo = Location( oArea, vPosition, fOrientation );

  AssignCommand( oPlayer, JumpToLocation( lWhereToGo ) );
}


Explications :
TeleportObject( string sZone, string sWayPont )
- sZone correspond au tag de la zone où il faut se téléporter.
- sWayPoint correspond à un tag de Waypoint où le personnage atterira.

Vous pouvez aussi ajouter un argument : object oPlayer et zapper la ligne : object oPlayer = GetPCSpeaker(); vu que je me sers de ce script essentiellement pour une téléportation par dialogue. (très pratique pour tester un module)

- object oArea = GetObjectByTag( sZone ) : on obtiens l'objet zone.
- float fOrientation = GetFacing( oPlayer ) : ceci est nécessaire pour la fonction Location. Même si on peut mettre 0.0 comme valeur par défaut.
- vector vPosition = GetPosition( GetObjectByTag( sWayPont ) ) : on crée un vecteur en fonction du Waypoint, cela nous permet de ne pas atterir n'importe où dans la zone : imaginez les dégats si la téléportation menait sur un mur ! (nota: le personnage serait inscruté dans le mur)
- location lWhereToGo = Location( oArea, vPosition, fOrientation ) : on stocke la location d'arrivée.
- AssignCommand( oPlayer, JumpToLocation( lWhereToGo ) ) : on se téléporte.



Edit:

pensez aussi à ceci : [http]
_________________
#nwnights-fr @ irc.darkmyst.org TitanQuest-FR
Dernière édition par Baldurien le 03/10/2002 23:36:49; édité 1 fois
 
Revenir en haut Voir le profil de l'utilisateur Envoyer un message privé Visiter le site web du posteur Ignorer l'utilisateur
 
Baldurien
L'homme qui chutait sur le macadam
Inscrit le: 12 Sep 2002
Messages: 14064
Localisation: Quadran Alpha
Répondre en citant
Posté le : 03/10/2002 23:35:44 Sujet du message : Ne pas créer à l'infini des objets

Code :

#include "NW_I0_TOOL"

void main()
{
  if ( CheckPartyForItem( GetFirstPC(), "itmMiscClair" ) == FALSE )
  {
    CreateItemOnObject( "itmmiscclair", GetFirstPC() );
  }
}


Lorsque vous commencez une partie, il peut être interessant de donner des objets: par exemple un livre , une sorte de journal des quêtes.

Cependant, lorsque vous sauvegardez le personnage, que vous refaites le module : paf! ça recrée l'objet. Ce qui, vous en conviendrez est fort peu sympathique (imaginez un objet de gros bill crée à l'infini...)

Vous devez pour cela avoir le tag de l'item, le blueprint d'une item, et le tag d'un joueur. (note: le 1.25 devrait faire apparaître la fonction GetResRef)

Notez bien : ici ce script ne teste QUE le premier joueur. Vous devrez surement passer par une boucle pour les autres joueurs.
_________________
#nwnights-fr @ irc.darkmyst.org TitanQuest-FR
 
Revenir en haut Voir le profil de l'utilisateur Envoyer un message privé Visiter le site web du posteur Ignorer l'utilisateur
 
Cassin
Papa-poule(t) & poissard intemporel
Inscrit le: 16 Sep 2002
Messages: 7471
Localisation: 6 bis rue de la Couveuse, Poulailler 39b
Répondre en citant
Posté le : 14/10/2002 13:21:38 Sujet du message :

Cet exemple s'applique à un PNJ pour qu'il "attaque" un arbre pour donner l'illusion qu'il le coupe, mais avec quelques modifs on peut appliquer ce qu'on veut comme effet.
Le but étant que le bûcheron arrête son boulot quand le joueur approche, afin de pouvoir lui parler, et qu'il recommence à couper l'arbre après son départ.

D'abord, créer un PNJ, si possible avec une hache Very Happy.
Pour un bô narbre, j'ai pris le tileset forest et comme les arbres sont des tiles qu'on ne peut pas "tagger", j'ai posé dessus un "InvisibleObject" que le bûcheron attaquera.

Autour du PNJ, créer un trigger qui délimitera la zone dans laquelle le joueur pénétrera et arrêtera en même temps le boulot du bûcheron.


Voilà les scripts à mettre :

Sur le Trigger :
- dans OnEnter :

Code :

void main()
{
    object oPC;
    oPC=GetEnteringObject();
    SetLocalInt(oPC,"InZone",1);
}


- Dans OnExit :
Code :

void main()
{
    object oPC;
    oPC = GetExitingObject();
    SetLocalInt(oPC,"InZone",0);
}




Sur le PNJ :
Dans OnPerception :
Code :

void main()
{
    if(GetIsPC(GetLastPerceived()))
    {
        SignalEvent(OBJECT_SELF,EventUserDefined(200));
    }
}


- Dans OnUserDefined :
Code :

void main()
{
    object oPC = GetNearestCreature(CREATURE_TYPE_PLAYER_CHAR, PLAYER_CHAR_IS_PC );
    switch(GetUserDefinedEventNumber())
   {
        case 200:
        {
            if(!IsInConversation(OBJECT_SELF) && GetLocalInt(oPC,"InZone") == 0)
            {
                ActionAttack(GetNearestObjectByTag("InvisibleObject"));
                DelayCommand(12.0,ClearAllActions());
                DelayCommand(24.0,SignalEvent(OBJECT_SELF,EventUserDefined(200)));
            }
            else
            {
                DelayCommand(12.0,SignalEvent(OBJECT_SELF,EventUserDefined(200)));
            }
        }
    }
}



Voilà !

PS : il est à noter qu'on ne peut pas parler au PNJ tant qu'il ne s'est pas mit en "mode repos" (dans mon cas, il repose sa hache sur son épaule). Si le PNJ renvoie la phrase "object is busy", il suffit d'attendre un peu que son attitude ou sa posture change pour pouvoir lui parler.
_________________
Aventure ! Camaraderie ! Et acier sur acier ! Les ingrédients légendaires ! Hein Bouh ?

http://cassin1306.spaces.live.com
 
Revenir en haut Voir le profil de l'utilisateur Envoyer un message privé Visiter le site web du posteur Ignorer l'utilisateur
 
Cassin
Papa-poule(t) & poissard intemporel
Inscrit le: 16 Sep 2002
Messages: 7471
Localisation: 6 bis rue de la Couveuse, Poulailler 39b
Répondre en citant
Posté le : 14/10/2002 16:04:34 Sujet du message : Invoquer et désinvoquer un PNJ avec FXs ;)

Dans mon module lorsque le joueur clique sur un autel il fait apparaître un esprit dans un déluge de tonnerre et de feu Wink

Voilà donc comment :
- bon, d'abord évidemment il faut commencer par créer le PNJ en question et noter son tag (ici : esprit)
- poser ensuite un waypoint, là où la créature apparaîtra. Ici il est noté WP_esprit
- ensuite, créer l'autel (ou autre placeable hein Wink ) et le rendre Useable (Utilisable en VF)
- dans le OnUsed du placeable, mettre le script suivant :
Code :
object oPC = GetLastUsedBy();

void main()
{
        effect eVis = EffectVisualEffect(VFX_DUR_GHOSTLY_VISAGE);
        location lLoc = GetLocation(GetNearestObjectByTag("WP_Esprit"));
        object oEsprit = CreateObject(OBJECT_TYPE_CREATURE,"esprit",lLoc,TRUE);
        ApplyEffectAtLocation(DURATION_TYPE_INSTANT,EffectVisualEffect(VFX_FNF_SUMMON_GATE),lLoc);
        ApplyEffectToObject(DURATION_TYPE_TEMPORARY,eVis,oEsprit);
}

Pour varier les effets, vous pouvez changer le VFX_FNF_SUMMON_GATE par autre chose, pour voir la liste, tapez VFX_FNF_SUMMON dans l'onglet "Constants" de l'éditeur de script. Cela va de l'effet d'invocation de monstre I à III en passant par les Celestials Wink...
- ensuite pour moi le PNJ devait déclencher une conversation, j'ai donc mis ce script dans son OnPerception :
Code :
void main()
{
    ActionStartConversation(GetLastPerceived(), "esprit",TRUE);
}

mais c'est évidemment facultatif si vous ne voulez pas le faire parler ! Very Happy
- A la fin de la conversation, dans les deux cases de "other files" ("autres fichiers" en VF) j'ai mis ce dernier script :
Code :
#include "NW_I0_Plot"
void main()
{
    effect eVis = EffectVisualEffect(VFX_IMP_UNSUMMON);
    ApplyEffectToObject(DURATION_TYPE_INSTANT,eVis,OBJECT_SELF);
    DestroyObject(OBJECT_SELF,0.5f);
    PlayOldTheme();
}

encore une fois ici on peut faire varier l'effet...

A noter que j'ai tiré ça de la campagne solo, fin du chapitre 1, juste avant d'entrer dans le fort de Heaum, il y a un PNJ qui apparaît lorsqu'on traverse le pont.
Là le PNJ apparaissait suite au passage sur un trigger, pour ça il suffit de changer dans le premier script le object oPC = GetLastUsedBy(); par un object oPC = GetLastEntered(); et de placer le script dans le OnEnter du trigger.
Ne pas oublier non plus de placer un DestroyObject(OBJECT_SELF); à la fin du script afin de détruire le trigger, sinon le PNJ apparaîtra chaque fois que vous le traverserez (mais c'est peut-être ce que vous voulez faire aussi Very Happy).

Voilà !
_________________
Aventure ! Camaraderie ! Et acier sur acier ! Les ingrédients légendaires ! Hein Bouh ?

http://cassin1306.spaces.live.com
 
Revenir en haut Voir le profil de l'utilisateur Envoyer un message privé Visiter le site web du posteur Ignorer l'utilisateur
 
Cassin
Papa-poule(t) & poissard intemporel
Inscrit le: 16 Sep 2002
Messages: 7471
Localisation: 6 bis rue de la Couveuse, Poulailler 39b
Répondre en citant
Posté le : 14/10/2002 16:16:59 Sujet du message : Les tokens adaptés au français, par Jedaï

La bibliothèque de Custom Tokens de Jedaï
_________________
Aventure ! Camaraderie ! Et acier sur acier ! Les ingrédients légendaires ! Hein Bouh ?

http://cassin1306.spaces.live.com
Dernière édition par Cassin le 12/05/2003 08:54:52; édité 2 fois
 
Revenir en haut Voir le profil de l'utilisateur Envoyer un message privé Visiter le site web du posteur Ignorer l'utilisateur
 
Cassin
Papa-poule(t) & poissard intemporel
Inscrit le: 16 Sep 2002
Messages: 7471
Localisation: 6 bis rue de la Couveuse, Poulailler 39b
Répondre en citant
Posté le : 14/10/2002 19:24:02 Sujet du message : Script de respawn

Bon attention on s'accroche là, c'est du gros morceau ! Very Happy

(tout d'abord merci à Jedaï (encore lui Wink ) et à Tyn' pour m'avoir grandement aidé sur ce #%£$*% de script ! Very Happy )

Donc comme le titre l'indique c'est un script de respawn. Ben oui, je trouve pas ça très réaliste que le joueur fonce de le tas et meure 36 fois en réssucitant de suite pour avoir à l'usure le vilain méchant en face. Alors voilà ce que je propose dans mon module :
- le joueur est dans un Monastère et reçoit pour mission de retrouver une arme magique dans la forêt proche. Bon. Tant qu'il n'a pas trouvé l'arme, il peut crever autant de fois, à son respawn il est téléporté au temple du monastère avec 1PV et il doit aller voir le guerrisseur avant de repartir à l'assaut.
- une fois l'arme trouvée, le monastère est sensé être détruit, et donc le joueur ne peut plus être téléporté au temple. Et c'est là que ça devient intéressant Niark : si le joueur meurt et respawn, hop!, un pt de constit en moins. Et oui, carrément ! Ca a le mérite de faire réfléchir et à plus utiliser le bouton Save Game / Load Game que Respawn... Very Happy
(et ça colle plus à une règle de AD&D qui disait qu'on ne pouvait être réssucité qu'autant de fois qu'on avait de pts de constit).

Alors avant tout, créez 10 "objets de créature" de type "peau de créature" ayant chacun comme propriété une pénalité d'un pt de constit' et de blueprint "constit1" ; "constit2" ; "constit3' etc...
(donc l'objet "constit1" avec une pénalité d'un point, l'objet "constit2" avec une pénalité de 2 pts etc... Wink )
SURTOUT n'oubliez pas de cocher la case "Identifié", sinon ça ne marchera pas ! (on ne peut pas utiliser un objet non-identifié !)

Voici donc le script :
Code :
#include "nw_i0_plot"
void main()
{
    object oRespawner = GetLastRespawnButtonPresser();
    ApplyEffectToObject(DURATION_TYPE_INSTANT,EffectResurrection(),oRespawner);

    if (!GetLocalInt(GetModule(), "get_armeMGK") == 0) // ici on vérifie si l'arme magique a bien été trouvée
   {
   string sDestTag =  "RespawnPoint"; // ça c'est le tag du waypoint de téléportation, situé dans le temple ; si vous le changez, pensez aussi à le modifier ici...

   if (GetIsObjectValid(GetObjectByTag(sDestTag)))
     {

        if (sDestTag == "RespawnPoint") // ... et ici aussi
        {
            object oPriest = GetObjectByTag("NW_DEATH_CLERIC");

            AssignCommand(oPriest, DelayCommand(2.1, PlayVoiceChat(VOICE_CHAT_TALKTOME, oPriest)));

            SetLocalLocation(oRespawner, "NW_L_I_DIED_HERE", GetLocation(GetLastRespawnButtonPresser()));
            SetLocalInt(oRespawner, "NW_L_I_DIED", 1);
            SetLocalObject(oPriest, "NW_L_LASTDIED", GetLastRespawnButtonPresser());
        }


        object oSpawnPoint = GetObjectByTag(sDestTag);
        SetLocalInt (oRespawner, "mort", 1);
        AssignCommand(oRespawner,JumpToLocation(GetLocation(oSpawnPoint)));
        // * mak
     }
   }
   else
   {
    //Respawn après : résurrect sur place mise en place des token -1 constits :

    object oRez = GetLastRespawnButtonPresser();
    ApplyEffectToObject(DURATION_TYPE_INSTANT,EffectHeal(GetMaxHitPoints(oRespawner)), oRespawner);
    RemoveEffects(oRespawner);  // ces 2 lignes soignent le joueur de tous ses maux, chose que le script ne faisait pas en le ramenant dans le temple.
    int nNbRez = GetLocalInt(oRez, "nNbRez");
    nNbRez++;
    if (nNbRez <=10)
    {
      DestroyObject(GetItemInSlot(INVENTORY_SLOT_CARMOUR, oRez));
      object oPenRez = CreateItemOnObject("constit"+IntToString(nNbRez), oRez);
      AssignCommand(oRez, ActionEquipItem(oPenRez, INVENTORY_SLOT_CARMOUR));
      SetLocalInt(oRez, "nNbRez", nNbRez);
    }
    }
}


Donc pensez surtout à bien nommer les BLUEPRINTS (et pas les tags) de vos objets de constit correctement, ainsi que le WP du temple si vous en mettez un...

J'espère que ceci vous aidera et vous évitera d'y passer des jours comme moi ! Wink
_________________
Aventure ! Camaraderie ! Et acier sur acier ! Les ingrédients légendaires ! Hein Bouh ?

http://cassin1306.spaces.live.com
 
Revenir en haut Voir le profil de l'utilisateur Envoyer un message privé Visiter le site web du posteur Ignorer l'utilisateur
 
Baldurien
L'homme qui chutait sur le macadam
Inscrit le: 12 Sep 2002
Messages: 14064
Localisation: Quadran Alpha
Répondre en citant
Posté le : 20/10/2002 18:35:42 Sujet du message :

Code :

// Effet special: fx: VFX_*, time : en seconde, type de dommage DAMAGE_TYPE_*
struct FX
{
  int fx;
  float time;
  int damage;
  int damageType;
  int damageMin;
  int damageMax;
};

// Creer un portail:
// - oCaller : personne appelant le portail
// - lUserItemLoc : location ou creet le portail
// - Structure Portail
object CreatePortail( object oCaller, location lUserItemLoc, struct FX cBeam, struct FX cAura, int iType = 0 );

object CreatePortail( object oCaller, location lUserItemLoc, struct FX cBeam, struct FX cAura, int iType = 0 )
{
  int bCanCreate = TRUE;

  object oPortail = OBJECT_INVALID;

  /////////////////////////////////////////////////////
  /* Partie a modifier selon le type d'action voulue */
  if ( iType == 0 &&
       GetIsPC( oCaller ) &&
       GetLocalInt( GetModule(), "bal_portail_used_by_" + GetPCPlayerName( oCaller ) )
       == TRUE )
  {
    FloatingTextStringOnCreature( GetPCPlayerName( oCaller ) + " : vous avez deja ouvert un portail.", oCaller, FALSE );
    bCanCreate = FALSE;
  }
  /* Partie a modifier selon le type d'action voulue */
  /////////////////////////////////////////////////////

  if ( bCanCreate == TRUE )
  {
    effect eEffect = EffectVisualEffect( VFX_DUR_ELEMENTAL_SHIELD );
    effect eEffect2 = EffectVisualEffect( cAura.fx );

    ApplyEffectAtLocation( DURATION_TYPE_TEMPORARY, eEffect, lUserItemLoc, 3.0);
    oPortail = CreateObject( OBJECT_TYPE_PLACEABLE, "teleport_portail", lUserItemLoc, FALSE );
    ApplyEffectAtLocation( DURATION_TYPE_TEMPORARY, eEffect2, lUserItemLoc, cAura.time );

    effect eLightning = EffectBeam( cBeam.fx, oPortail, BODY_NODE_CHEST );

    float fDelay = 0.2;

    object oTarget = GetFirstObjectInShape( SHAPE_SPHERE, RADIUS_SIZE_COLOSSAL, lUserItemLoc, TRUE, OBJECT_TYPE_CREATURE | OBJECT_TYPE_DOOR | OBJECT_TYPE_ITEM | OBJECT_TYPE_PLACEABLE );

    int iDamageRange = abs( cBeam.damageMax - cBeam.damageMin );
    effect eDamage;

    while ( GetIsObjectValid( oTarget ) )
    {
      if ( oTarget != oPortail )
      {
        DelayCommand(fDelay, ApplyEffectToObject( DURATION_TYPE_TEMPORARY, eLightning, oTarget, cBeam.time ) );

        if ( cBeam.damage == TRUE && iDamageRange > 0 )
        {
          eDamage = EffectDamage( ( cBeam.damageMin + Random( iDamageRange ) + 1 ), cBeam.damageType );
          DelayCommand( 0.0, ApplyEffectToObject( DURATION_TYPE_INSTANT, eDamage, oTarget ) );
        }
      }
      fDelay = fDelay + 0.1f;

     oTarget = GetNextObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_COLOSSAL, lUserItemLoc, TRUE, OBJECT_TYPE_CREATURE | OBJECT_TYPE_DOOR | OBJECT_TYPE_ITEM |  OBJECT_TYPE_PLACEABLE );
    }

    /* Type de portails
       0. portail prive de teleportation
    */

    /////////////////////////////////////////////////////
    /* Partie a modifier selon le type d'action voulue */
    if ( iType == 0 && GetIsPC( oCaller ) )
    {
      SetLocalInt( oPortail   , "bal_portail_type", iType );
      SetLocalString( oPortail, "bal_portail_user", GetPCPlayerName( oCaller ) );
      SetLocalInt( GetModule(), "bal_portail_used_by_" + GetPCPlayerName( oCaller ), 1 );
    }
    /* Partie a modifier selon le type d'action voulue */
    /////////////////////////////////////////////////////
  }

  return oPortail;
}


Un script que j'ai crée: le but est de créer un portail qui a pour blueprint teleport_portail. Ceci va en plus de créer le portail dégager des effets spéciaux histoire d'en mettre plein la vue. Ces effets spéciaux peuvent aussi mettre plein de dégâts aux créatures environnant le portail.

Je l'explique:

Code :

struct FX
{
  int fx;
  float time;
  int damage;
  int damageType;
  int damageMin;
  int damageMax;
};


Cette structure va nous permettre de définir un effet spécial, elle va nous simplifier la vie: au lieu de faire des noms de variable pas sympa du tout, on pourra faire appel à par exemple beam.time, ce qui est plus sympa quand même.

fx : il s'agit d'un entier représentant une des constantes VFX_*.
time : flottant représentant la durée de l'effet
damage : entier (ou booléen) représentant si oui (TRUE) ou non (FALSE) le portail dommagera les différentes choses (créatures, placeables, objets) qui traînent dans le coin.
damageType : type de dommage. Basiquement représenté par une constante DAMAGE_TYPE_*
damageMin, damageMax : dommage minimum et maximum. Et oui, on utilise pas les fonctions d20 Wink



Code :

object CreatePortail( object oCaller, location lUserItemLoc, struct FX cBeam, struct FX cAura, int iType = 0 )


oCaller: personne qui appelle le portail.
lUserItemLoc : l'endroit où va se 'poser' le portail. Basiquement: GetItemActivatedTargetLocation(); s'il s'agit d'une item créant le portail.
cBeam : représente le rayon (par exemple: électrique) qui 'touchera' chacun des objets présant dans la zone. Ici, cBeam.fx doit être une constante VFX_BEAM_*
cAura : lorsque le portail apparaît on crée une aura (sans effets sur les objets) : par exemple, une aura de 'froid' sur un portail menant vers les plaines hivernales. etc. Basiquement, ça doit être une constante VFX_DUR_AURA_*
iType : type de portail. Si vous désirez faire un portail menant vers l'enfer, alors il serait bon d'envoyer quelque démons, ceci vous permet d'ajouter des suppléments à la fonction Wink

La fonction renvoie par défaut le portail crée, ou un OBJECT_INVALID en cas de pépin.

Code :

  /////////////////////////////////////////////////////
  /* Partie a modifier selon le type d'action voulue */
  if ( iType == 0 &&
       GetIsPC( oCaller ) &&
       GetLocalInt( GetModule(), "bal_portail_used_by_" + GetPCPlayerName( oCaller ) )
       == TRUE )
  {
    FloatingTextStringOnCreature( GetPCPlayerName( oCaller ) + " : vous avez deja ouvert un portail.", oCaller, FALSE );
    bCanCreate = FALSE;
  }
  /* Partie a modifier selon le type d'action voulue */
  /////////////////////////////////////////////////////


Cette partie consiste basiquement à vérifier par exemple l'existance du portail et éviter qu'il soit recrée. Si vous donnez a valeur FALSE à bCanCreate alors rien ne se produira.

Code :

    /////////////////////////////////////////////////////
    /* Partie a modifier selon le type d'action voulue */
    if ( iType == 0 && GetIsPC( oCaller ) )
    {
      SetLocalInt( oPortail   , "bal_portail_type", iType );
      SetLocalString( oPortail, "bal_portail_user", GetPCPlayerName( oCaller ) );
      SetLocalInt( GetModule(), "bal_portail_used_by_" + GetPCPlayerName( oCaller ), 1 );
    }
    /* Partie a modifier selon le type d'action voulue */
    /////////////////////////////////////////////////////


C'est ici que cela se passe: en fonction du type, vous pouvez décider d'envoyer des démons, de personaliser le portail etc !



Enjoy !
_________________
#nwnights-fr @ irc.darkmyst.org TitanQuest-FR
 
Revenir en haut Voir le profil de l'utilisateur Envoyer un message privé Visiter le site web du posteur Ignorer l'utilisateur
 
elthair
Novice
Inscrit le: 22 Oct 2002
Messages: 12
Localisation: RP
Répondre en citant
Posté le : 22/10/2002 16:41:15 Sujet du message : Lien de portails

Un petit script amusant qui lie deux portails entre eux dans un module avec peu de contrainte, une cle peut-etre requise...
Utilisation:
creer un blueprint de portail avec un dialogue du style "voulez emprunter ce portail?
oui.............execution du script
non............sortie
Nommer ses portails sous cette forme: NomdePortail_A et Nomdeportail_B
et c'est tout... le lien vers la cible se fait tout seul...
Un script, un modele de portail et juste le tag a changer...

Code :

------------------------------------------------------------------
//besoin pour les fonctions de tests sur l'inventaire
#include "nw_i0_tool"

void main()
{
  //def du perso qui cause au portail
  object oClicker = GetPCSpeaker();

  //def du portail cible
  object oTarget;

  //test pour savoir si une cle speciale est demandee
  int iKeyRequired = GetLockKeyRequired(OBJECT_SELF);

  //recuperation du nom de cette fameuse cle
  string sKeyRequiredTag = GetLockKeyTag(OBJECT_SELF);

  //recuperation du tag du portail
  string sSourceName = GetTag(OBJECT_SELF);

  //on compte sa longueur
  int iSourceNameLength =  GetStringLength( sSourceName );

  //on recupere le dernier caractere du nom
  string sLastCharacter = GetStringRight( sSourceName, 1 );

  //def du nouveau dernier caractere
  string sNewLastCharacter ;

  //recuperation du nom moins le dernier caractere
  string sSourceNameBegining = GetStringLeft( sSourceName, iSourceNameLength -1 );

  //test sur le dernier caractere, si A alors devient B et reciproquement
  if ( sLastCharacter == "A" ){ sNewLastCharacter = "B";}
  if ( sLastCharacter == "B" ){ sNewLastCharacter = "A";}
 
  //la cible du portail devient le debut du nom + le nouveau dernier caractere
  oTarget = GetObjectByTag(sSourceNameBegining + sNewLastCharacter);

  // affichage de transition
  SetAreaTransitionBMP(AREA_TRANSITION_RANDOM);

  //si la cle est requise, test pour savoir si l'equipe l'a
  if (iKeyRequired == TRUE ){
  if (CheckPartyForItem(oClicker, sKeyRequiredTag))
  {

  // si oui alors on saute vers la cible
    AssignCommand(oClicker,JumpToObject(oTarget));
  }

  else
  {

  //si non texte...
    SpeakString("Vous n'avez pas la bonne cle.");
  }}
  else { AssignCommand(oClicker,JumpToObject(oTarget));}

}

_________________
Elthair,

J'epanche donc j'essuie Razz
 
Revenir en haut Voir le profil de l'utilisateur Envoyer un message privé Visiter le site web du posteur Ignorer l'utilisateur
 
Pof From Hell
Ecuyer
Inscrit le: 22 Oct 2002
Messages: 58
Localisation: Ba ....l'enfer....
Répondre en citant
Posté le : 04/12/2002 19:52:21 Sujet du message :

je voulais creer un script qui applique un effet sur un NPC qui es en train d'etre detrui....
mais comme l'effet s'applique sur le NPC ...ba quand il disparait ...l'effet aussi disparait .. Confused
donc pas cool Very Happy
alors j'ai fais ce petit script que j'ai place dans action consequentes dans un dialogue....et ca marche ...et c'est zolie !!!
voila
Code :

// Pour faire disparaitre un NPC //
// avec un effet qui persiste    //
// meme si le NPC a disparu      //
///////////////////////////////////

void main()
{
//On definit l'objet qui va disparaitre = oNPC,
object oNPC = GetObjectByTag("Ange001");

//On crée l'objet invisible sur lequel on va appliquer l'effet,
//il apparait a l'endroit ou est le NPC,
object oTarget = CreateObject(OBJECT_TYPE_PLACEABLE,"effetdeladestruc",GetLocation(oNPC));

//On determine l'effet a appliquer sur l'objet invisible,
effect eEffet = EffectVisualEffect(VFX_IMP_DEATH_L);

//On defini l'objet sur lequel va etre applique l'effet,
object oInvisible = GetNearestObjectByTag("EffetdelaDestructiondelAnge");

//ATTENTION: il y a un DelayCommand de 0.15, il est necessaire,
//car si le delai est inferieur a 0.15 ou s'il n'y a pas de delai,
//l'objet invisible n'a pas le temps d'apparaitre,
//donc l'effet ne peut etre applique,

//On applique l'effet a l'objet invisible,
DelayCommand(0.15,ApplyEffectToObject(DURATION_TYPE_INSTANT,eEffet,oInvisible));

//On fait disparaitre le NPC (c'est un ange dans mon exemple !!!),
DelayCommand(0.15,DestroyObject(oNPC));

//On detruit l'objet invisible qui ne sert plus a rien,
DelayCommand(10.0,DestroyObject(oInvisible));

//Et voila !!!
}


bon comme je débute en script....je pense que tout le monde savais ce script.....mais comme j'ai lutter pendant 3 heures ba chuis content donc voila

mais si qq'un trouve plus simple ..ou autre chose ...ba il peut me le dire

tcho
_________________
I'm a Cowboy From Hell !!!
 
Revenir en haut Voir le profil de l'utilisateur Envoyer un message privé Ignorer l'utilisateur
 
Nordehialen
Acolyte
Inscrit le: 22 Jan 2003
Messages: 37
Répondre en citant
Posté le : 25/01/2003 12:45:25 Sujet du message :

Voilà un script pour conditionner le repos dans le module "onreste"

Il a été fait Par Jedaï et ...... pour MOA Cool

Et Merci encore à toi....

" On dort obligatoirement dans une auberge et que si on achète la clef de la chambre SAUF si on a un Kit de Survie, dans ce cas on dort partout"

Code :
void main()
{
    object oPC = GetLastPCRested();
     
    string sArea = GetTag(GetArea(oPC));
     
    if (sArea == "Tag De L'Auberge1")
    {
        if( ! GetIsObjectValid(GetItemPossessedBy(oPC, "Tag de la clé1")))
        {
            AssignCommand(oPC, ClearAllActions());
            SendMessageToPC(oPC, "Vous ne pouvez pas dormir à l'auberge sans payer votre chambre !");
        }
    }
    else if (sArea == "Tag De L'Auberge2")
    {
        if( ! GetIsObjectValid(GetItemPossessedBy(oPC, "Tag de la clé2")))
        {
            AssignCommand(oPC, ClearAllActions());
            SendMessageToPC(oPC, "Vous ne pouvez pas dormir à l'auberge sans payer votre chambre !");
        }
    }
    else if (sArea == "Tag De L'Auberge3")
    {
        if( ! GetIsObjectValid(GetItemPossessedBy(oPC, "Tag de la clé3")))
        {
            AssignCommand(oPC, ClearAllActions());
            SendMessageToPC(oPC, "Vous ne pouvez pas dormir à l'auberge sans payer votre chambre !");
        }
    }
    else
    {
        if( ! GetIsObjectValid(GetItemPossessedBy(oPC, "Tag du kit")))
        {
            AssignCommand(oPC, ClearAllActions());
            SendMessageToPC(oPC, "Vous ne pouvez pas dormir à la belle étoile sans sac de couchage !");
        }
    }

}

_________________
Une drow loyale bonne, difficile à croire et pourtant... Wink
 
Revenir en haut Voir le profil de l'utilisateur Envoyer un message privé Ignorer l'utilisateur
 
Serguai
Grand Chevalier
Inscrit le: 07 Déc 2002
Messages: 104
Répondre en citant
Posté le : 16/02/2003 20:19:00 Sujet du message : Des pnj qui ne sont pas au même endroit le jour ou la nuit

Voilà donc un petit système de scripts pour que vos PNJ je soient pas au même endroit le jour et la nuit.
Une petite explication sur le fonctionnement:
Il vous faut remplacer les scripts onheartbeat et onspawn des pnj en question par ceux que je vous propose. Ensuite très simple vous n'avez que 4 waypoints a créer:
- Dans le lieu où le pnj se trouve le jour il vous faut un tag EXIT_tagdupnj (endroit ou le pnj s'en ira le soir), et un tag DAY_tagdupnj (endroit ou il apparait le jour)
- Dans le lieu où le pnj se trouve la nuit il vous faut un tag EXIT_tagdupnj (endroit ou le pnj s'en ira le matin), et un tag NIGHT_tagdupnj (endroit ou il apparait la nuit).

Dans les scripts vous n'avez qu'une chose à spécifier, c'est dans le onspawn les zones de jour qu'il faut lister dans la condition (c'est important pour initialiser les variables à chaque respawn).
Si vous ne voulez pas encombrer la condition, vous pouvez toujours choisir de faire autant de onspawn que de ville en extérieur... ou trouver une autre amélioration. Je suis ouvert à toute suggestion
Pour celà, jetez un coup d'oeil au commentaire.

Voilà le premier script, celui du OnHeartBeat:
La portion de code que j'ai rajouté au OnHeartBeat normal se trouve a la fin (attention, c'est important que ca se trouve a la fin !).
Code :
//::///////////////////////////////////////////////
//:: Heartbeat personnalise
//:: RAV_ANIMHB
//:://////////////////////////////////////////////
/*
    Animations personnalisees
*/
//:://////////////////////////////////////////////
//:: Created By: Serge GANDOLPHE
//:: Created On: 13 fevrier 2003
//:://////////////////////////////////////////////
#include "NW_I0_GENERIC"
#include "nw_i0_plot"

void main()
{

    //if(!GetIsInCombat() && !IsInConversation(OBJECT_SELF))
    //    ActionRandomWalk();

    if(GetSpawnInCondition(NW_FLAG_FAST_BUFF_ENEMY))
    {
        if(TalentAdvancedBuff(40.0))
        {
            SetSpawnInCondition(NW_FLAG_FAST_BUFF_ENEMY, FALSE);
            return;
        }
    }

    if(GetSpawnInCondition(NW_FLAG_DAY_NIGHT_POSTING))
    {
        int nDay = FALSE;
        if(GetIsDay() || GetIsDawn())
        {
            nDay = TRUE;
        }
        if(GetLocalInt(OBJECT_SELF, "NW_GENERIC_DAY_NIGHT") != nDay)
        {
            if(nDay == TRUE)
            {
                SetLocalInt(OBJECT_SELF, "NW_GENERIC_DAY_NIGHT", TRUE);
            }
            else
            {
                SetLocalInt(OBJECT_SELF, "NW_GENERIC_DAY_NIGHT", FALSE);
            }
            WalkWayPoints();
        }
    }

    if(!GetHasEffect(EFFECT_TYPE_SLEEP))
    {
        if(!GetIsPostOrWalking())
        {
            if(!GetIsObjectValid(GetAttemptedAttackTarget()) && !GetIsObjectValid(GetAttemptedSpellTarget()))
            {
                if(!GetIsObjectValid(GetNearestCreature(CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, OBJECT_SELF, 1, CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN)))
                {
                    if(!GetBehaviorState(NW_FLAG_BEHAVIOR_SPECIAL) && !IsInConversation(OBJECT_SELF))
                    {
                        if(GetSpawnInCondition(NW_FLAG_AMBIENT_ANIMATIONS) || GetSpawnInCondition(NW_FLAG_AMBIENT_ANIMATIONS_AVIAN))
                        {
                            PlayMobileAmbientAnimations();
                        }
                        else if(GetIsEncounterCreature() &&
                        !GetIsObjectValid(GetNearestCreature(CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, OBJECT_SELF, 1, CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN)))
                        {
                            PlayMobileAmbientAnimations();
                        }
                        else if(GetSpawnInCondition(NW_FLAG_IMMOBILE_AMBIENT_ANIMATIONS) &&
                           !GetIsObjectValid(GetNearestCreature(CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, OBJECT_SELF, 1, CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN)))
                        {
                            PlayImmobileAmbientAnimations();
                        }
                    }
                    else
                    {
                        DetermineSpecialBehavior();
                    }
                }
                else
                {
                    //DetermineCombatRound();
                }
            }
        }
    }
    else
    {
        if(GetSpawnInCondition(NW_FLAG_SLEEPING_AT_NIGHT))
        {
            effect eVis = EffectVisualEffect(VFX_IMP_SLEEP);
            if(d10() > 6)
            {
                ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, OBJECT_SELF);
            }
        }
    }
    if(GetSpawnInCondition(NW_FLAG_HEARTBEAT_EVENT))
    {
        SignalEvent(OBJECT_SELF, EventUserDefined(1001));
    }

    //Ca se passe ici
    /*Le jour le pnj se ballade dans le village et a la tombee de la nuit il rentre chez lui*/
        if(GetLocalInt(OBJECT_SELF,"isoutside"))
        {
            if((GetIsNight() || GetIsDusk()) && !GetLocalInt(OBJECT_SELF,"movedinside")){
                SetLocalInt(OBJECT_SELF,"isoutside", FALSE);
                SetLocalInt(OBJECT_SELF,"movedoutside",FALSE);
                SetLocalInt(OBJECT_SELF,"movedinside",TRUE);
                ClearAllActions(TRUE);
                EscapeArea(FALSE,"EXIT_"+GetTag(OBJECT_SELF));
                object OPnj = CreateObject(OBJECT_TYPE_CREATURE,GetResRef(OBJECT_SELF),GetLocation(GetWaypointByTag("NIGHT_"+GetTag(OBJECT_SELF))));
                DestroyObject(OBJECT_SELF,10.0f);//Pour etre certain de ne pas avoir de clones
            }
        }
        else{
            if((GetIsDay() || GetIsDawn()) && !GetLocalInt(OBJECT_SELF,"movedoutside")){
                SetLocalInt(OBJECT_SELF,"isoutside", TRUE);
                SetLocalInt(OBJECT_SELF,"movedoutside",TRUE);
                SetLocalInt(OBJECT_SELF,"movedinside",FALSE);
                ClearAllActions(TRUE);
                EscapeArea(FALSE,"EXIT_"+GetTag(OBJECT_SELF));
                object OPnj = CreateObject(OBJECT_TYPE_CREATURE,GetResRef(OBJECT_SELF),GetLocation(GetWaypointByTag("DAY_"+GetTag(OBJECT_SELF))));
                DestroyObject(OBJECT_SELF,10.0f);
            }
        }
}


Voilà le code OnSpawn

Code :
//::///////////////////////////////////////////////
//:: Default: On Spawn In
//:: rav_os_commoner
//:: Par Serge GANDOLPHE
//:://////////////////////////////////////////////
/*
    Determines the course of action to be taken
    after having just been spawned in
*/
//:://////////////////////////////////////////////
//:: Created By: Preston Watamaniuk
//:: Created On: Oct 25, 2001
//:://////////////////////////////////////////////
#include "NW_O2_CONINCLUDE"
#include "NW_I0_GENERIC"

void main()
{
    //Ici il faut lister vos zones de JOUR!!!!
    //Remplacez simplement zone1 et zone2 par les tags de vos zones et rajoutez autant de  || areaTag =="zonex" que vous avez de zones de jour
    string areaTag = GetTag(GetArea(OBJECT_SELF));
    if(areaTag =="zone1" || areaTag =="zone2" ){
        SetLocalInt(OBJECT_SELF,"isoutside", TRUE);
        SetLocalInt(OBJECT_SELF,"movedoutside",TRUE);
        SetLocalInt(OBJECT_SELF,"movedinside",FALSE);
    }
    else{
        SetLocalInt(OBJECT_SELF,"isoutside", FALSE);
        SetLocalInt(OBJECT_SELF,"movedoutside",FALSE);
        SetLocalInt(OBJECT_SELF,"movedinside",TRUE);
    }
// OPTIONAL BEHAVIORS (Comment In or Out to Activate ) ****************************************************************************
     //SetSpawnInCondition(NW_FLAG_SPECIAL_CONVERSATION);
     //SetSpawnInCondition(NW_FLAG_SPECIAL_COMBAT_CONVERSATION);
                // This causes the creature to say a special greeting in their conversation file
                // upon Perceiving the player. Attach the [NW_D2_GenCheck.nss] script to the desired
                // greeting in order to designate it. As the creature is actually saying this to
                // himself, don't attach any player responses to the greeting.

     //SetSpawnInCondition(NW_FLAG_SHOUT_ATTACK_MY_TARGET);
                // This will set the listening pattern on the NPC to attack when allies call
     //SetSpawnInCondition(NW_FLAG_STEALTH);
                // If the NPC has stealth and they are a rogue go into stealth mode
     //SetSpawnInCondition(NW_FLAG_SEARCH);
                // If the NPC has Search go into Search Mode
     //SetSpawnInCondition(NW_FLAG_SET_WARNINGS);
                // This will set the NPC to give a warning to non-enemies before attacking

     //SetSpawnInCondition(NW_FLAG_SLEEP);
                //Creatures that spawn in during the night will be asleep.
     //SetSpawnInCondition(NW_FLAG_DAY_NIGHT_POSTING);
     //SetSpawnInCondition(NW_FLAG_APPEAR_SPAWN_IN_ANIMATION);
     //SetSpawnInCondition(NW_FLAG_IMMOBILE_AMBIENT_ANIMATIONS);
     //SetSpawnInCondition(NW_FLAG_AMBIENT_ANIMATIONS);
                //This will play Ambient Animations until the NPC sees an enemy or is cleared.
                //NOTE that these animations will play automatically for Encounter Creatures.

    // NOTE: ONLY ONE OF THE FOLOOWING ESCAPE COMMANDS SHOULD EVER BE ACTIVATED AT ANY ONE TIME.
    //SetSpawnInCondition(NW_FLAG_ESCAPE_RETURN);    // OPTIONAL BEHAVIOR (Flee to a way point and return a short time later.)
    //SetSpawnInCondition(NW_FLAG_ESCAPE_LEAVE);     // OPTIONAL BEHAVIOR (Flee to a way point and do not return.)
    //SetSpawnInCondition(NW_FLAG_TELEPORT_LEAVE);   // OPTIONAL BEHAVIOR (Teleport to safety and do not return.)
    //SetSpawnInCondition(NW_FLAG_TELEPORT_RETURN);  // OPTIONAL BEHAVIOR (Teleport to safety and return a short time later.)

// CUSTOM USER DEFINED EVENTS
/*
    The following settings will allow the user to fire one of the blank user defined events in the NW_D2_DefaultD.  Like the
    On Spawn In script this script is meant to be customized by the end user to allow for unique behaviors.  The user defined
    events user 1000 - 1010
*/
    //SetSpawnInCondition(NW_FLAG_HEARTBEAT_EVENT);        //OPTIONAL BEHAVIOR - Fire User Defined Event 1001
    //SetSpawnInCondition(NW_FLAG_PERCIEVE_EVENT);         //OPTIONAL BEHAVIOR - Fire User Defined Event 1002
    //SetSpawnInCondition(NW_FLAG_ATTACK_EVENT);           //OPTIONAL BEHAVIOR - Fire User Defined Event 1005
    //SetSpawnInCondition(NW_FLAG_DAMAGED_EVENT);          //OPTIONAL BEHAVIOR - Fire User Defined Event 1006
    //SetSpawnInCondition(NW_FLAG_DISTURBED_EVENT);        //OPTIONAL BEHAVIOR - Fire User Defined Event 1008
    //SetSpawnInCondition(NW_FLAG_END_COMBAT_ROUND_EVENT); //OPTIONAL BEHAVIOR - Fire User Defined Event 1003
    //SetSpawnInCondition(NW_FLAG_ON_DIALOGUE_EVENT);      //OPTIONAL BEHAVIOR - Fire User Defined Event 1004
    //SetSpawnInCondition(NW_FLAG_DEATH_EVENT);            //OPTIONAL BEHAVIOR - Fire User Defined Event 1007

// DEFAULT GENERIC BEHAVIOR (DO NOT TOUCH) *****************************************************************************************
    SetListeningPatterns();    // Goes through and sets up which shouts the NPC will listen to.
    WalkWayPoints();           // Optional Parameter: void WalkWayPoints(int nRun = FALSE, float fPause = 1.0)
                               // 1. Looks to see if any Way Points in the module have the tag "WP_" + NPC TAG + "_0X", if so walk them
                               // 2. If the tag of the Way Point is "POST_" + NPC TAG the creature will return this way point after
                               //    combat.
    GenerateNPCTreasure();     //* Use this to create a small amount of treasure on the creature
}


Concernant les animations: Au début du OnHeartBeat j'ai mis un ActionRandomWalk que vous pouvez évidemment modifier selon l'action que vous souhaitez que votre pnj effectue.
Vous pouvez tout simplement l'enlever si vous voulez que le pnj soit immobile.
Vous pouvez toujours décommenter certains SetSpawnInCondition du OnSpawn si vous voulez affecter un comportement spécial a votre PNJ (ca marche comme avant, cf les commentaires en anglais qui sont ceux d'origine).
Pour toutes questions, remarque ou améliorations (je le modifierai peut être encore), postez sur le Thread intitulé "Une ville vivante"
Je précise que j'ai testé ce système et que ca ne ralentit pas plus que la normale.
 
Revenir en haut Voir le profil de l'utilisateur Envoyer un message privé Visiter le site web du posteur Numéro ICQ Ignorer l'utilisateur
 
Lavok
Légende vivante
Inscrit le: 22 Oct 2002
Messages: 434
Localisation: Sphère planaire
Répondre en citant
Posté le : 22/02/2003 10:33:08 Sujet du message : Mannequin d'entraînnement

Un script un peu long mais très simple quand je compare aux autres ici :

Code :

#include "nw_i0_tool"
void main()
{
 object oRigolo = GetLastDamager();
 //oRigolo est celui qui a touché le mannequin.
 object oGlups = OBJECT_SELF;
  //oGlups, c'est le mannequin.
  effect eBoum = EffectVisualEffect(VFX_FNF_SCREEN_SHAKE);
  //eBoum est un effet de tremblement d'écran qui est facultatif.
  int nDamage = GetTotalDamageDealt();
 //nDamage est le nombre de points de dommages qu'a reçu le mannequin.
if (GetIsPC(oRigolo))
  //Ici, on vérifie que oRigolo est bien un joueur.
  {
           if(nDamage > 99)
           //Ce qui suit entre accolades est ce qui se passera si nDamage vaut 100 ou plus.
           {
           SendMessageToPC(oRigolo, "Tricheur !");
           //On ne peut décement pas faire autant de dommages en un coup !
           DelayCommand(1.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectDeath(TRUE), oRigolo));
           //Bref, on tue le tricheur sans sommations !
                         }
                         else
                         {
           if(nDamage > 59)
           //Ce qui suit entre accolades est ce qui se passera si nDamage vaut 60 ou plus.
           {
           RewardPartyXP(20, oRigolo);
           //On offre 20 xp au joueur.
           SendMessageToPC(oRigolo, "CHAMPION DU MONDE !!!");
           //Un petit message au joueur...
           ApplyEffectToObject(DURATION_TYPE_INSTANT, eBoum, oGlups);
           DelayCommand(2.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eBoum, oGlups));
           DelayCommand(4.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eBoum, oGlups));
           //L'effet de tremblement. On peut le supprimer sans aucun problème.
                        }
           else
             {
            if(nDamage > 49)
           //Ce qui suit entre accolades est ce qui se passera si nDamage vaut 50 ou plus.
           {
           RewardPartyXP(10, oRigolo);
            //On offre 10 xp au joueur.
          SendMessageToPC(oRigolo, "CHAMPION !");
           //Un petit message au joueur...
           ApplyEffectToObject(DURATION_TYPE_INSTANT, eBoum, oGlups);
            //L'effet de tremblement. On peut le supprimer sans aucun problème.
                         }
           else
             {
            if(nDamage > 39)
           //Ce qui suit entre accolades est ce qui se passera si nDamage vaut 40 ou plus.
           {
           RewardPartyXP(8, oRigolo);
            //On offre 8 xp au joueur.
           SendMessageToPC(oRigolo, "Champion !");
            //Un petit message au joueur...
              }
           else
             {
            if(nDamage > 29)
           //Ce qui suit entre accolades est ce qui se passera si nDamage vaut 30 ou plus.
           {
           RewardPartyXP(6, oRigolo);
            //On offre 6 xp au joueur.
           SendMessageToPC(oRigolo, "Des muscles d'acier !");
             //Un petit message au joueur...
             }
           else
             {
           if(nDamage > 19)
           //Ce qui suit entre accolades est ce qui se passera si nDamage vaut 20 ou plus.
           {
           RewardPartyXP(4, oRigolo);
             //On offre 4 xp au joueur.
           SendMessageToPC(oRigolo, "Quelle force !");
             //Un petit message au joueur...
             }
           else
             {
          if(nDamage > 14)
           //Ce qui suit entre accolades est ce qui se passera si nDamage vaut 15 ou plus.
           {
           RewardPartyXP(3, oRigolo);
            //On offre 3 xp au joueur.
           SendMessageToPC(oRigolo, "Impressionant !");
             //Un petit message au joueur...
             }
           else
             {
           if(nDamage > 9)
           //Ce qui suit entre accolades est ce qui se passera si nDamage vaut 10 ou plus.
           {
           RewardPartyXP(2, oRigolo);
             //On offre 2 xp au joueur.
           SendMessageToPC(oRigolo, "Pas mal !");
             //Un petit message au joueur...
             }
           else
             {
            if(nDamage > 4)
            //Ce qui suit entre accolades est ce qui se passera si nDamage vaut 5 ou plus.
                {
                 RewardPartyXP(1, oRigolo);
                  //On offre 1 xp au joueur.
                SendMessageToPC(oRigolo, "Bof !");
                //Un petit message au joueur...
                }
                else
                {
                if(nDamage > 2)
            //Ce qui suit entre accolades est ce qui se passera si nDamage vaut 3 ou plus.
                {
                SendMessageToPC(oRigolo, "Pas terrible !");
                //Un petit message au joueur...
                }
                else
               //Ce qui suit entre accolades est ce qui se passera si nDamage vaut 1 ou 2.
                {
                SendMessageToPC(oRigolo, "Mauviette !");
               //Un petit message au joueur...
              }
              }
              }
              }
              }
              }
              }
              }
              }
              }
              }
              else
              //Ce qui suit entre accolades est ce qui se passera si oRigolo n'est pas un joueur.
              {
              ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectHeal(nDamage), oGlups);
              //On guérit le mannequin des dommages qu'il vient de recevoir( cela n'arrive donc que si une autre créature attaque le mannequin ).
              }
              }




Je ne pense pas qu'il y ait besoin d'énormément d'explications Very Happy : il suffit de mettre le script dans le OnDamaged ET le OnDeath du mannequin ( avec des scripts empêchant une contre-attaque bien sûr Very Happy ). Attention ! Surtout ne pas mettre "intrigue" au mannequin, sinon le script ne fonctionnera pas. Je conseille de mettre aux alentours de 200 points de vie au mannequin car c'est une source très facile d'xp( si on le rend invincible, les joueurs de votre module risquent de laisser leur personnage s'entraînner indéfiniment Confused !). Le mannequin doit être idéalement immunisé contre les sorts et tout ce qui ne sont pas des dommages physiques. Il est bien évident que les valeurs ( d'xp ou de dommages minimum ) et les messages envoyés au joueur sont très facilement modifiables. De même, ceux qui n'aiment pas l'effet de tremblement en cas de gros dommages peuvent l'enlever.

PS : Merci à Jedaï pour l'idée du "GetTotalDamageDealt()" ( c'était pour une cible mais c'est la même chose pour un mannequin )

EDIT : Attention ! Quand je parle de mannequin c'est en tant que créature avec une apparence de mannequin et pas en tant que plaçable !

EDIT2 : Je précise le script qui empêche la contre-attaque :
Code :


void main()
{
    object oPC = GetLastAttacker();
    SetIsTemporaryFriend(oPC,OBJECT_SELF,FALSE,0.001);
    DelayCommand(0.001,SetIsTemporaryEnemy(oPC));
}



A placer sur le 'OnPhysicalAttacked' et le 'OnSpellCastAt' du mannequin. Tous les autres événements que je n'ai pas encore cités sont vides. Le mannequin est immobile.
_________________
ToB : Une seule chose semble certaine : tant que le trône de sang de Bhaal restera vide, le chaos règnera.

Moi : Une seule chose semble certaine : tant que la tête de singe de Bush restera vide, le chaos règnera.
 
Revenir en haut Voir le profil de l'utilisateur Envoyer un message privé Ignorer l'utilisateur
 
Albator003
Invité


Répondre en citant
Posté le : 25/04/2003 12:16:38 Sujet du message :

désoler Cassin me suis planter sur mon envoie j'ai mis citation au lieux de nwn Script...delete mon post si tu peux

Bijour a tous
bien pour cela crée un placable (logique) et donner lui un tag et cocher la case intrigue. Apres ça crée une arme perso à laquel vous atribuerai un tag. Une fois que c'ets fais mettez ce script sur le On Damaged du placable

Code :
//://////////////////////////////////////////////
//:: FileName : Placable destructible que par une arme
//://///////////////////////////////////////////
//://///////////////////////////////////////////
//:: Created By: Albator003
//:: Created On:
//://///////////////////////////////////////////
void main()
{
object oPJ = GetLastDamager(); // On prend le dernier joueur qui attaque le placable
if(GetTag(GetLastWeaponUsed(oPJ)) == ("Tag de l'arme perso")) // On regarde si il possde l'arme pour dtruire le placable dans ce cas il la possde
{
effect eCasse = EffectVisualEffect(VFX_IMP_DEATH,VFX_FNF_LOS_EVIL_30); //Quelques effets visuelles pour que ce soit un peu plus beau
effect eCasse1 = EffectVisualEffect(VFX_IMP_LIGHTNING_M,VFX_DUR_WEB_MASS); //idem
ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eCasse, GetLocation(OBJECT_SELF)); //Execution des effet pour le cas ou il possede l'arme
ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eCasse1, GetLocation(OBJECT_SELF)); // Idem
DestroyObject(GetObjectByTag("Tag de votre placable")); //On detruit le placable
}
{
if(GetTag(GetLastWeaponUsed(oPJ)) != ("Tag de l'arme perso")) // On regarde si le joueur a l'arme (ici il ne la pas)

ActionSpeakString("*Vous touchez l'autel mais n'y faite aucune égratignure*"); // On lui signal que c'est pas la peine de s'acharner dessus lol
}
}


encore sry
 
Revenir en haut
 
Cassin
Papa-poule(t) & poissard intemporel
Inscrit le: 16 Sep 2002
Messages: 7471
Localisation: 6 bis rue de la Couveuse, Poulailler 39b
Répondre en citant
Posté le : 12/05/2003 08:47:30 Sujet du message :

Un récapitulatif des scripts des henchmen
_________________
Aventure ! Camaraderie ! Et acier sur acier ! Les ingrédients légendaires ! Hein Bouh ?

http://cassin1306.spaces.live.com
 
Revenir en haut Voir le profil de l'utilisateur Envoyer un message privé Visiter le site web du posteur Ignorer l'utilisateur
 
Tuyen
Demi-dieu
Inscrit le: 23 Nov 2002
Messages: 460
Localisation: Chez moi
Répondre en citant
Posté le : 16/05/2003 01:30:01 Sujet du message :

Lisez les instructions en commentaires sur le script tutu_transe pour savoir comment faire pour utilisez la transe dans vos modules comme dans FF9
Code :
//::///////////////////////////////////////////////
//:: Name    tutu_transe
//:: FileName
//:: Copyright (c) 2001 Bioware Corp.
//:://////////////////////////////////////////////
/*mettez ce script sous le nom de "tutu_transe" dans votre liste de scripts du module
Modifier le script NW_C2_DEFAULT3 ( c'est le script de fin de round ). Ensuite creez
une arme quelconque et donnez lui le tag de trance_01, trance_02 ou trance_99. Lorsque
vous utiliserez une de ces armes dans votre module, au bout d'un certain nombre de combats,
votre perso va entrer en transe et devenir beaucoup plus fort. Cette periode dure un court
instant et apres il perd beaucoup plus de puissance qu'avant la transe. Cette periode
des effets secondaires dure 90sec (modifiable).
Je me suis inspire d'un script deja poste sur NW Vault :
http://nwvault.ign.com/Files/scripts/data/1040734959970.shtml

A noter que lorsque le PJ quitte un combat pendant la transe, lorsqu'il rencontrera
de nouveau un ennemi il reviendra a l'etat de transe, tandis que les effets de la
contretranse sont predefinis.
*/
//:://////////////////////////////////////////////
//:: Created By:   Marvin Kosh
//:: Modified By:  Tuyen
//:://////////////////////////////////////////////
void main()
{
    // ***********************DEFINITION DES VARIABLES***************************
    object oTranse = OBJECT_SELF;
    int iTemps = GetLocalInt(oTranse, "temps");

    // Definir le nombre de Hit Point max et actuel du perso
    int iMaxHP = GetMaxHitPoints(oTranse);
    int iCurHP = GetCurrentHitPoints(oTranse);
    string sWeapon = GetTag(GetItemInSlot(INVENTORY_SLOT_RIGHTHAND, oTranse));

    // Definir le type de transe
    int iTranceProcess = StringToInt(GetSubString(sWeapon, 7, 2));

    // Definir les dialogues d'entree et de sortie de transe
    string sTranceStart = "*Transe!*";
    string sTranceEnd = "Vous sentez les effets de la transe vous quitter.";

    // Definir la duree du temps de transe et de contretranse
    float fEffectDur = 10.0;//Ne pas changer cette valeur
    float fSideEffectDur = 90.0; /*Changez cette valeur si vous voulez que
    les effets negatifs durent plus longtemps*/

    // Definir les effets de transe et de contretranse
    effect TranceEffect1;
    effect TranceEffect2;
    effect TranceEffect3;
    effect TranceEffect4;
    effect TranceSideEffect1;
    effect TranceSideEffect2;
    effect TranceSideEffect3;

    /* Definir les effets pour chaque type de transe : Chaque cas correspond a
    un type de transe different. Vous pouvez creer des transes qui ameliorent
    les capacites de combat ou plutot ceux de magie, et aussi modifier leurs
    puissances. Pour cela utiliser les fonctions de type 'Effect***' et ajouter
    cases entre case 1 et case 99 ne pas oublier de les declater en haut si vous
    voulez ajoutez plus de 4 effets pour un type de transe. */

    switch(iTranceProcess)
        {
        case 1:
        TranceEffect1 = EffectAbilityIncrease(ABILITY_STRENGTH, 10);
        TranceEffect2 = EffectHaste();
        TranceEffect3 = EffectVisualEffect(VFX_FNF_LOS_HOLY_30, FALSE);
        TranceEffect4 = EffectVisualEffect(VFX_DUR_PROTECTION_GOOD_MAJOR, FALSE);
        break;
        case 2:
        TranceEffect1 = EffectSpellResistanceIncrease(25);
        TranceEffect2 = EffectDamageReduction(10, DAMAGE_POWER_PLUS_TWO, 100);
        TranceEffect3 = EffectVisualEffect(VFX_IMP_HARM, FALSE);
        TranceEffect4 = EffectVisualEffect(VFX_DUR_SANCTUARY, FALSE);
        break;
        case 99:
        TranceEffect1 = EffectDamageIncrease(DAMAGE_BONUS_2d6, DAMAGE_TYPE_NEGATIVE);
        TranceEffect2 = EffectAttackIncrease(10, ATTACK_BONUS_MISC);
        TranceEffect3 = EffectVisualEffect(VFX_DUR_PROTECTION_EVIL_MAJOR, FALSE);
        TranceEffect4 = EffectVisualEffect(VFX_DUR_PROTECTION_ELEMENTS, FALSE);
        break;
        }

    // Definir les effets de contretranse pour chaque type de transe
    switch (iTranceProcess)
        {
        case 1:
        TranceSideEffect1 = EffectAbilityDecrease(ABILITY_STRENGTH, 14);
        TranceSideEffect2 = EffectSlow();
        TranceSideEffect3 = EffectVisualEffect(VFX_IMP_DISPEL, FALSE);
        break;
        case 2:
        TranceSideEffect1 = EffectSpellResistanceDecrease(25);
        TranceSideEffect2 = EffectDispelMagicAll(20);
        TranceSideEffect3 = EffectVisualEffect(VFX_IMP_DISPEL, FALSE);
        break;
        case 99:
        TranceSideEffect1 = EffectVisualEffect(VFX_IMP_DEATH, FALSE);
        TranceSideEffect2 = EffectSkillDecrease (SKILL_ALL_SKILLS, 20);
        TranceSideEffect3 = EffectVisualEffect(VFX_FNF_PWKILL, FALSE);
        break;
        }


    //************** C'EST LA QUE LES CHOSES SERIEUSES COMMENCENT **************
    //Incrementation de la variable temps d'un point
    iTemps = iTemps + 1;
    SetLocalInt(oTranse, "temps", iTemps);
    //Enlevez les commentaires de la ligne ci-dessous pour avoir le decompte des rounds
    //FloatingTextStringOnCreature(IntToString(iTemps), oTranse, FALSE);


    //Pendant 40 rounds, il ne se passe rien

    //A partir du 40ieme round et jusqu'au 47ieme round, le perso entre en transe
    if ((iTemps == 40) && (GetIsInCombat(oTranse)==TRUE))
      {
         FloatingTextStringOnCreature(sTranceStart, oTranse, FALSE);
         ApplyEffectToObject(DURATION_TYPE_TEMPORARY, TranceEffect3, oTranse, fEffectDur);
      }
    //Application de divers effets
    if ((iTemps >= 40) && (iTemps < 47) && (GetIsInCombat(oTranse)==TRUE))
      {
         ApplyEffectToObject(DURATION_TYPE_TEMPORARY, TranceEffect1, oTranse, fEffectDur);
         ApplyEffectToObject(DURATION_TYPE_TEMPORARY, TranceEffect2, oTranse, fEffectDur);
         ApplyEffectToObject(DURATION_TYPE_TEMPORARY, TranceEffect4, oTranse, fEffectDur);
      }
    //Au 47ieme round, c'est la fin de la transe, le perso se trouve sous des effets de
    //contretranse, qui le rabaissent. Ces effets durent
    if (iTemps == 47)
      {
         SendMessageToPC(oTranse, sTranceEnd);
         ApplyEffectToObject(DURATION_TYPE_TEMPORARY, TranceSideEffect1, oTranse, fSideEffectDur);
         ApplyEffectToObject(DURATION_TYPE_TEMPORARY, TranceSideEffect2, oTranse, fSideEffectDur);
         ApplyEffectToObject(DURATION_TYPE_TEMPORARY, TranceSideEffect3, oTranse, fSideEffectDur);
      }
    //Lorsque le compteur atteint 55, le remettre a 0
    if (iTemps == 55)
      {
         iTemps = 0;
      }
    SetLocalInt(oTranse, "temps", iTemps);

}



Et modifier le fichier nw_c2_default3 ( pour cela taper son nom lors de l'ouverture d'un script )
Code :
//::///////////////////////////////////////////////
//:: Default: End of Combat Round
//:: NW_C2_DEFAULT3
//:: Copyright (c) 2001 Bioware Corp.
//:://////////////////////////////////////////////
/*
    Calls the end of combat script every round
*/
//:://////////////////////////////////////////////
//:: Created By: Preston Watamaniuk
//:: Modified By : Marvin Kosh
//:: Implemente dans ce module par : Votre serviteur Tuyen (o_o)
//:: Created On: Oct 16, 2001
//:://////////////////////////////////////////////

#include "NW_I0_GENERIC"
void main()
{
    // Modifications pour la transe
        // Definir le dernier ennemi( soit le PC, soit un autre NPC )
        object oTarget = GetLastAttacker();
        // definir l'armer principale utilisee ( main droie )
        object oMainWeapon =(GetItemInSlot(INVENTORY_SLOT_RIGHTHAND, oTarget));
        // definir le tag de l'arme en tant que string
        string sTag = GetTag(oMainWeapon);
        // verifie si le tag commence par "transe_"
        // si c'est le cas lancer le script "tutu_transe" sur le dernier ennemi
        if (GetSubString(sTag, 0, 7) == "trance_")
        ExecuteScript("tutu_transe", oTarget);
    // Fin des modifications
    if(GetBehaviorState(NW_FLAG_BEHAVIOR_SPECIAL))
    {
        DetermineSpecialBehavior();
    }
    else if(!GetSpawnInCondition(NW_FLAG_SET_WARNINGS))
    {
       DetermineCombatRound();
    }
    if(GetSpawnInCondition(NW_FLAG_END_COMBAT_ROUND_EVENT))
    {
        SignalEvent(OBJECT_SELF, EventUserDefined(1003));
    }
}


Edit de finipe : j'ai ajouté un tout petit espace au début de tes def de variables, parce que le /* faussait le tout et mettait des trucs en commentaires Smile
 
Revenir en haut Voir le profil de l'utilisateur Envoyer un message privé MSN Messenger Ignorer l'utilisateur
 
Tyrion
Ecuyer
Inscrit le: 23 Fév 2003
Messages: 43
Répondre en citant
Posté le : 19/05/2003 09:22:37 Sujet du message :

Voila maintenant quelques semaines que je travaille sur un système de prison automatique et en rajoutant un cote assez rp, suite a quelques problèmes rencontrés lors de mes testes, j'ai perdu un peu de temps donc ce que je voulais rajouter (comme option pour le système) ne sont pas encore inclus.

Le système nécessite aucun DMs, il est entièrement configurable et facilement.

Ce que le système fait :

- lorsqu'un joueur Tue un autre joueur, il teleporte le tueur en prison
- il dépouille le joueur de ses objets lui mettant une tunique de bagnard
- il sort le PJ emprisonner 30 mn après son arrivée dans la prison(peut être réglé par vos soins)
- il prévient le taulard du temps qu'il lui reste avant de sortir
- il restitue tous les items au PJ
- il prévient tous les joueurs présent sur le serveur d'un envoie en prison ou d'une sortie ^^

Ce qu'il fera dans les prochaines versions : (enfin je l'espère)

- emprisonne le tueur qu'au bout de x crimes
- possibilité de sortir un PJ manuellement en coupant l chrono de tempo et rendant les objets
- j'attends vos idées ^^

Ce qui peu être mis en œuvre :

- une clef peu être posséder par les DMs pour mettre en prison manuellement
- cette même clef peu être possède par les joueurs (a définir dans le script) car sinon la clef est détruit si elle se trouve sur quelqu'un d'autre (et oui sa éviterai les petits malin qui les dupliquerais sur les serveurs autorisant les persos locaux


Voila pour la présentation.

Le système est dispo a ICI.

Merci de me dire ce que vous en penser, les bugs, ou vos idées d'amélioration. (et meme de l'aide Laughing: )

*sent la mort des PKs arriver*

Merci a elchwang (pour son aide)
 
Revenir en haut Voir le profil de l'utilisateur Envoyer un message privé MSN Messenger Numéro ICQ Ignorer l'utilisateur
 
Albator003
Invité


Répondre en citant
Posté le : 31/07/2003 18:01:36 Sujet du message : Poubelle portable

Apres le téléphone portable la poubelle portable
Apres quelque jour de reflexion voila ce que j'ai mis au point : un poubelle portative je m'explique.
tout dabord :
un contenant qui a lallure d'un coffre que je donne au PJ qui entre dans mon module.
Un livre qui sert de mode d'emploie et d'action pour ma poubelle (a detruire les item contenu dans linventaire du contenant.
Ce system peut etre utiliser dans les module ou il y a pas mal de dropitem.
Pour inciter les joueur a rendre nos terre plus belle chaque item detruit leur donne une somme d'argent Laughing (reglable a vous de choisir)
bien voila la théorie maintenant les script
Ps je ne detail pas les script c'es tassez simple a comprendre

Crée un contenant
Crée un livre dans ces propriété mettez lui lancer sort;pouvoir unique sur soi meme (utilisation illimité)

A mettre sur le OnActivateitem du module :

Code :

void main()
{
object oPC;

if (!GetIsPC(GetItemActivatedTarget())
|| GetIsInCombat(GetItemActivator())
){

SendMessageToPC(GetItemActivator(), "Vous ne pouvez pas utiliser cet objet maintenant !");
return;}

object oTarget;
oPC = GetItemActivator();



oTarget = oPC;

AssignCommand(oTarget, ActionStartConversation(oPC, "nomdudial"));

}



Crée un dialogue portant le meme nom que vous avez appeler dans le script au dessus ici "nomdudial". Crée un dialogue genre voulez vous detruire les objet - Oui ou NOn
sur le OUi vous allez a action conséquente et vous mettez ce script

Code :


void main()
{
object oPoubelle = GetObjectByTag("Tag de votre contenant");
object oPC = GetItemPossessor(oPoubelle);
object oObject = GetFirstItemInInventory(oPoubelle);
int nGold = 20;  //a vous de choisir combien vous voulez donné
while(GetIsObjectValid(oObject)==TRUE)
{
DestroyObject(oObject);
oObject = GetNextItemInInventory(oPoubelle);
GiveGoldToCreature(oPC, nGold);
}
}




Voila c'est pas bien compliquer et ca peux etre utile. Cool
...Vous aussi faite parti du comité des eboueurs !! Laughing
 
Revenir en haut
 
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/08/2003 08:05:41 Sujet du message : Multi-canaux privés de discussion sur NWN

Suite à une discussion sur un autre forum, j'ai réalisé une bibliothèque de script et proposé une solution pour créer des canaux de discussion dans NWN. C'est à l'état de prototype. Je retranscris ici les différents post qui composent le sujet, mais je vous renvoie au sujet d'origine pour toute nouvelle information qui pourrait apparaître. Ce sujet fait doublon avec la News de Gorkk.

------------------------------------

Chose promise, chose due. Voici le prototype du système de canaux privé multiple. Il est primitif et pas vraiment optimisé (autrment dit j'ai peur que ca rame un peu avec beaucoup de joueurs, mais ça reste à tester et cela peut être amélioré). Je l'ai pas beaucoup commenté également, mais je n'ai guère le temps de faire mieux pour le moment.
Voici donc ce qu'il faut faire pour l'installer. L'élement principal est une bibliothèque de script que voici et que j'appelle "lib_lrvmessqueue" :
Code :

/*******************************************************************************
**  Module      : Loreval Message Queue (prototype)                           **
**  Sous-Module : Systeme multi-canaux                                        **
**----------------------------------------------------------------------------**
**  Auteur               : Lendraste                                          **
**  Version              : 0.1b                                               **
**  Date de creation     : 14/08/2003                                         **
**  Date de modification : 16/08/2003                                         **
**  Compatibilites       : NWN 1.29+, SOU 1.30                                **
**----------------------------------------------------------------------------**
**  Module permettant la creation et la gestion de canaux et de liste de dif- **
**  fusion de message. Ce systeme s'appuie sur la presence d'un PNJ Listener  **
**----------------------------------------------------------------------------**
**  Historique                                                                **
**  14/08/2003 (v0.1b) : composition de la bibliotheque                       **
**  16/08/2003 (v0.1b) : premiere diffusion                                   **
*******************************************************************************/

// -----------------------
// Bibliothèques a inclure
// -----------------------
// --- Pas de bibliotheque ---

// --------------------------
// Déclaration des constantes
// --------------------------
string LMQ_PREFIXE="LMQ_";
string LMQ_CSUFFIX="_COUNT";

// -------------------------
// Prototypage des fonctions
// -------------------------
// --- Fonctions d'informations de base ---
int LMQ_IsChan(string sChanName);
int LMQ_IsChanCreator(object oPC, string sChanName);
int LMQ_IsChanMember(object oPC, string sChanName);
object LMQ_GetChanCreator(string sChanName);
object LMQ_GetChanMember(string sChanName, string sMember);
string LMQ_UserList(string sChanName);
// --- Fonctions d'actions primitives ---
int LMQ_AddToChannel(object oJoiner, string sChanName);
int LMQ_CreateChannel(object oCreator, string sChanName);
int LMQ_RemoveFromChannel(object oMember, string sChanName);
// --- Fonctions d'actions de haut niveau ---
int LMQ_JoinChannel(object oJoiner, string sChanName);
int LMQ_KickUser(string sChanName, string sUserName);
// --- Fonctions liees a la composition et la diffusion des messages ---
void LMQ_PushMessageOnChan(string sChanName, string sMessage, object oOwner=OBJECT_INVALID);
string LMQ_ComposeMessage(string sChanName, string sMessage, object oSender=OBJECT_INVALID);
void LMQ_SendMessage(object oDest, string sChanName, string sMessage, object oSender=OBJECT_INVALID);
// --- Fonctions liees au PNJ/Listener
void LMQ_CommandInterpretor(int nListenPN, object oOwner);
void LMQ_InitiateListener(object oListener);


// ------------------------
// Definition des fonctions
// ------------------------

/******************************************
* Fonction : LMQ_IsChan                   *
*-----------------------------------------*
* Cette fonction permet de savoir si le   *
* canal specifie existe                   *
*-----------------------------------------*
* Entree :                                *
*   sChanName : nom du canal a tester     *
*-----------------------------------------*
* Sortie :                                *
*   TRUE/FALSE indiquant si le canal exis-*
*   te ou non.                            *
*******************************************/
int LMQ_IsChan(string sChanName)
{
  // --- Recuperation du compteur suppose de membre du canal nomme ---
  int nCount=GetLocalInt(GetModule(), LMQ_PREFIXE+sChanName+LMQ_CSUFFIX);
  if (nCount>0)
  {
    // -- Compte superieur a 0 signifiant qu'il y a au moins un membre, le canal existe --
    return TRUE;
  }
  else
  {
    // -- Compte egal a 0 signifiant que le compteur n'existe pas ou qu'il n'y a pas de membre, le canal n'existe pas  --
    return FALSE;
  }
}

/******************************************
* Fonction : LMQ_IsChanMember             *
*-----------------------------------------*
* Cette fonction permet de savoir si le   *
* membre specifie appartient au canal     *
*-----------------------------------------*
* Entree :                                *
*   oPC : le membre a tester              *
*   sChanName : nom du canal a tester     *
*-----------------------------------------*
* Sortie :                                *
*   TRUE/FALSE indiquant si le membre fait*
*   bien partie du canal                  *
*******************************************/
int LMQ_IsChanMember(object oPC, string sChanName)
{
  // --- Test si le canal existe ---
  if (LMQ_IsChan(sChanName))
  {
    // --- Recupere dans  la liste le membre qui porterait le meme nom ---
    object oMember=LMQ_GetChanMember(sChanName, GetName(oPC));
    // --- Test si cette recherche a ete fructueuse
    if (GetIsObjectValid(oMember))
    {
      // -- La cle CD et le nom de joueur sont-ils identiques ? --
      if ((GetPCPublicCDKey(oPC)==GetPCPublicCDKey(oMember)) && (GetPCPlayerName(oPC)==GetPCPlayerName(oMember)))
      {
        // -- C'est bien un membre de la liste du canal --
        return TRUE;
      }
      else
      {
        // -- Il n'est pas membre --
        return FALSE;
      }
    }
    else
    {
      // -- aucun membre ne porte le meme nom, celui la n'est donc pas membre --
      return FALSE;
    }
  }
  else
  {
    // -- Le canal n'existe pas, donc pas de membre --
    return FALSE;
  }
}

/******************************************
* Fonction : LMQ_IsChanCreator            *
*-----------------------------------------*
* Cette fonction permet de savoir si le   *
* membre specifie est le createur du canal*
*-----------------------------------------*
* Entree :                                *
*   oPC : le membre a tester              *
*   sChanName : nom du canal a tester     *
*-----------------------------------------*
* Sortie :                                *
*   TRUE/FALSE indiquant si le membre fait*
*   bien partie du canal                  *
*******************************************/
int LMQ_IsChanCreator(object oPC, string sChanName)
{
  // --- Test si le canal existe ---
  if (LMQ_IsChan(sChanName))
  {
    // --- Recupere le premier membre du canal ---
    object oMember=LMQ_GetChanCreator(sChanName);
    // -- La cle CD et le nom de joueur et le nom du personnage sont-ils identiques ? --
    if ((GetName(oPC)==GetName(oMember)) && (GetPCPublicCDKey(oPC)==GetPCPublicCDKey(oMember)) && (GetPCPlayerName(oPC)==GetPCPlayerName(oMember)))
    {
      // C'est le cas, ce premier membre identifie est donc bien le createur
      return TRUE;
    }
    else
    {
      // -- aucun membre ne porte le meme nom, celui la n'est donc pas membre --
      return FALSE;
    }
  }
  else
  {
    // -- Le canal n'existe pas, donc pas de membre --
    return FALSE;
  }
}

/******************************************
* Fonction : LMQ_GetChanMember            *
*-----------------------------------------*
* Cette fonction renvoie le premier membre*
* d'un canal dont le nom est identique a  *
* celui specifie                          *
*-----------------------------------------*
* Entree :                                *
*   sChanName : nom du canal a tester     *
*   sMember : nom du personnage a chercher*
*-----------------------------------------*
* Sortie :                                *
*   un objet representant le membre ou    *
*   OBJECT_INVALID                        *
*******************************************/
object LMQ_GetChanMember(string sChanName, string sMember)
{
  if (LMQ_IsChan(sChanName))
  {
    int nCount=GetLocalInt(GetModule(), LMQ_PREFIXE+sChanName+LMQ_CSUFFIX);
    int bFound=FALSE;
    object oTmp;
    while ((nCount>0) && (!bFound))
    {
      oTmp=GetLocalObject(GetModule(), LMQ_PREFIXE+sChanName+IntToString(nCount));
      if (GetName(oTmp)==sMember)
      {
        bFound=TRUE;
      }
      else
      {
        nCount--;
      }
    }
    if (bFound)
    {
      return oTmp;
    }
    else
    {
      return OBJECT_INVALID;
    }
  }
  else
  {
    return OBJECT_INVALID;
  }
}

/******************************************
* Fonction : LMQ_GetChanCreator           *
*-----------------------------------------*
* Cette fonction renvoie le premier membre*
* d'un canal specifie                     *
*-----------------------------------------*
* Entree :                                *
*   sChanName : nom du canal a tester     *
*-----------------------------------------*
* Sortie :                                *
*   un objet representant le createur ou  *
*   OBJECT_INVALID pour le cas ou le canal*
*   n'existe pas. Un canal existant a tou-*
*   jours au moins un membre : le createur*
*******************************************/
object LMQ_GetChanCreator(string sChanName)
{
  if (LMQ_IsChan(sChanName))
  {
    return GetLocalObject(GetModule(), LMQ_PREFIXE+sChanName+"1");
  }
  else
  {
    return OBJECT_INVALID;
  }
}

/******************************************
* Fonction : LMQ_AddToChannel             *
*-----------------------------------------*
* Cette fonction ajoute la creature speci-*
* a la suite de la liste des membres du   *
* canal specifie                          *
*-----------------------------------------*
* Entree :                                *
*   oJoiner : creature a ajouter          *
*   sChanName : nom du canal cible        *
*-----------------------------------------*
* Sortie :                                *
*   toujours TRUE                         *
*******************************************/
int LMQ_AddToChannel(object oJoiner, string sChanName)
{
  int nCount=GetLocalInt(GetModule(), LMQ_PREFIXE+sChanName+LMQ_CSUFFIX);
  nCount++;
  SetLocalObject(GetModule(), LMQ_PREFIXE+sChanName+IntToString(nCount), oJoiner);
  SetLocalInt(GetModule(), LMQ_PREFIXE+sChanName+LMQ_CSUFFIX, nCount);
  return TRUE;
}

/******************************************
* Fonction : LMQ_CreateChannel            *
*-----------------------------------------*
* Cette fonction cree le premier membre   *
* d'un canal et le compteur associe       *
*-----------------------------------------*
* Entree :                                *
*   oCreator : membre createur            *
*   sChanName : nom du canal cible        *
*-----------------------------------------*
* Sortie :                                *
*   toujours TRUE                         *
*******************************************/
int LMQ_CreateChannel(object oCreator, string sChanName)
{
  object oModule=GetModule();
  SetLocalInt(oModule, LMQ_PREFIXE+sChanName+LMQ_CSUFFIX, 1);
  SetLocalObject(oModule, LMQ_PREFIXE+sChanName+"1", oCreator);
  return TRUE;
}

/******************************************
* Fonction : LMQ_RemoveFromChannel        *
*-----------------------------------------*
* Cette fonction supprime un membre speci-*
* fie du canal specifie                   *
*-----------------------------------------*
* Entree :                                *
*   oMember : membre a supprimer          *
*   sChanName : nom du canal cible        *
*-----------------------------------------*
* Sortie :                                *
*   renvoie TRUE si le membre est supprime*
*   sinon renvoie FALSE                   *
*******************************************/
int LMQ_RemoveFromChannel(object oMember, string sChanName)
{
  int nCount=GetLocalInt(GetModule(), LMQ_PREFIXE+sChanName+LMQ_CSUFFIX);
  object oModule=GetModule();
  int nC;
  object oTmp;
  int bFound=FALSE;
  for (nC=1;nC<=nCount;nC++)
  {
    oTmp=GetLocalObject(oModule, LMQ_PREFIXE+sChanName+IntToString(nC));
    if (!bFound)
    {
      if ((GetName(oMember)==GetName(oTmp)) && (GetPCPlayerName(oMember)==GetPCPlayerName(oTmp)) && (GetPCPublicCDKey(oMember)==GetPCPublicCDKey(oTmp)))
      {
        bFound=TRUE;
      }
    }
    if (bFound)
    {
      if (nC<nCount)
      {
        SetLocalObject(oModule, LMQ_PREFIXE+sChanName+IntToString(nC), GetLocalObject(oModule, LMQ_PREFIXE+sChanName+IntToString(nC+1)));
      }
    }
  }
  if (bFound)
  {
    DeleteLocalObject(oModule, LMQ_PREFIXE+sChanName+IntToString(nCount));
    nCount--;
    if (nCount>0)
    {
      SetLocalInt(oModule, LMQ_PREFIXE+sChanName+LMQ_CSUFFIX, nCount);
    }
    else
    {
      DeleteLocalInt(oModule, LMQ_PREFIXE+sChanName+LMQ_CSUFFIX);
    }
    return TRUE;
  }
  else
  {
    return FALSE;
  }
}


/******************************************
* Fonction : LMQ_JoinChannel              *
*-----------------------------------------*
* Cette fonction se charge d'ajouter un   *
* membre a un canal apres quelques test   *
* prealable                               *
*-----------------------------------------*
* Entree :                                *
*   oJoiner : creature a ajouter          *
*   sChanName : nom du canal cible        *
*-----------------------------------------*
* Sortie :                                *
*   TRUE si le membre est ajoute          *
*   FALSE dans les autres cas             *
*******************************************/
int LMQ_JoinChannel(object oJoiner, string sChanName)
{
  if (GetIsPC(oJoiner))
  {
    if (LMQ_IsChan(sChanName))
    {
      if (!LMQ_IsChanMember(oJoiner, sChanName))
      {
        return LMQ_AddToChannel(oJoiner, sChanName);
      }
      else
      {
        return FALSE;
      }
    }
    else
    {
      return FALSE;
    }
  }
  else
  {
    return FALSE;
  }
}

/******************************************
* Fonction : LMQ_KickUser                 *
*-----------------------------------------*
* Cette fonction kick un utilisateur de la*
* liste des membres du canal specifie     *
*-----------------------------------------*
* Entree :                                *
*   sChanName : nom du canal cible        *
*   sUserName : nom du membre             *
*-----------------------------------------*
* Sortie :                                *
*   TRUE si le membre est kicke           *
*   FALSE dans les autres cas             *
*******************************************/
int LMQ_KickUser(string sChanName, string sUserName)
{
  object oMember=LMQ_GetChanMember(sChanName, sUserName);
  if (GetIsPC(oMember))
  {
    return LMQ_RemoveFromChannel(oMember, sChanName);
  }
  else
  {
    return FALSE;
  }
}

/******************************************
* Fonction : LMQ_UserList                 *
*-----------------------------------------*
* Cette fonction cree un message compor-  *
* tant la liste des membres du canal donne*
*-----------------------------------------*
* Entree :                                *
*   sChanName : nom du canal cible        *
*-----------------------------------------*
* Sortie :                                *
*   chaine de caractere contenant la liste*
*   des membres                           *
*******************************************/
string LMQ_UserList(string sChanName)
{
  string sTmp="";
  object oMember;
  object oModule=GetModule();
  int nCount=GetLocalInt(GetModule(), LMQ_PREFIXE+sChanName+LMQ_CSUFFIX);
  int nC;
  for (nC=1;nC<=nCount;nC++)
  {
    oMember=GetLocalObject(oModule, LMQ_PREFIXE+sChanName+IntToString(nC));
    sTmp=sTmp+GetName(oMember);
    if (nC==1)
    {
      sTmp=sTmp+"*";
    }
    if (nC<nCount)
    {
      sTmp=sTmp+", ";
    }
  }
  return sTmp;
}


/******************************************
* Fonction : LMQ_PutMessageOnChan         *
*-----------------------------------------*
* Cette fonction distribue un message a   *
* tous les membres d'un canal             *
*-----------------------------------------*
* Entree :                                *
*   sChanName : nom du canal cible        *
*   sMessage : contenu du message         *
*   oOwner : envoyeur du message          *
*-----------------------------------------*
* Si le oOwner est omis, le message sera  *
* considere comme un message systeme      *
*******************************************/
void LMQ_PushMessageOnChan(string sChanName, string sMessage, object oOwner=OBJECT_INVALID)
{
  object oTmp;
  int nCount=GetLocalInt(GetModule(), LMQ_PREFIXE+sChanName+LMQ_CSUFFIX);
  string sToSend=LMQ_ComposeMessage(sChanName, sMessage, oOwner);
  while (nCount>0)
  {
    oTmp=GetLocalObject(GetModule(), LMQ_PREFIXE+sChanName+IntToString(nCount));
    if (GetIsPC(oTmp))
    {
      SendMessageToPC(oTmp, sToSend);
    }
    nCount--;
  }
}

/******************************************
* Fonction : LMQ_ComposeMessage           *
*-----------------------------------------*
* Cette fonction compose un message pour  *
* envoie sur un canal donne. Elle se char-*
* ge egalement de composer les messages   *
* d'erreur ou les messages automatiques   *
* du systeme                              *
*-----------------------------------------*
* Entree :                                *
*   sChanName : nom du canal cible        *
*   sMessage : contenu du message         *
*   oSender : envoyeur du message         *
*-----------------------------------------*
* Sortie :                                *
*   La chaine complete du message         *
*-----------------------------------------*
* Si oSender est invalide, le message est *
*  automatiquement de type "systeme"      *
* "!OK" est le nom de canal a employer    *
*  pour creer un message individuel d'in- *
*  formation.                             *
* "!KO" est le nom de canal a employer    *
*  pour creer un message individuel d'er- *
*  reur                                   *
*******************************************/
string LMQ_ComposeMessage(string sChanName, string sMessage, object oSender=OBJECT_INVALID)
{
  string sHeader;
  string sToSend;
  if (sChanName=="!OK")
  {
    sHeader+=">> ";
  }
  else if (sChanName=="!KO")
  {
    sHeader+="!! ";
  }
  else
  {
    if (GetIsObjectValid(oSender))
    {
      sHeader="["+sChanName+" : "+GetName(oSender)+"] ";
    }
    else
    {
      sHeader="["+sChanName+"]";
    }
  }
  if (GetIsObjectValid(oSender))
  {
    sToSend=sHeader+sMessage;
  }
  else
  {
    sToSend=sHeader+"<"+sMessage+">";
  }
  return sToSend;
}

/******************************************
* Fonction : LMQ_SendMessage              *
*-----------------------------------------*
* Cette fonction envoie un message a un   *
* unique destinataire                     *
*-----------------------------------------*
* Entree :                                *
*   oDest : le destinataire du message    *
*   sChanName : nom du canal relatif      *
*   sMessage : contenu du message         *
*   oOwner : envoyeur du message          *
*-----------------------------------------*
* Si le oOwner est omis, le message sera  *
* considere comme un message systeme      *
*******************************************/
void LMQ_SendMessage(object oDest, string sChanName, string sMessage, object oSender=OBJECT_INVALID)
{
  string sToSend=LMQ_ComposeMessage(sChanName, sMessage, oSender);
  SendMessageToPC(oDest, sToSend);
}

/******************************************
* Fonction : LMQ_CommandInterpretor       *
*-----------------------------------------*
* Cette fonction gere les Patterns captes *
* par le listener et execute les commandes*
* correspondante                          *
*-----------------------------------------*
* Entree :                                *
*   nListenPN : numero de pattern capte   *
*   oOwner : proprietaire du Listener     *
*******************************************/
void LMQ_CommandInterpretor(int nListenPN, object oOwner)
{
  switch (nListenPN)
  {
    case 3000 : // --- Envoie d'un message ---
    {
      string sChanName=GetMatchedSubstring(1);
      if (LMQ_IsChan(sChanName))
      {
        if (LMQ_IsChanMember(oOwner, sChanName))
        {
          string sMessage=GetMatchedSubstring(3);
          LMQ_PushMessageOnChan(sChanName, sMessage, oOwner);
        }
        else
        {
          LMQ_SendMessage(oOwner, "!KO", "Vous n'etes pas membre de ce canal");
        }
      }
      else
      {
        LMQ_SendMessage(oOwner, "!KO", "Le canal n'existe pas");
      }
    }break;
    case 3001 : // --- Creation d'un canal ---
    {
      string sChanName=GetMatchedSubstring(2);
      if (LMQ_IsChan(sChanName))
      {
        LMQ_SendMessage(oOwner, "!KO", "Le canal existe deja");
      }
      else
      {
        LMQ_CreateChannel(oOwner, sChanName);
        LMQ_SendMessage(oOwner, "!OK", "Canal '" + sChanName + "' cree");
      }
    }break;
    case 3002 : // --- Se joindre a un canal ---
    {
      string sChanName=GetMatchedSubstring(2);
      if (!LMQ_IsChan(sChanName))
      {
        LMQ_SendMessage(oOwner, "!KO", "Le canal n'existe pas");
      }
      else
      {
        if (LMQ_JoinChannel(oOwner, sChanName))
        {
          LMQ_SendMessage(oOwner, "!OK", "Vous rejoignez le canal '" + sChanName + "'");
          LMQ_PushMessageOnChan(sChanName, "L'utilisateur '"+GetName(oOwner)+"' a rejoins le canal");
        }
        else
        {
          LMQ_SendMessage(oOwner, "!KO", "Vous n'avez pas reussi a joindre le canal '" + sChanName + "'");
        }
      }
    }break;
    case 3003 : // --- Kicker un user d'un canal ---
    {
      string sChanName=GetMatchedSubstring(6);
      if (!LMQ_IsChan(sChanName))
      {
        LMQ_SendMessage(oOwner, "!KO", "Le canal n'existe pas");
      }
      else
      {
        if (LMQ_IsChanCreator(oOwner, sChanName))
        {
          string sUserName=GetMatchedSubstring(3);
          if (LMQ_KickUser(sChanName, sUserName))
          {
            LMQ_PushMessageOnChan(sChanName, "L'utilisateur '"+sUserName+"' a ete kicke du canal");
          }
          else
          {
            LMQ_SendMessage(oOwner, "!KO", "Impossible de banir l'utilisateur '"+sUserName+"'");
          }
        }
        else
        {
          LMQ_SendMessage(oOwner, "!KO", "Vous n'avez pas le droit de kicker sur ce canal");
        }
      }
    }break;
    case 3004 : // --- Quitter un canal ---
    {
      string sChanName=GetMatchedSubstring(2);
      if (!LMQ_IsChan(sChanName))
      {
        LMQ_SendMessage(oOwner, "!KO", "Le canal n'existe pas");
      }
      else
      {
        if (LMQ_RemoveFromChannel(oOwner, sChanName))
        {
          LMQ_PushMessageOnChan(sChanName, "L'utilisateur '"+GetName(oOwner)+"' a quitte le canal");
          LMQ_SendMessage(oOwner, "!OK", "Vous avez quitte le canal'"+sChanName+"'");
        }
        else
        {
          LMQ_SendMessage(oOwner, "!KO", "Vous n'avez pas reussi a quitte le canal'"+sChanName+"'");
        }
      }
    }break;
    case 3005 : // --- Lister les membres d'un canal ---
    {
      string sChanName=GetMatchedSubstring(2);
      if (!LMQ_IsChan(sChanName))
      {
        LMQ_SendMessage(oOwner, "!KO", "Le canal n'existe pas");
      }
      else
      {
        if (LMQ_IsChanMember(oOwner, sChanName))
        {
          string sList=LMQ_UserList(sChanName);
          LMQ_SendMessage(oOwner, "!OK", "Liste des membres du canal '"+sChanName+"' : "+sList);
        }
        else
        {
          LMQ_SendMessage(oOwner, "!KO", "Vous n'avez pas le droit de lister ce canal, vous n'en etes pas membre");
        }
      }
    }break;
  }
}

/******************************************
* Fonction : LMQ_InitiateListener         *
*-----------------------------------------*
* Cette fonction initialise la liste des  *
* Patterns captes par le Listener donne   *
*-----------------------------------------*
* Entree :                                *
*   oListener : le Listener               *
*******************************************/
void LMQ_InitiateListener(object oListener)
{
  SetListenPattern(oListener, "!***w**", 3000);
  SetListenPattern(oListener, "?cchan*w**", 3001);
  SetListenPattern(oListener, "?jchan*w**", 3002);
  SetListenPattern(oListener, "?kchan*w'**'*w**", 3003);
  SetListenPattern(oListener, "?qchan*w**", 3004);
  SetListenPattern(oListener, "?lchan*w**", 3005);
}

// --- Commenter pour la compilation dfinitive
//void main() {}

Cette bibliothèque, une fois créée est utilisée par 2 scripts qui devront être placé sur un PNJ dédié appelé Listener (ou ecouteur). J'ai gargé le nom "ecouteur" en ResRef, mais il suffit de peu pour que le Listener s'appelle autrement. Je conseille bien sur de faire le Listener invisible et invulnérable. Il est possible qu'il faille aussi lui ajouter quelque caractéristiques, mais ce n'est pas mon propos. Pour créer ce Listener, il faudra invoquer le morceaux de code suivant :
Code :

      object oListener=CreateObject(OBJECT_TYPE_CREATURE, "ecouteur", GetLocation(oObj)); // -- Creation du Listener --
      SetLocalObject(oListener, "MYPC", oObj); // -- Etablissement du lien Listener-PC --
      SetLocalObject(oObj, "MYLISTENER", oListener); // -- Etablissement du lien PC-Listener --
      AssignCommand(oListener, ActionForceFollowObject(oObj, 5.0)); // -- Passer en mode ForceFollow --

Dans ce code oObj désigne un PJ. Pour être sûr que tout PJ disposera de son Listener personnel, il faut utiliser ce code à l'entrée du module par un PJ.

Maintenant, sur le Listener, seuls 2 évènements sont indispensables (je ne saurais trop conseiller d'éliminer tous les scripts par défaut de Bioware sur ce PNJ).

Il nécessite un OnSpawn :
Code :

#include "lib_lrvmessqueue"

void main()
{
  LMQ_InitiateListener(OBJECT_SELF); // -- Initialisation des patterns d'ecoute --
  SetListening(OBJECT_SELF, TRUE); // -- Activation du mode d'ecoute --
}


Et un OnConversation :
Code :

#include "lib_lrvmessqueue"

void main()
{
  object oSpeaker=GetLastSpeaker(); // -- Recupere la derniere creature entendue --
  if (GetIsPC(oSpeaker)) // -- verifie qu'il s'agit d'un PC --
  {
    object oOwner=GetLocalObject(OBJECT_SELF, "MYPC");
    if (GetPCPublicCDKey(oOwner)==GetPCPublicCDKey(oSpeaker)) // -- verifie qu'il s'agit de SON PC --
    {
      int nLP=GetListenPatternNumber(); // -- recupere le numero de pattern capte --
      LMQ_CommandInterpretor(nLP, oSpeaker); // -- transmet l'info au central de commande --
    }
  }
}


Une fois ceci fait, le mode d'emploi est relativement simple. Les commandes peuvent bien sûr être customisée à loisirs. On peut les prononcer à haute voix (elle serotn alors visible par les autres joueurs à l'écran) ou bien les dire sur le canal DM et dans ce cas personne ne les vera sauf les DMs s'ils regardent leur canal. A noter d'ailleurs que je n'ai ps fait de canal DM spécifique dans ce système (ca mériterait de figurer au rangs des améliorations).
Voici la liste des commandes :
?cchan <nom_canal> : pour créer un canal.
?jchan <nom_canal> : pour se joindre à un canal existant
?qchan <nom_canal> : pour quitter un canal dont on est membre
?kchan '<nom_personnage>' <nom_canal> : pour kicker un personnage d'un canal dont on est le createur.
?lchan <nom_canal> : pour lister les membres d'un canal dont on est membre. Celui qui porte une * est le créateur.
!<nom_canal> <message> : pour écrire un message aux membres d'un canal.

<nom_canal> doit être un nom en un seul mot. L'utilisation d'espace est proscrite.
<nom_personnage> dans la commande de kick est placé entre quote. C'est important car il faut donner le nom complet du membre a kicker et ce dernier comporte parfois des espaces (entre le nom et le prénom par exemple)
<message> peut comporter autant de caractère et d'espace que vous voulez et être de n'importe quelle forme, cela n'a pas d'importance.

Je reste à disposition sur ce sujet pour parler des problèmes ou des améliorations. Je compte le laisser à l'état de prototype un bon moment encore, car j'ai d'autres priorités.

-----------------------------------------------

En fait, ayant moi-même vécu quelques déboires avec le OnClientEnter, je ne fais pratiquement plus d'opération sur le PJ à ce moment, mais sur OnEnter de toutes mes zones. Ma technique consiste juste à remplir une variable lors du OnClientEnter pour indiquer que le PJ vient d'entrer, par la suite, quelle que soit la zone sur laquelle il est introduit, on teste la variable et on effectue le code.
Je pense tout simplement qu'au moment d'un OnClientEnter, le personnage n'est pas encore présent dans une zone ce qui fait que les opération visant à le localiser ou à créer quelque chose à ses côté échouent. Voici la façon dont je gère cela.
A mettre dans le OnClientEnter :
Code :

void main()
{
  object oPC=GetEnteringObject();
  if (GetIsPC(oPC))
  {
    SetLocalInt(oPC, "FIRST", TRUE);
  }
}

et ceci sur le OnEnter de toutes les zones ou un PJ est susceptible d'apparaître à la connexion :
Code :

void main()
{
  object oObj=GetEnteringObject();
  if (GetIsPC(oObj))
  {
    if (GetLocalInt(oObj, "FIRST"))
    {
      DeleteLocalInt(oObj, "FIRST");
      object oListener=CreateObject(OBJECT_TYPE_CREATURE, "ecouteur", GetLocation(oObj)); // -- Creation du Listener --
      SetLocalObject(oListener, "MYPC", oObj); // -- Etablissement du lien Listener-PC --
      SetLocalObject(oObj, "MYLISTENER", oListener); // -- Etablissement du lien PC-Listener --
      AssignCommand(oListener, ActionForceFollowObject(oObj, 5.0)); // -- Passer en mode ForceFollow --
    }
  }
}


Je sais que c'est bourrin, mais le jour où j'ai rencontré je n'ai jamais cherché à creuser le problème, je l'ai contourné vite fait, et oublié. Ceci est ce qu'il y avait dans mon module de test, ca devrait donc fonctionner. J'aurai du le dire plus tôt. Désolé.

------------------------------------

Toujours pour aider les développeurs à fignoler cet outils voici quelques observations que j'ai pu faire :
1 - Le mode MD semble poser un problème au Listener. En effet, tant que le Listener n'a pas entendu le MD au moins une fois alors qu'il était visible et tangible, il est incapable de percevoir le MD. Ce bug (qui je pense est un bug de NWN) me tient depuis la 1.23 ce qui est véritablement prise de tête. Car cette situation se produit après chaque changement de zone de la part du MD (du moins en utilisant le "chooser"). Donc après chaque changement de zone, le MD doit se rendre visible, parler un coup et il peut se rendre de nouveau invisible, le Listener l'entendra normalement. Si quelqu'un entrevoit une solution pour contourner cette difficulté, je suis preneur.

2 - Le Listener peut demeurer visible pour le MJ, en revanche, il faut le rendrre totalement invisible pour les PNJs et aussi les Créatures (histoire que celle-ci ne le prenne pas pour cible. Or l'invisibilité n'est pas du tout la panacée. Il existe un sort bien plus efficace pour ça, c'est le Sanctuaire. L'effet sanctuaire rend totalement invisible et indécelable pour toute créature hostile celui qui en bénéficie. Si l'efficacité du sort de base Sanctuaire dépend d'un Jet de Protection (la barre peut être placée suffisamment haut pour que personne ne le réussisse) il existe un autre effet, depuis la 1.30 qui est, quant à lui, infaillible. C'est EffectEthereal . D'après ce que j'en sais, cet effet est aussi puissant que l'invisibilité de DM (en revanche, il ne rend pas intangible contrairement à ce que son nom peut laisser penser). L'astuce pour paraître invisible pour toute créature est donc d'appartenir à une faction spécialement conçue pour être hostile à tout le monde. Je rappelle à toute fin utile qu'un certaine proximité permet toujours de voir les créatures invisibles. Une créature sous cette effet là peut-être sous le nez d'un personnage sans être vu.
Cet effet est doublement avantageux car l'avatar MD n'étant hostile à personne, ce dernier pourra voir les Listeners.

3 - Parmis les caractéristiques de ce Listener, prévoyez de lui donner la vitesse de déplacement MD et de lui accorder la portée de perception maximale. Pour être encore plus sur de sa discrétion, vous pouvez lui accorder l'apparence "invisible", comme ça, même si son effet ethéré prend fin par accident, il restera relativement discret (visible avec TAB ou en passant le curseur sur lui). Accordez lui aussi le mode de déplacement discret avec un score défiant toute concurrence.

4 - La téléportation du MD vers une autre zone est semble-t-il un véritable handicap. En fait, c'est comme si l'avatar MD était détruit puis recréé. Cela réinitialise, bien sûr, la validité de la perception du MD comme expliqué au point 1 mais supprime également l'action ForceFollow implanté sur le PNJ. Il faut donc prévoir un cas de figure pour ça... Le OnHeartBeat semble le meilleur évènement pour le Listener pour lui permettre de vérifier si l'avatar qu'il suit est toujours prêt de lui. Si cela ne semble pas indispensable pour le PJ, ca l'est pour l'avatar MD. Afin d'éviter que tous les Listener n'exploite un OnHeartbeat, il serait bon de faire 2 Listener différents. Un pour les joueurs et un pour le MD avec quelques pouvoir en plus pour ne pas perdre de vu son MD. Une seconde difficulté se pose lorsque le MD s'incarne dans un PNJ, à ce moment l'Avatar cesse d'exister et le Listener est paumé Smile . Donc il faut prévoir le coup de la disparition du MD dans un PNJ afin qu'il conserve son Listener. A noter qu'incarné dans un PNJ, le MD deviendra hostile à son Listener et donc celui-ci disparaitra de sa vue.

Voilà ce qui m'est venu à l'esprit en réfléchissant aux améliorations à prévoir.
J'essaierai de coller d'autres observations au fur et à mesure qu'elles me viennent.
_________________
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
 
finipe
Grand Sage du Conseil
Inscrit le: 11 Fév 2003
Messages: 519
Localisation: Nantes
Répondre en citant
Posté le : 17/11/2003 08:00:15 Sujet du message : Potion frelatée

Un script tout bête que j'ai fait pour simuler une potion frelatée, avec 6 effets aléatoires bénéfiques ou pas.

Il faut créer un objet magique avec en propriétés "Pouvoir unique, sur soi uniquement [utilisation unique]", et puis une jolie description du genre "La potion est présentée dans une bouteille opaque étiquetée avec soin à la main : impossible de discerner la couleur du liquide, mais son emballage est irréprochable !". L'objet devra avoir comme tag "PotionFrelatee".

Sur le OnActivate du module, ajouter le script suivant :

NWScript :
void main()
{
  object oPlayer = GetItemActivator();
  object oItem = GetItemActivated();
  if(GetTag (oItem) == "PotionFrelatee")
  {
    switch (d6())
    {
      case 1: //potion ratee, provoque une maladie
      AssignCommand(oPlayer, ActionPlayAnimation(ANIMATION_FIREFORGET_DRINK));
      DelayCommand(1.2, ApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectDisease(DISEASE_SHAKES), oPlayer, 90.0));
      DelayCommand(1.3, SendMessageToPC(oPlayer, ""));
      DelayCommand(1.4, ApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectKnockdown(), oPlayer, 6.0));
      break;

      case 2: //potion ratee, provoque une perte de constitution de 2 pdt 1 minute
      AssignCommand(oPlayer, ActionPlayAnimation(ANIMATION_FIREFORGET_DRINK));
      DelayCommand(1.2, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_IMP_REDUCE_ABILITY_SCORE), oPlayer));
      DelayCommand(1.3, SendMessageToPC(oPlayer, ""));
      DelayCommand(1.4, ApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectAbilityDecrease(ABILITY_CONSTITUTION, 2), oPlayer, 60.0));
      break;

      case 3: //potion sans aucun effet
      AssignCommand(oPlayer, ActionPlayAnimation(ANIMATION_FIREFORGET_DRINK));
      SendMessageToPC(oPlayer, "Vous ne ressentez rien, aucun effet notable.");
      break;

      case 4: //potion reussie, augmente les jds de 2 pendant 1 minute
      AssignCommand(oPlayer, ActionPlayAnimation(ANIMATION_FIREFORGET_DRINK));
      DelayCommand(1.2, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_IMP_MAGICAL_VISION), oPlayer));
      DelayCommand(1.3, SendMessageToPC(oPlayer, ""));
      DelayCommand(1.4, ApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectSavingThrowIncrease(SAVING_THROW_ALL, 2), oPlayer, 60.0));
      break;

      case 5: //potion reussie, augmente la force et la constitution de 2 pendant 2 minutes
      AssignCommand(oPlayer, ActionPlayAnimation(ANIMATION_FIREFORGET_DRINK));
      DelayCommand(1.2, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_IMP_IMPROVE_ABILITY_SCORE), oPlayer));
      DelayCommand(1.3, SendMessageToPC(oPlayer, ""));
      DelayCommand(1.4, ApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectAbilityIncrease(ABILITY_CONSTITUTION, 2), oPlayer, 120.0));
      DelayCommand(1.4, ApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectAbilityIncrease(ABILITY_STRENGTH, 2), oPlayer, 120.0));
      break;

      case 6: //potion reussie, soigne puis regenere la personne pendant 2 minutes
      AssignCommand(oPlayer, ActionPlayAnimation(ANIMATION_FIREFORGET_DRINK));
      DelayCommand(1.2, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_IMP_HEALING_S), oPlayer));
      DelayCommand(1.2, SendMessageToPC(oPlayer, ""));
      DelayCommand(1.3, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectHeal(10), oPlayer));
      DelayCommand(1.4, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_IMP_ELEMENTAL_PROTECTION), oPlayer));
      DelayCommand(1.5, ApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectRegenerate(2, 10.0), oPlayer, 120.0));
      break;
    }
  }
}
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.


Voilà, il est bien sûr possible d'ajouter autant d'effet que l'on veut pour plus de possibilités Very Happy
_________________
» Le Tref & l'Aucube : Histoire, misanthropie & zoologie léonine
» 1626, le Gant & l'Epée : intrigues & duels sous le règne de Louis XIII
 
Revenir en haut Voir le profil de l'utilisateur Envoyer un message privé Visiter le site web du posteur Ignorer l'utilisateur
 
Klemmth
Seigneur
Inscrit le: 26 Juin 2004
Messages: 176
Localisation: france
Répondre en citant
Posté le : 26/06/2004 11:51:50 Sujet du message :

Voila un tout petit script (mon premier) qui permet, à partir d'un objet de créer un portail puis de s'y téléporter de n'importe où, même si on a changé de zone.

Auparavant, j'ai crée un objet que j'ai appelé "Teleporteur", et où j'ai mis "Pouvoir unique sur soi uniquement ( avec utilisation illimitée )" dans les propriétés. Cet objet a pour tag "teleporteur", et pour blueprint "hen_dae1qt001". J'ai aussi fait "editer copier" sur le "recall_portail" du jeu sans rien changer.

Ce script est à àjouter dans le onActivateItem du module.
Bon je crois que c'est tout, place au script.

NWScript :
////////////////////////////// ////////////////////////////// ////////////////////////////// ////////////////////////////// ///////


//A ajouter dans le OnActivate du module.
////////////////////////////// ////////////////////////////// ////////////////////////////// ////////////////////////////// ///////

void main()
{
  object oItem = GetItemActivated();
  string sItem = GetTag( oItem );
  object oPlayer = GetItemActivator();

  if ( sItem == "tag_item_teleporteur" )
  {
    if ( GetLocalInt( oItem, "DejaCree" ) != 1 )
    {
      effect eEffect = EffectVisualEffect( VFX_FNF_MYSTICAL_EXPLOSION );
      location lPortail = GetLocation( oPlayer );
      CreateObject( OBJECT_TYPE_PLACEABLE, "resref_du_portail_de_teleportation", lPortail, FALSE, "portail_teleportation" );
      ApplyEffectAtLocation( DURATION_TYPE_INSTANT, eEffect, lPortail, 0.0 );
      SetLocalInt( oItem, "DejaCree", 1);
    }
    else
    {
      object oPortail = GetObjectByTag( "portail_teleportation" );
      effect eEffect = EffectVisualEffect( VFX_IMP_DUST_EXPLOSION );
      location lPlayer = GetLocation( oPlayer );
      location lPortail = GetLocation( oPortail );
      ApplyEffectAtLocation( DURATION_TYPE_INSTANT, eEffect, lPlayer, 0.0 );
      AssignCommand( oPlayer, JumpToObject( oPortail ) );
      ApplyEffectAtLocation( DURATION_TYPE_INSTANT, eEffect, lPortail, 0.0 );
      DestroyObject( oPortail, 4.0 );
      SetLocalInt( oItem, "DejaCree", 0 );
    }
  }
}
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.
 
Revenir en haut Voir le profil de l'utilisateur Envoyer un message privé Ignorer l'utilisateur
 
PinMaster
Ecuyer
Inscrit le: 30 Sep 2004
Messages: 49
Localisation: Non loin de Marseille...
Répondre en citant
Posté le : 13/09/2005 07:28:20 Sujet du message : [Système] Panneau d'affichage et scribe (SPEC BBS 2.0)

Je viend ici pour vous informer de la finalisation du système BBS de mon cru... le SPEC BBS 2.0B et M (Bioware / MySQL).

Bref, vous pourrez trouver leurs liens et quelques informations sur son évolution sur le site NWN-Système (ici)...
Voici la description de ce système (en copier/coller):

Citation :
Voici le tout nouveau système de panneau d'affichage, il est inspiré du BBS (Bulletin Board System V1.1) de Serban Oprescu. Mais aujourd'hui, il n'a plus beaucoup de chose en rapport.

La modification se porte essentiellement sur la gestion du panneau d'affichage. Vous pourrez ainsi trouver différentes rubriques comme :
-> Communiqué de l'empereur
-> Messages divers
-> Avis de recherche
-> Achat et vente d'objet
-> Rapport de bug
-> Coin MD pour le paramétrage

Petite nouveauté en plus, les Plumes et les encriers utilisables sont basés sur un système de charge d'item. Le gros avantage réside dans le fait que l'on peu créé autant d'tiem que l'on souhaite sans pour autant toucher au code du BBS. Pour cela, il suffit de crée un item type Plume ou Encirer, de définir le nombre de charges, le prix de vente et le TAG (SPEC_ENCRIER pour tout type d'encrier, SPEC_PLUMES pour tout type de plumes)... le tour est joué, rien de plus rien de moins... il suffit juste d'utiliser Aurora pour la création d'item. Donc aucune connaissance en script ne sera nécessaire.
Vous trouverez ces systèmes aux liens ci-dessous :
-> Version Bioware :Cliquez-ici
-> Version MySQL : Cliquez-ici
_________________
Module en développement : Pandorn Nouvel Age
Système de Pandorn diffusé : Cliquez-ici
 
Revenir en haut Voir le profil de l'utilisateur Envoyer un message privé Visiter le site web du posteur MSN Messenger Ignorer l'utilisateur
 
lylver
Héros
Inscrit le: 08 Avr 2005
Messages: 274
Répondre en citant
Posté le : 20/09/2005 12:39:40 Sujet du message : complément BBS

modification et ajouts au système BBS de PinMaster, version database NWN je précise, indiqué ci-dessus.
Il s'agit d'ajouter des éléments de persistence pour :
- gérer la continuité de la date/heure du module
- réduire les problèmes de latence lors des accès aux commandes [Set/Get]Campaign[Int/String] du système de database NWN

1) Vous aurez besoin de définir dans un petit coin de votre module 4 points de passages avec les tags suivants : DBI_READ, DBS_READ, DBI_FIFO, DBS_FIFO.
Il serviront à stocker en variables locales des entiers et des chaînes de caractères.
2) Il vous faudra aussi modifier vos scripts de modules suivants :
Mod_OnModLoad, Mod_OnHeartBeat, Mod_OnUsrDefined, Mod_OnActvtItem.
3) Créér également un objet avec lancer un sort/pouvoir unique sur soi[utilisation unique] avec le Tag "RESTARTTN" (c'est changeable dans Mod_OnActvtItem si vous voulez autre chose)
pour le redémmarrage propre du module et mettez le nom de fichier de votre module au bon endroit dans Mod_OnUsrDefined (StartNewModule())

Précautions d'emploi : le cache est en mode FIFO, avec un "pacing" d'écriture que j'ai réglé à 0.5sec avec un DelayCommand. Les essais que j'ai fait me montre que les données sont stables après environ 15 secondes. Donc pour les cas de paranoïa, j'ai inclus un "restarter" pour le module, on pourrait sur le même modèle créer un "stop_module".
Sinon un peu de patience après le départ de tout le monde et vous pouvez couper sans risque.

J'ai enlevé les morceaux de scripts qui n'ont pas de rapport avec le BBS.
Voici les différents fichiers supplémentaires :
Ce message est un spoiler, et risque de vous informer de choses que vous auriez dû apprendre par vous même (fin d'un jeu, film, etc). À vos risques et périls (ludiques), vous pouvez le voir en cliquant sur cet avertissement.
Spoiler :

NWScript :
//:: //
//:: ly_lib_time.nss
//:: Lylver, time functions
//:: //
int ly_day()
{
    int iCTY = GetCalendarYear() ;
    int iCTM = GetCalendarMonth() ;
    int iCTD = GetCalendarDay() ;
    int iCDay = iCTY*12*28 + iCTM*28 + iCTD ;
    return iCDay ;
}

int ly_time()
{
    int iTH = GetTimeHour();
    int iTM = GetTimeMinute();
    int iTS = GetTimeSecond();
    int iCTime = FloatToInt(HoursToSeconds(iTH)) + iTM*60 + iTS ;
    return iCTime ;
}

// 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.


Ce message est un spoiler, et risque de vous informer de choses que vous auriez dû apprendre par vous même (fin d'un jeu, film, etc). À vos risques et périls (ludiques), vous pouvez le voir en cliquant sur cet avertissement.
Spoiler :
NWScript :
//:: ////
//:: bbs_lib_item.nss
//:: Update Lylver 2005-09-17
//:: //
//:: Updated Lylver 2005-08-01
//:: DB Flush Cache, On File Queue : User's Events 600 601 602
//:: //
// Systeme de cache database (from pcnt by Knat)
// caching increases memory usage..
// if you don't wanna use caching, set this to FALSE
const int DO_CACHE = TRUE;
// Write cache by Lylver
const int DO_WCACHE = TRUE;

struct MemDB
{
  string sDB ; // database Name
  object oChi ; // object holding integer read cache
  object oChs ; // object holding string read cache
  object oDbi ; // object holding integer write fifo cache
  object oDbs ; // object holding string write fifo cache
  string sVar ; // variable to fill
  int nValue ; // integer to write
  string sValue ; // string to write
};

int GCacheInt(struct MemDB stDB)
{
  // ne pas stocker 0
  int nCache = GetLocalInt(stDB.oChi,stDB.sDB+stDB.sVar);
  if(nCache == 0) {
    nCache = GetCampaignInt(stDB.sDB,stDB.sVar);
    SetLocalInt(stDB.oChi,stDB.sDB+stDB.sVar,nCache);
  }
  return nCache;
}

void SCacheInt(struct MemDB stDB)
{
  int nCache = GetLocalInt(stDB.oChi,stDB.sDB+stDB.sVar);
  // flush the cache if !=
  if( (nCache != stDB.nValue) || (stDB.nValue == 0) ){
      object oMod = GetModule() ;
      int bWCACHE = DO_WCACHE && !GetLocalInt(oMod,"REBOOT") ;
      SetLocalInt(stDB.oChi,stDB.sDB+stDB.sVar,stDB.nValue);
      if( bWCACHE ){
        int nModWCounter = 1+GetLocalInt(stDB.oDbi,"WDBICNT") ;
        SetLocalInt(stDB.oDbi,"WDBICNT",nModWCounter); // espere atomic
        SetLocalString(stDB.oDbi,"IDBCACHE"+IntToString(nModWCounter),stDB.sDB);
        SetLocalString(stDB.oDbi,"IVARCACHE"+IntToString(nModWCounter),stDB.sVar);
        SetLocalInt(stDB.oDbi,"IVALUECACHE"+IntToString(nModWCounter),stDB.nValue);
      }else{
        SetCampaignInt(stDB.sDB,stDB.sVar,stDB.nValue);
      }
  }
}

string GCacheString(struct MemDB stDB)
{
  // ne pas stocker ""
  string sCache = GetLocalString(stDB.oChs,stDB.sDB+stDB.sVar);
  // database access gets reduced greatly if using the cache
  // only reload on empty cache
  if(sCache == "") {
    sCache = GetCampaignString(stDB.sDB,stDB.sVar);
    SetLocalString(stDB.oChs,stDB.sDB+stDB.sVar,sCache);
  }
  return sCache;
}

void SCacheString(struct MemDB stDB)
{
  string sCache = GetLocalString(stDB.oChs,stDB.sDB+stDB.sVar);
  // flush the cache if !=
  if( (sCache != stDB.sValue) || (stDB.sValue == "") ){
      object oMod = GetModule() ;
      int bWCACHE = DO_WCACHE && !GetLocalInt(oMod,"REBOOT") ;
      SetLocalString(stDB.oChs,stDB.sDB+stDB.sVar,stDB.sValue);
      if( bWCACHE ){
        int nModWCounter = 1+GetLocalInt(stDB.oDbs,"WDBSCNT") ;
        SetLocalInt(stDB.oDbs,"WDBSCNT",nModWCounter); // espere atomic
        SetLocalString(stDB.oDbs,"SDBCACHE"+IntToString(nModWCounter),stDB.sDB);
        SetLocalString(stDB.oDbs,"SVARCACHE"+IntToString(nModWCounter),stDB.sVar);
        SetLocalString(stDB.oDbs,"SVALUECACHE"+IntToString(nModWCounter),stDB.sValue);
        WriteTimestampedLogEntry("SCacheString : "+"WDBSCNT"+"_"+IntToString(nModWCounter)+
        " "+"SDBCACHE"+IntToString(nModWCounter)+"_"+stDB.sDB+
        " "+"SVARCACHE"+IntToString(nModWCounter)+"_"+stDB.sVar+
        " "+"SVALUECACHE"+IntToString(nModWCounter)+"_"+stDB.sValue);
        // SetCampaignInt(sDatabase,sVarN ame,nValue);
      }else{
        SetCampaignString(stDB.sDB,stDB.sVar,stDB.sValue);
      }
  }
}

// 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.


Attention : celui là est une version modifiée de celui de MrPin

Ce message est un spoiler, et risque de vous informer de choses que vous auriez dû apprendre par vous même (fin d'un jeu, film, etc). À vos risques et périls (ludiques), vous pouvez le voir en cliquant sur cet avertissement.
Spoiler :
NWScript :
//:: ////
//:: bbs_include.nss
//:: Update Lylver 2005-09-17
//:: NwN database caching system
//:: ////
//BULLETIN BOARD SYSTEM VERSION 1.1

//This is an include file. Upon building your module you will get
//a compile error in this file. That is normal and does not
//affect the operation of the bulletin board.

// Modifier par MrPin le 27/08/2004
#include "bbs_lib_item"

void bbs_do_board_stats();
void bbs_initiate(object oBBS);
int bbs_can_show(int WhichEntry);
void bbs_change_page(int PageChange);
void bbs_select_entry(int WhichEntry);
void bbs_add_notice(object oBBS, string sPoster, string sTitle, string sMessage, string sDate, string sBBStag = "");

//Loads into tokens the stats for a board
void bbs_do_board_stats() {
  //
  object oMod=GetModule();
  struct MemDB dDB;
      dDB.sDB = "DB_BBS";
      dDB.oChi = GetLocalObject(oMod,"DBI_READ");
      dDB.oChs = GetLocalObject(oMod,"DBS_READ");
      dDB.oDbi = GetLocalObject(oMod,"DBI_FIFO");
      dDB.oDbs = GetLocalObject(oMod,"DBS_FIFO");
      dDB.sVar = "";
      dDB.nValue = 0;
      dDB.sValue = "";
  //
  object oBBS = GetLocalObject(GetModule(), "BBS_" + GetTag(OBJECT_SELF));
  int PageSize = GetLocalInt(oBBS, "PageSize");
  dDB.sVar = GetTag(oBBS)+ "#C" + GetLocalString(oBBS, "BBS_TYPE") ;
  int TotalItems = GCacheInt(dDB);
  int PageIndex = GetLocalInt(oBBS, "PageIndex") + 1;
  SetCustomToken(3671, IntToString(TotalItems));
  if (TotalItems == 0) {PageIndex = 0;}
  SetCustomToken(3672, IntToString(PageIndex));
  SetCustomToken(3673, IntToString((TotalItems + PageSize - 1) / PageSize));
}

//Initiates a bulletin board's settings if neccessary
void bbs_initiate(object oBBS) {
  string sBBS = "BBS_" + GetTag(oBBS);
  object myBBS = GetLocalObject(GetModule(), sBBS);
  if (!GetIsObjectValid(myBBS)) {
    SetLocalObject(GetModule(), sBBS, oBBS);
    myBBS = oBBS;
    //MaxItems is the maximum number of messages
    SetLocalInt(myBBS, "MaxItems", 100);
    //PageSize is the number of entries per page, between 1 and 10
    SetLocalInt(myBBS, "PageSize", 5);
  }
}

//Determines whether a dialogue option is visible in conversation
int bbs_can_show(int WhichEntry) {
  //
  object oMod=GetModule();
  struct MemDB dDB;
      dDB.sDB = "DB_BBS";
      dDB.oChi = GetLocalObject(oMod,"DBI_READ");
      dDB.oChs = GetLocalObject(oMod,"DBS_READ");
      dDB.oDbi = GetLocalObject(oMod,"DBI_FIFO");
      dDB.oDbs = GetLocalObject(oMod,"DBS_FIFO");
      dDB.sVar = "";
      dDB.nValue = 0;
      dDB.sValue = "";
  //
  object oBBS = GetLocalObject(GetModule(), "BBS_" + GetTag(OBJECT_SELF));
  int PageSize = GetLocalInt(oBBS, "PageSize");
  int nSpot = GetLocalInt(oBBS, "PageIndex") * PageSize + WhichEntry;
  dDB.sVar = GetTag(oBBS)+ "#C" + GetLocalString(oBBS, "BBS_TYPE") ;
  if(nSpot <= GCacheInt(dDB) && WhichEntry <= PageSize) {return TRUE;}
  return FALSE;
}

//Moves the page by the required PageFlip:
//0 to reload page, -1 for previous page, 1 for next page
void bbs_change_page(int PageFlip) {
  //
  object oMod=GetModule();
  struct MemDB dDB;
      dDB.sDB = "DB_BBS";
      dDB.oChi = GetLocalObject(oMod,"DBI_READ");
      dDB.oChs = GetLocalObject(oMod,"DBS_READ");
      dDB.oDbi = GetLocalObject(oMod,"DBI_FIFO");
      dDB.oDbs = GetLocalObject(oMod,"DBS_FIFO");
      dDB.sVar = "";
      dDB.nValue = 0;
      dDB.sValue = "";
  //
  object oBBS = GetLocalObject(GetModule(), "BBS_" + GetTag(OBJECT_SELF));
  string sType = GetLocalString(oBBS, "BBS_TYPE");
  int PageSize = GetLocalInt(oBBS, "PageSize");
  dDB.sVar = GetTag(oBBS)+ "#C" + sType ;
  int TotalItems = GCacheInt(dDB);
  int MaxItems = GetLocalInt(oBBS, "MaxItems");
  dDB.sVar = GetTag(oBBS)+ "#L" + sType ;
  int LatestItem = GCacheInt(dDB);
  int PageIndex = GetLocalInt(oBBS, "PageIndex") + 1 * PageFlip;
  if (PageIndex < 0) {PageIndex = 0;}
  SetLocalInt(oBBS, "PageIndex", PageIndex);

  string sInfo;
  int iLoop;
  int iNotice;

  for (iLoop = 0; iLoop < PageSize; iLoop++) {
    iNotice = LatestItem - PageIndex * PageSize - iLoop;
    if (iNotice < 1) {iNotice = MaxItems + iNotice;}
    dDB.sVar = GetTag(oBBS)+ "#T" + sType + IntToString(iNotice) ;
    sInfo = GCacheString(dDB);
    SetCustomToken(3680 + iLoop, sInfo);
    dDB.sVar = GetTag(oBBS)+ "#P" + sType + IntToString(iNotice) ;
    sInfo = GCacheString(dDB);
    if (((PageIndex * PageSize + iLoop + 2) > TotalItems) || (iLoop == PageSize - 1)){
      sInfo = sInfo + "\n ";
    }
    SetCustomToken(3690 + iLoop, sInfo);
  }
  bbs_do_board_stats();
  SetCustomToken(3674, "");
  SetCustomToken(3675, "");
  SetCustomToken(3676, "");
  SetCustomToken(3677, "");
  SetCustomToken(3678, "");
}

//Displays the selected post
void bbs_select_entry(int WhichEntry) {
  //
  object oMod=GetModule();
  struct MemDB dDB;
      dDB.sDB = "DB_BBS";
      dDB.oChi = GetLocalObject(oMod,"DBI_READ");
      dDB.oChs = GetLocalObject(oMod,"DBS_READ");
      dDB.oDbi = GetLocalObject(oMod,"DBI_FIFO");
      dDB.oDbs = GetLocalObject(oMod,"DBS_FIFO");
      dDB.sVar = "";
      dDB.nValue = 0;
      dDB.sValue = "";
  //
  object oBBS = GetLocalObject(GetModule(), "BBS_" + GetTag(OBJECT_SELF));
  string sType = GetLocalString(oBBS, "BBS_TYPE");
  int PageSize = GetLocalInt(oBBS, "PageSize");
  int MaxItems = GetLocalInt(oBBS, "MaxItems");
  dDB.sVar = GetTag(oBBS)+"#L" + sType ;
  int LatestItem = GCacheInt(dDB);
  int PageIndex = GetLocalInt(oBBS, "PageIndex");

  int iNotice = LatestItem - PageIndex * PageSize - WhichEntry + 1;
  if (iNotice < 1) {iNotice = MaxItems + iNotice;}

  string sNotice = IntToString(iNotice);
  bbs_do_board_stats();
  dDB.sVar = GetTag(oBBS)+ "#T" + sType + sNotice ;
  SetCustomToken(3674, "\n\n" + GCacheString(dDB) + "\nPar: ");
  dDB.sVar = GetTag(oBBS)+ "#P" + sType + sNotice ;
  SetCustomToken(3675, GCacheString(dDB));
  SetCustomToken(3676, " Le: ");
  dDB.sVar = GetTag(oBBS)+ "#D" + sType + sNotice ;
  SetCustomToken(3677, GCacheString(dDB));
  dDB.sVar = GetTag(oBBS)+ "#M" + sType + sNotice ;
  SetCustomToken(3678, "\n" + GCacheString(dDB));
}

//Adds a post to the bulletin board. This can be called at any time
//so you can insert your own notices. If you don't specify a sDate,
//it will use the current game time. The proper format for sDate is
//something like "6/30/1373 11:58". The last two lines write code to
//the log file for restoring the messages after a module edit.
void bbs_add_notice(object oBBS, string sPoster, string sTitle, string sMessage, string sDate, string sBBStag = "")
{
  //
  object oMod=GetModule();
  struct MemDB dDB;
      dDB.sDB = "DB_BBS";
      dDB.oChi = GetLocalObject(oMod,"DBI_READ");
      dDB.oChs = GetLocalObject(oMod,"DBS_READ");
      dDB.oDbi = GetLocalObject(oMod,"DBI_FIFO");
      dDB.oDbs = GetLocalObject(oMod,"DBS_FIFO");
      dDB.sVar = "";
      dDB.nValue = 0;
      dDB.sValue = "";
  //
  if (sBBStag != "") {oBBS = GetObjectByTag(sBBStag);}
  bbs_initiate(oBBS);
  oBBS = GetLocalObject(oMod, "BBS_" + GetTag(oBBS));
  if (sDate == "") {
    sDate = IntToString(GetTimeMinute());
    if (GetStringLength(sDate) == 1) {sDate = "0" + sDate;}
    sDate = IntToString(GetCalendarMonth()) + "/" + IntToString(GetCalendarDay()) + "/" + IntToString(GetCalendarYear()) + " " + IntToString(GetTimeHour()) + ":" + sDate;
  }
  string sType = GetLocalString(oBBS, "BBS_TYPE");
  int MaxItems = GetLocalInt(oBBS, "MaxItems");
  dDB.sVar = GetTag(oBBS)+ "#C" + sType ;
  int TotalItems = GCacheInt(dDB) ;
  int nSpot = TotalItems + 1;
  if (nSpot > MaxItems)
  {
    dDB.sVar = GetTag(oBBS)+ "#L" + sType ;
    nSpot = GCacheInt(dDB) + 1 ;
    if (nSpot > MaxItems) nSpot = nSpot - MaxItems;
  }
  dDB.sVar = GetTag(oBBS)+ "#P" + sType + IntToString(nSpot) ;
  dDB.sValue = sPoster ; SCacheString(dDB) ;
  dDB.sVar = GetTag(oBBS)+ "#D" + sType + IntToString(nSpot) ;
  dDB.sValue = sDate ; SCacheString(dDB) ;
  dDB.sVar = GetTag(oBBS)+ "#T" + sType + IntToString(nSpot) ;
  dDB.sValue = sTitle ; SCacheString(dDB) ;
  dDB.sVar = GetTag(oBBS)+ "#M" + sType + IntToString(nSpot) ;
  dDB.sValue = sMessage ; SCacheString(dDB) ;
  dDB.sVar = GetTag(oBBS)+ "#L" + sType ;
  dDB.nValue = nSpot ; SCacheInt(dDB) ;
  // correction le 05-04-2006
  if (MaxItems > TotalItems){
    dDB.sVar = GetTag(oBBS)+ "#C" + sType ;
    dDB.nValue = TotalItems + 1 ; SCacheInt(dDB) ;
  }
  // correction

  string sQuote = GetSubString(GetStringByStrRef(464), 13, 1);
  //PrintString("bbs_add_no tice(OBJECT_SELF, " + sQuote + sPoster + sQuote + ", " + sQuote + sTitle + sQuote + ", " + sQuote + sMessage + sQuote + ", " + sQuote + sDate + sQuote + ", " + sQuote + GetTag(oBBS) + sQuote + "); //:::BBS:::");
}
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.


Ce message est un spoiler, et risque de vous informer de choses que vous auriez dû apprendre par vous même (fin d'un jeu, film, etc). À vos risques et périls (ludiques), vous pouvez le voir en cliquant sur cet avertissement.
Spoiler :
NWScript :
//:Confused/
//:: bbs_mod_load.nss
//:: Mod_OnModLoad Event
//:: Updated 2005-09-17 Lylver
//:: date persistante, DB cache for BBS
//:Confused/

#include "x2_inc_switches"
#include "x2_inc_restsys"
#include "ly_lib_time"
#include "bbs_lib_item"
void main()
{
  object oMod = GetModule() ;
/* Compteur de temps en tours */
  DelayCommand(600.0, SignalEvent(OBJECT_SELF, EventUserDefined(200)));
// Fonction de mise en cache ecriture et lecture, les points de passage doivent etre present
    object oDBI=GetObjectByTag("DBI_FIFO");
    object oDBS=GetObjectByTag("DBS_FIFO");
    object oCacheI=GetObjectByTag("DBI_READ");
    object oCacheS=GetObjectByTag("DBS_READ");
    if( GetIsObjectValid(oDBI) ){
      WriteTimestampedLogEntry("Successul get of DBI_FIFO object");
      SetLocalObject(oMod,"DBI_FIFO",oDBI);
    } else {
      WriteTimestampedLogEntry("Fatal Error : unable to get DBI_FIFO object");
      EndGame("");
    }
    if( GetIsObjectValid(oDBS) ){
      WriteTimestampedLogEntry("Successul get of DBS_FIFO object");
      SetLocalObject(oMod,"DBS_FIFO",oDBI);
    } else {
      WriteTimestampedLogEntry("Fatal Error : unable to get DBS_FIFO object");
      EndGame("");
    }
    if( GetIsObjectValid(oCacheI) ){
      WriteTimestampedLogEntry("Successul get of DBI_READ object");
      SetLocalObject(oMod,"DBI_READ",oCacheI);
    } else {
      WriteTimestampedLogEntry("Fatal Error : unable to get DBI_READ object");
      EndGame("");
    }
    if( GetIsObjectValid(oCacheS) ){
      WriteTimestampedLogEntry("Successul get of DBS_READ object");
      SetLocalObject(oMod,"DBS_READ",oCacheS);
    } else {
      WriteTimestampedLogEntry("Fatal Error : unable to get DBS_READ object");
      EndGame("");
    }
//
//:: Initialisation de la date et de l'heure du module, fondamental pour le BBS et la persistance
  //
  struct MemDB dDB;
      dDB.sDB = "DATE_MODULE";
      dDB.oChi = GetLocalObject(oMod,"DBI_READ");
      dDB.oChs = GetLocalObject(oMod,"DBS_READ");
      dDB.oDbi = GetLocalObject(oMod,"DBI_FIFO");
      dDB.oDbs = GetLocalObject(oMod,"DBS_FIFO");
      dDB.sVar = "";
      dDB.nValue = 0;
      dDB.sValue = "";
  //
    int nCTY = GetCalendarYear() ;
    int nCTM = GetCalendarMonth() ;
    int nCTD = GetCalendarDay() ;
    int nTH = GetTimeHour();
    int nTM = GetTimeMinute();
    int nTS = GetTimeSecond();
    int nAbsolDay = ly_day() ; // temps du debut du module
    int nCTime = ly_time() ;
  // Lecture non-cachee de l'enregistrement du temps
  int iTM = GetCampaignInt("DATE_MODULE", "MINUTE") ;
  int iTH = GetCampaignInt("DATE_MODULE", "HEURE") ;
  int iCTD = GetCampaignInt("DATE_MODULE", "JOUR") ;
  int iCTM = GetCampaignInt("DATE_MODULE", "MOIS") ;
  int iCTY = GetCampaignInt("DATE_MODULE", "ANNEE") ;
  int iRBOOT = GetCampaignInt("DATE_MODULE", "NREBOOT") ;
  int iTOUR = GetCampaignInt("DATE_MODULE", "NTOUR") ;
  // premier demarrage
  if( iRBOOT==0 ) {
      iTM = nTM; iTH = nTH ; iCTD = nCTD ; iCTM = nCTM ; iCTY = nCTY ;
  }
  // compactage
  DestroyCampaignDatabase("DATE_MODULE");
  // Enregistrement du temps, avec mise en cache
  dDB.sVar = "MINUTE" ; dDB.nValue = iTM ; SCacheInt(dDB) ;
  dDB.sVar = "HEURE" ; dDB.nValue = iTH ; SCacheInt(dDB) ;
  dDB.sVar = "JOUR" ; dDB.nValue = iCTD ; SCacheInt(dDB) ;
  dDB.sVar = "MOIS" ; dDB.nValue = iCTM ; SCacheInt(dDB) ;
  dDB.sVar = "ANNEE" ; dDB.nValue = iCTY ; SCacheInt(dDB) ;
  dDB.sVar = "NTOUR" ; dDB.nValue = iTOUR ; SCacheInt(dDB) ;
  // Compteur de reboot (pour les quetes sans doute et reputation)
  dDB.sVar = "NREBOOT" ; dDB.nValue = iRBOOT+1 ; SCacheInt(dDB) ; // incrementation
  // Mise a l'heure du module  (mettre l'heure en premier)
  SetTime(iTH,iTM,0,0) ;
  SetCalendar(iCTY,iCTM,iCTD) ;
  // Annoncer dans les logs le jour et la difference
  int iAbsolDay = ly_day() ;
  int iCTime = ly_time() ;
  WriteTimestampedLogEntry("Module TN bouchon 2, version du 16-09-2005 et +");
  WriteTimestampedLogEntry(""+IntToString(iRBOOT+1));
  WriteTimestampedLogEntry(""+IntToString(iTOUR));
  WriteTimestampedLogEntry("");
  WriteTimestampedLogEntry("");
  WriteTimestampedLogEntry("");
  WriteTimestampedLogEntry("Date RP : lancement du monde le "+IntToString(nCTD)+" "+IntToString(nCTM)+" "+IntToString(nCTY));
  WriteTimestampedLogEntry("Date RP : actuellement nous sommes le "+IntToString(iCTD)+" "+IntToString(iCTM)+" "+IntToString(iCTY));
  WriteTimestampedLogEntry("Heure RP : il est "+IntToString(iTH)+":"+IntToString(iTM));
  //
    SetLocalInt(oMod, "StartDay", iAbsolDay) ;
  //
    SetLocalInt(oMod, "StartTime", iCTime) ;
}
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.


Ce message est un spoiler, et risque de vous informer de choses que vous auriez dû apprendre par vous même (fin d'un jeu, film, etc). À vos risques et périls (ludiques), vous pouvez le voir en cliquant sur cet avertissement.
Spoiler :
NWScript :
//:Confused/
//:: bbs_mod_hb.nss
//:: Mod_OnHeartBeat Event
//:: Created Lylver 2005-09-17
//:: pour implementation BBS
//:: DB Flush Cache, On File Queue : User's Events 600 601 602
//:: restart en User's Event 604
//:Confused/////////////////

void main()
{
  object oMod = GetModule();
  SignalEvent(oMod, EventUserDefined(600)); // DB Writer Flush Event
}
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.


Ce message est un spoiler, et risque de vous informer de choses que vous auriez dû apprendre par vous même (fin d'un jeu, film, etc). À vos risques et périls (ludiques), vous pouvez le voir en cliquant sur cet avertissement.
Spoiler :
NWScript :
//:Confused/
//:: bbs_mod_userdef.nss
//:: Mod_OnUsrDefined Event
//:: Updated 2005-09-17 Lylver
//:: pour le TN Bouchon 2 : BBS,
//:: systeme de Cache Database NWN
//:: persistence date/heure
//:Confused/

#include "ly_lib_time"
#include "bbs_lib_item"
void main(){
  object oMod = GetModule() ;
  switch (GetUserDefinedEventNumber()) {
      case 200:{
        DelayCommand(600.0, SignalEvent(OBJECT_SELF, EventUserDefined(200)));
        //
        struct MemDB dDB;
        dDB.sDB = "DATE_MODULE";
        dDB.oChi = GetLocalObject(oMod,"DBI_READ");
        dDB.oChs = GetLocalObject(oMod,"DBS_READ");
        dDB.oDbi = GetLocalObject(oMod,"DBI_FIFO");
        dDB.oDbs = GetLocalObject(oMod,"DBS_FIFO");
        dDB.sVar = "";
        dDB.nValue = 0;
        dDB.sValue = "";
        //
        // Decompte du temps de jeu par tranche de dix minutes.
        //
        int iCTY = GetCalendarYear() ;
        int iCTM = GetCalendarMonth() ;
        int iCTD = GetCalendarDay() ;
        int iTH = GetTimeHour();
        int iTM = GetTimeMinute();
        int iTS = GetTimeSecond();
        int iCDay = ly_day() ;
        int iCTime = ly_time() ;
        dDB.sVar = "NTOUR";
        int iTOUR = GCacheInt(dDB) ;
        // Enregistrement du temps, avec mise en cache
        dDB.sVar = "MINUTE" ; dDB.nValue = iTM ; SCacheInt(dDB) ;
        dDB.sVar = "HEURE" ; dDB.nValue = iTH ; SCacheInt(dDB) ;
        dDB.sVar = "JOUR" ; dDB.nValue = iCTD ; SCacheInt(dDB) ;
        dDB.sVar = "MOIS" ; dDB.nValue = iCTM ; SCacheInt(dDB) ;
        dDB.sVar = "ANNEE" ; dDB.nValue = iCTY ; SCacheInt(dDB) ;
        dDB.sVar = "NTOUR" ; dDB.nValue = iTOUR+1 ; SCacheInt(dDB) ; // incrementation
/*
    Export all characters every 'n' seconds. Note that this event triggers
    itself, on a timer, when finished -- until the module is unloaded.
*/

        ExportAllCharacters();
        break;
      }
      case 600:{
        ExecuteScript("bbs_mod_dbcache",OBJECT_SELF) ;
        break ;
      }
      case 601:{
        ExecuteScript("bbs_mod_dbcachi",OBJECT_SELF) ;
        break ;
      }
      case 602:{
        ExecuteScript("bbs_mod_dbcachs",OBJECT_SELF) ;
        break ;
      }
      case 604:{
        if( GetLocalInt(OBJECT_SELF,"DBIFLUSHED") && GetLocalInt(OBJECT_SELF,"DBSFLUSHED") ){
            SendMessageToAllDMs("DB Flush : completed.");
            WriteTimestampedLogEntry("DB Flush : completed.");
            StartNewModule("tnbouchon1609") ;
        }else{
            SendMessageToAllDMs("Waiting for DB Flush to complete...");
            WriteTimestampedLogEntry("Waiting for DB Flush to complete...");
            DelayCommand(2.0, SignalEvent(OBJECT_SELF, EventUserDefined(604)));
        }
        break ;
      }
  } /* switch */
}
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.


Ce message est un spoiler, et risque de vous informer de choses que vous auriez dû apprendre par vous même (fin d'un jeu, film, etc). À vos risques et périls (ludiques), vous pouvez le voir en cliquant sur cet avertissement.
Spoiler :
NWScript :
//:: ////
//:: bbs_mod_def_act.nss
//:: Mod_OnActvtItem Event
//:: Update Lylver 2005-09-17
//:: added restarter
//:: for module with Cache Database
//:: ////

void main()
{
object oItem = GetItemActivated(); // get the item activated
string sItemTag = GetTag(oItem); // and its tag
string sItemName = GetName(oItem); // and its name
object oActivator = GetItemActivator(); // get the wand's activator
object oTarget = GetItemActivatedTarget(); // get the target
string sTargetTag = GetTag(GetItemActivatedTarget()); // and its tag
location lTargetLoc = GetItemActivatedTargetLocation(); // Get the Location
object oMod = GetModule(); // Get the module object

  if(GetTag(oItem)=="RESTARTTN")
  {
      location lTarget = GetLocation(oTarget);
      effect eVis = EffectVisualEffect(VFX_FNF_TIME_STOP);
      effect eTime = EffectTimeStop(); // Note : arrete l'horloge PC ca
      SetLocalInt(oMod,"REBOOT",TRUE); // indicateur pour les process differes
      SignalEvent(oMod, EventUserDefined(200)); // Update PC Database
      DelayCommand(4.0 ,SignalEvent(oMod, EventUserDefined(600))) ; // Flush Database
      SignalEvent(oActivator, EventSpellCastAt(oActivator, SPELL_TIME_STOP, FALSE));
      DelayCommand(0.75, ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eTime, oActivator, 3.0));
      object oPC=GetFirstPC() ;
      while( GetIsObjectValid(oPC) ){
        ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eVis, GetLocation(oPC));
        SendMessageToPC(oPC,"REBOOT A CHAUD DU MODULE");
        oPC = GetNextPC() ;
      }
      SignalEvent(oMod, EventUserDefined(604)) ; // reboot apres DB flush
      return;
  }
}
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.


Ce message est un spoiler, et risque de vous informer de choses que vous auriez dû apprendre par vous même (fin d'un jeu, film, etc). À vos risques et périls (ludiques), vous pouvez le voir en cliquant sur cet avertissement.
Spoiler :
NWScript :
//:: ////
//:: bbs_mod_dbcache.nss
//:: Update Lylver 2005-09-17
//:: //
//:: Updated Lylver 2005-08-01
//:: DB Flush Cache, On File Queue : User's Events 600 601 602
#include "bbs_lib_item"
void main()
{
  //
  object oMod=GetModule();
  struct MemDB dDB;
      dDB.sDB = "";
      dDB.oChi = GetLocalObject(oMod,"DBI_READ");
      dDB.oChs = GetLocalObject(oMod,"DBS_READ");
      dDB.oDbi = GetLocalObject(oMod,"DBI_FIFO");
      dDB.oDbs = GetLocalObject(oMod,"DBS_FIFO");
      dDB.sVar = "";
      dDB.nValue = 0;
      dDB.sValue = "";
  //
  int nModFCounter = GetLocalInt(dDB.oDbi,"FDBICNT") ;
  int nModWCounter = GetLocalInt(dDB.oDbi,"WDBICNT") ;
  if( nModWCounter > nModFCounter ){ // il y a des ecritures en attente
      // SendMessageToAllDMs("DBI Cache : "+IntToString(nModWCounte r)+"-"+IntToString(n ModFCounter));
      SignalEvent(oMod, EventUserDefined(601));
  }else{
      if( nModWCounter < nModFCounter ){ // DB flush error
        WriteTimestampedLogEntry("DBI Cache Flush Error");
      }else{ // egalite
        if( nModFCounter > 10000 ){ // raz compteur pour pas aller trop haut en valeur
            DeleteLocalInt(dDB.oDbi,"FDBICNT");
            DeleteLocalInt(dDB.oDbi,"WDBICNT");
        }
      }
      if( GetLocalInt(oMod,"REBOOT") ){
            SetLocalInt(oMod,"DBIFLUSHED",TRUE);
      }
  }
  nModFCounter = GetLocalInt(dDB.oDbs,"FDBSCNT") ;
  nModWCounter = GetLocalInt(dDB.oDbs,"WDBSCNT") ;
  if( nModWCounter > nModFCounter ){ // il y a des ecritures en attente
      // SendMessageToAllDMs("DBS Cache : "+IntToString(nModWCounte r)+"-"+IntToString(n ModFCounter));
      SignalEvent(oMod, EventUserDefined(602));
  }else{
      if( nModWCounter < nModFCounter ){ // DB flush error
        WriteTimestampedLogEntry("DBS Cache Flush Error");
      }else{ // egalite
        if( nModFCounter > 10000 ){ // raz compteur pour pas aller trop haut en valeur
            DeleteLocalInt(dDB.oDbs,"FDBSCNT");
            DeleteLocalInt(dDB.oDbs,"WDBSCNT");
        }
      }
      if( GetLocalInt(oMod,"REBOOT") ){
            SetLocalInt(oMod,"DBSFLUSHED",TRUE);
      }
  }
}
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.


Ce message est un spoiler, et risque de vous informer de choses que vous auriez dû apprendre par vous même (fin d'un jeu, film, etc). À vos risques et périls (ludiques), vous pouvez le voir en cliquant sur cet avertissement.
Spoiler :
NWScript :
//:: ////
//:: bbs_mod_dbcachi.nss
//:: Update Lylver 2005-09-17
//:: //
//:: Updated Lylver 2005-08-01
//:: DB Flush Cache, On File Queue : User's Events 600 601 602
#include "bbs_lib_item"
void main()
{
  //
  object oMod=GetModule();
  struct MemDB dDB;
      dDB.sDB = "";
      dDB.oChi = GetLocalObject(oMod,"DBI_READ");
      dDB.oChs = GetLocalObject(oMod,"DBS_READ");
      dDB.oDbi = GetLocalObject(oMod,"DBI_FIFO");
      dDB.oDbs = GetLocalObject(oMod,"DBS_FIFO");
      dDB.sVar = "";
      dDB.nValue = 0;
      dDB.sValue = "";
  //
  int nModFCounter = GetLocalInt(dDB.oDbi,"FDBICNT") ;
  int nModWCounter = GetLocalInt(dDB.oDbi,"WDBICNT") ;
  if( nModWCounter > nModFCounter ){ // il y a des ecritures en attente
      nModFCounter++ ; // on prend en charge
      SetLocalInt(dDB.oDbi,"FDBICNT",nModFCounter) ; // espere atomique
      string sDBCache = GetLocalString(dDB.oDbi,"IDBCACHE"+IntToString(nModFCounter)) ;
      string sVARCache = GetLocalString(dDB.oDbi,"IVARCACHE"+IntToString(nModFCounter)) ;
      int nVALUECache = GetLocalInt(dDB.oDbi,"IVALUECACHE"+IntToString(nModFCounter)) ;
      // purge memoire
      DeleteLocalString(dDB.oDbi,"IDBCACHE"+IntToString(nModFCounter)) ;
      DeleteLocalString(dDB.oDbi,"IVARCACHE"+IntToString(nModFCounter)) ;
      DeleteLocalInt(dDB.oDbi,"IVALUECACHE"+IntToString(nModFCounter)) ;
      // flush
      SetCampaignInt(sDBCache,sVARCache,nVALUECache); // flush it
      // WriteTimestampedLogEntry(" ;DBIWriter : "+IntToString(nModFCounte r)+" "+sVARCache+" "+IntToString(nVALUECache ));
      if( nModWCounter != nModFCounter ){
        if( GetLocalInt(oMod,"REBOOT") ){
            SignalEvent(oMod,EventUserDefined(601)); // fast flush
        }else{
            DelayCommand(0.5,SignalEvent(oMod, EventUserDefined(601)));
        }
        // ajuste delai en fonction du lag ressenti
      }else{
        // SendMessageToAllDMs("DBI Cache : Done !");
        if( GetLocalInt(oMod,"REBOOT") ){
            SetLocalInt(oMod,"DBIFLUSHED",TRUE);
        }
      }
  }
}
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.


Ce message est un spoiler, et risque de vous informer de choses que vous auriez dû apprendre par vous même (fin d'un jeu, film, etc). À vos risques et périls (ludiques), vous pouvez le voir en cliquant sur cet avertissement.
Spoiler :
NWScript :
//:: ////
//:: bbs_mod_dbcachs.nss
//:: Update Lylver 2005-09-17
//:: //
//:: Updated Lylver 2005-08-01
//:: DB Flush Cache, On File Queue : User's Events 600 601 602
#include "bbs_lib_item"
void main()
{
  //
  object oMod=GetModule();
  struct MemDB dDB;
      dDB.sDB = "";
      dDB.oChi = GetLocalObject(oMod,"DBI_READ");
      dDB.oChs = GetLocalObject(oMod,"DBS_READ");
      dDB.oDbi = GetLocalObject(oMod,"DBI_FIFO");
      dDB.oDbs = GetLocalObject(oMod,"DBS_FIFO");
      dDB.sVar = "";
      dDB.nValue = 0;
      dDB.sValue = "";
  //
  int nModFCounter = GetLocalInt(dDB.oDbs,"FDBSCNT") ;
  int nModWCounter = GetLocalInt(dDB.oDbs,"WDBSCNT") ;
  if( nModWCounter > nModFCounter ){ // il y a des ecritures en attente
      nModFCounter++ ; // on prend en charge
      SetLocalInt(dDB.oDbs,"FDBSCNT",nModFCounter) ; // espere atomique
      string sDBCache = GetLocalString(dDB.oDbs,"SDBCACHE"+IntToString(nModFCounter)) ;
      string sVARCache = GetLocalString(dDB.oDbs,"SVARCACHE"+IntToString(nModFCounter)) ;
      string sVALUECache = GetLocalString(dDB.oDbs,"SVALUECACHE"+IntToString(nModFCounter)) ;
      // purge memoire
      DeleteLocalString(dDB.oDbs,"SDBCACHE"+IntToString(nModFCounter)) ;
      DeleteLocalString(dDB.oDbs,"SVARCACHE"+IntToString(nModFCounter)) ;
      DeleteLocalString(dDB.oDbs,"SVALUECACHE"+IntToString(nModFCounter)) ;
      // flush
      SetCampaignString(sDBCache,sVARCache,sVALUECache); // flush it
      // WriteTimestampedLogEntry(" ;DBSWriter : "+IntToString(nModFCounte r)+" "+sVARCache+" "+sVALUECache);
      if( nModWCounter != nModFCounter ){
        if( GetLocalInt(oMod,"REBOOT") ){
            SignalEvent(oMod,EventUserDefined(602)); // fast flush
        }else{
            DelayCommand(0.5,SignalEvent(oMod, EventUserDefined(602)));
        }
        // ajuste delai en fonction du lag ressenti
      }else{
        // SendMessageToAllDMs("DBS Cache : Done !");
        if( GetLocalInt(oMod,"REBOOT") ){
            SetLocalInt(oMod,"DBSFLUSHED",TRUE);
        }
      }
  }
}
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.


Ce message est un spoiler, et risque de vous informer de choses que vous auriez dû apprendre par vous même (fin d'un jeu, film, etc). À vos risques et périls (ludiques), vous pouvez le voir en cliquant sur cet avertissement.
Spoiler :
NWScript :



//:Confused///////////////////////// /////////////////////
//:: FileName: bbs_show_next
//:Confused///////////////////////// ////////////////////
/*
*/

//:Confused///////////////////////// ////////////////////
//:: Inspire du systeme du BBS1.1 de Serban Oprescu
//:: Created By: MrPin
//:: Created On: 27/08/2004
//:Confused///////////////////////// ////////////////////
#include "bbs_lib_item"
int StartingConditional()
{
  object oMod=GetModule();
  struct MemDB dDB;
      dDB.sDB = "DB_BBS";
      dDB.oChi = GetLocalObject(oMod,"DBI_READ");
      dDB.oChs = GetLocalObject(oMod,"DBS_READ");
      dDB.oDbi = GetLocalObject(oMod,"DBI_FIFO");
      dDB.oDbs = GetLocalObject(oMod,"DBS_FIFO");
      dDB.sVar = "";
      dDB.nValue = 0;
      dDB.sValue = "";
  //
  object oBBS = GetLocalObject(oMod, "BBS_" + GetTag(OBJECT_SELF));
  string sType = GetLocalString(oBBS, "BBS_TYPE");
  dDB.sVar = GetTag(oBBS)+ "#C" + sType ;
  int TotalItems = GCacheInt(dDB);
  int PageSize = GetLocalInt(oBBS, "PageSize");
  int PageIndex = GetLocalInt(oBBS, "PageIndex");
  if (TotalItems > (PageIndex + 1) * PageSize) {
    return TRUE;
  }
  return FALSE;
}
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.
Dernière édition par lylver le 06/04/2006 08:59:17; édité 2 fois
 
Revenir en haut Voir le profil de l'utilisateur Envoyer un message privé Ignorer l'utilisateur
 
BenGorre
Légende vivante
Inscrit le: 12 Fév 2004
Messages: 301
Répondre en citant
Posté le : 27/09/2005 17:07:38 Sujet du message :

Voici mon script pour enlever un effet visuel permanent qu'on a appliqué avant par script:
NWScript :

void main()
{
object oPC = /*definition du joueur cible*/;
effect eLoop=GetFirstEffect(oPC);
  while (GetIsEffectValid(eLoop))
  {
  if (GetEffectType(eLoop)== 74 && GetEffectSpellId(eLoop)==-1)
    RemoveEffect(oPC, eLoop);
  eLoop=GetNextEffect(oPC);
  }
}
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.


Je pense qu'il sera utile a beaucoup de gens. Ce script permet d'ameliorer les haks qui utilise des vfx pour mettre des cornes, des yeux brillants et autres.
_________________
La mort n'est rien seul le fait de mourir est terrible
Henry Fielding 1745

Le serveur Filandre a été stoppé pour le moment, je on travail à la conversion vers NWN2.
 
Revenir en haut Voir le profil de l'utilisateur Envoyer un message privé Ignorer l'utilisateur
 
Black Knight
Grand Maître Chanteur du Conseil
Inscrit le: 27 Oct 2005
Messages: 1031
Localisation: Fin fond du trou du cul du monde
Répondre en citant
Posté le : 31/10/2005 13:19:56 Sujet du message :

Il a plein de personne (je pense) qui souhaiterais faire un "Black Smith"

#Qu'est ce qu'un BLACK SMITH ?
C'est un personnage qui sert de "marchand de creation". Donc faire par exemple un armure a votre gouts!

#Petit conseil
Prenez tout votre temps. Les scripts sont super simple mais faire tout monsieur Black Smith c'est super long (j'ai du mettre 2 semaines)

#Preparation
Faite deja un Waypoint la ou les joueurs ne pourrons pas voir l'objet (je vous expliquerais) et ou il ne peuvent surtout pas le prendre. (tag : WP_Craft)

Faite une armure lourde tagger = ArmureLourde et en Ref = armurel_craft

#Le Dialogue
Deja il faut créer un dialogue (le dialogue que je vais vous faire est de base!):
Rouge : Black smith
Bleue : PJ
Gris : Lien

Dialogue : (ne fait pour l'instant pas gaff au dialogue lisez le juste tout vous sera explique ensuite)
-Bienvenue que voulez vous créer ?
--Une armure
---Quel genere d'armure ?
----Armure Lourde
-----Votre item coute : <CUSTOM2000>
------[CONTINUER]
-------Que voulez vous ajoute ?
--------Un bonnus d'armure
---------De combien voulez vous ?
----------+1
-----------J'ai ajuster ce que vous avez demendé
------Créer l'objet
-----J'ai ajuster ce que vous avez demendé
------Votre item coute : <CUSTOM2000>

Bon voila le dialogue.Nous allons evite les premiere lignes et nous allons regarde de plus pres la ligne : Armure Lourde
Ici vous devez ajoute ce petit script :

NWScript :

void main()
{
CreateObject(OBJECT_TYPE_ITEM, "armurel_craft", GetLocation(GetWaypointByTag("WP_Craft")));
object oObject = GetObjectByTag("ArmureLourde");
SetLocalObject(GetPCSpeaker(), "Item", oObject);
}
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.


Ce script vous permet :
1 => de creer l'objet (armure lourde) au Waypoint que je vous ai dit de creer
2 => D'enregistrer sur une local son nom avec comme base "Item"

La prochaine ligne est : Votre item coute : <CUSTOM2000>
Ici vous allez mettre le script suivant :

NWScript :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.


Ce script vous permet :
1) De dire combien l'objet coute grace a custom 2000

Apres prochaine phrase : Un bonnus d'armure
(Ce script est a mettre dans le Condition de la phrase!

NWScript :
int StartingConditional()
{

  // Inspecter variables locales
  if(!(GetLocalInt(GetPCSpeaker(), "Armure") == 0))
    return FALSE;

  return TRUE;
}
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.


Ce script vous permet :
1) D'evite a ce que le joueur puisse mettre plusieur bonnus d'armure (ce ne sera pas cumulable sinon (et de plus l'item coutera plus chere!))

Prochaine phrase : +1
Script a mettre :

NWScript :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.


Ce script vous permet :
1) De mettre l'armure demendé en armure +1

AU CAS OU : si le joueur c'est tromper vous pouvez mettre une phrase "Retour" mais attention ne pas oublier de mettre a LocalInt a 0 !! Sinon le joueur se retrouvera "un peut idiot" si il voulez mettre +1 a la CA

Apres : J'ai ajuster ce que vous avez demendé
Vous mettez ce script :

NWScript :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.


Ce script vous permet de :
1)Examiner l'objet en question (moi je doit avoir un bug sa ne s'examine pas, pourquoi ? il y a un bug ? si vous le trouvez merci de me le dire svp !)

Prochaine phrase : Créer l'objet
vous mettez ce script :

NWScript :
void main()
{
object oPC = GetPCSpeaker();
DestroyObject(GetLocalObject(oPC, "Item"));
int iGold = GetGold(oPC);
int iPiece = GetGoldPieceValue(GetLocalObject(oPC, "Item"));
if(iGold < iPiece)
{
FloatingTextStringOnCreature("IMPOSSIBLE : Vous n'avez pas assez d'argent. Crafting arreter !\n(Votre or : "+IntToString(iGold)+"\nCoute : "+IntToString(iPiece)+"\nVous avez besoin de : "+IntToString(abs(iPiece-iGold))+")", oPC);
}
else
{
CopyItem(GetLocalObject(oPC, "Item"), oPC);
TakeGoldFromCreature(GetGoldPieceValue(GetLocalObject(oPC, "Item")), oPC);
}
DeleteLocalObject(oPC, "Item");
SetLocalInt(oPC, "Armure", 0);
}
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.


Ce script vous permet :
1) De detruire l'objet (regarde la suite pour plus d'expliquation)
2) De voir si le PJ a assez d'argent, si oui il creer l'objet en prenant l'argent necessaire
3) De detruire la LocalObject "Item"
4) De remettre le bonnus d'armure a 0 (la LocalInt "Armure")

Si le joueur souhaite tout stopper vous rajouter une phrase "Annuler" au moment ou le PNJ dit "Votre item coute : <CUSTOM2000>"

a mettre ceci comme script a l'interrieur :

NWScript :
void main()
{
object oPC = GetPCSpeaker();
DestroyObject(GetLocalObject(oPC, "Item"));
SetLocalInt(oPC, "Armure", 0);
DeleteLocalObject(oPC, "Item");
}
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.


Ce script vous permet :
1) de detruire l'item
2) de detruire la LocalInt "Armure"
3) de detruire la LocalObject "Item"

#Info
-Un objet sera crée au Waypoint que je vous ai demendé de créer, ceci et pour que le blacksmith ajoute les proprietes dessus et dise cb il coute. Apres il a juste a faire une copie de celui ci et de detruire l'item.
-la LocalObject "Item" sert a ajoute TOUT sans faire des immences script, Black smith prend le tag de l'objet et le met dans une localobject, apres il ajuste tout sur cette local.
-Et une derniere chose je vous ai mis aussi la localobject pour que vous puissez faire des ccopier coller ! Voila les 2 phrase a copier coller en tant que lien :
Votre item coute : <CUSTOM2000>
J'ai ajuster ce que vous avez demendé
Apres dans les action des phrase commes Armure leger, Casque etc.. vous devez creer un Casque (par exemple) et remplace ce script :

NWScript :
void main()
{
CreateObject(OBJECT_TYPE_ITEM, "armurel_craft", GetLocation(GetWaypointByTag("WP_Craft")));
object oObject = GetObjectByTag("ArmureLourde");
SetLocalObject(GetPCSpeaker(), "Item", oObject);
}
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.


par celui la :

NWScript :
void main()
{
CreateObject(OBJECT_TYPE_ITEM, "casque_craft", GetLocation(GetWaypointByTag("WP_Craft")));
object oObject = GetObjectByTag("Casque");
SetLocalObject(GetPCSpeaker(), "Item", oObject);
}
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.


Voila si vous avez des questions je suis dispo si vous savez comment resoudre mon probleme d'examination de l'objet je suis dispo aussi ! Allez bonne chance a vous (et oui vous devez faire TOUT le reste vous comprenez maintenant pk les 2 semaines loool)
 
Revenir en haut Voir le profil de l'utilisateur Envoyer un message privé Ignorer l'utilisateur
 
Black Knight
Grand Maître Chanteur du Conseil
Inscrit le: 27 Oct 2005
Messages: 1031
Localisation: Fin fond du trou du cul du monde
Répondre en citant
Posté le : 02/11/2005 15:07:17 Sujet du message :

J'ai trouve mon p'tit bug pour l'examination, apparament sa serait du a cause d'une phrase direct :s voila comment il doit se presente :

NWScript :
void main()
{
object oPC = GetPCSpeaker();
object oItem = GetLocalObject(oPC, "Item");
AssignCommand(oPC, ActionExamine(oItem));
}
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.


Voila ceci fera l'affaire
 
Revenir en haut Voir le profil de l'utilisateur Envoyer un message privé Ignorer l'utilisateur
 
Montrer les messages depuis :
Page 1 sur 2 ¤ Aller à la page 1, 2  Suivante


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 265.684ms