]> git.tdb.fi Git - r2c2.git/blobdiff - source/libr2c2/train.cpp
Strip Id tags and copyright notices from files
[r2c2.git] / source / libr2c2 / train.cpp
index 16077ef8e4878823fe406e6098911e2ba6ee0e4b..620931dd0b2333bbd3f64be70f78c4d273d63d34 100644 (file)
@@ -1,10 +1,4 @@
-/* $Id$
-
-This file is part of R²C²
-Copyright © 2006-2011  Mikkosoft Productions, Mikko Rasa
-Distributed under the GPL
-*/
-
+#include <algorithm>
 #include <cmath>
 #include <msp/strings/formatter.h>
 #include <msp/time/units.h>
@@ -55,15 +49,13 @@ Train::Train(Layout &l, const VehicleType &t, unsigned a, const string &p):
        pending_block(0),
        reserving(false),
        advancing(false),
-       controller(new AIControl(*this, new SimpleController)),
-       timetable(0),
+       controller(new SimpleController),
        active(false),
        current_speed_step(0),
        speed_changing(false),
        reverse(false),
        functions(0),
        end_of_route(false),
-       status("Unplaced"),
        travel_dist(0),
        pure_speed(false),
        speed_quantizer(0),
@@ -86,7 +78,7 @@ Train::Train(Layout &l, const VehicleType &t, unsigned a, const string &p):
        layout.get_driver().signal_loco_function.connect(sigc::mem_fun(this, &Train::loco_func_event));
 
        layout.signal_block_reserved.connect(sigc::mem_fun(this, &Train::block_reserved));
-       layout.get_driver().signal_sensor.connect(sigc::mem_fun(this, &Train::sensor_event));
+       layout.signal_block_state_changed.connect(sigc::mem_fun(this, &Train::block_state_changed));
 
        layout.get_driver().signal_halt.connect(sigc::mem_fun(this, &Train::halt_event));
 
@@ -101,7 +93,6 @@ Train::Train(Layout &l, const VehicleType &t, unsigned a, const string &p):
 Train::~Train()
 {
        delete controller;
-       delete timetable;
        for(vector<Vehicle *>::iterator i=vehicles.begin(); i!=vehicles.end(); ++i)
                delete *i;
        layout.remove_train(*this);
@@ -181,10 +172,7 @@ void Train::set_active(bool a)
                reserve_more();
        }
        else
-       {
                stop_timeout = Time::now()+2*Time::sec;
-               set_status("Stopped");
-       }
 }
 
 void Train::set_function(unsigned func, bool state)
@@ -204,15 +192,45 @@ float Train::get_speed() const
        return controller->get_speed();
 }
 
+float Train::get_quantized_speed() const
+{
+       if(speed_quantizer)
+               return speed_quantizer->quantize_speed(controller->get_speed());
+       else
+               return controller->get_speed();
+}
+
 bool Train::get_function(unsigned func) const
 {
        return (functions>>func)&1;
 }
 
-void Train::set_timetable(Timetable *tt)
+void Train::add_ai(TrainAI &ai)
+{
+       ais.push_back(&ai);
+       ai.signal_event.connect(sigc::bind<0>(signal_ai_event, sigc::ref(ai)));
+}
+
+void Train::remove_ai(TrainAI &ai)
+{
+       list<TrainAI *>::iterator i = find(ais.begin(), ais.end(), &ai);
+       if(i!=ais.end())
+               ais.erase(i);
+}
+
+TrainAI *Train::get_tagged_ai(const string &tag) const
 {
-       delete timetable;
-       timetable = tt;
+       for(list<TrainAI *>::const_iterator i=ais.begin(); i!=ais.end(); ++i)
+               if((*i)->get_tag()==tag)
+                       return *i;
+
+       return 0;
+}
+
+void Train::ai_message(const TrainAI::Message &msg)
+{
+       for(list<TrainAI *>::iterator i=ais.begin(); i!=ais.end(); ++i)
+               (*i)->message(msg);
 }
 
 bool Train::set_route(const Route *r)
@@ -412,10 +430,7 @@ void Train::place(Block &block, unsigned entry)
        accurate_position = false;
 
        if(!block.reserve(this))
-       {
-               set_status("Unplaced");
                return;
-       }
 
        blocks.push_back(BlockIter(&block, entry));
        if(reverse)
@@ -442,8 +457,6 @@ void Train::unplace()
 
        for(vector<Vehicle *>::iterator i=vehicles.begin(); i!=vehicles.end(); ++i)
                (*i)->unplace();
-
-       set_status("Unplaced");
 }
 
 bool Train::free_block(Block &block)
@@ -559,15 +572,19 @@ void Train::tick(const Time::TimeStamp &t, const Time::TimeDelta &dt)
 
        Driver &driver = layout.get_driver();
 
-       if(timetable)
-               timetable->tick(t);
+       for(list<TrainAI *>::iterator i=ais.begin(); i!=ais.end(); ++i)
+               (*i)->tick(t, dt);
        controller->tick(dt);
        float speed = controller->get_speed();
+       bool moving = speed>0;
 
        if(controller->get_reverse()!=reverse)
        {
                reverse = controller->get_reverse();
-               driver.set_loco_reverse(address, reverse);
+               bool r = reverse;
+               if(loco_type.get_swap_direction())
+                       r = !r;
+               driver.set_loco_reverse(address, r);
 
                release_blocks(cur_blocks_end, blocks.end());
                reverse_blocks(blocks);
@@ -584,17 +601,12 @@ void Train::tick(const Time::TimeStamp &t, const Time::TimeDelta &dt)
                        driver.set_loco_speed(address, speed_step);
 
                        pure_speed = false;
-
-                       if(speed_step)
-                               set_status(format("Traveling %d kmh", get_travel_speed()));
-                       else
-                               set_status("Waiting");
                }
 
                speed = speed_quantizer->get_speed(current_speed_step);
        }
 
-       if(speed)
+       if(moving)
        {
                if(!active)
                        set_active(true);
@@ -679,12 +691,14 @@ void Train::save(list<DataFile::Statement> &st) const
                        st.push_back((DataFile::Statement("route"), i->route->get_name()));
        }
 
-       if(timetable)
-       {
-               DataFile::Statement ss("timetable");
-               timetable->save(ss.sub);
-               st.push_back(ss);
-       }
+       // XXX Need more generic way of saving AI state
+       for(list<TrainAI *>::const_iterator i=ais.begin(); i!=ais.end(); ++i)
+               if(Timetable *timetable = dynamic_cast<Timetable *>(*i))
+               {
+                       DataFile::Statement ss("timetable");
+                       timetable->save(ss.sub);
+                       st.push_back(ss);
+               }
 }
 
 void Train::control_changed(const Controller::Control &ctrl)
@@ -697,8 +711,11 @@ void Train::loco_speed_event(unsigned addr, unsigned speed, bool rev)
        if(addr==address)
        {
                current_speed_step = speed;
-               if(rev!=reverse)
-                       layout.get_driver().set_loco_reverse(address, reverse);
+               bool r = reverse;
+               if(loco_type.get_swap_direction())
+                       r = !r;
+               if(rev!=r)
+                       layout.get_driver().set_loco_reverse(address, r);
                speed_changing = false;
                pure_speed = false;
        }
@@ -717,9 +734,9 @@ void Train::loco_func_event(unsigned addr, unsigned func, bool state)
        }
 }
 
-void Train::sensor_event(unsigned addr, bool state)
+void Train::block_state_changed(Block &block, Block::State state)
 {
-       if(state)
+       if(state==Block::MAYBE_ACTIVE)
        {
                // Find the first sensor block from our reserved blocks that isn't this sensor
                BlockList::iterator end;
@@ -727,7 +744,7 @@ void Train::sensor_event(unsigned addr, bool state)
                for(end=cur_blocks_end; end!=blocks.end(); ++end)
                        if((*end)->get_sensor_id())
                        {
-                               if((*end)->get_sensor_id()!=addr)
+                               if(&**end!=&block)
                                {
                                        if(result==0)
                                                result = 2;
@@ -745,19 +762,15 @@ void Train::sensor_event(unsigned addr, bool state)
                        // Compute speed and update related state
                        float travel_time_secs = (Time::now()-last_entry_time)/Time::sec;
 
-                       if(pure_speed)
-                       {
-                               if(speed_quantizer && current_speed_step>0)
-                                       speed_quantizer->learn(current_speed_step, travel_dist/travel_time_secs, travel_time_secs);
-                               set_status(format("Traveling %d kmh", get_travel_speed()));
-                       }
+                       if(pure_speed && speed_quantizer && current_speed_step>0 && travel_time_secs>=2)
+                               speed_quantizer->learn(current_speed_step, travel_dist/travel_time_secs, travel_time_secs);
 
                        travel_dist = 0;
                        for(BlockList::iterator j=cur_blocks_end; j!=end; ++j)
                        {
                                travel_dist += (*j)->get_path_length(j->entry());
 
-                               if((*j)->get_sensor_id()==addr && !advancing)
+                               if(&**j==&block && !advancing)
                                {
                                        TrackIter track = j->track_iter();
                                        if(reverse)
@@ -800,7 +813,7 @@ void Train::sensor_event(unsigned addr, bool state)
                else if(result==3)
                        layout.emergency("Sensor for "+name+" triggered out of order");
        }
-       else
+       else if(state==Block::INACTIVE)
        {
                const Vehicle &veh = *(reverse ? vehicles.front() : vehicles.back());
 
@@ -1150,23 +1163,6 @@ float Train::get_reserved_distance_until(const Block *until_block, bool back) co
        return result;
 }
 
-float Train::get_travel_speed() const
-{
-       float speed = 0;
-       if(speed_quantizer)
-               speed = speed_quantizer->get_speed(current_speed_step);
-       else
-               speed = controller->get_speed();
-       float scale = layout.get_catalogue().get_scale();
-       return static_cast<int>(round(speed/scale*3.6/5))*5;
-}
-
-void Train::set_status(const string &s)
-{
-       status = s;
-       signal_status_changed.emit(s);
-}
-
 void Train::release_blocks()
 {
        release_blocks(blocks.begin(), blocks.end());
@@ -1313,8 +1309,6 @@ void Train::Loader::finish()
                TrackIter track = obj.blocks.front().track_iter();
                float offset = 2*obj.layout.get_catalogue().get_scale();
                obj.vehicles.back()->place(*track, track.entry(), offset, Vehicle::BACK_BUFFER);
-
-               obj.set_status("Stopped");
        }
 }
 
@@ -1379,11 +1373,8 @@ void Train::Loader::route(const string &n)
 
 void Train::Loader::timetable()
 {
-       if(obj.timetable)
-               throw InvalidState("A timetable has already been loaded");
-
-       obj.timetable = new Timetable(obj);
-       load_sub(*obj.timetable);
+       Timetable *ttbl = new Timetable(obj);
+       load_sub(*ttbl);
 }
 
 void Train::Loader::vehicle(ArticleNumber art_nr)