namespace Marklin {
-Train::Train(Layout &l, const VehicleType &t, unsigned a):
+Train::Train(Layout &l, const VehicleType &t, unsigned a, const string &p):
layout(l),
loco_type(t),
address(a),
+ protocol(p),
priority(0),
yielding_to(0),
cur_blocks_end(blocks.end()),
controller(new AIControl(*this, new SimpleController)),
timetable(0),
active(false),
- current_speed(0),
+ current_speed_step(0),
speed_changing(false),
reverse(false),
functions(0),
status("Unplaced"),
travel_dist(0),
pure_speed(false),
- real_speed(15),
+ real_speed(layout.get_driver().get_protocol_speed_steps(protocol)+1),
accurate_position(false),
overshoot_dist(false)
{
layout.add_train(*this);
- layout.get_driver().add_loco(address);
+ layout.get_driver().add_loco(address, protocol);
layout.get_driver().signal_loco_speed.connect(sigc::mem_fun(this, &Train::loco_speed_event));
layout.get_driver().signal_loco_function.connect(sigc::mem_fun(this, &Train::loco_func_event));
int route_path = route->route->get_turnout(from.get_turnout_id());
// Check that more than one path is available
- unsigned ep_paths = track->get_type().get_endpoints()[track.entry()].paths;
+ unsigned ep_paths = track.endpoint().paths;
if(!(ep_paths&(ep_paths-1)))
return false;
}
else
{
- const Block::Endpoint &bep = block.get_endpoints()[entry];
+ const Block::Endpoint &bep = block.get_endpoint(entry);
vehicles.back()->place(*bep.track, bep.track_ep, 0, Vehicle::BACK_BUFFER);
}
}
timetable->tick(t);
controller->tick(dt);
float speed = controller->get_speed();
- unsigned speed_notch = find_speed(speed);
+ unsigned speed_step = find_speed_step(speed);
if(controller->get_reverse()!=reverse)
{
reserve_more();
}
- if(speed_notch!=current_speed && !speed_changing && !driver.is_halted() && driver.get_power())
+ if(speed_step!=current_speed_step && !speed_changing && !driver.is_halted() && driver.get_power())
{
speed_changing = true;
- driver.set_loco_speed(address, speed_notch);
+ driver.set_loco_speed(address, speed_step);
pure_speed = false;
- if(speed_notch)
+ if(speed_step)
set_status(format("Traveling %d kmh", get_travel_speed()));
else
set_status("Waiting");
for(BlockList::const_iterator i=blocks.begin(); (!ok && i!=cur_blocks_end); ++i)
ok = (*i)->has_track(*track);
- float d = get_real_speed(current_speed)*(dt/Time::sec);
+ float d;
+ if(real_speed.size()>1)
+ d = get_real_speed(current_speed_step)*(dt/Time::sec);
+ else
+ d = speed*(dt/Time::sec);
if(ok)
{
SetFlag setf(advancing);
if(i!=vehicles.begin())
st.push_back((DataFile::Statement("vehicle"), (*i)->get_type().get_article_number()));
- for(unsigned i=0; i<=14; ++i)
+ for(unsigned i=0; i<real_speed.size(); ++i)
if(real_speed[i].weight)
st.push_back((DataFile::Statement("real_speed"), i, real_speed[i].speed, real_speed[i].weight));
{
if(addr==address)
{
- current_speed = speed;
+ current_speed_step = speed;
speed_changing = false;
pure_speed = false;
}
if(pure_speed)
{
- if(current_speed)
+ if(current_speed_step>0)
{
- RealSpeed &rs = real_speed[current_speed];
+ RealSpeed &rs = real_speed[current_speed_step];
rs.add(travel_dist/travel_time_secs, travel_time_secs);
}
set_status(format("Traveling %d kmh", get_travel_speed()));
// Check if we've reached the next route
if(routes.size()>1)
{
- const set<Track *> &rtracks = (++routes.begin())->route->get_tracks();
+ const Route &route = *(++routes.begin())->route;
for(BlockList::iterator j=cur_blocks_end; j!=end; ++j)
- if(rtracks.count((*j)->get_endpoints()[j->entry()].track))
+ if(route.has_track(*j->track_iter()))
{
routes.pop_front();
// XXX Exceptions?
if(block->get_turnout_id())
{
- const TrackType::Endpoint &track_ep = track->get_type().get_endpoints()[track.entry()];
+ const TrackType::Endpoint &track_ep = track.endpoint();
bool multiple_paths = (track_ep.paths&(track_ep.paths-1));
if(multiple_paths && cur_route!=routes.end() && cur_route->diversion!=block->get_turnout_id())
if((*i)->get_turnout_id())
{
TrackIter track = i->track_iter();
- const TrackType::Endpoint &track_ep = track->get_type().get_endpoints()[track.entry()];
+ const TrackType::Endpoint &track_ep = track.endpoint();
unsigned path = 0;
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;
+ unsigned mask = rev.endpoint().paths&track_ep.paths;
for(path=0; mask>1; mask>>=1, ++path) ;
}
else
float Train::get_real_speed(unsigned i) const
{
+ if(i==0)
+ return 0;
if(real_speed[i].weight)
return real_speed[i].speed;
for(low=i; low>0; --low)
if(real_speed[low].weight)
break;
- for(high=i; high<14; ++high)
+ for(high=i; high+1<real_speed.size(); ++high)
if(real_speed[high].weight)
break;
return 0;
}
-unsigned Train::find_speed(float real) const
+unsigned Train::find_speed_step(float real) const
{
- if(real<=real_speed[0].speed)
+ if(real_speed.size()<=1)
+ return 0;
+ if(real<=real_speed[1].speed*0.5)
return 0;
unsigned low = 0;
unsigned high = 0;
unsigned last = 0;
- for(unsigned i=0; (!high && i<=14); ++i)
+ for(unsigned i=0; (!high && i<real_speed.size()); ++i)
if(real_speed[i].weight)
{
last = i;
}
if(!high)
{
+ unsigned limit = real_speed.size()/5;
if(!low)
{
if(real)
- return 3;
+ return limit;
else
return 0;
}
- return min(min(static_cast<unsigned>(low*real/real_speed[low].speed), 14U), last+3);
+ return min(min(static_cast<unsigned>(low*real/real_speed[low].speed), real_speed.size()-1), last+limit);
}
float f = (real-real_speed[low].speed)/(real_speed[high].speed-real_speed[low].speed);
float Train::get_travel_speed() const
{
- float speed = get_real_speed(current_speed);
+ float speed = get_real_speed(current_speed_step);
float scale = layout.get_catalogue().get_scale();
return static_cast<int>(round(speed/scale*3.6/5))*5;
}
void Train::Loader::real_speed(unsigned i, float speed, float weight)
{
+ if(i>=obj.real_speed.size())
+ return;
obj.real_speed[i].speed = speed;
obj.real_speed[i].weight = weight;
}