Untitled
unknown
c_cpp
4 years ago
22 kB
11
Indexable
/*
* MIT License
*
* Copyright (c) 2021 ETJump team <zero@etjump.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
// etj_pmove.cpp - reimplementation of relevants parts of bg_pmove.cpp
// for calculation of pmove-centric parts of cgame code
#include "etj_pmove.h"
namespace ETJump
{
void Pmove::InitPmove(void)
{
p.pm_ps = cg.predictedPlayerState;
p.pm.tracemask = p.pm_ps.pm_type == PM_DEAD ? MASK_PLAYERSOLID & ~CONTENTS_BODY : MASK_PLAYERSOLID;
Pmove::PmoveSingle();
}
void Pmove::PmoveSingle(void)
{
auto const uCmdScale = p.pm_ps.stats[STAT_USERCMD_BUTTONS] & (BUTTON_WALKING << 8) ? 64 : 127;
if (!cg.demoPlayback && !(p.pm_ps.pm_flags & PMF_FOLLOW))
{
auto const cmdNum = trap_GetCurrentCmdNumber();
trap_GetUserCmd(cmdNum, &p.pm.cmd);
}
else
{
p.pm.cmd.forwardmove = uCmdScale * (!!(p.pm_ps.stats[STAT_USERCMD_MOVE] & UMOVE_FORWARD) -
!!(p.pm_ps.stats[STAT_USERCMD_MOVE] & UMOVE_BACKWARD));
p.pm.cmd.rightmove = uCmdScale * (!!(p.pm_ps.stats[STAT_USERCMD_MOVE] & UMOVE_RIGHT) -
!!(p.pm_ps.stats[STAT_USERCMD_MOVE] & UMOVE_LEFT));
p.pm.cmd.upmove = uCmdScale * (!!(p.pm_ps.stats[STAT_USERCMD_MOVE] & UMOVE_UP) -
!!(p.pm_ps.stats[STAT_USERCMD_MOVE] & UMOVE_DOWN));
}
// CG_Printf("%d %d %d\n", p.pm.cmd.forwardmove, p.pm.cmd.rightmove, p.pm.cmd.upmove);
// clear all pmove local vars
memset(&p.pml, 0, sizeof(p.pml));
// these were in pml previously, make sure they are cleared too
p.pm.walking = qfalse;
p.pm.groundPlane = qfalse;
memset(&p.pm.groundTrace, 0, sizeof(p.pm.groundTrace));
// save old velocity for crashlanding
VectorCopy(p.pm_ps.velocity, p.pml.previous_velocity);
AngleVectors(p.pm_ps.viewangles, p.pml.forward, p.pml.right, p.pml.up);
if (p.pm.cmd.upmove < 10)
{
// not holding jump
p.pm_ps.pm_flags &= ~PMF_JUMP_HELD;
}
if (p.pm_ps.pm_type >= PM_DEAD || p.pm_ps.pm_flags & (PMF_LIMBO | PMF_TIME_LOCKPLAYER)) // DHM - Nerve
{
p.pm.cmd.forwardmove = 0;
p.pm.cmd.rightmove = 0;
p.pm.cmd.upmove = 0;
}
// use default key combination when no user input
if (!p.pm.cmd.forwardmove && !p.pm.cmd.rightmove)
{
p.pm.cmd.forwardmove = uCmdScale;
p.pm.cmd.rightmove = uCmdScale;
}
// set mins, maxs, and viewheight
if (!PM_CheckProne(&p.pm, &p.pm_ps))
{
PM_CheckDuck(&p.pm, &p.pm_ps);
}
// set watertype, and waterlevel
PM_SetWaterLevel(&p.pm, &p.pm_ps);
// set groundentity
PM_GroundTrace(&p.pm, &p.pm_ps, &p.pml);
// for simplicity, we omit ladders and water
// and only consider ground, air and ice movement
if (p.pml.ladder)
{
return;
}
else if (p.pm_ps.pm_flags & PMF_TIME_WATERJUMP)
{
return;
}
else if (p.pm.waterlevel > 1)
{
// swimming
return;
}
else if (p.pm.walking && !(p.pm_ps.eFlags & EF_MOUNTEDTANK))
{
// walking on ground
PM_WalkMove(&p.pm, &p.pm_ps, &p.pml);
}
else if (!(p.pm_ps.eFlags & EF_MOUNTEDTANK))
{
// airborne
PM_AirMove(&p.pm, &p.pm_ps, &p.pml);
}
}
void Pmove::PM_AirMove(pmove_t* pm, playerState_t* pm_ps, pml_t* pml)
{
PM_Friction(pm, pm_ps, pml);
auto const scale = p.PM_CmdScale(pm_ps, &pm->cmd);
// project moves down to flat plane
pml->forward[2] = 0;
pml->right[2] = 0;
VectorNormalize(pml->forward);
VectorNormalize(pml->right);
p.PM_UpdateWishVel(pm, pml);
auto const wishspeed = scale * VectorLength2(p.wishvel);
// TODO: this is where we are going to seperate different
// cgame functions that use pmove calculations
// PM_Accelerate(wishdir, wishspeed, pm_airaccelerate);
}
void Pmove::PM_WalkMove(pmove_t* pm, playerState_t* pm_ps, pml_t* pml)
{
if (pm->waterlevel > 2 && DotProduct(pml->forward, pm->groundTrace.plane.normal) > 0)
{
// begin swimming
// PM_WaterMove();
return;
}
if (PM_CheckJump(pm, pm_ps))
{
// jumped away
if (pm->waterlevel > 1)
{
// PM_WaterMove();
}
else
{
PM_AirMove(pm, pm_ps, pml);
}
if (!(pm->cmd.serverTime - p.pmext.jumpTime < ETJump::JUMP_DELAY_TIME))
{
p.pmext.sprintTime -= 2500;
if (p.pmext.sprintTime < 0)
{
p.pmext.sprintTime = 0;
}
}
p.pmext.jumpTime = pm->cmd.serverTime;
// JPW NERVE
pm_ps->jumpTime = pm->cmd.serverTime; // Arnout: NOTE : TEMP DEBUG
return;
}
PM_Friction(pm, pm_ps, pml);
auto const scale = p.PM_CmdScale(pm_ps, &pm->cmd);
// project moves down to flat plane
pml->forward[2] = 0;
pml->right[2] = 0;
// FIXME: only flat ground is correct
// project the forward and right directions onto the ground plane
// PM_ClipVelocity(pml->forward, pm->groundTrace.plane.normal, pml->forward, OVERCLIP);
// PM_ClipVelocity(pml->right, pm->groundTrace.plane.normal, pml->right, OVERCLIP);
//
VectorNormalize(pml->forward);
VectorNormalize(pml->right);
PM_UpdateWishVel(pm, pml);
float wishspeed = scale * VectorLength2(p.wishvel);
// clamp the speed lower if prone
if (pm_ps->eFlags & EF_PRONE)
{
if (wishspeed > pm_ps->speed * pm_proneSpeedScale)
{
wishspeed = pm_ps->speed * pm_proneSpeedScale;
}
}
else if (pm_ps->pm_flags & PMF_DUCKED) // clamp the speed lower if ducking
{
if (wishspeed > pm_ps->speed * pm_ps->crouchSpeedScale)
{
wishspeed = pm_ps->speed * pm_ps->crouchSpeedScale;
}
}
// clamp the speed lower if wading or walking on the bottom
if (pm->waterlevel)
{
float waterScale;
waterScale = pm->waterlevel / 3.0;
if (pm->watertype == CONTENTS_SLIME) //----(SA) slag
{
waterScale = 1.0 - (1.0 - pm_slagSwimScale) * waterScale;
}
else
{
waterScale = 1.0 - (1.0 - pm_waterSwimScale) * waterScale;
}
if (wishspeed > pm_ps->speed * waterScale)
{
wishspeed = pm_ps->speed * waterScale;
}
}
#if 0
// when a player gets hit, they temporarily lose
// full control, which allows them to be moved a bit
// TODO: PM_Accelerate
if ((pm->groundTrace.surfaceFlags & SURF_SLICK) || pm_ps->pm_flags & PMF_TIME_KNOCKBACK)
{
PM_Accelerate(wishdir, wishspeed, pm_airaccelerate);
}
else
{
PM_Accelerate(wishdir, wishspeed, pm_accelerate);
}
#endif
}
void Pmove::PM_Friction(pmove_t* pm, playerState_t* pm_ps, pml_t* pml)
{
// ignore slope movement
auto const speed = pm->walking ? VectorLength2(pm_ps->velocity) : VectorLength(pm_ps->velocity);
// rain - #179 don't do this for PM_SPECTATOR/PM_NOCLIP, we always want them to stop
if (speed < 1 && pm_ps->pm_type != PM_SPECTATOR && pm_ps->pm_type != PM_NOCLIP)
{
pm_ps->velocity[0] = 0;
pm_ps->velocity[1] = 0; // allow sinking underwater
// FIXME: still have z friction underwater?
return;
}
float drop = 0;
// apply ground friction
if (pm->waterlevel <= 1)
{
if (pm->walking && !(pm->groundTrace.surfaceFlags & SURF_SLICK))
{
// if getting knocked back, no friction
if (!(pm_ps->pm_flags & PMF_TIME_KNOCKBACK))
{
auto const control = speed < pm_stopspeed ? pm_stopspeed : speed;
drop += control * pm_friction * pml->frametime;
}
}
}
// apply water friction even if just wading
if (pm->waterlevel)
{
if (pm->watertype == CONTENTS_SLIME) //----(SA) slag
{
drop += speed * pm_slagfriction * pm->waterlevel * pml->frametime;
}
else
{
drop += speed * pm_waterfriction * pm->waterlevel * pml->frametime;
}
}
if (pm_ps->pm_type == PM_SPECTATOR)
{
drop += speed * pm_spectatorfriction * pml->frametime;
}
// apply ladder strafe friction
if (pml->ladder)
{
drop += speed * pm_ladderfriction * pml->frametime;
}
// scale the velocity
auto newspeed = speed - drop;
if (newspeed < 0)
{
newspeed = 0;
}
newspeed /= speed;
// rain - if we're barely moving and barely slowing down, we want to
// help things along--we don't want to end up getting snapped back to
// our previous speed
if (pm_ps->pm_type == PM_SPECTATOR || pm_ps->pm_type == PM_NOCLIP)
{
if (drop < 1.0f && speed < 3.0f)
{
newspeed = 0.0;
}
}
// rain - used VectorScale instead of multiplying by hand
VectorScale(pm_ps->velocity, newspeed, pm_ps->velocity);
}
void Pmove::PM_UpdateWishVel(pmove_t* pm, pml_t* pml)
{
for (auto i = 0; i < 2; i++)
{
p.wishvel[i] = pml->forward[i] * pm->cmd.forwardmove + pml->right[i] * pm->cmd.rightmove;
}
}
float Pmove::PM_CmdScale(playerState_t const* pm_ps, usercmd_t const* cmd)
{
auto max = abs(cmd->forwardmove);
if (abs(cmd->rightmove) > max)
{
max = abs(cmd->rightmove);
}
if (abs(cmd->upmove) > max)
{
max = abs(cmd->upmove);
}
if (!max)
{
return 0;
}
auto const total = sqrtf(cmd->forwardmove * cmd->forwardmove + cmd->rightmove * cmd->rightmove + cmd->upmove * cmd->upmove);
auto const scale = (float)pm_ps->speed * max / (127.f * total);
if (pm_ps->stats[STAT_USERCMD_BUTTONS] & (BUTTON_SPRINT << 8) && p.pmext.sprintTime > 50)
{
return scale * pm_ps->sprintSpeedScale;
}
else
{
return scale * pm_ps->runSpeedScale;
}
}
bool Pmove::PM_CheckJump(pmove_t* pm, playerState_t* pm_ps)
{
// no jumpin when prone
if (pm_ps->eFlags & EF_PRONE)
{
return false;
}
// JPW NERVE -- jumping in multiplayer uses and requires sprint juice (to prevent turbo skating, sprint + jumps)
// don't allow jump accel
// rain - revert to using pmext for this since pmext is fixed now.
// fix for #166
if (pm->cmd.serverTime - p.pmext.jumpTime < ETJump::JUMP_DELAY_TIME)
{
if (ETJump::hasJustStoodUp())
{
return false;
}
if (pm->shared & BG_LEVEL_NO_JUMPDELAY)
{
if (pm->groundTrace.surfaceFlags & SURF_NOJUMPDELAY)
{
return false;
}
}
else
{
if (!(pm->groundTrace.surfaceFlags & SURF_NOJUMPDELAY))
{
return false;
}
}
}
if (pm_ps->pm_flags & PMF_RESPAWNED)
{
return false; // don't allow jump until all buttons are up
}
if (pm->cmd.upmove < 10)
{
// not holding jump
return false;
}
// must wait for jump to be released
if (pm_ps->pm_flags & PMF_JUMP_HELD)
{
// clear upmove so cmdscale doesn't lower running speed
pm->cmd.upmove = 0;
return false;
}
pm->groundPlane = qfalse; // jumping away
pm->walking = qfalse;
pm_ps->pm_flags |= PMF_JUMP_HELD;
p.pmext.isJumpLand = true;
pm_ps->groundEntityNum = ENTITYNUM_NONE;
pm_ps->velocity[2] = JUMP_VELOCITY;
return true;
}
void Pmove::PM_CheckDuck(pmove_t* pm, playerState_t* pm_ps)
{
trace_t trace;
// Ridah, modified this for configurable bounding boxes
pm->mins[0] = pm_ps->mins[0];
pm->mins[1] = pm_ps->mins[1];
pm->maxs[0] = pm_ps->maxs[0];
pm->maxs[1] = pm_ps->maxs[1];
pm->mins[2] = pm_ps->mins[2];
if (pm_ps->pm_type == PM_DEAD)
{
pm->maxs[2] = pm_ps->maxs[2]; // NOTE: must set death bounding box in game code
pm_ps->viewheight = pm_ps->deadViewHeight;
return;
}
if ((pm->cmd.upmove < 0 && !(pm_ps->eFlags & EF_MOUNTEDTANK) && !(pm_ps->pm_flags & PMF_LADDER)) || pm_ps->weapon == WP_MORTAR_SET)
{ // duck
pm_ps->pm_flags |= PMF_DUCKED;
}
else
{ // stand up if possible
if (pm_ps->pm_flags & PMF_DUCKED)
{
// try to stand up
pm->maxs[2] = pm_ps->maxs[2];
PM_TraceAll(&trace, pm_ps->origin, pm_ps->origin);
if (!trace.allsolid)
{
pm_ps->pm_flags &= ~PMF_DUCKED;
}
}
}
if (pm_ps->pm_flags & PMF_DUCKED)
{
pm->maxs[2] = pm_ps->crouchMaxZ;
pm_ps->viewheight = pm_ps->crouchViewHeight;
}
else
{
pm->maxs[2] = pm_ps->maxs[2];
pm_ps->viewheight = pm_ps->standViewHeight;
}
}
bool Pmove::PM_CheckProne(pmove_t* pm, playerState_t* pm_ps)
{
trace_t trace;
//pm->trace(&trace, pm_ps->origin, pm_ps->mins, pm_ps->maxs, pm_ps->origin, pm_ps->clientNum, CONTENTS_NOPRONE);
trap_CM_CapsuleTrace(&trace, pm_ps->origin, pm_ps->mins, pm_ps->maxs, pm_ps->origin, 0, CONTENTS_NOPRONE);
if (pm->shared & BG_LEVEL_NO_PRONE)
{
if (trace.fraction == 1.0f)
{
pm_ps->eFlags &= ~EF_PRONE;
pm_ps->eFlags &= ~EF_PRONE_MOVING;
return false;
}
}
else
{
if (trace.fraction != 1.0f)
{
pm_ps->eFlags &= ~EF_PRONE;
pm_ps->eFlags &= ~EF_PRONE_MOVING;
return false;
}
}
if (!(pm_ps->eFlags & EF_PRONE))
{
// can't go prone on ladders
if (pm_ps->pm_flags & PMF_LADDER)
{
return false;
}
// no prone when using mg42's
if (pm_ps->persistant[PERS_HWEAPON_USE] || pm_ps->eFlags & EF_MOUNTEDTANK)
{
return false;
}
if (pm_ps->weaponDelay && pm_ps->weapon == WP_PANZERFAUST)
{
return false;
}
if (pm_ps->weapon == WP_MORTAR_SET)
{
return false;
}
// can't go prone while swimming
if (pm->waterlevel > 1)
{
return false;
}
if (((pm_ps->pm_flags & PMF_DUCKED && pm->cmd.doubleTap == DT_FORWARD) ||
(pm->cmd.wbuttons & WBUTTON_PRONE)) && pm->cmd.serverTime - p.pmext.proneTime > ETJump::PRONE_DELAY_TIME)
{
trace_t trace;
pm->mins[0] = pm_ps->mins[0];
pm->mins[1] = pm_ps->mins[1];
pm->maxs[0] = pm_ps->maxs[0];
pm->maxs[1] = pm_ps->maxs[1];
pm->mins[2] = pm_ps->mins[2];
pm->maxs[2] = pm_ps->crouchMaxZ;
pm_ps->eFlags |= EF_PRONE;
PM_TraceAll(&trace, pm_ps->origin, pm_ps->origin);
pm_ps->eFlags &= ~EF_PRONE;
if (!trace.startsolid && !trace.allsolid)
{
// go prone
pm_ps->pm_flags |= PMF_DUCKED; // crouched as well
pm_ps->eFlags |= EF_PRONE;
p.pmext.proneTime = pm->cmd.serverTime; // timestamp 'go prone'
p.pmext.proneGroundTime = pm->cmd.serverTime;
}
}
}
if (pm_ps->eFlags & EF_PRONE)
{
if (pm->waterlevel > 1 ||
pm_ps->pm_type == PM_DEAD ||
pm_ps->eFlags & EF_MOUNTEDTANK ||
// zinx - what was the reason for this, anyway? removing fixes bug 424
// pm->cmd.serverTime - pm->pmext->proneGroundTime > 450 ||
((pm->cmd.doubleTap == DT_BACK || pm->cmd.upmove > 10 || pm->cmd.wbuttons & WBUTTON_PRONE) && pm->cmd.serverTime - p.pmext.proneTime > ETJump::PRONE_DELAY_TIME))
{
trace_t trace;
// see if we have the space to stop prone
pm->mins[0] = pm_ps->mins[0];
pm->mins[1] = pm_ps->mins[1];
pm->maxs[0] = pm_ps->maxs[0];
pm->maxs[1] = pm_ps->maxs[1];
pm->mins[2] = pm_ps->mins[2];
pm->maxs[2] = pm_ps->crouchMaxZ;
pm_ps->eFlags &= ~EF_PRONE;
PM_TraceAll(&trace, pm_ps->origin, pm_ps->origin);
pm_ps->eFlags |= EF_PRONE;
if (!trace.allsolid)
{
// crouch for a bit
pm_ps->pm_flags |= PMF_DUCKED;
// stop prone
pm_ps->eFlags &= ~EF_PRONE;
pm_ps->eFlags &= ~EF_PRONE_MOVING;
p.pmext.proneTime = pm->cmd.serverTime; // timestamp 'stop prone'
// don't jump for a bit
p.pmext.jumpTime = pm->cmd.serverTime - ETJump::PRONE_JUMP_DELAY_TIME;
pm_ps->jumpTime = pm->cmd.serverTime - ETJump::PRONE_JUMP_DELAY_TIME;
}
}
}
if (pm_ps->eFlags & EF_PRONE)
{
// See if we are moving
float spd = VectorLength(pm_ps->velocity);
bool userinput = abs(pm->cmd.forwardmove) + abs(pm->cmd.rightmove) > 10 ? true : false;
if (userinput && spd > 40.f && !(pm_ps->eFlags & EF_PRONE_MOVING))
{
pm_ps->eFlags |= EF_PRONE_MOVING;
}
else if (!userinput && spd < 20.0f && (pm_ps->eFlags & EF_PRONE_MOVING))
{
pm_ps->eFlags &= ~EF_PRONE_MOVING;
}
pm->mins[0] = pm_ps->mins[0];
pm->mins[1] = pm_ps->mins[1];
pm->maxs[0] = pm_ps->maxs[0];
pm->maxs[1] = pm_ps->maxs[1];
pm->mins[2] = pm_ps->mins[2];
pm->maxs[2] = pm_ps->maxs[2] - pm_ps->standViewHeight - PRONE_VIEWHEIGHT;
pm_ps->viewheight = PRONE_VIEWHEIGHT;
return true;
}
return false;
}
void Pmove::PM_GroundTrace(pmove_t* pm, playerState_t* pm_ps, pml_t* pml)
{
vec3_t point;
trace_t trace;
point[0] = pm_ps->origin[0];
point[1] = pm_ps->origin[1];
point[2] = pm_ps->origin[2] - 0.25f;
//PM_TraceAllLegs(&trace, &pm->pmext->proneLegsOffset, pm_ps->origin, point);
trap_CM_CapsuleTrace(&trace, pm_ps->origin, point, pm->mins, pm->maxs, 0, pm->tracemask);
pm->groundTrace = trace;
// do something corrective if the trace starts in a solid...
if (trace.allsolid && !(pm_ps->eFlags & EF_MOUNTEDTANK))
{
if (!PM_CorrectAllSolid(&trace, pm, pm_ps))
{
return;
}
}
// if the trace didn't hit anything, we are in free fall
if (trace.fraction == 1.0)
{
PM_GroundTraceMissed(pm, pm_ps);
return;
}
// check if getting thrown off the ground
if (pm_ps->velocity[2] > 0 && DotProduct(pm_ps->velocity, trace.plane.normal) > 10)
{
pm_ps->groundEntityNum = ENTITYNUM_NONE;
pm->groundPlane = qfalse;
pm->walking = qfalse;
return;
}
// slopes that are too steep will not be considered onground
if (trace.plane.normal[2] < MIN_WALK_NORMAL)
{
// FIXME: if they can't slide down the slope, let them
// walk (sharp crevices)
pm_ps->groundEntityNum = ENTITYNUM_NONE;
pm->groundPlane = qtrue;
pm->walking = qfalse;
return;
}
pm->groundPlane = qtrue;
pm->walking = qtrue;
// hitting solid ground will end a waterjump
if (pm_ps->pm_flags & PMF_TIME_WATERJUMP)
{
pm_ps->pm_flags &= ~(PMF_TIME_WATERJUMP | PMF_TIME_LAND);
pm_ps->pm_time = 0;
}
if (pm_ps->groundEntityNum == ENTITYNUM_NONE)
{
// just hit the ground
// TODO: do we need this..?
//Feen:
// PM_CheckPortal();
// don't do landing time if we were just going down a slope
if (pml->previous_velocity[2] < -200)
{
// don't allow another jump for a little while
pm_ps->pm_flags |= PMF_TIME_LAND;
pm_ps->pm_time = 250;
}
}
pm_ps->groundEntityNum = trace.entityNum;
}
void Pmove::PM_GroundTraceMissed(pmove_t* pm, playerState_t* pm_ps)
{
// If we've never yet touched the ground, it's because we're spawning, so don't
// set to "in air"
if (pm_ps->groundEntityNum != -1)
{
// Signify that we're in mid-air
pm_ps->groundEntityNum = ENTITYNUM_NONE;
} // if (pm_ps->groundEntityNum != -1)...
pm->groundPlane = qfalse;
pm->walking = qfalse;
}
bool Pmove::PM_CorrectAllSolid(trace_t* trace, pmove_t *pm, playerState_t* pm_ps)
{
vec3_t point;
// jitter around
for (auto i = -1; i <= 1; i++)
{
for (auto j = -1; j <= 1; j++)
{
for (auto k = -1; k <= 1; k++)
{
VectorCopy(pm_ps->origin, point);
point[0] += (float)i;
point[1] += (float)j;
point[2] += (float)k;
PM_TraceAll(trace, point, point);
if (!trace->allsolid)
{
point[0] = pm_ps->origin[0];
point[1] = pm_ps->origin[1];
point[2] = pm_ps->origin[2] - 0.25;
PM_TraceAll(trace, pm_ps->origin, point);
pm->groundTrace = *trace;
return true;
}
}
}
}
pm_ps->groundEntityNum = ENTITYNUM_NONE;
pm->groundPlane = qfalse;
pm->walking = qfalse;
return false;
}
void Pmove::PM_SetWaterLevel(pmove_t* pm, playerState_t* pm_ps)
{
vec3_t point;
int cont;
int sample1;
int sample2;
// get waterlevel, accounting for ducking
pm->waterlevel = 0;
pm->watertype = 0;
// Ridah, modified this
point[0] = pm_ps->origin[0];
point[1] = pm_ps->origin[1];
point[2] = pm_ps->origin[2] + pm_ps->mins[2] + 1;
//cont = pm->pointcontents(point, pm_ps->clientNum);
cont = trap_CM_PointContents(point, 0);
if (cont & MASK_WATER)
{
sample2 = pm_ps->viewheight - pm_ps->mins[2];
sample1 = sample2 / 2;
pm->watertype = cont;
pm->waterlevel = 1;
point[2] = pm_ps->origin[2] + pm_ps->mins[2] + sample1;
cont = trap_CM_PointContents(point, 0);
if (cont & MASK_WATER)
{
pm->waterlevel = 2;
point[2] = pm_ps->origin[2] + pm_ps->mins[2] + sample2;
cont = trap_CM_PointContents(point, 0);
if (cont & MASK_WATER)
{
pm->waterlevel = 3;
}
}
}
}
}
Editor is loading...