diff --git a/TODO.txt b/TODO.txt index 29f88cf..7cd5262 100644 --- a/TODO.txt +++ b/TODO.txt @@ -23,25 +23,25 @@ count - bonus maps in the external file (also 5?) - map types: - - purely falling map - - traveling salesman kind of maze, with fans n shit + - purely falling map DONE + - traveling salesman kind of maze, with fans n shit KINDA DONE - city map? - - some kinda buggy bumpy downhill - - map where car starts upside down - - dirt map + - some kinda buggy bumpy downhill DONE + - map where car starts upside down DONE + - dirt map DONE - ice map - - boss map - - text or picture from blocks? - - chessboard from different materials - - falling tube map? - - grass hills as decoration? - - something with multiple roads + - boss map DONE + - text or picture from blocks? DONE + - chessboard from different materials KINDA DONE + - falling tube map? DONE + - grass hills as decoration? DONE + - something with multiple roads DONE - RPG kinda map? could be in bonus maps - some speed map (mostly flat to prevent high speed bugs) - - some (at least partially) interior map - - something with multiple finishes - - U-ramp to build speed and jump up to catch a CP (done) - - jump through air ring with CP + - some (at least partially) interior map KINDA DONE + - something with multiple finishes DONE + - U-ramp to build speed and jump up to catch a CP (done) DONE + - jump through air ring with CP DONE - test: - long replay - replay stretching works @@ -51,7 +51,6 @@ verifying replays etc., i.e. make the module measure time, count checkpoints etc. - allow slowing down in air like in TM? -- compile time option to choose how many maps to include (for platforms with lower memory) - at the end check error handling, make sure the game handles garbage data in resource file etc. @@ -59,14 +58,16 @@ =========== BUGS ================= - sometimes during long loading the screen goes black, seems to have appeared - after adding LCR_LOADING_COMMAND -- immediately after starting the map countdown seems to be lower + after adding LCR_LOADING_COMMAND (seems fixed now) +- immediately after starting the map countdown seems to be lower (seems to + perhaps be caused by nextPhysicsFrameTime, look into it) - the pinch collision test seems to sometimes stop the car e.g. after falling from bigger height or when running into ramp at high speed (or not?) - FIX =========== HANDLED ============== - add ifdefs that change car color? +- compile time option to choose how many maps to include (for platforms with - sometimes the games prints huge long ass number of newlines, WHY (happens when driving on accelerator) - add indicator that menu can be scrolled down diff --git a/assets.h b/assets.h index e6d5b49..87fe947 100644 --- a/assets.h +++ b/assets.h @@ -61,6 +61,7 @@ static const char *LCR_texts[] = // TODO: define string for CLI arguments for frontends? static const char *LCR_internalDataFile = +#if !LCR_SETTING_ONLY_SMALL_MAPS // MAP 1: "MLC1;4321 0 " ":*C2mL:!x6G:+L2H:+D38" // start, finish, CPs @@ -357,6 +358,8 @@ static const char *LCR_internalDataFile = ":=c2q3 :f513" // ice ":;g082L :f151 :;g0e2J :f151 :-g58 :f117 :~g493- :~g4d3-" // gate +#endif // !LCR_SETTING_ONLY_SMALL_MAPS + /* tiny maps, max: - 400 character string - 512 (0x200) blocks @@ -475,7 +478,6 @@ static const char *LCR_internalDataFile = // fans: ":Vm1xI:Vm1z" ":-w0q1:-y0q1" - "#" // for user data file ; diff --git a/audio.h b/audio.h index e3c17be..aa958b9 100644 --- a/audio.h +++ b/audio.h @@ -8,18 +8,19 @@ 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). + file, left to be optionally loaded and played by the frontend). Audio samples + are generated procedurally. */ -#define LCR_SOUND_NONE 0 -#define LCR_SOUND_CLICK 1 -#define LCR_SOUND_CRASH_SMALL 2 -#define LCR_SOUND_CRASH_BIG 3 -#define LCR_SOUND_ACCELERATOR 4 -#define LCR_SOUND_FAN 5 +#define LCR_SOUND_NONE 0 +#define LCR_SOUND_CLICK 1 +#define LCR_SOUND_CRASH_SMALL 2 +#define LCR_SOUND_CRASH_BIG 3 +#define LCR_SOUND_ACCELERATOR 4 +#define LCR_SOUND_FAN 5 -#define LCR_AUDIO_CRASH_SOUND_LEN 2048 -#define LCR_AUDIO_FAN_SOUND_LEN 4096 +#define LCR_AUDIO_CRASH_SOUND_LEN 2048 +#define LCR_AUDIO_FAN_SOUND_LEN 4096 struct { diff --git a/frontend_sdl.c b/frontend_sdl.c index 480fef1..e6abfeb 100644 --- a/frontend_sdl.c +++ b/frontend_sdl.c @@ -1,19 +1,20 @@ +/** + SDL2 frontend for Licar. +*/ + #include #include #define LCR_SETTING_LOG_LEVEL 2 - #define DATA_FILE_NAME "data" - #define LCR_LOADING_COMMAND SDL_PumpEvents(); +#include "game.h" SDL_Window *window; SDL_Renderer *renderer; SDL_Texture *texture; SDL_Surface *screenSurface; -#include "game.h" - uint16_t screen[LCR_SETTING_RESOLUTION_X * LCR_SETTING_RESOLUTION_Y]; FILE *musicFile = 0; diff --git a/game.h b/game.h index 7f66fef..a7453c9 100644 --- a/game.h +++ b/game.h @@ -13,7 +13,7 @@ (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. UNITS: There are various kinds of units used to ensure independence of the diff --git a/map.h b/map.h index d0e31dd..7228b20 100644 --- a/map.h +++ b/map.h @@ -85,7 +85,6 @@ // normal blocks: #define LCR_BLOCK_FULL '=' ///< completely filled block - #define LCR_BLOCK_BOTTOM '-' ///< filled bottom half #define LCR_BLOCK_LEFT ';' ///< filled left half #define LCR_BLOCK_BOTTOM_LEFT ',' ///< filled bottom left quarter @@ -107,42 +106,30 @@ #define LCR_BLOCK_BUMP '~' ///< small bump on the road #define LCR_BLOCK_CORNER_CONVEX 'n' ///< curved corner (convex) #define LCR_BLOCK_CORNER_CONCAVE 'u' ///< curved corner (concave) - #define LCR_BLOCK_FULL_ACCEL '>' ///< full block with accelerator #define LCR_BLOCK_BOTTOM_ACCEL 'z' ///< bottom half block with accelerator #define LCR_BLOCK_RAMP_ACCEL 'y' ///< ramp block with accelerator - #define LCR_BLOCK_FULL_FAN 'o' ///< full block with fan #define LCR_BLOCK_RAMP_FAN 'V' ///< ramp block with fan - #define LCR_BLOCK_CHECKPOINT_0 '+' ///< checkpoint, not taken #define LCR_BLOCK_CHECKPOINT_1 '\t' ///< checkpoint, taken - #define LCR_BLOCK_FINISH '!' ///< finish // special blocks: #define LCR_BLOCK_NONE 'x' ///< no block (to make holes etc.) - #define LCR_BLOCK_CUBOID_FILL 'f' /**< makes a cuboid from the previously specified block, the size is given by block coords */ #define LCR_BLOCK_CUBOID_HOLLOW 'h' /**< same as cuboid special block, but makes a hollow one */ - #define LCR_BLOCK_MIRROR 'm' /**< makes a mirror copy along each major axis, starting at coords of last added block and iterating over a block of size given by this block's coords */ - #define LCR_BLOCK_START '*' ///< specifies start block position - #define LCR_BLOCK_QUIT 'e' /**< special block, ends reading the map (useful when creating maps) */ -/* - TODO: - - bigger structures like a loop, sloped road etc? -*/ #define LCR_MAP_BLOCK_CACHE_SIZE (8 * 2) ///< Do not change. @@ -245,9 +232,8 @@ uint8_t LCR_mapBlockGetTransform(const uint8_t block[LCR_BLOCK_SIZE]) uint8_t LCR_mapBlockGetMaterial(const uint8_t block[LCR_BLOCK_SIZE]) { - return (LCR_mapBlockIsAccelerator(block[0]) || - LCR_mapBlockIsFan(block[0])) ? LCR_BLOCK_MATERIAL_CONCRETE : - ((block[3] >> 2) & 0x03); + return (LCR_mapBlockIsAccelerator(block[0]) || LCR_mapBlockIsFan(block[0])) ? + LCR_BLOCK_MATERIAL_CONCRETE : ((block[3] >> 2) & 0x03); } uint32_t LCR_mapBlockGetCoordNumber(const uint8_t block[LCR_BLOCK_SIZE]) @@ -669,7 +655,6 @@ uint8_t LCR_mapLoadFromStr(char (*getNextCharFunc)(void), const char *name) LCR_currentMap.startPos[2] = coords[2]; LCR_currentMap.startPos[3] = trans; break; - // kek, is this legit? case LCR_BLOCK_CHECKPOINT_0: LCR_currentMap.checkpointCount++; // fall through @@ -853,7 +838,7 @@ void LCR_mapGetBlockShape(uint8_t blockType, uint8_t transform, (blockType == LCR_BLOCK_BOTTOM_LEFT_FRONT)), zBack = 6 >> ((blockType == LCR_BLOCK_BOTTOM_LEFT_FRONT) | - (blockType == LCR_BLOCK_LEFT_FRONT)); + (blockType == LCR_BLOCK_LEFT_FRONT)); ADD(0,0,0) ADD(xRight,0,0) ADD(xRight,yTop,0) // front ADD(0,0,0) ADD(xRight,yTop,0) ADD(0,yTop,0) diff --git a/media/manual.txt b/media/manual.txt index a05b27c..d2db8fe 100644 --- a/media/manual.txt +++ b/media/manual.txt @@ -1,11 +1,11 @@ WORK IN PROGRESS --._.-'"'-._.-'"'- LICAR MANUAL -'"'-._.-'"'-._.- +'-._-'"'-_.-'"'-._.-'"'-._.-'"'- LICAR MANUAL -'"'-._.-'"'-._.-'"'-._.-'"'-._.-' -libre racing video game by drummyfish -released under CC0 1.0, public domain + libre racing video game by drummyfish + released under CC0 1.0, public domain -~~~ GENERAL ~~~ +~~~~~ GENERAL ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Licar is a relatively simple 3D stunt racing game inspired by other popular games of the genre such as Trackmania and Stunts. Unlike mainstream video games, @@ -24,11 +24,10 @@ what the platforms allow. Some versions may have more features or visual game, it's probably because of limitations of your platform. On PCs and laptops however everything should be supported. -~~~ RUNNING ~~~ +~~~~~ RUNNING ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -There are compiled versions of Licar for many different platforms. If yours -is among them, running the game should be as simple as running any other -program. +There are compiled versions of Licar for many different platforms. If yours is +among them, running the game should be as simple as running any other program. If there isn't a version for your system or for some other reason you can't run the game, you may try to compile the game yourself from the source code. @@ -43,7 +42,7 @@ If you know what command line arguments are, you may also check them out by running the game with -h argument. This will allow you to for example start the game and immediately load a map, which is handy when creating new maps. -~~~ GAMEPLAY ~~~ +~~~~~ GAMEPLAY ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ In Licar, unlike in most other racing games, the player always only attempts time attacks, i.e. you only race against time with no physical opponents on the @@ -70,7 +69,7 @@ attempts to achieve a good time on a map. During the run the game also displays additional info such as your current speed, times at checkpoints etc. -~~~ CONTROLS ~~~ +~~~~~ CONTROLS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Controls are extremely simple. The car is only controlled by 4 directional keys: up (accelerate), down (deccelerate, reverse), left (steer left) and @@ -80,7 +79,7 @@ restarting runs and handling menu. PRO TIP: pressing brake while in air stops the car's horizontal rotation! -~~~ DATA FILE ~~~ +~~~~~ DATA FILE ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Where supported, the game uses a so called data file to store data such as maps, replays, information about map completion etc. On platforms that don't support @@ -102,7 +101,7 @@ map, 'R' for a replay), then its name follows immediately, terminated by the depends on what data it is, so map data of course have a different format than replay data. For example a map named "mymap" will start with "Mmymap;". -~~~ CONFIGURATION ~~~ +~~~~~ CONFIGURATION ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The game offers a very high level of configuration and customization, and those with at least basic programming skill will be able to implement any changes @@ -115,7 +114,7 @@ simple). All user settings, along with their descriptions, are located in the settings.h source file. The game also comes in several precompiled versions with different settings. -~~~ REPLAYS ~~~ +~~~~~ REPLAYS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ If your platform supports it, Licar can save and play back recorded runs as "replays" (sometimes also called "demos"), which are just exact records of game @@ -128,7 +127,7 @@ Whenever a map's target time is beaten, replay is automatically saved. It's also possible to save a replay manually by opening the menu and selecting "save replay". -~~~ GHOSTS ~~~ +~~~~~ GHOSTS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The game supports ghost cars to race against (note that this may be unsupported on some weaker platforms). A ghost car is created from a replay and will race @@ -136,7 +135,7 @@ in real time against the player, without being able to collide with him. This is very useful when attacking someone else's (or one's own) achieved time, to see where exactly time losses against the opponent occur. -~~~ MAKING CUSTOM MAPS ~~~ +~~~~~ MAKING CUSTOM MAPS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Maps are stored in the data file. For its simplicity the original game doesn't come with a user-friendly map editor, the maps are hand-written directly in the @@ -245,11 +244,11 @@ A few tips for making maps: - There is a special "mirror" block that's very useful for creating 8-symmetrical structures. -~~~ COMPILING AND MODIFYING ~~~ +~~~~~ COMPILING AND MODIFYING ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ TODO -~~~ FAQ ~~~ +~~~~~ FAQ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Q: Is this game really free? Do I have to pay for it? What can I legally do with it? Can I use it commercially? What's the catch? diff --git a/renderer.h b/renderer.h index 1bf905d..0b8728c 100644 --- a/renderer.h +++ b/renderer.h @@ -854,14 +854,14 @@ void _LCR_makeMapChunks(void) const S3L_Unit *v = LCR_renderer.mapVerts + 3 * tri[0]; if (v[0] >= chunkCorner[0] && - v[0] < chunkCorner[0] + LCR_RENDERER_CHUNK_SIZE_HORIZONTAL + - ((chunkNo & 0x03) == 0x03) && // includes last edge - v[1] >= chunkCorner[1] && - v[1] < chunkCorner[1] + (LCR_RENDERER_CHUNK_SIZE_HORIZONTAL / 2) + - (((chunkNo >> 2) & 0x03) == 0x03) && - v[2] >= chunkCorner[2] && - v[2] < chunkCorner[2] + LCR_RENDERER_CHUNK_SIZE_HORIZONTAL + - (((chunkNo >> 4) & 0x03) == 0x03)) + v[0] < chunkCorner[0] + LCR_RENDERER_CHUNK_SIZE_HORIZONTAL + + ((chunkNo & 0x03) == 0x03) && // includes last edge + v[1] >= chunkCorner[1] && + v[1] < chunkCorner[1] + (LCR_RENDERER_CHUNK_SIZE_HORIZONTAL / 2) + + (((chunkNo >> 2) & 0x03) == 0x03) && + v[2] >= chunkCorner[2] && + v[2] < chunkCorner[2] + LCR_RENDERER_CHUNK_SIZE_HORIZONTAL + + (((chunkNo >> 4) & 0x03) == 0x03)) { _LCR_rendererSwapMapTris(i,start); start++; diff --git a/settings.h b/settings.h index 8f42a4a..95d6dbb 100644 --- a/settings.h +++ b/settings.h @@ -20,8 +20,9 @@ #endif #ifndef LCR_SETTING_RESOLUTION_SUBDIVIDE - /** Subdivides the whole game resolution by this amount by making each pixel - this number of times bigger. */ + /** Subdivides the whole game's effective resolution by this value, by making + each pixel this number of times bigger. This can drastically improve + performance. */ #define LCR_SETTING_RESOLUTION_SUBDIVIDE 1 #endif @@ -43,7 +44,7 @@ #ifndef LCR_SETTING_MAX_MAP_VERTICES /** Maximum number of vertices for 3D rendering. Lower number will decrease - RAM usage but will prevent larger maps from being loaded. */ + RAM usage but also prevent larger maps from being loaded. */ #define LCR_SETTING_MAX_MAP_VERTICES 4096 #endif @@ -240,4 +241,11 @@ #define LCR_SETTING_CAR_TINT 0x07 #endif +#ifndef LCR_SETTING_ONLY_SMALL_MAPS + /** Turning this on will only include the small maps in the internal data + file. This option exists for weak devices that couldn't handle big maps + and/or have to reduce the size of the internal data file. */ + #define LCR_SETTING_ONLY_SMALL_MAPS 0 +#endif + #endif // guard