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