]> git.tdb.fi Git - r2c2.git/blob - source/libr2c2/aicontrol.cpp
Don't bother with creating intermediate steps for state updates
[r2c2.git] / source / libr2c2 / aicontrol.cpp
1 #include "aicontrol.h"
2 #include "catalogue.h"
3 #include "layout.h"
4 #include "train.h"
5
6 using namespace std;
7 using namespace Msp;
8
9 namespace R2C2 {
10
11 AIControl::AIControl(Train &t):
12         TrainAI(t),
13         target_speed(0),
14         reverse(false),
15         pending_reverse(false),
16         state(NORMAL),
17         need_update(false)
18 {
19         train.signal_ai_event.connect(sigc::mem_fun(this, &AIControl::event));
20 }
21
22 void AIControl::set_target_speed(float s)
23 {
24         target_speed = s;
25         need_update = true;
26         signal_event.emit(Message("target-speed-changed", target_speed));
27 }
28
29 void AIControl::set_reverse(bool r)
30 {
31         pending_reverse = r;
32         if(train.get_controller().get_speed())
33                 set_target_speed(0);
34         else
35         {
36                 reverse = r;
37                 train.set_control("reverse", reverse);
38                 signal_event.emit(Message("reverse-changed", reverse));
39         }
40 }
41
42 void AIControl::message(const Message &msg)
43 {
44         if(msg.type=="set-target-speed")
45                 set_target_speed(msg.value.value<float>());
46         else if(msg.type=="set-reverse")
47                 set_reverse(msg.value.value<bool>());
48         else if(msg.type=="toggle-reverse")
49                 set_reverse(!reverse);
50 }
51
52 void AIControl::tick(const Time::TimeDelta &)
53 {
54         float scale = train.get_layout().get_catalogue().get_scale();
55         float rsv_dist = train.get_reserved_distance();
56         float brake_dist = train.get_controller().get_braking_distance();
57         float approach_margin = 50*scale;
58         float approach_speed = 5*scale;
59         float margin = 1*scale;
60
61         State old_state = state;
62
63         if(state==FOLLOW && !train.get_preceding_train())
64                 state = NORMAL;
65
66         if(rsv_dist<brake_dist+margin)
67                 state = BLOCKED;
68         else if(rsv_dist>brake_dist+margin*2 && rsv_dist<brake_dist*1.3+approach_margin)
69                 state = APPROACH;
70         else if(rsv_dist>brake_dist*1.3+approach_margin*2)
71                 state = NORMAL;
72
73         if(state==NORMAL && train.get_preceding_train())
74                 state = FOLLOW;
75
76         if(state!=old_state || state==FOLLOW || need_update)
77         {
78                 float speed_limit = -1;
79                 if(state==BLOCKED)
80                         speed_limit = 0;
81                 else if(state==APPROACH)
82                         speed_limit = approach_speed;
83                 else if(state==FOLLOW && train.get_preceding_train()->get_block_allocator().is_active())
84                         speed_limit = train.get_preceding_train()->get_speed();
85
86                 if(speed_limit>=0 && target_speed>speed_limit)
87                         train.set_control("speed", speed_limit);
88                 else
89                         train.set_control("speed", target_speed);
90
91                 need_update = false;
92         }
93
94         if(pending_reverse!=reverse && !train.get_controller().get_speed())
95         {
96                 reverse = pending_reverse;
97                 train.set_control("reverse", reverse);
98         }
99 }
100
101 bool AIControl::has_intent_to_move() const
102 {
103         return target_speed;
104 }
105
106 void AIControl::event(TrainAI &, const Message &ev)
107 {
108         if(ev.type=="arrived")
109                 set_target_speed(0);
110 }
111
112 } // namespace R2C2