-/* $Id$
-
-This file is part of R²C²
-Copyright © 2010 Mikkosoft Productions, Mikko Rasa
-Distributed under the GPL
-*/
-
#include "aicontrol.h"
#include "catalogue.h"
#include "layout.h"
namespace R2C2 {
-AIControl::AIControl(Train &t, Controller *n):
- train(t),
- next_ctrl(n),
- target_speed(Control::continuous("speed", 0, 1000)),
- blocked(false),
- approach(false)
+AIControl::AIControl(Train &t):
+ TrainAI(t),
+ target_speed(0),
+ reverse(false),
+ pending_reverse(false),
+ state(NORMAL),
+ need_update(false)
{
- target_speed.set(0);
-
train.signal_arrived.connect(sigc::mem_fun(this, &AIControl::arrived));
- next_ctrl->signal_control_changed.connect(sigc::mem_fun(this, &AIControl::control_changed));
}
-AIControl::~AIControl()
+void AIControl::set_target_speed(float s)
{
- delete next_ctrl;
-}
+ if(s && !train.is_active())
+ train.set_active(true);
-void AIControl::set_control(const string &n, float v)
-{
- if(n=="speed")
- {
- if(v && !train.is_active())
- train.set_active(true);
-
- target_speed.set(v);
- if(!blocked)
- {
- float approach_speed = 5*train.get_layout().get_catalogue().get_scale();
- if(approach && target_speed.value>approach_speed)
- next_ctrl->set_control("speed", approach_speed);
- else
- next_ctrl->set_control("speed", target_speed.value);
- }
-
- signal_control_changed.emit(target_speed);
- }
- else
- next_ctrl->set_control(n, v);
+ target_speed = s;
+ need_update = true;
+ signal_event.emit(Message("target-speed-changed", target_speed));
}
-const Controller::Control &AIControl::get_control(const string &n) const
+void AIControl::set_reverse(bool r)
{
- if(n=="speed")
- return target_speed;
+ pending_reverse = r;
+ if(train.get_controller().get_speed())
+ set_target_speed(0);
else
- return next_ctrl->get_control(n);
-}
-
-float AIControl::get_speed() const
-{
- return next_ctrl->get_speed();
-}
-
-bool AIControl::get_reverse() const
-{
- return next_ctrl->get_reverse();
+ {
+ reverse = r;
+ train.set_control("reverse", reverse);
+ signal_event.emit(Message("reverse-changed", reverse));
+ }
}
-float AIControl::get_braking_distance() const
+void AIControl::message(const Message &msg)
{
- return next_ctrl->get_braking_distance();
+ if(msg.type=="set-target-speed")
+ set_target_speed(msg.value.value<float>());
+ else if(msg.type=="set-reverse")
+ set_reverse(msg.value.value<bool>());
+ else if(msg.type=="toggle-reverse")
+ set_reverse(!reverse);
}
-void AIControl::tick(const Time::TimeDelta &dt)
+void AIControl::tick(const Time::TimeStamp &, const Time::TimeDelta &)
{
float scale = train.get_layout().get_catalogue().get_scale();
float rsv_dist = train.get_reserved_distance();
- float brake_dist = next_ctrl->get_braking_distance();
+ float brake_dist = train.get_controller().get_braking_distance();
float approach_margin = 50*scale;
float approach_speed = 5*scale;
- float margin = 10*scale;
+ float margin = 1*scale;
- if(!blocked && rsv_dist<brake_dist+margin)
- {
- blocked = true;
- next_ctrl->set_control("speed", 0);
- }
- else if((!approach && rsv_dist<brake_dist*1.3+approach_margin) || (blocked && rsv_dist>brake_dist+margin*2))
+ State old_state = state;
+
+ if(state==FOLLOW && !train.get_preceding_train())
+ state = NORMAL;
+
+ if(rsv_dist<brake_dist+margin)
+ state = BLOCKED;
+ else if(rsv_dist>brake_dist+margin*2 && rsv_dist<brake_dist*1.3+approach_margin)
+ state = APPROACH;
+ else if(rsv_dist>brake_dist*1.3+approach_margin*2)
+ state = NORMAL;
+
+ if(state==NORMAL && train.get_preceding_train())
+ state = FOLLOW;
+
+ if(state!=old_state || state==FOLLOW || need_update)
{
- blocked = false;
- approach = true;
- if(target_speed.value>approach_speed)
- next_ctrl->set_control("speed", approach_speed);
+ float speed_limit = -1;
+ if(state==BLOCKED)
+ speed_limit = 0;
+ else if(state==APPROACH)
+ speed_limit = approach_speed;
+ else if(state==FOLLOW && train.get_preceding_train()->is_active())
+ speed_limit = train.get_preceding_train()->get_speed();
+
+ if(speed_limit>=0 && target_speed>speed_limit)
+ train.set_control("speed", speed_limit);
else
- next_ctrl->set_control("speed", target_speed.value);
+ train.set_control("speed", target_speed);
+
+ need_update = false;
}
- else if((blocked || approach) && rsv_dist>brake_dist*1.3+approach_margin*2)
+
+ if(pending_reverse!=reverse && !train.get_controller().get_speed())
{
- blocked = false;
- approach = false;
- next_ctrl->set_control("speed", target_speed.value);
+ reverse = pending_reverse;
+ train.set_control("reverse", reverse);
}
- next_ctrl->tick(dt);
-
- if(!target_speed.value && !next_ctrl->get_speed() && train.is_active())
+ if(!target_speed && !train.get_controller().get_speed() && train.is_active())
train.set_active(false);
}
-void AIControl::control_changed(const Control &ctrl)
-{
- if(ctrl.name!="speed")
- signal_control_changed.emit(ctrl);
-}
-
void AIControl::arrived()
{
- set_control("speed", 0);
+ set_target_speed(0);
}
} // namespace R2C2