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