2016-03-27 11:49:47 +02:00
|
|
|
/*
|
|
|
|
===========================================================================
|
2023-10-22 20:25:54 +02:00
|
|
|
Copyright (C) 2023 the OpenMoHAA team
|
2016-03-27 11:49:47 +02:00
|
|
|
|
|
|
|
This file is part of OpenMoHAA source code.
|
|
|
|
|
|
|
|
OpenMoHAA source code is free software; you can redistribute it
|
|
|
|
and/or modify it under the terms of the GNU General Public License as
|
|
|
|
published by the Free Software Foundation; either version 2 of the License,
|
|
|
|
or (at your option) any later version.
|
|
|
|
|
|
|
|
OpenMoHAA source code is distributed in the hope that it will be
|
|
|
|
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
GNU General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with OpenMoHAA source code; if not, write to the Free Software
|
|
|
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
|
|
===========================================================================
|
|
|
|
*/
|
|
|
|
|
|
|
|
// g_mmove.cpp : AI/Path movement code.
|
|
|
|
//
|
|
|
|
|
|
|
|
#include "g_local.h"
|
|
|
|
#include "entity.h"
|
2023-01-29 20:59:31 +01:00
|
|
|
#include "game.h"
|
2016-03-27 11:49:47 +02:00
|
|
|
|
|
|
|
typedef struct {
|
2023-10-22 20:25:54 +02:00
|
|
|
qboolean validGroundTrace;
|
|
|
|
trace_t groundTrace;
|
|
|
|
float previous_origin[3];
|
|
|
|
float previous_velocity[3];
|
2016-03-27 11:49:47 +02:00
|
|
|
} mml_t;
|
|
|
|
|
|
|
|
mmove_t *mm;
|
2023-10-22 20:25:54 +02:00
|
|
|
mml_t mml;
|
|
|
|
|
|
|
|
void MM_ClipVelocity(float *in, float *normal, float *out, float overbounce)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-22 20:25:54 +02:00
|
|
|
float backoff;
|
|
|
|
float dir_z;
|
|
|
|
float normal2[3];
|
|
|
|
|
2023-10-22 21:03:25 +02:00
|
|
|
if (normal[2] >= MIN_WALK_NORMAL) {
|
2023-10-22 20:25:54 +02:00
|
|
|
if (in[0] == 0.0f && in[1] == 0.0f) {
|
|
|
|
VectorClear(out);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
normal2[0] = in[0] + DotProduct2D(in, normal);
|
|
|
|
normal2[1] = in[1] + DotProduct2D(in, normal);
|
|
|
|
normal2[2] = normal[2] * DotProduct2D(in, in);
|
|
|
|
|
|
|
|
VectorNormalize(normal2);
|
|
|
|
|
|
|
|
dir_z = -normal2[2];
|
|
|
|
|
|
|
|
out[0] = in[0];
|
|
|
|
out[1] = in[1];
|
|
|
|
out[2] = DotProduct2D(in, normal2) / dir_z;
|
|
|
|
} else {
|
|
|
|
backoff = DotProduct(in, normal);
|
|
|
|
|
|
|
|
if (backoff < 0) {
|
|
|
|
backoff *= overbounce;
|
|
|
|
} else {
|
|
|
|
backoff /= overbounce;
|
|
|
|
}
|
|
|
|
|
|
|
|
out[0] = in[0] - normal[0] * backoff;
|
|
|
|
out[1] = in[1] - normal[1] * backoff;
|
|
|
|
out[2] = in[2] - normal[2] * backoff;
|
|
|
|
}
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2023-10-22 20:25:54 +02:00
|
|
|
qboolean MM_AddTouchEnt(int entityNum)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-22 20:25:54 +02:00
|
|
|
int i;
|
|
|
|
qboolean blockEnt;
|
|
|
|
Entity *ent;
|
|
|
|
|
|
|
|
if (entityNum == ENTITYNUM_NONE || entityNum == ENTITYNUM_WORLD) {
|
|
|
|
return qtrue;
|
|
|
|
}
|
|
|
|
|
|
|
|
ent = G_GetEntity(entityNum);
|
|
|
|
|
|
|
|
blockEnt = ent->BlocksAIMovement();
|
|
|
|
|
|
|
|
if (!blockEnt) {
|
|
|
|
if (ent->IsSubclassOfPlayer()) {
|
|
|
|
mm->hit_temp_obstacle |= 1;
|
|
|
|
} else if (ent->IsSubclassOfDoor()) {
|
|
|
|
mm->hit_temp_obstacle |= 2;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-10-22 21:03:25 +02:00
|
|
|
if (mm->numtouch == MAXTOUCH) {
|
|
|
|
return blockEnt;
|
|
|
|
}
|
|
|
|
|
2023-10-22 20:25:54 +02:00
|
|
|
// see if it is already added
|
|
|
|
for (i = 0; i < mm->numtouch; i++) {
|
|
|
|
if (mm->touchents[i] == entityNum) {
|
|
|
|
return blockEnt;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// add it
|
|
|
|
mm->touchents[mm->numtouch] = entityNum;
|
|
|
|
mm->numtouch++;
|
|
|
|
|
|
|
|
return blockEnt;
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2023-10-22 20:25:54 +02:00
|
|
|
qboolean MM_SlideMove(qboolean gravity)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-22 20:25:54 +02:00
|
|
|
int bumpcount;
|
|
|
|
vec3_t dir;
|
|
|
|
float d;
|
|
|
|
int numplanes;
|
|
|
|
vec3_t planes[5];
|
|
|
|
vec3_t clipVelocity;
|
|
|
|
int i;
|
|
|
|
int j;
|
|
|
|
int k;
|
|
|
|
trace_t trace;
|
|
|
|
vec3_t end;
|
|
|
|
float time_left;
|
|
|
|
qboolean bBlockEnt;
|
|
|
|
|
|
|
|
if (gravity) {
|
|
|
|
mm->velocity[2] = mm->velocity[2] - mm->frametime * sv_gravity->integer;
|
|
|
|
if (mm->groundPlane) {
|
|
|
|
MM_ClipVelocity(mm->velocity, mm->groundPlaneNormal, mm->velocity, OVERCLIP);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
time_left = mm->frametime;
|
|
|
|
|
|
|
|
if (mm->groundPlane) {
|
|
|
|
numplanes = 1;
|
|
|
|
VectorCopy(mm->groundPlaneNormal, planes[0]);
|
|
|
|
} else {
|
|
|
|
numplanes = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// never turn against original velocity
|
|
|
|
VectorNormalize2(mm->velocity, planes[numplanes]);
|
|
|
|
numplanes++;
|
|
|
|
|
|
|
|
for (bumpcount = 0; bumpcount < 4; bumpcount++) {
|
|
|
|
// calculate position we are trying to move to
|
|
|
|
VectorMA(mm->origin, time_left, mm->velocity, end);
|
|
|
|
|
|
|
|
// see if we can make it there
|
|
|
|
gi.trace(&trace, mm->origin, mm->mins, mm->maxs, end, mm->entityNum, mm->tracemask, qtrue, qfalse);
|
|
|
|
|
|
|
|
if (trace.allsolid) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (trace.fraction > 0) {
|
|
|
|
// actually covered some distance
|
|
|
|
VectorCopy(trace.endpos, mm->origin);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (trace.fraction == 1) {
|
|
|
|
return bumpcount != 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// save entity for contact
|
|
|
|
bBlockEnt = MM_AddTouchEnt(trace.entityNum);
|
|
|
|
|
|
|
|
if (trace.plane.normal[2] < MIN_WALK_NORMAL) {
|
|
|
|
if (trace.plane.normal[2] > -0.999f && bBlockEnt && mm->groundPlane) {
|
|
|
|
if (!mm->hit_obstacle) {
|
|
|
|
mm->hit_obstacle = true;
|
|
|
|
VectorCopy(mm->origin, mm->hit_origin);
|
|
|
|
}
|
|
|
|
|
|
|
|
VectorAdd(mm->obstacle_normal, trace.plane.normal, mm->obstacle_normal);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
memcpy(&mml.groundTrace, &trace, sizeof(mml.groundTrace));
|
|
|
|
mml.validGroundTrace = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
time_left -= time_left * trace.fraction;
|
|
|
|
|
|
|
|
if (numplanes >= MAX_CLIP_PLANES) {
|
|
|
|
VectorClear(mm->velocity);
|
|
|
|
return qtrue;
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// if this is the same plane we hit before, nudge velocity
|
|
|
|
// out along it, which fixes some epsilon issues with
|
|
|
|
// non-axial planes
|
|
|
|
//
|
|
|
|
for (i = 0; i < numplanes; i++) {
|
|
|
|
if (DotProduct(trace.plane.normal, planes[i]) > 0.99) {
|
|
|
|
VectorAdd(trace.plane.normal, mm->velocity, mm->velocity);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (i >= numplanes) {
|
|
|
|
//
|
|
|
|
// modify velocity so it parallels all of the clip planes
|
|
|
|
//
|
2024-03-31 22:15:19 +02:00
|
|
|
VectorCopy(trace.plane.normal, planes[numplanes]);
|
|
|
|
numplanes++;
|
2023-10-22 20:25:54 +02:00
|
|
|
|
|
|
|
// find a plane that it enters
|
|
|
|
for (i = 0; i < numplanes; i++) {
|
|
|
|
if (DotProduct(mm->velocity, planes[i]) >= 0.1) {
|
|
|
|
continue; // move doesn't interact with the plane
|
|
|
|
}
|
|
|
|
|
|
|
|
// slide along the plane
|
|
|
|
MM_ClipVelocity(mm->velocity, planes[i], clipVelocity, OVERCLIP);
|
|
|
|
|
|
|
|
// see if there is a second plane that the new move enters
|
|
|
|
for (j = 0; j < numplanes; j++) {
|
|
|
|
if (j == i) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2024-03-31 22:15:19 +02:00
|
|
|
if (DotProduct(clipVelocity, planes[j]) >= 0.1) {
|
|
|
|
continue; // move doesn't interact with the plane
|
|
|
|
}
|
|
|
|
|
2023-10-22 20:25:54 +02:00
|
|
|
// slide along the plane
|
2024-03-31 22:15:19 +02:00
|
|
|
MM_ClipVelocity(clipVelocity, planes[j], clipVelocity, OVERCLIP);
|
2023-10-22 20:25:54 +02:00
|
|
|
|
2024-03-31 22:15:19 +02:00
|
|
|
if (DotProduct(clipVelocity, planes[i]) >= 0) {
|
2023-10-22 20:25:54 +02:00
|
|
|
continue; // move doesn't interact with the plane
|
|
|
|
}
|
|
|
|
|
|
|
|
// slide the original velocity along the crease
|
|
|
|
CrossProduct(planes[i], planes[j], dir);
|
|
|
|
VectorNormalize(dir);
|
|
|
|
d = DotProduct(dir, mm->velocity);
|
|
|
|
VectorScale(dir, d, clipVelocity);
|
|
|
|
|
|
|
|
// see if there is a third plane the the new move enters
|
|
|
|
for (k = 0; k < numplanes; k++) {
|
|
|
|
if (k == i || k == j) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2024-03-31 22:15:19 +02:00
|
|
|
if (DotProduct(clipVelocity, planes[k]) >= 0.1) {
|
2023-10-22 20:25:54 +02:00
|
|
|
continue; // move doesn't interact with the plane
|
|
|
|
}
|
|
|
|
|
|
|
|
// stop dead at a tripple plane interaction
|
|
|
|
VectorClear(mm->velocity);
|
|
|
|
return qtrue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// if we have fixed all interactions, try another move
|
|
|
|
VectorCopy(clipVelocity, mm->velocity);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (mm->velocity[0] || mm->velocity[1]) {
|
|
|
|
if (mm->groundPlane) {
|
|
|
|
VectorCopy(mm->velocity, dir);
|
|
|
|
VectorNegate(dir, dir);
|
|
|
|
VectorNormalize(dir);
|
|
|
|
|
|
|
|
if (MM_AddTouchEnt(trace.entityNum)) {
|
|
|
|
if (!mm->hit_obstacle) {
|
|
|
|
mm->hit_obstacle = true;
|
|
|
|
VectorCopy(mm->origin, mm->hit_origin);
|
|
|
|
}
|
|
|
|
|
|
|
|
VectorAdd(mm->obstacle_normal, dir, mm->obstacle_normal);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
VectorClear(mm->velocity);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
mm->velocity[2] = 0;
|
|
|
|
return false;
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2023-10-22 20:25:54 +02:00
|
|
|
void MM_GroundTraceInternal(void)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-22 20:25:54 +02:00
|
|
|
if (mml.groundTrace.fraction == 1.0f) {
|
|
|
|
mm->groundPlane = qfalse;
|
|
|
|
mm->walking = qfalse;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (mm->velocity[2] > 0.0f) {
|
|
|
|
if (DotProduct(mm->velocity, mml.groundTrace.plane.normal) > 10.0f) {
|
|
|
|
mm->groundPlane = qfalse;
|
|
|
|
mm->walking = qfalse;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// slopes that are too steep will not be considered onground
|
|
|
|
if (mml.groundTrace.plane.normal[2] < MIN_WALK_NORMAL) {
|
|
|
|
vec3_t oldvel;
|
|
|
|
float d;
|
|
|
|
|
|
|
|
VectorCopy(mm->velocity, oldvel);
|
|
|
|
VectorSet(mm->velocity, 0, 0, -1.0f / mm->frametime);
|
|
|
|
MM_SlideMove(qfalse);
|
|
|
|
|
|
|
|
d = VectorLength(mm->velocity);
|
|
|
|
VectorCopy(oldvel, mm->velocity);
|
|
|
|
|
|
|
|
if (d > (0.1f / mm->frametime)) {
|
|
|
|
mm->groundPlane = qtrue;
|
|
|
|
mm->walking = qfalse;
|
|
|
|
VectorCopy(mml.groundTrace.plane.normal, mm->groundPlaneNormal);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
mm->groundPlane = qtrue;
|
|
|
|
mm->walking = qtrue;
|
|
|
|
VectorCopy(mml.groundTrace.plane.normal, mm->groundPlaneNormal);
|
|
|
|
|
|
|
|
MM_AddTouchEnt(mml.groundTrace.entityNum);
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2023-10-22 20:25:54 +02:00
|
|
|
void MM_GroundTrace(void)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-22 20:25:54 +02:00
|
|
|
float point[3];
|
2016-03-27 11:49:47 +02:00
|
|
|
|
2023-10-22 20:25:54 +02:00
|
|
|
point[0] = mm->origin[0];
|
|
|
|
point[1] = mm->origin[1];
|
|
|
|
point[2] = mm->origin[2] - 0.25f;
|
2016-03-27 11:49:47 +02:00
|
|
|
|
2023-10-22 20:25:54 +02:00
|
|
|
gi.trace(&mml.groundTrace, mm->origin, mm->mins, mm->maxs, point, mm->entityNum, mm->tracemask, qtrue, qfalse);
|
|
|
|
MM_GroundTraceInternal();
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2023-10-22 20:25:54 +02:00
|
|
|
void MM_StepSlideMove(void)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-22 20:25:54 +02:00
|
|
|
vec3_t start_o;
|
|
|
|
vec3_t start_v;
|
|
|
|
vec3_t nostep_o;
|
|
|
|
vec3_t nostep_v;
|
|
|
|
trace_t trace;
|
|
|
|
qboolean bWasOnGoodGround;
|
|
|
|
vec3_t up;
|
|
|
|
vec3_t down;
|
|
|
|
qboolean start_hit_wall;
|
|
|
|
vec3_t start_wall_normal;
|
|
|
|
qboolean first_hit_wall;
|
|
|
|
vec3_t first_wall_normal;
|
|
|
|
vec3_t start_hit_origin;
|
|
|
|
vec3_t first_hit_origin;
|
|
|
|
trace_t nostep_groundTrace;
|
|
|
|
|
|
|
|
VectorCopy(mm->origin, start_o);
|
|
|
|
VectorCopy(mm->velocity, start_v);
|
|
|
|
start_hit_wall = mm->hit_obstacle;
|
|
|
|
VectorCopy(mm->hit_origin, start_hit_origin);
|
|
|
|
VectorCopy(mm->obstacle_normal, start_wall_normal);
|
|
|
|
|
|
|
|
if (MM_SlideMove(qtrue) == 0) {
|
2023-10-22 21:03:25 +02:00
|
|
|
if (mml.validGroundTrace) {
|
|
|
|
MM_GroundTraceInternal();
|
|
|
|
} else {
|
2023-10-22 20:25:54 +02:00
|
|
|
MM_GroundTrace();
|
|
|
|
}
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
VectorCopy(start_o, down);
|
|
|
|
down[2] -= STEPSIZE;
|
|
|
|
gi.trace(&trace, start_o, mm->mins, mm->maxs, down, mm->entityNum, mm->tracemask, qtrue, qfalse);
|
|
|
|
VectorSet(up, 0, 0, 1);
|
|
|
|
|
|
|
|
// never step up when you still have up velocity
|
|
|
|
if (mm->velocity[2] > 0 && (trace.fraction == 1.0f || DotProduct(trace.plane.normal, up) < MIN_WALK_NORMAL)) {
|
2023-10-22 21:03:25 +02:00
|
|
|
if (mml.validGroundTrace) {
|
2023-10-22 20:25:54 +02:00
|
|
|
MM_GroundTraceInternal();
|
2023-10-22 21:03:25 +02:00
|
|
|
} else {
|
|
|
|
MM_GroundTrace();
|
2023-10-22 20:25:54 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (mm->groundPlane && mm->groundPlaneNormal[2] >= MIN_WALK_NORMAL) {
|
|
|
|
bWasOnGoodGround = qtrue;
|
|
|
|
} else {
|
|
|
|
bWasOnGoodGround = qfalse;
|
|
|
|
}
|
|
|
|
|
2024-03-31 22:52:30 +02:00
|
|
|
VectorCopy(start_o, up);
|
|
|
|
up[2] += 18;
|
|
|
|
|
2023-10-22 20:25:54 +02:00
|
|
|
VectorCopy(mm->origin, nostep_o);
|
|
|
|
VectorCopy(mm->velocity, nostep_v);
|
|
|
|
memcpy(&nostep_groundTrace, &mml.groundTrace, sizeof(trace_t));
|
|
|
|
|
2024-03-31 22:52:30 +02:00
|
|
|
VectorCopy(up, mm->origin);
|
2023-10-22 20:25:54 +02:00
|
|
|
VectorCopy(start_v, mm->velocity);
|
|
|
|
|
|
|
|
first_hit_wall = mm->hit_obstacle;
|
|
|
|
VectorCopy(mm->hit_origin, first_hit_origin);
|
|
|
|
VectorCopy(mm->obstacle_normal, first_wall_normal);
|
|
|
|
|
|
|
|
mm->hit_obstacle = start_hit_wall;
|
|
|
|
VectorCopy(start_hit_origin, mm->hit_origin);
|
|
|
|
VectorCopy(start_wall_normal, mm->obstacle_normal);
|
|
|
|
MM_SlideMove(qtrue);
|
|
|
|
|
|
|
|
VectorCopy(mm->origin, down);
|
|
|
|
down[2] -= STEPSIZE * 2;
|
|
|
|
|
|
|
|
// test the player position if they were a stepheight higher
|
2024-03-31 22:52:30 +02:00
|
|
|
gi.trace(&trace, mm->origin, mm->mins, mm->maxs, down, mm->entityNum, mm->tracemask, qtrue, qfalse);
|
2023-10-22 21:03:25 +02:00
|
|
|
if (trace.entityNum != ENTITYNUM_WORLD && trace.entityNum != ENTITYNUM_NONE) {
|
2023-10-22 20:25:54 +02:00
|
|
|
VectorCopy(nostep_o, mm->origin);
|
|
|
|
VectorCopy(nostep_v, mm->velocity);
|
|
|
|
memcpy(&mml.groundTrace, &nostep_groundTrace, sizeof(mml.groundTrace));
|
|
|
|
mm->hit_obstacle = first_hit_wall;
|
|
|
|
VectorCopy(first_hit_origin, mm->hit_origin);
|
|
|
|
VectorCopy(first_wall_normal, mm->obstacle_normal);
|
|
|
|
|
2023-10-22 21:03:25 +02:00
|
|
|
if (mml.validGroundTrace) {
|
2023-10-22 20:25:54 +02:00
|
|
|
MM_GroundTraceInternal();
|
2023-10-22 21:03:25 +02:00
|
|
|
} else {
|
|
|
|
MM_GroundTrace();
|
2023-10-22 20:25:54 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!trace.allsolid) {
|
|
|
|
memcpy(&mml.groundTrace, &trace, sizeof(mml.groundTrace));
|
|
|
|
mml.validGroundTrace = qtrue;
|
|
|
|
|
2023-10-22 21:03:25 +02:00
|
|
|
if (bWasOnGoodGround && trace.fraction < 1 && trace.plane.normal[2] < MIN_WALK_NORMAL) {
|
2023-10-22 20:25:54 +02:00
|
|
|
VectorCopy(nostep_o, mm->origin);
|
|
|
|
VectorCopy(nostep_v, mm->velocity);
|
|
|
|
|
|
|
|
if (first_hit_wall) {
|
|
|
|
mm->hit_obstacle = first_hit_wall;
|
|
|
|
VectorCopy(first_hit_origin, mm->hit_origin);
|
|
|
|
VectorCopy(first_wall_normal, mm->obstacle_normal);
|
|
|
|
}
|
|
|
|
|
|
|
|
MM_GroundTraceInternal();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
VectorCopy(trace.endpos, mm->origin);
|
|
|
|
}
|
|
|
|
|
2023-10-22 21:03:25 +02:00
|
|
|
if (trace.fraction < 1) {
|
2023-10-22 20:25:54 +02:00
|
|
|
MM_ClipVelocity(mm->velocity, trace.plane.normal, mm->velocity, OVERCLIP);
|
|
|
|
}
|
|
|
|
|
2023-10-22 21:03:25 +02:00
|
|
|
if (mml.validGroundTrace) {
|
2023-10-22 20:25:54 +02:00
|
|
|
MM_GroundTraceInternal();
|
2023-10-22 21:03:25 +02:00
|
|
|
} else {
|
|
|
|
MM_GroundTrace();
|
2023-10-22 20:25:54 +02:00
|
|
|
}
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2023-10-22 20:25:54 +02:00
|
|
|
void MM_ClipVelocity2D(float *in, float *normal, float *out, float overbounce)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-22 20:25:54 +02:00
|
|
|
float backoff;
|
|
|
|
float dir_z;
|
|
|
|
float normal2[3];
|
|
|
|
|
2023-10-22 21:03:25 +02:00
|
|
|
if (normal[2] >= MIN_WALK_NORMAL) {
|
2023-10-22 20:25:54 +02:00
|
|
|
if (in[0] == 0.0f && in[1] == 0.0f) {
|
|
|
|
VectorClear(out);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
normal2[0] = in[0] + DotProduct2D(in, normal);
|
|
|
|
normal2[1] = in[1] + DotProduct2D(in, normal);
|
|
|
|
normal2[2] = normal[2] * DotProduct2D(in, in);
|
|
|
|
|
|
|
|
VectorNormalize(normal2);
|
|
|
|
|
|
|
|
dir_z = -normal2[2];
|
|
|
|
|
|
|
|
out[0] = in[0];
|
|
|
|
out[1] = in[1];
|
2023-10-22 21:03:25 +02:00
|
|
|
out[2] = DotProduct2D(in, normal2) / dir_z;
|
2023-10-22 20:25:54 +02:00
|
|
|
} else {
|
|
|
|
backoff = DotProduct2D(in, normal);
|
|
|
|
|
|
|
|
if (backoff < 0) {
|
|
|
|
backoff *= overbounce;
|
|
|
|
} else {
|
|
|
|
backoff /= overbounce;
|
|
|
|
}
|
|
|
|
|
|
|
|
out[0] = in[0] - normal[0] * backoff;
|
|
|
|
out[1] = in[1] - normal[1] * backoff;
|
|
|
|
out[2] = -(backoff * normal[2]);
|
|
|
|
}
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2023-10-22 20:25:54 +02:00
|
|
|
void MmoveSingle(mmove_t *mmove)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-22 20:25:54 +02:00
|
|
|
float point[3];
|
|
|
|
trace_t trace;
|
|
|
|
|
|
|
|
mm = mmove;
|
|
|
|
|
2023-10-22 21:03:25 +02:00
|
|
|
mmove->numtouch = 0;
|
|
|
|
mm->hit_obstacle = false;
|
|
|
|
VectorCopy(vec3_origin, mm->obstacle_normal);
|
|
|
|
mm->hit_temp_obstacle = false;
|
2023-10-22 20:25:54 +02:00
|
|
|
|
|
|
|
memset(&mml, 0, sizeof(mml_t));
|
|
|
|
|
2023-10-22 21:03:25 +02:00
|
|
|
VectorCopy(mm->origin, mml.previous_origin);
|
|
|
|
VectorCopy(mm->velocity, mml.previous_velocity);
|
2023-10-22 20:25:54 +02:00
|
|
|
|
2023-10-22 21:03:25 +02:00
|
|
|
if (mm->walking) {
|
|
|
|
if (mm->desired_speed < 1.0f) {
|
|
|
|
VectorClear2D(mm->velocity);
|
2023-10-22 20:25:54 +02:00
|
|
|
MM_GroundTrace();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2023-10-22 21:03:25 +02:00
|
|
|
vec3_t wishdir;
|
2023-10-22 20:25:54 +02:00
|
|
|
|
|
|
|
MM_ClipVelocity2D(mm->desired_dir, mm->groundPlaneNormal, wishdir, OVERCLIP);
|
|
|
|
VectorNormalize(wishdir);
|
|
|
|
|
|
|
|
mm->velocity[0] = mm->desired_speed * wishdir[0];
|
|
|
|
mm->velocity[1] = mm->desired_speed * wishdir[1];
|
2023-10-22 21:03:25 +02:00
|
|
|
} else if (mm->groundPlane) {
|
|
|
|
MM_ClipVelocity(mm->velocity, mm->groundPlaneNormal, mm->velocity, OVERCLIP);
|
2023-10-22 20:25:54 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
MM_StepSlideMove();
|
|
|
|
|
|
|
|
if (!mm->walking && mml.previous_velocity[2] >= 0.0f && mm->velocity[2] <= 0.0f) {
|
2023-10-22 21:03:25 +02:00
|
|
|
point[0] = mm->origin[0];
|
|
|
|
point[1] = mm->origin[1];
|
|
|
|
point[2] = mm->origin[2] - 18.0f;
|
2023-10-22 20:25:54 +02:00
|
|
|
|
|
|
|
gi.trace(&trace, mm->origin, mm->mins, mm->maxs, point, mm->entityNum, mm->tracemask, qtrue, qfalse);
|
|
|
|
|
|
|
|
if (trace.fraction < 1.0f && !trace.allsolid) {
|
2023-10-22 21:03:25 +02:00
|
|
|
VectorCopy(trace.endpos, mm->origin);
|
2023-10-22 20:25:54 +02:00
|
|
|
MM_GroundTrace();
|
|
|
|
}
|
|
|
|
}
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|