]> www.fi.muni.cz Git - slotcarman.git/blob - SCX/Track.pm
Sound support
[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 use SCX::Sound;
11
12 our $SEMAPHORE_STEP = 1000;
13
14 sub new {
15         my ($class, $args) = @_;
16
17         my $self = {
18                 gui => $args->{gui},
19                 race_running => 0,
20                 lap_counting_up => 1,
21                 round => 0,
22                 now => 0,
23                 qualification_setup => -100,
24                 no_semaphore => $args->{no_semaphore},
25         };
26
27         bless $self, $class;
28
29         for my $i (0..5) {
30                 $self->{cars}->[$i] = SCX::Car->new({
31                         gui => $self->{gui},
32                         id => $i,
33                         track => $self,
34                 });
35         }
36
37         $self->print_rounds;
38         $self->{gui}->time(undef);
39         $self->{gui}->best_lap(undef, undef);
40
41         $self->{sound} = new SCX::Sound;
42
43         return $self;
44 }
45
46 sub car { return shift->{cars}->[shift]; }
47
48 sub race_start {
49         my ($self, $time) = @_;
50
51         return if $self->{race_running} || $self->{start_in_progress}
52                 || $self->{qualification_running};
53
54         if ($time - $self->{qualification_setup} < 1) {
55                 $self->{qualification_running} = 1;
56         } elsif ($self->{no_semaphore}) {
57                 $self->{round} = 0;
58                 $self->{race_running} = 1;
59                 $self->{race_running_since} = $self->{now};
60                 $self->{start_in_progress} = undef;
61         } else {
62                 $self->{round} = 0;
63                 $self->{race_running} = 0;
64                 $self->{start_in_progress} = 1;
65                 $self->{semaphore} = 0;
66                 $self->{gui}->show_semaphore(0);
67                 Glib::Timeout->add($SEMAPHORE_STEP, \&semaphore_step, $self);
68         }
69         $self->print_rounds;
70 }
71
72 sub semaphore_step {
73         my ($self) = @_;
74
75         return FALSE if !$self->{start_in_progress} && !$self->{race_running};
76
77         $self->{semaphore}++;
78         if ($self->{semaphore} <= 5) {
79                 $self->{gui}->show_semaphore($self->{semaphore});
80                 my $timeout = $SEMAPHORE_STEP;
81                 $timeout += $SEMAPHORE_STEP * rand()
82                         if $self->{semaphore} == 5;
83                 Glib::Timeout->add($timeout, \&semaphore_step, $self);
84         } elsif ($self->{semaphore} == 6) {
85                 $self->{race_running} = 1;
86                 $self->{race_running_since} = $self->{now};
87                 $self->{start_in_progress} = undef;
88                 $self->{gui}->show_semaphore(0);
89                 Glib::Timeout->add($SEMAPHORE_STEP, \&semaphore_step, $self);
90         } else {
91                 $self->{gui}->show_semaphore(undef);
92                 $self->{semaphore} = undef;
93                 $self->{sound}->start();
94         }
95         return FALSE;
96 }
97
98 sub race_end {
99         my ($self) = @_;
100
101         $self->{race_running} = 0;
102 }
103
104 sub race_setup {
105         my ($self, $rounds, $time) = @_;
106
107         if ($time - $self->{qualification_setup} < 1) {
108                 $self->{round} = 0;
109         } else {
110                 if ($rounds) {
111                         $self->{race_rounds} = $rounds;
112                 } else {
113                         $self->{race_rounds} = 0;
114                 }
115         }
116
117         $self->{round} = 0;
118         $self->print_rounds;
119         $self->{best_lap} = undef;
120
121         $self->{gui}->show_semaphore(undef);
122         $self->{race_running} = 0;
123         $self->{qualification_running} = 0;
124         $self->{start_in_progress} = 0;
125         $self->{race_finishing} = 0;
126
127         $self->{gui}->time(undef);
128         $self->{gui}->best_lap(undef);
129
130         for my $car (0..5) {
131                 $self->car($car)->reset;
132         }
133 }
134
135 sub print_rounds {
136         my ($self) = @_;
137
138         my $msg;
139         if ($self->{qualification_running}
140                 || $self->{now} - $self->{qualification_setup} < 1) {
141                 $msg = 'Qualification: ' . $self->{race_rounds}
142                         . ($self->{race_rounds} == 1 ? ' round' : ' rounds');
143         } elsif ($self->{race_rounds}) {
144                 $msg = $self->{round} . '/' . $self->{race_rounds};
145         } else {
146                 $msg = $self->{round};
147         }
148
149         $self->{gui}->rounds($msg);
150 }
151
152 sub notify_best_lap {
153         my ($self, $id, $time, $who) = @_;
154
155         return if !defined $time || $time == 0;
156
157 #       print "Check_best_lap $time $who vs ",
158 #               defined $self->{best_lap} ? $self->{best_lap} : 'undef',
159 #               "\n";
160         if (!defined $self->{best_lap}
161                 || $time < $self->{best_lap}) {
162                 $self->{best_lap} = $time;
163                 $self->{gui}->best_lap($time, $who);
164
165                 for my $car (0..5) {
166                         $self->car($car)->set_global_best($car == $id);
167                         $self->car($car)->print_best_lap;
168                 }
169
170                 if (!$self->{race_running} || $self->{round} > 1) {
171                         # skip the first round in the race
172                         $self->{sound}->best_lap($id);
173                 }
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                 if (!$self->{race_finishing}) {
239                         $self->{sound}->winner($new_order[0]);
240                 }
241                 $self->{race_finishing} = 1;
242         }
243
244         for my $id (0..5) {
245                 my $car = $new_order[$id];
246                 if ($self->car($car)->{order} != $id) {
247                         $self->car($car)->set_order($id);
248                 }
249         }
250         return ($lap_max_changed, $lap_max, $times[$new_order[0]]);
251 }
252
253 sub recalc_qual_order {
254         my ($self) = @_;
255
256         return if !$self->{qualification_running};
257
258         my @times;
259         for my $id (0..5) {
260                 $times[$id] = $self->car($id)->{best_lap};
261                 if (!defined $times[$id] || $times[$id] <= 0) {
262                         $times[$id] = 999_999;
263                 }
264         }
265
266         my @new_order = sort {
267                 $times[$a] <=> $times[$b]
268                 ||
269                 $a <=> $b;
270         } (0..5);
271
272         my $best_time = $times[$new_order[0]];
273
274         for my $id (0..5) {
275                 my $car = $new_order[$id];
276                 if ($self->car($car)->{order} != $id) {
277                         $self->car($car)->set_order($id);
278                 }
279         }
280         return ($times[$new_order[0]]);
281 }
282
283 sub finish_line {
284         my ($self, $time, $regular, @cars) = @_;
285
286         my %processed;
287         my $was_processed;
288
289         for my $car (@cars) {
290                 if ($self->car($car)->finish_line($time, $regular)) {
291                         $processed{$car} = 1;
292                         $was_processed = 1;
293                 }
294         }
295
296         return if !$was_processed;
297
298         if ($self->{qualification_running}) {
299                 my ($best) = $self->recalc_qual_order;
300                 for my $car (0..5) {
301                         $self->car($car)->recalc_qual_distance($best);
302                 }
303                 return;
304         }
305
306         my ($lap_max_changed, $lap_max, $time_min)
307                 = $self->recalc_order($time);
308
309         for my $car (0..5) {
310                 if ($processed{$car}) {
311                         $self->car($car)->recalc_distance(
312                                 $lap_max, $time_min, $self->{race_finishing},
313                         );
314                 } elsif ($lap_max_changed) {
315                         $self->car($car)->greyout_distance;
316                 }
317         }
318 }
319
320 1;
321