]> git.tdb.fi Git - r2c2.git/blobdiff - source/libr2c2/train.cpp
Mark turnout blocks before the next sensor as current
[r2c2.git] / source / libr2c2 / train.cpp
index 78c16c072809ce74f2df57edac7b313d22826342..936f74aa82d6d522bb74a7d500a59eeecea0f2d2 100644 (file)
@@ -1,13 +1,7 @@
-/* $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/core/maputils.h>
+#include <msp/strings/format.h>
 #include <msp/time/units.h>
 #include <msp/time/utils.h>
 #include "aicontrol.h"
@@ -70,7 +64,7 @@ Train::Train(Layout &l, const VehicleType &t, unsigned a, const string &p):
        overshoot_dist(false)
 {
        if(!loco_type.is_locomotive())
-               throw InvalidParameterValue("Initial vehicle must be a locomotive");
+               throw invalid_argument("Train::Train");
 
        unsigned speed_steps = layout.get_driver().get_protocol_speed_steps(protocol);
        if(speed_steps)
@@ -85,7 +79,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));
 
@@ -132,9 +126,9 @@ void Train::add_vehicle(const VehicleType &vt)
 void Train::remove_vehicle(unsigned i)
 {
        if(i>=vehicles.size())
-               throw InvalidParameterValue("Vehicle index out of range");
+               throw out_of_range("Train::remove_vehicle");
        if(i==0)
-               throw InvalidParameterValue("Can't remove the locomotive");
+               throw logic_error("can't remove locomotive");
        delete vehicles[i];
        vehicles.erase(vehicles.begin()+i);
        if(i<vehicles.size())
@@ -149,14 +143,14 @@ unsigned Train::get_n_vehicles() const
 Vehicle &Train::get_vehicle(unsigned i)
 {
        if(i>=vehicles.size())
-               throw InvalidParameterValue("Vehicle index out of range");
+               throw out_of_range("Train::get_vehicle");
        return *vehicles[i];
 }
 
 const Vehicle &Train::get_vehicle(unsigned i) const
 {
        if(i>=vehicles.size())
-               throw InvalidParameterValue("Vehicle index out of range");
+               throw out_of_range("Train::get_vehicle");
        return *vehicles[i];
 }
 
@@ -170,7 +164,7 @@ void Train::set_active(bool a)
        if(a==active)
                return;
        if(!a && controller->get_speed())
-               throw InvalidState("Can't deactivate while moving");
+               throw logic_error("moving");
 
        active = a;
        if(active)
@@ -185,7 +179,7 @@ void Train::set_active(bool a)
 void Train::set_function(unsigned func, bool state)
 {
        if(!loco_type.get_functions().count(func))
-               throw InvalidParameterValue("Invalid function");
+               throw invalid_argument("Train::set_function");
        layout.get_driver().set_loco_function(address, func, state);
 }
 
@@ -327,7 +321,7 @@ bool Train::go_to(const Zone &to)
 bool Train::divert(Track &from)
 {
        if(!from.get_turnout_id())
-               throw InvalidParameterValue("Can't divert from a non-turnout");
+               throw invalid_argument("Train::divert");
        if(routes.empty())
                return false;
 
@@ -401,7 +395,7 @@ bool Train::divert(Track &from)
                if(end!=routes.end())
                        break;
                else if(!diversion->has_track(*track))
-                       throw LogicError("Pathfinder returned a bad route");
+                       throw logic_error("bad diversion");
 
                track = track.next(diversion->get_path(*track));
        }
@@ -429,7 +423,7 @@ const Route *Train::get_route() const
 void Train::place(Block &block, unsigned entry)
 {
        if(controller->get_speed())
-               throw InvalidState("Must be stopped before placing");
+               throw logic_error("moving");
 
        release_blocks();
 
@@ -455,7 +449,7 @@ void Train::place(Block &block, unsigned entry)
 void Train::unplace()
 {
        if(controller->get_speed())
-               throw InvalidState("Must be stopped before unplacing");
+               throw logic_error("moving");
 
        release_blocks();
 
@@ -548,7 +542,7 @@ void Train::free_noncritical_blocks()
        }
 }
 
-int Train::get_entry_to_block(Block &block) const
+int Train::get_entry_to_block(const Block &block) const
 {
        for(BlockList::const_iterator i=blocks.begin(); i!=blocks.end(); ++i)
                if(i->block()==&block)
@@ -583,11 +577,15 @@ void Train::tick(const Time::TimeStamp &t, const Time::TimeDelta &dt)
                (*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);
@@ -609,7 +607,7 @@ void Train::tick(const Time::TimeStamp &t, const Time::TimeDelta &dt)
                speed = speed_quantizer->get_speed(current_speed_step);
        }
 
-       if(speed)
+       if(moving)
        {
                if(!active)
                        set_active(true);
@@ -714,8 +712,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;
        }
@@ -734,9 +735,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;
@@ -744,7 +745,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;
@@ -762,7 +763,7 @@ 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 && speed_quantizer && current_speed_step>0)
+                       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;
@@ -770,7 +771,7 @@ void Train::sensor_event(unsigned addr, bool state)
                        {
                                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)
@@ -813,7 +814,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());
 
@@ -976,7 +977,7 @@ void Train::reserve_more()
                        Train *other_train = block->get_train();
                        int other_entry = other_train->get_entry_to_block(*block);
                        if(other_entry<0)
-                               throw LogicError("Block reservation inconsistency");
+                               throw logic_error("block reservation inconsistency");
 
                        unsigned exit = block.reverse().entry();
                        unsigned other_exit = BlockIter(block.block(), other_entry).reverse().entry();
@@ -1104,6 +1105,8 @@ void Train::check_turnout_paths(bool set)
 
                if(i==clear_blocks_end)
                        ++clear_blocks_end;
+               if(i==cur_blocks_end && !(*i)->get_sensor_id())
+                       ++cur_blocks_end;
        }
 }
 
@@ -1288,7 +1291,7 @@ Train::RouteRef::RouteRef(const Route *r, unsigned d):
 
 
 Train::Loader::Loader(Train &t):
-       DataFile::BasicLoader<Train>(t),
+       DataFile::ObjectLoader<Train>(t),
        prev_block(0),
        blocks_valid(true)
 {
@@ -1322,7 +1325,7 @@ void Train::Loader::block(unsigned id)
        {
                blk = &obj.layout.get_block(id);
        }
-       catch(const KeyError &)
+       catch(const key_error &)
        {
                blocks_valid = false;
                return;
@@ -1349,7 +1352,7 @@ void Train::Loader::block_hint(unsigned id)
        {
                prev_block = &obj.layout.get_block(id);
        }
-       catch(const KeyError &)
+       catch(const key_error &)
        {
                blocks_valid = false;
        }