Compare commits

..

No commits in common. "74013219e57628af0de8912a5a2998e42b242216" and "41f9d3f886c8d3b36eb6dee7012b2f58ee832806" have entirely different histories.

6 changed files with 602 additions and 676 deletions

View file

@ -2,8 +2,10 @@ fuck issue trackers :D
=========== GENERAL ==============
- controller supports? analog input could be "tapping" the keys with varying
frequency
- check again the target times for maps
- remake TM maps in the third party repo
- make reverse maps
- ghost color
- frontends:
- auto test frontend, with no I/O, that will just internally run a series of
inputs and check if the output is as expected
@ -44,12 +46,6 @@ fuck issue trackers :D
=========== HANDLED ==============
- should drifting make a sound? NO NEED
- menu: key repeat?
- replay validation? maybe yes?
- ghost color
- make reverse maps
- remake TM maps in the third party repo
- check again the target times for maps
- redo the menu effect somehow
- press forward map??? :-D only when physics is frozen
- devtest map, internal camera: reversing at start makes the car face completely
@ -73,6 +69,8 @@ fuck issue trackers :D
again (reshape iterations, tension, ...); seem acceptable now maybe?
- in tiny resolution the sky jumps when rotating
- car particles seem too big in low res
- replay validation? MAYBE NOT, make a separate tool if needed, shouldn't likely
be part of the game
- at high resolution (like 1920) buggy triangles sometimes appeard, tried to
fix this in S3L now but needs to be tested
- shift the car texture a bit to align the wheels? KINDA DOESN'T GETT BETTER NOW

1109
assets.h

File diff suppressed because it is too large Load diff

View file

@ -29,7 +29,7 @@ const char *part1 = // big maps
":=C0j:f347"
":=H0q2:f42c"
":xB2k:f625" // start hole
":uB2o:uF2oJ:uB2kL:uF2kI" // curved corners in start
":uB2o:uF2oJ :uB2kL :uF2kI" // curved corners in start
":]G2kL:]G2oL" // decorative ramps near start
":-w29:f41e"
":xH0r:f35b" // hole
@ -92,7 +92,7 @@ const char *part1 = // big maps
":xA1I:f912:xf0n:f715"
":xf0s:fc1a:xC0B:f419"
":xL0n:f32c:xf0N:fg23"
":-r1s:f418:=i0h2:f63a"
":-r1s:f418:=i0h2 :f63a"
":^n2m2L:f114:^l2q2I:f211:vn2q2J:An0q2L:f121:=l0m:m335"
":=n0q2:'n0C2L:f116:'o0C2J:f116"
":'l1I2L:f115:-m1I2:f215:'o1I2J:f115"
@ -122,7 +122,7 @@ const char *part1 = // big maps
":<ubrJ:]uarL-:|u9rL-:|tarJ:]t9rJ"
":=t8r:<u5rJ-:]u6rL:|u7rL:|t6rJ-:]t7rJ-"
":<g1G2:f511:'g1H2:f511" // ramp left
":<J1G2:f511:'J1H2:f511" // ramp right
":<J1G2 :f511 :'J1H2 :f511" // ramp right
// details:
":vw1F1:f131:vx1F1|:f131:vw1E1L:f131:vx1E1|J:f131" // tree
":~m1D2:~q1E2:~z2I2:~v2M2:~E2K2:~q1o2:~u1p2:~G1z:~H1E" // bumps
@ -142,7 +142,7 @@ const char *part1 = // big maps
":*qrt:!o1y:!o1z:+Wsz"
// start box:
":=mqr:f96d:xnrs:f74b:^mvrJ:f11d:^uvrL:f11d"
":~ouz3-:~suz3-:~ouw3-:~suw3-" // lights
":~ouz3- :~suz3- :~ouw3- :~suw3-" // lights
":^utuI-:^utv-:^utzI-:^utA-"
":'ustI:-usu:-usv:'usw"
":'usyI:-usz:-usA:'usB"
@ -390,7 +390,7 @@ const char *part2 = // small maps
- 1536 (0x600) triangles */
// TINY MAP 1:
"#MLCtiny1;330 0:*G1b:+n9H:!I1H"
"#MLCtiny1;330 0 :*G1b:+n9H:!I1H"
// start
":=E0b:f61i"
":^D1bJ:f11i:^J1bL:f11i"

3
data
View file

@ -53,6 +53,7 @@ details
:=h0h2 :fl12 :f11o :=B0i2 :f11m :=m0n2 :fb12
:*n1EI :!n1F :+p1r :+y1l :+y3I :+k1l
#MLCbonus2;1309 1
:*B1lJ
:^y0oI :f611
:=w0k :f814 :=w0o :f2a1 :=y6c :f21d
@ -129,6 +130,7 @@ details
:]h0gI :}g0gI :|g1gI :f211 :|g3gI- :f211 :]g4gI- :f211 :;g0fJ :f251
:-e5g :f413 :|g0hL
:+018 :f213 :!v05 :f311
#Mempty;594 0
#MLCpressforw1;594 0
:*cac
press forward map, blocks go in the direction that car travels
@ -206,3 +208,4 @@ air path
#Rdrummy LCbonus1 13'16;00LCbonus1;999b1acd 0000399:0001:0089:0051:0079:0021:0093:0031:0089:0031:0119:0091:0053:00f1:01a3:00d1:0099:0201:0073:0051:0063:0051:0059:0051:00d9:00b1:0089:0041:00a3:0031:02b9:0048:0020:0081:0149:00c1:0059:0031:0113:0051:0019:0078:0099:0041
#Rdrummy LCbonus2 24'18;00LCbonus2;288d28fe 0000733:0001:0153:00d1:0023:0081:00d3:0041:0023:00a9:0128:0034:0036:00e4:005c:0054:0096:0044:007c:0024:0146:0112:0018:0029:00f1:0063:0061:00c3:0031:00c3:0031:0025:0031:0039:0081:0033:01d1:0083:0081:0073:0031:00e3:0071:00f9:0051:01b9:00c4:0040:0028:0069:0021:0043:00e1:0090:0046:00b0:0031:0043:0070:0024:0026:00e0:0018:0049:0018:0039:01a1:0039:0051:0049:0048:001c:0098:0050:0011:0039:0061:00d9:0041:00a9:0018:00c9:00e1:0083:0042:0010:0042:0093:00b1:0170:0022:0016:0042:0083:0141:0013:0021:0059:0041:0053
#Rdrummy LCpressforw1 21'31;00LCpressforw1;6363b43d 0000599:0001

56
game.h
View file

@ -853,8 +853,8 @@ uint8_t LCR_gameLoadMap(unsigned int mapIndex)
/**
Loads replay by its index, returns index of a map for the replay (and the map
will be loaded as with LCR_mapLoadFromStr) or -1 if the map wasn't found or -2
if the replay couldn't be loaded or -3 if the replay is invalid. This function
potentially reloads current map!
if the replay couldn't be loaded. This function potentially reloads current
map!
*/
unsigned int LCR_gameLoadReplay(unsigned int replayIndex)
{
@ -900,7 +900,7 @@ unsigned int LCR_gameLoadReplay(unsigned int replayIndex)
LCR_LOG2("map name hash matches");
if (LCR_gameLoadMap(mapIndex) && mapHash == LCR_currentMap.hash)
return LCR_replayValidate() ? mapIndex : -3;
return mapIndex;
else
{
LCR_LOG2("bad map");
@ -1243,10 +1243,10 @@ void LCR_gameDraw3DView(void)
LCR_GameUnit carTransform[6];
LCR_GameUnit physicsInterpolationParam =
!(LCR_racing.replay.on && LCR_replayHasFinished()) ?
!(LCR_racing.playingReplay && LCR_replayHasFinished()) ?
LCR_GAME_UNIT -
((LCR_game.nextRacingTickTime - LCR_game.time) * LCR_GAME_UNIT)
/ LCR_RACING_TICK_MS_RT
/ LCR_RACING_TICK_MS
: LCR_GAME_UNIT / 2;
LCR_racingGetCarTransform(carTransform,carTransform + 3,
@ -1353,8 +1353,7 @@ void LCR_gameSaveReplay(void)
LCR_gameTimeToStr(LCR_timeTicksToMS(LCR_game.runTime),str);
for (int i = (str[0] == '0' && str[1] == '0' ? 3 : 0);
i < LCR_MAP_NAME_MAX_LEN; ++i)
for (int i = 0; i < LCR_MAP_NAME_MAX_LEN; ++i)
if (str[i])
_LCR_gameDataCharWrite(str[i]);
else
@ -1366,17 +1365,6 @@ void LCR_gameSaveReplay(void)
LCR_gamePopupMessage(LCR_texts[LCR_TEXTS_SAVED]);
}
/**
Checks if given key is either immediately pressed or repeated after being
held for some time.
*/
uint8_t LCR_gameKeyActive(uint8_t key)
{
return LCR_game.keyStates[key] == 1 ||
(LCR_game.keyStates[key] >= (1200 / LCR_SETTING_FPS)
&& ((LCR_game.frame & 0x03) == 0));
}
/**
Helper subroutine, handles user input during main loop frame, EXCEPT for the
driving input (that is handled in the loop itself).
@ -1399,7 +1387,7 @@ void LCR_gameHandleInput(void)
LCR_currentMap.targetTime = LCR_game.runTime;
}
LCR_gameResetRun(LCR_racing.replay.on,LCR_game.ghost.active);
LCR_gameResetRun(LCR_racing.playingReplay,LCR_game.ghost.active);
}
}
else if (LCR_game.state == LCR_GAME_STATE_RUN_STARTING)
@ -1459,7 +1447,7 @@ void LCR_gameHandleInput(void)
LCR_rendererMoveCamera(offsets,offsets + 3);
}
else if (LCR_game.keyStates[LCR_KEY_A] == 1)
LCR_gameResetRun(LCR_racing.replay.on,LCR_game.ghost.active);
LCR_gameResetRun(LCR_racing.playingReplay,LCR_game.ghost.active);
}
else // LCR_GAME_STATE_MENU
{
@ -1481,7 +1469,7 @@ void LCR_gameHandleInput(void)
LCR_game.menu.selectedItem = 0;
LCR_audioPlaySound(LCR_SOUND_CLICK);
}
else if (LCR_gameKeyActive(LCR_KEY_UP))
else if (LCR_game.keyStates[LCR_KEY_UP] == 1)
{
LCR_LOG1("menu item up");
@ -1498,7 +1486,7 @@ void LCR_gameHandleInput(void)
scrolled = -1;
}
}
else if (LCR_gameKeyActive(LCR_KEY_DOWN))
else if (LCR_game.keyStates[LCR_KEY_DOWN] == 1)
{
LCR_LOG1("menu item down");
@ -1560,7 +1548,7 @@ void LCR_gameHandleInput(void)
case 3:
if (LCR_game.statePrev == LCR_GAME_STATE_RUN_FINISHED &&
!LCR_racing.replay.on)
!LCR_racing.playingReplay)
LCR_gameSaveReplay();
else
LCR_gamePopupMessage(LCR_texts[LCR_TEXTS_FAIL]);
@ -1730,12 +1718,12 @@ uint8_t LCR_gameStep(uint32_t time)
LCR_LOG1_NUM(LCR_game.runTime);
if (LCR_game.runTime <= LCR_currentMap.targetTime &&
!LCR_racing.replay.on)
!LCR_racing.playingReplay)
{
LCR_gameSaveReplay();
if (!LCR_game.mapBeaten && !LCR_game.ghost.active &&
!LCR_racing.replay.on)
!LCR_racing.playingReplay)
{
LCR_LOG1("map beaten");
LCR_game.mapBeaten = 1;
@ -1782,9 +1770,11 @@ uint8_t LCR_gameStep(uint32_t time)
if (LCR_game.state != LCR_GAME_STATE_RUN_FINISHED)
LCR_game.runTime = LCR_racing.tick;
LCR_game.nextRacingTickTime += LCR_RACING_TICK_MS_RT;
LCR_game.nextRacingTickTime += LCR_RACING_TICK_MS;
}
sleep = (3 * (LCR_game.nextRacingTickTime - time)) / 4;
// handle rendering:
if (time >= LCR_game.nextRenderFrameTime ||
LCR_game.state == LCR_GAME_STATE_LOADING)
@ -1820,6 +1810,11 @@ uint8_t LCR_gameStep(uint32_t time)
LCR_game.renderFramesMeasured++;
#endif
}
else
{
uint32_t tmp = (3 * (LCR_game.nextRenderFrameTime - time)) / 4;
sleep = tmp < sleep ? tmp : sleep;
}
if (LCR_game.state == LCR_GAME_STATE_LOADING)
{
@ -1830,15 +1825,6 @@ uint8_t LCR_gameStep(uint32_t time)
LCR_gameDrawPopupMessage();
}
if (LCR_game.nextRacingTickTime > time)
sleep = LCR_game.nextRenderFrameTime - time;
if (LCR_game.nextRenderFrameTime > time &&
LCR_game.nextRenderFrameTime - time < sleep)
sleep = LCR_game.nextRenderFrameTime - time;
sleep = (sleep * 3) / 4;
if (sleep)
LCR_sleep(sleep);
else

View file

@ -56,10 +56,7 @@ typedef int32_t LCR_GameUnit; ///< Abstract game unit.
#define LCR_RACING_FPS 30 /**< Physics FPS, i.e. the number of
physics ticks per second. */
#define LCR_RACING_TICK_MS (1000 / LCR_RACING_FPS)
#define LCR_RACING_TICK_MS_RT \
#define LCR_RACING_TICK_MS \
(100000 / (LCR_RACING_FPS * LCR_SETTING_TIME_MULTIPLIER))
#define LCR_RACING_VERSION1 '0' ///< First part of physics eng. version.
@ -171,9 +168,10 @@ struct
uint16_t crashState;
uint8_t playingReplay;
struct
{
uint8_t on; ///< Currently playing replay?
uint16_t eventCount;
uint16_t events[LCR_SETTING_REPLAY_MAX_SIZE];
@ -378,7 +376,7 @@ int LCR_replayHasFinished(void)
for (int i = 0; i < LCR_racing.replay.eventCount; ++i)
totalTime += LCR_racing.replay.events[i] >> 4;
return totalTime > LCR_racing.replay.achievedTime;
return totalTime >= LCR_racing.replay.achievedTime;
}
return LCR_racing.replay.currentEvent > LCR_racing.replay.eventCount;
@ -447,8 +445,7 @@ int LCR_replayRecordEvent(uint32_t frame, uint8_t input)
frame -= previousFrame; // convert to offset
while (frame > 4095 && LCR_racing.replay.eventCount <
LCR_SETTING_REPLAY_MAX_SIZE)
while (frame > 4095 && LCR_racing.replay.eventCount < LCR_SETTING_REPLAY_MAX_SIZE)
{
// add intermediate events
frame -= 4095;
@ -985,7 +982,7 @@ void LCR_racingRestart(uint8_t replay)
LCR_racing.tick = 0;
LCR_racing.fanForce = 0;
LCR_racing.replay.on = replay;
LCR_racing.playingReplay = replay;
TPE_bodyActivate(&(LCR_racing.carBody));
LCR_racing.wheelCollisions = 0;
@ -1069,7 +1066,7 @@ void LCR_racingInit(void)
TPE_worldInit(&(LCR_racing.physicsWorld),
&(LCR_racing.carBody),1,_LCR_racingEnvironmentFunction);
LCR_racing.replay.on = 0;
LCR_racing.playingReplay = 0;
LCR_racing.physicsWorld.collisionCallback = _LCR_racingCollisionHandler;
}
@ -1205,9 +1202,8 @@ int _LCR_racingCarShapeOK(void)
}
/**
Updates the racing physics world, call every LCR_RACING_TICK_MS_RT
milliseconds. Returns a set of events (logically ORed) that occured during
this step.
Updates the racing physics world, call every LCR_RACING_TICK_MS milliseconds.
Returns a set of events (logically ORed) that occured during this step.
*/
uint32_t LCR_racingStep(unsigned int input)
{
@ -1221,7 +1217,7 @@ uint32_t LCR_racingStep(unsigned int input)
LCR_racing.groundMaterial = LCR_BLOCK_MATERIAL_CONCRETE;
if (LCR_racing.replay.on)
if (LCR_racing.playingReplay)
{
if (LCR_racing.tick == 0)
LCR_replayInitPlaying();
@ -1641,7 +1637,7 @@ uint32_t LCR_racingStep(unsigned int input)
{
result |= LCR_RACING_EVENT_FINISHED;
if (!LCR_racing.replay.on)
if (!LCR_racing.playingReplay)
LCR_replayRecordEvent(LCR_racing.tick,LCR_REPLAY_EVENT_END);
}
}
@ -1681,63 +1677,5 @@ void LCR_physicsDebugDraw(LCR_GameUnit camPos[3], LCR_GameUnit camRot[2],
cPos,cRot,cView,16,LCR_PHYSICS_UNIT / 4,LCR_racing.tick * 4);
#endif
}
/**
Validates replay, i.e. checks if it finishes and whether its achieved time
agrees with the stored time. The function can only be called when both the
replay and the correct map are loaded. The loaded replay's playing position
will be reset after this function returns.
*/
int LCR_replayValidate(void)
{
LCR_LOG1("validating replay");
int result = 0;
LCR_racingRestart(1);
while (LCR_racing.tick < 0x00f00000 // no infinite loops
&& LCR_racing.tick <= LCR_racing.replay.achievedTime)
{
int coords[3];
LCR_racingStep(0);
LCR_racingGetCarBlockCoords(coords);
coords[0] = LCR_mapGetBlockAt(coords[0],coords[1],coords[2]);
if (coords[0] && LCR_currentMap.blocks[coords[0] * LCR_BLOCK_SIZE] ==
LCR_BLOCK_FINISH)
{
uint8_t allCPsTaken = 1; // reuse as variable
for (int i = 0; i < LCR_currentMap.blockCount; ++i)
if (LCR_currentMap.blocks[i * LCR_BLOCK_SIZE] == LCR_BLOCK_CHECKPOINT_0)
{
allCPsTaken = 0;
break;
}
if (allCPsTaken)
{
result = LCR_racing.tick == (LCR_racing.replay.achievedTime + 1);
break;
}
}
}
if (result)
{
LCR_LOG1("replay valid");
}
else
{
LCR_LOG1("replay invalid!");
}
LCR_racingRestart(1);
return result;
}
#endif // guard