From the sound of things you are pretty much there or thereabouts

As you know, PSYS_SRC_TARGET_KEY is the parameter that has to be passed a key of the intended target, and also the PSYS_PART_TARGET_POS_MASK flag has to be set.
The value that you pass PSYS_SRC_TARGET_KEY can be obtained from any function or combination of functions that returns a key.
So you have already used llGetKey() & llGetOwner() but you could also use, say. llDetectedKey(0) from within a touch_start or sensor, eg:
target = llDetectedKey(0);
or even target towards a specific linked-prim, eg:
target = llGetLinkKey(9);
or a random linked-prim within the link-set, eg:
target = llGetLinkKey(llFloor(llFrand(llGetNumberOfPrims())));
The point is, so long as PSYS_SRC_TARGET_KEY is passed a valid key, and that PSYS_PART_TARGET_POS_MASK is set, then the particle stream will attempt to direct towards that target (all other things being equal: that is, range and other llParticleSystem parameters also have a bearing, but putting them aside for one moment for clarity)
The following example script gives an indication of how this might be used.
Note that PSYS_SRC_TARGET_KEY is passed the key value held within variable "target" and that PSYS_PART_FLAGS is passed a value of '64' (which sets PSYS_PART_TARGET_POS_MASK ). In this example PSYS_PART_TARGET_LINEAR_MASK has also been set, having a value of '128'. PSYS_PART_FLAGS is therefore passed the sum of these two, '192'.
The script does a number of things:
1) On compile (state_entry) it sets the target to a random prim within the set and fires off llParticleSystem() every five seconds using a timer. This random prim will remain the target until:
a) the object is touched, in which case the person touching the object becomes the target (touch_start)
or
b) a sensor detects an Agent with 5.0m of the object, in which case that detected agent become the target (sensor)
2) when no Agent is detected, the target reverts to being a random prim within the set ( non_sensor)
key target;
ParticleStart()
{
llSay(0, (string)target);
llParticleSystem([
PSYS_PART_START_SCALE,<0.3, 0.6, 0.0>,
PSYS_PART_END_SCALE,<0.0, 0.6, 0.0>,
PSYS_PART_START_COLOR,<0.3, 1.20, 0.0>,
PSYS_PART_END_COLOR,<1.0, 0.0, 0.3>,
PSYS_PART_START_ALPHA,1.0,
PSYS_PART_END_ALPHA,0.90,
PSYS_SRC_BURST_PART_COUNT,1,
PSYS_SRC_BURST_RATE,0.0,
PSYS_PART_MAX_AGE,1.25,
PSYS_SRC_MAX_AGE,2.3,
PSYS_SRC_PATTERN,8,
PSYS_SRC_BURST_RADIUS,0.05,
PSYS_SRC_ANGLE_BEGIN,0.0,
PSYS_SRC_ANGLE_END,0.017453,
PSYS_SRC_OMEGA,<0.0, 0.0, 0.0>,
PSYS_SRC_ACCEL,<0.0, 0.0, 0.0>,
PSYS_SRC_BURST_SPEED_MIN,0.01,
PSYS_SRC_BURST_SPEED_MAX,0.03,
//target parameter is passed a key
PSYS_SRC_TARGET_KEY, target,
//the value of PSYS_PART_TARGET_POS_MASK is '64' & //PSYS_PART_TARGET_LINEAR_MASK is '128' so PSYS_PART_FLAGS is passed '192'
PSYS_PART_FLAGS, ( 192 ) ]);
}
default
{
state_entry()
{
llSetTimerEvent(5.0);
target = llGetLinkKey(llFloor(llFrand(llGetNumberOfPrims())));
llSensorRepeat("",NULL_KEY,AGENT,5.0,PI,1.0);
}
touch_start(integer touches)
{
target = llDetectedKey(0);
}
sensor(integer number)
{
target = llDetectedKey(0);
}
no_sensor()
{
target = llGetLinkKey(llFloor(llFrand(llGetNumberOfPrims())));
}
timer()
{
ParticleStart();
}
}
Hope that helps
