#include <msp/strings/format.h>
#include <msp/time/units.h>
#include <msp/time/utils.h>
-#include "aicontrol.h"
#include "beamgate.h"
#include "block.h"
#include "catalogue.h"
#include "driver.h"
#include "layout.h"
-#include "route.h"
#include "simplecontroller.h"
#include "speedquantizer.h"
#include "timetable.h"
#include "trainrouter.h"
#include "vehicle.h"
#include "vehicletype.h"
-#include "zone.h"
using namespace std;
using namespace Msp;
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));
- layout.signal_sensor_state_changed.connect(sigc::mem_fun(this, &Train::sensor_state_changed));
-
layout.get_driver().signal_halt.connect(sigc::mem_fun(this, &Train::halt_event));
controller->signal_control_changed.connect(sigc::mem_fun(this, &Train::control_changed));
+
+ allocator.signal_advanced.connect(sigc::mem_fun(this, &Train::advanced));
+ allocator.signal_rear_advanced.connect(signal_rear_advanced);
}
Train::~Train()
bool Train::is_block_critical(const Block &block) const
{
- return get_reserved_distance_until(&block)<=controller->get_braking_distance()*1.3;
+ if(allocator.is_block_current(block))
+ return true;
+
+ BlockIter i = check_critical_blocks(&block);
+ return i.block()==█
+}
+
+BlockIter Train::get_last_critical_block() const
+{
+ return check_critical_blocks(0);
}
-BlockIter Train::get_first_noncritical_block() const
+BlockIter Train::check_critical_blocks(const Block *check) const
{
if(allocator.empty())
return BlockIter();
- BlockIter i = allocator.last_current().next();
+ BlockIter i = allocator.last_current();
if(controller->get_speed()==0)
return i;
+ BlockIter last = allocator.last();
+ if(i.block()==last.block())
+ return i;
+
float margin = 10*layout.get_catalogue().get_scale();
float min_dist = controller->get_braking_distance()*1.3+margin;
float dist = 0;
bool sensor_seen = false;
- for(; i->get_train()==this; i=i.next())
+ i = i.next();
+ while(i.block()!=last.block() && i.block()!=check)
{
- if(dist>min_dist && sensor_seen)
- return i;
-
dist += i->get_path_length(i.entry());
if(i->get_sensor_address())
sensor_seen = true;
+
+ if(dist>min_dist && sensor_seen)
+ break;
+
+ BlockIter j = i.next();
+ if(j->get_train()!=this)
+ break;
+
+ i = j;
}
return i;
void Train::refresh_blocks_from(Block &block)
{
if(is_block_critical(block))
- allocator.rewind_to(*get_first_noncritical_block());
+ allocator.rewind_to(*get_last_critical_block().next());
else
allocator.rewind_to(block);
}
{
if(stop_timeout)
{
- stop_timeout -= dt;
+ stop_timeout = max(stop_timeout-dt, Time::zero);
if(stop_timeout<=Time::zero)
- {
allocator.set_active(false);
- stop_timeout = Time::TimeDelta();
- }
}
travel_time += dt;
Driver &driver = layout.get_driver();
+ allocator.tick();
+
bool intent_to_move = false;
for(list<TrainAI *>::iterator i=ais.begin(); i!=ais.end(); ++i)
{
Vehicle &vehicle = *(reverse ? vehicles.back() : vehicles.front());
float d = speed*(dt/Time::sec);
- if(allocator.is_block_current(vehicle.get_placement().get_position(reverse ? VehiclePlacement::BACK_AXLE : VehiclePlacement::FRONT_AXLE)->get_block()))
+ Block &block = vehicle.get_placement().get_position(reverse ? VehiclePlacement::BACK_AXLE : VehiclePlacement::FRONT_AXLE)->get_block();
+ if(allocator.is_block_current(block))
{
SetFlag setf(advancing);
vehicle.advance(reverse ? -d : d);
overshoot_dist += d;
if(overshoot_dist>40*layout.get_catalogue().get_scale())
{
- layout.emergency(name+" has not arrived at sensor");
+ layout.emergency(&block, name+" has not arrived at sensor");
accurate_position = false;
}
}
{
st.push_back((DataFile::Statement("name"), name));
+ const Catalogue &cat = layout.get_catalogue();
for(vector<Vehicle *>::const_iterator i=vehicles.begin(); i!=vehicles.end(); ++i)
if(i!=vehicles.begin())
- st.push_back((DataFile::Statement("vehicle"), (*i)->get_type().get_article_number()));
+ st.push_back((DataFile::Statement("vehicle"), cat.get_name(&(*i)->get_type())));
if(speed_quantizer)
{
st.push_back(ss);
}
+ const VehicleType::FunctionMap &func_map = loco_type.get_functions();
+ for(VehicleType::FunctionMap::const_iterator i=func_map.begin(); i!=func_map.end(); ++i)
+ st.push_back((DataFile::Statement("function"), i->first, static_cast<bool>(functions&(1<<i->first))));
+
// XXX Need more generic way of saving AI state
for(list<TrainAI *>::const_iterator i=ais.begin(); i!=ais.end(); ++i)
{
}
}
-void Train::sensor_state_changed(Sensor &sensor, Sensor::State state)
+void Train::advanced(Block &block, Sensor *sensor)
{
- if(!current_speed_step || state!=Sensor::MAYBE_ACTIVE)
- return;
+ if(!sensor || sensor==block.get_sensor())
+ signal_advanced.emit(block);
- Block *block = sensor.get_block();
- if(!block || block->get_train()!=this)
+ if(!sensor)
return;
- if(last_entry_block && &*last_entry_block!=block)
- {
- for(BlockIter i=last_entry_block.next(); (i && &*i!=block); i=i.next())
- if(i->get_train()!=this || i->get_sensor_address())
- return;
- }
-
- if(dynamic_cast<TrackCircuit *>(&sensor))
+ if(sensor==block.get_sensor())
{
if(last_entry_block && pure_speed && speed_quantizer)
{
float travel_distance = 0;
- for(BlockIter i=last_entry_block; &*i!=block; i=i.next())
+ for(BlockIter i=last_entry_block; &*i!=█ i=i.next())
travel_distance += i->get_path_length(i.entry());
if(travel_distance>0)
}
}
- last_entry_block = allocator.iter_for(*block);
+ last_entry_block = allocator.iter_for(block);
travel_time = Time::zero;
if(!layout.get_driver().is_halted())
{
vehicles.front()->place(track, VehiclePlacement::FRONT_AXLE);
}
}
- else if(BeamGate *gate = dynamic_cast<BeamGate *>(&sensor))
+ else if(BeamGate *gate = dynamic_cast<BeamGate *>(sensor))
{
if(!advancing && vehicles.front()->is_placed())
{
- TrackIter track = allocator.iter_for(*block).track_iter();
- for(; (track && &track->get_block()==block); track=track.next())
+ TrackIter track = allocator.iter_for(block).track_iter();
+ for(; (track && &track->get_block()==&block); track=track.next())
if(track.track()==gate->get_track())
{
if(reverse)
blocks_valid(true)
{
add("blocks", &Loader::blocks);
+ add("function", &Loader::function);
add("name", &Loader::name);
add("quantized_speed", &Loader::quantized_speed);
add("router", &Loader::router);
load_sub(obj.allocator);
}
+void Train::Loader::function(unsigned f, bool s)
+{
+ obj.set_function(f, s);
+}
+
void Train::Loader::name(const string &n)
{
obj.set_name(n);
load_sub(*ttbl, obj.layout);
}
-void Train::Loader::vehicle(ArticleNumber art_nr)
+void Train::Loader::vehicle(const string &n)
{
- const VehicleType &vtype = obj.layout.get_catalogue().get<VehicleType>(art_nr);
+ const VehicleType &vtype = obj.layout.get_catalogue().get<VehicleType>(n);
Vehicle *veh = new Vehicle(obj.layout, vtype);
obj.vehicles.back()->attach_back(*veh);
obj.vehicles.push_back(veh);