+ /* We've found another train. If it wants to exit the block from the
+ same endpoint we're trying to enter from or the other way around,
+ treat it as coming towards us. Otherwise treat it as going in the
+ same direction. */
+ Train *other_train = block->get_train();
+ int other_entry = other_train->get_entry_to_block(*block);
+ if(other_entry<0)
+ throw LogicError("Block reservation inconsistency");
+
+ unsigned exit = block.reverse().entry();
+ unsigned other_exit = BlockIter(block.block(), other_entry).reverse().entry();
+ bool entry_conflict = (block.entry()==other_exit);
+ bool exit_conflict = (exit==static_cast<unsigned>(other_entry));
+ if(!entry_conflict && !last->get_turnout_id())
+ {
+ /* The other train is not coming to the blocks we're holding, so we
+ can keep them. */
+ good = last;
+ good_sens = nsens;
+ good_dist = dist;
+ }
+
+ int other_prio = other_train->get_priority();
+
+ if(!entry_conflict && !exit_conflict && other_prio<priority)
+ {
+ /* Ask a lesser priority train going to the same direction to free
+ the block for us */
+ if(other_train->free_block(*block))
+ reserved = block->reserve(this);
+ }
+ else if(other_train!=yielding_to && (other_prio<priority || (other_prio==priority && entry_conflict)))
+ {
+ /* A lesser priority train is coming at us, we must ask it to free
+ enough blocks to get clear of it to avoid a potential deadlock */
+ blocking_train = other_train;
+ contested_blocks.clear();
+ contested_blocks.push_back(block);
+ continue;
+ }
+ else if(divert_track && (entry_conflict || exit_conflict))
+ // We are blocked, but there's a diversion possibility
+ try_divert = true;
+
+ if(!reserved)
+ {
+ pending_block = &*block;
+ break;
+ }
+ }
+
+ if(block->get_turnout_id())
+ {
+ const TrackType::Endpoint &track_ep = track->get_type().get_endpoints()[track.entry()];
+ bool multiple_paths = (track_ep.paths&(track_ep.paths-1));
+
+ if(multiple_paths || !last->get_turnout_id())
+ {
+ /* We can keep the blocks reserved so far if we are facing the
+ points or if there was no turnout immediately before this one.
+ With multiple successive turnouts (as is common in crossovers) it's
+ best to hold at one we can divert from. */
+ good = last;
+ good_sens = nsens;
+ good_dist = dist;
+ }
+
+ // Figure out what path we'd like to take on the turnout
+ int path = -1;
+ for(list<RouteRef>::iterator i=cur_route; (path<0 && i!=routes.end()); ++i)
+ path = i->route->get_turnout(block->get_turnout_id());
+ if(path<0)
+ path = track->get_active_path();
+ if(!(track_ep.paths&(1<<path)))
+ {
+ for(unsigned i=0; track_ep.paths>>i; ++i)
+ if(track_ep.paths&(1<<i))
+ path = i;
+ }
+
+ if(path!=static_cast<int>(track->get_active_path()))
+ {
+ // The turnout is set to wrong path - switch and wait for it
+ pending_block = &*block;
+ track->set_active_path(path);
+ if(pending_block)
+ {
+ block->reserve(0);
+ break;
+ }
+ }
+
+ if(multiple_paths && cur_route!=routes.end() && cur_route->diversion!=block->get_turnout_id())
+ /* There's multiple paths to be taken and we are on a route - take
+ note of the diversion possibility */
+ divert_track = &*track;