Clean
This commit is contained in:
parent
e695921c5c
commit
6986028e33
4 changed files with 171 additions and 155 deletions
22
audio.h
22
audio.h
|
@ -1,5 +1,10 @@
|
||||||
/**
|
/*
|
||||||
audio: this file implements the audio system.
|
Licar audio
|
||||||
|
|
||||||
|
This file implements the audio system. The module only computes audio samples
|
||||||
|
(playing them must be done by the frontend). The audio format is 8bit, 8 KHz
|
||||||
|
mono. This module does NOT deal with music (music is stored in a separate
|
||||||
|
file, left to be optionally loaded and played by the frontend).
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef _LCR_AUDIO
|
#ifndef _LCR_AUDIO
|
||||||
|
@ -26,6 +31,9 @@ struct
|
||||||
int engineInc;
|
int engineInc;
|
||||||
} LCR_audio;
|
} LCR_audio;
|
||||||
|
|
||||||
|
/**
|
||||||
|
Initializes the audio system, only call once.
|
||||||
|
*/
|
||||||
void LCR_audioInit(void)
|
void LCR_audioInit(void)
|
||||||
{
|
{
|
||||||
LCR_LOG0("initializing audio");
|
LCR_LOG0("initializing audio");
|
||||||
|
@ -40,11 +48,18 @@ void LCR_audioInit(void)
|
||||||
LCR_audio.engineIntensity = 0;
|
LCR_audio.engineIntensity = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Sets the intensity of car engine sound that's constantly played (unless when
|
||||||
|
intensitiy has been set to 0). Maximum value is 255.
|
||||||
|
*/
|
||||||
void LCR_audioSetEngineIntensity(uint8_t value)
|
void LCR_audioSetEngineIntensity(uint8_t value)
|
||||||
{
|
{
|
||||||
LCR_audio.engineIntensity = value;
|
LCR_audio.engineIntensity = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Tells the audio system to play certain sound (see the sound constants).
|
||||||
|
*/
|
||||||
void LCR_audioPlaySound(uint8_t sound)
|
void LCR_audioPlaySound(uint8_t sound)
|
||||||
{
|
{
|
||||||
LCR_LOG2("playing sound");
|
LCR_LOG2("playing sound");
|
||||||
|
@ -58,6 +73,9 @@ uint8_t _LCR_audioNoise(void)
|
||||||
return LCR_audio.noise >> 16;
|
return LCR_audio.noise >> 16;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Gets the next audio sample.
|
||||||
|
*/
|
||||||
uint8_t LCR_audioGetNextSample(void)
|
uint8_t LCR_audioGetNextSample(void)
|
||||||
{
|
{
|
||||||
unsigned char result = 128;
|
unsigned char result = 128;
|
||||||
|
|
98
game.h
98
game.h
|
@ -8,6 +8,9 @@
|
||||||
graphics, sound etc., and is meant to be included and used by specific
|
graphics, sound etc., and is meant to be included and used by specific
|
||||||
frontends (which will handle each platform's hardware details and I/O). See
|
frontends (which will handle each platform's hardware details and I/O). See
|
||||||
the frontend info below for help with porting the game to a new platform.
|
the frontend info below for help with porting the game to a new platform.
|
||||||
|
This module (with the help of other modules) will perform all the computations
|
||||||
|
(physics, graphics, audio, ...) and only use the frontend's quite primitive
|
||||||
|
functions to actually present the results to the user.
|
||||||
|
|
||||||
The code uses LCR_ (or _LCR) prefix as a kind of namespace preventing
|
The code uses LCR_ (or _LCR) prefix as a kind of namespace preventing
|
||||||
collision with 3rd party identifiers.
|
collision with 3rd party identifiers.
|
||||||
|
@ -59,19 +62,21 @@
|
||||||
|
|
||||||
/*
|
/*
|
||||||
FOR FRONTENDS (porting to other platforms):
|
FOR FRONTENDS (porting to other platforms):
|
||||||
- Implement the below described functions according to their description.
|
- Implement the frontend functions given below according to their description.
|
||||||
- Implement the main program and game loop.
|
- Implement the main program and game loop.
|
||||||
- Call the below described functions as described.
|
- Call some of the frontend funtions given below in your main program in
|
||||||
- If you want to support music, make your frontend play music from the "music"
|
places as described in the description of the function.
|
||||||
file in assets. It is in raw format, storing 8bit unsigned samples at 8000
|
- If you want to support music, make your code load and play the "music"
|
||||||
Hz. Use the LCR_gameMusicOn to check what the music volume is. If you
|
file in the asset directory. It is in raw format, storing 8bit unsigned
|
||||||
don't support music, set LCR_SETTING_MUSIC to 0 in your frontend code so
|
samples at 8 KHz mono. Use the LCR_gameMusicOn function to check whether the
|
||||||
that the game knows music is disabled.
|
music is currently enabled (if not, stop playing it). If you don't want to
|
||||||
|
support music, set LCR_SETTING_MUSIC to 0 in your frontend code (before
|
||||||
|
including this module) so that the game knows music is disabled.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Implement this in your frontend. Returns 1 if given key is pressed or 0
|
Implement this in your frontend. Returns 1 if given key (see LCR_KEY_*
|
||||||
otherwise.
|
constants) is pressed or 0 otherwise.
|
||||||
*/
|
*/
|
||||||
uint8_t LCR_keyPressed(uint8_t key);
|
uint8_t LCR_keyPressed(uint8_t key);
|
||||||
|
|
||||||
|
@ -87,35 +92,40 @@ void LCR_sleep(uint16_t timeMs);
|
||||||
to the screen back buffer (i.e. NOT directly to screen, back buffer shall
|
to the screen back buffer (i.e. NOT directly to screen, back buffer shall
|
||||||
only be copied to front buffer once the LCR_gameStep function finishes all
|
only be copied to front buffer once the LCR_gameStep function finishes all
|
||||||
rendering). This function should NOT check for out-of-screen coordinates, this
|
rendering). This function should NOT check for out-of-screen coordinates, this
|
||||||
is handled by the game internals and out-of-screen pixels will never be drawn.
|
is handled by the game internals and out-of-screen pixels will never be drawn
|
||||||
The color value depends on game settings but is normally an RGB565 value.
|
(your code unnecessarily checking it again would likely slow down rendering a
|
||||||
|
lot, as drawing pixels is a bottleneck). The color value depends on game
|
||||||
|
settings but is normally an RGB565 value. The index parameter says the
|
||||||
|
coordinate at which to write the pixel, assuming the pixels are stored by
|
||||||
|
rows, from top to bottom.
|
||||||
*/
|
*/
|
||||||
void LCR_drawPixel(unsigned long index, uint16_t color);
|
void LCR_drawPixel(unsigned long index, uint16_t color);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Implement this in your frontend. This function will be called to log what the
|
Implement this in your frontend. This function will be called to log what the
|
||||||
program is doing. If you want to ignore logging, simply make the function do
|
program is doing. Typically this function should print the string to console.
|
||||||
nothing.
|
If you want to ignore logging, simply make the function do nothing.
|
||||||
*/
|
*/
|
||||||
void LCR_log(const char *str);
|
void LCR_log(const char *str);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Implement this in your frontend. This function serves for loading optional
|
Implement this in your frontend. This function serves for loading optional
|
||||||
data file that allows to add more maps, replays etc. If your frontend
|
data file that allows adding more maps, replays etc. If your frontend won't
|
||||||
won't support this, just make the function return 0. Otherwise it must return
|
support this, just make the function return 0. Otherwise it must return
|
||||||
characters from the data file one by one; after reaching the end of file
|
characters from the data file one by one; after reaching the end of file 0
|
||||||
0 must be returned and the reading position will be reset to start again.
|
must be returned and the reading position will be reset to start from
|
||||||
|
beginning again.
|
||||||
*/
|
*/
|
||||||
char LCR_getNextDataFileChar(void);
|
char LCR_getNextDataFileChar(void);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Implement this in your frontend. This serves to store data in the optional
|
Implement this in your frontend. This serves to store data in the optional
|
||||||
data file, e.g. replays. If your frontend doesn't support this (e.g.
|
data file (e.g. replays and info about beaten maps). If your frontend doesn't
|
||||||
because the file is read only), the function may ignore the append, but if
|
support this (e.g. because the file is read only), the function may ignore the
|
||||||
the file is otherwise supported, a rewind of the read position must still be
|
append, but if the file is otherwise supported, a rewind of the read position
|
||||||
done. If appending is supported, the function must append the provided string
|
must still be performed. If appending is supported, the function must append
|
||||||
to the data file AND then reset the data file reading position back to
|
the provided string to the data file AND then reset the data file reading
|
||||||
the start.
|
position back to the start.
|
||||||
*/
|
*/
|
||||||
void LCR_appendDataStr(const char *str);
|
void LCR_appendDataStr(const char *str);
|
||||||
|
|
||||||
|
@ -134,18 +144,22 @@ void LCR_gameEnd(void);
|
||||||
Call this function in your frontend repeatedly inside the main loop, pass the
|
Call this function in your frontend repeatedly inside the main loop, pass the
|
||||||
current time as the number of milliseconds since program start. This function
|
current time as the number of milliseconds since program start. This function
|
||||||
will perform the game step AND other things such as checking the input states,
|
will perform the game step AND other things such as checking the input states,
|
||||||
rendering or sleeping (all using the above functions you should implement).
|
rendering or sleeping (all using the above described functions you should
|
||||||
Returns 0 if program should end, otherwise 1.
|
implement). Returns 0 if program should end, otherwise 1.
|
||||||
*/
|
*/
|
||||||
uint8_t LCR_gameStep(uint32_t timeMs);
|
uint8_t LCR_gameStep(uint32_t timeMs);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Gets the current music volume;
|
Returns 1 if music is currently on, else 0. If your frontend supports music,
|
||||||
|
use this function at each frame to know whether you should start/stop playing
|
||||||
|
music. Otherwise ignore this.
|
||||||
*/
|
*/
|
||||||
uint8_t LCR_gameMusicOn(void);
|
uint8_t LCR_gameMusicOn(void);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Gets next audio sample (unsigned 8bit samples, 8 KHz).
|
Gets the next audio sample (unsigned 8bit samples, 8 KHz mono). If your
|
||||||
|
frontend supports sound, call this continuously and play the stream of
|
||||||
|
samples, otherwise ignore this.
|
||||||
*/
|
*/
|
||||||
uint8_t LCR_gameGetNextAudioSample(void);
|
uint8_t LCR_gameGetNextAudioSample(void);
|
||||||
|
|
||||||
|
@ -187,7 +201,7 @@ uint8_t LCR_gameGetNextAudioSample(void);
|
||||||
// forward decls of pixel drawing functions for the renderer
|
// forward decls of pixel drawing functions for the renderer
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Internal pixel drawing function that draws pixel at specified screen coords
|
Internal pixel drawing function that puts a pixel at specified screen coords
|
||||||
without checking for safety (it's faster but can only be done if we know for
|
without checking for safety (it's faster but can only be done if we know for
|
||||||
sure we're not drawing outside the screen).
|
sure we're not drawing outside the screen).
|
||||||
*/
|
*/
|
||||||
|
@ -213,7 +227,7 @@ static inline void LCR_drawPixelXYSafe(unsigned int x, unsigned int y,
|
||||||
|
|
||||||
#if LCR_SETTING_GHOST_MAX_SAMPLES == 0
|
#if LCR_SETTING_GHOST_MAX_SAMPLES == 0
|
||||||
#undef LCR_MENU_TABS
|
#undef LCR_MENU_TABS
|
||||||
#define LCR_MENU_TABS 3
|
#define LCR_MENU_TABS 3 // no ghosts => remove the tab for ghosts
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define LCR_MENU_STRING_SIZE 16
|
#define LCR_MENU_STRING_SIZE 16
|
||||||
|
@ -241,18 +255,17 @@ struct
|
||||||
{
|
{
|
||||||
uint8_t state;
|
uint8_t state;
|
||||||
uint32_t stateStartTime;
|
uint32_t stateStartTime;
|
||||||
uint32_t time;
|
uint32_t time; ///< Current frame's time.
|
||||||
uint32_t frame;
|
uint32_t frame; ///< Current frame number.
|
||||||
uint32_t nextRenderFrameTime;
|
uint32_t nextRenderFrameTime; ///< At which frame to render next frame.
|
||||||
uint32_t nextRacingTickTime;
|
uint32_t nextRacingTickTime; ///< When to simulate next physics tick.
|
||||||
uint8_t cameraMode;
|
uint8_t cameraMode;
|
||||||
uint8_t debugDraw;
|
|
||||||
uint8_t musicOn;
|
uint8_t musicOn;
|
||||||
uint8_t keyStates[LCR_KEYS_TOTAL]; /**< Assures unchanging key states
|
uint8_t keyStates[LCR_KEYS_TOTAL]; /**< Assures unchanging key states
|
||||||
during a single frame, hold number of
|
during a single frame, hold number of
|
||||||
frames for which the key has been
|
frames for which the key has been
|
||||||
continuously held. */
|
continuously held. */
|
||||||
uint32_t runTimeMS; /**< Current time of the run */
|
uint32_t runTimeMS; ///< Current time of the run
|
||||||
|
|
||||||
struct
|
struct
|
||||||
{
|
{
|
||||||
|
@ -260,14 +273,14 @@ struct
|
||||||
uint8_t selectedItem;
|
uint8_t selectedItem;
|
||||||
uint8_t itemCount;
|
uint8_t itemCount;
|
||||||
char itemNames[LCR_MENU_MAX_ITEMS][LCR_MENU_STRING_SIZE];
|
char itemNames[LCR_MENU_MAX_ITEMS][LCR_MENU_STRING_SIZE];
|
||||||
const char *itemNamePtrs[LCR_MENU_MAX_ITEMS]; ///< helper array
|
const char *itemNamePtrs[LCR_MENU_MAX_ITEMS]; ///< Helper array.
|
||||||
} menu;
|
} menu;
|
||||||
|
|
||||||
struct
|
struct
|
||||||
{
|
{
|
||||||
int state; ///< -1 if reading external res. f., else pos.
|
int state; ///< -1 if reading external data f., else pos.
|
||||||
|
|
||||||
// indices and counts are among the data of the same type
|
// Indices and counts are among the data of the same type.
|
||||||
unsigned int firstItemIndex;
|
unsigned int firstItemIndex;
|
||||||
unsigned int itemsTotal;
|
unsigned int itemsTotal;
|
||||||
} dataFile;
|
} dataFile;
|
||||||
|
@ -286,7 +299,6 @@ struct
|
||||||
is to allow ghosts for even long replays. */
|
is to allow ghosts for even long replays. */
|
||||||
} ghost;
|
} ghost;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
} LCR_game;
|
} LCR_game;
|
||||||
|
|
||||||
uint8_t LCR_gameMusicOn(void)
|
uint8_t LCR_gameMusicOn(void)
|
||||||
|
@ -448,7 +460,7 @@ void _LCR_gamePrepareGhost(void)
|
||||||
|
|
||||||
LCR_game.ghost.stretch = 0;
|
LCR_game.ghost.stretch = 0;
|
||||||
|
|
||||||
while (((int) LCR_replay.achievedTime) >
|
while (((int) LCR_racing.replay.achievedTime) >
|
||||||
(LCR_SETTING_GHOST_STEP << LCR_game.ghost.stretch) *
|
(LCR_SETTING_GHOST_STEP << LCR_game.ghost.stretch) *
|
||||||
LCR_SETTING_GHOST_MAX_SAMPLES)
|
LCR_SETTING_GHOST_MAX_SAMPLES)
|
||||||
{
|
{
|
||||||
|
@ -780,7 +792,7 @@ void LCR_gameInit(int argc, const char **argv)
|
||||||
LCR_game.menu.selectedItem = 0;
|
LCR_game.menu.selectedItem = 0;
|
||||||
|
|
||||||
LCR_game.frame = 0;
|
LCR_game.frame = 0;
|
||||||
LCR_game.musicOn = 1;
|
LCR_game.musicOn = LCR_SETTING_MUSIC;
|
||||||
LCR_game.nextRenderFrameTime = 0;
|
LCR_game.nextRenderFrameTime = 0;
|
||||||
LCR_game.nextRacingTickTime = 0;
|
LCR_game.nextRacingTickTime = 0;
|
||||||
LCR_game.cameraMode = LCR_CAMERA_MODE_DRIVE;
|
LCR_game.cameraMode = LCR_CAMERA_MODE_DRIVE;
|
||||||
|
@ -1176,9 +1188,11 @@ void LCR_gameHandleInput(void)
|
||||||
LCR_rendererCameraReset();
|
LCR_rendererCameraReset();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
#if LCR_SETTING_MUSIC
|
||||||
case 1:
|
case 1:
|
||||||
LCR_game.musicOn = !LCR_game.musicOn;
|
LCR_game.musicOn = !LCR_game.musicOn;
|
||||||
break;
|
break;
|
||||||
|
#endif
|
||||||
|
|
||||||
case 2:
|
case 2:
|
||||||
LCR_audio.on = !LCR_audio.on;
|
LCR_audio.on = !LCR_audio.on;
|
||||||
|
|
20
map.h
20
map.h
|
@ -94,7 +94,7 @@
|
||||||
#define LCR_BLOCK_RAMP_34 '/' ///< plain ramp, 3/4 size
|
#define LCR_BLOCK_RAMP_34 '/' ///< plain ramp, 3/4 size
|
||||||
#define LCR_BLOCK_RAMP_12 '<' ///< plain ramp, 1/2 size
|
#define LCR_BLOCK_RAMP_12 '<' ///< plain ramp, 1/2 size
|
||||||
#define LCR_BLOCK_RAMP_14 '_' ///< plain ramp, 1/4 size
|
#define LCR_BLOCK_RAMP_14 '_' ///< plain ramp, 1/4 size
|
||||||
#define LCR_BLOCK_RAMP_CORNER 'v' ///< corner of ramp
|
#define LCR_BLOCK_RAMP_CORNER 'v' ///< corner of a ramp
|
||||||
#define LCR_BLOCK_RAMP_CURVED_PLAT ']' ///< curved ramp with top platgform
|
#define LCR_BLOCK_RAMP_CURVED_PLAT ']' ///< curved ramp with top platgform
|
||||||
#define LCR_BLOCK_RAMP_CURVED ')' ///< curv. ramp without top platf.
|
#define LCR_BLOCK_RAMP_CURVED ')' ///< curv. ramp without top platf.
|
||||||
#define LCR_BLOCK_RAMP_CURVED_WALL '}' ///< curved ramp plus small wall
|
#define LCR_BLOCK_RAMP_CURVED_WALL '}' ///< curved ramp plus small wall
|
||||||
|
@ -103,6 +103,8 @@
|
||||||
#define LCR_BLOCK_CORNER_12 '\\' ///< diagonal corner (1/2 wide)
|
#define LCR_BLOCK_CORNER_12 '\\' ///< diagonal corner (1/2 wide)
|
||||||
#define LCR_BLOCK_HILL '(' ///< curved "hill"
|
#define LCR_BLOCK_HILL '(' ///< curved "hill"
|
||||||
#define LCR_BLOCK_BUMP '~' ///< small bump on the road
|
#define LCR_BLOCK_BUMP '~' ///< small bump on the road
|
||||||
|
#define LCR_BLOCK_CORNER_CONVEX 'n' ///< curved corner (convex)
|
||||||
|
#define LCR_BLOCK_CORNER_CONCAVE 'l' ///< curved corner (concave)
|
||||||
|
|
||||||
#define LCR_BLOCK_FULL_ACCEL '>'
|
#define LCR_BLOCK_FULL_ACCEL '>'
|
||||||
#define LCR_BLOCK_BOTTOM_ACCEL 'z'
|
#define LCR_BLOCK_BOTTOM_ACCEL 'z'
|
||||||
|
@ -111,9 +113,6 @@
|
||||||
#define LCR_BLOCK_FULL_FAN 'o'
|
#define LCR_BLOCK_FULL_FAN 'o'
|
||||||
#define LCR_BLOCK_RAMP_FAN 'V'
|
#define LCR_BLOCK_RAMP_FAN 'V'
|
||||||
|
|
||||||
#define LCR_BLOCK_CORNER_CONVEX 'n'
|
|
||||||
#define LCR_BLOCK_CORNER_CONCAVE 'l'
|
|
||||||
|
|
||||||
#define LCR_BLOCK_CHECKPOINT_0 '+' ///< checkpoint, not taken
|
#define LCR_BLOCK_CHECKPOINT_0 '+' ///< checkpoint, not taken
|
||||||
#define LCR_BLOCK_CHECKPOINT_1 '\'' ///< checkpoint, taken
|
#define LCR_BLOCK_CHECKPOINT_1 '\'' ///< checkpoint, taken
|
||||||
|
|
||||||
|
@ -131,15 +130,10 @@
|
||||||
|
|
||||||
/*
|
/*
|
||||||
TODO:
|
TODO:
|
||||||
- ramp corner???
|
|
||||||
- curved corner?
|
|
||||||
- curved out corner?
|
|
||||||
- curved "hill"
|
|
||||||
- bumpy road
|
|
||||||
- bigger structures like a loop, sloped road etc?
|
- bigger structures like a loop, sloped road etc?
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define LCR_MAP_BLOCK_CACHE_SIZE (8 * 2) /// do not change
|
#define LCR_MAP_BLOCK_CACHE_SIZE (8 * 2) ///< Do not change.
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Cache for accelerating LCR_mapGetBlockAtFast, consists of 8 2-item records,
|
Cache for accelerating LCR_mapGetBlockAtFast, consists of 8 2-item records,
|
||||||
|
@ -154,12 +148,12 @@ struct
|
||||||
{
|
{
|
||||||
uint16_t blockCount;
|
uint16_t blockCount;
|
||||||
uint8_t blocks[LCR_SETTING_MAP_MAX_BLOCKS * LCR_BLOCK_SIZE];
|
uint8_t blocks[LCR_SETTING_MAP_MAX_BLOCKS * LCR_BLOCK_SIZE];
|
||||||
uint8_t startPos[4]; ///< Initial position and rotation.
|
uint8_t startPos[4]; ///< Initial position and rotation.
|
||||||
|
|
||||||
uint8_t environment;
|
uint8_t environment;
|
||||||
uint8_t checkpointCount;
|
uint8_t checkpointCount;
|
||||||
|
|
||||||
uint32_t hash; ///< Hash of the processed binary map.
|
uint32_t hash; ///< Hash of the processed binary map.
|
||||||
uint32_t targetTime;
|
uint32_t targetTime;
|
||||||
|
|
||||||
char name[LCR_MAP_NAME_MAX_LEN + 1];
|
char name[LCR_MAP_NAME_MAX_LEN + 1];
|
||||||
|
@ -249,7 +243,7 @@ void LCR_rampGetDimensions(uint8_t rampType, uint8_t *height4ths,
|
||||||
|
|
||||||
uint8_t *LCR_getMapBlockAtCoordNumber(uint32_t coord)
|
uint8_t *LCR_getMapBlockAtCoordNumber(uint32_t coord)
|
||||||
{
|
{
|
||||||
// binary search the block:
|
// Binary search the block:
|
||||||
|
|
||||||
uint16_t a = 0, b = LCR_currentMap.blockCount - 1;
|
uint16_t a = 0, b = LCR_currentMap.blockCount - 1;
|
||||||
|
|
||||||
|
|
186
racing.h
186
racing.h
|
@ -43,8 +43,8 @@ typedef int32_t LCR_GameUnit; ///< abstract game unit
|
||||||
|
|
||||||
#define LCR_PHYSICS_UNIT 4096 ///< len. of square for phys. engine
|
#define LCR_PHYSICS_UNIT 4096 ///< len. of square for phys. engine
|
||||||
|
|
||||||
#define TPE_RESHAPE_TENSION_LIMIT 3
|
#define TPE_RESHAPE_TENSION_LIMIT 3
|
||||||
#define TPE_RESHAPE_ITERATIONS 8
|
#define TPE_RESHAPE_ITERATIONS 8
|
||||||
|
|
||||||
#include "general.h"
|
#include "general.h"
|
||||||
#include "map.h"
|
#include "map.h"
|
||||||
|
@ -69,10 +69,10 @@ typedef int32_t LCR_GameUnit; ///< abstract game unit
|
||||||
#define LCR_CAR_CRASH_SPEED_SMALL 400
|
#define LCR_CAR_CRASH_SPEED_SMALL 400
|
||||||
#define LCR_CAR_CRASH_SPEED_BIG 800
|
#define LCR_CAR_CRASH_SPEED_BIG 800
|
||||||
|
|
||||||
// multipliers (in 8ths) of friction and acceleration on concrete:
|
// Multipliers (in 8ths) of friction and acceleration on concrete:
|
||||||
#define LCR_CAR_GRASS_FACTOR 5
|
#define LCR_CAR_GRASS_FACTOR 5
|
||||||
#define LCR_CAR_DIRT_FACTOR 3
|
#define LCR_CAR_DIRT_FACTOR 3
|
||||||
#define LCR_CAR_ICE_FACTOR 1
|
#define LCR_CAR_ICE_FACTOR 1
|
||||||
#define LCR_CAR_DRIFT_FACTOR 2 ///< only affects steering friction
|
#define LCR_CAR_DRIFT_FACTOR 2 ///< only affects steering friction
|
||||||
|
|
||||||
#define LCR_CAR_JOINTS 5
|
#define LCR_CAR_JOINTS 5
|
||||||
|
@ -87,7 +87,7 @@ struct
|
||||||
TPE_Joint carJoints[LCR_CAR_JOINTS];
|
TPE_Joint carJoints[LCR_CAR_JOINTS];
|
||||||
TPE_Connection carConnections[LCR_CAR_CONNECTIONS];
|
TPE_Connection carConnections[LCR_CAR_CONNECTIONS];
|
||||||
|
|
||||||
uint32_t tick;
|
uint32_t tick; ///< Physics tick (frame) number.
|
||||||
uint8_t wheelCollisions; /**< In individual bits records for each car wheel
|
uint8_t wheelCollisions; /**< In individual bits records for each car wheel
|
||||||
whether it's currently touching the ground.
|
whether it's currently touching the ground.
|
||||||
Lower bits record current collisions, higher
|
Lower bits record current collisions, higher
|
||||||
|
@ -111,19 +111,19 @@ struct
|
||||||
uint16_t crashState;
|
uint16_t crashState;
|
||||||
|
|
||||||
uint8_t playingReplay;
|
uint8_t playingReplay;
|
||||||
|
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
uint16_t eventCount;
|
||||||
|
uint16_t events[LCR_SETTING_REPLAY_MAX_SIZE];
|
||||||
|
|
||||||
|
// for playing
|
||||||
|
uint16_t currentEvent;
|
||||||
|
uint16_t currentFrame;
|
||||||
|
uint32_t achievedTime;
|
||||||
|
} replay;
|
||||||
} LCR_racing;
|
} LCR_racing;
|
||||||
|
|
||||||
struct
|
|
||||||
{
|
|
||||||
uint16_t eventCount;
|
|
||||||
uint16_t events[LCR_SETTING_REPLAY_MAX_SIZE];
|
|
||||||
|
|
||||||
// for playing
|
|
||||||
uint16_t currentEvent;
|
|
||||||
uint16_t currentFrame;
|
|
||||||
uint32_t achievedTime;
|
|
||||||
} LCR_replay; // TODO: move inside LCR_racing?
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Gets times of the run in milliseconds.
|
Gets times of the run in milliseconds.
|
||||||
*/
|
*/
|
||||||
|
@ -144,15 +144,15 @@ TPE_Vec3 _LCR_TPE_vec3DividePlain(TPE_Vec3 v, TPE_Unit d)
|
||||||
void LCR_replayInitRecording(void)
|
void LCR_replayInitRecording(void)
|
||||||
{
|
{
|
||||||
LCR_LOG1("initializing replay recording");
|
LCR_LOG1("initializing replay recording");
|
||||||
LCR_replay.eventCount = 0;
|
LCR_racing.replay.eventCount = 0;
|
||||||
LCR_replay.achievedTime = 0;
|
LCR_racing.replay.achievedTime = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void LCR_replayInitPlaying(void)
|
void LCR_replayInitPlaying(void)
|
||||||
{
|
{
|
||||||
LCR_LOG1("initializing replay playing");
|
LCR_LOG1("initializing replay playing");
|
||||||
LCR_replay.currentEvent = 0;
|
LCR_racing.replay.currentEvent = 0;
|
||||||
LCR_replay.currentFrame = 0;
|
LCR_racing.replay.currentFrame = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -185,14 +185,16 @@ void LCR_replayOutputStr(void (*printChar)(char))
|
||||||
|
|
||||||
// 8 decimal digits are enough to record 24 hours
|
// 8 decimal digits are enough to record 24 hours
|
||||||
|
|
||||||
#define PUTD(order) printChar('0' + (LCR_replay.achievedTime / order) % 10);
|
#define PUTD(order) \
|
||||||
|
printChar('0' + (LCR_racing.replay.achievedTime / order) % 10);
|
||||||
|
|
||||||
PUTD(10000000) PUTD(1000000) PUTD(100000) PUTD(10000)
|
PUTD(10000000) PUTD(1000000) PUTD(100000) PUTD(10000)
|
||||||
PUTD(1000) PUTD(100) PUTD(10) PUTD(1)
|
PUTD(1000) PUTD(100) PUTD(10) PUTD(1)
|
||||||
#undef PUTD
|
#undef PUTD
|
||||||
|
|
||||||
for (int i = 0; i < LCR_replay.eventCount; ++i)
|
for (int i = 0; i < LCR_racing.replay.eventCount; ++i)
|
||||||
{
|
{
|
||||||
uint16_t e = LCR_replay.events[i];
|
uint16_t e = LCR_racing.replay.events[i];
|
||||||
printChar(':');
|
printChar(':');
|
||||||
|
|
||||||
for (int j = 0; j < 4; ++j)
|
for (int j = 0; j < 4; ++j)
|
||||||
|
@ -208,51 +210,35 @@ void LCR_replayOutputStr(void (*printChar)(char))
|
||||||
/**
|
/**
|
||||||
Reads replay from string using provided function that returns next character
|
Reads replay from string using provided function that returns next character
|
||||||
in the string. The mapHash and nameHash pointers are optional: if non-zero,
|
in the string. The mapHash and nameHash pointers are optional: if non-zero,
|
||||||
they will be filled with the map hash and name hash. Returns 1 on success,
|
the memory they point to will be filled with the map hash and name hash.
|
||||||
else 0.
|
Returns 1 on success, else 0.
|
||||||
*/
|
*/
|
||||||
int LCR_replayLoadFromStr(char (*nextChar)(void),
|
int LCR_replayLoadFromStr(char (*nextChar)(void),
|
||||||
uint32_t *mapHash, uint16_t *nameHash)
|
uint32_t *mapHash, uint16_t *nameHash)
|
||||||
{
|
{
|
||||||
char c = ' ';
|
char c = ' ';
|
||||||
|
|
||||||
LCR_replay.eventCount = 0;
|
LCR_racing.replay.eventCount = 0;
|
||||||
LCR_replay.achievedTime = 0;
|
LCR_racing.replay.achievedTime = 0;
|
||||||
|
|
||||||
if (nameHash)
|
if (nameHash)
|
||||||
*nameHash = _LCR_simpleStrHash(nextChar,';');
|
*nameHash = _LCR_simpleStrHash(nextChar,';');
|
||||||
else
|
else
|
||||||
_LCR_simpleStrHash(nextChar,';');
|
_LCR_simpleStrHash(nextChar,';');
|
||||||
|
|
||||||
/*
|
if (mapHash)
|
||||||
do // map name
|
*mapHash = 0;
|
||||||
|
|
||||||
|
for (int i = 0; i < 8; ++i) // hash
|
||||||
{
|
{
|
||||||
c = nextChar();
|
c = nextChar();
|
||||||
|
|
||||||
if (c == 0)
|
if (_LCR_hexDigitVal(c) < 0)
|
||||||
return 0;
|
return 0;
|
||||||
} while (c != ';');
|
|
||||||
*/
|
|
||||||
|
|
||||||
if (mapHash)
|
if (mapHash)
|
||||||
*mapHash = 0;
|
*mapHash = ((*mapHash) << 4) | _LCR_hexDigitVal(c);
|
||||||
|
}
|
||||||
for (int i = 0; i < 8; ++i) // hash
|
|
||||||
{
|
|
||||||
c = nextChar();
|
|
||||||
|
|
||||||
if (_LCR_hexDigitVal(c) < 0)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (mapHash)
|
|
||||||
*mapHash = ((*mapHash) << 4) | _LCR_hexDigitVal(c);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
for (int i = 0; i < 8; ++i) // hash
|
|
||||||
if (_LCR_hexDigitVal(nextChar()) < 0)
|
|
||||||
return 0;
|
|
||||||
*/
|
|
||||||
|
|
||||||
nextChar();
|
nextChar();
|
||||||
|
|
||||||
|
@ -263,7 +249,8 @@ for (int i = 0; i < 8; ++i) // hash
|
||||||
if (c < '0' || c > '9')
|
if (c < '0' || c > '9')
|
||||||
break;
|
break;
|
||||||
|
|
||||||
LCR_replay.achievedTime = LCR_replay.achievedTime * 10 + c - '0';
|
LCR_racing.replay.achievedTime =
|
||||||
|
LCR_racing.replay.achievedTime * 10 + c - '0';
|
||||||
}
|
}
|
||||||
|
|
||||||
while (c != 0) // events
|
while (c != 0) // events
|
||||||
|
@ -278,11 +265,11 @@ for (int i = 0; i < 8; ++i) // hash
|
||||||
if (e == 0)
|
if (e == 0)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (LCR_replay.eventCount >= LCR_SETTING_REPLAY_MAX_SIZE)
|
if (LCR_racing.replay.eventCount >= LCR_SETTING_REPLAY_MAX_SIZE)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
LCR_replay.events[LCR_replay.eventCount] = e;
|
LCR_racing.replay.events[LCR_racing.replay.eventCount] = e;
|
||||||
LCR_replay.eventCount++;
|
LCR_racing.replay.eventCount++;
|
||||||
}
|
}
|
||||||
|
|
||||||
c = nextChar();
|
c = nextChar();
|
||||||
|
@ -292,60 +279,61 @@ for (int i = 0; i < 8; ++i) // hash
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
During playing of a replay returns the next input and shifts to next frame.
|
When playing back a replay this function returns the next recorded input and
|
||||||
|
shifts to the next frame.
|
||||||
*/
|
*/
|
||||||
uint8_t LCR_replayGetNextInput(void)
|
uint8_t LCR_replayGetNextInput(void)
|
||||||
{
|
{
|
||||||
if (LCR_replay.currentEvent >= LCR_replay.eventCount)
|
if (LCR_racing.replay.currentEvent >= LCR_racing.replay.eventCount)
|
||||||
{
|
{
|
||||||
LCR_replay.currentFrame++; // has to be here
|
LCR_racing.replay.currentFrame++; // has to be here
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (LCR_replay.currentFrame ==
|
if (LCR_racing.replay.currentFrame ==
|
||||||
(LCR_replay.events[LCR_replay.currentEvent] >> 4))
|
(LCR_racing.replay.events[LCR_racing.replay.currentEvent] >> 4))
|
||||||
{
|
{
|
||||||
LCR_replay.currentEvent++;
|
LCR_racing.replay.currentEvent++;
|
||||||
LCR_replay.currentFrame = 0;
|
LCR_racing.replay.currentFrame = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
LCR_replay.currentFrame++;
|
LCR_racing.replay.currentFrame++;
|
||||||
|
|
||||||
return LCR_replay.currentEvent ?
|
return LCR_racing.replay.currentEvent ?
|
||||||
(LCR_replay.events[LCR_replay.currentEvent - 1] & 0x0f) : 0;
|
(LCR_racing.replay.events[LCR_racing.replay.currentEvent - 1] & 0x0f) : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int LCR_replayHasFinished(void)
|
int LCR_replayHasFinished(void)
|
||||||
{
|
{
|
||||||
if (LCR_replay.currentEvent == LCR_replay.eventCount)
|
if (LCR_racing.replay.currentEvent == LCR_racing.replay.eventCount)
|
||||||
{
|
{
|
||||||
uint32_t totalTime = LCR_replay.currentFrame;
|
uint32_t totalTime = LCR_racing.replay.currentFrame;
|
||||||
|
|
||||||
for (int i = 0; i < LCR_replay.eventCount; ++i)
|
for (int i = 0; i < LCR_racing.replay.eventCount; ++i)
|
||||||
totalTime += LCR_replay.events[i] >> 4;
|
totalTime += LCR_racing.replay.events[i] >> 4;
|
||||||
|
|
||||||
return totalTime >= LCR_replay.achievedTime;
|
return totalTime >= LCR_racing.replay.achievedTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
return LCR_replay.currentEvent > LCR_replay.eventCount;
|
return LCR_racing.replay.currentEvent > LCR_racing.replay.eventCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Records another input event. Returns 1 on success, or 0 if the event couldn't
|
Records another input event into a replay. Returns 1 on success, or 0 if the
|
||||||
be recorded. The event is only added if necessary, i.e. this function can
|
event couldn't be recorded. The event is only added if necessary, i.e. this
|
||||||
(and must) be called every frame without worrying about inflating its size.
|
function can, and MUST, be called every frame without worrying about inflating
|
||||||
When the run ends, the LCR_REPLAY_EVENT_END has to be fed!
|
its size. When the run ends, the LCR_REPLAY_EVENT_END has to be fed!
|
||||||
*/
|
*/
|
||||||
int LCR_replayRecordEvent(uint32_t frame, uint8_t input)
|
int LCR_replayRecordEvent(uint32_t frame, uint8_t input)
|
||||||
{
|
{
|
||||||
LCR_LOG2("recording replay event");
|
LCR_LOG2("recording replay event");
|
||||||
|
|
||||||
if (LCR_replay.achievedTime)
|
if (LCR_racing.replay.achievedTime)
|
||||||
return 1; // already finished
|
return 1; // already finished
|
||||||
|
|
||||||
if (input == LCR_REPLAY_EVENT_END)
|
if (input == LCR_REPLAY_EVENT_END)
|
||||||
{
|
{
|
||||||
LCR_replay.achievedTime = frame;
|
LCR_racing.replay.achievedTime = frame;
|
||||||
LCR_LOG1("replay recording finished");
|
LCR_LOG1("replay recording finished");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
@ -354,10 +342,10 @@ int LCR_replayRecordEvent(uint32_t frame, uint8_t input)
|
||||||
uint8_t previousInput = 0;
|
uint8_t previousInput = 0;
|
||||||
uint32_t previousFrame = 0;
|
uint32_t previousFrame = 0;
|
||||||
|
|
||||||
for (int i = 0; i < LCR_replay.eventCount; ++i)
|
for (int i = 0; i < LCR_racing.replay.eventCount; ++i)
|
||||||
{
|
{
|
||||||
previousInput = LCR_replay.events[i] & 0x0f;
|
previousInput = LCR_racing.replay.events[i] & 0x0f;
|
||||||
previousFrame += LCR_replay.events[i] >> 4;
|
previousFrame += LCR_racing.replay.events[i] >> 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (input == previousInput)
|
if (input == previousInput)
|
||||||
|
@ -368,30 +356,30 @@ int LCR_replayRecordEvent(uint32_t frame, uint8_t input)
|
||||||
|
|
||||||
frame -= previousFrame; // convert to offset
|
frame -= previousFrame; // convert to offset
|
||||||
|
|
||||||
while (frame > 4095 && LCR_replay.eventCount < LCR_SETTING_REPLAY_MAX_SIZE)
|
while (frame > 4095 && LCR_racing.replay.eventCount < LCR_SETTING_REPLAY_MAX_SIZE)
|
||||||
{
|
{
|
||||||
// add intermediate events
|
// add intermediate events
|
||||||
frame -= 4095;
|
frame -= 4095;
|
||||||
previousFrame += 4095;
|
previousFrame += 4095;
|
||||||
|
|
||||||
LCR_replay.events[LCR_replay.eventCount] =
|
LCR_racing.replay.events[LCR_racing.replay.eventCount] =
|
||||||
(previousFrame << 4) | previousInput;
|
(previousFrame << 4) | previousInput;
|
||||||
LCR_replay.eventCount++;
|
LCR_racing.replay.eventCount++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (LCR_replay.eventCount >= LCR_SETTING_REPLAY_MAX_SIZE)
|
if (LCR_racing.replay.eventCount >= LCR_SETTING_REPLAY_MAX_SIZE)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
LCR_replay.events[LCR_replay.eventCount] = (frame << 4) | (input & 0x0f);
|
LCR_racing.replay.events[LCR_racing.replay.eventCount] = (frame << 4) | (input & 0x0f);
|
||||||
LCR_replay.eventCount++;
|
LCR_racing.replay.eventCount++;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Helper function for _LCR_racingEnvironmentFunction, returns closest point
|
Helper function for _LCR_racingEnvironmentFunction, returns closest point on
|
||||||
on a map block placed at coordinate origin.
|
a map block placed at coordinate origin.
|
||||||
*/
|
*/
|
||||||
TPE_Vec3 _LCR_racingBlockEnvFunc(TPE_Vec3 point, const uint8_t *block)
|
TPE_Vec3 _LCR_racingBlockEnvFunc(TPE_Vec3 point, const uint8_t *block)
|
||||||
{
|
{
|
||||||
|
@ -691,8 +679,8 @@ TPE_Vec3 _LCR_racingBlockEnvFunc(TPE_Vec3 point, const uint8_t *block)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
For tinyphysicsengine, function that defines the shape of physics world,
|
For tinyphysicsengine, function that defines the shape of the static physics
|
||||||
returns closest point to any given point in space.
|
world, returns closest point to any given point in space.
|
||||||
*/
|
*/
|
||||||
TPE_Vec3 _LCR_racingEnvironmentFunction(TPE_Vec3 point, TPE_Unit maxDist)
|
TPE_Vec3 _LCR_racingEnvironmentFunction(TPE_Vec3 point, TPE_Unit maxDist)
|
||||||
{
|
{
|
||||||
|
@ -795,10 +783,10 @@ LCR_GameUnit LCR_racingGetCarSpeedSigned(void)
|
||||||
uint8_t _LCR_racingCollisionHandler(uint16_t b1, uint16_t j1, uint16_t b2,
|
uint8_t _LCR_racingCollisionHandler(uint16_t b1, uint16_t j1, uint16_t b2,
|
||||||
uint16_t j2, TPE_Vec3 p)
|
uint16_t j2, TPE_Vec3 p)
|
||||||
{
|
{
|
||||||
// check which wheels are touching the ground.
|
|
||||||
|
|
||||||
#if LCR_SETTING_CRASH_SOUNDS
|
#if LCR_SETTING_CRASH_SOUNDS
|
||||||
TPE_Unit speed = TPE_vec3Len( // detect crashes
|
// Detect crashes:
|
||||||
|
|
||||||
|
TPE_Unit speed = TPE_vec3Len(
|
||||||
TPE_vec3Project(
|
TPE_vec3Project(
|
||||||
TPE_vec3(
|
TPE_vec3(
|
||||||
LCR_racing.carBody.joints[j1].velocity[0],
|
LCR_racing.carBody.joints[j1].velocity[0],
|
||||||
|
@ -811,6 +799,8 @@ uint8_t _LCR_racingCollisionHandler(uint16_t b1, uint16_t j1, uint16_t b2,
|
||||||
(speed >= LCR_CAR_CRASH_SPEED_SMALL);
|
(speed >= LCR_CAR_CRASH_SPEED_SMALL);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// Check which wheels are touching the ground:
|
||||||
|
|
||||||
if (j1 < 4) // wheel joint?
|
if (j1 < 4) // wheel joint?
|
||||||
LCR_racing.wheelCollisions |= 0x01 << j1;
|
LCR_racing.wheelCollisions |= 0x01 << j1;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue