At some point in the thread you've spawned you're checking for the player to "be in a location". Normally, the check you're doing there isn't blocking in itself, so these conditions are checked by the main logic thread. Checked but not waited on. That's the key, every frame if you like, check for the condition being met, if it is, do the "then" case.
How you implement the condition checking is up to you, but usually there's an array/list of things to check against (in code or data) and the resultant state change function or functor.
It sounds like what you're doing is:
while( !condition );
doSomething();
Whereas what you need to be doing is more like:
if( interestedInDoingSomething && condition )
doSomething();
"User clicks on an item The function walkToAndPickUp(item)"
In this case you have a functor called WalkToAndPickup, that is created with the item as an argument, and it ticks until it returns that it's done. Instead of having thread for the fact that you are moving, the object's existence provides the information you need to determine where to walk to and what object to pick up once you get there.
functors.insert( new WalkToAndPickup( item ) );
...
while( gameActive )
{
for functor in functors
{
functor.Update();
if( functor.Done() )
{
functors.remove( functor );
delete functor;
}
}
}
So what you have here is an impementation that inserts a new functor/task into a container of tasks that are always running. If a task (like walktoitem) finishes, then it gets deleted. What you do inside the functor update is up to you, and will mirror the contents of your threaded system, except you will probably want to either spawn a new functor for each stage of your tasks, or have another internal state for controlling what code to run at what point in the task's sequence of events.
an example of what you might write in your functor's update:
update()
{
switch( state )
{
case 0: walkto( item ); if( atItem( item) ) state = 1; break;
case 1: takeitem( item ); if( gotItem( item) ) state = 2; break;
case 2: setAsFinished(); break;
}
}
also, don't forget you can insert new functors in the functor list from inside an update. That's how you can chain your dependencies.