I think you are on the right track with an array of tasks, however the tracking of the tasks is a problem, as you say.
I am working on a similar situation where I have multiple references for various instruments and I need to keep track of what role each instrument performs.
My suggestion:
create a global which is a cluster
put in this cluster an array of tasks
add an array of strings
[optional]
create an ENUM, customize it, edit the list of items and create an item for each valve type ("in", "out", etc.) and save it as a Type Def. customized control.
add an array of ENUM
Now when you initialize your system you create an array of tasks. At the same time create an array of strings labelling these tasks, in fact you could cleverly construct these strings like "IN:water", "OUT:water", "IN:blue dye", "OUT:HF", or whatever you need.
Then write both the array of tasks and the array of strings into the global.
Later when you need the valve which controls water output, read the string array from the global, then search the array for the string "OUT:water". (In fact if you have logic which specifies the liquid name and the valve direction you could programmitically construct the search string using the concatenation function.) Then read the tasks array and use the index from the string array search to retrieve the proper task.
This way you don't need to keep track of the order of the tasks, you only need to make sure that when you initialize your program that the tasks and the string descriptions are saved in matching order.
If needed you can put error checking later in your program which will read the tasks array and the strings array from the global and check to see if they are the same length: if they are not, then throw and error and gracefully exit with a dialog.
Best of luck.
Leif Kirschenbaum