]> git.tdb.fi Git - r2c2.git/blob - source/libr2c2/aicontrol.cpp
Fix some more copyright messages
[r2c2.git] / source / libr2c2 / aicontrol.cpp
1 /* $Id$
2
3 This file is part of R²C²
4 Copyright © 2010-2011  Mikkosoft Productions, Mikko Rasa
5 Distributed under the GPL
6 */
7
8 #include "aicontrol.h"
9 #include "catalogue.h"
10 #include "layout.h"
11 #include "train.h"
12
13 using namespace std;
14 using namespace Msp;
15
16 namespace R2C2 {
17
18 AIControl::AIControl(Train &t, Controller *n):
19         train(t),
20         next_ctrl(n),
21         target_speed(Control::continuous("speed", 0, 1000)),
22         state(NORMAL)
23 {
24         target_speed.set(0);
25
26         train.signal_arrived.connect(sigc::mem_fun(this, &AIControl::arrived));
27         next_ctrl->signal_control_changed.connect(sigc::mem_fun(this, &AIControl::control_changed));
28 }
29
30 AIControl::~AIControl()
31 {
32         delete next_ctrl;
33 }
34
35 const char *AIControl::enumerate_controls(unsigned index) const
36 {
37         if(index==0)
38                 return target_speed.name.c_str();
39         else
40         {
41                 for(--index;; ++index)
42                 {
43                         const char *ret = next_ctrl->enumerate_controls(index-1);
44                         if(!ret || ret!=target_speed.name)
45                                 return ret;
46                 }
47         }
48 }
49
50 void AIControl::set_control(const string &n, float v)
51 {
52         if(n==target_speed.name)
53         {
54                 if(v && !train.is_active())
55                         train.set_active(true);
56
57                 target_speed.set(v);
58                 if(state!=BLOCKED)
59                 {
60                         float approach_speed = 5*train.get_layout().get_catalogue().get_scale();
61                         if(state==APPROACH && target_speed.value>approach_speed)
62                                 next_ctrl->set_control("speed", approach_speed);
63                         else
64                                 next_ctrl->set_control("speed", target_speed.value);
65                 }
66
67                 signal_control_changed.emit(target_speed);
68         }
69         else
70                 next_ctrl->set_control(n, v);
71 }
72
73 const Controller::Control &AIControl::get_control(const string &n) const
74 {
75         if(n==target_speed.name)
76                 return target_speed;
77         else
78                 return next_ctrl->get_control(n);
79 }
80
81 float AIControl::get_speed() const
82 {
83         return next_ctrl->get_speed();
84 }
85
86 bool AIControl::get_reverse() const
87 {
88         return next_ctrl->get_reverse();
89 }
90
91 float AIControl::get_braking_distance() const
92 {
93         return next_ctrl->get_braking_distance();
94 }
95
96 void AIControl::tick(const Time::TimeDelta &dt)
97 {
98         float scale = train.get_layout().get_catalogue().get_scale();
99         float rsv_dist = train.get_reserved_distance();
100         float brake_dist = next_ctrl->get_braking_distance();
101         float approach_margin = 50*scale;
102         float approach_speed = 5*scale;
103         float margin = 1*scale;
104
105         State old_state = state;
106
107         if(state==FOLLOW && !train.get_preceding_train())
108                 state = NORMAL;
109
110         if(rsv_dist<brake_dist+margin)
111                 state = BLOCKED;
112         else if(rsv_dist>brake_dist+margin*2 && rsv_dist<brake_dist*1.3+approach_margin)
113                 state = APPROACH;
114         else if(rsv_dist>brake_dist*1.3+approach_margin*2)
115                 state = NORMAL;
116
117         if(state==NORMAL && train.get_preceding_train())
118                 state = FOLLOW;
119
120         if(state!=old_state || state==FOLLOW)
121         {
122                 float speed_limit = -1;
123                 if(state==BLOCKED)
124                         speed_limit = 0;
125                 else if(state==APPROACH)
126                         speed_limit = approach_speed;
127                 else if(state==FOLLOW && train.get_preceding_train()->is_active())
128                         speed_limit = train.get_preceding_train()->get_speed();
129
130                 if(speed_limit>=0 && target_speed.value>speed_limit)
131                         next_ctrl->set_control("speed", speed_limit);
132                 else
133                         next_ctrl->set_control("speed", target_speed.value);
134         }
135
136         next_ctrl->tick(dt);
137
138         if(!target_speed.value && !next_ctrl->get_speed() && train.is_active())
139                 train.set_active(false);
140 }
141
142 void AIControl::control_changed(const Control &ctrl)
143 {
144         if(ctrl.name!="speed")
145                 signal_control_changed.emit(ctrl);
146 }
147
148 void AIControl::arrived()
149 {
150         set_control("speed", 0);
151 }
152
153 } // namespace R2C2