#!/usr/bin/perl -w package SCX::Car; use strict; sub new { my ($class, $args) = @_; my $self = { gui => $args->{gui}, driver => $args->{driver} || '--', throttle => undef, button => undef, fuel => 0, lap => 0, laptime => 0, car_img => $args->{car_img}, id => $args->{id}, track => $args->{track}, }; bless $self, $class; $self->set_order($self->{id}); return $self; } sub gui { return shift->{gui}; } sub track { return shift->{track}; } sub same { my ($self, $key, $val) = @_; return 1 if !defined $self->{$key} && !defined $val || (defined $self->{$key} && defined $val && $self->{$key} eq $val); $self->{$key} = $val; return undef; } sub set_throttle { my ($self, $val, $button, $time) = @_; return if $self->same('throttle', $val) && $self->same('button', $button); if ($self->track->{start_in_progress} && $val) { $self->{early_start} = 1; $self->gui->set_name($self->{order}, 'Early start!'); } if ($self->{in_pit_lane} && defined $val) { $self->{last_finish_time} = $time; if ($val > 3) { $self->leave_pit_lane; } } $self->gui->set_throttle($self->{order}, $val, $button); } sub set_fuel { my ($self, $val) = @_; my $prev = $self->{fuel}; return if $self->same('fuel', $val); if (defined $val && defined $prev && $val < 8) { if ($val == $prev + 1 && !$self->{in_pit_lane}) { print STDERR $self->track->{now}, ' car ', $self->{id}, ' missed pit lane entry', "\n"; $self->enter_pit_lane; } if ($val == $prev - 1 && $val <= 2 && !$self->{in_pit_lane}) { $self->track->{sound}->box($self->{id}); } } if (defined $val && defined $prev && $val == 8 && $prev == 7 && $self->{in_pit_lane}) { $self->track->{sound}->filled($self->{id}); } $self->gui->set_fuel($self->{order}, $val); } sub set_light { # TODO } sub set_backbutton { # TODO } sub set_model { my ($self, $name) = @_; return if $self->same('car_img', $name); $self->gui->set_car_icon($self->{order}, $name); } sub set_lap { my ($self, $lap_nr) = @_; if (!$lap_nr) { $self->{lap} = $lap_nr; $self->gui->set_lap($self->{order}, $lap_nr); return; } return if $self->same('lap', $lap_nr); if (defined $self->{lap} && defined $self->track->{race_rounds} && $self->track->{race_rounds} > 0 && $self->{lap} > $self->track->{race_rounds}) { $self->{finished} = 1; $self->print_state; } $self->gui->set_lap($self->{order}, $lap_nr); if ($self->track->{race_running} && $self->{lap} > 1) { my $now = $self->{last_finish_time}; } } sub set_laptime { my ($self, $lap_time) = @_; if (!defined $lap_time) { $self->{best_lap} = undef; $self->{global_best_lap} = undef; $self->print_best_lap; } return if $self->same('laptime', $lap_time); $self->gui->set_laptime($self->{order}, $lap_time); return if !defined $lap_time || $lap_time <= 1.0 || $self->{in_pit_lane}; return if $self->{finished}; return if defined $self->{best_lap} && $self->{best_lap} <= $lap_time; $self->{best_lap} = $lap_time; $self->print_best_lap; $self->{track}->notify_best_lap($self->{id}, $lap_time, $self->{driver}); } sub print_best_lap { my ($self) = @_; $self->gui->set_best_lap($self->{order}, $self->{best_lap}, $self->{global_best_lap}); } sub set_global_best { my ($self, $val) = @_; $self->{global_best_lap} = $val ? 1 : undef; } sub set_driver { my ($self, $driver_name) = @_; return if $self->same('driver', $driver_name); $self->gui->set_name($self->{order}, $driver_name); } sub enter_pit_lane { my ($self) = @_; return if $self->{in_pit_lane}; $self->{in_pit_lane} = 1; $self->print_state; } sub leave_pit_lane { my ($self) = @_; return if !$self->{in_pit_lane}; $self->{in_pit_lane} = 0; $self->print_state; } sub set_order { my ($self, $pos) = @_; $self->{order} = $pos; $self->gui->set_name($self->{order}, $self->{driver}); $self->gui->set_car_icon($self->{order}, $self->{car_img}); $self->gui->set_throttle($self->{order}, $self->{throttle}, $self->{button}); $self->gui->set_lap($self->{order}, $self->{lap}); $self->gui->set_laptime($self->{order}, $self->{laptime}); $self->gui->set_fuel($self->{order}, $self->{fuel}); $self->gui->set_car_id($self->{order}, $self->{id} + 1); $self->gui->set_distance($self->{order}, $self->{time_diff}, $self->{lap_diff}, $self->{grey_diff}); $self->print_state; $self->print_best_lap; } sub print_state { my ($self) = @_; if ($self->{in_pit_lane}) { $self->{state} = 'pit'; } elsif ($self->{finished}) { $self->{state} = 'finished'; } elsif ($self->{early_start}) { $self->{state} = 'disqualified'; } else { $self->{state} = 'greenflag'; } $self->gui->set_state($self->{order}, $self->{state}); } sub reset { my ($self) = @_; $self->set_lap(0); $self->set_laptime(undef); $self->{finished} = 0; $self->{in_pit_lane} = 0; $self->{early_start} = undef; $self->{last_finish_time} = undef; $self->{first_finish_time} = undef; $self->{time_diff} = undef; $self->{lap_diff} = undef; $self->{total_time} = undef; $self->{grey_diff} = undef; $self->print_state; } sub finish_line { my ($self, $time, $regular) = @_; if (defined $self->{last_finish_time} && $time - $self->{last_finish_time} < 2) { $self->{last_finish_time} = $time; if ($regular && $self->{in_pit_lane}) { $self->leave_pit_lane; } return undef; } if ($regular) { if (defined $self->{first_finish_time}) { $self->set_laptime($time - $self->{first_finish_time}); } } else { $self->enter_pit_lane; } $self->{first_finish_time} = $self->{last_finish_time} = $time; if ($self->track->{race_running}) { $self->set_lap($self->{lap} + 1); } elsif ($self->track->{qualification_running} && !$self->{finished}) { $self->set_lap($self->{lap} + 1); if ($self->{lap} > $self->track->{race_rounds}) { $self->{finished} = 1; $self->print_state; } } return 1; } sub recalc_distance { my ($self, $lap_first, $time_first, $finishing) = @_; return if !defined $lap_first || !defined $self->{lap} || !defined $time_first || !defined $self->{first_finish_time}; $self->{total_time} = undef; $self->{lap_diff} = undef; $self->{time_diff} = undef; $self->{grey_diff} = undef; if ($self->{lap} == $lap_first) { if ($self->{first_finish_time} == $time_first) { $self->{total_time} = $self->{first_finish_time} - $self->track->{race_running_since}; } else { $self->{time_diff} = $self->{first_finish_time} - $time_first; } } else { $self->{lap_diff} = $lap_first - $self->{lap}; } $self->gui->set_distance($self->{order}, $self->{total_time}, $self->{lap_diff}, $self->{time_diff}, $self->{grey_diff}); if ($finishing) { $self->{finished} = 1; $self->print_state; } } sub recalc_qual_distance { my ($self, $time_first) = @_; return if !defined $self->{best_lap} || $self->{best_lap} <= 0; $self->{total_time} = undef; $self->{time_diff} = undef; $self->{grey_diff} = undef; $self->{lap_diff} = undef; if ($self->{best_lap} == $time_first) { $self->{total_time} = $self->{best_lap}; } else { $self->{time_diff} = $self->{best_lap} - $time_first; } $self->gui->set_distance($self->{order}, $self->{total_time}, $self->{lap_diff}, $self->{time_diff}, $self->{grey_diff}); } sub greyout_distance { my ($self) = @_; return if $self->{grey_diff}; $self->{grey_diff} = 1; $self->gui->set_distance($self->{order}, $self->{total_time}, $self->{lap_diff}, $self->{time_diff}, $self->{grey_diff}); } 1;