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