if(!active && stop_timeout && t>=stop_timeout)
{
release_blocks(cur_blocks_end, blocks.end());
- end_of_route = false;
stop_timeout = Time::TimeStamp();
}
void Train::turnout_path_changed(Track &track)
{
for(list<BlockIter>::iterator i=blocks.begin(); i!=blocks.end(); ++i)
- if((*i)->get_turnout_id()==track.get_turnout_id())
- {
- if(!reserving)
- check_turnout_paths(false);
- else if(i==clear_blocks_end)
- ++clear_blocks_end;
- }
+ if((*i)->get_turnout_id()==track.get_turnout_id() && !reserving)
+ check_turnout_paths(false);
}
void Train::halt_event(bool h)
reserve_more();
}
-unsigned Train::reserve_more()
+void Train::reserve_more()
{
- if(!active || blocks.empty())
- return 0;
+ if(!active || blocks.empty() || end_of_route)
+ return;
BlockIter start = blocks.back();
if(nsens>0)
dist += (*i)->get_path_length(i->entry());
}
-
- if(end_of_route)
- return nsens;
list<RouteRef>::iterator cur_route = routes.begin();
advance_route(cur_route, *start.track_iter());
list<BlockIter>::iterator good_end = blocks.end();
Track *divert_track = 0;
bool try_divert = false;
- unsigned good_sens = nsens;
- float good_dist = dist;
Train *blocking_train = 0;
BlockList contested_blocks;
SetFlag setf(reserving);
- while(good_sens<3 || good_dist<min_dist || !contested_blocks.empty())
+ while(1)
{
BlockIter last = block;
block = block.next(cur_route!=routes.end() ? cur_route->route : 0);
- if(!block)
+ if(!block || block->get_endpoints().size()<2)
+ {
+ if(!blocking_train)
+ good_end = blocks.end();
break;
+ }
TrackIter track = block.track_iter();
if(!blocking_train)
{
good_end = blocks.end();
- good_sens = nsens;
- good_dist = dist;
end_of_route = true;
}
break;
}
}
- else if(!routes.empty() && routes.front().route->has_track(*track))
- cur_route = routes.begin();
- if(block->get_endpoints().size()<2)
+ if(block->get_turnout_id() && !last->get_turnout_id())
{
- if(!blocking_train)
- {
- good_end = blocks.end();
- good_sens = nsens;
- good_dist = dist;
- }
- break;
+ /* We can keep the blocks if we arrive at a turnout from a non-turnout
+ block. Having a turnout block as our last reserved block is not good
+ as it would limit our diversion possibilities for little benefit. */
+ good_end = blocks.end();
+ if(nsens>=3 && dist>=min_dist)
+ break;
}
if(blocking_train)
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();
- good_sens = nsens;
- good_dist = dist;
- }
int other_prio = other_train->get_priority();
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_end = blocks.end();
- good_sens = nsens;
- good_dist = dist;
- }
-
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 */
check_turnout_paths(true);
// Make any sensorless blocks at the beginning immediately current
- while(cur_blocks_end!=blocks.end() && !(*cur_blocks_end)->get_sensor_id())
+ while(cur_blocks_end!=clear_blocks_end && !(*cur_blocks_end)->get_sensor_id())
++cur_blocks_end;
if(try_divert && divert(*divert_track))
- return reserve_more();
-
- return good_sens;
+ reserve_more();
}
void Train::check_turnout_paths(bool set)
if(clear_blocks_end==blocks.end())
return;
- list<RouteRef>::iterator route = routes.begin();
-
for(list<BlockIter>::iterator i=clear_blocks_end; i!=blocks.end(); ++i)
{
- advance_route(route, *i->track_iter());
-
if((*i)->get_turnout_id())
{
TrackIter track = i->track_iter();
const TrackType::Endpoint &track_ep = track->get_type().get_endpoints()[track.entry()];
- int path = -1;
- for(list<RouteRef>::iterator j=route; (path<0 && j!=routes.end()); ++j)
- path = j->route->get_turnout((*i)->get_turnout_id());
- if(path<0)
- path = track->get_active_path();
- if(!(track_ep.paths&(1<<path)))
+ unsigned path = 0;
+ list<BlockIter>::iterator j = i;
+ if(++j!=blocks.end())
{
- list<BlockIter>::iterator j = i;
- if(++j!=blocks.end())
- {
- TrackIter rev = j->track_iter().flip();
- unsigned mask = rev->get_type().get_endpoints()[rev.entry()].paths&track_ep.paths;
- for(path=0; mask>1; mask>>=1, ++path) ;
- }
- else
- return;
+ TrackIter rev = j->track_iter().flip();
+ unsigned mask = rev->get_type().get_endpoints()[rev.entry()].paths&track_ep.paths;
+ for(path=0; mask>1; mask>>=1, ++path) ;
}
+ else
+ return;
- if(path!=static_cast<int>(track->get_active_path()))
+ if(path!=track->get_active_path())
{
if(set)
track->set_active_path(path);
- continue;
+ /* Check again, in case the driver was able to service the request
+ instantly */
+ if(!set || path!=track->get_active_path())
+ continue;
}
}
Block &block = **begin;
blocks.erase(begin++);
block.reserve(0);
+
+ if(begin==blocks.end())
+ end_of_route = false;
}
}