]> www.fi.muni.cz Git - slotcarman.git/blob - SCX/Track.pm
Reset car status before the race.
[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         for my $car (0..5) {
126                 $self->car($car)->reset;
127         }
128 }
129
130 sub reset {
131         my ($self) = @_;
132
133         $self->{race_running} = 0;
134         $self->{qualification_running} = 0;
135         $self->{start_in_progress} = 0;
136         $self->{race_finishing} = 0;
137         $self->{best_lap} = undef;
138         $self->{round} = 0;
139
140         $self->print_rounds;
141         $self->{gui}->best_lap(undef);
142         $self->{gui}->time(undef);
143
144         for my $car (0..5) {
145                 $self->car($car)->reset;
146         }
147 }
148
149 sub print_rounds {
150         my ($self) = @_;
151
152         my $msg;
153         if ($self->{qualification_running}
154                 || $self->{now} - $self->{qualification_setup} < 1) {
155                 $msg = 'Qualification: ' . $self->{race_rounds}
156                         . ($self->{race_rounds} == 1 ? ' round' : ' rounds');
157         } elsif ($self->{race_rounds}) {
158                 $msg = $self->{round} . '/' . $self->{race_rounds};
159         } else {
160                 $msg = $self->{round};
161         }
162
163         $self->{gui}->rounds($msg);
164 }
165
166 sub check_best_lap {
167         my ($self, $time, $who) = @_;
168
169         return if !defined $time || $time == 0;
170
171 #       print "Check_best_lap $time $who vs ",
172 #               defined $self->{best_lap} ? $self->{best_lap} : 'undef',
173 #               "\n";
174         if (!defined $self->{best_lap}
175                 || $time < $self->{best_lap}) {
176                 $self->{best_lap} = $time;
177                 $self->{gui}->best_lap($time, $who);
178                 return 1;
179         }
180         return 0;
181 }
182
183 sub qualification_setup {
184         my ($self, $rounds, $cars, $time) = @_;
185
186         return if $self->{qualification_running};
187
188         for my $car (0..5) {
189                 $self->car($car)->set_lap(undef);
190                 $self->car($car)->set_laptime(undef);
191         }
192
193         $self->{qualification_setup} = $time;
194         $self->{race_rounds} = $rounds;
195         $self->{qualification_cars} = $cars;
196         $self->{gui}->time(undef);
197         $self->{gui}->best_lap(undef);
198         $self->print_rounds;
199 }
200
201 sub packet_received {
202         my ($self, $time) = @_;
203
204         $self->{now} = $time;
205
206         if ($self->{race_running}) {
207                 $self->{gui}->time($time - $self->{race_running_since});
208         }
209 }
210
211 sub recalc_order {
212         my ($self, $now) = @_;
213
214         return if !$self->{race_running};
215
216         my @laps;
217         my @times;
218         for my $id (0..5) {
219                 $laps[$id]  = $self->car($id)->{lap} // -1;
220                 $times[$id] = $self->car($id)->{first_finish_time} // $now;
221         }
222
223         my @new_order = sort {
224                 $laps[$b] <=> $laps[$a]
225                 ||
226                 $times[$a] <=> $times[$b]
227                 ||
228                 $a <=> $b;
229         } (0..5);
230
231         my $lap_max = $laps[$new_order[0]];
232         my $lap_max_changed = 0;
233         if (defined $lap_max && defined $self->{round}
234                 && $lap_max != $self->{round}) {
235                 $self->{round} = $lap_max;
236                 $lap_max_changed = 1;
237                 $self->print_rounds;
238         }
239
240         if ($self->{round} && $self->{race_rounds}
241                 && $self->{round} > $self->{race_rounds}) {
242                 $self->{race_finishing} = 1;
243         }
244
245         for my $id (0..5) {
246                 my $car = $new_order[$id];
247                 if ($self->car($car)->{order} != $id) {
248                         $self->car($car)->set_order($id);
249                 }
250         }
251         return ($lap_max_changed, $lap_max, $times[$new_order[0]]);
252 }
253
254 sub recalc_qual_order {
255         my ($self) = @_;
256
257         return if !$self->{qualification_running};
258
259         my @times;
260         for my $id (0..5) {
261                 $times[$id] = $self->car($id)->{best_lap};
262                 if (!defined $times[$id] || $times[$id] <= 0) {
263                         $times[$id] = 999_999;
264                 }
265         }
266
267         my @new_order = sort {
268                 $times[$a] <=> $times[$b]
269                 ||
270                 $a <=> $b;
271         } (0..5);
272
273         my $best_time = $times[$new_order[0]];
274
275         for my $id (0..5) {
276                 my $car = $new_order[$id];
277                 if ($self->car($car)->{order} != $id) {
278                         $self->car($car)->set_order($id);
279                 }
280         }
281         return ($times[$new_order[0]]);
282 }
283
284 sub finish_line {
285         my ($self, $time, $regular, @cars) = @_;
286
287         my %processed;
288         my $was_processed;
289
290         for my $car (@cars) {
291                 if ($self->car($car)->finish_line($time, $regular)) {
292                         $processed{$car} = 1;
293                         $was_processed = 1;
294                 }
295         }
296
297         return if !$was_processed;
298
299         if ($self->{qualification_running}) {
300                 my ($best) = $self->recalc_qual_order;
301                 for my $car (0..5) {
302                         $self->car($car)->recalc_qual_distance($best);
303                 }
304                 return;
305         }
306
307         my ($lap_max_changed, $lap_max, $time_min)
308                 = $self->recalc_order($time);
309
310         for my $car (0..5) {
311                 if ($processed{$car}) {
312                         $self->car($car)->recalc_distance(
313                                 $lap_max, $time_min, $self->{race_finishing},
314                         );
315                 } elsif ($lap_max_changed) {
316                         $self->car($car)->greyout_distance;
317                 }
318         }
319 }
320
321 1;
322