]> www.fi.muni.cz Git - slotcarman.git/blob - SCX/Track.pm
fcf6b80d94747fbe3cf4e1af8edf0d285f78de9a
[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 Time::HiRes qw(gettimeofday);
9 use Glib qw(TRUE FALSE);
10 use SCX::Car;
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         };
23
24         bless $self, $class;
25
26         for my $i (0..5) {
27                 $self->{cars}->[$i] = SCX::Car->new({
28                         gui => $self->{gui},
29                         id => $i,
30                         track => $self,
31                 });
32         }
33
34         $self->print_rounds;
35         $self->{gui}->time(undef);
36         $self->{gui}->best_lap(undef, undef);
37
38         return $self;
39 }
40
41 sub car { return shift->{cars}->[shift]; }
42
43 sub race_start {
44         my ($self) = @_;
45
46         return if $self->{race_running} || $self->{start_in_progress}
47                 || $self->{qualification_running};
48         $self->{round} = 0;
49         $self->{race_running} = 0;
50         $self->{start_in_progress} = 1;
51         $self->{semaphore} = 0;
52         $self->{gui}->show_semaphore(0);
53         Glib::Timeout->add($SEMAPHORE_STEP, \&semaphore_step, $self);
54 }
55
56 sub semaphore_step {
57         my ($self) = @_;
58
59         return FALSE if !$self->{start_in_progress} && !$self->{race_running};
60
61         $self->{semaphore}++;
62         if ($self->{semaphore} <= 5) {
63                 $self->{gui}->show_semaphore($self->{semaphore});
64                 my $timeout = $SEMAPHORE_STEP;
65                 $timeout += $SEMAPHORE_STEP * rand()
66                         if $self->{semaphore} == 5;
67                 Glib::Timeout->add($timeout, \&semaphore_step, $self);
68         } elsif ($self->{semaphore} == 6) {
69                 $self->{race_running} = 1;
70                 $self->{race_running_since} = gettimeofday;
71                 $self->{start_in_progress} = undef;
72                 $self->{gui}->show_semaphore(0);
73                 Glib::Timeout->add($SEMAPHORE_STEP, \&semaphore_step, $self);
74         } else {
75                 $self->{gui}->show_semaphore(undef);
76                 $self->{semaphore} = undef;
77         }
78         return FALSE;
79 }
80 sub race_end {
81         my ($self) = @_;
82
83         $self->{race_running} = 0;
84 }
85
86 sub race_setup {
87         my ($self, $rounds) = @_;
88
89         $self->{round} = 0;
90         if ($rounds) {
91                 $self->{race_rounds} = $rounds;
92         } else {
93                 $self->{race_rounds} = 0;
94         }
95
96         $self->print_rounds;
97         $self->{best_lap} = undef;
98
99         $self->{gui}->show_semaphore(undef);
100         $self->{race_running} = 0;
101         $self->{start_in_progress} = 0;
102
103         $self->{gui}->time(undef);
104         $self->{gui}->best_lap(undef);
105 }
106
107 sub reset {
108         my ($self) = @_;
109
110         $self->{race_running} = 0;
111         $self->{start_in_progress} = 0;
112         $self->{race_finishing} = 0;
113         $self->{best_lap} = undef;
114         $self->{round} = 0;
115
116         $self->print_rounds;
117         $self->{gui}->best_lap(undef);
118         $self->{gui}->time(undef);
119
120         for my $car (0..5) {
121                 $self->car($car)->reset;
122         }
123 }
124
125 sub print_rounds {
126         my ($self) = @_;
127
128         my $msg;
129         if ($self->{qualification_running}) {
130                 $msg = 'Qualification';
131         } elsif ($self->{race_rounds}) {
132                 $msg = $self->{round} . '/' . $self->{race_rounds};
133         } else {
134                 $msg = $self->{round};
135         }
136
137         $self->{gui}->rounds($msg);
138 }
139
140 sub check_best_lap {
141         my ($self, $time, $who) = @_;
142
143         return if !defined $time || $time == 0;
144
145 #       print "Check_best_lap $time $who vs ",
146 #               defined $self->{best_lap} ? $self->{best_lap} : 'undef',
147 #               "\n";
148         if (!defined $self->{best_lap}
149                 || $time < $self->{best_lap}) {
150                 $self->{best_lap} = $time;
151                 $self->{gui}->best_lap($time, $who);
152                 return 1;
153         }
154         return 0;
155 }
156
157 sub qualification_start {
158         my ($self) = @_;
159
160         return if $self->{qualification_running};
161         for my $car (0..5) {
162                 $self->car($car)->set_lap(undef);
163                 $self->car($car)->set_laptime(undef);
164         }
165
166         $self->{qualification_running} = 1;
167         $self->{gui}->rounds('Qualification');
168         $self->{gui}->time(undef);
169         $self->{gui}->best_lap(undef);
170 }
171
172 sub packet_received {
173         my ($self, $time) = @_;
174
175         if ($self->{race_running}) {
176                 $self->{gui}->time($time - $self->{race_running_since});
177         }
178 }
179
180 sub recalc_order {
181         my ($self, $now) = @_;
182
183         return if !$self->{race_running};
184
185         my @laps;
186         my @times;
187         for my $id (0..5) {
188                 $laps[$id]  = $self->car($id)->{lap} // -1;
189                 $times[$id] = $self->car($id)->{first_finish_time} // $now;
190         }
191
192         my @new_order = sort {
193                 $laps[$b] <=> $laps[$a]
194                 ||
195                 $times[$a] <=> $times[$b]
196                 ||
197                 $a <=> $b;
198         } (0..5);
199
200         my $lap_max = $laps[$new_order[0]];
201         my $lap_max_changed = 0;
202         if (defined $lap_max && defined $self->{round}
203                 && $lap_max != $self->{round}) {
204                 $self->{round} = $lap_max;
205                 $lap_max_changed = 1;
206                 $self->print_rounds;
207         }
208
209         if ($self->{round} && $self->{race_rounds}
210                 && $self->{round} > $self->{race_rounds}) {
211                 $self->{race_finishing} = 1;
212         }
213
214         for my $id (0..5) {
215                 my $car = $new_order[$id];
216                 if ($self->car($car)->{order} != $id) {
217                         $self->car($car)->set_order($id);
218                 }
219         }
220         return ($lap_max_changed, $lap_max, $times[$new_order[0]]);
221 }
222
223 sub finish_line {
224         my ($self, $time, $regular, @cars) = @_;
225
226         my %processed;
227         my $was_processed;
228
229         for my $car (@cars) {
230                 if ($self->car($car)->finish_line($time, $regular)) {
231                         $processed{$car} = 1;
232                         $was_processed = 1;
233                 }
234         }
235
236         return if !$was_processed;
237
238         my ($lap_max_changed, $lap_max, $time_min)
239                 = $self->recalc_order($time);
240
241         for my $car (0..5) {
242                 if ($processed{$car}) {
243                         $self->car($car)->recalc_distance(
244                                 $lap_max, $time_min, $self->{race_finishing},
245                         );
246                 } elsif ($lap_max_changed) {
247                         $self->car($car)->greyout_distance;
248                 }
249         }
250 }
251
252 1;
253