Boïndil
05.06.2011, 15:31
Hallo, Leute,
mich hat es grausam genervt, wie aufgebläht und ineffizient die Scripte in Vanilla sind, was bedeutet, dass sie auch schwer zu warten und zu debuggen sind.
Man denke da nur an die diversen ellenlangen Warten-Befehle vor jedem DLC, die teilweise in Quest-Scripten, aber teilweise auch Result-Scripts sind.
Einige Modder haben teilweise eine bessere Programmier-Moral als die Original-Entwickler, arbeiten teilweise schon mit Funktionen, aber zu wenig weit.
Liegt vielleicht daran, dass ich frisch in die Sprache eingestiegen bin, aber mir sonst gewöhnt bin, mit JS, VB und dem unglaublich skalierbaren, effizienten und leistungsfähigen C#.Net zu programmieren. Hier gibt es keine Notwendigkeit, Code haufenweise zu duplizieren und es ist unglaublich, wie kurz Scripte sein können, die ein komplettes Gebiet abdecken. Klassen, Vererbung und Überladungen kann ich nicht nachrüsten, aber zumindest das beste aus dem wenigen rausholen.
Also habe ich begonnen, ein System zu entwicklen, wo Funktionen abgekapselt und flexibel einzusetzen sind, dadurch sind sie übersichtlicher und einfacher zu warten und dies vor allem an einem Ort.
Dies beginnt als Beispiel mit einer neuen Quest MeinModBegleiterFunktionenQuest.
Diese braucht wahrscheinlich keine hohe Priorität, aber die Script-Processing-Delay setzen wir auf Default, kann aber auch höher sein, falls es nicht um Speed geht. Und natürlich muss sie Start Game Enabled sein.
Generell geht es darum, dass Scripte überall im Spiel Funktionen mit Variabeln aus der Funktionen-Quest aufrufen können.
Die Entscheidung, die Funktion aufzurufen, kann in einem Actor-Effect-Script, einem Aktivator, einem Quest-Script oder einem Itemscript sein. Hier muss darauf geachtet werden, dass die Konditionen stimmen und die Parameter korrekte Werte kriegen.
Die Funktionen selbst führen nur die Variabeln aus, sie überprüfen nicht selbst, ob die Kondition stimmt und die Variable einen korrekten Wert hat.
Man könnte das natürlich tun, bläht dann aber die Scripte wieder auf.
Bevor man beginnt, sollte man sich überlegen, welche Tasks zu einem bestimmten Bereich gehören und welche vor allem oft benötigt werden:
-Warten
-Folgen
-Heilen
-Wiederbeleben
Gerade bei den Begleitern muss man einberechnen, dass Tasks entweder nur einen oder alle betreffen können. So bricht man die Funktionen auf die kleinsten möglichen Teile runter, die einzeln für sich überschaubar sind.
Manche Tasks sind oberflächlich gesehen eine Funktion, können aber aus mehreren Sub-Funktionen bestehen, die auch Teil von anderen Funktionen sind.
Z.B. bedeutet ein Feuern, dass der Kampfstil auf Default gesetzt wird, dass dem Follower alle Verbindungen zum Player wie Fraktion und TeamMate gekappt werden werden und dass er zu seinem HomeMarker gebeamt wird. Also machen wir keine einzelne Funktion "Feuern" sondern die Funktionen "Kampfstil", "Als Begleiter deaktivieren" und "Gehe zum HomeMarker". Denn das sind alles einzelne Funktionen, die auch anderweitig benutzt werden.
Anschliessend muss man sich überlegen, welche Unterfunktionen in die Funktion gehören und welche in den Aufruf.
Beispiel: Die Funktion Warten benötigt kein Wissen darüber, in welchem Gebiet sie sich befindet und welche Message z.B. beim Warten ausgelöst wird, denn sonst würde man die Funktion wieder mit haufenweisen GetInWorldSpace und einer Auflistung von passenden Messages aufblähen.
Hingegen weiss der Aufrufer(z.B. BogDoorScript), wo er sich befindet, denn er löst ja das Warten aus, weil man z.B. die Bog-Door öffnet.
Bei der Funktion muss man sich auch überlegen, ob eine Steuerung dazu gehört. Wenn man zum Beispiel eine Funktion "Waffen eines Begleiter reparieren" erstellt, benötigt es folgende Angaben
-Reparaturhöhe als Float
-Begleiter-Index (0 = alle, 7 = Cross)
In den folgenden Beispielen werde ich die eigentlichen Funktionen auf das wesentliche begrenzen, jeder weiss ja, wieviel Zeilen Code es bedeutet, einen Begleiter professionell zu feuern.
Also beginnt unser neues Quest-Script:
scn MeinModBegleiterFunktionenScript
short TaskType ; Short: Index der Funktion
short TaskRef ; Short: Interner Index des Object
short TaskShort1 ; Short: Generischer Wert als Short
short TaskShort2 ; Short: Generischer Wert als Short
short TaskShort3 ; Short: Generischer Wert als Short
short TaskShort4 ; Short: Generischer Wert als Short
float TaskFloat1 ; Float: Generischer Wert als Float
float TaskFloat2 ; Float: Generischer Wert als Float
float TaskFloat3 ; Float: Generischer Wert als Float
float TaskFloat4 ; Float: Generischer Wert als Float
float TaskDelay ; Float: Gegebenenfalls Verzoegerung der Funktion
Begin GameMode
If TaskDelay <= 0
; Begleiter feuern
; TaskRef: 0 = Alle, FollowerIndex = einzelner Begleiter
If TaskType == 1
If TaskRef == 0 || TaskRef == 1
Set Followers.ButchHired To 0
Set Followers.ButchFired To 1
ElseIf TaskRef == 0 || TaskRef == 2
Set Followers.CrossHired To 0
Set Followers.CrossFired To 1
ElseIf TaskRef == 0 || TaskRef == 3
Set Followers.CloverHired To 0
Set Followers.CloverFired To 1
EndIf
; Variablen-Reset (Pflicht), Weiterleitung aber moeglich
Set TaskRef To 0
Set TaskType To 0
; Begleiter wiederbeleben
; TaskRef: 0 = Alle, FollowerIndex = einzelner Begleiter
ElseIf TaskType == 2
If ButchRef.GetDead == 0 && (TaskRef == 0 || TaskRef == 1 )
ButchRef.Ressurect
ElseIf CrossRef.GetDead == 0 && (TaskRef == 0 || TaskRef == 2 )
CrossRef.Ressurect
ElseIf CloverRef.GetDead == 0 && (TaskRef == 0 || TaskRef == 3 )
CloverRef.Ressurect
EndIf
; Variablen-Reset (Pflicht), Weiterleitung aber moeglich
Set TaskType To 3 ; Gesundheit erhoehen
Set TaskDelay To 5 ; Delay setzen
; Begleiter Gesundheit Reset
; TaskRef: 0 = Alle, FollowerIndex = einzelner Begleiter
ElseIf TaskType == 3
If TaskRef == 0 || TaskRef == 1
ButchRef.ResetHealth
ElseIf TaskRef == 0 || TaskRef == 2
CrossRef.ResetHealth
ElseIf TaskRef == 0 || TaskRef == 3
CloverRef.ResetHealth
EndIf
; Variablen-Reset (Pflicht), Weiterleitung aber moeglich
Set TaskRef To 0
Set TaskType To 0
; Begleiter Waffenstil Ranged
; TaskRef: 0 = Alle, FollowerIndex = einzelner Begleiter
ElseIf TaskType == 4
; Funktionen
; Variablen-Reset (Pflicht), Weiterleitung aber moeglich
Set TaskRef To 0
Set TaskType To 0
; Begleiter Waffenstil Melee
; TaskRef: 0 = Alle, FollowerIndex = einzelner Begleiter
ElseIf TaskType == 5
; Funktionen
; Variablen-Reset (Pflicht), Weiterleitung aber moeglich
Set TaskRef To 0
Set TaskType To 0
EndIf
Else
Set TaskDelay To TaskDelay - GetSecondsPassed
EndIf
End
Erläuterung
TaskType: Ist die Index-Nummer der Funktion
TaskRef: Ist die Index-Nummer des aktuellen Objects(Waffen, Outfits, NPC)
TaskDelay: Macht es möglich, die Funktion verzögert ablaufen zu lassen
TaskShortX, TaskFloatX: sind mögliche weitere Parameter mit diesen Daten-Typen( Stat-Modifier, HealthPercent, Scale)
ScriptAblauf:
Im Actor-Script wird entschieden, dass die Waffe eines speziellen Begleiters repariert werden muss.
Also setzt man den TaskType auf 9(Waffen reparieren), den TaskRef auf Clover(3), und nimmt den TaskFloat1, um den Wert der Reparatur zu bestimmen.
; Waffen eines Begleiters reparieren
If GetWeaponHealthPercentage < 0.85
; Clovers Waffe reparieren
Set MeinModBegleiterFunktionenQuest.TaskRef To 3
Set MeinModBegleiterFunktionenQuest.TaskFloat1 To 0.85
Set MeinModBegleiterFunktionenQuest.TaskType To 9
EndIf
Weitere Beispiele:
; Begleiter-Grösse als Spielerei beim Betreten einer Zelle
If DoOnce == 0 && Player.GetInCell MeinModCellX == 1
; Clover vergroessern
Set MeinModBegleiterFunktionenQuest.TaskRef To 3
Set MeinModBegleiterFunktionenQuest.TaskFloat1 To 1.8
Set MeinModBegleiterFunktionenQuest.TaskType To 7
EndIf
; Begleiter nach einem Gefecht automatisch heilen oder wiederbeleben
Begin OnCombatEnd
If GlobalFollowerHealMode == 1
; Alle Begleiter wiederbeleben und auf vollstaendige Gesundheit bringen
Set MeinModBegleiterFunktionenQuest.TaskType To 2
ElseIf GlobalFollowerHealMode == 2
; Alle auf vollstaendige Gesundheit bringen
Set MeinModBegleiterFunktionenQuest.TaskType To 3
EndIf
End
Wie man im letzten Beispiel (auch im Script)sieht, ist es auch möglich Funktionen durch interne Sprünge anzusteuern.
Bei TaskType 2 wird der Begleiter ressurected, dann ein Delay gesetzt und die Gesundheit des Begleiter mit einer Weiterleitung auf TaskType 3 wiederhergestellt.
Bei TaskType 3 wird nur die Gesundheit wiederhergestellt.
Also bedeutet 2 (= Wiederbeleben) auch 3 (= Gesundheit reseten).
Hier noch ein aktuelles Beispiel vom Code für ein Warten von definierten Begleitern(oder allen) an einem bestimmten Ort oder gleich hier.
Die HomeMarker für alle oder einzelne Begleiter oder einem bestimmten CurrentHomeMarker wird in den betreffenden Scripten bestimmt.
Z.B. hat die Bog Door im InActivate mein Script:
scn DLC04BogDoorSCRIPT
; Followers have to wait.
; wlwFollowersNotAllowed wird aufgehoben in Quest DLC04MQ02, Stage 180
Begin OnActivate Player
if GetStage DLC04MQ02 == 150
setStage DLC04MQ02 180
else
If Followers.PlayerHasFollower == 1
wlwFollowersCurrentWaitMarker.MoveTo DLC04BogAwakenMarker
ShowMessage wlwDLC04BogFollowersMsg
Set wlwFollowersNotAllowed To 1
Set Followers.TaskShort1 To 3
Set Followers.TaskType To 3
EndIf
; activate player (thanx @ Aaaaaimbot)
Activate
endif
End
Hier der aktuelle Warten-Block im Follower-Quest-Script:
; Param TaskType: 3 = FollowersWait
; Param TaskRef : 0 = All | FollowerId
; TaskShort1: 0 = Aktuelle Position | 1 == wlwFollowersXXXHomeMarker | 2 = wlwFollowersHomeWaitMarker | 3 = wlwFollowersCurrentWaitMarker
; TaskShort2: 0 = FollowerWaitTime | Integer = Integer * FollowerWaitTime
If TaskType == 3
If TaskShort2 == 0
Set TaskShort2 To FollowerWaitTime
Else
Set TaskShort2 To (FollowerWaitTime * TaskShort2)
EndIf
If Followers.DogmeatHired == 1 && DogmeatRef.Waiting == 0 && (TaskRef == 0 || TaskRef == 1)
Set DogmeatRef.Waiting To 1
Set Followers.DogmeatWaitingLeaveDay To( GameDaysPassed + TaskShort2 )
If TaskShort1 == 1
DogmeatRef.MoveTo wlwFollowersDogMeatHomeMarker
ElseIf TaskShort1 == 2
DogmeatRef.MoveTo wlwFollowersHomeWaitMarker
ElseIf TaskShort1 == 3
DogmeatRef.MoveTo wlwFollowersCurrentWaitMarker
EndIf
EndIf
If Followers.ButchHired == 1 && ButchRef.Waiting == 0 && (TaskRef == 0 || TaskRef == 2)
Set ButchRef.Waiting To 1
Set Followers.ButchWaitingLeaveDay To( GameDaysPassed + TaskShort2 )
If TaskShort1 == 1
ButchRef.MoveTo wlwFollowersButchHomeMarker
ElseIf TaskShort1 == 2
ButchRef.MoveTo wlwFollowersHomeWaitMarker
ElseIf TaskShort1 == 3
ButchRef.MoveTo wlwFollowersCurrentWaitMarker
EndIf
EndIf
If Followers.CharonHired == 1 && CharonRef.Waiting == 0 && (TaskRef == 0 || TaskRef == 3)
Set CharonRef.Waiting To 1
Set Followers.CharonWaitingLeaveDay To( GameDaysPassed + TaskShort2 )
If TaskShort1 == 1
CharonRef.MoveTo wlwFollowersCharonHomeMarker
ElseIf TaskShort1 == 2
CharonRef.MoveTo wlwFollowersHomeWaitMarker
ElseIf TaskShort1 == 3
CharonRef.MoveTo wlwFollowersCurrentWaitMarker
EndIf
EndIf
If Followers.CloverHired == 1 && CloverRef.Waiting == 0 && (TaskRef == 0 || TaskRef == 4)
Set CloverRef.Waiting To 1
Set Followers.CloverWaitingLeaveDay To( GameDaysPassed + TaskShort2 )
If TaskShort1 == 1
CloverRef.MoveTo wlwFollowersCloverHomeMarker
ElseIf TaskShort1 == 2
CloverRef.MoveTo wlwFollowersHomeWaitMarker
ElseIf TaskShort1 == 3
CloverRef.MoveTo wlwFollowersCurrentWaitMarker
EndIf
EndIf
If Followers.JerichoHired == 1 && JerichoRef.Waiting == 0 && (TaskRef == 0 || TaskRef == 5)
Set JerichoRef.Waiting To 1
Set Followers.JerichoWaitingLeaveDay To( GameDaysPassed + TaskShort2 )
If TaskShort1 == 1
JerichoRef.MoveTo wlwFollowersJerichoHomeMarker
ElseIf TaskShort1 == 2
JerichoRef.MoveTo wlwFollowersHomeWaitMarker
ElseIf TaskShort1 == 3
JerichoRef.MoveTo wlwFollowersCurrentWaitMarker
EndIf
EndIf
If Followers.FawkesHired == 1 && MQ08FawkesRef.Waiting == 0&& (TaskRef == 0 || TaskRef == 6)
Set MQ08FawkesRef.Waiting To 1
Set Followers.FawkesWaitingLeaveDay To( GameDaysPassed + TaskShort2 )
If TaskShort1 == 1
MQ08FawkesRef.MoveTo wlwFollowersFawkesHomeMarker
ElseIf TaskShort1 == 2
MQ08FawkesRef.MoveTo wlwFollowersHomeWaitMarker
ElseIf TaskShort1 == 3
MQ08FawkesRef.MoveTo wlwFollowersCurrentWaitMarker
EndIf
EndIf
If Followers.RL3Hired == 1 && RL3Ref.Waiting == 0 && (TaskRef == 0 || TaskRef == 7)
Set RL3Ref.Waiting To 1
Set Followers.RL3WaitingLeaveDay To( GameDaysPassed + TaskShort2 )
If TaskShort1 == 1
RL3Ref.MoveTo wlwFollowersRL3HomeMarker
ElseIf TaskShort1 == 2
RL3Ref.MoveTo wlwFollowersHomeWaitMarker
ElseIf TaskShort1 == 3
RL3Ref.MoveTo wlwFollowersCurrentWaitMarker
EndIf
EndIf
If Followers.StarPaladinCrossHired == 1 && StarPaladinCrossRef.Waiting == 0 && (TaskRef == 0 || TaskRef == 8)
Set StarPaladinCrossRef.Waiting To 1
Set Followers.CrossWaitingLeaveDay To( GameDaysPassed + TaskShort2 )
If TaskShort1 == 1
StarPaladinCrossRef.MoveTo wlwFollowersCrossHomeMarker
ElseIf TaskShort1 == 2
StarPaladinCrossRef.MoveTo wlwFollowersHomeWaitMarker
ElseIf TaskShort1 == 3
StarPaladinCrossRef.MoveTo wlwFollowersCurrentWaitMarker
EndIf
EndIf
Set TaskType To 0
Set TaskRef To 0
Set TaskShort1 To 0
Set TaskShort2 To 0
EndIf
Ich hoffe, dass das einigermassen verständlich war und dass ich damit einige Anregungen für ein effizientes Coden geben kann und stehe natürlich auch für eine Diskussion bereit.
Diese Methoden sind natürlich nicht auf Begleiter begrenzt.
Grüsse und ein schönes Weekend
Boïndil (der gerade wieder in Pitt angekommen ist)
mich hat es grausam genervt, wie aufgebläht und ineffizient die Scripte in Vanilla sind, was bedeutet, dass sie auch schwer zu warten und zu debuggen sind.
Man denke da nur an die diversen ellenlangen Warten-Befehle vor jedem DLC, die teilweise in Quest-Scripten, aber teilweise auch Result-Scripts sind.
Einige Modder haben teilweise eine bessere Programmier-Moral als die Original-Entwickler, arbeiten teilweise schon mit Funktionen, aber zu wenig weit.
Liegt vielleicht daran, dass ich frisch in die Sprache eingestiegen bin, aber mir sonst gewöhnt bin, mit JS, VB und dem unglaublich skalierbaren, effizienten und leistungsfähigen C#.Net zu programmieren. Hier gibt es keine Notwendigkeit, Code haufenweise zu duplizieren und es ist unglaublich, wie kurz Scripte sein können, die ein komplettes Gebiet abdecken. Klassen, Vererbung und Überladungen kann ich nicht nachrüsten, aber zumindest das beste aus dem wenigen rausholen.
Also habe ich begonnen, ein System zu entwicklen, wo Funktionen abgekapselt und flexibel einzusetzen sind, dadurch sind sie übersichtlicher und einfacher zu warten und dies vor allem an einem Ort.
Dies beginnt als Beispiel mit einer neuen Quest MeinModBegleiterFunktionenQuest.
Diese braucht wahrscheinlich keine hohe Priorität, aber die Script-Processing-Delay setzen wir auf Default, kann aber auch höher sein, falls es nicht um Speed geht. Und natürlich muss sie Start Game Enabled sein.
Generell geht es darum, dass Scripte überall im Spiel Funktionen mit Variabeln aus der Funktionen-Quest aufrufen können.
Die Entscheidung, die Funktion aufzurufen, kann in einem Actor-Effect-Script, einem Aktivator, einem Quest-Script oder einem Itemscript sein. Hier muss darauf geachtet werden, dass die Konditionen stimmen und die Parameter korrekte Werte kriegen.
Die Funktionen selbst führen nur die Variabeln aus, sie überprüfen nicht selbst, ob die Kondition stimmt und die Variable einen korrekten Wert hat.
Man könnte das natürlich tun, bläht dann aber die Scripte wieder auf.
Bevor man beginnt, sollte man sich überlegen, welche Tasks zu einem bestimmten Bereich gehören und welche vor allem oft benötigt werden:
-Warten
-Folgen
-Heilen
-Wiederbeleben
Gerade bei den Begleitern muss man einberechnen, dass Tasks entweder nur einen oder alle betreffen können. So bricht man die Funktionen auf die kleinsten möglichen Teile runter, die einzeln für sich überschaubar sind.
Manche Tasks sind oberflächlich gesehen eine Funktion, können aber aus mehreren Sub-Funktionen bestehen, die auch Teil von anderen Funktionen sind.
Z.B. bedeutet ein Feuern, dass der Kampfstil auf Default gesetzt wird, dass dem Follower alle Verbindungen zum Player wie Fraktion und TeamMate gekappt werden werden und dass er zu seinem HomeMarker gebeamt wird. Also machen wir keine einzelne Funktion "Feuern" sondern die Funktionen "Kampfstil", "Als Begleiter deaktivieren" und "Gehe zum HomeMarker". Denn das sind alles einzelne Funktionen, die auch anderweitig benutzt werden.
Anschliessend muss man sich überlegen, welche Unterfunktionen in die Funktion gehören und welche in den Aufruf.
Beispiel: Die Funktion Warten benötigt kein Wissen darüber, in welchem Gebiet sie sich befindet und welche Message z.B. beim Warten ausgelöst wird, denn sonst würde man die Funktion wieder mit haufenweisen GetInWorldSpace und einer Auflistung von passenden Messages aufblähen.
Hingegen weiss der Aufrufer(z.B. BogDoorScript), wo er sich befindet, denn er löst ja das Warten aus, weil man z.B. die Bog-Door öffnet.
Bei der Funktion muss man sich auch überlegen, ob eine Steuerung dazu gehört. Wenn man zum Beispiel eine Funktion "Waffen eines Begleiter reparieren" erstellt, benötigt es folgende Angaben
-Reparaturhöhe als Float
-Begleiter-Index (0 = alle, 7 = Cross)
In den folgenden Beispielen werde ich die eigentlichen Funktionen auf das wesentliche begrenzen, jeder weiss ja, wieviel Zeilen Code es bedeutet, einen Begleiter professionell zu feuern.
Also beginnt unser neues Quest-Script:
scn MeinModBegleiterFunktionenScript
short TaskType ; Short: Index der Funktion
short TaskRef ; Short: Interner Index des Object
short TaskShort1 ; Short: Generischer Wert als Short
short TaskShort2 ; Short: Generischer Wert als Short
short TaskShort3 ; Short: Generischer Wert als Short
short TaskShort4 ; Short: Generischer Wert als Short
float TaskFloat1 ; Float: Generischer Wert als Float
float TaskFloat2 ; Float: Generischer Wert als Float
float TaskFloat3 ; Float: Generischer Wert als Float
float TaskFloat4 ; Float: Generischer Wert als Float
float TaskDelay ; Float: Gegebenenfalls Verzoegerung der Funktion
Begin GameMode
If TaskDelay <= 0
; Begleiter feuern
; TaskRef: 0 = Alle, FollowerIndex = einzelner Begleiter
If TaskType == 1
If TaskRef == 0 || TaskRef == 1
Set Followers.ButchHired To 0
Set Followers.ButchFired To 1
ElseIf TaskRef == 0 || TaskRef == 2
Set Followers.CrossHired To 0
Set Followers.CrossFired To 1
ElseIf TaskRef == 0 || TaskRef == 3
Set Followers.CloverHired To 0
Set Followers.CloverFired To 1
EndIf
; Variablen-Reset (Pflicht), Weiterleitung aber moeglich
Set TaskRef To 0
Set TaskType To 0
; Begleiter wiederbeleben
; TaskRef: 0 = Alle, FollowerIndex = einzelner Begleiter
ElseIf TaskType == 2
If ButchRef.GetDead == 0 && (TaskRef == 0 || TaskRef == 1 )
ButchRef.Ressurect
ElseIf CrossRef.GetDead == 0 && (TaskRef == 0 || TaskRef == 2 )
CrossRef.Ressurect
ElseIf CloverRef.GetDead == 0 && (TaskRef == 0 || TaskRef == 3 )
CloverRef.Ressurect
EndIf
; Variablen-Reset (Pflicht), Weiterleitung aber moeglich
Set TaskType To 3 ; Gesundheit erhoehen
Set TaskDelay To 5 ; Delay setzen
; Begleiter Gesundheit Reset
; TaskRef: 0 = Alle, FollowerIndex = einzelner Begleiter
ElseIf TaskType == 3
If TaskRef == 0 || TaskRef == 1
ButchRef.ResetHealth
ElseIf TaskRef == 0 || TaskRef == 2
CrossRef.ResetHealth
ElseIf TaskRef == 0 || TaskRef == 3
CloverRef.ResetHealth
EndIf
; Variablen-Reset (Pflicht), Weiterleitung aber moeglich
Set TaskRef To 0
Set TaskType To 0
; Begleiter Waffenstil Ranged
; TaskRef: 0 = Alle, FollowerIndex = einzelner Begleiter
ElseIf TaskType == 4
; Funktionen
; Variablen-Reset (Pflicht), Weiterleitung aber moeglich
Set TaskRef To 0
Set TaskType To 0
; Begleiter Waffenstil Melee
; TaskRef: 0 = Alle, FollowerIndex = einzelner Begleiter
ElseIf TaskType == 5
; Funktionen
; Variablen-Reset (Pflicht), Weiterleitung aber moeglich
Set TaskRef To 0
Set TaskType To 0
EndIf
Else
Set TaskDelay To TaskDelay - GetSecondsPassed
EndIf
End
Erläuterung
TaskType: Ist die Index-Nummer der Funktion
TaskRef: Ist die Index-Nummer des aktuellen Objects(Waffen, Outfits, NPC)
TaskDelay: Macht es möglich, die Funktion verzögert ablaufen zu lassen
TaskShortX, TaskFloatX: sind mögliche weitere Parameter mit diesen Daten-Typen( Stat-Modifier, HealthPercent, Scale)
ScriptAblauf:
Im Actor-Script wird entschieden, dass die Waffe eines speziellen Begleiters repariert werden muss.
Also setzt man den TaskType auf 9(Waffen reparieren), den TaskRef auf Clover(3), und nimmt den TaskFloat1, um den Wert der Reparatur zu bestimmen.
; Waffen eines Begleiters reparieren
If GetWeaponHealthPercentage < 0.85
; Clovers Waffe reparieren
Set MeinModBegleiterFunktionenQuest.TaskRef To 3
Set MeinModBegleiterFunktionenQuest.TaskFloat1 To 0.85
Set MeinModBegleiterFunktionenQuest.TaskType To 9
EndIf
Weitere Beispiele:
; Begleiter-Grösse als Spielerei beim Betreten einer Zelle
If DoOnce == 0 && Player.GetInCell MeinModCellX == 1
; Clover vergroessern
Set MeinModBegleiterFunktionenQuest.TaskRef To 3
Set MeinModBegleiterFunktionenQuest.TaskFloat1 To 1.8
Set MeinModBegleiterFunktionenQuest.TaskType To 7
EndIf
; Begleiter nach einem Gefecht automatisch heilen oder wiederbeleben
Begin OnCombatEnd
If GlobalFollowerHealMode == 1
; Alle Begleiter wiederbeleben und auf vollstaendige Gesundheit bringen
Set MeinModBegleiterFunktionenQuest.TaskType To 2
ElseIf GlobalFollowerHealMode == 2
; Alle auf vollstaendige Gesundheit bringen
Set MeinModBegleiterFunktionenQuest.TaskType To 3
EndIf
End
Wie man im letzten Beispiel (auch im Script)sieht, ist es auch möglich Funktionen durch interne Sprünge anzusteuern.
Bei TaskType 2 wird der Begleiter ressurected, dann ein Delay gesetzt und die Gesundheit des Begleiter mit einer Weiterleitung auf TaskType 3 wiederhergestellt.
Bei TaskType 3 wird nur die Gesundheit wiederhergestellt.
Also bedeutet 2 (= Wiederbeleben) auch 3 (= Gesundheit reseten).
Hier noch ein aktuelles Beispiel vom Code für ein Warten von definierten Begleitern(oder allen) an einem bestimmten Ort oder gleich hier.
Die HomeMarker für alle oder einzelne Begleiter oder einem bestimmten CurrentHomeMarker wird in den betreffenden Scripten bestimmt.
Z.B. hat die Bog Door im InActivate mein Script:
scn DLC04BogDoorSCRIPT
; Followers have to wait.
; wlwFollowersNotAllowed wird aufgehoben in Quest DLC04MQ02, Stage 180
Begin OnActivate Player
if GetStage DLC04MQ02 == 150
setStage DLC04MQ02 180
else
If Followers.PlayerHasFollower == 1
wlwFollowersCurrentWaitMarker.MoveTo DLC04BogAwakenMarker
ShowMessage wlwDLC04BogFollowersMsg
Set wlwFollowersNotAllowed To 1
Set Followers.TaskShort1 To 3
Set Followers.TaskType To 3
EndIf
; activate player (thanx @ Aaaaaimbot)
Activate
endif
End
Hier der aktuelle Warten-Block im Follower-Quest-Script:
; Param TaskType: 3 = FollowersWait
; Param TaskRef : 0 = All | FollowerId
; TaskShort1: 0 = Aktuelle Position | 1 == wlwFollowersXXXHomeMarker | 2 = wlwFollowersHomeWaitMarker | 3 = wlwFollowersCurrentWaitMarker
; TaskShort2: 0 = FollowerWaitTime | Integer = Integer * FollowerWaitTime
If TaskType == 3
If TaskShort2 == 0
Set TaskShort2 To FollowerWaitTime
Else
Set TaskShort2 To (FollowerWaitTime * TaskShort2)
EndIf
If Followers.DogmeatHired == 1 && DogmeatRef.Waiting == 0 && (TaskRef == 0 || TaskRef == 1)
Set DogmeatRef.Waiting To 1
Set Followers.DogmeatWaitingLeaveDay To( GameDaysPassed + TaskShort2 )
If TaskShort1 == 1
DogmeatRef.MoveTo wlwFollowersDogMeatHomeMarker
ElseIf TaskShort1 == 2
DogmeatRef.MoveTo wlwFollowersHomeWaitMarker
ElseIf TaskShort1 == 3
DogmeatRef.MoveTo wlwFollowersCurrentWaitMarker
EndIf
EndIf
If Followers.ButchHired == 1 && ButchRef.Waiting == 0 && (TaskRef == 0 || TaskRef == 2)
Set ButchRef.Waiting To 1
Set Followers.ButchWaitingLeaveDay To( GameDaysPassed + TaskShort2 )
If TaskShort1 == 1
ButchRef.MoveTo wlwFollowersButchHomeMarker
ElseIf TaskShort1 == 2
ButchRef.MoveTo wlwFollowersHomeWaitMarker
ElseIf TaskShort1 == 3
ButchRef.MoveTo wlwFollowersCurrentWaitMarker
EndIf
EndIf
If Followers.CharonHired == 1 && CharonRef.Waiting == 0 && (TaskRef == 0 || TaskRef == 3)
Set CharonRef.Waiting To 1
Set Followers.CharonWaitingLeaveDay To( GameDaysPassed + TaskShort2 )
If TaskShort1 == 1
CharonRef.MoveTo wlwFollowersCharonHomeMarker
ElseIf TaskShort1 == 2
CharonRef.MoveTo wlwFollowersHomeWaitMarker
ElseIf TaskShort1 == 3
CharonRef.MoveTo wlwFollowersCurrentWaitMarker
EndIf
EndIf
If Followers.CloverHired == 1 && CloverRef.Waiting == 0 && (TaskRef == 0 || TaskRef == 4)
Set CloverRef.Waiting To 1
Set Followers.CloverWaitingLeaveDay To( GameDaysPassed + TaskShort2 )
If TaskShort1 == 1
CloverRef.MoveTo wlwFollowersCloverHomeMarker
ElseIf TaskShort1 == 2
CloverRef.MoveTo wlwFollowersHomeWaitMarker
ElseIf TaskShort1 == 3
CloverRef.MoveTo wlwFollowersCurrentWaitMarker
EndIf
EndIf
If Followers.JerichoHired == 1 && JerichoRef.Waiting == 0 && (TaskRef == 0 || TaskRef == 5)
Set JerichoRef.Waiting To 1
Set Followers.JerichoWaitingLeaveDay To( GameDaysPassed + TaskShort2 )
If TaskShort1 == 1
JerichoRef.MoveTo wlwFollowersJerichoHomeMarker
ElseIf TaskShort1 == 2
JerichoRef.MoveTo wlwFollowersHomeWaitMarker
ElseIf TaskShort1 == 3
JerichoRef.MoveTo wlwFollowersCurrentWaitMarker
EndIf
EndIf
If Followers.FawkesHired == 1 && MQ08FawkesRef.Waiting == 0&& (TaskRef == 0 || TaskRef == 6)
Set MQ08FawkesRef.Waiting To 1
Set Followers.FawkesWaitingLeaveDay To( GameDaysPassed + TaskShort2 )
If TaskShort1 == 1
MQ08FawkesRef.MoveTo wlwFollowersFawkesHomeMarker
ElseIf TaskShort1 == 2
MQ08FawkesRef.MoveTo wlwFollowersHomeWaitMarker
ElseIf TaskShort1 == 3
MQ08FawkesRef.MoveTo wlwFollowersCurrentWaitMarker
EndIf
EndIf
If Followers.RL3Hired == 1 && RL3Ref.Waiting == 0 && (TaskRef == 0 || TaskRef == 7)
Set RL3Ref.Waiting To 1
Set Followers.RL3WaitingLeaveDay To( GameDaysPassed + TaskShort2 )
If TaskShort1 == 1
RL3Ref.MoveTo wlwFollowersRL3HomeMarker
ElseIf TaskShort1 == 2
RL3Ref.MoveTo wlwFollowersHomeWaitMarker
ElseIf TaskShort1 == 3
RL3Ref.MoveTo wlwFollowersCurrentWaitMarker
EndIf
EndIf
If Followers.StarPaladinCrossHired == 1 && StarPaladinCrossRef.Waiting == 0 && (TaskRef == 0 || TaskRef == 8)
Set StarPaladinCrossRef.Waiting To 1
Set Followers.CrossWaitingLeaveDay To( GameDaysPassed + TaskShort2 )
If TaskShort1 == 1
StarPaladinCrossRef.MoveTo wlwFollowersCrossHomeMarker
ElseIf TaskShort1 == 2
StarPaladinCrossRef.MoveTo wlwFollowersHomeWaitMarker
ElseIf TaskShort1 == 3
StarPaladinCrossRef.MoveTo wlwFollowersCurrentWaitMarker
EndIf
EndIf
Set TaskType To 0
Set TaskRef To 0
Set TaskShort1 To 0
Set TaskShort2 To 0
EndIf
Ich hoffe, dass das einigermassen verständlich war und dass ich damit einige Anregungen für ein effizientes Coden geben kann und stehe natürlich auch für eine Diskussion bereit.
Diese Methoden sind natürlich nicht auf Begleiter begrenzt.
Grüsse und ein schönes Weekend
Boïndil (der gerade wieder in Pitt angekommen ist)