8 use Glib qw(TRUE FALSE);
12 our $SEMAPHORE_STEP = 1000;
15 my ($class, $args) = @_;
23 qualification_setup => -100,
24 no_semaphore => $args->{no_semaphore},
30 $self->{cars}->[$i] = SCX::Car->new({
38 $self->{gui}->time(undef);
39 $self->{gui}->best_lap(undef, undef);
41 $self->{sound} = new SCX::Sound;
46 sub car { return shift->{cars}->[shift]; }
49 my ($self, $time) = @_;
51 return if $self->{race_running} || $self->{start_in_progress}
52 || $self->{qualification_running};
54 if ($time - $self->{qualification_setup} < 1) {
55 $self->{qualification_running} = 1;
56 } elsif ($self->{no_semaphore}) {
58 $self->{race_running} = 1;
59 $self->{race_running_since} = $self->{now};
60 $self->{start_in_progress} = undef;
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);
75 return FALSE if !$self->{start_in_progress} && !$self->{race_running};
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);
91 $self->{gui}->show_semaphore(undef);
92 $self->{semaphore} = undef;
93 $self->{sound}->start();
101 $self->{race_running} = 0;
105 my ($self, $rounds, $time) = @_;
107 if ($time - $self->{qualification_setup} < 1) {
111 $self->{race_rounds} = $rounds;
113 $self->{race_rounds} = 0;
119 $self->{best_lap} = undef;
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;
127 $self->{gui}->time(undef);
128 $self->{gui}->best_lap(undef);
131 $self->car($car)->reset;
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};
146 $msg = $self->{round};
149 $self->{gui}->rounds($msg);
152 sub notify_best_lap {
153 my ($self, $id, $time, $who) = @_;
155 return if !defined $time || $time == 0;
157 # print "Check_best_lap $time $who vs ",
158 # defined $self->{best_lap} ? $self->{best_lap} : 'undef',
160 if (!defined $self->{best_lap}
161 || $time < $self->{best_lap}) {
162 $self->{best_lap} = $time;
163 $self->{gui}->best_lap($time, $who);
166 $self->car($car)->set_global_best($car == $id);
167 $self->car($car)->print_best_lap;
170 if (!$self->{race_running} || $self->{round} > 1) {
171 # skip the first round in the race
172 $self->{sound}->best_lap($id);
179 sub qualification_setup {
180 my ($self, $rounds, $cars, $time) = @_;
182 return if $self->{qualification_running};
185 $self->car($car)->set_lap(undef);
186 $self->car($car)->set_laptime(undef);
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);
197 sub packet_received {
198 my ($self, $time) = @_;
200 $self->{now} = $time;
202 if ($self->{race_running}) {
203 $self->{gui}->time($time - $self->{race_running_since});
208 my ($self, $now) = @_;
210 return if !$self->{race_running};
215 $laps[$id] = $self->car($id)->{lap} // -1;
216 $times[$id] = $self->car($id)->{first_finish_time} // $now;
219 my @new_order = sort {
220 $laps[$b] <=> $laps[$a]
222 $times[$a] <=> $times[$b]
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;
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]);
241 $self->{race_finishing} = 1;
245 my $car = $new_order[$id];
246 if ($self->car($car)->{order} != $id) {
247 $self->car($car)->set_order($id);
250 return ($lap_max_changed, $lap_max, $times[$new_order[0]]);
253 sub recalc_qual_order {
256 return if !$self->{qualification_running};
260 $times[$id] = $self->car($id)->{best_lap};
261 if (!defined $times[$id] || $times[$id] <= 0) {
262 $times[$id] = 999_999;
266 my @new_order = sort {
267 $times[$a] <=> $times[$b]
272 my $best_time = $times[$new_order[0]];
275 my $car = $new_order[$id];
276 if ($self->car($car)->{order} != $id) {
277 $self->car($car)->set_order($id);
280 return ($times[$new_order[0]]);
284 my ($self, $time, $regular, @cars) = @_;
289 for my $car (@cars) {
290 if ($self->car($car)->finish_line($time, $regular)) {
291 $processed{$car} = 1;
296 return if !$was_processed;
298 if ($self->{qualification_running}) {
299 my ($best) = $self->recalc_qual_order;
301 $self->car($car)->recalc_qual_distance($best);
306 my ($lap_max_changed, $lap_max, $time_min)
307 = $self->recalc_order($time);
310 if ($processed{$car}) {
311 $self->car($car)->recalc_distance(
312 $lap_max, $time_min, $self->{race_finishing},
314 } elsif ($lap_max_changed) {
315 $self->car($car)->greyout_distance;