Compare commits
4 commits
41f9d3f886
...
74013219e5
Author | SHA1 | Date | |
---|---|---|---|
74013219e5 | |||
60cf16c8de | |||
57097c57bb | |||
f0d8521e90 |
6 changed files with 676 additions and 602 deletions
14
TODO.txt
14
TODO.txt
|
@ -2,10 +2,8 @@ fuck issue trackers :D
|
|||
|
||||
=========== GENERAL ==============
|
||||
|
||||
- check again the target times for maps
|
||||
- remake TM maps in the third party repo
|
||||
- make reverse maps
|
||||
- ghost color
|
||||
- controller supports? analog input could be "tapping" the keys with varying
|
||||
frequency
|
||||
- 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
|
||||
|
@ -46,6 +44,12 @@ 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
|
||||
|
@ -69,8 +73,6 @@ 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
|
||||
|
|
|
@ -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
3
data
|
@ -53,7 +53,6 @@ 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
|
||||
|
@ -130,7 +129,6 @@ 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
|
||||
|
@ -208,4 +206,3 @@ 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
56
game.h
|
@ -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. This function potentially reloads current
|
||||
map!
|
||||
if the replay couldn't be loaded or -3 if the replay is invalid. 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 mapIndex;
|
||||
return LCR_replayValidate() ? mapIndex : -3;
|
||||
else
|
||||
{
|
||||
LCR_LOG2("bad map");
|
||||
|
@ -1243,10 +1243,10 @@ void LCR_gameDraw3DView(void)
|
|||
LCR_GameUnit carTransform[6];
|
||||
|
||||
LCR_GameUnit physicsInterpolationParam =
|
||||
!(LCR_racing.playingReplay && LCR_replayHasFinished()) ?
|
||||
!(LCR_racing.replay.on && LCR_replayHasFinished()) ?
|
||||
LCR_GAME_UNIT -
|
||||
((LCR_game.nextRacingTickTime - LCR_game.time) * LCR_GAME_UNIT)
|
||||
/ LCR_RACING_TICK_MS
|
||||
/ LCR_RACING_TICK_MS_RT
|
||||
: LCR_GAME_UNIT / 2;
|
||||
|
||||
LCR_racingGetCarTransform(carTransform,carTransform + 3,
|
||||
|
@ -1353,7 +1353,8 @@ void LCR_gameSaveReplay(void)
|
|||
|
||||
LCR_gameTimeToStr(LCR_timeTicksToMS(LCR_game.runTime),str);
|
||||
|
||||
for (int i = 0; i < LCR_MAP_NAME_MAX_LEN; ++i)
|
||||
for (int i = (str[0] == '0' && str[1] == '0' ? 3 : 0);
|
||||
i < LCR_MAP_NAME_MAX_LEN; ++i)
|
||||
if (str[i])
|
||||
_LCR_gameDataCharWrite(str[i]);
|
||||
else
|
||||
|
@ -1365,6 +1366,17 @@ 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).
|
||||
|
@ -1387,7 +1399,7 @@ void LCR_gameHandleInput(void)
|
|||
LCR_currentMap.targetTime = LCR_game.runTime;
|
||||
}
|
||||
|
||||
LCR_gameResetRun(LCR_racing.playingReplay,LCR_game.ghost.active);
|
||||
LCR_gameResetRun(LCR_racing.replay.on,LCR_game.ghost.active);
|
||||
}
|
||||
}
|
||||
else if (LCR_game.state == LCR_GAME_STATE_RUN_STARTING)
|
||||
|
@ -1447,7 +1459,7 @@ void LCR_gameHandleInput(void)
|
|||
LCR_rendererMoveCamera(offsets,offsets + 3);
|
||||
}
|
||||
else if (LCR_game.keyStates[LCR_KEY_A] == 1)
|
||||
LCR_gameResetRun(LCR_racing.playingReplay,LCR_game.ghost.active);
|
||||
LCR_gameResetRun(LCR_racing.replay.on,LCR_game.ghost.active);
|
||||
}
|
||||
else // LCR_GAME_STATE_MENU
|
||||
{
|
||||
|
@ -1469,7 +1481,7 @@ void LCR_gameHandleInput(void)
|
|||
LCR_game.menu.selectedItem = 0;
|
||||
LCR_audioPlaySound(LCR_SOUND_CLICK);
|
||||
}
|
||||
else if (LCR_game.keyStates[LCR_KEY_UP] == 1)
|
||||
else if (LCR_gameKeyActive(LCR_KEY_UP))
|
||||
{
|
||||
LCR_LOG1("menu item up");
|
||||
|
||||
|
@ -1486,7 +1498,7 @@ void LCR_gameHandleInput(void)
|
|||
scrolled = -1;
|
||||
}
|
||||
}
|
||||
else if (LCR_game.keyStates[LCR_KEY_DOWN] == 1)
|
||||
else if (LCR_gameKeyActive(LCR_KEY_DOWN))
|
||||
{
|
||||
LCR_LOG1("menu item down");
|
||||
|
||||
|
@ -1548,7 +1560,7 @@ void LCR_gameHandleInput(void)
|
|||
|
||||
case 3:
|
||||
if (LCR_game.statePrev == LCR_GAME_STATE_RUN_FINISHED &&
|
||||
!LCR_racing.playingReplay)
|
||||
!LCR_racing.replay.on)
|
||||
LCR_gameSaveReplay();
|
||||
else
|
||||
LCR_gamePopupMessage(LCR_texts[LCR_TEXTS_FAIL]);
|
||||
|
@ -1718,12 +1730,12 @@ uint8_t LCR_gameStep(uint32_t time)
|
|||
LCR_LOG1_NUM(LCR_game.runTime);
|
||||
|
||||
if (LCR_game.runTime <= LCR_currentMap.targetTime &&
|
||||
!LCR_racing.playingReplay)
|
||||
!LCR_racing.replay.on)
|
||||
{
|
||||
LCR_gameSaveReplay();
|
||||
|
||||
if (!LCR_game.mapBeaten && !LCR_game.ghost.active &&
|
||||
!LCR_racing.playingReplay)
|
||||
!LCR_racing.replay.on)
|
||||
{
|
||||
LCR_LOG1("map beaten");
|
||||
LCR_game.mapBeaten = 1;
|
||||
|
@ -1770,11 +1782,9 @@ 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;
|
||||
LCR_game.nextRacingTickTime += LCR_RACING_TICK_MS_RT;
|
||||
}
|
||||
|
||||
sleep = (3 * (LCR_game.nextRacingTickTime - time)) / 4;
|
||||
|
||||
// handle rendering:
|
||||
if (time >= LCR_game.nextRenderFrameTime ||
|
||||
LCR_game.state == LCR_GAME_STATE_LOADING)
|
||||
|
@ -1810,11 +1820,6 @@ 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)
|
||||
{
|
||||
|
@ -1825,6 +1830,15 @@ 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
|
||||
|
|
84
racing.h
84
racing.h
|
@ -56,7 +56,10 @@ 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 \
|
||||
|
||||
#define LCR_RACING_TICK_MS (1000 / LCR_RACING_FPS)
|
||||
|
||||
#define LCR_RACING_TICK_MS_RT \
|
||||
(100000 / (LCR_RACING_FPS * LCR_SETTING_TIME_MULTIPLIER))
|
||||
|
||||
#define LCR_RACING_VERSION1 '0' ///< First part of physics eng. version.
|
||||
|
@ -168,10 +171,9 @@ 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];
|
||||
|
||||
|
@ -376,7 +378,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;
|
||||
|
@ -445,7 +447,8 @@ 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;
|
||||
|
@ -982,7 +985,7 @@ void LCR_racingRestart(uint8_t replay)
|
|||
LCR_racing.tick = 0;
|
||||
LCR_racing.fanForce = 0;
|
||||
|
||||
LCR_racing.playingReplay = replay;
|
||||
LCR_racing.replay.on = replay;
|
||||
|
||||
TPE_bodyActivate(&(LCR_racing.carBody));
|
||||
LCR_racing.wheelCollisions = 0;
|
||||
|
@ -1066,7 +1069,7 @@ void LCR_racingInit(void)
|
|||
TPE_worldInit(&(LCR_racing.physicsWorld),
|
||||
&(LCR_racing.carBody),1,_LCR_racingEnvironmentFunction);
|
||||
|
||||
LCR_racing.playingReplay = 0;
|
||||
LCR_racing.replay.on = 0;
|
||||
LCR_racing.physicsWorld.collisionCallback = _LCR_racingCollisionHandler;
|
||||
}
|
||||
|
||||
|
@ -1202,8 +1205,9 @@ int _LCR_racingCarShapeOK(void)
|
|||
}
|
||||
|
||||
/**
|
||||
Updates the racing physics world, call every LCR_RACING_TICK_MS milliseconds.
|
||||
Returns a set of events (logically ORed) that occured during this step.
|
||||
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.
|
||||
*/
|
||||
uint32_t LCR_racingStep(unsigned int input)
|
||||
{
|
||||
|
@ -1217,7 +1221,7 @@ uint32_t LCR_racingStep(unsigned int input)
|
|||
|
||||
LCR_racing.groundMaterial = LCR_BLOCK_MATERIAL_CONCRETE;
|
||||
|
||||
if (LCR_racing.playingReplay)
|
||||
if (LCR_racing.replay.on)
|
||||
{
|
||||
if (LCR_racing.tick == 0)
|
||||
LCR_replayInitPlaying();
|
||||
|
@ -1637,7 +1641,7 @@ uint32_t LCR_racingStep(unsigned int input)
|
|||
{
|
||||
result |= LCR_RACING_EVENT_FINISHED;
|
||||
|
||||
if (!LCR_racing.playingReplay)
|
||||
if (!LCR_racing.replay.on)
|
||||
LCR_replayRecordEvent(LCR_racing.tick,LCR_REPLAY_EVENT_END);
|
||||
}
|
||||
}
|
||||
|
@ -1678,4 +1682,62 @@ void LCR_physicsDebugDraw(LCR_GameUnit camPos[3], LCR_GameUnit camRot[2],
|
|||
#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
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue