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