]> git.tdb.fi Git - r2c2.git/blob - source/libr2c2/aicontrol.cpp
Make the simulation independent of wall clock time
[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         if(s && !train.is_active())
25                 train.set_active(true);
26
27         target_speed = s;
28         need_update = true;
29         signal_event.emit(Message("target-speed-changed", target_speed));
30 }
31
32 void AIControl::set_reverse(bool r)
33 {
34         pending_reverse = r;
35         if(train.get_controller().get_speed())
36                 set_target_speed(0);
37         else
38         {
39                 reverse = r;
40                 train.set_control("reverse", reverse);
41                 signal_event.emit(Message("reverse-changed", reverse));
42         }
43 }
44
45 void AIControl::message(const Message &msg)
46 {
47         if(msg.type=="set-target-speed")
48                 set_target_speed(msg.value.value<float>());
49         else if(msg.type=="set-reverse")
50                 set_reverse(msg.value.value<bool>());
51         else if(msg.type=="toggle-reverse")
52                 set_reverse(!reverse);
53 }
54
55 void AIControl::tick(const Time::TimeDelta &)
56 {
57         float scale = train.get_layout().get_catalogue().get_scale();
58         float rsv_dist = train.get_reserved_distance();
59         float brake_dist = train.get_controller().get_braking_distance();
60         float approach_margin = 50*scale;
61         float approach_speed = 5*scale;
62         float margin = 1*scale;
63
64         State old_state = state;
65
66         if(state==FOLLOW && !train.get_preceding_train())
67                 state = NORMAL;
68
69         if(rsv_dist<brake_dist+margin)
70                 state = BLOCKED;
71         else if(rsv_dist>brake_dist+margin*2 && rsv_dist<brake_dist*1.3+approach_margin)
72                 state = APPROACH;
73         else if(rsv_dist>brake_dist*1.3+approach_margin*2)
74                 state = NORMAL;
75
76         if(state==NORMAL && train.get_preceding_train())
77                 state = FOLLOW;
78
79         if(state!=old_state || state==FOLLOW || need_update)
80         {
81                 float speed_limit = -1;
82                 if(state==BLOCKED)
83                         speed_limit = 0;
84                 else if(state==APPROACH)
85                         speed_limit = approach_speed;
86                 else if(state==FOLLOW && train.get_preceding_train()->is_active())
87                         speed_limit = train.get_preceding_train()->get_speed();
88
89                 if(speed_limit>=0 && target_speed>speed_limit)
90                         train.set_control("speed", speed_limit);
91                 else
92                         train.set_control("speed", target_speed);
93
94                 need_update = false;
95         }
96
97         if(pending_reverse!=reverse && !train.get_controller().get_speed())
98         {
99                 reverse = pending_reverse;
100                 train.set_control("reverse", reverse);
101         }
102
103         if(!target_speed && !train.get_controller().get_speed() && train.is_active())
104                 train.set_active(false);
105 }
106
107 void AIControl::event(TrainAI &, const Message &ev)
108 {
109         if(ev.type=="arrived")
110                 set_target_speed(0);
111 }
112
113 } // namespace R2C2