Events should not have any logic attached to them; they are merely a message, a technique to tell the interested components of what happened, but how to deal with the event is the responsibility of said components (aka, listeners). In your case, that is your NPC(s).
But I don't understand your argument towards "events not being OO", what makes you believe that? What is it about events that can't be object-oriented?
Now on how to handle events and the process overall, I don't have experience with C# but I've done my share in C++, and here's an approach I repeatedly used, which was flexible enough for my needs:
I had an Event meta-class from which every specific event could subclass (ie, UI events, NPC events, etc). There was also an EventManager that creates and destroys all the events ("Emitters", components that need to trigger events, would call the manager for an instance, ie GameObjects) and most importantly, has the processing queue.
Emitter objects would "hook" the event to the queue, and the EventManager would dispatch them to the "Listeners". Now, a Listener is interested in events, and thus can register itself to certain Events or their types. Once the manager dispatches an event to these listeners, it's up to them to perform the logic related to that event from there on.
Eventually, the design of having an event meta-class from which I have to keep subclassing was not very flexible for me, and it was tedious work, so I went with another approach where I can attach properties arbitrarily to an event object, and the handling component would have to know how to deal with it. This has an impact on performance of course, but it was in a way necessary for me as I triggering and handling event logic in Lua, not C++.
If you are making an RPG game, events and scripting are pretty much the bulk of your game, and you will really need a clean design of these two aspects before you get into coding things. I suggest reading event-handling articles on Gamedev.net for a start.
Finally, I'm not sure if it will be helpful to you, but I posted once about events while I was making a networked game in C++/Lua, the design is probably more complex than you need given the nature of networked games, but you can check it out here anyway.
Update: I will show you an example of how I'd use my system, but I have to be clear first: you are using C# and XNA for a reason, and I can't be mistaken that XNA provides exactly what you need, so I would advise against using my event management system or anyone's for the matter, as mine is tightly coupled to C++ and its templating mechanisms, and might not be of use to you. The framework should give you what you need, so check that out first.
// singleton
class EventManager {
public:
Event* createEvt<EventType*>();
void subscribe(Event*, Listener*);
void hook(Event*);
void update();
}
class Listener {
// tells evt manager we want to listen to these events
void register(Event* someEvtType, Handler* myMethod);
// adds event to the queue (called by the EventManager)
void enqueue(Event* someEvt);
// processes events in the queue
void process();
protected:
// calls every subscribed handler to process the event
// a handler is only a functor that is bound to an event
// when calling "register()"
void dispatch(Event*);
map<Event*, list<Handler*>> myHandlers; // an event could have multiple handlers (methods)
}
class GameObject : public Listener {
}
class NPC : public GameObject {
protected:
void walkTo(NPCEvent_Walk* evt);
void talk(NPCEvent_Talk* evt);
}
// inside wherever you're gonna trigger the event, i presumed on mouseclick here
void InputManager::mouseClicked(MouseEvent* evt) {
// we want the NPC to move
NPCEvent_Walk* evtWalk = EventManager->createEvt<NPCEvent_Walk>();
evtWalk->setX(...);
evtWalk->setY(...);
// and talk
NPCEvent_Talk* evtTalk = EventManager->createEvt<NPCEvent_Talk>();
evtTalk->setText(...);
// when the master queue is empty, these events will be
// dispatched to their registered Listeners which will
// process them on their own terms
EventManager->hook(evtWalk);
EventManager->hook(evtTalk);
}
// as an NPC, i'd like to be notified of NPCEvents
NPC::NPC() {
register(NPCEvent_Walk*, &NPC::walkTo);
register(NPCEvent_Talk*, &NPC::talk);
}
void NPC::walkTo(NPCEvent_Walk*) {
// move it
// ...
// are we done?
// return true;
// if we need more updates, return false and we will be called again
// return false;
}
void NPC::talk(NPCEvent_Talk*) {
// update UI components or whatever
// ...
return true;
}
Clearly, this code will not work as it lacks all implementation details and isn't even syntactically correct, but it should give you an idea. However, as I said above, you shouldn't need to do this if you're using XNA.