+ if(addr==address)
+ {
+ current_speed = speed;
+ speed_changing = false;
+ pure_speed = false;
+ }
+}
+
+void Train::loco_func_event(unsigned addr, unsigned func, bool state)
+{
+ if(addr==address || (addr==address+1 && loco_type.get_max_function()>4))
+ {
+ if(addr==address+1)
+ func += 4;
+ if(state)
+ functions |= 1<<func;
+ else
+ functions &= ~(1<<func);
+
+ signal_function_changed.emit(func, state);
+ }
+}
+
+void Train::sensor_event(unsigned addr, bool state)
+{
+ if(state)
+ {
+ // Find the first sensor block from our reserved blocks that isn't this sensor
+ list<BlockRef>::iterator i;
+ unsigned result = 0;
+ for(i=rsv_blocks.begin(); i!=rsv_blocks.end(); ++i)
+ if(i->block->get_sensor_id())
+ {
+ if(i->block->get_sensor_id()!=addr)
+ {
+ if(result==0)
+ result = 2;
+ else if(result==1)
+ break;
+ }
+ else if(result==0)
+ result = 1;
+ else if(result==2)
+ result = 3;
+ }
+
+ if(result==1 && i!=rsv_blocks.begin())
+ {
+ // Compute speed and update related state
+ float travel_time_secs = (Time::now()-last_entry_time)/Time::sec;
+
+ if(pure_speed)
+ {
+ if(current_speed)
+ {
+ RealSpeed &rs = real_speed[current_speed];
+ rs.add(travel_dist/travel_time_secs, travel_time_secs);
+ }
+ set_status(format("Traveling %d kmh", get_travel_speed()));
+ }
+
+ travel_dist = 0;
+ float block_len;
+ for(list<BlockRef>::iterator j=rsv_blocks.begin(); j!=i; ++j)
+ {
+ j->block->traverse(j->entry, &block_len);
+ travel_dist += block_len;
+
+ if(j->block->get_sensor_id()==addr)
+ {
+ const Block::Endpoint &bep = j->block->get_endpoints()[j->entry];
+ if(reverse)
+ {
+ Track *track = bep.track->get_link(bep.track_ep);
+ unsigned ep = track->get_endpoint_by_link(*bep.track);
+ vehicles.back()->place(track, ep, 0, Vehicle::BACK_AXLE);
+ }
+ else
+ vehicles.front()->place(bep.track, bep.track_ep, 0, Vehicle::FRONT_AXLE);
+ }
+ }
+ last_entry_time = Time::now();
+ pure_speed = true;
+ accurate_position = true;
+ overshoot_dist = 0;
+
+ // Check if we've reached the next route
+ if(next_route)
+ {
+ const set<const Track *> &rtracks = next_route->get_tracks();
+ for(list<BlockRef>::iterator j=rsv_blocks.begin(); j!=i; ++j)
+ if(rtracks.count(j->block->get_endpoints()[j->entry].track))
+ {
+ route = next_route;
+ next_route = 0;
+ // XXX Exceptions?
+ signal_route_changed.emit(route);
+ break;
+ }
+ }
+
+ // Move blocks up to the next sensor to our current blocks
+ cur_blocks.splice(cur_blocks.end(), rsv_blocks, rsv_blocks.begin(), i);
+
+ // Try to get more blocks if we're moving
+ if(active)
+ {
+ unsigned nsens = reserve_more();
+ if(!nsens && end_of_route)
+ signal_arrived.emit();
+ }
+ }
+ else if(result==3)
+ layout.emergency("Sensor for "+name+" triggered out of order");
+ }
+ else
+ {
+ // Find the first sensor in our current blocks that's still active
+ list<BlockRef>::iterator end = cur_blocks.begin();
+ for(list<BlockRef>::iterator i=cur_blocks.begin(); i!=cur_blocks.end(); ++i)
+ if(i->block->get_sensor_id())
+ {
+ if(layout.get_driver().get_sensor(i->block->get_sensor_id()))
+ break;
+ else
+ {
+ end = i;
+ ++end;
+ }
+ }
+
+ if(end!=cur_blocks.begin())
+ // Free blocks up to the last inactive sensor
+ release_blocks(cur_blocks, cur_blocks.begin(), end);
+ }
+}
+
+void Train::turnout_event(unsigned addr, bool)
+{
+ if(pending_block)
+ {
+ unsigned pending_addr = pending_block->get_turnout_id();
+ bool double_addr = (*pending_block->get_tracks().begin())->get_type().is_double_address();
+ if(addr==pending_addr || (double_addr && addr==pending_addr+1))
+ reserve_more();
+ }
+}
+
+void Train::halt_event(bool h)
+{
+ if(h)
+ accurate_position = false;
+}
+
+void Train::block_reserved(const Block &block, const Train *train)
+{
+ if(&block==pending_block && !train)
+ reserve_more();
+}
+
+unsigned Train::reserve_more()
+{
+ if(!active)
+ return 0;
+
+ BlockRef *last = 0;