Beispiel #1
0
wxSize wxSpinButton::DoGetBestSize() const
{
    return IsVertical() ? wxSize( 20, 30 ) : wxSize( 30, 20 );
}
Beispiel #2
0
bool wxChoice::CreateAndInit(wxWindow *parent,
                             wxWindowID id,
                             const wxPoint& pos,
                             const wxSize& size,
                             int n, const wxString choices[],
                             long style,
                             const wxValidator& validator,
                             const wxString& name)
{
    if ( !(style & wxSP_VERTICAL) )
        style |= wxSP_HORIZONTAL;

    if ( (style & wxBORDER_MASK) == wxBORDER_DEFAULT )
        style |= wxBORDER_SIMPLE;

    style |= wxSP_ARROW_KEYS;

    SetWindowStyle(style);

    WXDWORD exStyle = 0;
    WXDWORD msStyle = MSWGetStyle(GetWindowStyle(), & exStyle) ;

    wxSize sizeText(size), sizeBtn(size);
    sizeBtn.x = GetBestSpinnerSize(IsVertical(style)).x;

    if ( sizeText.x == wxDefaultCoord )
    {
        // DEFAULT_ITEM_WIDTH is the default width for the text control
        sizeText.x = DEFAULT_ITEM_WIDTH + MARGIN_BETWEEN + sizeBtn.x;
    }

    sizeText.x -= sizeBtn.x + MARGIN_BETWEEN;
    if ( sizeText.x <= 0 )
    {
        wxLogDebug(wxT("not enough space for wxSpinCtrl!"));
    }

    wxPoint posBtn(pos);
    posBtn.x += sizeText.x + MARGIN_BETWEEN;

    // we must create the list control before the spin button for the purpose
    // of the dialog navigation: if there is a static text just before the spin
    // control, activating it by Alt-letter should give focus to the text
    // control, not the spin and the dialog navigation code will give focus to
    // the next control (at Windows level), not the one after it

    // create the text window

    m_hwndBuddy = (WXHWND)::CreateWindowEx
                    (
                     exStyle,                // sunken border
                     wxT("LISTBOX"),         // window class
                     NULL,                   // no window title
                     msStyle,                // style (will be shown later)
                     pos.x, pos.y,           // position
                     0, 0,                   // size (will be set later)
                     GetHwndOf(parent),      // parent
                     (HMENU)-1,              // control id
                     wxGetInstance(),        // app instance
                     NULL                    // unused client data
                    );

    if ( !m_hwndBuddy )
    {
        wxLogLastError(wxT("CreateWindow(buddy text window)"));

        return false;
    }

    // initialize wxControl
    if ( !CreateControl(parent, id, posBtn, sizeBtn, style, validator, name) )
        return false;

    // now create the real HWND
    WXDWORD spiner_style = WS_VISIBLE |
                           UDS_ALIGNRIGHT |
                           UDS_ARROWKEYS |
                           UDS_SETBUDDYINT |
                           UDS_EXPANDABLE;

    if ( !IsVertical(style) )
        spiner_style |= UDS_HORZ;

    if ( style & wxSP_WRAP )
        spiner_style |= UDS_WRAP;

    if ( !MSWCreateControl(UPDOWN_CLASS, spiner_style, posBtn, sizeBtn, wxEmptyString, 0) )
        return false;

    // subclass the text ctrl to be able to intercept some events
    wxSetWindowUserData(GetBuddyHwnd(), this);
    m_wndProcBuddy = (WXFARPROC)wxSetWindowProc(GetBuddyHwnd(),
                                                wxBuddyChoiceWndProc);

    // set up fonts and colours  (This is nomally done in MSWCreateControl)
    InheritAttributes();
    if (!m_hasFont)
        SetFont(GetDefaultAttributes().font);

    // set the size of the text window - can do it only now, because we
    // couldn't call DoGetBestSize() before as font wasn't set
    if ( sizeText.y <= 0 )
    {
        int cx, cy;
        wxGetCharSize(GetHWND(), &cx, &cy, GetFont());

        sizeText.y = EDIT_HEIGHT_FROM_CHAR_HEIGHT(cy);
    }

    SetInitialSize(size);

    (void)::ShowWindow(GetBuddyHwnd(), SW_SHOW);

    // associate the list window with the spin button
    (void)::SendMessage(GetHwnd(), UDM_SETBUDDY, (WPARAM)GetBuddyHwnd(), 0);

    // do it after finishing with m_hwndBuddy creation to avoid generating
    // initial wxEVT_TEXT message
    ms_allChoiceSpins.Add(this);

    // initialize the controls contents
    for ( int i = 0; i < n; i++ )
    {
        Append(choices[i]);
    }

    return true;
}
Beispiel #3
0
long wxListbook::GetListCtrlIconViewFlags() const
{
    return (IsVertical() ? wxLC_ALIGN_LEFT : wxLC_ALIGN_TOP) | wxLC_ICON;
}
Beispiel #4
0
void VehicleAi::OnTick() {
	if (!game_->GetVehicle() || !game_->GetVehicle()->IsLoaded() ||
		!game_->GetLevel() || !game_->GetLevel()->IsLoaded() ||
		game_->GetFlybyMode() != Game::kFlybyInactive) {
		return;
	}

	const cure::TimeManager* _time = GetManager()->GetGameManager()->GetTimeManager();
	const int mode_run_delta_frame_count = _time->GetCurrentPhysicsFrameDelta(mode_start_frame_);
	const float mode_run_time = _time->ConvertPhysicsFramesToSeconds(mode_run_delta_frame_count);
	const float aim_distance = AIM_DISTANCE;

	float strength = 1.0f;
	const vec3 _position = game_->GetVehicle()->GetPosition();
	const vec3 _velocity = game_->GetVehicle()->GetVelocity();
	switch (mode_) {
		case kModeFindBestPath:
		case kModeFindPathOffElevator: {
			float start_time = 0.5f;
			if (active_path_ != -1) {
				// Synchronize all paths.
				Spline* _path = game_->GetLevel()->QueryPath()->GetPath(active_path_);
				start_time = _path->GetCurrentInterpolationTime();
				active_path_ = -1;
			}
			log_.Headlinef("Trying to find new path... starting iterating from  %.2f.", start_time);
			vec3 elevator_direction;
			if (mode_ == kModeFindPathOffElevator) {
				game_->GetVehicle()->SetEnginePower(0, 0);
				game_->GetVehicle()->SetEnginePower(2, -strength);	// Negative = use full brakes, not only hand brake.
				const cure::Elevator* _nearest_elevator;
				const vec3 elevator_position = GetClosestElevatorPosition(_position, _nearest_elevator);
				if (elevator_position.GetDistanceSquared(_position) > ELEVATOR_TOO_CLOSE_DISTANCE*ELEVATOR_TOO_CLOSE_DISTANCE) {
					log_.AHeadline("Fell off elevator while looking for get-off route. Looking for somewhere else to go.");
					SetMode(kModeFindBestPath);
					return;
				}
				elevator_direction = _nearest_elevator->GetVelocity().GetNormalized(0.5f);
			}
			float best_path_distance = 1000000;
			std::vector<PathIndexLikeliness> relevant_paths;
			bool lifting_towards_goal = false;
			const int path_count = game_->GetLevel()->QueryPath()->GetPathCount();
			for (int x = 0; x < path_count; ++x) {
				bool current_lifting_towards_goal = false;
				Spline* _path = game_->GetLevel()->QueryPath()->GetPath(x);
				_path->GotoAbsoluteTime(start_time);
				float _likeliness = 1;
				const float nearest_distance = GetClosestPathDistance(_position, x, &_likeliness)/SCALE_FACTOR/2;
				log_.Infof(" - Path %2i is %2.2f units away.", x, nearest_distance);
				if (mode_ == kModeFindPathOffElevator) {
					if (_path->GetCurrentInterpolationTime() > 0.7f) {
						// This path is probably the one I used to get ON the elevator (or one
						// just like it from another direction), we're not using that!
						log_.AInfo("   (Not relevant, too close to path end.)");
						continue;
					} else {
						const float towards_distance = GetClosestPathDistance(_position+elevator_direction, x)/SCALE_FACTOR/2;
						if (towards_distance < nearest_distance) {
							current_lifting_towards_goal = true;
							if (!lifting_towards_goal) {
								lifting_towards_goal = true;
								best_path_distance = 1000000;
							}
						}
					}
				}
				if (!current_lifting_towards_goal && lifting_towards_goal) {
					// This elevator isn't heading in the right direction, but at least one other is.
					continue;
				}
				PathIndexLikeliness pl;
				pl.path_index_ = x;
				pl.likeliness_ = _likeliness;
				pl.distance_ = nearest_distance;
				relevant_paths.push_back(pl);
				if (nearest_distance < best_path_distance) {
					best_path_distance = nearest_distance;
				}
			}
			// Sort out those that are too far away.
			float total_likeliness = 0;
			std::vector<PathIndexLikeliness>::iterator x;
			for (x = relevant_paths.begin(); x != relevant_paths.end();) {
				if (x->distance_ < best_path_distance+2.0f) {
					total_likeliness += x->likeliness_;
					++x;
				} else {
					x = relevant_paths.erase(x);
				}
			}
			if (mode_ == kModeFindPathOffElevator) {
				if (best_path_distance > 5 || relevant_paths.size() != 1) {
					if (relevant_paths.size() == 1) {
						// Point wheels in the right direction for us to get off safely.
						Spline* _path = game_->GetLevel()->QueryPath()->GetPath(relevant_paths[0].path_index_);
						const vec3 _direction = game_->GetVehicle()->GetOrientation() * vec3(0,1,0);
						const vec3 wanted_direction = _path->GetValue() - _position;
						const float angle = LEPRA_XY_ANGLE(wanted_direction, _direction);
						game_->GetVehicle()->SetEnginePower(1, angle*0.5f);
					}
					log_.Headlinef("On elevator: too long distance to path %.1f, or too many paths %u.", best_path_distance, relevant_paths.size());
					if (best_path_distance > 15) {
						const cure::Elevator* _nearest_elevator;
						const vec3 nearest_lift_position = GetClosestElevatorPosition(_position, _nearest_elevator);
						if (nearest_lift_position.GetDistanceSquared(_position) > ELEVATOR_TOO_CLOSE_DISTANCE*ELEVATOR_TOO_CLOSE_DISTANCE) {
							// DUCK!!! We fell off!
							log_.AHeadline("Was on elevator: I'm far from the elevator, so must've fallen off!");
							SetMode(kModeFindBestPath);
						}
					}
					if (mode_run_time >= 20) {
						log_.AHeadline("On elevator: been here too long, getting off!");
						SetMode(kModeFindBestPath);
					}
					return;
				}
				log_.Headlinef("Getting off elevator: distance to path %.1f.", best_path_distance);
			}
			deb_assert(!relevant_paths.empty());
			if (relevant_paths.empty()) {
				return;
			}
			const float picked_likeliness = Random::Uniform(0.0f, total_likeliness);
			total_likeliness = 0;
			for (x = relevant_paths.begin(); x != relevant_paths.end(); ++x) {
				const float next_likeliness = total_likeliness + x->likeliness_;
				if (picked_likeliness >= total_likeliness && picked_likeliness <= next_likeliness) {
					active_path_ = x->path_index_;
					break;
				}
				total_likeliness = next_likeliness;
			}
			if (active_path_ < 0) {
				active_path_ = relevant_paths[Random::GetRandomNumber() % relevant_paths.size()].path_index_;
			}
			Spline* _path = game_->GetLevel()->QueryPath()->GetPath(active_path_);
			const float wanted_distance = aim_distance;
			float step = wanted_distance * _path->GetDistanceNormal();
			if (step + _path->GetCurrentInterpolationTime() > 1) {
				step = 1 - _path->GetCurrentInterpolationTime();
			}
			_path->StepInterpolation(step);
			// Fetch ending position.
			const float t = _path->GetCurrentInterpolationTime();
			_path->GotoAbsoluteTime(END_PATH_TIME);
			elevator_get_on_position_ = _path->GetValue();
			_path->GotoAbsoluteTime(t);

			log_.Headlinef("Picked path %i (%i pickable."), active_path_, relevant_paths.size());
			if (mode_ == kModeFindPathOffElevator) {
				SetMode(kModeGetOffElevator);
			} else {
				SetMode(kModeHeadingBackOnTrack);
			}
		} break;
		case kModeHeadingBackOnTrack: {
			if (mode_run_delta_frame_count%5 == 2) {
				const float velocity_scale_factor = std::min(1.0f, _velocity.GetLength() / 2.5f);
				Spline* _path = game_->GetLevel()->QueryPath()->GetPath(active_path_);
				const float current_time = _path->GetCurrentInterpolationTime();
				const float nearest_path_distance = GetClosestPathDistance(_position, active_path_, 0, 1);
				if (nearest_path_distance > 3.0f) {
					// First verify that we haven't ended up under path somehow. We do that by checking
					// steepness, since pure Z-distance may be big when going over ditches.
					const vec3 path_position = _path->GetValue();
					const float steepness = (path_position.z - _position.z) / nearest_path_distance;
					//log_.Infof("Checking steepness, nearest path distance is %.3f, steepness is %.3f.", nearest_path_distance, steepness);
					if (steepness > 0.6f) {
						log_.Infof("Searching for new, better path, we seem to have ended up under the path. Beneath a bridge perhaps? Nearest path is %.2f, steepness is %.2f.", nearest_path_distance, steepness);
						SetMode(kModeFindBestPath);
						return;
					}
				}
				_path->GotoAbsoluteTime(current_time);
				if (nearest_path_distance < SCALE_FACTOR * OFF_COURSE_DISTANCE * velocity_scale_factor) {
					// We were able to return to normal, keep on running.
					SetMode(kModeNormal);
					return;
				}
				/*else if (nearest_path_distance > SCALE_FACTOR * OFF_COURSE_DISTANCE * velocity_scale_factor * 5) {
					// We're far off, perhaps we fell down from a plateu.
					active_path_ = -1;
					SetMode(kModeFindBestPath);
					return;
				}*/
				else if (mode_run_time > 7.0f) {
					SetMode(kModeFindBestPath);
					return;
				}
			}
		}
		// TRICKY: fall through.
		case kModeNormal:
		case kModeGetOnElevator:
		case kModeGetOffElevator: {
			if (mode_ == kModeGetOnElevator) {
				if (mode_run_time > 4.5) {
					log_.Headlinef("Something presumably hinders me getting on the elevator, back square one. (mode run time=%f"), mode_run_time);
					SetMode(kModeFindBestPath);
					return;
				}
				const cure::Elevator* _nearest_elevator;
				const vec3 nearest_lift_position = GetClosestElevatorPosition(elevator_get_on_position_, _nearest_elevator);
				if (nearest_lift_position.z > _position.z+0.5f) {
					log_.AHeadline("Couldn't get on in time, going back to waiting.");
					SetMode(kModeWaitingForElevator);
					return;
				}
			}

			if (mode_ != kModeHeadingBackOnTrack && mode_ != kModeGetOnElevator && mode_run_delta_frame_count%20 == 19) {
				const float _distance = GetClosestPathDistance(_position);
				if (_distance > SCALE_FACTOR * TOTALLY_OFF_COURSE_DISTANCE) {
					log_.AHeadline("Fell off something. Trying some new path.");
					SetMode(kModeFindBestPath);
					return;
				}
				const float velocity_scale_factor = ((mode_ == kModeNormal)? 1.0f : 3.0f) * Math::Clamp(_velocity.GetLength() / 2.5f, 0.3f, 1.0f);
				if (_distance > SCALE_FACTOR * OFF_COURSE_DISTANCE * velocity_scale_factor) {
					log_.AHeadline("Going about my way, but got offside somehow. Heading back.");
					SetMode(kModeHeadingBackOnTrack);
					return;
				}
			}

			Spline* _path = game_->GetLevel()->QueryPath()->GetPath(active_path_);
			vec3 target = _path->GetValue();

			// Check if vehicle stopped. That would mean either crashed against something or too steep hill.
			if (mode_run_delta_frame_count%7 == 4 && game_->GetVehicle()->GetHealth() > 0) {
				if (QueryVehicleHindered(_time, _velocity)) {
					const vec3 _direction = game_->GetVehicle()->GetOrientation() * vec3(0,1,0);
					const vec3 wanted_direction = target-_position;
					const float forward_angle = LEPRA_XY_ANGLE(wanted_direction, _direction);
					// Amplify angle to be either full left or full right.
					const float angle = (forward_angle < 0)? -1.0f : 1.0f;
					game_->GetVehicle()->SetEnginePower(1, -angle);
					SetMode(kModeBackingUp);
					return;
				}
			}

			// Are we heading towards an elevator?
			if (mode_ != kModeGetOnElevator && mode_ != kModeGetOffElevator && _path->GetType() == "to_elevator") {
				if (_path->GetDistanceLeft() <= ELEVATOR_WAIT_DISTANCE) {
					if (elevator_get_on_position_.GetDistanceSquared(_position) <= ELEVATOR_WAIT_DISTANCE*ELEVATOR_WAIT_DISTANCE) {
						log_.AHeadline("Normal mode close to end of path to elevator, changing mode.");
						SetMode(kModeWaitingForElevator);
						return;
					}
				}
			}

			// Did we just pass (fly by?) the goal?
			if (mode_run_delta_frame_count%3 == 0) {
				const vec3 goal_direction = game_->GetGoal()->GetPosition() - _position;
				if (::fabs(goal_direction.z) < 2 &&
					goal_direction.GetLengthSquared() < ELEVATOR_FAR_DISTANCE*ELEVATOR_FAR_DISTANCE &&
					_velocity.GetLengthSquared() < 6*6) {
					const vec3 vehicle_direction = game_->GetVehicle()->GetOrientation() * vec3(0,1,0);
					const float delta_angle = ::fabs(LEPRA_XY_ANGLE(goal_direction, vehicle_direction));
					if (delta_angle >= PIF-PIF/4 && delta_angle <= PIF+PIF/4) {
						log_.AHeadline("Passed goal, it's right behind me!");
						SetMode(kModeBackingUpToGoal);
						return;
					}
				}
			}

			// Step target (aim) ahead.
			{
				const float actual_distance2 = target.GetDistanceSquared(_position);
				const float max_aim_factor = (mode_ == kModeGetOffElevator)? 1.0f : 1.5f;
				const float wanted_distance = aim_distance * Math::Clamp(_velocity.GetLength() / 2.5f, 0.5f, max_aim_factor);
				if (actual_distance2 < wanted_distance*wanted_distance) {
					const float move_ahead = wanted_distance*1.1f - ::sqrt(actual_distance2);
					_path->StepInterpolation(move_ahead * _path->GetDistanceNormal());
					log_volatile(log_.Debugf("Stepping %f (=%f m from %f."), move_ahead*_path->GetDistanceNormal(), move_ahead, _path->GetCurrentInterpolationTime()));
				}

				// Check if we're there yet.
				const float t = _path->GetCurrentInterpolationTime();
				_path->GotoAbsoluteTime(1.0f);
				const float target_distance = (mode_ == kModeGetOnElevator)? ON_ELEVATOR_DISTANCE : ON_GOAL_DISTANCE + game_->GetVehicle()->GetForwardSpeed()/4;
				if (IsCloseToTarget(_position, target_distance)) {
					const bool towards_elevator = (_path->GetType() == "to_elevator");
					if (towards_elevator) {
						if (mode_ == kModeGetOnElevator) {
							SetMode(kModeOnElevator);
							return;
						} else if (mode_ != kModeGetOffElevator) {
							// We got off track somewhere, try to shape up!
							log_.AHeadline("Normal mode target wrapped on our way to an elevator, changing mode.");
							SetMode(kModeWaitingForElevator);
							return;
						}
					} else {
						SetMode(kModeStoppingAtGoal);
						return;
					}
				}
				_path->GotoAbsoluteTime(t);

				target = _path->GetValue();
			}

			const float get_off_delay_time = 0.4f;
			if (!(mode_ == kModeGetOffElevator && mode_run_time < get_off_delay_time)) {
				// Move forward.
				game_->GetVehicle()->SetEnginePower(0, +strength);
				game_->GetVehicle()->SetEnginePower(2, 0);
			}

			// Steer.
			const vec3 _direction = game_->GetVehicle()->GetOrientation() * vec3(0,1,0);
			const vec3 wanted_direction = target-_position;
			float angle = LEPRA_XY_ANGLE(wanted_direction, _direction);
			if (mode_ == kModeGetOffElevator) {
				// Aborting too early might cause us to stop, waiting for the next ride in mid-air.
				const float get_off_distance = GetClosestElevatorRadius() + ELEVATOR_GOT_OFF_EXTRA_DISTANCE;
				vec2 elevator_get_off2d(elevator_get_off_position_.x, elevator_get_off_position_.y);
				vec2 position2d(_position.x, _position.y);
				log_.Infof("ElevatorGetOff (%f;%f, pos (%f;%f)"), elevator_get_off2d.x, elevator_get_off2d.y, position2d.x, position2d.y);
				if (elevator_get_off2d.GetDistanceSquared(position2d) > get_off_distance*get_off_distance) {
					SetMode(kModeNormal);
				}
				angle *= 2;	// Make steering more powerful while getting off.
			}
			game_->GetVehicle()->SetEnginePower(1, +angle);
			last_average_angle_ = Math::Lerp(last_average_angle_, angle, 0.5f);

			// Check if we need to slow down.
			const float high_speed = SCALE_FACTOR * 2.7f;
			const float abs_angle = ::fabs(angle);
			if (_velocity.GetLengthSquared() > high_speed*high_speed) {
				if (abs_angle > 0.2f) {
					float factor = 0.10f;
					game_->GetVehicle()->SetEnginePower(2, abs_angle*factor + _velocity.GetLength()*factor*0.1f);
				} else if (_path->GetCurrentInterpolationTime() >= DOUBLE_OFF_END_PATH_TIME &&
					IsCloseToTarget(_position, SLOW_DOWN_DISTANCE)) {
					game_->GetVehicle()->SetEnginePower(2, 0.2f);
				}
			}
		} break;
		case kModeBackingUp: {
			// Brake or move backward.
			const bool is_moving_forward = (game_->GetVehicle()->GetForwardSpeed() > 0.1f*SCALE_FACTOR);
			game_->GetVehicle()->SetEnginePower(0, is_moving_forward? 0.0f : -strength);
			game_->GetVehicle()->SetEnginePower(2, is_moving_forward? strength :  0.0f);

			const float back_time = 1.7f;
			if (!is_moving_forward && mode_run_time > back_time) {
				SetMode(kModeHeadingBackOnTrack);
				return;
			}
		} break;
		case kModeBackingUpToGoal: {
			vec3 wanted_direction = game_->GetGoal()->GetPosition() - _position;
			const float distance2 = wanted_direction.GetLengthSquared();
			if (distance2 <= ON_GOAL_DISTANCE*ON_GOAL_DISTANCE) {
				Spline* _path = game_->GetLevel()->QueryPath()->GetPath(active_path_);
				_path->GotoAbsoluteTime(END_PATH_TIME);
				SetMode(kModeStoppingAtGoal);
				return;
			} else if (distance2 >= TOTALLY_OFF_COURSE_DISTANCE*TOTALLY_OFF_COURSE_DISTANCE) {
				SetMode(kModeFindBestPath);
				return;
			}

			// Brake or move backward.
			const bool is_moving_forward = (game_->GetVehicle()->GetForwardSpeed() > 0.1f*SCALE_FACTOR);
			game_->GetVehicle()->SetEnginePower(0, is_moving_forward? 0.0f : -strength);
			game_->GetVehicle()->SetEnginePower(2, is_moving_forward? strength :  0.0f);

			// Turn steering wheel.
			const vec3 _direction = game_->GetVehicle()->GetOrientation() * vec3(0,1,0);
			float angle = LEPRA_XY_ANGLE(wanted_direction, _direction);
			angle += (angle < 0)? +PIF : -PIF;
			angle *= 3;
			game_->GetVehicle()->SetEnginePower(1, -angle);

			if (mode_run_time > 15) {
				log_.AHeadline("Not getting back to goal. F**k it.");
				SetMode(kModeRotateOnTheSpot);
				return;
			}
		} break;
		case kModeFlee: {
			// Pedal to the metal.
			game_->GetVehicle()->SetEnginePower(0, +strength);
			game_->GetVehicle()->SetEnginePower(1, 0);
			game_->GetVehicle()->SetEnginePower(2, 0);
			if (mode_run_time > 3.0f) {
				SetMode(kModeFindBestPath);
				return;
			}
		} break;
		case kModeStoppingAtGoal:
		case kModeAtGoal: {
			Spline* _path = game_->GetLevel()->QueryPath()->GetPath(active_path_);
			if (!IsCloseToTarget(_position, ON_GOAL_DISTANCE)) {
				// If either already stopped at goal, OR stopped but at the wrong spot.
				if (mode_ != kModeStoppingAtGoal || game_->GetVehicle()->GetForwardSpeed() < 0.5f*SCALE_FACTOR) {
					_path->GotoAbsoluteTime(DOUBLE_OFF_END_PATH_TIME);	// Close to end, but not at end.
					SetMode(kModeHeadingBackOnTrack);
					return;
				}
			}
			if (mode_ != kModeAtGoal) {
				SetMode(kModeAtGoal);
			}
			// Brake!
			game_->GetVehicle()->SetEnginePower(0, 0);
			game_->GetVehicle()->SetEnginePower(2, -strength);	// Negative = use full brakes, not only hand brake.
		} break;
		case kModeWaitingForElevator: {
			if (mode_run_time > 25.0f) {
				log_.AHeadline("Movin' on, I've waited for the elevator too long.");
				SetMode(kModeFlee);
				return;
			}
			if (::fabs(last_average_angle_) > 0.1f) {
				strength *= SMOOTH_BRAKING_FACTOR;	// Smooth braking when turning, we can always back up if necessary.
			}
			const float elevator_distance2 = elevator_get_on_position_.GetDistanceSquared(_position);
			if (elevator_distance2 < ELEVATOR_TOO_CLOSE_DISTANCE*ELEVATOR_TOO_CLOSE_DISTANCE) {
				log_.AHeadline("Got too close to the elevator stop position, backing up.");
				// Back up parallel to the spline direction.
				const vec3 _direction = game_->GetVehicle()->GetOrientation() * vec3(0,1,0);
				Spline* _path = game_->GetLevel()->QueryPath()->GetPath(active_path_);
				const vec3 wanted_direction = _path->GetSlope();
				const float angle = LEPRA_XY_ANGLE(wanted_direction, _direction);
				game_->GetVehicle()->SetEnginePower(1, +angle);
				const bool is_moving_forward = (game_->GetVehicle()->GetForwardSpeed() > 0.1f*SCALE_FACTOR);
				game_->GetVehicle()->SetEnginePower(0, is_moving_forward? 0.0f : -strength);
				game_->GetVehicle()->SetEnginePower(2, is_moving_forward? strength :  0.0f);

				const cure::Elevator* _nearest_elevator;
				vec3 _nearest_lift_position2d;
				float _elevator_xy_distance2_to_elevator_stop;
				const bool is_elevator_here = HasElevatorArrived(_nearest_elevator, _position.z, _nearest_lift_position2d, _elevator_xy_distance2_to_elevator_stop);
				if (is_elevator_here) {
					SetMode(kModeGetOnElevator);
				} else if (QueryVehicleHindered(_time, _velocity)) {
					last_average_angle_ = (Random::Uniform(0.0f, 1.0f) > 0.5f)? +2.0f : -2.0f;
					SetMode(kModeRotateOnTheSpot);
				}
				return;
			}
			if (::fabs(elevator_get_on_position_.z-_position.z) >= 3 ||
				elevator_distance2 > ELEVATOR_FAR_DISTANCE*ELEVATOR_FAR_DISTANCE) {
				log_.AHeadline("Somehow got away from the elevator wait position, doing something else.");
				SetMode(kModeFindBestPath);
				return;
			}

			// Check that we're headed towards the elevator center.
			if (_velocity.GetLengthSquared() < 0.5f) {
				vec3 up(0, 0, 1);
				up = game_->GetVehicle()->GetOrientation() * up;
				if (up.z > 0.7f) {
					const vec3 _direction = game_->GetVehicle()->GetOrientation() * vec3(0,1,0);
					const vec3 wanted_direction = elevator_get_on_position_ - _position;
					const float angle = LEPRA_XY_ANGLE(wanted_direction, _direction);
					if (::fabs(angle) > PIF/12) {
						rotate_angle_ = -angle;
						SetMode(kModeRotateOnTheSpotWaiting);
						return;
					}
				}
			}

			const cure::Elevator* _nearest_elevator;
			vec3 _nearest_lift_position2d;
			float _elevator_xy_distance2_to_elevator_stop;
			if (HasElevatorArrived(_nearest_elevator, _position.z, _nearest_lift_position2d, _elevator_xy_distance2_to_elevator_stop)) {
				vec3 velocity_xy = _nearest_elevator->GetVelocity();
				bool try_get_on = false;
				// Check if elevator is on it's way out.
				if (IsVertical(velocity_xy)) {
					try_get_on = true;
				} else {
					velocity_xy.x *= 0.1f;
					velocity_xy.y *= 0.1f;
					velocity_xy.z  = 0;
					if (_elevator_xy_distance2_to_elevator_stop+0.1f >= elevator_get_on_position_.GetDistanceSquared(_nearest_lift_position2d+velocity_xy)) {
						try_get_on = true;
					}
				}
				if (try_get_on) {
					log_.AInfo("Elevator here - getting on!");
					SetMode(kModeGetOnElevator);
					return;
				} else {
					log_.AInfo("Waiting for elevator: not getting on, since elevator is departing!");
				}
			}

			game_->GetVehicle()->SetEnginePower(1, 0);
			// Brake!
			game_->GetVehicle()->SetEnginePower(0, 0);
			game_->GetVehicle()->SetEnginePower(2, -strength);	// Negative = use full brakes, not only hand brake.
		} break;
		case kModeOnElevator: {
			strength *= SMOOTH_BRAKING_FACTOR;	// Smooth braking, we can always back up if necessary.

			// Brake!
			game_->GetVehicle()->SetEnginePower(0, 0);
			game_->GetVehicle()->SetEnginePower(1, 0);
			game_->GetVehicle()->SetEnginePower(2, -strength);	// Negative = use full brakes, not only hand brake.

			// Check if elevator departed.
			const float minimum_velocity2 = 0.5f*0.5f;
			if (mode_run_time > 0.7f && _velocity.GetLengthSquared() > minimum_velocity2) {
				const cure::Elevator* _nearest_elevator;
				const vec3 nearest_lift_position = GetClosestElevatorPosition(elevator_get_on_position_, _nearest_elevator);
				if (nearest_lift_position.z > _position.z+0.2f) {
					// Crap, we missed it!
					log_.AHeadline("Must have missed the elevator (it's not close!), waiting for it again!");
					SetMode(kModeWaitingForElevator);
					return;
				}
				// Vehicle speed check not enouch (bouncy wheels), so check elevator speed too.
				vec3 elevator_velocity = _nearest_elevator->GetVelocity();
				if (elevator_velocity.GetLengthSquared() > minimum_velocity2) {
					const bool is_horizontal = !IsVertical(elevator_velocity);
					const vec3 _direction = is_horizontal? elevator_velocity : game_->GetVehicle()->GetOrientation() * vec3(0,1,0);
					rotate_angle_ = -GetRelativeDriveOnAngle(_direction);
					if (::fabs(rotate_angle_) > PIF/6 || is_horizontal) {
						if (is_horizontal) {
							rotate_angle_ = (rotate_angle_ < 0)? -1.3f : +1.3f;
						}
						SetMode(kModeRotateOnTheSpotDuring);
						return;
					}
					SetMode(kModeFindPathOffElevator);
					return;
				}
			} else if (mode_run_time > 4.5f) {
				// Crap, we missed it!
				log_.AHeadline("Must have missed the elevator (I'm still here!), waiting for it again!");
				SetMode(kModeWaitingForElevator);
				return;
			}

			if (mode_run_time > 0.8f) {
				// Check if we should adjust pos.
				const vec3 forward = game_->GetVehicle()->GetOrientation() * vec3(0,1,0);
				const float dist = elevator_get_on_position_.GetDistanceSquared(_position);
				if (dist > elevator_get_on_position_.GetDistanceSquared(_position+forward)) {
					game_->GetVehicle()->SetEnginePower(0, +strength);
					game_->GetVehicle()->SetEnginePower(2, 0);
				} else if (dist > elevator_get_on_position_.GetDistanceSquared(_position-forward)) {
					game_->GetVehicle()->SetEnginePower(0, -strength);
					game_->GetVehicle()->SetEnginePower(2, 0);
				}
			}
		} break;
		case kModeRotateOnTheSpot:
		case kModeRotateOnTheSpotDuring:
		case kModeRotateOnTheSpotWaiting: {
			float angle = rotate_angle_;
			const float min_angle = 0.3f;
			if (::fabs(angle) < min_angle) {
				angle = (angle < 0)? -min_angle : +min_angle;
			}
			float steer_end_time = 0.4f;
			float forward_end_time = steer_end_time + 0.9f;
			float other_steer_end_time = forward_end_time + steer_end_time;
			float period = other_steer_end_time + 0.8f;

			// A monster truck's steering impared.
			angle *= 2;
			steer_end_time = 0.7f;
			forward_end_time = steer_end_time + 0.7f;
			other_steer_end_time = forward_end_time + steer_end_time;
			period = other_steer_end_time + 1.0f;
			strength *= SMOOTH_BRAKING_FACTOR;
			if (mode_ == kModeRotateOnTheSpotWaiting) {
				const cure::Elevator* _nearest_elevator;
				vec3 _nearest_lift_position2d;
				float _elevator_xy_distance2_to_elevator_stop;
				if (HasElevatorArrived(_nearest_elevator, _position.z, _nearest_lift_position2d, _elevator_xy_distance2_to_elevator_stop)) {
					log_.AHeadline("Elevator arrived while rotating on the spot, getting on instead!");
					SetMode(kModeGetOnElevator);
					return;
				}
			}
			// Finish this rotation show if we're getting there.
			const int iterations = (mode_ == kModeRotateOnTheSpotWaiting)? 1 : 2;
			if (mode_run_time > iterations*period+steer_end_time) {
				game_->GetVehicle()->SetEnginePower(0, 0);
				game_->GetVehicle()->SetEnginePower(1, -angle);
				game_->GetVehicle()->SetEnginePower(2, -1);
				if (mode_ == kModeRotateOnTheSpot) {
					SetMode(kModeHeadingBackOnTrack);
				} else if (mode_ == kModeRotateOnTheSpotDuring) {
					SetMode(kModeFindPathOffElevator);
				} else {
					SetMode(kModeWaitingForElevator);
				}
				return;
			}
			for (int x = 0; x < iterations+1; ++x) {
				const float base = x*period;
				if (mode_run_time >= base && mode_run_time < base+steer_end_time) {
					// Brake and turn in "forward direction".
					game_->GetVehicle()->SetEnginePower(0, 0);
					game_->GetVehicle()->SetEnginePower(1, -angle);
					game_->GetVehicle()->SetEnginePower(2, -strength);
					break;
				} else if (mode_run_time >= base+steer_end_time && mode_run_time < base+forward_end_time) {
					// Drive forward.
					game_->GetVehicle()->SetEnginePower(0, +strength);
					game_->GetVehicle()->SetEnginePower(2, 0);
					break;
				} else if (mode_run_time >= base+forward_end_time && mode_run_time < base+other_steer_end_time) {
					// Brake and turn in "backward direction".
					game_->GetVehicle()->SetEnginePower(0, 0);
					game_->GetVehicle()->SetEnginePower(1, +angle);
					game_->GetVehicle()->SetEnginePower(2, -strength);
					break;
				} else if (mode_run_time >= base+other_steer_end_time && mode_run_time < base+period) {
					// Drive backward.
					game_->GetVehicle()->SetEnginePower(0, -0.7f*strength);
					game_->GetVehicle()->SetEnginePower(2, 0);
					break;
				}
			}
		} break;
	}
bool wxScrollBar::MSWOnScroll(int WXUNUSED(orientation), WXWORD wParam,
                              WXWORD WXUNUSED(pos), WXHWND WXUNUSED(control))
{
    // don't use pos parameter because it is limited to 16 bits, get the full
    // 32 bit position from the control itself instead
    WinStruct<SCROLLINFO> scrollInfo;
    scrollInfo.fMask = SIF_RANGE | SIF_POS | SIF_TRACKPOS;

    if ( !::GetScrollInfo(GetHwnd(), SB_CTL, &scrollInfo) )
    {
        wxLogLastError(wxT("GetScrollInfo"));
        return false;
    }

    int maxPos = scrollInfo.nMax;

    // A page size greater than one has the effect of reducing the effective
    // range, therefore the range has already been boosted artificially - so
    // reduce it again.
    if ( m_pageSize > 1 )
        maxPos -= (m_pageSize - 1);

    int position = scrollInfo.nPos;
    wxEventType scrollEvent = wxEVT_NULL;
    switch ( wParam )
    {
        case SB_TOP:
            position = 0;
            scrollEvent = wxEVT_SCROLL_TOP;
            break;

        case SB_BOTTOM:
            position = maxPos;
            scrollEvent = wxEVT_SCROLL_BOTTOM;
            break;

        case SB_LINEUP:
            position--;
            scrollEvent = wxEVT_SCROLL_LINEUP;
            break;

        case SB_LINEDOWN:
            position++;
            scrollEvent = wxEVT_SCROLL_LINEDOWN;
            break;

        case SB_PAGEUP:
            position -= GetPageSize();
            scrollEvent = wxEVT_SCROLL_PAGEUP;
            break;

        case SB_PAGEDOWN:
            position += GetPageSize();
            scrollEvent = wxEVT_SCROLL_PAGEDOWN;
            break;

        case SB_THUMBPOSITION:
        case SB_THUMBTRACK:
            position = scrollInfo.nTrackPos;
            scrollEvent = wParam == SB_THUMBPOSITION ? wxEVT_SCROLL_THUMBRELEASE
                                                     : wxEVT_SCROLL_THUMBTRACK;
            break;

        case SB_ENDSCROLL:
            scrollEvent = wxEVT_SCROLL_CHANGED;
            break;
    }

    if ( position != scrollInfo.nPos )
    {
        if ( position < 0 )
            position = 0;
        if ( position > maxPos )
            position = maxPos;

        SetThumbPosition(position);
    }
    else if ( scrollEvent != wxEVT_SCROLL_THUMBRELEASE &&
                scrollEvent != wxEVT_SCROLL_CHANGED )
    {
        // don't process the event if there is no displacement,
        // unless this is a thumb release or end scroll event.
        return false;
    }

    wxScrollEvent event(scrollEvent, m_windowId);
    event.SetOrientation(IsVertical() ? wxVERTICAL : wxHORIZONTAL);
    event.SetPosition(position);
    event.SetEventObject( this );

    return HandleWindowEvent(event);
}
void wxFoldPanelBar::OnSizePanel(wxSizeEvent &event)
{
    // skip all stuff when we are not initialised yet

    if(!m_controlCreated)
    {
        event.Skip();
        return;
    }

    // now size the fold panel area and the
    // lower bar in such a way that the bar is always
    // visible

    wxRect foldrect = GetRect();

    // fold panel itself. If too little space,
    // don't show it

#if 0
    if(foldrect.GetHeight() < 23)
        foldrect.SetHeight(0);
    else
        foldrect.SetHeight(foldrect.GetHeight() - 22);
#endif

    foldrect.SetX(0);
    foldrect.SetY(0);
    m_foldPanel->SetSize(foldrect);

    if(m_extraStyle & wxFPB_COLLAPSE_TO_BOTTOM)
    {
        wxRect rect = RepositionCollapsedToBottom();
        bool vertical = IsVertical();
        if((vertical && rect.GetHeight() > 0) || (!vertical && rect.GetWidth() > 0))
            RefreshRect(rect);
    }

    // TODO: A smart way to check wether the old - new width of the
    // panel changed, if so no need to resize the fold panel items

    RedisplayFoldPanelItems();

    // tool panel for icons and other stuff

#if 0
    wxRect bottomrect = GetRect();
    if(bottomrect.GetHeight() < 22)
        bottomrect.SetY(0);
    else
        bottomrect.SetY(bottomrect.GetHeight() - 22);

    bottomrect.SetHeight(22);
    bottomrect.SetX(0);
    m_bottomPanel->SetSize(bottomrect);

    // TODO: redraw the bitmap properly
    // use the captionbar algorithm for that

    m_bottomPanel->Refresh();
#endif
}