En fait, une quête peut être démarrée dès le début de manière invisible pour placer le script ou être démarré par le biais de menus ajoutés, de sorts....
C'est pas un soucis.
Tu n'auras jamais un esp à partir d'un script. Il faut ouvrir le CK et créer les objets (quêtes, referencealias...) nécessaires et y placer les scripts.
Le script ci-dessus ne sert qu'à faire tourner le joueur vers l'ennemi le plus proche en appuyant sur une touche.
Il te faut maintenant déterminer qui est l'actor le plus proche.
Le seul truc important, c'est l'alias ClosestActor qui selon moi doit être placé dans une autre quête.
tu obtien :
- une quête avec ton script (placé dans l'onglet script de la quête (le type de script est précisé après extends de la première ligne).
- un quête avec 2 alias : - le joueur (n'importe quel nom d'alias, mais ne pas cocher "allow reuse inq quest.
- closest actor qui sera de type find matching reference avec les 2 cases find in loadede area et closest et un isactor == 1 dans les conditions.
- une quête avec un stage dans le fragment duquel tu mets un registerfosingle update(1)
et un script du genre
Quest property maquetedesalias auto ; tu remplis la propriété avec le nom de la quête des alias.
event onupdate()
maquetedesalias.stop()
utility.wait(0.1)
maquetedesalias.start()
registerforsingleupdate(2)
enevent
Quand tu créé une quête, toujours refermer et ouvrir la fenêtre avant de créer les alias. Après avoir créé l'alias et avant d'y ajouter un script. Fermer puis réouvrir toutes les fenêtres.
Dans le CK, tu double-cliques sur tes script et tu remplis les properties. Par exemple closestactor du script de Sagi doit pointer vers l'alias que tu aura créé dans une autre quête.
Le bout de script ci-dessus est loin d'être suffisant. Il faudrait ajouter une condition sur variable globale pour pouvoir stopper les registerforsingleupdate (pour la désinstallation du mod...) C'est fonctionnel pour un essai mais ne le fais pas sur ta save principale. On verra le reste plus tard.
EDIT :
En fait il doit être possible de tout faire tenir en un script. Il faut juste jongler un peu avec les probabilités et faire un compromis entre efficacité et temps de latence de la commande. J'ai déjà utilisé une routine de ce type dans plusieurs mods et ça fonctionne.
Il permettra de verrouiller la cible la plus proche de l'axe du joueur et non la plus proche. Ce qui collera plus à ta demande.
En gros un appui sur la touche verrouillera la cible, un autre appui deverrouillera.
Je ferai le script et l'esp ce weekend en me basant sur celui de Sagi.
La partie appui touche et calage du regard du joueur sera celle de Sagi.
Je t'enverrai un esp de test ce weekend. Vu qu'il n'y aura qu'un seul script, ça devrait aller vite.
Il y aura un fichier texte expliquant le tout et surtout comment attacher le script dans l'esp pour qu'il fonctionne en jeu. Prend le comme un exemple pédagogique. Cela te permettra de faire plein d'autres mods en t'inspirant du modèle.
En fait, je vais tester ça dans quelques minutes :
Scriptname SG_targetlockingscript extends Quest
;c'est le script du mod auto...pas encore au point. On va plutôt revenir sur l'idée de Sagi : une visée quand on appuie sur la touche. Et garder ça en réserve...
;Le lien qui peut mener au mapping des touches
;http://fose.silverlock.org/fose_command_doc.html#DirectX_Scancodes"]http://fose.silverlo...rectX_Scancodes
import debug
Import Input
import math
Actor Property PlayerREF Auto
faction property currentfollowerfaction auto
globalvariable property SG_MODON auto ;cela permettra de désactiver le mod avant désinstallation
actor closest = None ; c'est la variable où je stocke l'acteur le plus proche de l'axe. Remplacé à chaque fois que je trouve plus proche.
ReferenceAlias Property ClosestActor Auto
Int Property KeyPressed = 0 Auto
function detect()
float zoffset ; servira pour les calculs dans la fonction, ne pas confondre avec la variable des event. Elle est connue que par la fonction.
float zoffsetmin = 90 ; stockera la valeur la plus petite, plus la valeur est élevée, plus le champ de recherche est grand. C'est donc un réglage à faire.
int t = 0 ; la variable qui me servira à compter le nombre d'itérations
while (t <= 7) ; le nombre d'itérations ou l'art du compromis entre rapidité et efficacité. C'est ça le truc en fait.
Actor randomActor = Game.FindRandomActorFromRef(playerref, 5000.0) ;la commande demandant l'actor le plus proche retourne toujours le joueur alors je tape au hasard pendant mes itérations. Autre astuce.
if (!((randomActor == playerref) || (randomActor.GetFactionRank(CurrentFollowerFaction) >= 0))) && !randomactor.isdead() && randomActor != None && playerref.hasLOS(randomactor) && randomactor.IsHostileToActor(playerref) ; je ne fais les calculs et la prise en compte que si ce n'est pas le joueur, un compagnon et qu'un actor a été trouvé.
zOffset = playerref.GetHeadingAngle(randomactor) ; je demande l'écart par rapport à l'axe du joueur.
if abs(zoffset) < abs(zoffsetmin) ;si l'actor trouvé est plus dans l'axe que le précédent, l'écart ainsi que son nom sont stockés...
zoffsetmin = zoffset
closest = randomactor ;la variable closest est commune à toutes les instances du script car déclarée au début du script
endif
endif
t = t +1 ;important sinon la fonction tourne en boucle.
endwhile
if closest == none
notification("Aucune cible trouvée")
else
notification("Cible verrouillée.")
endif
endfunction
Event OnInit()
RegisterForSingleUpdate(0.1) ;à l'initialisation du script, on se prépare à appeler une fois l'event onupdate()
EndEvent
auto state attente ; le joueur n'a pas de cible vérouillée
Event OnUpdate()
if IsKeyPressed(45) && KeyPressed == 0
KeyPressed = 1
detect()
if closest != none
gotostate("tracking")
float zOffset = PlayerREF.GetHeadingAngle(closest)
PlayerREF.SetAngle(PlayerREF.GetAngleX(), PlayerREF.GetAngleY(), PlayerREF.GetAngleZ() + zOffset)
notification("En mode poursuite auto")
else
notification("aucune cible trouvée")
endif
elseif IsKeyPressed(45) == 0
KeyPressed = 0
endif
if SG_MODON.getvalueint() == 1
RegisterForSingleUpdate(0.1)
endif
EndEvent
endstate
state tracking
event onupdate()
PlayerREF.SetAngle(PlayerREF.GetAngleX(), PlayerREF.GetAngleY(), PlayerREF.GetAngleZ() + PlayerREF.GetHeadingAngle(closest))
if closest.isdead()
notification("Cible décédé : poursuite interrompue")
gotostate("attente")
;elseif !playerref.hasLOS(closest)
; notification("Vous ne voyez plus la cible : poursuite interrompue")
; gotostate("attente")
endif
if IsKeyPressed(45) && KeyPressed == 0
gotostate("attente")
notification("poursuite interrompue par le joueur")
KeyPressed = 1
elseif IsKeyPressed(45) == 0
KeyPressed = 0
endif
if SG_MODON.getvalueint() == 1
RegisterForSingleUpdate(0.1)
endif
endevent
endstate
Le script fonctionne en jeu mais il est loin d'être parfait. Je vais revenir à une valeur de 0.1 comme Sagi avait mis pour diminuer les saccades en poursuite. Tester aussi deux choses supplémentaires : si le joueur voit l'acteur verrouillé et si l'acteur est vivant.
Sinon, un appui sur X, la cible est verrouillée et le regard sui cette cible. Un deuxième appui sur X, fin du verrouillage.
Je peux aussi faire une version sans le suivi automatique...(on ne recale que lors de l'appui sur unee touche) si tu veux. En gros, il suffit de mélanger le script de Sagi et celui que j'ai modifié.
Le mieux serait de faire un menu in-game permettant de choisir entre les options (poursuite auto ou non, distance max de recherche, angle de recherche autour de l'axe de regard du joueur, choix entre certaines touches (Il est possible de faire un choix entre plusieurs configurations pré-définies afin de satisfaire ceux qui ont des soucis du bras gauche ou du bras droit (comme ma pomme...)).
Cela ne prendrait pas longtemps à faire et serait un vrai plus favorisant encore l'accessibilité du jeu.
Comme tu le vois, chaque ligne ou presque ajoutée est expliquée.
EDIT : je mettrai le script ci-dessus à jour au fur et à mesure des essais en jeu.
EDIT2 : La poursuite auto n'est pas terrible (ça saccade un peu) et est un peu haute pour l'utiliser pour l'arc.
Demain, sortira une deuxième version du script reprenant le fonctionnement que Sagi avait en tête.
Un appui sur X te mettra face à l'ennemi, visible, vivant, le plus proche de l'axe ou tu regardes (ou du moins un des plus proches (compromis rapidité/efficacité à trouver).
La version auto sera conservée mais en option car pas pratique du tout avec mes réglages (avec un taux de rafraichissement réglable par le menu, il serait possible d'adapter le mod aux besoins de tout le monde...).
Je t'envoie tout ça rapidement par MP comme ça tu pourras le modifier en fonction de tes besoins.
Le script où la vue se recale que quand on appuie sur la touche :
Scriptname SG_targetview extends Quest
;ce script permet de voir la ou une des cibles les plus proches de l'axe de visée du joueur, évitant les grands mouvemets de souris.
;Le lien qui peut mener au mapping des touches
;http://fose.silverlock.org/fose_command_doc.html#DirectX_Scancodes"]http://fose.silverlo...rectX_Scancodes
import debug
Import Input
import math
Actor Property PlayerREF Auto
faction property currentfollowerfaction auto
globalvariable property SG_MODON auto ;cela permettra de désactiver le mod avant désinstallation
actor closest = None ; c'est la variable où je stocke l'acteur le plus proche de l'axe. Remplacé à chaque fois que je trouve plus proche.
ReferenceAlias Property ClosestActor Auto
Int Property KeyPressed = 0 Auto
function detect()
float zoffset ; servira pour les calculs dans la fonction, ne pas confondre avec la variable des event. Elle est connue que par la fonction.
float zoffsetmin = 90 ; stockera la valeur la plus petite, plus la valeur est élevée, plus le champ de recherche est grand. C'est donc un réglage à faire.
int t = 0 ; la variable qui me servira à compter le nombre d'itérations
while (t <= 7) ; le nombre d'itérations ou l'art du compromis entre rapidité et efficacité. C'est ça le truc en fait.
Actor randomActor = Game.FindRandomActorFromRef(playerref, 5000.0) ;la commande demandant l'actor le plus proche retourne toujours le joueur alors je tape au hasard pendant mes itérations. Autre astuce.
if (!((randomActor == playerref) || (randomActor.GetFactionRank(CurrentFollowerFaction) >= 0))) && !randomactor.isdead() && randomActor != None && playerref.hasLOS(randomactor) && randomactor.IsHostileToActor(playerref) ; je ne fais les calculs et la prise en compte que si ce n'est pas le joueur, un compagnon et qu'un actor a été trouvé.
zOffset = playerref.GetHeadingAngle(randomactor) ; je demande l'écart par rapport à l'axe du joueur.
if abs(zoffset) < abs(zoffsetmin) ;si l'actor trouvé est plus dans l'axe que le précédent, l'écart ainsi que son nom sont stockés...
zoffsetmin = zoffset
closest = randomactor ;la variable closest est commune à toutes les instances du script car déclarée au début du script
endif
endif
t = t +1 ;important sinon la fonction tourne en boucle.
endwhile
if closest == none
notification("Aucune cible trouvée")
endif
endfunction
Event OnInit()
RegisterForSingleUpdate(0.1) ;à l'initialisation du script, on se prépare à appeler une fois l'event onupdate()
EndEvent
Event OnUpdate()
if IsKeyPressed(45) && KeyPressed == 0
KeyPressed = 1
detect()
if closest != none
float zOffset = PlayerREF.GetHeadingAngle(closest)
PlayerREF.SetAngle(PlayerREF.GetAngleX(), PlayerREF.GetAngleY(), PlayerREF.GetAngleZ() + zOffset)
endif
elseif IsKeyPressed(45) == 0
KeyPressed = 0
endif
if SG_MODON.getvalueint() == 1
RegisterForSingleUpdate(0.1)
endif
EndEvent
Il ne manquera plus qu'à le tester demain en attendant de faire le menu.
Tu proposes le choix entre quelles touches? J'ai mis X par défaut car proche des autres mais c'est pas pratique pour ceux qui utilisent le clavier main droite.
Modifié par Gérauld, 03 juillet 2012 - 00:31.
L'ours blanc est l'un des plus grands carnivores de Nirn. Les poils du pelage sont translucides et creux. C'est la réfraction de la lumière visible sur la surface interne des poils creux et incolores qui les fait paraître blancs. Cette particularité lui permet de se camoufler dans son environnement de neige et de glace, afin de mieux surprendre ses proies. Ce plantigrade vit exclusivement en Bordeciel et sur l'île de Solstheim.