Add map beating

This commit is contained in:
Miloslav Ciz 2025-01-27 23:46:44 +01:00
parent 2172fcedd1
commit ea105ba3f3
6 changed files with 119 additions and 18 deletions

View file

@ -1,13 +1,19 @@
=========== GENERAL ==============
- make a small txt game menual
- test if the replay stretching works
- test:
- long replay
- replay stretching works
- replay with input not occuring for more that LCR_SETTING_GHOST_STEP
- replay validation
- ghosts: if the replay for the ghost is too long (too many samples for the
preallocated array), we can subdivide the sample resolution (i.e. "stretch"
the samples) to cover the whole replay (ofc for the price of worse quality).
- add argc/argv to gameInit? could be used to quickly start maps, verify
replays etc.
replays etc. Options:
-sN: sound (0/1)
-mN: music (0/1)
-cN: set camera
-M: load last map in resource files (good for making maps)
-R: load last replay in resource files (good for making TASes)
-P: load and play against last replay in resource files
- maybe each map could have a target time embedded: when beaten, the map would
be marked as such
- player name (modifiable via resource file)
@ -24,13 +30,15 @@
=========== BUGS =================
- starting test replay two twice in a row breaks it
- drawing dithered transparent objects fills z-buffer in the transparent parts
and then the geometry behind it isn't drawn <- PARTIALLY FIXED NOW
=========== HANDLED ==============
- allow stopping car rotation in air like in Trackmania
- drawing dithered transparent objects fills z-buffer in the transparent parts
and then the geometry behind it isn't drawn <- PARTIALLY FIXED, LOOKS GOOD
- starting test replay two twice in a row breaks it
- ghosts: if the replay for the ghost is too long (too many samples for the
preallocated array), we can subdivide the sample resolution (i.e. "stretch"
the samples) to cover the whole replay (ofc for the price of worse quality).
- force chunk reload upon map restart so that there's no blinking at start
- ghost visible distance -- maybe even car should have this (watching rep with
free camera)? maybe generalize setCar/GhostVisibility to

View file

@ -172,6 +172,7 @@ uint16_t LCR_getFontChar(char c)
case '_': _F( 8,10,10,10,10,10,10,10,10,10)
case '|': _F( 5, 7, 7, 7, 7, 7, 7, 7, 7, 7)
case '=': _F( 4, 6, 0, 2, 2, 2, 2, 2, 2, 2)
case '#': _F( 5, 7,14,14,14,14,14,14,14,14) // used for "check"
default: return 0; break;
}

2
data
View file

@ -1,2 +1,4 @@
#Mmap2;4321 1 :*H1k0J :,s0s0 :fd190
#Bnomap
#Rrep2;testmap;482f70f9 00000843:0173:0081:0029:0111:0039:0071:00a3:0061:0169:0051:00b3:0041:0073:0081:0033:0041:0033:0231:0030:0098:0029:0011:0163:00f1:0053:0081:0033:0051:0023:0031:00f0:0032:0023:0131:00b9:0081:0023:00a1:0119:00e1:00c9:0071:0039:00a1:00d3:0021:01f9:0091:0079:0091:0039:0051:0049:0021:0083:0031:0083:0031:0083:0061:0089:0121:00a0:0058:002c:0048:0061:0013:0150:0052:00c0:00a1:0053:0041:0043:0031:0020:0092:0063:0181:0010:00a2:0013:0071:00e0:0028:00e9:0078:00a9:0043:0032:0123:0042:0080:0038:004c:01a8:0050:0032:0033:0101
#Btestmap;

67
game.h
View file

@ -838,13 +838,71 @@ void LCR_gameLoadDataFileChunk(unsigned int startIndex, char magicNumber)
}
}
/**
Assumes maps are loaded in menu items, checks (in the resource file) which
ones have been marked as beaten and marks corresponding menu items as such.
*/
void LCR_checkBeatenMaps(void)
{
LCR_LOG2("checking beaten maps");
char name[LCR_MAP_NAME_MAX_LEN + 1];
LCR_gameRewindDataFile();
while (1)
{
char c = LCR_gameGetNextDataFileChar();
if (c == 'B')
{
uint8_t i = 0;
while (i < LCR_MAP_NAME_MAX_LEN + 1)
{
c = LCR_gameGetNextDataFileChar();
if (c < ' ' || c == LCR_RESOURCE_FILE_SEPARATOR ||
c == LCR_RESOURCE_FILE_SEPARATOR2)
break;
name[i] = c;
i++;
}
name[i] = 0;
for (uint8_t j = 0; j < LCR_game.menu.itemCount; ++j)
if (_LCR_strCmp(name,LCR_game.menu.itemNamePtrs[j]))
{
for (uint8_t k = 0; k < LCR_MENU_STRING_SIZE; ++k)
if (LCR_game.menu.itemNames[j][k] == 0)
{
LCR_game.menu.itemNames[j]
[k - (k == LCR_MENU_STRING_SIZE - 1)] = '#';
LCR_game.menu.itemNames[j]
[k + (k != LCR_MENU_STRING_SIZE - 1)] = 0;
break;
}
}
}
else
while (c != 0 && c != LCR_RESOURCE_FILE_SEPARATOR)
c = LCR_gameGetNextDataFileChar();
if (c == 0)
break;
}
}
void LCR_gameEnd(void)
{
LCR_LOG0("ending");
}
void LCR_gameTimeToStr(uint32_t timeMS, char *str)
{
str[9] = 0;
@ -1168,10 +1226,15 @@ void LCR_gameHandleInput(void)
if (tabSwitchedTo == 0)
LCR_gameLoadMainMenuItems();
else if (tabSwitchedTo > 0 || scrolled != 0)
{
LCR_gameLoadDataFileChunk(
(tabSwitchedTo > 0) ? 0 : (LCR_game.dataFile.firstItemIndex +
scrolled * LCR_RESOURCE_ITEM_CHUNK),
LCR_game.menu.selectedTab == 1 ? 'M' : 'R');
if (LCR_game.menu.selectedTab == 1)
LCR_checkBeatenMaps();
}
}
uint8_t LCR_gameStep(uint32_t time)

View file

@ -66,4 +66,21 @@ uint16_t _LCR_simpleStrHash(char (*nextChar)(void), char endChar)
return r;
}
int _LCR_strCmp(const char *s1, const char *s2)
{
while (1)
{
if (*s1 != *s2)
return 0;
if (*s1 == 0)
break;
s1++;
s2++;
}
return 1;
}
#endif // guard

View file

@ -1789,8 +1789,8 @@ void LCR_rendererBlitImage(uint8_t index, unsigned int x, unsigned int y,
void LCR_rendererDrawMenu(const char *tabName,const char **items,
unsigned char itemCount,char selectedItem)
{
int stripHeight = LCR_EFFECTIVE_RESOLUTION_Y / 4;
int stripHeight2 = LCR_EFFECTIVE_RESOLUTION_Y / 10;
int stripHeight = (2 * LCR_EFFECTIVE_RESOLUTION_Y) / 7;
int stripHeight2 = LCR_EFFECTIVE_RESOLUTION_Y / 9;
int i = 0;
uint16_t effect = LCR_renderer.frame >> 1;
@ -1798,13 +1798,13 @@ void LCR_rendererDrawMenu(const char *tabName,const char **items,
while (i < stripHeight * LCR_EFFECTIVE_RESOLUTION_X)
{
LCR_drawPixel(i,0xd69b
LCR_drawPixel(i,0x4a8c
#if LCR_SETTING_POTATO_GRAPHICS
);
#else
^ (effect & 0x18e3));
^ (effect & 0x1827));
effect += 7;
effect += 3;
#endif
++i;
@ -1850,6 +1850,16 @@ void LCR_rendererDrawMenu(const char *tabName,const char **items,
for (int j = 0; j < itemCount + 1; ++j)
{
const char *s = j ? items[j - 1] : tabName;
const char *s2 = s;
uint16_t textColor = 0x5aeb;
while (*s2) // if the item contains '#' (check), we draw it as green
{
if (*s2 == '#')
textColor = 0x0700;
s2++;
}
if (j == selectedItem + 1)
for (int y = i - 10; y < i + LCR_rendererComputeTextHeight(3) + 10; ++y)
@ -1859,7 +1869,7 @@ void LCR_rendererDrawMenu(const char *tabName,const char **items,
LCR_rendererDrawText(s,(LCR_EFFECTIVE_RESOLUTION_X -
LCR_rendererComputeTextWidth(s,3)) / 2,i,
(j == 0 || j == selectedItem + 1) ? 0xf79c : 0x5aeb,3);
(j == 0 || j == selectedItem + 1) ? 0xf79c : textColor,3);
if (j == 0)
i = stripHeight + stripHeight2;
@ -1873,7 +1883,7 @@ void LCR_rendererDrawMenu(const char *tabName,const char **items,
stripHeight / LCR_IMAGE_SIZE,0xffff);
#endif
LCR_rendererDrawText(LCR_texts[LCR_TEXTS_VERSION],5,5,0xffff,2);
LCR_rendererDrawText(LCR_texts[LCR_TEXTS_VERSION],5,5,0xe71c,2);
LCR_renderer.frame++;
}