392 lines
11 KiB
C++
392 lines
11 KiB
C++
/* --------------------------------------------------------------------
|
|
EXTREME TUXRACER
|
|
|
|
Copyright (C) 1999-2001 Jasmin F. Patry (Tuxracer)
|
|
Copyright (C) 2010 Extreme Tuxracer Team
|
|
|
|
This program is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU General Public License
|
|
as published by the Free Software Foundation; either version 2
|
|
of the License, or (at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
---------------------------------------------------------------------*/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include <etr_config.h>
|
|
#endif
|
|
|
|
#include "racing.h"
|
|
#include "audio.h"
|
|
#include "course_render.h"
|
|
#include "ogl.h"
|
|
#include "view.h"
|
|
#include "env.h"
|
|
#include "track_marks.h"
|
|
#include "hud.h"
|
|
#include "course.h"
|
|
#include "particles.h"
|
|
#include "textures.h"
|
|
#include "game_ctrl.h"
|
|
#include "game_over.h"
|
|
#include "paused.h"
|
|
#include "reset.h"
|
|
#include "winsys.h"
|
|
#include "physics.h"
|
|
|
|
#define MAX_JUMP_AMT 1.0
|
|
#define ROLL_DECAY 0.2
|
|
#define JUMP_MAX_START_HEIGHT 0.30
|
|
|
|
CRacing Racing;
|
|
|
|
static bool right_turn;
|
|
static bool left_turn;
|
|
static bool stick_turn;
|
|
static double stick_turnfact;
|
|
static bool key_paddling;
|
|
static bool stick_paddling;
|
|
static bool key_charging;
|
|
static bool stick_charging;
|
|
static bool key_braking;
|
|
static bool stick_braking;
|
|
static double charge_start_time;
|
|
static bool trick_modifier;
|
|
|
|
static bool sky = true;
|
|
static bool fog = true;
|
|
static bool terr = true;
|
|
static bool trees = true;
|
|
|
|
static int newsound = -1;
|
|
static int lastsound = -1;
|
|
|
|
void CRacing::Keyb (unsigned int key, bool special, bool release, int x, int y) {
|
|
switch (key) {
|
|
// steering flipflops
|
|
case SDLK_UP:
|
|
key_paddling = !release;
|
|
break;
|
|
case SDLK_DOWN:
|
|
key_braking = !release;
|
|
break;
|
|
case SDLK_LEFT:
|
|
left_turn = !release;
|
|
break;
|
|
case SDLK_RIGHT:
|
|
right_turn = !release;
|
|
break;
|
|
case SDLK_SPACE:
|
|
key_charging = !release;
|
|
break;
|
|
case SDLK_t:
|
|
trick_modifier = !release;
|
|
break;
|
|
// mode changing and other actions
|
|
case SDLK_ESCAPE:
|
|
if (!release) {
|
|
g_game.raceaborted = true;
|
|
g_game.race_result = -1;
|
|
State::manager.RequestEnterState (GameOver);
|
|
}
|
|
break;
|
|
case SDLK_p:
|
|
if (!release) State::manager.RequestEnterState (Paused);
|
|
break;
|
|
case SDLK_r:
|
|
if (!release) State::manager.RequestEnterState (Reset);
|
|
break;
|
|
case SDLK_s:
|
|
if (!release) ScreenshotN ();
|
|
break;
|
|
|
|
// view changing
|
|
case SDLK_1:
|
|
if (!release) {
|
|
set_view_mode (Players.GetCtrl (g_game.player_id), ABOVE);
|
|
param.view_mode = ABOVE;
|
|
}
|
|
break;
|
|
case SDLK_2:
|
|
if (!release) {
|
|
set_view_mode (Players.GetCtrl (g_game.player_id), FOLLOW);
|
|
param.view_mode = FOLLOW;
|
|
}
|
|
break;
|
|
case SDLK_3:
|
|
if (!release) {
|
|
set_view_mode (Players.GetCtrl (g_game.player_id), BEHIND);
|
|
param.view_mode = BEHIND;
|
|
}
|
|
break;
|
|
|
|
// toggle
|
|
case SDLK_h:
|
|
if (!release) param.show_hud = !param.show_hud;
|
|
break;
|
|
case SDLK_f:
|
|
if (!release) param.display_fps = !param.display_fps;
|
|
break;
|
|
case SDLK_F5:
|
|
if (!release) sky = !sky;
|
|
break;
|
|
case SDLK_F6:
|
|
if (!release) fog = !fog;
|
|
break;
|
|
case SDLK_F7:
|
|
if (!release) terr = !terr;
|
|
break;
|
|
case SDLK_F8:
|
|
if (!release) trees = !trees;
|
|
break;
|
|
}
|
|
}
|
|
|
|
void CRacing::Jaxis (int axis, double value) {
|
|
if (axis == 0) { // left and right
|
|
stick_turn = ((value < -0.2) || (value > 0.2));
|
|
if (stick_turn) stick_turnfact = value;
|
|
else stick_turnfact = 0.0;
|
|
} else if (axis == 1) { // paddling and braking
|
|
stick_paddling = (value < -0.3);
|
|
stick_braking = (value > 0.3);
|
|
}
|
|
}
|
|
|
|
void CRacing::Jbutt (int button, int state) {
|
|
if (button == 0) {
|
|
key_charging = state != 0;
|
|
} else if (button == 1) {
|
|
// key_charging = (bool) state;
|
|
}
|
|
}
|
|
|
|
void CalcJumpEnergy (double time_step) {
|
|
CControl *ctrl = Players.GetCtrl (g_game.player_id);
|
|
|
|
if (ctrl->jump_charging) {
|
|
ctrl->jump_amt = min (MAX_JUMP_AMT, g_game.time - charge_start_time);
|
|
} else if (ctrl->jumping) {
|
|
ctrl->jump_amt *= (1.0 - (g_game.time - ctrl->jump_start_time) /
|
|
JUMP_FORCE_DURATION);
|
|
} else {
|
|
ctrl->jump_amt = 0;
|
|
}
|
|
}
|
|
|
|
int CalcSoundVol (double fact) {
|
|
double vv = (double) param.sound_volume * fact;
|
|
if (vv > 120) vv = 120;
|
|
return (int) vv;
|
|
}
|
|
|
|
void SetSoundVolumes () {
|
|
Sound.SetVolume ("pickup1", CalcSoundVol (1.0));
|
|
Sound.SetVolume ("pickup2", CalcSoundVol (0.8));
|
|
Sound.SetVolume ("pickup3", CalcSoundVol (0.8));
|
|
Sound.SetVolume ("snow_sound", CalcSoundVol (1.5));
|
|
Sound.SetVolume ("ice_sound", CalcSoundVol (0.6));
|
|
Sound.SetVolume ("rock_sound", CalcSoundVol (1.1));
|
|
}
|
|
|
|
// ---------------------------- init ----------------------------------
|
|
void CRacing::Enter (void) {
|
|
CControl *ctrl = Players.GetCtrl (g_game.player_id);
|
|
|
|
if (param.view_mode < 0 || param.view_mode >= NUM_VIEW_MODES) {
|
|
param.view_mode = ABOVE;
|
|
}
|
|
set_view_mode (ctrl, (TViewMode)param.view_mode);
|
|
left_turn = right_turn = trick_modifier = false;
|
|
|
|
ctrl->turn_fact = 0.0;
|
|
ctrl->turn_animation = 0.0;
|
|
ctrl->is_braking = false;
|
|
ctrl->is_paddling = false;
|
|
ctrl->jumping = false;
|
|
ctrl->jump_charging = false;
|
|
|
|
lastsound = -1;
|
|
newsound = -1;
|
|
|
|
if (State::manager.PreviousState() != &Paused) ctrl->Init ();
|
|
g_game.raceaborted = false;
|
|
|
|
SetSoundVolumes ();
|
|
Music.PlayTheme (g_game.theme_id, MUS_RACING);
|
|
|
|
g_game.finish = false;
|
|
}
|
|
|
|
// -------------------- sound -----------------------------------------
|
|
|
|
// this function is not used yet.
|
|
int SlideVolume (CControl *ctrl, double speed, int typ) {
|
|
if (typ == 1) { // only at paddling or braking
|
|
return (int)(MIN ((((pow(ctrl->turn_fact, 2) * 128)) +
|
|
(ctrl->is_braking ? 128:0) +
|
|
(ctrl->jumping ? 128:0) + 20) * (speed / 10), 128));
|
|
} else { // always
|
|
return (int)(128 * pow((speed/2),2));
|
|
}
|
|
}
|
|
|
|
void PlayTerrainSound (CControl *ctrl, bool airborne) {
|
|
int terridx = -1;
|
|
TTerrType *TerrList = &Course.TerrList[0];
|
|
|
|
if (airborne == false) {
|
|
terridx = Course.GetTerrainIdx (ctrl->cpos.x, ctrl->cpos.z, 0.5);
|
|
if (terridx >= 0) {
|
|
newsound = (int)Sound.GetSoundIdx (TerrList[terridx].sound);
|
|
} else newsound = -1;
|
|
} else newsound = -1;
|
|
if ((newsound != lastsound) && (lastsound >= 0)) Sound.Halt (lastsound);
|
|
if (newsound >= 0) Sound.Play (newsound, -1);
|
|
|
|
lastsound = newsound;
|
|
}
|
|
|
|
// ----------------------- controls -----------------------------------
|
|
void CalcSteeringControls (CControl *ctrl, double time_step) {
|
|
if (stick_turn) {
|
|
ctrl->turn_fact = stick_turnfact;
|
|
ctrl->turn_animation += ctrl->turn_fact * 2 * time_step;
|
|
ctrl->turn_animation = min (1.0, max (-1.0, ctrl->turn_animation));
|
|
} else if (left_turn ^ right_turn) {
|
|
if (left_turn) ctrl->turn_fact = -1.0;
|
|
else ctrl->turn_fact = 1.0;
|
|
ctrl->turn_animation += ctrl->turn_fact * 2 * time_step;
|
|
ctrl->turn_animation = min (1.0, max (-1.0, ctrl->turn_animation));
|
|
} else {
|
|
ctrl->turn_fact = 0.0;
|
|
if (time_step < ROLL_DECAY) {
|
|
ctrl->turn_animation *= 1.0 - time_step / ROLL_DECAY;
|
|
} else {
|
|
ctrl->turn_animation = 0.0;
|
|
}
|
|
}
|
|
|
|
bool paddling = key_paddling || stick_paddling;
|
|
if (paddling && ctrl->is_paddling == false) {
|
|
ctrl->is_paddling = true;
|
|
ctrl->paddle_time = g_game.time;
|
|
}
|
|
|
|
bool braking = key_braking || stick_braking;
|
|
ctrl->is_braking = braking;
|
|
|
|
bool charge = key_charging || stick_charging;
|
|
bool invcharge = !key_charging && !stick_charging;
|
|
CalcJumpEnergy (time_step);
|
|
if ((charge) && !ctrl->jump_charging && !ctrl->jumping) {
|
|
ctrl->jump_charging = true;
|
|
charge_start_time = g_game.time;
|
|
}
|
|
if ((invcharge) && ctrl->jump_charging) {
|
|
ctrl->jump_charging = false;
|
|
ctrl->begin_jump = true;
|
|
}
|
|
}
|
|
|
|
void CalcFinishControls (CControl *ctrl, double timestep, bool airborne) {
|
|
TVector3 movdir = ctrl->cvel;
|
|
double speed = NormVector (movdir);
|
|
double dir_angle = atan (movdir.x / movdir.z) * 57.3;
|
|
|
|
if (fabs (dir_angle) > 5 && speed > 5) {
|
|
ctrl->turn_fact = dir_angle / 20;
|
|
if (ctrl->turn_fact < -1) ctrl->turn_fact = -1;
|
|
if (ctrl->turn_fact > 1) ctrl->turn_fact = 1;
|
|
ctrl->turn_animation += ctrl->turn_fact * 2 * timestep;
|
|
} else {
|
|
ctrl->turn_fact = 0;
|
|
if (timestep < ROLL_DECAY) {
|
|
ctrl->turn_animation *= 1.0 - timestep / ROLL_DECAY;
|
|
} else ctrl->turn_animation = 0.0;
|
|
}
|
|
}
|
|
|
|
// ----------------------- trick --------------------------------------
|
|
|
|
void CalcTrickControls (CControl *ctrl, double time_step, bool airborne) {
|
|
if (airborne && trick_modifier) {
|
|
if (left_turn) ctrl->roll_left = true;
|
|
if (right_turn) ctrl->roll_right = true;
|
|
if (key_paddling) ctrl->front_flip = true;
|
|
if (ctrl->is_braking) ctrl->back_flip = true;
|
|
}
|
|
|
|
if (ctrl->roll_left || ctrl->roll_right) {
|
|
ctrl->roll_factor += (ctrl->roll_left ? -1 : 1) * 0.15 * time_step / 0.05;
|
|
if (ctrl->roll_factor > 1 || ctrl->roll_factor < -1) {
|
|
ctrl->roll_factor = 0;
|
|
ctrl->roll_left = ctrl->roll_right = false;
|
|
}
|
|
}
|
|
if (ctrl->front_flip || ctrl->back_flip) {
|
|
ctrl->flip_factor += (ctrl->back_flip ? -1 : 1) * 0.15 * time_step / 0.05;
|
|
if (ctrl->flip_factor > 1 || ctrl->flip_factor < -1) {
|
|
ctrl->flip_factor = 0;
|
|
ctrl->front_flip = ctrl->back_flip = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
// ====================================================================
|
|
// loop
|
|
// ====================================================================
|
|
|
|
void CRacing::Loop (double time_step) {
|
|
CControl *ctrl = Players.GetCtrl (g_game.player_id);
|
|
double ycoord = Course.FindYCoord (ctrl->cpos.x, ctrl->cpos.z);
|
|
bool airborne = (bool) (ctrl->cpos.y > (ycoord + JUMP_MAX_START_HEIGHT));
|
|
|
|
check_gl_error();
|
|
ClearRenderContext ();
|
|
Env.SetupFog ();
|
|
Music.Update ();
|
|
CalcTrickControls (ctrl, time_step, airborne);
|
|
|
|
if (!g_game.finish) CalcSteeringControls (ctrl, time_step);
|
|
else CalcFinishControls (ctrl, time_step, airborne);
|
|
PlayTerrainSound (ctrl, airborne);
|
|
|
|
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
|
|
ctrl->UpdatePlayerPos (time_step);
|
|
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
|
|
|
|
if (g_game.finish) IncCameraDistance (time_step);
|
|
update_view (ctrl, time_step);
|
|
UpdateTrackmarks (ctrl);
|
|
|
|
SetupViewFrustum (ctrl);
|
|
if (sky) Env.DrawSkybox (ctrl->viewpos);
|
|
if (fog) Env.DrawFog ();
|
|
void SetupLight ();
|
|
if (terr) RenderCourse ();
|
|
DrawTrackmarks ();
|
|
if (trees) DrawTrees ();
|
|
if (param.perf_level > 2) {
|
|
update_particles (time_step);
|
|
draw_particles (ctrl);
|
|
}
|
|
Char.Draw (g_game.char_id);
|
|
UpdateWind (time_step);
|
|
UpdateSnow (time_step, ctrl);
|
|
DrawSnow (ctrl);
|
|
DrawHud (ctrl);
|
|
|
|
Reshape (Winsys.resolution.width, Winsys.resolution.height);
|
|
Winsys.SwapBuffers ();
|
|
if (g_game.finish == false) g_game.time += time_step;
|
|
}
|
|
// ---------------------------------- term ------------------
|
|
void CRacing::Exit() {
|
|
Sound.HaltAll ();
|
|
break_track_marks ();
|
|
}
|