]> www.fi.muni.cz Git - slotcarman.git/blob - SCX/Track.pm
6ed3d822581242fb96e88dc86d7c9f3b626196e3
[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 check_best_lap {
149         my ($self, $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                 return 1;
161         }
162         return 0;
163 }
164
165 sub qualification_setup {
166         my ($self, $rounds, $cars, $time) = @_;
167
168         return if $self->{qualification_running};
169
170         for my $car (0..5) {
171                 $self->car($car)->set_lap(undef);
172                 $self->car($car)->set_laptime(undef);
173         }
174
175         $self->{qualification_setup} = $time;
176         $self->{race_rounds} = $rounds;
177         $self->{qualification_cars} = $cars;
178         $self->{gui}->time(undef);
179         $self->{gui}->best_lap(undef);
180         $self->print_rounds;
181 }
182
183 sub packet_received {
184         my ($self, $time) = @_;
185
186         $self->{now} = $time;
187
188         if ($self->{race_running}) {
189                 $self->{gui}->time($time - $self->{race_running_since});
190         }
191 }
192
193 sub recalc_order {
194         my ($self, $now) = @_;
195
196         return if !$self->{race_running};
197
198         my @laps;
199         my @times;
200         for my $id (0..5) {
201                 $laps[$id]  = $self->car($id)->{lap} // -1;
202                 $times[$id] = $self->car($id)->{first_finish_time} // $now;
203         }
204
205         my @new_order = sort {
206                 $laps[$b] <=> $laps[$a]
207                 ||
208                 $times[$a] <=> $times[$b]
209                 ||
210                 $a <=> $b;
211         } (0..5);
212
213         my $lap_max = $laps[$new_order[0]];
214         my $lap_max_changed = 0;
215         if (defined $lap_max && defined $self->{round}
216                 && $lap_max != $self->{round}) {
217                 $self->{round} = $lap_max;
218                 $lap_max_changed = 1;
219                 $self->print_rounds;
220         }
221
222         if ($self->{round} && $self->{race_rounds}
223                 && $self->{round} > $self->{race_rounds}) {
224                 $self->{race_finishing} = 1;
225         }
226
227         for my $id (0..5) {
228                 my $car = $new_order[$id];
229                 if ($self->car($car)->{order} != $id) {
230                         $self->car($car)->set_order($id);
231                 }
232         }
233         return ($lap_max_changed, $lap_max, $times[$new_order[0]]);
234 }
235
236 sub recalc_qual_order {
237         my ($self) = @_;
238
239         return if !$self->{qualification_running};
240
241         my @times;
242         for my $id (0..5) {
243                 $times[$id] = $self->car($id)->{best_lap};
244                 if (!defined $times[$id] || $times[$id] <= 0) {
245                         $times[$id] = 999_999;
246                 }
247         }
248
249         my @new_order = sort {
250                 $times[$a] <=> $times[$b]
251                 ||
252                 $a <=> $b;
253         } (0..5);
254
255         my $best_time = $times[$new_order[0]];
256
257         for my $id (0..5) {
258                 my $car = $new_order[$id];
259                 if ($self->car($car)->{order} != $id) {
260                         $self->car($car)->set_order($id);
261                 }
262         }
263         return ($times[$new_order[0]]);
264 }
265
266 sub finish_line {
267         my ($self, $time, $regular, @cars) = @_;
268
269         my %processed;
270         my $was_processed;
271
272         for my $car (@cars) {
273                 if ($self->car($car)->finish_line($time, $regular)) {
274                         $processed{$car} = 1;
275                         $was_processed = 1;
276                 }
277         }
278
279         return if !$was_processed;
280
281         if ($self->{qualification_running}) {
282                 my ($best) = $self->recalc_qual_order;
283                 for my $car (0..5) {
284                         $self->car($car)->recalc_qual_distance($best);
285                 }
286                 return;
287         }
288
289         my ($lap_max_changed, $lap_max, $time_min)
290                 = $self->recalc_order($time);
291
292         for my $car (0..5) {
293                 if ($processed{$car}) {
294                         $self->car($car)->recalc_distance(
295                                 $lap_max, $time_min, $self->{race_finishing},
296                         );
297                 } elsif ($lap_max_changed) {
298                         $self->car($car)->greyout_distance;
299                 }
300         }
301 }
302
303 1;
304