- if(blocking_train)
- {
- if(block->get_train()!=blocking_train)
- {
- if(blocking_train->free_block(*contested_blocks.back()))
- {
- // Roll back and start actually reserving the blocks
- block = blocks.back();
- cur_route = routes.begin();
- advance_route(cur_route, *block.track_iter().track());
- if(blocking_train->get_priority()==priority)
- blocking_train->yield_to(*this);
- blocking_train = 0;
- continue;
- }
- else
- {
- yield_to(*blocking_train);
- pending_block = contested_blocks.front().block();
- try_divert = divert_track;
- break;
- }
- }
- else
- {
- contested_blocks.push_back(block);
- continue;
- }
- }
-
- bool reserved = block->reserve(this);
- if(!reserved)
- {
- /* 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_end = blocks.end();
-
- if(static_cast<unsigned>(other_entry)==block.entry())
- preceding_train = other_train;
- }
-
- 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 || !other_train->is_active()))
- // We are blocked, but there's a diversion possibility
- try_divert = true;
-
- if(!reserved)
- {
- pending_block = &*block;
- break;
- }
- }
-
- if(block->get_turnout_id())