La Bibliothèque de Neverwinter Nights
Aide et informations diverses sur Neverwinter Nights ainsi que D&D3.
Aide et informations diverses sur Neverwinter Nights ainsi que D&D3.
FAQ
Rechercher
Liste des Membres
Groupes d'utilisateurs
S'enregistrer Se connecter pour vérifier ses messages privés Connexion
S'enregistrer Se connecter pour vérifier ses messages privés Connexion
La date/heure actuelle est 23/11/2024 23:00:41
La Bibliothèque de Neverwinter Nights Index du Forum »
La Bibliothèque Binaire du NWScript - Neverwinter Nights
Voir le sujet précédent ¤ Voir le sujet suivant | |
---|---|
Auteur | Message |
Djezebel Héros Messages: 252 |
Bonjour à tous
Avec mes petites mimines, je me suis débrouillée pour faire un script qui tient en partie. Il y a juste quelques "problèmes". Je vous place le décors : Un coffre qui ne peut être ouvert qu'avec une clef. Cette clef est sur un gros monstre et ne peut être volée. Le but des PJ : Prendre la clef et ouvrir le coffre. Effet voulu : Au moment où le Boss (portant la clef) tombe, au bout de quelques secondes, un homme (PNJ) apparait, figeant tous les joueurs. Il s'approche lentement de la clef (ou de celui qui la porte), dit "Merci bien...", s'en va vers le coffre contenant l'objet désiré des joueurs, ouvre le coffre et prend ce qu'il y a dedans puis se téléporte de la même manière qu'il est arrivé. J'ai placé pour ce faire 3 scripts : - Un à la mort du boss qui fait apparaitre un objet invisible qui, lui-même fait apparaitre avec un délais le PNJ. - Un trigger qui dit que si le PNJ en question entre dedans, tous les joueurs sont figés dans un rayon de 30 ... mètres (? feet ? yard ?) - Une animation dans le onSpawn du PNJ. Je vous passe cette dernière car je suppose que ce sera celle-ci qu'il faudra modifier ; les deux autres fonctionnant parfaitement. (j'explique le problème en dessous) NWScript :
void main() { object oClef = GetObjectByTag("g_clef"); object oRelique = GetObjectByTag("g_relique"); object oPC = GetItemPossessor(oClef); object oCoffre = GetItemPossessor(oRelique); effect eVisufx = EffectVisualEffect(34); if (GetIsObjectValid(OBJECT_SELF) == TRUE) // Si le PNJ est encore vivant { ActionMoveToObject(oClef, FALSE, 50.0); DelayCommand(3.8, ActionTakeItem(oClef, oPC)); // Il va voler la clef DelayCommand(10.0, ActionSpeakString("Merci bien...")); if (GetIsObjectValid(OBJECT_SELF) == TRUE) { DelayCommand(11.0, ActionMoveToObject(oRelique, FALSE, 30.0)); if (GetIsObjectValid(OBJECT_SELF) == TRUE) { DelayCommand(16.3, ActionTakeItem(oRelique, oCoffre)); if (GetIsObjectValid(OBJECT_SELF) == TRUE) { DelayCommand(19.5, AssignCommand(oCoffre, ActionPlayAnimation(ANIMATION_PLACEABLE_OPEN))); DelayCommand(20.4, ActionSpeakString("Vos efforts auront ete utiles. Merci encore...")); DelayCommand(22.5, AssignCommand(oCoffre, ActionPlayAnimation(ANIMATION_PLACEABLE_CLOSE))); DelayCommand(26.0, ApplyEffectToObject(0, eVisufx , OBJECT_SELF)); DelayCommand(26.5, DestroyObject(OBJECT_SELF)); } } } } } Les problèmes sont les suivants : - Si je réussi à prendre la clef et à aller vers le coffre rapidement, le PNJ reste sur place, dit juste "merci" et ne prend pas du tout les objets... - Si un groupe de joueurs entre pendant que les premiers sont paralysés, ils ont la possibilité de tuer le PNJ. Mais s'ils échouent, le PNJ risque de ne pas prendre en compte le reste de ses actions à faire... donc comment faire ? - Est-ce que le PNJ, entrant en combat continuera à faire ce script ? (comme dire "merci", aller là où ils doit allier) où bien il sera interrompu ? - Problème mineur : pourquoi mon PNJ même si je lui dit de marcher, il court ? Merci pour toutes vos lumières ! Dernière édition par Djezebel le 06/01/2006 11:07:34; édité 1 fois
|
Revenir en haut | |
Enki Légende vivante Messages: 432 |
Salut Djezebel,
je trouve cette petite scène très marrante et je vais voir ce que je peux faire. Néanmoins, peux-tu m'expliquer pourquoi tu as besoin de demander 4 fois si le PNJ est un objet valide ? Bon je te recontacte dès que c'est fait ! A plus tard ! |
Revenir en haut | |
Djezebel Héros Messages: 252 |
C'est peut-être très bête, mais je n'aimerai pas que le script continue de se dérouler si le PNJ est mort.
Par exemple qu'il dise la dernière phrase alors qu'il est sur le sol ou bien qu'il prenne un objet alors qu'il est sensé ne plus être là. Vu ta remarque, je me dis que ça doit être inutile En tout cas, merci de te pencher sur mon problème |
Revenir en haut | |
Enki Légende vivante Messages: 432 |
Salut Djezebel,
J'ai terminé les scripts de ta scène, et j'espère avoir bien compris ce que tu voulais. Je l'ai rendu un poil plus vivante qu'elle ne l'était, de sorte que je suis plutôt content de moi. En fait, je crois que c'est la scène la plus sympa que j'ai faite. Alors, j'ai fait 5 scripts au lieu de trois, mais c'est plus simple ainsi. J'ai également fait : - 1 coffre. - 1 trigger. - 1 PNJ dans la zone, celui qui possède la clef, appelons-le "le monstre". - 1 PNJ dans la palette avec comme ResRef "luline006" (je l'ai trouvé dans un de tes messages précédents, il me semblait que cela avait un rapport) - 1 waypoint avec comme TAG "WP_Spawn" - 1 clef avec comme TAG "g_clef" - 1 relique avec comme TAG "g_relique" Pas d'objet invisible, cela ne sert à rien. Le monstre doit avoir dans ses propriétés : - Laisser corps détroussables > 20 Sec. et - Pas de mort définitive. - Et bien sûr, la clef dans son inventaire, abandon possible, mais vol impossible. Il doit avoir le script suivant sur le OnDeath : NWScript :
// fonction permettant d'appliquer un delai a la creation d'un objet void DelayCreatObject(int nObjectType, string sTemplate, location lLoc, int bUseAppearAnimation = FALSE, string sNewTag= "") { CreateObject(nObjectType, sTemplate, lLoc, bUseAppearAnimation, sNewTag); } void main() { object oPC=GetLastKiller(); SetIsDestroyable(FALSE, TRUE, TRUE); SetLocalInt(GetModule(),"mort",100); object oSpawn = GetNearestObjectByTag("WP_Spawn"); location lSpawn = GetLocation(oSpawn); effect eVisufx = EffectVisualEffect(34); DelayCommand(5.5, ApplyEffectAtLocation(0, eVisufx , lSpawn)); DelayCommand(6.0,DelayCreatObject(OBJECT_TYPE_CREATURE, "luline006", lSpawn, FALSE, "Homme etrange")); DelayCommand(2.5, AssignCommand(oPC,SpeakString(""))); DelayCommand(2.5, AssignCommand(oPC,PlayAnimation(ANIMATION_LOOPING_SPASM,1.0,26.0))); SetCutsceneMode(oPC,TRUE); } Tu le reconnais ? C'est le tien à quelque chose près. Le coffre doit être utilisable, inventaire, et intrigue. + vérouillé, clef requise pour dévérouiller, TAG clef "g_clef". Tu mets la relique à l'intérieur. Tu lui enlèves TOUS les scripts, et sur le Unlock tu places 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. C'est mieux de faire ainsi plutôt que dans le OnSpawn du "voleur", avec des delayCommand pas très précis. Puis, tu places le waypoint "WP_Spawn" ou tu veux. Ensuite, tu places ton trigger de sorte qu'il englobe le coffre(important) et le waypoint (facultatif). Sur le trigger, dans le OnEnter tu mets ce script : NWScript :
void main() { object oPC=GetEnteringObject(); int iMort=GetLocalInt(GetModule(),"mort"); if (iMort!=100) return; if (GetIsPC(oPC)) { SetCutsceneMode(oPC,TRUE); DelayCommand(2.5, AssignCommand(oPC,SpeakString(""))); DelayCommand(2.5, AssignCommand(oPC,PlayAnimation(ANIMATION_LOOPING_SPASM,1.0,20.0))); } } Il sert à empécher les autres joueurs éventuels de tuer le PNJ qui vient prendre la clef et la relique. Enfin, sur le PNJ avec le ResRef "luline006", tu mets ces deux scripts : Sur le OnSpawn : NWScript :
void LibereAllPC(object oPJ) { object oPJ = GetFirstPC(); while(GetIsObjectValid(oPJ)) { SetCutsceneMode(oPJ,FALSE); oPJ = GetNextPC(); } } #include "x0_i0_position" #include "NW_I0_GENERIC" void main() { // * Fire User Defined Event 1001 in the OnHeartbeat // * SetSpawnInCondition(NW_FLAG_HEARTBEAT_EVENT); // * Fire User Defined Event 1002 // * // SetSpawnInCondition(NW_FLAG_PE RCIEVE_EVENT); // * Fire User Defined Event 1005 // * // SetSpawnInCondition(NW_FLAG_AT TACK_EVENT); // * Fire User Defined Event 1006 // * // SetSpawnInCondition(NW_FLAG_DA MAGED_EVENT); // * Fire User Defined Event 1008 // * // SetSpawnInCondition(NW_FLAG_DI STURBED_EVENT); // * Fire User Defined Event 1003 // * // SetSpawnInCondition(NW_FLAG_EN D_COMBAT_ROUND_EVENT); // * Fire User Defined Event 1004 // * // SetSpawnInCondition(NW_FLAG_ON _DIALOGUE_EVENT); object oPJ = GetFirstPC(); object oClef = GetObjectByTag("g_clef"); object oRelique = GetObjectByTag("g_relique"); object oPC = GetItemPossessor(oClef); object oCoffre = GetItemPossessor(oRelique); effect eVisufx = EffectVisualEffect(34); float oFace=GetFacing(OBJECT_SELF); float oFace01=GetFacing(oPJ); float oFace02=GetOppositeDirection(oFace); AssignCommand(oPJ,SetCameraFacing(oFace02,-1.0f,-1.0,CAMERA_TRANSITION_TYPE_MEDIUM)); ActionMoveToObject(oPC, FALSE, 1.0f); ActionPlayAnimation(ANIMATION_LOOPING_GET_LOW,1.0,2.0); ActionTakeItem(oClef, oPC); // Il va voler la clef ActionSpeakString("Merci bien..."); ActionMoveToObject(oCoffre, FALSE, 0.5f); ActionDoCommand(DoPlaceableObjectAction(oCoffre,PLACEABLE_ACTION_UNLOCK)); ActionTakeItem(oRelique, oCoffre); ActionPlayAnimation(ANIMATION_LOOPING_TALK_LAUGHING,1.0,1.0); ActionSpeakString(""); DelayCommand(25.5, ApplyEffectToObject(0, eVisufx , OBJECT_SELF)); DelayCommand(26.0, SetLocalInt(GetModule(),"mort",0)); DelayCommand(26.5, LibereAllPC(oPJ)); DelayCommand(25.0,AssignCommand(oPJ,SetCameraFacing(oFace01,-1.0f,-1.0,CAMERA_TRANSITION_TYPE_FAST))); DelayCommand(26.5, DestroyObject(OBJECT_SELF)); } et sur le OnUserDefined : NWScript :
void main() { int nUser = GetUserDefinedEventNumber(); if(nUser == 1001) //HEARTBEAT { object oPJ = GetFirstPC(); float oFace=GetFacing(OBJECT_SELF); AssignCommand(oPJ,SetCameraFacing(oFace,-1.0f,-1.0,CAMERA_TRANSITION_TYPE_MEDIUM)); } } Et voilà, si je n'ai pas bien compris, ou si tu veux rajouter ou enlever des choses, n'hésite pas à le demander ! Bon jeu ! |
Revenir en haut | |
Djezebel Héros Messages: 252 |
Très sympa en effet
Seulement, comme je suis pointilleuse (et embêtante), j'aimerai que ce ne soit pas une cutscene qui se passe (parce que c'est plutot pour un multijoueurs). Donc, j'avais pensé à mettre : - un trigger dans lequel marche le pnj "luline006" avec ce script : - un waypoint nommé "g_mid" (qui sert de centre à l'effet de paralysie) NWScript :
void main() { string sEnter = GetTag(GetEnteringObject()); location lMiddle = GetLocation(GetObjectByTag("g_mid")); object oPC = GetFirstObjectInShape(SHAPE_CUBE, 25.0, lMiddle, FALSE, OBJECT_TYPE_CREATURE); effect eEfx = EffectParalyze(); if (GetIsPC(GetEnteringObject()) == FALSE ) { while(GetIsObjectValid(oPC)) { if(GetIsPC(oPC) == TRUE) { ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eEfx, oPC, 25.0); } oPC = GetNextObjectInShape(SHAPE_CUBE, 35.0, lMiddle, FALSE, OBJECT_TYPE_CREATURE); } } } Le but étant que quand le PNJ passe dessus, tous les joueurs soient bloqués (ceux qui ont tué la créature) Cependant, j'aimerai qu'il soit possible de tuer "l'homme mystérieux" qui arrive. Pour cela, il faut que les joueurs soient organisés : - un groupe accepte de tuer la créature et de se faire paralyser pendant qu'un autre attend en dehors de la pièce. - Une fois que le premier groupe est paralysé, le second peut intervenir pour éventuellement tuer le PNJ. Tu as une idée sur ce qui est possible de faire ? |
Revenir en haut | |
Enki Légende vivante Messages: 432 |
Salut,
En fait il faudrait que chaque PJ qui attaque le monstre reçoive une variable pour dire qu'ils ont participé au combat. Ensuite, il faut appliquer un effet pour ces joueurs, je pense que EffectCutsceneImmobilize ou EffectCutsceneParalyze est mieux que effectParalyze pour deux raison, d'abord parce qu'un joueur peut résister à la paralysie normale, ensuite parce que cela permet de conserver l'animation de spasm des PJs, que je trouve sympa (sinon, ils sont trop statiques, je trouve que cela fait cloche ... ), à toi de voir. Cependant, d'autres problèmes surgissent du coup : - Si les joueurs qui ont tué le monstre sont paralysés et que le PNj "luline006" devient un ennemi, ils vont se faire tailler en charpie. - Et bien sûr, si le PNJ gagne que se passe-t-il ? Il s'en va sans tuer les pjs paralysés ? Il les tue et dans ce cas là, la scène doit-elle recommencer quand d'autres PJs ou les mêmes ressuscités reviennent ? Je pense que je peux trouver une solution, mais d'autres précisions seraient utiles ! Voilà, à plus tard. |
Revenir en haut | |
Djezebel Héros Messages: 252 |
Citation : En fait il faudrait que chaque PJ qui attaque le monstre reçoive une variable pour dire qu'ils ont participé au combat. En fait, le fait que la paralysie s'étende à une zone est très bien dans mon idée
Ainsi, pas besoin de variables : les joueurs qui sont dans la zone du monstre sont paralysés, les autres ne le sont pas. (c'est ainsi que fonctionne le script sur le trigger que j'ai mis juste au dessus non ?) Pour l' EffectCutsceneParalyze , est-ce que ça enlève l'interface du joueur ? Parce que (ça c'est tout à fait subjectif), je préfère quand l'interface est présente. Pour l'animation du PJ c'est une idée intéressante, autant la garder. Citation : Si les joueurs qui ont tué le monstre sont paralysés et que le PNj "luline006" devient un ennemi, ils vont se faire tailler en charpie.
C'est justement là le problème, j'aimerai que s'il est attaqué, il attaque les joueurs qui l'attaquent (à la base ce serait un PNJ "bleu" et non ennemi) et une fois qu'il les a tué (s'il réussi), il délaisse les paralysés et s'occupe d'ouvrir le coffre.
En somme, il n'a pas envie de tuer des PJ, ne tuera que pour se défendre et préfèrera prendre la relique. N'hésites pas à demander d'autres informations si tu as besoin ! Merci encore |
Revenir en haut | |
Enki Légende vivante Messages: 432 |
Bien, je crois que j'ai compris.
Cependant, l'histoire des variables sur le PJ me semble incontournable parce qu'avec ton script, les pj ne seront immobiles "que" durant 25 Sec. et si un pj et un peu trop près (35.0 c'est pas mal) il sera immobilisé sans le vouloir. Imagine que le combat entre le deuxième groupe et "luline006" dure plus longtemps, ou que pendant le combat, "luline006" marche à nouveau sur le trigger, etc... De plus, je crois que c'est plus cohérent du point de vue de l'histoire (même si je ne la connais pas) de voir cette immobilisation comme une sorte de malédiction pour avoir porté la main sur le gardien de la clef, ou de la relique. Sinon, si c'est "luline006" qui a un tel pouvoir, on ne comprend pas pourquoi il avait besoin d'attendre que les pj viennent pour s'emparer de la relique, ni pourquoi il ne s'en sert pas à nouveau contre le deuxième groupe qui l'attaque. Ce qui nous intéresse , c'est que le premier groupe soit immobilisé tant que "luline006" est présent. Enfin, pour ce qui est de faire repartir "luline006" en cas de défaite des PJs, il suffit de modifier un peu l'événement onHeartBeat de l'UserDefined. Allez, dès que c'est fait je mets les scripts en ligne ! |
Revenir en haut | |
Enki Légende vivante Messages: 432 |
Vous, qui passez dans ce forum et voyez ce message, arrêtez-vous un instant !
L'idée que Djezebel a eue est tout simplement géniale, et très sérieusement, je conseille à tous ceux qui s'intéressent aux scrips et aux animations qui donnent de la vie à nos modules de lire attentivement ce message et (les scripts qui l'accompagnent), ou tout simplement d'avoir la curiosité de faire un petit module de démo pour voir comment ça rend. Pour ceux qui auraient la flemme de tout lire depuis le début, je résume la situation : Un groupe d'aventuriers est parti à la recherche d'une relique très rare. Au bout d'une route longue et périlleuse et après de nombreuses embûches ils parviennent enfin à leur but. Mais là, un gardien attend... Un monstre, un géant, une créature qui ferait frémir le plus brave des guerriers, le plus fier des soldats de la garde de Minas Tirith et même les Mélnibonéens les plus versés dans les arts obscurs n'oseraient s'en approcher ! Mais nos héros n'ont pas peur de lui, ils sont nombreux, mais surtout, ils ont un plan. Ils savent pertinemment que l'on ne peut porter la main sur une créature de ce niveau de développement ontologique sans en subir les conséquences. Ils ont prévu de se séparer en deux groupes, un groupe qui tuerait la bête, l'autre qui attendrait patiemment son tour, qui agirait promptement une fois la "sale besogne" accompli, afin de s'emparer de la relique sans être sous le coup de la malédiction. Le combat fait rage, et seul le fracas des armes et les cris de guerre effrénés de leurs compagnons parviennent aux membres du deuxième groupe. Puis, d'un seul coup, le silence. Et juste après, des hurlements de peur et des appels à l'aide. Nos valeureux héros n'en peuvent mais, et décident de s'élancer comme Arutha dans la célèbre bataille qui l'opposa aux Tsuranis, au secours de leurs amis. La scène qui se déroule devant eux semble incompréhensible : ceux de leurs amis qui sont encore vivants sont paralysés et parcourus de spasmes, alors que tranquillement comme surgi de nulle part, un homme mystérieux, un personnage sournois connu seulement par son pseudonyme "luline006", (006, est-ce un espion ?) marche avec nonchalance vers le corps sans vie du gardien, pour y prendre un objet (peut-être la clef du reliquaire ?), et là, que fait-il ? Il remercie avec ironie les courageux aventuriers qui se sont sacrifiés et ont endossé la malédiction à sa place. A ce point du récit, nos héros encore libres de leurs mouvements ne tiennent plus, le mystérieux personnage ne les ayant pas vu, ils décident d'attaquer avec la soudaineté d'un ouragan pour bénéficier au maximum de l'effet de surprise. C'est à vous d'écrire (ou plutôt de "jouer") l'issue de cette bataille... Pour réaliser cette petite scène, tu as besoin : - d'une zone de taille respectable, disons six par six au minimum, plutôt en intérieur. - d'un waypoint TAG : "WP_Spawn" où "luline006" apparaît. - d'un coffre (ou équivalent) qui doit être utilisable, inventaire, et intrigue. + vérouillé, clef requise pour dévérouiller, TAG clef "g_clef". Tu mets la relique à l'intérieur : TAG "g_relique". Tu lui enlèves TOUS les scripts, et sur le Unlock tu places ce script : (Je le remets juste au cas où) 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. Il faut également : - un PNJ sur l'area : le gardien, ( au choix, mais pas trop kitch, s'il vous plait...) il doit avoir la clef (TAG "g_clef") sur lui (abandon possible). Ce PNJ est l'hote de de trois scripts : Le premier sur le OnSpawn est le même que le script par défaut (NW_C2_DEFAULT9) à l'exception de ces lignes dont les commentaires (//) ont été enlevés : NWScript :
// * Fire User Defined Event 1001 in the OnHeartbeat // * SetSpawnInCondition(NW_FLAG_HEARTBEAT_EVENT); SetSpawnInCondition(NW_FLAG_PERCIEVE_EVENT); SetSpawnInCondition(NW_FLAG_ATTACK_EVENT); SetSpawnInCondition(NW_FLAG_DAMAGED_EVENT); SetSpawnInCondition(NW_FLAG_END_COMBAT_ROUND_EVENT); //Fire User Defined Event 1011 in the OnCastSpellAt// SetSpawnInCondition(NW_FLAG_SPELL_CAST_AT_EVENT); Le deuxième se met sur le OnDeath : NWScript :
void DoSpasm() { // Note that OBJECT_SELF is now the assigned object (oNPC) ActionSpeakString(""); ActionWait(1.0); ActionDoCommand(PlayVoiceChat(VOICE_CHAT_HELP)); ActionPlayAnimation(ANIMATION_LOOPING_SPASM,1.0,250.0); SetCommandable(FALSE); } // fonction permettant d'appliquer un delai a la creation d'un objet void DelayCreatObject(int nObjectType, string sTemplate, location lLoc, int bUseAppearAnimation = FALSE, string sNewTag= "") { CreateObject(nObjectType, sTemplate, lLoc, bUseAppearAnimation, sNewTag); } void main() { object oPC=GetLastKiller(); SetIsDestroyable(FALSE, TRUE, TRUE); object oSpawn = GetNearestObjectByTag("WP_Spawn"); location lSpawn = GetLocation(oSpawn); effect eVisufx = EffectVisualEffect(34); effect eEffect=EffectCutsceneImmobilize(); object oArea = GetArea(OBJECT_SELF); object oObject = GetFirstObjectInArea(oArea); DelayCommand(5.5, ApplyEffectAtLocation(0, eVisufx , lSpawn)); DelayCommand(6.0,DelayCreatObject(OBJECT_TYPE_CREATURE, "luline006", lSpawn, FALSE, "Homme etrange")); while(GetIsObjectValid(oObject)) { if(GetLocalInt(oObject,"maudit") == 100) { DelayCommand(2.5,AssignCommand(oObject,DoSpasm())); ApplyEffectToObject(DURATION_TYPE_PERMANENT,eEffect,oPC); } oObject = GetNextObjectInArea(oArea); } } Le troisième sur OnUserDefined : NWScript :
//User Defined///////////////////// void main() { int nUser = GetUserDefinedEventNumber(); if(nUser == 1001) //HEARTBEAT { } else if(nUser == 1002) // PERCEIVE { location lLoc=GetLocation(OBJECT_SELF); object oPC = GetFirstObjectInShape(SHAPE_CUBE, 25.0, lLoc, TRUE, OBJECT_TYPE_CREATURE); while(GetObjectSeen(oPC)) { if(GetIsEnemy(oPC)) { SetLocalInt(oPC,"maudit", 100); } oPC = GetNextObjectInShape(SHAPE_CUBE, 25.0, lLoc, TRUE, OBJECT_TYPE_CREATURE); } } else if(nUser == 1003) // END OF COMBAT { object oPC=GetLastHostileActor(); SetLocalInt(oPC,"maudit", 100); if (GetCurrentHitPoints()<= 50)/// A toi de voir en fonction du nombre de PV de ton PNJ// { SpeakString(""); } } else if(nUser == 1004) // ON DIALOGUE { } else if(nUser == 1005) // ATTACKED { object oPC=GetLastHostileActor(); SetLocalInt(oPC,"maudit", 100); } else if(nUser == 1006) // DAMAGED { object oPC=GetLastHostileActor(); SetLocalInt(oPC,"maudit", 100); } else if(nUser == 1007) // DEATH { } else if(nUser == 1008) // DISTURBED { } else if(nUser == 1011) // SPELL_CAST_AT { object oPC=GetLastHostileActor(); SetLocalInt(oPC,"maudit", 100); } } Voilà pour ce PNJ, quand il meurt, il fait apparaitre l'autre PNJ et "fige" les PNJ qui l'ont combattu. L'autre PNJ a un ResRef "luline006", son tag importe peu. Il faut impérativement lui créer une faction à part, Neutre avec tout le monde, c'est le seul moyen pour qu'il n'attaque pas les PJs (et PNJs s'ils ont des henchmen) qui sont figés. Il faut également lui laisser son corps détroussable plus de 5 secondes. Il n'apparait pas sur l'area mais seulement dans la palette. Il a lui aussi 3 scripts : Le OnSpawn, trés simple : 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. Le oOnDeath : NWScript :
// OnDeath event. object oArea=GetArea(OBJECT_SELF); void RemoveAllEffect(object oPJ,effect eLoop ) { effect eLoop=GetFirstEffect(oPJ); while (GetIsEffectValid(eLoop)) { RemoveEffect(oPJ, eLoop); eLoop=GetNextEffect(oPJ); } } ////////////////////////////// /////////////////////////// void LibereAllPC(object oPJ) { object oPJ = GetFirstObjectInArea(oArea); effect eEffect=EffectCutsceneImmobilize(); while(GetIsObjectValid(oPJ)) { RemoveAllEffect(oPJ,eEffect); SetCommandable(TRUE,oPJ); oPJ = GetNextObjectInArea(oArea); } } void ClearAllPC(object oPJ) { object oPJ = GetFirstObjectInArea(oArea); while(GetIsObjectValid(oPJ)) { if(GetLocalInt(oPJ,"maudit") == 100) { AssignCommand(oPJ,ClearAllActions()); AssignCommand(oPJ,ActionPlayAnimation(ANIMATION_LOOPING_DEAD_FRONT,1.0,2.0)); } oPJ = GetNextObjectInArea(oArea); } } object oNPC=OBJECT_SELF; object oPJ = GetFirstPC(); object oClef = GetObjectByTag("g_clef"); object oRelique = GetObjectByTag("g_relique"); object oMonstre = GetItemPossessor(oClef); object oCoffre = GetItemPossessor(oRelique); #include "x2_inc_compon" void main() { object oKiller = GetLastKiller(); LibereAllPC(oPJ); DelayCommand(3.0,ClearAllPC (oPJ)); craft_drop_items(oKiller); } Et Enfin le gros morceau : Le OnUserDefined : NWScript :
///Script de chaine d'actions par Enki. ///////// /* 1) aller du waypoint au corps + se baisser + prendre la clef + dire merci 2) aller devant le coffre + ouvrir le coffre + prendre l'objet 3) dire "vous etes utiles..." + disparaitre. */ #include "nw_i0_plot" object oArea=GetArea(OBJECT_SELF); void RemoveAllEffect(object oPJ,effect eLoop ) { effect eLoop=GetFirstEffect(oPJ); while (GetIsEffectValid(eLoop)) { RemoveEffect(oPJ, eLoop); eLoop=GetNextEffect(oPJ); } } ////////////////////////////// /////////////////////////// void LibereAllPC(object oPJ) { object oPJ = GetFirstObjectInArea(oArea); effect eEffect=EffectCutsceneImmobilize(); while(GetIsObjectValid(oPJ)) { RemoveAllEffect(oPJ,eEffect); SetCommandable(TRUE,oPJ); oPJ = GetNextObjectInArea(oArea); } } void ClearAllPC(object oPJ) { object oPJ = GetFirstObjectInArea(oArea); while(GetIsObjectValid(oPJ)) { if(GetLocalInt(oPJ,"maudit") == 100) { AssignCommand(oPJ,ClearAllActions()); AssignCommand(oPJ,ActionPlayAnimation(ANIMATION_LOOPING_DEAD_FRONT,1.0,2.0)); } oPJ = GetNextObjectInArea(oArea); } } object oNPC=OBJECT_SELF; object oPJ = GetFirstPC(); object oClef = GetObjectByTag("g_clef"); object oRelique = GetObjectByTag("g_relique"); object oMonstre = GetItemPossessor(oClef); object oCoffre = GetItemPossessor(oRelique); effect eVisufx = EffectVisualEffect(34); ////////////////////////////// /////////////////////////// void Action01 () { ActionMoveToObject(oMonstre, FALSE, 0.0f); ActionPlayAnimation(ANIMATION_LOOPING_GET_LOW,1.0,1.5); ActionTakeItem(oClef, oMonstre); ActionDoCommand(PlayVoiceChat(VOICE_CHAT_THANKS));/*la voiceChat ne marche qu'avec les voix des joueurs*/ // Il va voler la clef } ////////////////////////////// /////////////////////////// void Action02 () { ActionMoveToObject(oCoffre, FALSE, 0.5f); ActionDoCommand(DoPlaceableObjectAction(oCoffre,PLACEABLE_ACTION_UNLOCK)); ActionTakeItem(oRelique, oCoffre); } ////////////////////////////// /////////////////////////// void Action03 () { ActionPlayAnimation(ANIMATION_LOOPING_TALK_LAUGHING,1.0,1.0); ActionDoCommand(PlayVoiceChat(VOICE_CHAT_LAUGH)); ActionSpeakString(""); DelayCommand(2.5, LibereAllPC(oPJ)); } ////////////////////////////// /////////////////////////// void main() { int nUser = GetUserDefinedEventNumber(); object oNPC=OBJECT_SELF; object oPJ = GetFirstPC(); object oClef = GetObjectByTag("g_clef"); object oRelique = GetObjectByTag("g_relique"); object oMonstre = GetItemPossessor(oClef); object oCoffre = GetItemPossessor(oRelique); if(nUser == 1001) //HEARTBEAT { if (!GetIsInCombat()) { if (HasItem(oNPC,GetTag(oRelique))) { Action03(); DelayCommand(2.5,ClearAllPC (oPJ)); DelayCommand(2.5, ApplyEffectToObject(0, eVisufx , OBJECT_SELF,1.0f)); DelayCommand(2.9, DestroyObject(OBJECT_SELF)); } else if (HasItem(oNPC,GetTag(oClef))) { Action02(); } else { Action01(); } } } } Celui-ci est assez compliqué (pour moi en tout cas). On pré programme des chaînes d'actions en début de script, sous forme de nouvelles fonctions. Ces chaînes se déclenchent en fonction de l'action que doit faire le PNJ, dans l'event OnHeartBeat. En fait, toutes les six secondes (durée d'un round) le programme teste le PNJ pour voir où il en est dans ses actions afin de l'empêcher de s'arrêter. Si une action est interrompu,(par un obstacle, un dialogue, un combat ...) une fois l'interruption fini, le PNJ reprend ses actions là où il en était, il ne s'arrête pas bêtement pour se demander quoi faire ! Voilà, je crois que c'est à peu près tout. Ces scripts fonctionnent bien, du moins durant mes nombreux tests je n'ai rien vu d'anormal. Si un joueur du groupe 1, durant la demi-seconde qu'il a de libre avant d'être paralysé s'empare de la clef, "006" va la lui reprendre sans problème. Si un joueur du groupe 2 s'en empare avant lui et décide de s'enfuir avec, "006" le suivra partout dans le module. Les autres joueurs resteront alors figés (on peut toutefois y remédier) tant que le couard ne sera pas mort ou que "luline006" ne le soit. Enfin, La variable "maudit" à "100" que les PNJs ont sur eux reste sur eux. Cela n'a aucune incidence sauf si tu le souhaites, auquels cas tu peux la rappeler dans un dialogue ou bien t'en servir ultérieurement pour un autre effet inatendu de la "malédiction". C'est terminé, à bientôt. P.S. : Pardon par avance Djezebel, si tu trouves que je suis allé un peu trop loin, mais ayant du mal à trouver la sommeil, j'ai décidé de terminer la scène que tu voulais réaliser, et en conséquence, à 8h00 du matin, j'estime que l'on a le droit de se lâcher un petit peu. |
Revenir en haut | |
Djezebel Héros Messages: 252 |
Enki : Alors non, je ne te pardonne pas ! Je te félicite C'est très sympa d'avoir bossé sur ce script jusqu'à une heure si tardive
L'effet est tout simplement excellent ! Ca fonctionne, il y a juste deux tous petits problèmes qui seront faciles à régler je pense. - Le premier : le PNJ radote (comme à chaque fois il refait la boucle, il dit plusieurs fois "merci" et plusieurs fois ses phrases. Peut-etre faudrait-il alors les inclure entre chaque Action0x() ? Ou bien faire une boucle afin de vérifier si la phrase n'a pas été déjà dite ? (mais ça serait peut-être un peu lourd) - Le second problème : Le gardien défait reste au sol ad vitam mortem eternam. Quelle est la case magique à cocher, le script magique à mettre pour qu'il s'en aille une fois que les joueurs ont constatés qu'il n'y avait plus rien sur le corps ? Merci encore Enki, c'est très sympa tout ce que tu as fais et ton repos est bien mérité ! Je suis très contente d'avoir provoqué cet enthousiasme Et à vous, chers lecteurs, merci d'avoir été aussi fidèles dans les aventures de luline006 (*ne fera plus jamais d'editer/copier sur des PNJ*) et la g_relique ! |
Revenir en haut | |
Enki Légende vivante Messages: 432 |
Bonjour Djezebel,
Les deux bugs signalés plus hauts sont corrigés. Pour que le corps du gardien disparaisse, il suffit de décocher toutes les cases dans propriétés > Avancées > Interfaces et de remplacer le script OnDeath par celui-ci : NWScript :
void DoSpasm() { // Note that OBJECT_SELF is now the assigned object (oNPC) ActionSpeakString(""); ActionWait(1.0); ActionDoCommand(PlayVoiceChat(VOICE_CHAT_HELP)); ActionPlayAnimation(ANIMATION_LOOPING_SPASM,1.0,250.0); SetCommandable(FALSE); } // fonction permettant d'appliquer un delai a la creation d'un objet void DelayCreatObject(int nObjectType, string sTemplate, location lLoc, int bUseAppearAnimation = FALSE, string sNewTag= "") { CreateObject(nObjectType, sTemplate, lLoc, bUseAppearAnimation, sNewTag); } #include "x2_inc_compon" void main() { object oPC=GetLastKiller(); SetIsDestroyable(FALSE, TRUE, TRUE); object oSpawn = GetNearestObjectByTag("WP_Spawn"); location lSpawn = GetLocation(oSpawn); effect eVisufx = EffectVisualEffect(34); effect eEffect=EffectCutsceneImmobilize(); object oArea = GetArea(OBJECT_SELF); object oObject = GetFirstObjectInArea(oArea); DelayCommand(5.5, ApplyEffectAtLocation(0, eVisufx , lSpawn)); DelayCommand(6.0,DelayCreatObject(OBJECT_TYPE_CREATURE, "luline006", lSpawn, FALSE, "Homme etrange")); DelayCommand(10.0,SetIsDestroyable(TRUE, FALSE, FALSE)); craft_drop_items(oPC); while(GetIsObjectValid(oObject)) { if(GetLocalInt(oObject,"maudit") == 100) { DelayCommand(2.5,AssignCommand(oObject,DoSpasm())); ApplyEffectToObject(DURATION_TYPE_PERMANENT,eEffect,oPC); } oObject = GetNextObjectInArea(oArea); } } Pour le bégaiement, remplace le script OnUserDefined de "luline006" par le suivant : NWScript :
///Script de chaine d'actions par Enki. ///////// /* 1) aller du waypoint au corps + se baisser + prendre la clef + dire merci 2) aller devant le coffre + ouvrir le coffre + prendre l'objet 3) dire "vous etes utiles..." + disparaitre. */ #include "nw_i0_plot" object oArea=GetArea(OBJECT_SELF); void RemoveAllEffect(object oPJ,effect eLoop ) { effect eLoop=GetFirstEffect(oPJ); while (GetIsEffectValid(eLoop)) { RemoveEffect(oPJ, eLoop); eLoop=GetNextEffect(oPJ); } } ////////////////////////////// /////////////////////////// void LibereAllPC(object oPJ) { object oPJ = GetFirstObjectInArea(oArea); effect eEffect=EffectCutsceneImmobilize(); while(GetIsObjectValid(oPJ)) { RemoveAllEffect(oPJ,eEffect); SetCommandable(TRUE,oPJ); oPJ = GetNextObjectInArea(oArea); } } void ClearAllPC(object oPJ) { object oPJ = GetFirstObjectInArea(oArea); while(GetIsObjectValid(oPJ)) { if(GetLocalInt(oPJ,"maudit") == 100) { AssignCommand(oPJ,ClearAllActions()); AssignCommand(oPJ,ActionPlayAnimation(ANIMATION_LOOPING_DEAD_FRONT,1.0,2.0)); } oPJ = GetNextObjectInArea(oArea); } } object oNPC=OBJECT_SELF; object oPJ = GetFirstPC(); object oClef = GetObjectByTag("g_clef"); object oRelique = GetObjectByTag("g_relique"); object oMonstre = GetItemPossessor(oClef); object oCoffre = GetItemPossessor(oRelique); effect eVisufx = EffectVisualEffect(34); ////////////////////////////// /////////////////////////// void Action01 () { ActionMoveToObject(oMonstre, FALSE, 0.0f); ActionPlayAnimation(ANIMATION_LOOPING_GET_LOW,1.0,1.5); ActionTakeItem(oClef, oMonstre); // Il va voler la clef //ActionSpeakString("Merc i..."); } ////////////////////////////// /////////////////////////// void Action02 () { ActionMoveToObject(oCoffre, FALSE, 0.5f); ActionDoCommand(DoPlaceableObjectAction(oCoffre,PLACEABLE_ACTION_UNLOCK)); ActionTakeItem(oRelique, oCoffre); } ////////////////////////////// /////////////////////////// void Action03 () { ActionPlayAnimation(ANIMATION_LOOPING_TALK_LAUGHING,1.0,1.0); ActionDoCommand(PlayVoiceChat(VOICE_CHAT_LAUGH)); ActionSpeakString(""); DelayCommand(2.5, LibereAllPC(oPJ)); } ////////////////////////////// /////////////////////////// void main() { int nUser = GetUserDefinedEventNumber(); object oNPC=OBJECT_SELF; object oPJ = GetFirstPC(); object oClef = GetObjectByTag("g_clef"); object oRelique = GetObjectByTag("g_relique"); object oMonstre = GetItemPossessor(oClef); object oCoffre = GetItemPossessor(oRelique); object oGardien=GetObjectByTag("gardien"); if(nUser == 1001) //HEARTBEAT { if (!GetIsInCombat()) { if (HasItem(oNPC,GetTag(oRelique))) { Action03(); DelayCommand(2.5,ClearAllPC (oPJ)); DelayCommand(2.5, ApplyEffectToObject(0, eVisufx , OBJECT_SELF,1.0f)); DelayCommand(2.9, DestroyObject(OBJECT_SELF)); } else if (HasItem(oNPC,GetTag(oClef))) { Action02(); } else { Action01(); if (GetLocalInt(OBJECT_SELF,"NW_DO_ONCE") != 0) { return; } ActionDoCommand(PlayVoiceChat(VOICE_CHAT_THANKS)); SetLocalInt(OBJECT_SELF,"NW_DO_ONCE",1); } } } } Voilà, je pense que cette fois-ci, vraiment, tout y est ! |
Revenir en haut | |
Djezebel Héros Messages: 252 |
Rebonjour !
NWScript :
void Action01 () { ActionMoveToObject(oMonstre, FALSE, 0.0f); ActionPlayAnimation(ANIMATION_LOOPING_GET_LOW,1.0,1.5); ActionTakeItem(oClef, oMonstre); // Il va voler la clef //ActionSpeakString("Merc i..."); } A la base, luline006 allait vers le possesseur de la clef et non vers le cadavre car il y avait un bref instant où le joueur pouvait encore looter l'objet. (C'est pourquoi j'avais besoin de l'objet invisible pour faire apparaitre luline006 ) Pour ce qui est de //ActionSpeakString("Merc i..."); Si j'enlève les // Il se remet à bégayer cette phrase (que j'ai d'ailleurs changée en "Domage... Un si grand combat pour une fin si misérable") Mais bon, je ne vais pas chipotter, j'aurai qu'à trouver un autre endroit où mettre cette phrase ou carrément l'enlever En tout cas merci beaucoup de ta précieuse aide |
Revenir en haut | |
Enki Légende vivante Messages: 432 |
En fait, tu dois mettre des commentaires à la ligne 131 du script UserDefined de "luline006"
comme cela : NWScript :
// ActionDoCommand(PlayVoiceChat( VOICE_CHAT_THANKS)); tu dois couper la ligne 67 NWScript :
ActionSpeakString("Merci... (ou ce que tu veux...) "); et la mettre juste en dessous de la ligne 131. Comme cela, le PNJ ne la dit qu'une seule fois. C'est tout simple ! |
Revenir en haut | |
La Bibliothèque de Neverwinter Nights Index du Forum »
La Bibliothèque Binaire du NWScript - Neverwinter Nights
Page 1 sur 1 ¤
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