Well, if you're writing WinForms, you could just turn your whole app event based and deal with input the way a normal windows app would: let your app idle waiting for updates, and just go through the motions of a turn until you're ready to idle again.
But I suspect, having a run loop and all, that what you're after is more of a traditional game loop for a turn based game like Civilization. In that case, you need to bear in mind that your logic is turn based, but your game actually isn't.
Here's an outline of what I would normally do:
main() {
while( true ) {
collectInput(); // deal with common code for filling in keyboard queues, determining mouse positions, etc.
preBookKeeping(); // do any other work that needs constant ticks, like updating streaming/sound/physics/networking receives, etc.
runLogic(); // see below
postBookKeeping(); // again any stuff that needs ticking, but would want to take into account what happened in runLogic this frame, e.g. animation/particles/networking transmit, etc
drawEverything(); // any actual rendering actions you need to take
}
}
runLogic() {
// this is where you actually have a statemachine
switch ( state ) {
case WaitingForInput:
// look at the collected input and see if any of it is actionable
case WaitingForOpponent:
// look at the input and warn the player that they are doing stuff that isn't going to work right now e.g. a "It's not your turn!" notification.
// otherwise, use input to do things that might be valid when it's not the player's turn, like pan around the map.
case etc:
// a real game would have a ton more actual states, including transition states, start/end/options screens, etc.
}
}
The idea here is that runLogic() wouldn't actually block, it would just deal with input for the current time step.
Your transition from state to state would make the game appear to be turn based in that at the appropriate states it would appear to be waiting for the player to take action, but in reality your game loop ticks on carrying out animation and rendering duties.
You can hierarchically extend this to your objects: each object would get ticked to let it decide if it needs to take action based on the current state of the game. The trick is similarly to avoid blocking by having states that represent the object waiting for input. When you're in such a state, check the current input for the motivation you're looking for and just do nothing if it's not present, allowing the rest of the game to continue.
The same goes for messaging. Rather than delivering messages immediately between objects and blocking when you get to an object that cannot continue, what you want is to post all messages to a central postmaster, and then once a tick deliver them. Return results the same way, by posting a return message. In this manner, objects that expect a response will automatically be able to wait over any number of ticks where other objects are happily ticking away. You can decouple the frequency of this messaging from your display frame rate by just ticking the postmaster multiple times a frame.
A final note on optimization: it sounds like you'll have to do a lot of ticking and checking of every object just to do nothing, but once you have everything up and running, obvious optimizations should become self evident. For instance, rather than having one object list, split it into two: actively ticking objects that need to reconsider every tick, and dormant objects that won't need to do anything until a suitable message comes along to wake them up. You should find that very few things will really need to watch the world, and that the vast majority will just respond to messages to do their work.