diff --git a/TODO.txt b/TODO.txt index 8cb2cba..2d7edfb 100644 --- a/TODO.txt +++ b/TODO.txt @@ -1,7 +1,7 @@ =========== GENERAL ============== -- add indication when CP is taken: in 1st man view it may be unclear if CP was - taken or not otherwise +- maybe remove setting string from menu (like music: 1) and use popups instead + (have just music and show "on" or "off" in popup) - on 1st map the camera is obscured by the wall at the start, fix it somehow (not the best first impression) - culling is very slow now, it showed that distance bailout can accelerate it @@ -38,8 +38,6 @@ - maybe each map could have a target time embedded: when beaten, the map would be marked as such - player name (modifiable via resource file) -- popup messages? would be useful for several things: showing checkpoint times, - showing changes in menu etc. - make the racing module usable by itself, e.g. to allow making tools for verifying replays etc., i.e. make the module measure time, count checkpoints etc. @@ -56,6 +54,10 @@ =========== HANDLED ============== +- add indication when CP is taken: in 1st man view it may be unclear if CP was + taken or not otherwise +- popup messages? would be useful for several things: showing checkpoint times, + showing changes in menu etc. - allow stopping car rotation in air like in Trackmania - countdown and finish text sometimes seem to jump horizontally somehow - add argc/argv to gameInit? could be used to quickly start maps, verify diff --git a/game.h b/game.h index fc729a1..ba593ef 100644 --- a/game.h +++ b/game.h @@ -185,17 +185,17 @@ uint8_t LCR_gameGetNextAudioSample(void); #endif #endif -#define LCR_CAMERA_MODE_DRIVE 0x00 -#define LCR_CAMERA_MODE_DRIVE2 0x01 -#define LCR_CAMERA_MODE_INSIDE 0x02 -#define LCR_CAMERA_MODE_FREE 0x03 +#define LCR_CAMERA_MODE_DRIVE 0x00 +#define LCR_CAMERA_MODE_DRIVE2 0x01 +#define LCR_CAMERA_MODE_INSIDE 0x02 +#define LCR_CAMERA_MODE_FREE 0x03 #define LCR_GAME_STATE_MENU 0x00 #define LCR_GAME_STATE_RUN_STARTING 0x01 #define LCR_GAME_STATE_RUN 0x02 #define LCR_GAME_STATE_RUN_FINISHED 0x03 -#define LCR_GAME_STATE_LOADING 0x04 +#define LCR_GAME_STATE_LOADING 0x04 #define LCR_GAME_STATE_END 0xff @@ -259,6 +259,8 @@ static inline void LCR_gameDrawPixelXYSafe(unsigned int x, unsigned int y, #define LCR_FREE_CAMERA_TURN_STEP 1 #endif +#define LCR_POPUP_STR_SIZE 16 + struct { uint8_t state; @@ -275,6 +277,9 @@ struct continuously held. */ uint32_t runTimeMS; ///< Current time of the run + char popupStr[LCR_POPUP_STR_SIZE]; + uint8_t popupCountdown; + struct { uint8_t selectedTab; @@ -340,6 +345,26 @@ void LCR_gameDrawPixel(unsigned long index, uint16_t color) #endif } +void LCR_gamePopupMessage(const char *str) +{ + if (*str == 0) + { + LCR_game.popupCountdown = 0; + return; + } + + for (uint8_t i = 0; i < LCR_POPUP_STR_SIZE - 1; ++i) + { + LCR_game.popupStr[i] = str[i]; + + if (str[i] == 0) + break; + } + + LCR_game.popupCountdown = + (LCR_SETTING_POPUP_DURATION * LCR_SETTING_FPS) / 1000; +} + void LCR_gameDrawPixelXYUnsafe(unsigned int x, unsigned int y, uint16_t color) { @@ -886,6 +911,9 @@ void LCR_gameInit(int argc, const char **argv) LCR_game.menu.selectedTab = 0; LCR_game.menu.selectedItem = 0; + LCR_game.popupCountdown = 0; + LCR_game.popupStr[LCR_POPUP_STR_SIZE - 1] = 0; + LCR_game.frame = 0; LCR_game.musicOn = LCR_SETTING_MUSIC; LCR_game.nextRenderFrameTime = 0; @@ -1023,6 +1051,18 @@ void LCR_gameTimeToStr(uint32_t timeMS, char *str) str[1] = '0' + timeMS % 10; str[2] = '\''; } + +LCR_gameDrawPopupMessage(void) +{ + int textH = LCR_rendererComputeTextHeight(4); + int textW = LCR_rendererComputeTextWidth(LCR_game.popupStr,4); + + LCR_rendererDrawRect((LCR_EFFECTIVE_RESOLUTION_X - textW) / 2 - 6,4, + textW + 12,textH + 8,0xffff,1); + + LCR_rendererDrawText(LCR_game.popupStr,(LCR_EFFECTIVE_RESOLUTION_X - textW) + / 2,8,0x0700,4); +} void LCR_gameDraw3DView(void) { @@ -1071,17 +1111,6 @@ void LCR_gameDraw3DView(void) switch (LCR_game.state) { - case LCR_GAME_STATE_RUN_STARTING: - str[0] = '0' + LCR_SETTING_COUNTDOWN_SECONDS - - (LCR_game.time - LCR_game.stateStartTime) / 1000; - str[1] = 0; - - LCR_rendererDrawText(str, - (LCR_EFFECTIVE_RESOLUTION_X - LCR_rendererComputeTextWidth(str,8)) / 2, - LCR_EFFECTIVE_RESOLUTION_Y / 2 - ,0x0707,8); - break; - default: { int val = LCR_carSpeedKMH(); @@ -1280,7 +1309,17 @@ void LCR_gameHandleInput(void) case LCR_GAME_STATE_RUN_STARTING: if (LCR_game.time - LCR_game.stateStartTime >= 1000 * LCR_SETTING_COUNTDOWN_SECONDS) + { LCR_gameSetState(LCR_GAME_STATE_RUN); + LCR_gamePopupMessage(""); + } + else + { + LCR_game.popupStr[0] = '0' + LCR_SETTING_COUNTDOWN_SECONDS - + (LCR_game.time - LCR_game.stateStartTime) / 1000; + LCR_game.popupStr[1] = 0; + LCR_gamePopupMessage(LCR_game.popupStr); + } // fall through default: @@ -1343,7 +1382,7 @@ void LCR_gameHandleInput(void) LCR_checkBeatenMaps(); } } - + uint8_t LCR_gameStep(uint32_t time) { LCR_LOG2("game step (start)"); @@ -1393,11 +1432,14 @@ uint8_t LCR_gameStep(uint32_t time) if (events & LCR_RACING_EVENT_CP_TAKEN) { int carBlock[3]; + char str[10]; LCR_LOG1("CP taken"); LCR_racingGetCarBlockCoords(carBlock); LCR_rendererMarkTakenCP(carBlock[0],carBlock[1],carBlock[2]); LCR_audioPlaySound(LCR_SOUND_CLICK); + LCR_gameTimeToStr(LCR_game.runTimeMS,str); + LCR_gamePopupMessage(str); } else if (events & LCR_RACING_EVENT_FINISHED && LCR_game.state != LCR_GAME_STATE_RUN_FINISHED) @@ -1453,6 +1495,12 @@ LCR_replayOutputStr(_LCR_gameDataCharWrite); LCR_game.menu.itemCount + 1,LCR_game.menu.selectedItem); else LCR_gameDraw3DView(); + + if (LCR_game.popupCountdown) + { + LCR_gameDrawPopupMessage(); + LCR_game.popupCountdown--; + } } else { @@ -1464,25 +1512,9 @@ LCR_replayOutputStr(_LCR_gameDataCharWrite); { // show the "loading" screen - LCR_rendererDrawRect( - LCR_EFFECTIVE_RESOLUTION_X / 8 - 2, - LCR_EFFECTIVE_RESOLUTION_Y / 3 - 2, - LCR_EFFECTIVE_RESOLUTION_X - LCR_EFFECTIVE_RESOLUTION_X / 4 + 4, - LCR_EFFECTIVE_RESOLUTION_Y - 2 * LCR_EFFECTIVE_RESOLUTION_Y / 3 + 4, - 0x0000,0); - - LCR_rendererDrawRect( - LCR_EFFECTIVE_RESOLUTION_X / 8, - LCR_EFFECTIVE_RESOLUTION_Y / 3, - LCR_EFFECTIVE_RESOLUTION_X - LCR_EFFECTIVE_RESOLUTION_X / 4, - LCR_EFFECTIVE_RESOLUTION_Y - 2 * LCR_EFFECTIVE_RESOLUTION_Y / 3, - 0xffff,0); - - LCR_rendererDrawText(LCR_texts[LCR_TEXTS_LOADING], - (LCR_EFFECTIVE_RESOLUTION_X - - LCR_rendererComputeTextWidth(LCR_texts[LCR_TEXTS_LOADING],4)) / 2, - (LCR_EFFECTIVE_RESOLUTION_Y - - LCR_rendererComputeTextHeight(4)) / 2,0x0000,4); + LCR_gamePopupMessage(LCR_texts[LCR_TEXTS_LOADING]); + LCR_game.popupCountdown = 2; + LCR_gameDrawPopupMessage(); } if (sleep) diff --git a/settings.h b/settings.h index bdb09f7..a26ff16 100644 --- a/settings.h +++ b/settings.h @@ -178,7 +178,7 @@ #ifndef LCR_SETTING_COUNTDOWN_SECONDS /** Run start countdown length in seconds. */ - #define LCR_SETTING_COUNTDOWN_SECONDS 1 // for release make 3 + #define LCR_SETTING_COUNTDOWN_SECONDS 3 // for release make 3 #endif #ifndef LCR_SETTING_MAP_CHUNK_RELOAD_INTERVAL @@ -228,4 +228,9 @@ #define LCR_SETTING_CRASH_SOUNDS 1 #endif +#ifndef LCR_SETTING_POPUP_DURATION + /** Duration of popup messages in milliseconds. */ + #define LCR_SETTING_POPUP_DURATION 2500 +#endif + #endif // guard