Jump to content

Compiler Error - no viable alternative at input '\\r\\n'


Recommended Posts

Hey guys, got a compiler error. I'm trying to add a line or two to to the Angry Artillery script but I get the error: ArtilleryReferenceScript.psc(22,16): no viable alternative at input '\\r\\n'

 

How can I fix this?

The script:

;/ Decompiled by Champollion V1.0.5
PEX format v3.9 GameID: 2
Source   : D:\Program Files (x86)\Steam\steamapps\common\Fallout 4\Data\scripts\ArtilleryReferenceScript.psc
Modified : 2016-02-03 03:40:37
Compiled : 2016-02-03 03:40:39
User     : Reid Rankin
Computer : ICARUS
/;
ScriptName ArtilleryReferenceScript extends ObjectReference

;-- Properties --------------------------------------
PropertyGroup ExplosionProperties
	Weapon Property WorkshopArtilleryWeapon Auto
	Activator Property WorkshopArtilleryFakeProjectile Auto
	Form Property XmarkerHeading Auto
	Sound Property FXProjectileArtilleryMinutemen Auto
	Explosion Property WorkshopArtilleryForce Auto
	Explosion Property MinArtilleryMuzzleFlash Auto
	Activator Property WorkshopArtilleryStrikeProjectileShooterClose Auto
	Activator Property WorkshopArtilleryStrikeProjectileShooterFar Auto
	Sound Property WPNArtilleryMinutemenFire Auto
EndPropertyGroup

PropertyGroup AnimationProperties collapsedonref
	Idle Property ArtilleryFire Auto
	Idle Property ArtilleryStop Auto
	Idle Property ArtilleryTurnClockwise Auto
	Idle Property ArtilleryTurnCounterClockwise Auto
EndPropertyGroup


;-- Variables ---------------------------------------
int CurrentCardinal = 0
ObjectReference CurrentTarget
string CurrentTurnEvent
bool noFire = False
int PreviousCardinal = 0
float AngleSnap = 20
bool TestFire = False
ObjectReference MinArtilleryMarker
float ArtillerySpreadRadius = 50

;-- Functions ---------------------------------------

Function PlaceTargetMarker()
	MinArtilleryMarker = CurrentTarget.PlaceAtMe(XmarkerHeading, 1, False, False, True)
	ObjectReference strikeOrigin = Self as ObjectReference
	float xOffset = Utility.RandomFloat(-1 * ArtillerySpreadRadius, ArtillerySpreadRadius)
	float yOffset = Utility.RandomFloat(-1 * ArtillerySpreadRadius, ArtillerySpreadRadius)
	MinArtilleryMarker.MoveTo(CurrentTarget, xOffset, yOffset, 0, True)
	float headingAngle = MinArtilleryMarker.GetHeadingAngle(strikeOrigin)
	headingAngle += MinArtilleryMarker.GetAngleZ()
	MinArtilleryMarker.SetAngle(0, 0, headingAngle)
EndFunction

Function Test(bool justAim)
	TestFire = True
	Self.FireAtTarget(Game.GetPlayer() as ObjectReference, justAim)
EndFunction

Function PlaceMortarExplosion()
	FXProjectileArtilleryMinutemen.Play(MinArtilleryMarker)
	ObjectReference myFiringMarker = None
	If (Self.Is3DLoaded())
		myFiringMarker = MinArtilleryMarker.PlaceAtMe(WorkshopArtilleryStrikeProjectileShooterClose as Form, 1, False, False, True)
	Else
		myFiringMarker = MinArtilleryMarker.PlaceAtMe(WorkshopArtilleryStrikeProjectileShooterFar as Form, 1, False, False, True)
	EndIf
	If (TestFire)
		MinArtilleryMarker.Delete()
	Else
		MinArtilleryMarker = None
	EndIf
	CurrentTarget = None
	TestFire = False
	var[] kargs = new var[1]
	kargs[0] = Self as var
	Self.SendCustomEvent("artilleryreferencescript_FinishedFiring", kargs)
EndFunction

Function PlayAnimOrIdle(Idle myIdle, string myAnim)
	Actor CurrentWorker = Self.GetActorRefOwner()
	Self.IsFurnitureInUse(True) && CurrentWorker as bool && CurrentWorker.PlayIdle(myIdle)
	Self.PlayAnimation(myAnim)
EndFunction

;bool Function GetTurnDirection(int P, int N)
;	bool CW = False
;	bool CCW = True
;	int T = (360 / AngleSnap) as int
;	N > P && T - N + P >= N - P
;	If (T - P + N <= P - N)
;		return CW
;	Else
;		return CCW
;	EndIf
;EndFunction

Function FireAtTarget(ObjectReference TargetToFireAt, bool turnToTargetOnly)
	CurrentTarget = TargetToFireAt
	If (TestFire)
		Self.PlaceTargetMarker()
	Else
		MinArtilleryMarker = TargetToFireAt
	EndIf
	Self.FireMortar(False)
EndFunction

;Function OnAnimationEvent(ObjectReference akSource, string asEventName)
;	If (asEventName == CurrentTurnEvent)
;		Self.UnregisterForAnimationEvent(Self as ObjectReference, CurrentTurnEvent)
;		Self.PlayAnimOrIdle(ArtilleryStop, "Stop")
;		If (noFire == False)
;			Self.FireMortar(False)
;		Else
;			noFire = True
;		EndIf
;	EndIf
;EndFunction

Function FireMortar(bool fakeFire)
	ObjectReference objSelf = Self as ObjectReference
	If (Self.Is3DLoaded())
		float CurrentDistance = objSelf.getDistance(CurrentTarget)
		Self.PlayAnimOrIdle(ArtilleryFire, "Fire")
		Utility.Wait(0.9)
		Self.PlaceAtNode("ProjectileNode", MinArtilleryMuzzleFlash as Form, 1, False, False, True, False)
		WorkshopArtilleryWeapon.Fire(objSelf, None)
	Else
		WPNArtilleryMinutemenFire.Play(objSelf)
	EndIf
	If (fakeFire == False)
		Self.PlaceMortarExplosion()
	EndIf
EndFunction

;Function TurnToTarget(ObjectReference TargetToFireAt, bool doNotFire)
;	bool TurnCCW = False
;	float FiringAngle = 0
;	float myHeadingAngle = 0
;	int myHeadingCardinal = 0
;	myHeadingAngle = Self.GetHeadingAngle(TargetToFireAt)
;	FiringAngle = myHeadingAngle
;	If (FiringAngle < 0)
;		FiringAngle += 360
;	EndIf
;	int upDownTest = Math.Floor(FiringAngle / AngleSnap / 2) % 2
;	If (upDownTest == 1)
;		myHeadingCardinal = Math.Ceiling(FiringAngle / AngleSnap)
;	Else
;		myHeadingCardinal = Math.Floor(FiringAngle / AngleSnap)
;	EndIf
;	myHeadingCardinal %= (360 / AngleSnap) as int
;	CurrentTurnEvent = myHeadingCardinal as string
;	If (PreviousCardinal != myHeadingCardinal)
;		Self.RegisterForAnimationEvent(Self as ObjectReference, CurrentTurnEvent)
;		TurnCCW = Self.GetTurnDirection(PreviousCardinal, myHeadingCardinal)
;		If (doNotFire)
;			noFire = True
;		Else
;			noFire = False
;		EndIf
;		If (TurnCCW == False)
;			Self.PlayAnimOrIdle(ArtilleryTurnClockwise, "TurnClockwise")
;		Else
;			Self.PlayAnimOrIdle(ArtilleryTurnCounterClockwise, "TurnCounterClockwise")
;		EndIf
;	ElseIf (doNotFire == False)
;		noFire = False
;		Self.FireMortar(False)
;	Else
;		noFire = True
;	EndIf
;	PreviousCardinal = myHeadingCardinal
;EndFunction

 

 

Link to comment
Share on other sites

To start with, I actually never really bothered with Property Groups before (as the documentation says, they are almost purely "visual/organizational"), but if my line counting was correct, I'm guessing that the decompiled source was from a pre-FO4CK time, toolset, or frame of mind where PropertyGroup and EndPropertyGroup were acceptable keywords.

 

You might try Group and EndGroup, as this is what's used in my copy of the very original script in the Script source folder (Fallout 4\Data\Scripts\Source\Base\ArtilleryReferenceScript.psc).

Link to comment
Share on other sites

Thanks for the reply. That actually did work but now there are a ton of other errors, looks like the script might have to be rebuilt and I can't do that.

 

Would it be possible to write a small, separate script which hooks onto the Angry Artillery script and runs when a certain thing takes place? It's a simple thing I want to run--PlayGamebryoAnimation. I know the settings for that and it just needs to run after Self.PlaceAtNode("ProjectileNode", MinArtilleryMuzzleFlash).

Link to comment
Share on other sites

Off the top of my head, generically you may be able to do some terrible workaround under those constraints, and register for and intercept the Fire animation event on the artillery, or have some other object be constantly polling for the flash effect to exist in the world, but that is not something to do.

 

I don't have a lot of errors when I fix your copy of the script in my editor, and basically fixing the initialization of a few floats (adding the .0) and the declaration of a CustomEvent lets the script compile.

I have not read the changes to the game's script to see if they are sane changes, though!

 

;Scriptname Demonstration:ArtilleryReferenceScript extends ObjectReference
ScriptName ArtilleryReferenceScript extends ObjectReference

;-- Properties --------------------------------------
Group ExplosionProperties
	Weapon Property WorkshopArtilleryWeapon Auto
	Activator Property WorkshopArtilleryFakeProjectile Auto
	Form Property XmarkerHeading Auto
	Sound Property FXProjectileArtilleryMinutemen Auto
	Explosion Property WorkshopArtilleryForce Auto
	Explosion Property MinArtilleryMuzzleFlash Auto
	Activator Property WorkshopArtilleryStrikeProjectileShooterClose Auto
	Activator Property WorkshopArtilleryStrikeProjectileShooterFar Auto
	Sound Property WPNArtilleryMinutemenFire Auto
EndGroup

Group AnimationProperties collapsedonref
	Idle Property ArtilleryFire Auto
	Idle Property ArtilleryStop Auto
	Idle Property ArtilleryTurnClockwise Auto
	Idle Property ArtilleryTurnCounterClockwise Auto
EndGroup

CustomEvent artilleryreferencescript_FinishedFiring

;-- Variables ---------------------------------------
int CurrentCardinal = 0
ObjectReference CurrentTarget
string CurrentTurnEvent
bool noFire = False
int PreviousCardinal = 0
float AngleSnap = 20.0
bool TestFire = False
ObjectReference MinArtilleryMarker
float ArtillerySpreadRadius = 50.0

;-- Functions ---------------------------------------

Function PlaceTargetMarker()
	MinArtilleryMarker = CurrentTarget.PlaceAtMe(XmarkerHeading, 1, False, False, True)
	ObjectReference strikeOrigin = Self as ObjectReference
	float xOffset = Utility.RandomFloat(-1 * ArtillerySpreadRadius, ArtillerySpreadRadius)
	float yOffset = Utility.RandomFloat(-1 * ArtillerySpreadRadius, ArtillerySpreadRadius)
	MinArtilleryMarker.MoveTo(CurrentTarget, xOffset, yOffset, 0, True)
	float headingAngle = MinArtilleryMarker.GetHeadingAngle(strikeOrigin)
	headingAngle += MinArtilleryMarker.GetAngleZ()
	MinArtilleryMarker.SetAngle(0, 0, headingAngle)
EndFunction

Function Test(bool justAim)
	TestFire = True
	Self.FireAtTarget(Game.GetPlayer() as ObjectReference, justAim)
EndFunction

Function PlaceMortarExplosion()
	FXProjectileArtilleryMinutemen.Play(MinArtilleryMarker)
	ObjectReference myFiringMarker = None
	If (Self.Is3DLoaded())
		myFiringMarker = MinArtilleryMarker.PlaceAtMe(WorkshopArtilleryStrikeProjectileShooterClose as Form, 1, False, False, True)
	Else
		myFiringMarker = MinArtilleryMarker.PlaceAtMe(WorkshopArtilleryStrikeProjectileShooterFar as Form, 1, False, False, True)
	EndIf
	If (TestFire)
		MinArtilleryMarker.Delete()
	Else
		MinArtilleryMarker = None
	EndIf
	CurrentTarget = None
	TestFire = False
	var[] kargs = new var[1]
	kargs[0] = Self as var
	Self.SendCustomEvent("artilleryreferencescript_FinishedFiring", kargs)
EndFunction

Function PlayAnimOrIdle(Idle myIdle, string myAnim)
	Actor CurrentWorker = Self.GetActorRefOwner()
	Self.IsFurnitureInUse(True) && CurrentWorker as bool && CurrentWorker.PlayIdle(myIdle)
	Self.PlayAnimation(myAnim)
EndFunction

;bool Function GetTurnDirection(int P, int N)
;	bool CW = False
;	bool CCW = True
;	int T = (360 / AngleSnap) as int
;	N > P && T - N + P >= N - P
;	If (T - P + N <= P - N)
;		return CW
;	Else
;		return CCW
;	EndIf
;EndFunction

Function FireAtTarget(ObjectReference TargetToFireAt, bool turnToTargetOnly)
	CurrentTarget = TargetToFireAt
	If (TestFire)
		Self.PlaceTargetMarker()
	Else
		MinArtilleryMarker = TargetToFireAt
	EndIf
	Self.FireMortar(False)
EndFunction

;Function OnAnimationEvent(ObjectReference akSource, string asEventName)
;	If (asEventName == CurrentTurnEvent)
;		Self.UnregisterForAnimationEvent(Self as ObjectReference, CurrentTurnEvent)
;		Self.PlayAnimOrIdle(ArtilleryStop, "Stop")
;		If (noFire == False)
;			Self.FireMortar(False)
;		Else
;			noFire = True
;		EndIf
;	EndIf
;EndFunction

Function FireMortar(bool fakeFire)
	ObjectReference objSelf = Self as ObjectReference
	If (Self.Is3DLoaded())
		float CurrentDistance = objSelf.getDistance(CurrentTarget)
		Self.PlayAnimOrIdle(ArtilleryFire, "Fire")
		Utility.Wait(0.9)
		Self.PlaceAtNode("ProjectileNode", MinArtilleryMuzzleFlash as Form, 1, False, False, True, False)
		WorkshopArtilleryWeapon.Fire(objSelf, None)
	Else
		WPNArtilleryMinutemenFire.Play(objSelf)
	EndIf
	If (fakeFire == False)
		Self.PlaceMortarExplosion()
	EndIf
EndFunction

;Function TurnToTarget(ObjectReference TargetToFireAt, bool doNotFire)
;	bool TurnCCW = False
;	float FiringAngle = 0
;	float myHeadingAngle = 0
;	int myHeadingCardinal = 0
;	myHeadingAngle = Self.GetHeadingAngle(TargetToFireAt)
;	FiringAngle = myHeadingAngle
;	If (FiringAngle < 0)
;		FiringAngle += 360
;	EndIf
;	int upDownTest = Math.Floor(FiringAngle / AngleSnap / 2) % 2
;	If (upDownTest == 1)
;		myHeadingCardinal = Math.Ceiling(FiringAngle / AngleSnap)
;	Else
;		myHeadingCardinal = Math.Floor(FiringAngle / AngleSnap)
;	EndIf
;	myHeadingCardinal %= (360 / AngleSnap) as int
;	CurrentTurnEvent = myHeadingCardinal as string
;	If (PreviousCardinal != myHeadingCardinal)
;		Self.RegisterForAnimationEvent(Self as ObjectReference, CurrentTurnEvent)
;		TurnCCW = Self.GetTurnDirection(PreviousCardinal, myHeadingCardinal)
;		If (doNotFire)
;			noFire = True
;		Else
;			noFire = False
;		EndIf
;		If (TurnCCW == False)
;			Self.PlayAnimOrIdle(ArtilleryTurnClockwise, "TurnClockwise")
;		Else
;			Self.PlayAnimOrIdle(ArtilleryTurnCounterClockwise, "TurnCounterClockwise")
;		EndIf
;	ElseIf (doNotFire == False)
;		noFire = False
;		Self.FireMortar(False)
;	Else
;		noFire = True
;	EndIf
;	PreviousCardinal = myHeadingCardinal
;EndFunction

 

 

Edited by ElPolloAzul
Link to comment
Share on other sites

You're a magician. Works like a charm.

 

See, the thing I was doing was finding the errors and if I couldn't fix them by doing very minor things I'd just delete them and yea.... then you have even more errors. All I can do related to scripts is butcher them, and quite well actually.

 

Thanks a lot!

Link to comment
Share on other sites

@ ElPolloAzul

 

If I may ask: I've never seen properties referenced in Groups like that - what the purpose of that as opposed to referencing them all one by one?

Link to comment
Share on other sites

@ ElPolloAzul

 

If I may ask: I've never seen properties referenced in Groups like that - what the purpose of that as opposed to referencing them all one by one?

 

It's almost entirely just for the purpose of organization within the script and its property value assignment dialog window. If you had a large quest script or core game mechanic (like the workshops) you might want to view variables in groups corresponding to different parts of the functionality, like settler recruitment vs. marker linking vs. synth spy spawning. If you have a particularly meaty script effect or activator script, you might want to split up, for example, the stuff related to loading and unloading and applying hazards to objects vs. sound effects, shader effects, and explosions. This is just another way to have separation of concerns, like a less powerful version of C#'s regions. There are apparently some nice touches to this process I have never looked at that make it work with inheritance (merges subclass variables grouped under a heading with parent class), internal documentation (groups can carry their own docstrings), and grouped display on the ingame console (SV/SQV), and naming (group declaration should override in-menu alphabetization of variable names).

 

You almost always see such nice clean, well-intentioned behavior more often in the original game's heavily-relied-upon scripts; it is, understandably, somewhat less likely with the modding set.

 

Now structs are an entirely different thing, and potentially very useful for organizing scripting. These are somewhat like structures in C-style languages, so you can create plain old data objects with multiple "fields", and move these united records around, store them in scripts, etc. My "Blast From The Past" grenades (e.g. in the EPA Season Pass) use structs to store unified position and aliveness records of ObjectReferences so that previous states can be recalled. Unfortunately, you can't stuff these with dynamically typed objects, arrays, const variables (well, that part makes sense), or other structs. You can replace this type of structured programming with parallel arrays if you are feeling silly, but that comes with its own disadvantages.

 

I love the inclusion of more proper, dynamically-sized arrays with Skyrim (theoretically, you could make all kinds of data structures using invisible or dummy-cell placed in-game objects and linked references), but it would have been nice to not have the 128 element limit, etc. There's still a lot you can work around there. If I had all of my mods come out in one big pack, I would have wanted to use the imports and external calls to global functions facilities more for shared utility functions, but this didn't happen.

 

Groups are a good in-editor and in-console only kind of feature, but I do wish things like PackIns, Lights, and, in particular, BendableSplines, were a tad more programmatically controllable (imagine all the fun you could have with dynamically relocatable physical wires), and not just in-editor or in-settlement-building-mode features. And it is funny to see all these nice object-oriented and OO-lite facilities without proper string handling, or input handling functionality -- kind of like the ALGOL 60 no standard I/O functions situation.

Link to comment
Share on other sites

Hey, thanks a lot and kudos for taking time to clarify that for me :)

 

You make it a lot easier for me to understand than the original description on the FO4 Wiki - I have absolutely no programmer's background but I nonetheless create scripted mods which work fine.

 

The reason I asked is because I'm currently polishing a new FO4 mod which adds some 20 or more animations to the player, and knowing that each one of them can be a sequences of 3, 4, 5 or more different idles, I end up with an incredibly long list of Idle Properties in my scripts - which could probably benefit to be grouped. But looking at the script you posted earlier, I can't see how I could use this the way you do in your "FireMortar" or "PlayAnimOrIdle" functions for instance. I do use arrays for quite a few other functions but not so much for my animation sequences because they're all different: different trigger event, different duration, different sequences (sometimes I'll use the same idle several times in the same sequence), different length, etc.

 

Hmm... Maybe I'll find a way... That's food for thoughts anyway - thanks a lot for that!

Link to comment
Share on other sites

Hey, thanks a lot and kudos for taking time to clarify that for me :smile:

 

You make it a lot easier for me to understand than the original description on the FO4 Wiki - I have absolutely no programmer's background but I nonetheless create scripted mods which work fine.

 

The reason I asked is because I'm currently polishing a new FO4 mod which adds some 20 or more animations to the player, and knowing that each one of them can be a sequences of 3, 4, 5 or more different idles, I end up with an incredibly long list of Idle Properties in my scripts - which could probably benefit to be grouped. But looking at the script you posted earlier, I can't see how I could use this the way you do in your "FireMortar" or "PlayAnimOrIdle" functions for instance. I do use arrays for quite a few other functions but not so much for my animation sequences because they're all different: different trigger event, different duration, different sequences (sometimes I'll use the same idle several times in the same sequence), different length, etc.

 

Hmm... Maybe I'll find a way... That's food for thoughts anyway - thanks a lot for that!

 

You probably wouldn't get that much extra organization out of this (since to really save space, it would be nice if structs could have arrays), but you could probably start by thinking about something like the following, which blends parallel arrays with groups:

 

 

 

Scriptname Demonstration:AnimationPlayerScript extends ObjectReference

; Add new animation groups to the script here, and configure the arrays in the Property editor:

Group AnimSequence_DrinkTankard
{'Drinking from a tankard, then doing some other anims with delays in between.'}
  Idle[] Property AnimSequence_DrinkTankard_IDLES auto
  float[] Property AnimSequence_DrinkTankard_DELAYS auto
EndGroup

Group AnimSequence_LookAtHands
{'Bringing up my hands, then doing some other anims with delays in between.'}
  Idle[] Property AnimSequence_LookAtHands_IDLES auto
  float[] Property AnimSequence_LookAtHands_DELAYS auto
EndGroup

Group AnimSequence_BringUpPipBoy
{'Looking at my PipBoy, then doing some other anims with delays in between.'}
  Idle[] Property AnimSequence_BringUpPipBoy_IDLES auto
  float[] Property AnimSequence_BringUpPipBoy_DELAYS auto
EndGroup

; End of animation groups.

; The animation player function (calls PlayIdle on Actor a for a sequence of idles, with hardcoded waits post each Idle dispatch).
Function PlayIdleAnimationSequence(Actor a, Idle[] idles2Play, float[] delays2make)
    int animationCounter = 0
    while animationCounter < idles2Play.Length
        a.PlayIdle(idles2Play[animationCounter])
        Utility.Wait(delays2make[animationCounter])
        animationCounter = animationCounter + 1
    endwhile
EndFunction

; Some triggering Event handling here, like if (contrived situation and interceptable animation events ahoy!)
; this script was attached to an obelisk that, until the player left the cell, tracked player animations after something activates it.
; I expect your chosen Events to make a lot more sense...

Actor poorUnfortunate

Event OnActivate(ObjectReference o)
  poorUnfortunate = Game.GetPlayer()
  RegisterForAnimationEvent(poorUnfortunate, "weaponSwing")
  RegisterForAnimationEvent(poorUnfortunate, "weaponDraw")
  RegisterForAnimationEvent(poorUnfortunate, "weaponLeftSwing")
EndEvent

Event OnUnload()
  UnregisterForAnimationEvent(poorUnfortunate, "weaponSwing")
  UnregisterForAnimationEvent(poorUnfortunate, "weaponDraw")
  UnregisterForAnimationEvent(poorUnfortunate, "weaponLeftSwing")
EndEvent

Event OnAnimationEvent(ObjectReference akSource, string asEventName)
  if (asEventName == "weaponSwing")
            PlayIdleAnimationSequence(poorUnfortunate,  AnimSequence_DrinkTankard_IDLES,  AnimSequence_DrinkTankard_DELAYS)
  elseif (asEventName == "weaponDraw")
       PlayIdleAnimationSequence(poorUnfortunate,  AnimSequence_LookAtHands_IDLES,  AnimSequence_LookAtHands_DELAYS)
  else
       PlayIdleAnimationSequence(poorUnfortunate,  AnimSequence_BringUpPipBoy_IDLES,  AnimSequence_BringUpPipBoy_DELAYS)
  endIf
endEvent

 

 

Link to comment
Share on other sites

Hey, thanks again for your time, ElPolloaAzul :)

 

Indeed, I considered something like that - without thinking of grouping properties though - but in the end not only did it not really make the scripts more compact but it also made the procedure I wanted to add for the player to be able to stop animations any time he wanted way more complicated to implement. Fallout 4 anims don't work the way they used to in Skyrim and are, in my experience, a bit harder to play around with safely. If I was a seasoned coder like Chesko or had more experience with animations like some other non-Nexus modders, I might have ended up with a more efficient result. In the end, I used arrays and states and lots of custom functions, the scripts may not be very elegant but they work well and I managed to keep them all as magicEffects which hopefully will have very little impact impacts on the game.

 

Thanks for sharing, ElPolloAzul - I'm sure what you've just showed me will come handy at some point in my others mods.

 

Cheers from France :).

Link to comment
Share on other sites

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...