EDIT: See my reply below. Right after posting this, I came up with what I think is a much, much better idea than all of this...
While you can always run a control script on a backpack and wait for events, the only event that an item can receive is for incoming speech, and I don't think it's really all that useful for what Kiko needs.
That said, I think it's as simple as this, basically;
First, start off with a property that a) marks the PC as being "controlled" and b) notes the PID of the script doing the control. For ease of understanding, let's just use the CProp "controlled"...
Code:
program controlPC(who)
SetObjProperty(who, "#controlled", GetPID());
...
EraseObjProperty(who, "#controlled");
endprogram
You would then need to hook walk packets, if you intend to prevent the PC from moving themselves while under 'control'. Obviously, this could be very problematic. It's -very- important that if you do this, your walk request hook script be as lean and mean as possible. Just consider how often walk request packets are sent, PER CHARACTER, PER STEP... and know that you should -never- do even a single bit of extra processing in them than absolutely necessary.
However, for your needs, it is necessary. There's no other practical way to prevent them from moving themselves.
So the walk request packet hook should simply check for the presence of the "controlled" CProp on the character. Though normally I would definitely recommend you do so,
in this case I recommend you NOT try to check to make sure a process is actually still running with that PID by use of GetProcess(pid);... because again; we're in a walk request packet hook, and I think that's adding too much processing. You will need to just make sure that the 'controlling' script never exits without clearing it's cprop or, if it does, that there is another way to check to make sure the PID marked in the "controlled" CProp is still running, and remove the CProp if not.
I would definitely put checks in on login, for instance. Or depending on why you need such a thing, maybe the system itself would offer some good times and places to double-check that the player does not have an 'orphan' "controlled" CProp on them. Seriously, though: Don't try to GetProcess() within an already critical, already very-heavily-called packet hook.
So... umm... next; Now that we've got the player unable to control their own movements, the rest is easy as pie, really. Moving a PC step-by-step involves two things; Setting their facing, then moving them to the new location. Well, I say it's easy, but there are possible pitfalls, perhaps.
The thing to keep in mind basically, though; If you move a character to an adjacent spot, all clients will see that as taking a 'step', as if they had really 'walked' there. The PC's player themselves does NOT see it 'correctly' in appearance, but everyone else does,
provided the move was to an adjacent square. The 'step' animation is actually done even if it's not adjacent, but it won't at all look the same. Also, you do need to make sure to get them facing in the correct direction first, so that it looks like they took a step in the proper direction.... the step animation is made to look like they took a step forward, so that stepping animation won't appear correct when they are moved to a space that is 'beside' or 'behind' the character.
You can easily determine the proper facing by testing against either the direction you wish them to step in (no 'testing' really, there), or by testing the changes in x/y from where they are now;
Code:
function SetFacingForMoveTo(who, x, y)
if (who.x==x && who.y==y+1)
who.facing := 0; //north
elseif (who.x==x-1 && who.y==y+1)
who.facing := 1; //North-East
....etc...
endfunction
Then, just move them. But be sure to carefully examine the area to get the 'standable' Z level, using their current Z as the starting point... so that you get them standing on the proper floor of a building (say, if they are on the third floor of a building, if you don't check for standing level starting at their current Z, you may end up moving them down to the ground floor), or so that you don't move them into a wall. There could be some tricks to trying to get that to work, but that's more about determining how and where to walk outside of the NPC functions, which isn't strictly related to 'attaching' a script to a PC.
Incidentally, though... some may be confused by the word 'attach' here; There is already such a term, and yes, scripts can be, and frequently are attached to PCs: when they double-click an item, the script is attached to them until it returns, or calls Detach(); I know that's not what you mean, but it might help to use a different term to describe the concept, to avoid possible confusion.