-/* $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)),
- state(NORMAL)
+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));
+ train.signal_ai_event.connect(sigc::mem_fun(this, &AIControl::event));
}
-AIControl::~AIControl()
+void AIControl::set_target_speed(float s)
{
- delete next_ctrl;
+ target_speed = s;
+ need_update = true;
+ signal_event.emit(Message("target-speed-changed", target_speed));
}
-const char *AIControl::enumerate_controls(unsigned index) const
+void AIControl::set_reverse(bool r)
{
- if(index==0)
- return target_speed.name.c_str();
+ pending_reverse = r;
+ if(train.get_controller().get_speed())
+ set_target_speed(0);
else
{
- for(--index;; ++index)
- {
- const char *ret = next_ctrl->enumerate_controls(index-1);
- if(!ret || ret!=target_speed.name)
- return ret;
- }
- }
-}
-
-void AIControl::set_control(const string &n, float v)
-{
- if(n==target_speed.name)
- {
- if(v && !train.is_active())
- train.set_active(true);
-
- target_speed.set(v);
- if(state!=BLOCKED)
- {
- float approach_speed = 5*train.get_layout().get_catalogue().get_scale();
- if(state==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);
+ reverse = r;
+ train.set_control("reverse", reverse);
+ signal_event.emit(Message("reverse-changed", reverse));
}
- else
- next_ctrl->set_control(n, v);
}
-const Controller::Control &AIControl::get_control(const string &n) const
+void AIControl::message(const Message &msg)
{
- if(n==target_speed.name)
- return target_speed;
- else
- return next_ctrl->get_control(n);
+ 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);
}
-float AIControl::get_speed() const
-{
- return next_ctrl->get_speed();
-}
-
-bool AIControl::get_reverse() const
-{
- return next_ctrl->get_reverse();
-}
-
-float AIControl::get_braking_distance() const
-{
- return next_ctrl->get_braking_distance();
-}
-
-void AIControl::tick(const Time::TimeDelta &dt)
+void AIControl::tick(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;
State old_state = state;
if(state==NORMAL && train.get_preceding_train())
state = FOLLOW;
- if(state!=old_state || state==FOLLOW)
+ if(state!=old_state || state==FOLLOW || need_update)
{
float speed_limit = -1;
if(state==BLOCKED)
speed_limit = 0;
else if(state==APPROACH)
speed_limit = approach_speed;
- else if(state==FOLLOW)
+ else if(state==FOLLOW && train.get_preceding_train()->get_block_allocator().is_active())
speed_limit = train.get_preceding_train()->get_speed();
- if(speed_limit>=0 && target_speed.value>speed_limit)
- next_ctrl->set_control("speed", speed_limit);
+ 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);
- next_ctrl->tick(dt);
+ need_update = false;
+ }
- if(!target_speed.value && !next_ctrl->get_speed() && train.is_active())
- train.set_active(false);
+ if(pending_reverse!=reverse && !train.get_controller().get_speed())
+ {
+ reverse = pending_reverse;
+ train.set_control("reverse", reverse);
+ }
}
-void AIControl::control_changed(const Control &ctrl)
+bool AIControl::has_intent_to_move() const
{
- if(ctrl.name!="speed")
- signal_control_changed.emit(ctrl);
+ return target_speed;
}
-void AIControl::arrived()
+void AIControl::event(TrainAI &, const Message &ev)
{
- set_control("speed", 0);
+ if(ev.type=="arrived")
+ set_target_speed(0);
}
} // namespace R2C2