So I've tried now the following:
1) (During runtime) created a block-shaped model-entity in front of the player (taking into account his angles of course)
2) Traced downwards from the block position using "USE_BOX" with the "me" flag set to the block
3) moving the player using the "target"-vector minus the current player position as the absolute movement distance
Well, works. ALLMOST. I use a straight rail for testing purposes and at one certain point the player just stops, in other words: gets stuck somehow. Ive been looking at my code for hours now and I just can't figure out why the hell he gets stuck halfway on the rail for no visible reason whatsoever.
Here's my current code, it is being called once per frame:
ENTITY* grindblock;
ENTITY* current_rail;
VECTOR* grindtrace = {x=0; y=0; z=0;}
VECTOR* grindheight = {x=0; y=0; z=0;}
VECTOR* grindtest = {x=0; y=0; z=0;}
[...]
void movement_state_grind()
{
if(grindblock == NULL) // has the block already been created? If not, create it
{
grindblock = ent_create("grindblock.mdl", nullvector, NULL);
set(grindblock, TRANSLUCENT);
set(grindblock, PASSABLE);
grindblock.alpha = 0;
}
vec_set(grindblock.x, nullvector);
grindblock.x = 1;
vec_rotate(grindblock.x, player.pan); // take into account the player's angles
vec_normalize(grindblock.x, 3); // place it 3 quants in front of him (speed = 3 quants per frame for testing)
vec_add(grindblock.x, player.x); // the final position of the block
vec_set(grindblock.pan, player.pan); // to make sure the block and the player are facing into the same direction
vec_set(grindtrace, nullvector);
grindtrace.z = -1; // trace downwards
vec_rotate(grindtrace, grindblock.pan); // "downwards" is relative - rotate it and align the angle to the player angle
vec_normalize(grindtrace, 100); // trace 100 quants downwards (should always be enough to hit the rail)
vec_add(grindtrace, grindblock.x); // final position of the trace target
me = grindblock;
you = player;
c_trace(grindblock.x, grindtrace, IGNORE_ME|IGNORE_YOU|IGNORE_PASSABLE|USE_BOX); // ignore the grindblock itself and the player
vec_set(grindtest, target);
if(you == current_rail)
{
if is(your, FLAG3)
{
vec_set(grindheight, nullvector);
grindheight.z = -1;
vec_rotate(grindheight, player.pan);
vec_normalize(grindheight, -47); // go up 47 quants from the target vector to get the new position of the player model
vec_set(move_reldist, nullvector); // no relative movement
vec_diff(move_absdist, target, player.x); // absolute movement is the difference between current and new absolute position
vec_to_angle(player.pan, move_absdist); // force the player to look into that direction
vec_add(move_absdist, grindheight); // add in the 47 quants for player hight
}
}
else
{
player_movement = falling; // if the rail was NOT hit, the end of the rail has been reached (most likely ^^')
}
}
The c_move itself is done in the player-action main loop, but it's very simple:
c_move(player, move_reldist, move_absdist, IGNORE_PASSABLE|GLIDE);
... with move_reldist being equal to the nullvector while grinding. There's really nothing (much) else going on, I even tried to completely switch off gravity during grinding, didn't change anything about the result so there HAS to be some problem with my code above... The code is very well documented and easy to understand, I hope, however, I can't find the mistake...