Jump to content

Playing Around With Animations


A.J.

Recommended Posts

Hello,

 

I'm going to post this here because it's the result of some tries I did, but please don't consider it a tutorial at all.

 

IMPORTANT: this is not a Bible, take what you see as the consequences of my tries and experiments. However, I'LL BE GLAD TO ADD MORE INFORMATIONS IF SOMEONE WILL AKNOWLEDGE ME, but I would also like to be in the possibility to try these things on my own (so for example provide me specific files if they are required to make addictional tries)

 

I'll also will write tons of obvious things probably, because this is a generic speech about animations.

 

Types of animations

There are two main groups of animations: SpecialIdles and AnimGroups. The tools we have to invoke them are 3: PickIdle, PlayIdle and Playgroup. The first two invoke SpecialIdles, the third invokes AnimGroups.

 

Invoking a Special Idle

>>> PlayIdle

It can be done in many ways. The most common example is going in TFC mode, clicking to our character and write playidle name_of_the_animation. It can be done by script too, but PC will have a limit on it: they won't work, they only work in TFC mode.

Anyway there are a couple of exceptions:

- When the actor has a spell effect, inside the spell there's a PlayIdle on the actor who carries the spell effect. If the actor is the player, the animation will be invoked, no matter if we are not in TFC mode

- When the actor uses an activator, if in the first frame of the script attached there's a playidle, the actor will trigger the animation. So it's the same if the actor is the player (source: Beth guide. Didn't try that, but since much or less it's the same concept behind the spell I feel it should works)

 

>>> PickIdle

It controls the Idle Animation list, from top to bottom, it will play the first animation which has a satisfied condition. Still on the player it won't work if not in TFC mode, same rules as above.

I admit I didn't spend many efforts to this system, because I had discrepancies on the results (sometimes it was working, other times it was stuck). Digging around in Oblivion posts, I've read more than once sentences like "why are you using the BUGGY pickidle?". I don't know if it was buggy, I don't know if it's still buggy, all I know is that there's a lack of official documentation. So, since the whole animations subject is quite "blurry", I wanted more certainties and I will leave that for future investigations.

 

There are some additional infos on how the engine evaluates some things concerning animations in Oblivion at this link

 

>>> Token

There's some sort of automatic pickidle inside the engine itself. You can see it when you add an animation on the Animation Idle List and you don't put a condition. The animation on top will lead to all the actors playing that animation when you will go in game.

For the same principle, you can add by script a peculiar item to the player's inventory (so called "token") and use a GetItemCount condition inside the animation. At that point, when your script will add that token, your character will start playing that animation.

NOTE: the token system will work only if you placed your animation branch on top of the other ones. If you don't, and for example you place it on bottom, just before Loose animations, another vanilla will be evaluated before yours (I suspect is GeneralIdles branch)

 

Some tries I did led to bugs in this. Generally, this is one of the most common things I noticed:

I added a token -> Animation started

I added another token, whose condition was satisfied above on the list -> animation didn't change

I forced a pickidle by console -> animation changed

I removed the token by console -> nothing changed

I forced a pickidle by console -> nothing changed

The only way to reset it was forcing a reset (I'll explain later the many ways to force it). Also, I was closing the console every step, even trying to TFC to see if something else was changing.

It also happened that playing too much with different tokens all together the animation system broke (busy animation) until I resetted it. But I never had these problems if I was correctly exchanging tokens (i.e. by script, I add a token - this triggers an animation - I remove the token and add a different one - new animation trigger)

 

Invoking an AnimGroup

It can be done by script or console with playgroup name_of_the_group -parameter-

It follows completely different laws compared to Special Idles (which, by the way, they still should be a sub group of AnimGroup)

The first noticiable thing is that it can be invoked in any moment, I don't need to be in TFC.

The second noticiable thing is that it stacks with Special Idles, following certain rules (I'll explain later)

Third, they are not configurable or they can't be added as we can do with common Special Idles, this lead to my big displeasure that we can't stack 2 custom animations together without replacing vanilla.

Groups require certain specific conditions, which are hard-coded. For example you can't reload a weapon if you are not wielding one.

 

I attached at the end an example on mixing SpecialIdles with AnimGroups, based by bone priorities.

 

Different groups can be played at the same time and they will stack together, following some rules, but only if they are part of a different group. So for example you can run (movement group) and fight (weapon group) but you can't walk and run together or you can't reload and fight togheter. IN THE SAME WAY, YOU CAN PLAY A SPECIAL IDLE WHILE YOU ARE PLAYING A ANIMGROUP, BUT YOU CAN'T PLAY 2 DIFFERENT SPECIAL IDLES TOGETHER SINCE THEY'RE IN THE SAME GROUP.

 

Something more about Groups of Animations

The name of the group is, in nifskope, on the name field in the NiControlloerSequence root on top.

If you are going to do a Special Idle, you can't call it LoversLab or it won't trigger ingame.

But you can call it SpecialIdle_LoversLab for example

Other GroupAnims have similar names, based by the actions that they trigger, so for example a Forward AnimGroup will be called Forward. even its file is placed in a certain location and must have a certain name (if I remember well it is mt+action, so mtforward for example, but I should check)

 

But... if you make a Special Idle and you will call it Forward, it won't be used as a AnimGroup, because when you create a special idle in the Idles branch, automatically you will do a Special Idle, no way to go against it, its path will be under character\male\idleanims\etc.etc. and it's hardcoded. Do you want to do an AnimGroup? well then you will have to call the file in that certain way, the nif in that certain way, and place it in a certain path: SO YOU WILL DO A VANILLA REPLACER. You also CAN'T put an AnimGroup in a different path and assume it will be played as an AnimGroup because the game won't take it. If you are wondering what means when Bethesda guide say "it was demostrated that it's possible to replace one AnimGroup blablabla" but unfortunally the link is dead, well that is a script on a spell which check if the AnimGroup of the reloading is playing, in that case it replaces it with a Special Idle which takes priority over it.

Anyway, you can see more details about AnimGroups inside the Animation tab of the NPCs. Also, when you preview one of these animations, you will see below which group is actually playing, so you can understand which animation replaces another one (i.e. reload is in the same group of shoot, they both are Weapon group, so they both can't be triggered together, one will replace the other one)

 

Stacking different animations

Animations in different groups will stack together CONCERNING BONE PRIORITIES. So for example if you are running and you shoot with your rifle, your arms will follow the rifle because their bones have a higher priority. The shoot animation will have high priority on arms and low priority on legs, so that you still will be able to move.

When you are not doing anything, you are currently playing Idle. Idle is not Special Idle... Idle is mtidle and it's inside the path of AnimGroups, and it has low priority on every bone: if it wasn't so you weren't able to move.

Bone priorities can be decided inside Controlled Blocks (the field is called Priority) in Nifskope or inside Constraints in Buttom Window in Blender.

 

NOTE: there's a ... bug? which I found many times in the past modifying vanilla animations. Inside Blender, you move a shoulder of 10 degrees, when you play the animation you will see that shoulder doing a circle in the opposite direction. I tried in many ways to control that, for example rotating of -350 degrees etc. But then surfing around the web I found some explanations. THIS IS NOT TESTED BECAUSE I NEVER HAD ANOTHER CHANCE, BUT I'LL DO THE FIRST TIME THIS WILL HAPPEN AGAIN. I found that there's some kind of bug during the import of the Constraints, and the consequence are those weird movements in some bones. The solution was removing the Constraint (so I assume later you will have to tweak it on Nifskope?). Anyway, I'll test it the next time I'll have this bug.

This is a reference from a website about that (bug?)

"But the information in the below post is still good, to make animators aware of the bad rotation risks if they choose to import Null constraints, a work-around for fixing those bad rotations, information about bone priorities, and information on the new PYFFI scripts."

And another person was saying that he always solved that removing the Constraint in Blender. Take these infos as they are.

 

Text Data

It is a plain text which contains some extra informations on how the animation interacts with the game. The most common ones you can find on Special Idles are Start, End, StartLoop, EndLoop. You can play a sound with Sound, or you can attach a weapon with Attach (on combat Animgroups for example). If you open vanilla you can see them often, for example the npc smoking has a Sound text data, you will hear him smoking in game. I THINK the name you must put in that case is the GECK name, but I tried once to replace it with a custom and it wasn't working, I'm wondering if it needs a specific path, it deserves more investigations.

 

These datas interact directly with the engine. I mean, ... do you know that Loop field, where you can flag as Loop Forever, inside the Idle Animations branch? Well, that field will be gray if you don't have the StartLoop and EndLoop text data, so you won't be able to loop the animation (Cycle Loop is another thing, It's not a loop, I'll write later)

You can add textdatas in Blender inside the Text field, opening the Anim text (thank you DManxx) or you can modify it in nifskope on the last branch, which is called NiKeyTextExtraData.

 

Example (because I'm getting lost in this explanation...): the Loop forever check is greyed in your GECK for your animation.

So... open the kf in nifskope, go in the last branch, you will find a field called Num Text Keys, this contains the number of text data your animation has. So for example let's say it is 2, probably you only have a Start and a End field. You can see these fields just below that, they are called Text Keys, just open them and expand. The two strings that interest you are Time and Value. All you have to do is changing that 2 in 4, then click on the green arrows (it will refresh), so you will see now the Text Keys are 4. You can now edit them properly. Let me attach some pictures...

 

z748nlwbkfz3zmh4g.jpg

 

smqqkja194z0uuw4g.jpg

 

usgphs9ct9ew8dg4g.jpg

 

After you do that, you will see in real time that the check inside the GECK will become avaiable again... so it reads directly that info inside the file.

 

Note: see how the pre-existing fields were lowercase while I wrote StartLoop. It doesn't matter, the engine will understand. BUT when I wrote the new end text data in the fourth Data Key, I wrote lowercase so it didn't create a new different block on the index.

Also, the end time is written in seconds (while in Blender it is in number of frames, see below), you can achieve this value in the NiControllerSequence root, the Stop time. You can find the time you need for other datas with a mathematical operation, something like this:

 

frames : frame when something must happen = total seconds : x

 

So for example if you want to trigger an event by text data at the frame 15, and your animation is 30 frames and leasts 1 second:

 

30 : 15 = 1 : x        x = 0.5 seconds

 

You will notice that there's a discrepancy of 1 frame between Blender and the time, but that's another story, we're speaking about 33 milliseconds, so it doesn't care that much in my opinion. Or you can simply do your animations of frames+1, you know why.

 

Blender: writing TextDatas in Blender is done in this way, with a Slash on it

 

2k416up769sxr7o4g.jpg

 

IMPORTANT:

Text datas are written in a chronological order, which starts with "start" and ends with "end".

Another thing... if you still don't know, in Nifskope when you want to modify a number which is an index of an existing block, and you want to replace it with a new string so that a new index is created, you must right click - Edit string index and then write it there. As the case if you miss the startloop.

 

Some more infos on the Idle Animation Tab on the GECK menu:

There's a ... strange dropdown menu, that allows you to specify the group. What's that? well, I did some tries and even if it needs more experiments this is what I found for now.

This doesn't make a Special Idle working in a different group (so that you could stack it with another Special Idle for example), this decides in which way that Special Idle will replace an existing AnimGroup, following the bone priority rules.

So, THEORETICALLY, if your special idle is classified as weapon, it should merge with the other AnimGroups following the bone priority properties only for the bones involved in the Weapon group (so... arms?)

As I said it needs more investigation because I didn't find easy ways to try that, but on the few ones I did it's essentially what happened.

There are some interesting infos at this link but I had some troubles in understanding everything.

 

...

Now what...

...

 

Oh yes, let's talk about Facial Animations.

For the above statements, I should already understand that since 2 Special Idles can't play together, and since a FE is added as any other Special Idle inside the Idle Animation branches, it shouldn't be possible to trigger them.

So why people can trigger a FE on groovatron and then trigger a SO animation? But, mainly, why the contrary doesn't happen?!?

 

This is some sort of exception I can't fully understand, but I can say that a FE is some sort of glitch. Here's what I found.

 

Cycle Loop and Cycle Clamp

If an animation is Clamp, it means that when it loops it won't start again from the first frame, but it will stick on the last frame.

If it's Loop, it will start from the begin.

If it's Reverse, it will do forward and backward.

Now these values depend by how long is the animation and the loop itself (we're speaking about kf, ignore the GECK for now)

So for example, if the animation starts at 0, and ends at 8, and we put start loop at 0 and end loop at 2, it will be repeated 4 times if it's CYCLE_LOOP, It will be repeated once and then stick on the last frame for 6 seconds if it's CYCLE_CLAMP, it will be repeated twice back and forth if it's CYCLE_REVERSE.

Interesting link

 

And here some practical examples on how this "conflicts" in some ways with my NV

- Cycle Clamp on an animation which has not all the bones involved (not all the controlled blocks exported, I don't know which ones specifically create this issue but I feel it is Bip01 Non Accuum): instant CTD at the end of the animation. It doesn't CTD with Loop.

- Cycle Clamp on an animation with all the bones: animation sticks on the last frame. Another playidle WON'T WORK, the system is "busy" until I don't reset it in some ways (see below). I ASSUME that a script wouldn't even return a "yes the animation is playing", but I need to test it.

- Cycle Clamp on facial animation: animation sticks on the last frame, another playidle WILL WORK, the system isn't busy (but I broke it more than a time mixing some tries by console, can't say the exact sequence)

 

Said that, I think you can see that there's something... "weird" on that.

The Blessed Purple Doctasax gave me a good clue on that. He had problems in stopping the vanilla sweeping animation, but he could stop the Groovatron sweeping animation. I took a look, the files are IDENTICAL. The only difference, and it's very important, vanilla is setted as Clamp, Groovatron is setted as Loop.

So, it seems that a Clamp isn't possible to be stopped invoking a second animation, the game answers that it's busy, you only can force a reset... I know that the vanilla LooseSweeping is setted as it has to act from 3 to 5 loops before than THE GECK will force it to stop.

 

Now these are pure assumptions, I still have to understand it properly.

On other tries I did, it seems that the FE are the only clamps who can play without a Bip 01 Accuum and don't CTD, they can put an expression in your face AND then allow you to invoke another Special Idle (it means the expression is a stuck animation, but the system doesn't mark as "busy", I assume it checks other bones, but still, these are only my assumptions), so essentially it's like if a FE morphs your face but the game doesn't know that and this will allow you to trigger a second Special Idle. The contrary doesn't happen because the system sees that you are playing a Special Idle and it will interrupt it to play the FE (which is another special idle, let's don't forget that).

 

OPEN BRACKET

While this could be very bad explained but in my mind I can find some sense, there's a thing that still doesn't make sense for me. In some circumstances the FE triggers and will go off after few seconds. This was seen by Panthercom but I knew what he was meaning because I already have seen that too. We both had SO installed. I can say that I never had that issue with Groovatron alone, but also I don't know how FE interact with SO itself, I mean, did you create new branches and copied the files? or were you using the original ones? did you move the branches from top to bottom? Did you mark them as Loop instead that Clamp? since I didn't check anything about that, for now I will stop, but I think these are the only things to check when a FE doesn't work as in Groovatron. Oh yes, because I forgot to write that, putting a FE from Clamp to Loop will have that effect, it will reset after few seconds.

CLOSE BRACKET

 

So... why Groovatron stops facial animations? it doesn't, it replaces it with a resetted facial animation, if you open the 0reset.kf you can see it, as he setted all the avaiable morphs (ah, big ah, etc.) to 0 power. That's the same method I found in other posts around, when you introduce a FE in an animation you should set its power to 0 when you finish that animation.

 

But generally... how do I stop a Special Idle? ...

There's still some blur on it, need to do more tries.

But the theory is that I invoke another SpecialIdle, even empty

Taking a look at the Groovatron reset.kf, it contains only the Bip01 Non Accuum set with the highest priority, that bone is set at the common Z which is around 65. So essentially that Special Idle doesn't do anything else than setting my player on the common Z.

I found another interesting post where a guy was "playing dirty" with the animations: he was never creating a loop animation, he was setting the end value to <float> (which is some millions of years), so the animation was playing indefinetely as if it was looping. To stop it, he just needed to invoke the same animation and that was erasing it. He was also saying that the GECK wasn't liking that solution and was putting a warning on that animation, but he never had downsides.

 

Mixing invocations of Special Idles and AnimGroups, I managed to get stuck many times. For example, a Special Idle on all the bones, set as Loop inside the GECK, had the result to stuck my player in that idle. Manually invoking other anim groups I couldn't change the animation, so for example invoking a Forward didn't have as result the player walking, because my bones had higher priority than the walk, but still the player was "moving" forward (but not animated)

 

So here some resets i usually do:

- I'm playing a Special Idle - I can invoke reset.kf - invoking a Forward will stack - invoking playgroup idle 1 doesn't reset the Special Idle (but reset the AnimGroups, so I'll see the Special Idle still playing)

- I'm playing an AnimGroup - invoking playgroup idle 1 will reset it

- And the force reset, the most important I found: I played with the animations at the point that now the system doesn't respond anymore, animations (like a Clamp for example) are stuck - I invoke playgroup Equip 1 which won't equip the animation, but at this point it will unstuck the R, doing that it will equip the weapon and it will reset every animation. Note that when I manage to get animations stuck, and it happened even simply playing around with Groovatron, this procedure always solved it, it's the only real "force reset" I found. Oh, Equip could also be Holster, it's the same. I tried with other movement AnimGroups and they weren't working, I think the only one that really resets it is a combat group, but if I don't wield a weapon equip/holster are the only I can think about.

 

Another random but very useful information on Special Idle

If when you play a Special Idle you will see your unequipped weapon moving from it's actual point to "inside your body", it is because you exported the Weapon node. To correct that, you should go in Blender, select that bone (which is near the hand usually, but you can see it easily in Action Editor for example), go in Edit mode and erase it, then re-export (or I think you can simply hide it and it shouldn't be exported). I already checked many vanilla animations, they usually miss that node, so I really think it has not to be exported. No downside detected. I still didn't find a way to erase it directly by Nifskope.

 

Update - Animgroups and items (1404)

Items, like furnitures etc. they too can play Animgroups. A classical example is the NV grinding wheel. They have Text Datas and ControllerSequence not very different from .kf.

As experiment, I took the grinding wheel mesh and I created 3 different items: a furniture (the gray icons, like a chair), a static (violet icon) and an activator (white icon), and I pointed to the same grinding wheel mesh.

As result, clicking on them ingame and invoking playgroup forward 1 had the effect to animate the mesh in all the 3 cases. So the engine doesn't make difference among them.

For NPCs the animation files must be placed in a specific path, for the items it can be inside the nif itself, so I wondered if the engine really needed a specific alias to invoke them even in this case (i.e. forward). I tried to change its name by nifskope, from "forward" to "spin", but the result is that the engine won't invoke the animation. It really needs to use some specific words as parameters or it won't work even if the animation is inside the nif itself.

 

Animgroups - Funny discovery

When listing the avaiable AnimGroups, FO3 Beth guide writes about Stagger, which is not used but still it's present. So I've placed an animation inside the animgroup path, I called it mtstagger (this is not important), I called it Stagger on nifskope (THIS, is important) and then I invoked it ingame with Playgroup Stagger 1: it was working :)

This means I can add a custom Stagger animation and invoke it by script when I want, it could even stack with other AnimGroups. If only there was the possibility to add more of them...

 

Last discovery (0205)

Thanks to Jaam I had the complete list of AnimGroups, it shows there are some unused that can be used to stack animations.

Excluding the common ones, which are of course untouchable, here's some new ones that can be used because I assume they're unused in vanilla:

- Dodge: dodgeforward/back/right/left, it's a movement AnimGroup and works fine, already tested

- As I already stated, Stagger. Has some limitations, it seems falling back to Forward, still understand how it really works. I solved triggering playgroup idle 1, but that was working on tfc

- Stomp

Here's complete list:

 

 

aIdle_0
aDynamicidle
aSpecialidle
aForward
aBackward
aLeft_0
aRight_0
aFastforward
aFastbackward
aFastleft
aFastright
aDodgeforward
aDodgeback
aDodgeleft
aDodgeright
aTurnleft
aTurnright
aAim
aAimup
aAimdown
aAimis
aAimisup
aAimisdown
aHolster
aEquip
aUnequip
aAttackleft
aAttackleftup
aAttackleftdown
aAttackleftis
aAttackleftisup
aAttackleftisdown
aAttackright
aAttackrightup
aAttackrightdown
aAttackrightis
aAttackrightisup
aAttackrightisdown
aAttack3
aAttack3up
aAttack3down
aAttack3is
aAttack3isup
aAttack3isdown
aAttack4
aAttack4up
aAttack4down
aAttack4is
aAttack4isup
aAttack4isdown
aAttack5
aAttack5up
aAttack5down
aAttack5is
aAttack5isup
aAttack5isdown
aAttack6
aAttack6up
aAttack6down
aAttack6is
aAttack6isup
aAttack6isdown
aAttack7
aAttack7up
aAttack7down
aAttack7is
aAttack7isup
aAttack7isdown
aAttack8
aAttack8up
aAttack8down
aAttack8is
aAttack8isup
aAttack8isdown
aAttackloop
aAttackloopup
aAttackloopdown
aAttackloopis
aAttackloopisup
aAttackloopisdown
aAttackspin
aAttackspinup
aAttackspindown
aAttackspinis
aAttackspinisup
aAttackspinisdown
aAttackspin2
aAttackspin2up
aAttackspin2down
aAttackspin2is
aAttackspin2isup
aAttackspin2isdown
aAttackpower
aAttackforwardpower
aAttackbackpower
aAttackleftpower
aAttackrightpower
aAttackcustom1power
aAttackcustom2power
aAttackcustom3power
aAttackcustom4power
aAttackcustom5power
aPlacemine
aPlacemineup
aPlaceminedown
aPlacemineis
aPlacemineisup
aPlacemineisdown
aPlacemine2
aPlacemine2up
aPlacemine2down
aPlacemine2is
aPlacemine2isup
aPlacemine2isdown
aAttackthrow
aAttackthrowup
aAttackthrowdown
aAttackthrowis
aAttackthrowisup
aAttackthrowisdown
aAttackthrow2
aAttackthrow2up
aAttackthrow2down
aAttackthrow2is
aAttackthrow2isup
aAttackthrow2isdown
aAttackthrow3
aAttackthrow3up
aAttackthrow3down
aAttackthrow3is
aAttackthrow3isup
aAttackthrow3isdown
aAttackthrow4
aAttackthrow4up
aAttackthrow4down
aAttackthrow4is
aAttackthrow4isup
aAttackthrow4isdown
aAttackthrow5
aAttackthrow5up
aAttackthrow5down
aAttackthrow5is
aAttackthrow5isup
aAttackthrow5isdown
aAttack9
aAttack9up
aAttack9down
aAttack9is
aAttack9isup
aAttack9isdown
aAttackthrow6
aAttackthrow6up
aAttackthrow6down
aAttackthrow6is
aAttackthrow6isup
aAttackthrow6isdown
aAttackthrow7
aAttackthrow7up
aAttackthrow7down
aAttackthrow7is
aAttackthrow7isup
aAttackthrow7isdown
aAttackthrow8
aAttackthrow8up
aAttackthrow8down
aAttackthrow8is
aAttackthrow8isup
aAttackthrow8isdown
aCounter
aStomp_0
aBlockidle
aBlockhit
aRecoil
aReloadwstart
aReloadxstart
aReloadystart
aReloadzstart
aReloada
aReloadb
aReloadc
aReloadd
aReloade
aReloadf
aReloadg
aReloadh
aReloadi
aReloadj
aReloadk
aReloadl
aReloadm
aReloadn
aReloado
aReloadp
aReloadq
aReloadr
aReloads
aReloadw
aReloadx
aReloady
aReloadz
aJama
aJamb
aJamc
aJamd
aJame
aJamf
aJamg
aJamh
aJami
aJamj
aJamk
aJaml
aJamm
aJamn
aJamo
aJamp
aJamq
aJamr
aJams
aJamw
aJamx
aJamy
aJamz
aStagger
aDeath
aTalking
aPipboy_0
aJumpstart
aJumploop
aJumpland
aHandgrip1
aHandgrip2
aHandgrip3
aHandgrip4
aHandgrip5
aHandgrip6
aJumploopforward
aJumploopbackward
aJumploopleft
aJumploopright
aPipboychild
aJumplandforward
aJumplandbackward
aJumplandleft
aJumplandright

 

 

 

 

So, essentially, them all can be triggered by Playgroup. You put a kf inside _male (or _male\locomotion), you call the file whatever you want, then you only need to change it on the kf header using nifskope (the one you call SpecialIdle when you do them), calling it exactly with one of these parameters above here. Well not exact, the "a" in front is not involved, remove it, as for the "_0" at end when it's present

 

What else... I think that's all. And that's more I could ever figure at start, I really think it could open nice new possibilities for modding

Link to comment

A "contributor" should be in the air. Also her machinima post/tutorial was utterly interesting even for inexperienced users and useful. Anyway, glad to know this is an excellent work, already saved in the category future nightmares/what's next, of course. ;)

 

 

EDIT

EDIT: Was I confused when I wrote this? ....

 

I actually have interpreted your words in the way "No, Victoria, it's not the horse that is outstanding, this tutorial is" in reference to what I wrote in the first comment. Lol.

 

Anyway, glad to see A.J. with the Contributor title now, as I hoped ;)

Congrats!

Link to comment

Archived

This topic is now archived and is closed to further replies.

  • Recently Browsing   0 members

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

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue. For more information, see our Privacy Policy & Terms of Use