12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709 |
- // Copyright (c) ZeniMax Media Inc.
- // Licensed under the GNU General Public License 2.0.
- #include "q_std.h"
- #define GAME_INCLUDE
- #include "bg_local.h"
- // [Paril-KEX] generic code to detect & fix a stuck object
- stuck_result_t G_FixStuckObject_Generic(vec3_t &origin, const vec3_t &own_mins, const vec3_t &own_maxs, std::function<stuck_object_trace_fn_t> trace)
- {
- if (!trace(origin, own_mins, own_maxs, origin).startsolid)
- return stuck_result_t::GOOD_POSITION;
- struct {
- float distance;
- vec3_t origin;
- } good_positions[6];
- size_t num_good_positions = 0;
- constexpr struct {
- std::array<int8_t, 3> normal;
- std::array<int8_t, 3> mins, maxs;
- } side_checks[] = {
- { { 0, 0, 1 }, { -1, -1, 0 }, { 1, 1, 0 } },
- { { 0, 0, -1 }, { -1, -1, 0 }, { 1, 1, 0 } },
- { { 1, 0, 0 }, { 0, -1, -1 }, { 0, 1, 1 } },
- { { -1, 0, 0 }, { 0, -1, -1 }, { 0, 1, 1 } },
- { { 0, 1, 0 }, { -1, 0, -1 }, { 1, 0, 1 } },
- { { 0, -1, 0 }, { -1, 0, -1 }, { 1, 0, 1 } },
- };
- for (size_t sn = 0; sn < q_countof(side_checks); sn++)
- {
- auto &side = side_checks[sn];
- vec3_t start = origin;
- vec3_t mins {}, maxs {};
- for (size_t n = 0; n < 3; n++)
- {
- if (side.normal[n] < 0)
- start[n] += own_mins[n];
- else if (side.normal[n] > 0)
- start[n] += own_maxs[n];
- if (side.mins[n] == -1)
- mins[n] = own_mins[n];
- else if (side.mins[n] == 1)
- mins[n] = own_maxs[n];
- if (side.maxs[n] == -1)
- maxs[n] = own_mins[n];
- else if (side.maxs[n] == 1)
- maxs[n] = own_maxs[n];
- }
- trace_t tr = trace(start, mins, maxs, start);
- int8_t needed_epsilon_fix = -1;
- int8_t needed_epsilon_dir;
- if (tr.startsolid)
- {
- for (size_t e = 0; e < 3; e++)
- {
- if (side.normal[e] != 0)
- continue;
- vec3_t ep_start = start;
- ep_start[e] += 1;
- tr = trace(ep_start, mins, maxs, ep_start);
- if (!tr.startsolid)
- {
- start = ep_start;
- needed_epsilon_fix = e;
- needed_epsilon_dir = 1;
- break;
- }
- ep_start[e] -= 2;
- tr = trace(ep_start, mins, maxs, ep_start);
- if (!tr.startsolid)
- {
- start = ep_start;
- needed_epsilon_fix = e;
- needed_epsilon_dir = -1;
- break;
- }
- }
- }
- // no good
- if (tr.startsolid)
- continue;
- vec3_t opposite_start = origin;
- auto &other_side = side_checks[sn ^ 1];
- for (size_t n = 0; n < 3; n++)
- {
- if (other_side.normal[n] < 0)
- opposite_start[n] += own_mins[n];
- else if (other_side.normal[n] > 0)
- opposite_start[n] += own_maxs[n];
- }
- if (needed_epsilon_fix >= 0)
- opposite_start[needed_epsilon_fix] += needed_epsilon_dir;
- // potentially a good side; start from our center, push back to the opposite side
- // to find how much clearance we have
- tr = trace(start, mins, maxs, opposite_start);
- // ???
- if (tr.startsolid)
- continue;
- // check the delta
- vec3_t end = tr.endpos;
- // push us very slightly away from the wall
- end += vec3_t{(float) side.normal[0], (float) side.normal[1], (float) side.normal[2]} * 0.125f;
- // calculate delta
- const vec3_t delta = end - opposite_start;
- vec3_t new_origin = origin + delta;
- if (needed_epsilon_fix >= 0)
- new_origin[needed_epsilon_fix] += needed_epsilon_dir;
- tr = trace(new_origin, own_mins, own_maxs, new_origin);
- // bad
- if (tr.startsolid)
- continue;
- good_positions[num_good_positions].origin = new_origin;
- good_positions[num_good_positions].distance = delta.lengthSquared();
- num_good_positions++;
- }
- if (num_good_positions)
- {
- std::sort(&good_positions[0], &good_positions[num_good_positions - 1], [](const auto &a, const auto &b) { return a.distance < b.distance; });
- origin = good_positions[0].origin;
- return stuck_result_t::FIXED;
- }
- return stuck_result_t::NO_GOOD_POSITION;
- }
- // all of the locals will be zeroed before each
- // pmove, just to make damn sure we don't have
- // any differences when running on client or server
- struct pml_t
- {
- vec3_t origin; // full float precision
- vec3_t velocity; // full float precision
- vec3_t forward, right, up;
- float frametime;
- csurface_t *groundsurface;
- int groundcontents;
- vec3_t previous_origin;
- vec3_t start_velocity;
- };
- pm_config_t pm_config;
- pmove_t *pm;
- pml_t pml;
- // movement parameters
- float pm_stopspeed = 100;
- float pm_maxspeed = 300;
- float pm_duckspeed = 100;
- float pm_accelerate = 10;
- float pm_wateraccelerate = 10;
- float pm_friction = 6;
- float pm_waterfriction = 1;
- float pm_waterspeed = 400;
- float pm_laddermod = 0.5f;
- /*
- walking up a step should kill some velocity
- */
- /*
- ==================
- PM_ClipVelocity
- Slide off of the impacting object
- returns the blocked flags (1 = floor, 2 = step / wall)
- ==================
- */
- void PM_ClipVelocity(const vec3_t &in, const vec3_t &normal, vec3_t &out, float overbounce)
- {
- float backoff;
- float change;
- int i;
- backoff = in.dot(normal) * overbounce;
- for (i = 0; i < 3; i++)
- {
- change = normal[i] * backoff;
- out[i] = in[i] - change;
- if (out[i] > -STOP_EPSILON && out[i] < STOP_EPSILON)
- out[i] = 0;
- }
- }
- trace_t PM_Clip(const vec3_t &start, const vec3_t &mins, const vec3_t &maxs, const vec3_t &end, contents_t mask)
- {
- return pm->clip(start, &mins, &maxs, end, mask);
- }
- trace_t PM_Trace(const vec3_t &start, const vec3_t &mins, const vec3_t &maxs, const vec3_t &end, contents_t mask = CONTENTS_NONE)
- {
- if (pm->s.pm_type == PM_SPECTATOR)
- return PM_Clip(start, mins, maxs, end, MASK_SOLID);
- if (mask == CONTENTS_NONE)
- {
- if (pm->s.pm_type == PM_DEAD || pm->s.pm_type == PM_GIB)
- mask = MASK_DEADSOLID;
- else if (pm->s.pm_type == PM_SPECTATOR)
- mask = MASK_SOLID;
- else
- mask = MASK_PLAYERSOLID;
- if (pm->s.pm_flags & PMF_IGNORE_PLAYER_COLLISION)
- mask &= ~CONTENTS_PLAYER;
- }
- return pm->trace(start, &mins, &maxs, end, pm->player, mask);
- }
- // only here to satisfy pm_trace_t
- inline trace_t PM_Trace_Auto(const vec3_t &start, const vec3_t &mins, const vec3_t &maxs, const vec3_t &end)
- {
- return PM_Trace(start, mins, maxs, end);
- }
- /*
- ==================
- PM_StepSlideMove
- Each intersection will try to step over the obstruction instead of
- sliding along it.
- Returns a new origin, velocity, and contact entity
- Does not modify any world state?
- ==================
- */
- constexpr float MIN_STEP_NORMAL = 0.7f; // can't step up onto very steep slopes
- constexpr size_t MAX_CLIP_PLANES = 5;
- inline void PM_RecordTrace(touch_list_t &touch, trace_t &tr)
- {
- if (touch.num == MAXTOUCH)
- return;
- for (size_t i = 0; i < touch.num; i++)
- if (touch.traces[i].ent == tr.ent)
- return;
- touch.traces[touch.num++] = tr;
- }
- // [Paril-KEX] made generic so you can run this without
- // needing a pml/pm
- void PM_StepSlideMove_Generic(vec3_t &origin, vec3_t &velocity, float frametime, const vec3_t &mins, const vec3_t &maxs, touch_list_t &touch, bool has_time, pm_trace_t trace_func)
- {
- int bumpcount, numbumps;
- vec3_t dir;
- float d;
- int numplanes;
- vec3_t planes[MAX_CLIP_PLANES];
- vec3_t primal_velocity;
- int i, j;
- trace_t trace;
- vec3_t end;
- float time_left;
- numbumps = 4;
- primal_velocity = velocity;
- numplanes = 0;
- time_left = frametime;
- for (bumpcount = 0; bumpcount < numbumps; bumpcount++)
- {
- for (i = 0; i < 3; i++)
- end[i] = origin[i] + time_left * velocity[i];
- trace = trace_func(origin, mins, maxs, end);
- if (trace.allsolid)
- { // entity is trapped in another solid
- velocity[2] = 0; // don't build up falling damage
-
- // save entity for contact
- PM_RecordTrace(touch, trace);
- return;
- }
- // [Paril-KEX] experimental attempt to fix stray collisions on curved
- // surfaces; easiest to see on q2dm1 by running/jumping against the sides
- // of the curved map.
- if (trace.surface2)
- {
- vec3_t clipped_a, clipped_b;
- PM_ClipVelocity(velocity, trace.plane.normal, clipped_a, 1.01f);
- PM_ClipVelocity(velocity, trace.plane2.normal, clipped_b, 1.01f);
- bool better = false;
- for (int i = 0; i < 3; i++)
- {
- if (fabsf(clipped_a[i]) < fabsf(clipped_b[i]))
- {
- better = true;
- break;
- }
- }
- if (better)
- {
- trace.plane = trace.plane2;
- trace.surface = trace.surface2;
- }
- }
- if (trace.fraction > 0)
- { // actually covered some distance
- origin = trace.endpos;
- numplanes = 0;
- }
- if (trace.fraction == 1)
- break; // moved the entire distance
- // save entity for contact
- PM_RecordTrace(touch, trace);
- time_left -= time_left * trace.fraction;
- // slide along this plane
- if (numplanes >= MAX_CLIP_PLANES)
- { // this shouldn't really happen
- velocity = vec3_origin;
- break;
- }
- //
- // if this is the same plane we hit before, nudge origin
- // out along it, which fixes some epsilon issues with
- // non-axial planes (xswamp, q2dm1 sometimes...)
- //
- for (i = 0; i < numplanes; i++)
- {
- if (trace.plane.normal.dot(planes[i]) > 0.99f)
- {
- pml.origin.x += trace.plane.normal.x * 0.01f;
- pml.origin.y += trace.plane.normal.y * 0.01f;
- G_FixStuckObject_Generic(pml.origin, mins, maxs, trace_func);
- break;
- }
- }
- if (i < numplanes)
- continue;
- planes[numplanes] = trace.plane.normal;
- numplanes++;
- //
- // modify original_velocity so it parallels all of the clip planes
- //
- for (i = 0; i < numplanes; i++)
- {
- PM_ClipVelocity(velocity, planes[i], velocity, 1.01f);
- for (j = 0; j < numplanes; j++)
- if (j != i)
- {
- if (velocity.dot(planes[j]) < 0)
- break; // not ok
- }
- if (j == numplanes)
- break;
- }
- if (i != numplanes)
- { // go along this plane
- }
- else
- { // go along the crease
- if (numplanes != 2)
- {
- velocity = vec3_origin;
- break;
- }
- dir = planes[0].cross(planes[1]);
- d = dir.dot(velocity);
- velocity = dir * d;
- }
- //
- // if velocity is against the original velocity, stop dead
- // to avoid tiny oscillations in sloping corners
- //
- if (velocity.dot(primal_velocity) <= 0)
- {
- velocity = vec3_origin;
- break;
- }
- }
- if (has_time)
- {
- velocity = primal_velocity;
- }
- }
- inline void PM_StepSlideMove_()
- {
- PM_StepSlideMove_Generic(pml.origin, pml.velocity, pml.frametime, pm->mins, pm->maxs, pm->touch, pm->s.pm_time, PM_Trace_Auto);
- }
- /*
- ==================
- PM_StepSlideMove
- ==================
- */
- void PM_StepSlideMove()
- {
- vec3_t start_o, start_v;
- vec3_t down_o, down_v;
- trace_t trace;
- float down_dist, up_dist;
- // vec3_t delta;
- vec3_t up, down;
- start_o = pml.origin;
- start_v = pml.velocity;
- PM_StepSlideMove_();
- down_o = pml.origin;
- down_v = pml.velocity;
- up = start_o;
- up[2] += STEPSIZE;
- trace = PM_Trace(start_o, pm->mins, pm->maxs, up);
- if (trace.allsolid)
- return; // can't step up
- float stepSize = trace.endpos[2] - start_o[2];
- // try sliding above
- pml.origin = trace.endpos;
- pml.velocity = start_v;
- PM_StepSlideMove_();
- // push down the final amount
- down = pml.origin;
- down[2] -= stepSize;
- // [Paril-KEX] jitspoe suggestion for stair clip fix; store
- // the old down position, and pick a better spot for downwards
- // trace if the start origin's Z position is lower than the down end pt.
- vec3_t original_down = down;
- if (start_o[2] < down[2])
- down[2] = start_o[2] - 1.f;
- trace = PM_Trace(pml.origin, pm->mins, pm->maxs, down);
- if (!trace.allsolid)
- {
- // [Paril-KEX] from above, do the proper trace now
- trace_t real_trace = PM_Trace(pml.origin, pm->mins, pm->maxs, original_down);
- pml.origin = real_trace.endpos;
- // only an upwards jump is a stair clip
- if (pml.velocity.z > 0.f)
- {
- pm->step_clip = true;
- }
- }
- up = pml.origin;
- // decide which one went farther
- down_dist = (down_o[0] - start_o[0]) * (down_o[0] - start_o[0]) + (down_o[1] - start_o[1]) * (down_o[1] - start_o[1]);
- up_dist = (up[0] - start_o[0]) * (up[0] - start_o[0]) + (up[1] - start_o[1]) * (up[1] - start_o[1]);
- if (down_dist > up_dist || trace.plane.normal[2] < MIN_STEP_NORMAL)
- {
- pml.origin = down_o;
- pml.velocity = down_v;
- }
- // [Paril-KEX] NB: this line being commented is crucial for ramp-jumps to work.
- // thanks to Jitspoe for pointing this one out.
- else// if (pm->s.pm_flags & PMF_ON_GROUND)
- //!! Special case
- // if we were walking along a plane, then we need to copy the Z over
- pml.velocity[2] = down_v[2];
- // Paril: step down stairs/slopes
- if ((pm->s.pm_flags & PMF_ON_GROUND) && !(pm->s.pm_flags & PMF_ON_LADDER) &&
- (pm->waterlevel < WATER_WAIST || (!(pm->cmd.buttons & BUTTON_JUMP) && pml.velocity.z <= 0)))
- {
- down = pml.origin;
- down[2] -= STEPSIZE;
- trace = PM_Trace(pml.origin, pm->mins, pm->maxs, down);
- if (trace.fraction < 1.f)
- {
- pml.origin = trace.endpos;
- }
- }
- }
- /*
- ==================
- PM_Friction
- Handles both ground friction and water friction
- ==================
- */
- void PM_Friction()
- {
- float *vel;
- float speed, newspeed, control;
- float friction;
- float drop;
- vel = &pml.velocity.x;
- speed = sqrt(vel[0] * vel[0] + vel[1] * vel[1] + vel[2] * vel[2]);
- if (speed < 1)
- {
- vel[0] = 0;
- vel[1] = 0;
- return;
- }
- drop = 0;
- // apply ground friction
- if ((pm->groundentity && pml.groundsurface && !(pml.groundsurface->flags & SURF_SLICK)) || (pm->s.pm_flags & PMF_ON_LADDER))
- {
- friction = pm_friction;
- control = speed < pm_stopspeed ? pm_stopspeed : speed;
- drop += control * friction * pml.frametime;
- }
- // apply water friction
- if (pm->waterlevel && !(pm->s.pm_flags & PMF_ON_LADDER))
- drop += speed * pm_waterfriction * (float) pm->waterlevel * pml.frametime;
- // scale the velocity
- newspeed = speed - drop;
- if (newspeed < 0)
- {
- newspeed = 0;
- }
- newspeed /= speed;
- vel[0] = vel[0] * newspeed;
- vel[1] = vel[1] * newspeed;
- vel[2] = vel[2] * newspeed;
- }
- /*
- ==============
- PM_Accelerate
- Handles user intended acceleration
- ==============
- */
- void PM_Accelerate(const vec3_t &wishdir, float wishspeed, float accel)
- {
- int i;
- float addspeed, accelspeed, currentspeed;
- currentspeed = pml.velocity.dot(wishdir);
- addspeed = wishspeed - currentspeed;
- if (addspeed <= 0)
- return;
- accelspeed = accel * pml.frametime * wishspeed;
- if (accelspeed > addspeed)
- accelspeed = addspeed;
- for (i = 0; i < 3; i++)
- pml.velocity[i] += accelspeed * wishdir[i];
- }
- void PM_AirAccelerate(const vec3_t &wishdir, float wishspeed, float accel)
- {
- int i;
- float addspeed, accelspeed, currentspeed, wishspd = wishspeed;
- if (wishspd > 30)
- wishspd = 30;
- currentspeed = pml.velocity.dot(wishdir);
- addspeed = wishspd - currentspeed;
- if (addspeed <= 0)
- return;
- accelspeed = accel * wishspeed * pml.frametime;
- if (accelspeed > addspeed)
- accelspeed = addspeed;
- for (i = 0; i < 3; i++)
- pml.velocity[i] += accelspeed * wishdir[i];
- }
- /*
- =============
- PM_AddCurrents
- =============
- */
- void PM_AddCurrents(vec3_t &wishvel)
- {
- vec3_t v;
- float s;
- //
- // account for ladders
- //
- if (pm->s.pm_flags & PMF_ON_LADDER)
- {
- if (pm->cmd.buttons & (BUTTON_JUMP | BUTTON_CROUCH))
- {
- // [Paril-KEX]: if we're underwater, use full speed on ladders
- float ladder_speed = pm->waterlevel >= WATER_WAIST ? pm_maxspeed : 200;
-
- if (pm->cmd.buttons & BUTTON_JUMP)
- wishvel[2] = ladder_speed;
- else if (pm->cmd.buttons & BUTTON_CROUCH)
- wishvel[2] = -ladder_speed;
- }
- else if (pm->cmd.forwardmove)
- {
- // [Paril-KEX] clamp the speed a bit so we're not too fast
- float ladder_speed = std::clamp(pm->cmd.forwardmove, -200.f, 200.f);
- if (pm->cmd.forwardmove > 0)
- {
- if (pm->viewangles[PITCH] < 15)
- wishvel[2] = ladder_speed;
- else
- wishvel[2] = -ladder_speed;
- }
- // [Paril-KEX] allow using "back" arrow to go down on ladder
- else if (pm->cmd.forwardmove < 0)
- {
- // if we haven't touched ground yet, remove x/y so we don't
- // slide off of the ladder
- if (!pm->groundentity)
- wishvel[0] = wishvel[1] = 0;
- wishvel[2] = ladder_speed;
- }
- }
- else
- wishvel[2] = 0;
- // limit horizontal speed when on a ladder
- // [Paril-KEX] unless we're on the ground
- if (!pm->groundentity)
- {
- // [Paril-KEX] instead of left/right not doing anything,
- // have them move you perpendicular to the ladder plane
- if (pm->cmd.sidemove)
- {
- // clamp side speed so it's not jarring...
- float ladder_speed = std::clamp(pm->cmd.sidemove, -150.f, 150.f);
- if (pm->waterlevel < WATER_WAIST)
- ladder_speed *= pm_laddermod;
- // check for ladder
- vec3_t flatforward, spot;
- flatforward[0] = pml.forward[0];
- flatforward[1] = pml.forward[1];
- flatforward[2] = 0;
- flatforward.normalize();
- spot = pml.origin + (flatforward * 1);
- trace_t trace = PM_Trace(pml.origin, pm->mins, pm->maxs, spot, CONTENTS_LADDER);
- if (trace.fraction != 1.f && (trace.contents & CONTENTS_LADDER))
- {
- vec3_t right = trace.plane.normal.cross({ 0, 0, 1 });
- wishvel[0] = wishvel[1] = 0;
- wishvel += (right * -ladder_speed);
- }
- }
- else
- {
- if (wishvel[0] < -25)
- wishvel[0] = -25;
- else if (wishvel[0] > 25)
- wishvel[0] = 25;
- if (wishvel[1] < -25)
- wishvel[1] = -25;
- else if (wishvel[1] > 25)
- wishvel[1] = 25;
- }
- }
- }
- //
- // add water currents
- //
- if (pm->watertype & MASK_CURRENT)
- {
- v = {};
- if (pm->watertype & CONTENTS_CURRENT_0)
- v[0] += 1;
- if (pm->watertype & CONTENTS_CURRENT_90)
- v[1] += 1;
- if (pm->watertype & CONTENTS_CURRENT_180)
- v[0] -= 1;
- if (pm->watertype & CONTENTS_CURRENT_270)
- v[1] -= 1;
- if (pm->watertype & CONTENTS_CURRENT_UP)
- v[2] += 1;
- if (pm->watertype & CONTENTS_CURRENT_DOWN)
- v[2] -= 1;
- s = pm_waterspeed;
- if ((pm->waterlevel == WATER_FEET) && (pm->groundentity))
- s /= 2;
- wishvel += (v * s);
- }
- //
- // add conveyor belt velocities
- //
- if (pm->groundentity)
- {
- v = {};
- if (pml.groundcontents & CONTENTS_CURRENT_0)
- v[0] += 1;
- if (pml.groundcontents & CONTENTS_CURRENT_90)
- v[1] += 1;
- if (pml.groundcontents & CONTENTS_CURRENT_180)
- v[0] -= 1;
- if (pml.groundcontents & CONTENTS_CURRENT_270)
- v[1] -= 1;
- if (pml.groundcontents & CONTENTS_CURRENT_UP)
- v[2] += 1;
- if (pml.groundcontents & CONTENTS_CURRENT_DOWN)
- v[2] -= 1;
- wishvel += v * 100;
- }
- }
- /*
- ===================
- PM_WaterMove
- ===================
- */
- void PM_WaterMove()
- {
- int i;
- vec3_t wishvel;
- float wishspeed;
- vec3_t wishdir;
- //
- // user intentions
- //
- for (i = 0; i < 3; i++)
- wishvel[i] = pml.forward[i] * pm->cmd.forwardmove + pml.right[i] * pm->cmd.sidemove;
- if (!pm->cmd.forwardmove && !pm->cmd.sidemove &&
- !(pm->cmd.buttons & (BUTTON_JUMP | BUTTON_CROUCH)))
- {
- if (!pm->groundentity)
- wishvel[2] -= 60; // drift towards bottom
- }
- else
- {
- if (pm->cmd.buttons & BUTTON_CROUCH)
- wishvel[2] -= pm_waterspeed * 0.5f;
- else if (pm->cmd.buttons & BUTTON_JUMP)
- wishvel[2] += pm_waterspeed * 0.5f;
- }
- PM_AddCurrents(wishvel);
- wishdir = wishvel;
- wishspeed = wishdir.normalize();
- if (wishspeed > pm_maxspeed)
- {
- wishvel *= pm_maxspeed / wishspeed;
- wishspeed = pm_maxspeed;
- }
- wishspeed *= 0.5f;
- if ((pm->s.pm_flags & PMF_DUCKED) && wishspeed > pm_duckspeed)
- {
- wishvel *= pm_duckspeed / wishspeed;
- wishspeed = pm_duckspeed;
- }
- PM_Accelerate(wishdir, wishspeed, pm_wateraccelerate);
- PM_StepSlideMove();
- }
- /*
- ===================
- PM_AirMove
- ===================
- */
- void PM_AirMove()
- {
- int i;
- vec3_t wishvel;
- float fmove, smove;
- vec3_t wishdir;
- float wishspeed;
- float maxspeed;
- fmove = pm->cmd.forwardmove;
- smove = pm->cmd.sidemove;
- for (i = 0; i < 2; i++)
- wishvel[i] = pml.forward[i] * fmove + pml.right[i] * smove;
- wishvel[2] = 0;
- PM_AddCurrents(wishvel);
- wishdir = wishvel;
- wishspeed = wishdir.normalize();
- //
- // clamp to server defined max speed
- //
- maxspeed = (pm->s.pm_flags & PMF_DUCKED) ? pm_duckspeed : pm_maxspeed;
- if (wishspeed > maxspeed)
- {
- wishvel *= maxspeed / wishspeed;
- wishspeed = maxspeed;
- }
- if (pm->s.pm_flags & PMF_ON_LADDER)
- {
- PM_Accelerate(wishdir, wishspeed, pm_accelerate);
- if (!wishvel[2])
- {
- if (pml.velocity[2] > 0)
- {
- pml.velocity[2] -= pm->s.gravity * pml.frametime;
- if (pml.velocity[2] < 0)
- pml.velocity[2] = 0;
- }
- else
- {
- pml.velocity[2] += pm->s.gravity * pml.frametime;
- if (pml.velocity[2] > 0)
- pml.velocity[2] = 0;
- }
- }
- PM_StepSlideMove();
- }
- else if (pm->groundentity)
- { // walking on ground
- pml.velocity[2] = 0; //!!! this is before the accel
- PM_Accelerate(wishdir, wishspeed, pm_accelerate);
- // PGM -- fix for negative trigger_gravity fields
- // pml.velocity[2] = 0;
- if (pm->s.gravity > 0)
- pml.velocity[2] = 0;
- else
- pml.velocity[2] -= pm->s.gravity * pml.frametime;
- // PGM
- if (!pml.velocity[0] && !pml.velocity[1])
- return;
- PM_StepSlideMove();
- }
- else
- { // not on ground, so little effect on velocity
- if (pm_config.airaccel)
- PM_AirAccelerate(wishdir, wishspeed, pm_config.airaccel);
- else
- PM_Accelerate(wishdir, wishspeed, 1);
- // add gravity
- if (pm->s.pm_type != PM_GRAPPLE)
- pml.velocity[2] -= pm->s.gravity * pml.frametime;
- PM_StepSlideMove();
- }
- }
- inline void PM_GetWaterLevel(const vec3_t &position, water_level_t &level, contents_t &type)
- {
- //
- // get waterlevel, accounting for ducking
- //
- level = WATER_NONE;
- type = CONTENTS_NONE;
- int32_t sample2 = (int) (pm->s.viewheight - pm->mins[2]);
- int32_t sample1 = sample2 / 2;
- vec3_t point = position;
- point[2] += pm->mins[2] + 1;
- contents_t cont = pm->pointcontents(point);
- if (cont & MASK_WATER)
- {
- type = cont;
- level = WATER_FEET;
- point[2] = pml.origin[2] + pm->mins[2] + sample1;
- cont = pm->pointcontents(point);
- if (cont & MASK_WATER)
- {
- level = WATER_WAIST;
- point[2] = pml.origin[2] + pm->mins[2] + sample2;
- cont = pm->pointcontents(point);
- if (cont & MASK_WATER)
- level = WATER_UNDER;
- }
- }
- }
- /*
- =============
- PM_CatagorizePosition
- =============
- */
- void PM_CatagorizePosition()
- {
- vec3_t point;
- trace_t trace;
- // if the player hull point one unit down is solid, the player
- // is on ground
- // see if standing on something solid
- point[0] = pml.origin[0];
- point[1] = pml.origin[1];
- point[2] = pml.origin[2] - 0.25f;
- if (pml.velocity[2] > 180 || pm->s.pm_type == PM_GRAPPLE) //!!ZOID changed from 100 to 180 (ramp accel)
- {
- pm->s.pm_flags &= ~PMF_ON_GROUND;
- pm->groundentity = nullptr;
- }
- else
- {
- trace = PM_Trace(pml.origin, pm->mins, pm->maxs, point);
- pm->groundplane = trace.plane;
- pml.groundsurface = trace.surface;
- pml.groundcontents = trace.contents;
- // [Paril-KEX] to attempt to fix edge cases where you get stuck
- // wedged between a slope and a wall (which is irrecoverable
- // most of the time), we'll allow the player to "stand" on
- // slopes if they are right up against a wall
- bool slanted_ground = trace.fraction < 1.0f && trace.plane.normal[2] < 0.7f;
- if (slanted_ground)
- {
- trace_t slant = PM_Trace(pml.origin, pm->mins, pm->maxs, pml.origin + trace.plane.normal);
- if (slant.fraction < 1.0f && !slant.startsolid)
- slanted_ground = false;
- }
- if (trace.fraction == 1.0f || (slanted_ground && !trace.startsolid))
- {
- pm->groundentity = nullptr;
- pm->s.pm_flags &= ~PMF_ON_GROUND;
- }
- else
- {
- pm->groundentity = trace.ent;
- // hitting solid ground will end a waterjump
- if (pm->s.pm_flags & PMF_TIME_WATERJUMP)
- {
- pm->s.pm_flags &= ~(PMF_TIME_WATERJUMP | PMF_TIME_LAND | PMF_TIME_TELEPORT | PMF_TIME_TRICK);
- pm->s.pm_time = 0;
- }
- if (!(pm->s.pm_flags & PMF_ON_GROUND))
- {
- // just hit the ground
- // [Paril-KEX]
- if (!pm_config.n64_physics && pml.velocity[2] >= 100.f && pm->groundplane.normal[2] >= 0.9f && !(pm->s.pm_flags & PMF_DUCKED))
- {
- pm->s.pm_flags |= PMF_TIME_TRICK;
- pm->s.pm_time = 64;
- }
- // [Paril-KEX] calculate impact delta; this also fixes triple jumping
- vec3_t clipped_velocity;
- PM_ClipVelocity(pml.velocity, pm->groundplane.normal, clipped_velocity, 1.01f);
- pm->impact_delta = pml.start_velocity[2] - clipped_velocity[2];
- pm->s.pm_flags |= PMF_ON_GROUND;
- if (pm_config.n64_physics || (pm->s.pm_flags & PMF_DUCKED))
- {
- pm->s.pm_flags |= PMF_TIME_LAND;
- pm->s.pm_time = 128;
- }
- }
- }
- PM_RecordTrace(pm->touch, trace);
- }
- //
- // get waterlevel, accounting for ducking
- //
- PM_GetWaterLevel(pml.origin, pm->waterlevel, pm->watertype);
- }
- /*
- =============
- PM_CheckJump
- =============
- */
- void PM_CheckJump()
- {
- if (pm->s.pm_flags & PMF_TIME_LAND)
- { // hasn't been long enough since landing to jump again
- return;
- }
-
- if (!(pm->cmd.buttons & BUTTON_JUMP))
- { // not holding jump
- pm->s.pm_flags &= ~PMF_JUMP_HELD;
- return;
- }
- // must wait for jump to be released
- if (pm->s.pm_flags & PMF_JUMP_HELD)
- return;
- if (pm->s.pm_type == PM_DEAD)
- return;
- if (pm->waterlevel >= WATER_WAIST)
- { // swimming, not jumping
- pm->groundentity = nullptr;
- return;
- }
- if (pm->groundentity == nullptr)
- return; // in air, so no effect
- pm->s.pm_flags |= PMF_JUMP_HELD;
- pm->jump_sound = true;
- pm->groundentity = nullptr;
- pm->s.pm_flags &= ~PMF_ON_GROUND;
- float jump_height = 270.f;
- pml.velocity[2] += jump_height;
- if (pml.velocity[2] < jump_height)
- pml.velocity[2] = jump_height;
- }
- /*
- =============
- PM_CheckSpecialMovement
- =============
- */
- void PM_CheckSpecialMovement()
- {
- vec3_t spot;
- vec3_t flatforward;
- trace_t trace;
- if (pm->s.pm_time)
- return;
- pm->s.pm_flags &= ~PMF_ON_LADDER;
- // check for ladder
- flatforward[0] = pml.forward[0];
- flatforward[1] = pml.forward[1];
- flatforward[2] = 0;
- flatforward.normalize();
- spot = pml.origin + (flatforward * 1);
- trace = PM_Trace(pml.origin, pm->mins, pm->maxs, spot, CONTENTS_LADDER);
- if ((trace.fraction < 1) && (trace.contents & CONTENTS_LADDER) && pm->waterlevel < WATER_WAIST)
- pm->s.pm_flags |= PMF_ON_LADDER;
- if (!pm->s.gravity)
- return;
- // check for water jump
- // [Paril-KEX] don't try waterjump if we're moving against where we'll hop
- if (!(pm->cmd.buttons & BUTTON_JUMP)
- && pm->cmd.forwardmove <= 0)
- return;
- if (pm->waterlevel != WATER_WAIST)
- return;
- // [Paril-KEX]
- else if (pm->watertype & CONTENTS_NO_WATERJUMP)
- return;
- // quick check that something is even blocking us forward
- trace = PM_Trace(pml.origin, pm->mins, pm->maxs, pml.origin + (flatforward * 40), MASK_SOLID);
- // we aren't blocked, or what we're blocked by is something we can walk up
- if (trace.fraction == 1.0f || trace.plane.normal.z >= 0.7f)
- return;
- // [Paril-KEX] improved waterjump
- vec3_t waterjump_vel = flatforward * 50;
- waterjump_vel.z = 350;
- // simulate what would happen if we jumped out here, and
- // if we land on a dry spot we're good!
- // simulate 1 sec worth of movement
- touch_list_t touches;
- vec3_t waterjump_origin = pml.origin;
- float time = 0.1f;
- bool has_time = true;
- for (size_t i = 0; i < min(50, (int32_t) (10 * (800.f / pm->s.gravity))); i++)
- {
- waterjump_vel[2] -= pm->s.gravity * time;
- if (waterjump_vel[2] < 0)
- has_time = false;
- PM_StepSlideMove_Generic(waterjump_origin, waterjump_vel, time, pm->mins, pm->maxs, touches, has_time, PM_Trace_Auto);
- }
- // snap down to ground
- trace = PM_Trace(waterjump_origin, pm->mins, pm->maxs, waterjump_origin - vec3_t { 0, 0, 2.f }, MASK_SOLID);
- // can't stand here
- if (trace.fraction == 1.0f || trace.plane.normal.z < 0.7f ||
- trace.endpos.z < pml.origin.z)
- return;
- // we're currently standing on ground, and the snapped position
- // is a step
- if (pm->groundentity && fabsf(pml.origin.z - trace.endpos.z) <= STEPSIZE)
- return;
- water_level_t level;
- contents_t type;
- PM_GetWaterLevel(trace.endpos, level, type);
- // the water jump spot will be under water, so we're
- // probably hitting something weird that isn't important
- if (level >= WATER_WAIST)
- return;
- // valid waterjump!
- // jump out of water
- pml.velocity = flatforward * 50;
- pml.velocity[2] = 350;
- pm->s.pm_flags |= PMF_TIME_WATERJUMP;
- pm->s.pm_time = 2048;
- }
- /*
- ===============
- PM_FlyMove
- ===============
- */
- void PM_FlyMove(bool doclip)
- {
- float speed, drop, friction, control, newspeed;
- float currentspeed, addspeed, accelspeed;
- int i;
- vec3_t wishvel;
- float fmove, smove;
- vec3_t wishdir;
- float wishspeed;
- pm->s.viewheight = doclip ? 0 : 22;
- // friction
- speed = pml.velocity.length();
- if (speed < 1)
- {
- pml.velocity = vec3_origin;
- }
- else
- {
- drop = 0;
- friction = pm_friction * 1.5f; // extra friction
- control = speed < pm_stopspeed ? pm_stopspeed : speed;
- drop += control * friction * pml.frametime;
- // scale the velocity
- newspeed = speed - drop;
- if (newspeed < 0)
- newspeed = 0;
- newspeed /= speed;
- pml.velocity *= newspeed;
- }
- // accelerate
- fmove = pm->cmd.forwardmove;
- smove = pm->cmd.sidemove;
- pml.forward.normalize();
- pml.right.normalize();
- for (i = 0; i < 3; i++)
- wishvel[i] = pml.forward[i] * fmove + pml.right[i] * smove;
- if (pm->cmd.buttons & BUTTON_JUMP)
- wishvel[2] += (pm_waterspeed * 0.5f);
- if (pm->cmd.buttons & BUTTON_CROUCH)
- wishvel[2] -= (pm_waterspeed * 0.5f);
- wishdir = wishvel;
- wishspeed = wishdir.normalize();
- //
- // clamp to server defined max speed
- //
- if (wishspeed > pm_maxspeed)
- {
- wishvel *= pm_maxspeed / wishspeed;
- wishspeed = pm_maxspeed;
- }
- // Paril: newer clients do this
- wishspeed *= 2;
- currentspeed = pml.velocity.dot(wishdir);
- addspeed = wishspeed - currentspeed;
- if (addspeed > 0)
- {
- accelspeed = pm_accelerate * pml.frametime * wishspeed;
- if (accelspeed > addspeed)
- accelspeed = addspeed;
- for (i = 0; i < 3; i++)
- pml.velocity[i] += accelspeed * wishdir[i];
- }
- if (doclip)
- {
- /*for (i = 0; i < 3; i++)
- end[i] = pml.origin[i] + pml.frametime * pml.velocity[i];
- trace = PM_Trace(pml.origin, pm->mins, pm->maxs, end);
- pml.origin = trace.endpos;*/
- PM_StepSlideMove();
- }
- else
- {
- // move
- pml.origin += (pml.velocity * pml.frametime);
- }
- }
- void PM_SetDimensions()
- {
- pm->mins[0] = -16;
- pm->mins[1] = -16;
- pm->maxs[0] = 16;
- pm->maxs[1] = 16;
- if (pm->s.pm_type == PM_GIB)
- {
- pm->mins[2] = 0;
- pm->maxs[2] = 16;
- pm->s.viewheight = 8;
- return;
- }
- pm->mins[2] = -24;
- if ((pm->s.pm_flags & PMF_DUCKED) || pm->s.pm_type == PM_DEAD)
- {
- pm->maxs[2] = 4;
- pm->s.viewheight = -2;
- }
- else
- {
- pm->maxs[2] = 32;
- pm->s.viewheight = 22;
- }
- }
- inline bool PM_AboveWater()
- {
- const vec3_t below = pml.origin - vec3_t{ 0, 0, 8 };
- bool solid_below = pm->trace(pml.origin, &pm->mins, &pm->maxs, below, pm->player, MASK_SOLID).fraction < 1.0f;
- if (solid_below)
- return false;
- bool water_below = pm->trace(pml.origin, &pm->mins, &pm->maxs, below, pm->player, MASK_WATER).fraction < 1.0f;
- if (water_below)
- return true;
- return false;
- }
- /*
- ==============
- PM_CheckDuck
- Sets mins, maxs, and pm->viewheight
- ==============
- */
- bool PM_CheckDuck()
- {
- if (pm->s.pm_type == PM_GIB)
- return false;
- trace_t trace;
- bool flags_changed = false;
- if (pm->s.pm_type == PM_DEAD)
- {
- if (!(pm->s.pm_flags & PMF_DUCKED))
- {
- pm->s.pm_flags |= PMF_DUCKED;
- flags_changed = true;
- }
- }
- else if (
- (pm->cmd.buttons & BUTTON_CROUCH) &&
- (pm->groundentity || (pm->waterlevel <= WATER_FEET && !PM_AboveWater())) &&
- !(pm->s.pm_flags & PMF_ON_LADDER) &&
- !pm_config.n64_physics)
- { // duck
- if (!(pm->s.pm_flags & PMF_DUCKED))
- {
- // check that duck won't be blocked
- vec3_t check_maxs = { pm->maxs[0], pm->maxs[1], 4 };
- trace = PM_Trace(pml.origin, pm->mins, check_maxs, pml.origin);
- if (!trace.allsolid)
- {
- pm->s.pm_flags |= PMF_DUCKED;
- flags_changed = true;
- }
- }
- }
- else
- { // stand up if possible
- if (pm->s.pm_flags & PMF_DUCKED)
- {
- // try to stand up
- vec3_t check_maxs = { pm->maxs[0], pm->maxs[1], 32 };
- trace = PM_Trace(pml.origin, pm->mins, check_maxs, pml.origin);
- if (!trace.allsolid)
- {
- pm->s.pm_flags &= ~PMF_DUCKED;
- flags_changed = true;
- }
- }
- }
- if (!flags_changed)
- return false;
- PM_SetDimensions();
- return true;
- }
- /*
- ==============
- PM_DeadMove
- ==============
- */
- void PM_DeadMove()
- {
- float forward;
- if (!pm->groundentity)
- return;
- // extra friction
- forward = pml.velocity.length();
- forward -= 20;
- if (forward <= 0)
- {
- pml.velocity = {};
- }
- else
- {
- pml.velocity.normalize();
- pml.velocity *= forward;
- }
- }
- bool PM_GoodPosition()
- {
- if (pm->s.pm_type == PM_NOCLIP)
- return true;
- trace_t trace = PM_Trace(pm->s.origin, pm->mins, pm->maxs, pm->s.origin);
- return !trace.allsolid;
- }
- /*
- ================
- PM_SnapPosition
- On exit, the origin will have a value that is pre-quantized to the PMove
- precision of the network channel and in a valid position.
- ================
- */
- void PM_SnapPosition()
- {
- pm->s.velocity = pml.velocity;
- pm->s.origin = pml.origin;
- if (PM_GoodPosition())
- return;
- if (G_FixStuckObject_Generic(pm->s.origin, pm->mins, pm->maxs, PM_Trace_Auto) == stuck_result_t::NO_GOOD_POSITION) {
- pm->s.origin = pml.previous_origin;
- return;
- }
- }
- /*
- ================
- PM_InitialSnapPosition
- ================
- */
- void PM_InitialSnapPosition()
- {
- int x, y, z;
- vec3_t base;
- constexpr int offset[3] = { 0, -1, 1 };
- base = pm->s.origin;
- for (z = 0; z < 3; z++)
- {
- pm->s.origin[2] = base[2] + offset[z];
- for (y = 0; y < 3; y++)
- {
- pm->s.origin[1] = base[1] + offset[y];
- for (x = 0; x < 3; x++)
- {
- pm->s.origin[0] = base[0] + offset[x];
- if (PM_GoodPosition())
- {
- pml.origin = pm->s.origin;
- pml.previous_origin = pm->s.origin;
- return;
- }
- }
- }
- }
- }
- /*
- ================
- PM_ClampAngles
- ================
- */
- void PM_ClampAngles()
- {
- if (pm->s.pm_flags & PMF_TIME_TELEPORT)
- {
- pm->viewangles[YAW] = pm->cmd.angles[YAW] + pm->s.delta_angles[YAW];
- pm->viewangles[PITCH] = 0;
- pm->viewangles[ROLL] = 0;
- }
- else
- {
- // circularly clamp the angles with deltas
- pm->viewangles = pm->cmd.angles + pm->s.delta_angles;
- // don't let the player look up or down more than 90 degrees
- if (pm->viewangles[PITCH] > 89 && pm->viewangles[PITCH] < 180)
- pm->viewangles[PITCH] = 89;
- else if (pm->viewangles[PITCH] < 271 && pm->viewangles[PITCH] >= 180)
- pm->viewangles[PITCH] = 271;
- }
- AngleVectors(pm->viewangles, pml.forward, pml.right, pml.up);
- }
- // [Paril-KEX]
- static void PM_ScreenEffects()
- {
- // add for contents
- vec3_t vieworg = pml.origin + pm->viewoffset + vec3_t{ 0, 0, (float) pm->s.viewheight };
- contents_t contents = pm->pointcontents(vieworg);
- if (contents & (CONTENTS_LAVA | CONTENTS_SLIME | CONTENTS_WATER))
- pm->rdflags |= RDF_UNDERWATER;
- else
- pm->rdflags &= ~RDF_UNDERWATER;
- if (contents & (CONTENTS_SOLID | CONTENTS_LAVA))
- G_AddBlend(1.0f, 0.3f, 0.0f, 0.6f, pm->screen_blend);
- else if (contents & CONTENTS_SLIME)
- G_AddBlend(0.0f, 0.1f, 0.05f, 0.6f, pm->screen_blend);
- else if (contents & CONTENTS_WATER)
- G_AddBlend(0.5f, 0.3f, 0.2f, 0.4f, pm->screen_blend);
- }
- /*
- ================
- Pmove
- Can be called by either the server or the client
- ================
- */
- void Pmove(pmove_t *pmove)
- {
- pm = pmove;
- // clear results
- pm->touch.num = 0;
- pm->viewangles = {};
- pm->s.viewheight = 0;
- pm->groundentity = nullptr;
- pm->watertype = CONTENTS_NONE;
- pm->waterlevel = WATER_NONE;
- pm->screen_blend = {};
- pm->rdflags = RDF_NONE;
- pm->jump_sound = false;
- pm->step_clip = false;
- pm->impact_delta = 0;
- // clear all pmove local vars
- pml = {};
- // convert origin and velocity to float values
- pml.origin = pm->s.origin;
- pml.velocity = pm->s.velocity;
- pml.start_velocity = pml.velocity;
- // save old org in case we get stuck
- pml.previous_origin = pm->s.origin;
- pml.frametime = pm->cmd.msec * 0.001f;
- PM_ClampAngles();
- if (pm->s.pm_type == PM_SPECTATOR || pm->s.pm_type == PM_NOCLIP)
- {
- pm->s.pm_flags = PMF_NONE;
- if (pm->s.pm_type == PM_SPECTATOR)
- {
- pm->mins[0] = -8;
- pm->mins[1] = -8;
- pm->maxs[0] = 8;
- pm->maxs[1] = 8;
- pm->mins[2] = -8;
- pm->maxs[2] = 8;
- }
- PM_FlyMove(pm->s.pm_type == PM_SPECTATOR);
- PM_SnapPosition();
- return;
- }
- if (pm->s.pm_type >= PM_DEAD)
- {
- pm->cmd.forwardmove = 0;
- pm->cmd.sidemove = 0;
- pm->cmd.buttons &= ~(BUTTON_JUMP | BUTTON_CROUCH);
- }
- if (pm->s.pm_type == PM_FREEZE)
- return; // no movement at all
- // set mins, maxs, and viewheight
- PM_SetDimensions();
- // catagorize for ducking
- PM_CatagorizePosition();
- if (pm->snapinitial)
- PM_InitialSnapPosition();
- // set groundentity, watertype, and waterlevel
- if (PM_CheckDuck())
- PM_CatagorizePosition();
- if (pm->s.pm_type == PM_DEAD)
- PM_DeadMove();
- PM_CheckSpecialMovement();
- // drop timing counter
- if (pm->s.pm_time)
- {
- if (pm->cmd.msec >= pm->s.pm_time)
- {
- pm->s.pm_flags &= ~(PMF_TIME_WATERJUMP | PMF_TIME_LAND | PMF_TIME_TELEPORT | PMF_TIME_TRICK);
- pm->s.pm_time = 0;
- }
- else
- pm->s.pm_time -= pm->cmd.msec;
- }
- if (pm->s.pm_flags & PMF_TIME_TELEPORT)
- { // teleport pause stays exactly in place
- }
- else if (pm->s.pm_flags & PMF_TIME_WATERJUMP)
- { // waterjump has no control, but falls
- pml.velocity[2] -= pm->s.gravity * pml.frametime;
- if (pml.velocity[2] < 0)
- { // cancel as soon as we are falling down again
- pm->s.pm_flags &= ~(PMF_TIME_WATERJUMP | PMF_TIME_LAND | PMF_TIME_TELEPORT | PMF_TIME_TRICK);
- pm->s.pm_time = 0;
- }
- PM_StepSlideMove();
- }
- else
- {
- PM_CheckJump();
- PM_Friction();
- if (pm->waterlevel >= WATER_WAIST)
- PM_WaterMove();
- else
- {
- vec3_t angles;
- angles = pm->viewangles;
- if (angles[PITCH] > 180)
- angles[PITCH] = angles[PITCH] - 360;
- angles[PITCH] /= 3;
- AngleVectors(angles, pml.forward, pml.right, pml.up);
- PM_AirMove();
- }
- }
- // set groundentity, watertype, and waterlevel for final spot
- PM_CatagorizePosition();
- // trick jump
- if (pm->s.pm_flags & PMF_TIME_TRICK)
- PM_CheckJump();
- // [Paril-KEX]
- PM_ScreenEffects();
- PM_SnapPosition();
- }
|