Suite à mes petites digressions dans le sujet de Kebra ici, j'ouvre un nouveau sujet afin de ne pas polluer le sien. Plusieurs problèmes m'amènent.
Le premier concerne l'animation en elle-même. J'ai la possibilité d'utilisé 2 animations de Qarl. L'une intègre uniquement le sommeil en idle 8 alors que l'autre intègre plusieurs animations (danse entre autre) dont le sommeil en idle 8 également (Seul le sommeil m'intéresse et je peux me passer du reste). Le problème concerne (pour les deux animations) un sursaut qui se produit à la fin de l'animation où le npc repasse subitement en position debout, ce qui est du plus mauvais effet.
Le second problème concerne le comportement des npcs si on les dérange lors du sommeil. En effet ils combattent mais se mettent rapidement à alterner avec leur position couché.
Voici le script. Je précise que ces npcs ne sont "enable" que pendant la nuit grâce à un script global qui gère aussi leur alter-ego du jour.
begin A_P_va_dodoter_ville
short dormeur
short alea
if ( MenuMode == 1 )
return
endif
if ( getdisabled == 1 )
return
endif
if ( OnActivate == 1 )
if ( GetHealth > 0 )
set alea to random 4
if ( alea == 0 )
MessageBox, "Cette personne semble dormir profondément."
Playsound3D "A_P_ronfle01"
elseif ( alea == 1 )
MessageBox, "Cette personne sommeille."
Playsound3D "A_P_ronfle02"
elseif ( alea == 2 )
MessageBox, "Le sommeil de cette personne semble paisible."
Playsound3D "A_P_ronfle01"
elseif ( alea == 3 )
MessageBox, "On dirait que cette personne dort calmement."
else
MessageBox, "Il semble que la personne dort tranquilement."
endif
else
activate
endif
endif
if ( getdisabled == 0 )
if ( CellChanged == 0 )
if ( GetSoundPlaying "A_P_dormeur01" == 0 )
PlayLoopSound3DVP "A_P_dormeur01" 1.0, 1.0
endif
endif
endif
end
Pour que les npcs appliquent l'animation, j'ai modifié leur feuille de stat en mettant AIWander à 0 dans tous les autres idles et en mettant 100 pour le 8.
Je ne sais pas s'il existe une fonction équivalente à ResetActor qu'on peut utiliser dans la console pour replacer un npc dans son lit si le joueur l'a attaqué
puis a payé l'amende...
Palme d'honneur 2010 pour le mod Archipel de Pertevue
Je ne sais pas s'il existe une fonction équivalente à ResetActor qu'on peut utiliser dans la console pour replacer un npc dans son lit si le joueur l'a attaqué
puis a payé l'amende...
RA peut très bien s'utiliser dans un script mais j'espère que ton dormeur fait chambre à part car la commande est globale (renverra tous les acteurs présents à la case départ)
Pour le reste la commande GetTarget player devrait t'aider. En effet cette commande, pour un PNJ, renvoie 1 en deux circonstances :
- Lorsque l'acteur est engagé en combat contre le PJ.
- Lorsque l'acteur a remarqué la présence du PJ. Pour ce point, dans la pratique, c'est lorsqu'il lui balance une tirade vocale hello et pour une durée de quelques secondes. Ce qui implique que GetLOS et GetDetected renvoient toute deux uns aussi et que le PJ est à une distance fixée par son paramètre AIHello (inutile de tester ça dans le script, c'est de l'implicit hardcodé )
Avec ça je pense que tu peux faire un script qui détecte le changement de résultat pour GetTarget player pour modifier à la volée le package AIWander (un "de sommeil" comme tu l'as défini dans la fiche et un "autre" sans l'idle 8 pour la situation "PNJ réveillé par les activités du PJ").
Ça devrait même donner un résultat plus naturel et RP que ton système à base de onactivate (si le PJ est suffisamment discret il ne réveille pas le PNJ, peut même lui faire les poches...)
Pour le problème spécifique à l'animation de sommeil, je ne sais pas
Voici le script d'un NPC provenant du mod Animated Morrowind, au cas où...
Il gère le combat (ici, enlever la "fausse" canne à pêche etc...), ainsi que la remise en position après le combat.
il est possible de remplacer les variables des setpos par des valeurs précalculées, afin que cela soit indépendant de tribunal.
;ANIMATED MORROWIND NPC SCRIPT
;GENERAL PART
short DoOnce
short Reposition
short Rand
float NpcX
float NpcY
float NpcZ
float NpcZrot
short positionOnce
if PositionOnce == 0
set NpcX to GetPos X
set NpcY to GetPos Y
set NpcZ to GetPos Z
set NpcZrot to GetAngle Z
set PositionOnce to 1
endif
if Reposition == 0
if GetTarget Player == 1
set Reposition to 1
RemoveItem AM_FishingPole 1
endif
endif
if Reposition == 1
if CellChanged == 1
if GetDetected Player
set Reposition to 0
AddItem AM_FishingPole 1
; RA ; Reset Actors
setPos X NpcX
setPos Y NpcY
setPos Z NpcZ
setAngle Z NpcZrot
endif
endif
endif
;DISABLES THE NPCS DURING THE NIGHT
if DoONce == 0
if GameHour < 9
set DoONce to 1
Disable
endif
if GamehOur > 20
set DoONce to 1
Disable
endif
endif
;ENALBES THE NPCS DURING THE DAY with a chance of 40%
if DoOnce == 1
if GameHour > = 9
if GameHour <= 20
set DoOnce to 0
set Rand to Random 10
if Rand > 5
if GetHealth > 0
Enable
endif
endif
endif
endif
endif
; SPECIFIC PART FOR THIS NPC: FISHERMAN
if GetDisabled == 0
if Reposition == 0
if ( GetSoundPlaying "AM_FishManSound" == 0 )
PlaySound3D "AM_FishManSound", 1.0, 1.0
endif
endif
endif
if DoOnce < 10
if GetHealth <= 0
RemoveItem AM_FishingPole 1
set DoOnce to 10
endif
endif
end
Sinon, pour le problème d'animation, Animated Morrowind utilise la même méthode que toi sans soucis. Je pencherait donc pour un problème de timing dans le .nif. :/
Comme je te le demandais dans le sujet de Kebra, as-tu essayé de changer son AI Wander en cas d'attaque?...
Les pnj de Morrowind ont souvent cette tendance à effectuer un idle entre deux mouvements de combat, et si tu lui as dit que son idle de sommeil est à 100%, c'est celui-là qu'il va exécuter...
Tout n'est qu'illusion... Surtout le fait de le penser.....
(Wiwi d'or de la plus serviable et de la plus cool... Merci à vous tous...)
Merci pour vos propositions, je vais tacher d'étudier tout ça.
Je précise que ce script est générique : il doit pouvoir s'appliquer à tous les npcs qui l'ont. Ça exclue donc des coordonnées individualisées. Mais je pense que ça ne sera pas nécessaire.
Citation
Ça devrait même donner un résultat plus naturel et RP que ton système à base de onactivate (si le PJ est suffisamment discret il ne réveille pas le PNJ, peut même lui faire les poches...)
En fait, le onactivate sert à empêcher qu'on parle au npc. Et c'est indispensable car ce ne sont pas les mêmes ID que leur alter ego (donc pas les mêmes topics, la même disposition...).
Palme d'honneur 2010 pour le mod Archipel de Pertevue
Probablement l'une des plus belle série d'animations que j'ai testé. Elle comporte plusieurs attitudes de dormeurs dont l'une a l'air trés bien (sais plus laquelle, en fin de liste, les bras ne tournicottent pas dans tout les sens comme chez Qarl). J'y ai aussi ajouté des postures allongés mais qui peuvent aussi bien animer le sommeil que la mort(!), l'avantage est que le PNJ ne se relève pas, si tu utilise d'autres IA pour la journée, ce sera peut-etre utile.
Si tu as besoin d'autres anims, je te les ferai parvenir, il y a surtout (chez axr31) de la danse et du combat mais remarquablement bien fait.
Merci Kebra. Je vais aussi prendre le temps de regarder ça. Si l'anim est meilleure que celles que j'utilise, pourrais-tu mettre un lien vers un site où figurent les coordonnées de axr31. Merci.
Palme d'honneur 2010 pour le mod Archipel de Pertevue
Je n'ai pas eu le temps de me pencher sur les animations en tant que telles. Par contre, j'ai travaillé le script :
if ( GetTarget Player == 1 )
if ( fait == 0 )
aiwander, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
setfight 100
set fait to 1
return
endif
endif
Rajouter ce code permet bien d'empêcher le npc de se repositionner dans la mauvaise idle, a priori.
Maintenant, j'ai un autre problème qui tient à la construction des scripts... Je vais détailler l'articulation des scripts globaux et locaux.
Le script global gère l'apparition et la disparition des npcs en fonction des heures. Chaque npc est en double : un réveillé et un dormeur. Le script global détecte si un des deux alter égo est mort (dans ce cas, on ne disable pas la version morte et on ne fait pas apparaitre le double vivant).
Le script local gère donc maintenant le changement d'animation en cas de combat. Il gère le son et l'impossibilité de faire activate quand le dormeur dort.
Le problème c'est que si le joueur attaque un npc (le dormeur par exemple) et que les heures passent, il y a le changement d'alter-ego. Et le joueur se trouve alors avec un npc (le réveillé dans cet exemple) qui ne l'attaque plus. Si le temps passe à nouveau (12h), le joueur se retrouve de nouveau face au npc (normalement dormeur mais pour le coup toujours réveillé) qui l'attaque.. Je ne sais pas si je suis bien clair.
Il faudrait donc que je trouve un moyen d'empêcher que le script global face son job si un des alter-ego a été attaqué. Comment détecter ça au mieux sans que ça nécessite un traitement individualisé de chaque script de npc ? (L'idée c'est de garder un script général sur les npcs.)
Je vous mets le script global (enfin un des scripts globaux car il y a en a plusieurs comme ça, sinon c'était trop long pour le moteur).
Spoiler
begin A_P_z_npc_ariddan
short nuit
if ( menumode == 1 )
return
endif
if ( getinterior == 0 )
return
endif
if ( getpccell "Ariddan" == 0 )
return
endif
; ############# verification des meurtres de la nuit ############
if ( gamehour > 8 )
if ( gamehour <= 20 )
; -------------------------------------- Ariddan, cabane d'Altrena Veralek -------------------------------
if ( getdeadcount "A_P_ereora_paltsaell02" > 0 )
A_P_ereora_paltsaell->disable
A_P_ereora_paltsaell02->enable
else
A_P_ereora_paltsaell02->disable
A_P_ereora_paltsaell->enable
endif
; -------------------------------------- Ariddan, cabane de Lareleo Kaylsaré -------------------------------
if ( getdeadcount "A_P_QP01_Lareleo_Kayl02" > 0 )
A_P_QP01_Lareleo_Kayl->disable
A_P_QP01_Lareleo_Kayl02->enable
else
A_P_QP01_Lareleo_Kayl02->disable
A_P_QP01_Lareleo_Kayl->enable
endif
; -------------------------------------- Ariddan, cabane d'Altrena Veralek -------------------------------
if ( getdeadcount "A_P_altrena_veralek02" > 0 )
A_P_altrena_veralek->disable
A_P_altrena_veralek02->enable
else
A_P_altrena_veralek02->disable
A_P_altrena_veralek->enable
endif
; -------------------------------------- Ariddan, cabane de Bakrel Avertalek -------------------------------
if ( getdeadcount "A_P_bakrel_avertalek02" > 0 )
A_P_bakrel_avertalek->disable
A_P_bakrel_avertalek02->enable
else
A_P_bakrel_avertalek02->disable
A_P_bakrel_avertalek->enable
endif
; -------------------------------------- Ariddan, cabane de Jélia Olmkré -------------------------------
if ( getdeadcount "A_P_jelia_olmkre02" > 0 )
A_P_jelia_olmkre->disable
A_P_jelia_olmkre02->enable
else
A_P_jelia_olmkre02->disable
A_P_jelia_olmkre->enable
endif
; -------------------------------------- Ariddan, cabane de Rourrickel Archèldarn -------------------------------
if ( getdeadcount "A_P_cprim_ro_archeldar2" > 0 )
A_P_cprim_ro_archeldarn->disable
A_P_cprim_ro_archeldar2->enable
else
A_P_cprim_ro_archeldar2->disable
A_P_cprim_ro_archeldarn->enable
endif
set nuit to 0
return
endif
endif
; ############# verification des meurtres du jour ############
if ( gamehour < 8 )
set nuit to 1
endif
if ( gamehour > 20 )
set nuit to 1
endif
if ( nuit == 0 )
return
endif
; -------------------------------------- Ariddan, cabane d'Eréora Paltsaéll -------------------------------
if ( getdeadcount "A_P_ereora_paltsaell" > 0 )
A_P_ereora_paltsaell02->disable
A_P_ereora_paltsaell->enable
else
A_P_ereora_paltsaell->disable
A_P_ereora_paltsaell02->enable
endif
; -------------------------------------- Ariddan, cabane de Lareleo Kaylsaré -------------------------------
if ( getdeadcount "A_P_QP01_Lareleo_Kayl" > 0 )
A_P_QP01_Lareleo_Kayl02->disable
A_P_QP01_Lareleo_Kayl->enable
else
A_P_QP01_Lareleo_Kayl->disable
A_P_QP01_Lareleo_Kayl02->enable
endif
; -------------------------------------- Ariddan, cabane d'Altrena Veralek -------------------------------
if ( getdeadcount "A_P_altrena_veralek" > 0 )
A_P_altrena_veralek02->disable
A_P_altrena_veralek->enable
else
A_P_altrena_veralek->disable
A_P_altrena_veralek02->enable
endif
; -------------------------------------- Ariddan, cabane de Bakrel Avertalek -------------------------------
if ( getdeadcount "A_P_bakrel_avertalek" > 0 )
A_P_bakrel_avertalek02->disable
A_P_bakrel_avertalek->enable
else
A_P_bakrel_avertalek->disable
A_P_bakrel_avertalek02->enable
endif
; -------------------------------------- Ariddan, cabane de Jélia Olmkré -------------------------------
if ( getdeadcount "A_P_jelia_olmkre" > 0 )
A_P_jelia_olmkre02->disable
A_P_jelia_olmkre->enable
else
A_P_jelia_olmkre->disable
A_P_jelia_olmkre02->enable
endif
; -------------------------------------- Ariddan, cabane de Rourrickel Archèldarn -------------------------------
if ( getdeadcount "A_P_cprim_ro_archeldarn" > 0 )
A_P_cprim_ro_archeldar2->disable
A_P_cprim_ro_archeldarn->enable
else
A_P_cprim_ro_archeldarn->disable
A_P_cprim_ro_archeldar2->enable
endif
end
Merci beaucoup pour les courageux qui auront le temps et l'énergie de se plonger dans mon problème !
Palme d'honneur 2010 pour le mod Archipel de Pertevue
Si j'avais utilisé Tribunal, j'aurai attribué une variable locale "attaque" (mise à 1 en cas d'attaque de la part du joueur) que j'aurai lue à partir du script global pour connaitre l'état du npc.
Mais comme l'Archipel de Pertevue est Morrowind seul, j'ai rusé.
En fait, quand le npc version dormeur est attaqué, je lui donne un sort bateau qui agit exactement comme la variable local : avec un getspell, je peux détecter dans le script global le fait que le npc ait été attaqué tout en gardant un script générique sur chaque npc dormeur. Le tour est joué !
Le comportement des npcs dormeurs / réveillés est nettement optimiser maintenant ! Merci pour votre aide.
Palme d'honneur 2010 pour le mod Archipel de Pertevue