]> www.fi.muni.cz Git - slotcarman.git/blob - SCX/Track.pm
Make the main app use SCX::Parser
[slotcarman.git] / SCX / Track.pm
1 #!/usr/bin/perl -w
2
3 package SCX::Track;
4
5 use strict;
6 use Carp;
7
8 use Glib qw(TRUE FALSE);
9 use SCX::Car;
10
11 our $SEMAPHORE_STEP = 1000;
12
13 sub new {
14         my ($class, $args) = @_;
15
16         my $self = {
17                 gui => $args->{gui},
18                 race_running => 0,
19                 lap_counting_up => 1,
20                 round => 0,
21                 now => 0,
22                 qualification_setup => -100,
23         };
24
25         bless $self, $class;
26
27         for my $i (0..5) {
28                 $self->{cars}->[$i] = SCX::Car->new({
29                         gui => $self->{gui},
30                         id => $i,
31                         track => $self,
32                 });
33         }
34
35         $self->print_rounds;
36         $self->{gui}->time(undef);
37         $self->{gui}->best_lap(undef, undef);
38
39         return $self;
40 }
41
42 sub car { return shift->{cars}->[shift]; }
43
44 sub race_start {
45         my ($self, $time) = @_;
46
47         return if $self->{race_running} || $self->{start_in_progress}
48                 || $self->{qualification_running};
49
50         if ($time - $self->{qualification_setup} < 1) {
51                 $self->{qualification_running} = 1;
52         } else {
53                 $self->{round} = 0;
54                 $self->{race_running} = 0;
55                 $self->{start_in_progress} = 1;
56                 $self->{semaphore} = 0;
57                 $self->{gui}->show_semaphore(0);
58                 Glib::Timeout->add($SEMAPHORE_STEP, \&semaphore_step, $self);
59         }
60         $self->print_rounds;
61 }
62
63 sub semaphore_step {
64         my ($self) = @_;
65
66         return FALSE if !$self->{start_in_progress} && !$self->{race_running};
67
68         $self->{semaphore}++;
69         if ($self->{semaphore} <= 5) {
70                 $self->{gui}->show_semaphore($self->{semaphore});
71                 my $timeout = $SEMAPHORE_STEP;
72                 $timeout += $SEMAPHORE_STEP * rand()
73                         if $self->{semaphore} == 5;
74                 Glib::Timeout->add($timeout, \&semaphore_step, $self);
75         } elsif ($self->{semaphore} == 6) {
76                 $self->{race_running} = 1;
77                 $self->{race_running_since} = $self->{now};
78                 $self->{start_in_progress} = undef;
79                 $self->{gui}->show_semaphore(0);
80                 Glib::Timeout->add($SEMAPHORE_STEP, \&semaphore_step, $self);
81         } else {
82                 $self->{gui}->show_semaphore(undef);
83                 $self->{semaphore} = undef;
84         }
85         return FALSE;
86 }
87
88 sub race_end {
89         my ($self) = @_;
90
91         $self->{race_running} = 0;
92 }
93
94 sub race_setup {
95         my ($self, $rounds, $time) = @_;
96
97         if ($time - $self->{qualification_setup} < 1) {
98                 $self->{round} = 0;
99         } else {
100                 if ($rounds) {
101                         $self->{race_rounds} = $rounds;
102                 } else {
103                         $self->{race_rounds} = 0;
104                 }
105         }
106
107         $self->{round} = 0;
108         $self->print_rounds;
109         $self->{best_lap} = undef;
110
111         $self->{gui}->show_semaphore(undef);
112         $self->{race_running} = 0;
113         $self->{qualification_running} = 0;
114         $self->{start_in_progress} = 0;
115
116         $self->{gui}->time(undef);
117         $self->{gui}->best_lap(undef);
118 }
119
120 sub reset {
121         my ($self) = @_;
122
123         $self->{race_running} = 0;
124         $self->{qualification_running} = 0;
125         $self->{start_in_progress} = 0;
126         $self->{race_finishing} = 0;
127         $self->{best_lap} = undef;
128         $self->{round} = 0;
129
130         $self->print_rounds;
131         $self->{gui}->best_lap(undef);
132         $self->{gui}->time(undef);
133
134         for my $car (0..5) {
135                 $self->car($car)->reset;
136         }
137 }
138
139 sub print_rounds {
140         my ($self) = @_;
141
142         my $msg;
143         if ($self->{qualification_running}
144                 || $self->{now} - $self->{qualification_setup} < 1) {
145                 $msg = 'Qualification: ' . $self->{race_rounds}
146                         . ($self->{race_rounds} == 1 ? ' round' : ' rounds');
147         } elsif ($self->{race_rounds}) {
148                 $msg = $self->{round} . '/' . $self->{race_rounds};
149         } else {
150                 $msg = $self->{round};
151         }
152
153         $self->{gui}->rounds($msg);
154 }
155
156 sub check_best_lap {
157         my ($self, $time, $who) = @_;
158
159         return if !defined $time || $time == 0;
160
161 #       print "Check_best_lap $time $who vs ",
162 #               defined $self->{best_lap} ? $self->{best_lap} : 'undef',
163 #               "\n";
164         if (!defined $self->{best_lap}
165                 || $time < $self->{best_lap}) {
166                 $self->{best_lap} = $time;
167                 $self->{gui}->best_lap($time, $who);
168                 return 1;
169         }
170         return 0;
171 }
172
173 sub qualification_setup {
174         my ($self, $rounds, $cars, $time) = @_;
175
176         return if $self->{qualification_running};
177
178         for my $car (0..5) {
179                 $self->car($car)->set_lap(undef);
180                 $self->car($car)->set_laptime(undef);
181         }
182
183         $self->{qualification_setup} = $time;
184         $self->{race_rounds} = $rounds;
185         $self->{qualification_cars} = $cars;
186         $self->{gui}->time(undef);
187         $self->{gui}->best_lap(undef);
188         $self->print_rounds;
189 }
190
191 sub packet_received {
192         my ($self, $time) = @_;
193
194         $self->{now} = $time;
195
196         if ($self->{race_running}) {
197                 $self->{gui}->time($time - $self->{race_running_since});
198         }
199 }
200
201 sub recalc_order {
202         my ($self, $now) = @_;
203
204         return if !$self->{race_running};
205
206         my @laps;
207         my @times;
208         for my $id (0..5) {
209                 $laps[$id]  = $self->car($id)->{lap} // -1;
210                 $times[$id] = $self->car($id)->{first_finish_time} // $now;
211         }
212
213         my @new_order = sort {
214                 $laps[$b] <=> $laps[$a]
215                 ||
216                 $times[$a] <=> $times[$b]
217                 ||
218                 $a <=> $b;
219         } (0..5);
220
221         my $lap_max = $laps[$new_order[0]];
222         my $lap_max_changed = 0;
223         if (defined $lap_max && defined $self->{round}
224                 && $lap_max != $self->{round}) {
225                 $self->{round} = $lap_max;
226                 $lap_max_changed = 1;
227                 $self->print_rounds;
228         }
229
230         if ($self->{round} && $self->{race_rounds}
231                 && $self->{round} > $self->{race_rounds}) {
232                 $self->{race_finishing} = 1;
233         }
234
235         for my $id (0..5) {
236                 my $car = $new_order[$id];
237                 if ($self->car($car)->{order} != $id) {
238                         $self->car($car)->set_order($id);
239                 }
240         }
241         return ($lap_max_changed, $lap_max, $times[$new_order[0]]);
242 }
243
244 sub recalc_qual_order {
245         my ($self) = @_;
246
247         return if !$self->{qualification_running};
248
249         my @times;
250         for my $id (0..5) {
251                 $times[$id] = $self->car($id)->{best_lap};
252                 if (!defined $times[$id] || $times[$id] <= 0) {
253                         $times[$id] = 999_999;
254                 }
255         }
256
257         my @new_order = sort {
258                 $times[$a] <=> $times[$b]
259                 ||
260                 $a <=> $b;
261         } (0..5);
262
263         my $best_time = $times[$new_order[0]];
264
265         for my $id (0..5) {
266                 my $car = $new_order[$id];
267                 if ($self->car($car)->{order} != $id) {
268                         $self->car($car)->set_order($id);
269                 }
270         }
271         return ($times[$new_order[0]]);
272 }
273
274 sub finish_line {
275         my ($self, $time, $regular, @cars) = @_;
276
277         my %processed;
278         my $was_processed;
279
280         for my $car (@cars) {
281                 if ($self->car($car)->finish_line($time, $regular)) {
282                         $processed{$car} = 1;
283                         $was_processed = 1;
284                 }
285         }
286
287         return if !$was_processed;
288
289         if ($self->{qualification_running}) {
290                 my ($best) = $self->recalc_qual_order;
291                 for my $car (0..5) {
292                         $self->car($car)->recalc_qual_distance($best);
293                 }
294                 return;
295         }
296
297         my ($lap_max_changed, $lap_max, $time_min)
298                 = $self->recalc_order($time);
299
300         for my $car (0..5) {
301                 if ($processed{$car}) {
302                         $self->car($car)->recalc_distance(
303                                 $lap_max, $time_min, $self->{race_finishing},
304                         );
305                 } elsif ($lap_max_changed) {
306                         $self->car($car)->greyout_distance;
307                 }
308         }
309 }
310
311 1;
312