p_move.cpp 37 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709
  1. // Copyright (c) ZeniMax Media Inc.
  2. // Licensed under the GNU General Public License 2.0.
  3. #include "q_std.h"
  4. #define GAME_INCLUDE
  5. #include "bg_local.h"
  6. // [Paril-KEX] generic code to detect & fix a stuck object
  7. 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)
  8. {
  9. if (!trace(origin, own_mins, own_maxs, origin).startsolid)
  10. return stuck_result_t::GOOD_POSITION;
  11. struct {
  12. float distance;
  13. vec3_t origin;
  14. } good_positions[6];
  15. size_t num_good_positions = 0;
  16. constexpr struct {
  17. std::array<int8_t, 3> normal;
  18. std::array<int8_t, 3> mins, maxs;
  19. } side_checks[] = {
  20. { { 0, 0, 1 }, { -1, -1, 0 }, { 1, 1, 0 } },
  21. { { 0, 0, -1 }, { -1, -1, 0 }, { 1, 1, 0 } },
  22. { { 1, 0, 0 }, { 0, -1, -1 }, { 0, 1, 1 } },
  23. { { -1, 0, 0 }, { 0, -1, -1 }, { 0, 1, 1 } },
  24. { { 0, 1, 0 }, { -1, 0, -1 }, { 1, 0, 1 } },
  25. { { 0, -1, 0 }, { -1, 0, -1 }, { 1, 0, 1 } },
  26. };
  27. for (size_t sn = 0; sn < q_countof(side_checks); sn++)
  28. {
  29. auto &side = side_checks[sn];
  30. vec3_t start = origin;
  31. vec3_t mins {}, maxs {};
  32. for (size_t n = 0; n < 3; n++)
  33. {
  34. if (side.normal[n] < 0)
  35. start[n] += own_mins[n];
  36. else if (side.normal[n] > 0)
  37. start[n] += own_maxs[n];
  38. if (side.mins[n] == -1)
  39. mins[n] = own_mins[n];
  40. else if (side.mins[n] == 1)
  41. mins[n] = own_maxs[n];
  42. if (side.maxs[n] == -1)
  43. maxs[n] = own_mins[n];
  44. else if (side.maxs[n] == 1)
  45. maxs[n] = own_maxs[n];
  46. }
  47. trace_t tr = trace(start, mins, maxs, start);
  48. int8_t needed_epsilon_fix = -1;
  49. int8_t needed_epsilon_dir;
  50. if (tr.startsolid)
  51. {
  52. for (size_t e = 0; e < 3; e++)
  53. {
  54. if (side.normal[e] != 0)
  55. continue;
  56. vec3_t ep_start = start;
  57. ep_start[e] += 1;
  58. tr = trace(ep_start, mins, maxs, ep_start);
  59. if (!tr.startsolid)
  60. {
  61. start = ep_start;
  62. needed_epsilon_fix = e;
  63. needed_epsilon_dir = 1;
  64. break;
  65. }
  66. ep_start[e] -= 2;
  67. tr = trace(ep_start, mins, maxs, ep_start);
  68. if (!tr.startsolid)
  69. {
  70. start = ep_start;
  71. needed_epsilon_fix = e;
  72. needed_epsilon_dir = -1;
  73. break;
  74. }
  75. }
  76. }
  77. // no good
  78. if (tr.startsolid)
  79. continue;
  80. vec3_t opposite_start = origin;
  81. auto &other_side = side_checks[sn ^ 1];
  82. for (size_t n = 0; n < 3; n++)
  83. {
  84. if (other_side.normal[n] < 0)
  85. opposite_start[n] += own_mins[n];
  86. else if (other_side.normal[n] > 0)
  87. opposite_start[n] += own_maxs[n];
  88. }
  89. if (needed_epsilon_fix >= 0)
  90. opposite_start[needed_epsilon_fix] += needed_epsilon_dir;
  91. // potentially a good side; start from our center, push back to the opposite side
  92. // to find how much clearance we have
  93. tr = trace(start, mins, maxs, opposite_start);
  94. // ???
  95. if (tr.startsolid)
  96. continue;
  97. // check the delta
  98. vec3_t end = tr.endpos;
  99. // push us very slightly away from the wall
  100. end += vec3_t{(float) side.normal[0], (float) side.normal[1], (float) side.normal[2]} * 0.125f;
  101. // calculate delta
  102. const vec3_t delta = end - opposite_start;
  103. vec3_t new_origin = origin + delta;
  104. if (needed_epsilon_fix >= 0)
  105. new_origin[needed_epsilon_fix] += needed_epsilon_dir;
  106. tr = trace(new_origin, own_mins, own_maxs, new_origin);
  107. // bad
  108. if (tr.startsolid)
  109. continue;
  110. good_positions[num_good_positions].origin = new_origin;
  111. good_positions[num_good_positions].distance = delta.lengthSquared();
  112. num_good_positions++;
  113. }
  114. if (num_good_positions)
  115. {
  116. std::sort(&good_positions[0], &good_positions[num_good_positions - 1], [](const auto &a, const auto &b) { return a.distance < b.distance; });
  117. origin = good_positions[0].origin;
  118. return stuck_result_t::FIXED;
  119. }
  120. return stuck_result_t::NO_GOOD_POSITION;
  121. }
  122. // all of the locals will be zeroed before each
  123. // pmove, just to make damn sure we don't have
  124. // any differences when running on client or server
  125. struct pml_t
  126. {
  127. vec3_t origin; // full float precision
  128. vec3_t velocity; // full float precision
  129. vec3_t forward, right, up;
  130. float frametime;
  131. csurface_t *groundsurface;
  132. int groundcontents;
  133. vec3_t previous_origin;
  134. vec3_t start_velocity;
  135. };
  136. pm_config_t pm_config;
  137. pmove_t *pm;
  138. pml_t pml;
  139. // movement parameters
  140. float pm_stopspeed = 100;
  141. float pm_maxspeed = 300;
  142. float pm_duckspeed = 100;
  143. float pm_accelerate = 10;
  144. float pm_wateraccelerate = 10;
  145. float pm_friction = 6;
  146. float pm_waterfriction = 1;
  147. float pm_waterspeed = 400;
  148. float pm_laddermod = 0.5f;
  149. /*
  150. walking up a step should kill some velocity
  151. */
  152. /*
  153. ==================
  154. PM_ClipVelocity
  155. Slide off of the impacting object
  156. returns the blocked flags (1 = floor, 2 = step / wall)
  157. ==================
  158. */
  159. void PM_ClipVelocity(const vec3_t &in, const vec3_t &normal, vec3_t &out, float overbounce)
  160. {
  161. float backoff;
  162. float change;
  163. int i;
  164. backoff = in.dot(normal) * overbounce;
  165. for (i = 0; i < 3; i++)
  166. {
  167. change = normal[i] * backoff;
  168. out[i] = in[i] - change;
  169. if (out[i] > -STOP_EPSILON && out[i] < STOP_EPSILON)
  170. out[i] = 0;
  171. }
  172. }
  173. trace_t PM_Clip(const vec3_t &start, const vec3_t &mins, const vec3_t &maxs, const vec3_t &end, contents_t mask)
  174. {
  175. return pm->clip(start, &mins, &maxs, end, mask);
  176. }
  177. 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)
  178. {
  179. if (pm->s.pm_type == PM_SPECTATOR)
  180. return PM_Clip(start, mins, maxs, end, MASK_SOLID);
  181. if (mask == CONTENTS_NONE)
  182. {
  183. if (pm->s.pm_type == PM_DEAD || pm->s.pm_type == PM_GIB)
  184. mask = MASK_DEADSOLID;
  185. else if (pm->s.pm_type == PM_SPECTATOR)
  186. mask = MASK_SOLID;
  187. else
  188. mask = MASK_PLAYERSOLID;
  189. if (pm->s.pm_flags & PMF_IGNORE_PLAYER_COLLISION)
  190. mask &= ~CONTENTS_PLAYER;
  191. }
  192. return pm->trace(start, &mins, &maxs, end, pm->player, mask);
  193. }
  194. // only here to satisfy pm_trace_t
  195. inline trace_t PM_Trace_Auto(const vec3_t &start, const vec3_t &mins, const vec3_t &maxs, const vec3_t &end)
  196. {
  197. return PM_Trace(start, mins, maxs, end);
  198. }
  199. /*
  200. ==================
  201. PM_StepSlideMove
  202. Each intersection will try to step over the obstruction instead of
  203. sliding along it.
  204. Returns a new origin, velocity, and contact entity
  205. Does not modify any world state?
  206. ==================
  207. */
  208. constexpr float MIN_STEP_NORMAL = 0.7f; // can't step up onto very steep slopes
  209. constexpr size_t MAX_CLIP_PLANES = 5;
  210. inline void PM_RecordTrace(touch_list_t &touch, trace_t &tr)
  211. {
  212. if (touch.num == MAXTOUCH)
  213. return;
  214. for (size_t i = 0; i < touch.num; i++)
  215. if (touch.traces[i].ent == tr.ent)
  216. return;
  217. touch.traces[touch.num++] = tr;
  218. }
  219. // [Paril-KEX] made generic so you can run this without
  220. // needing a pml/pm
  221. 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)
  222. {
  223. int bumpcount, numbumps;
  224. vec3_t dir;
  225. float d;
  226. int numplanes;
  227. vec3_t planes[MAX_CLIP_PLANES];
  228. vec3_t primal_velocity;
  229. int i, j;
  230. trace_t trace;
  231. vec3_t end;
  232. float time_left;
  233. numbumps = 4;
  234. primal_velocity = velocity;
  235. numplanes = 0;
  236. time_left = frametime;
  237. for (bumpcount = 0; bumpcount < numbumps; bumpcount++)
  238. {
  239. for (i = 0; i < 3; i++)
  240. end[i] = origin[i] + time_left * velocity[i];
  241. trace = trace_func(origin, mins, maxs, end);
  242. if (trace.allsolid)
  243. { // entity is trapped in another solid
  244. velocity[2] = 0; // don't build up falling damage
  245. // save entity for contact
  246. PM_RecordTrace(touch, trace);
  247. return;
  248. }
  249. // [Paril-KEX] experimental attempt to fix stray collisions on curved
  250. // surfaces; easiest to see on q2dm1 by running/jumping against the sides
  251. // of the curved map.
  252. if (trace.surface2)
  253. {
  254. vec3_t clipped_a, clipped_b;
  255. PM_ClipVelocity(velocity, trace.plane.normal, clipped_a, 1.01f);
  256. PM_ClipVelocity(velocity, trace.plane2.normal, clipped_b, 1.01f);
  257. bool better = false;
  258. for (int i = 0; i < 3; i++)
  259. {
  260. if (fabsf(clipped_a[i]) < fabsf(clipped_b[i]))
  261. {
  262. better = true;
  263. break;
  264. }
  265. }
  266. if (better)
  267. {
  268. trace.plane = trace.plane2;
  269. trace.surface = trace.surface2;
  270. }
  271. }
  272. if (trace.fraction > 0)
  273. { // actually covered some distance
  274. origin = trace.endpos;
  275. numplanes = 0;
  276. }
  277. if (trace.fraction == 1)
  278. break; // moved the entire distance
  279. // save entity for contact
  280. PM_RecordTrace(touch, trace);
  281. time_left -= time_left * trace.fraction;
  282. // slide along this plane
  283. if (numplanes >= MAX_CLIP_PLANES)
  284. { // this shouldn't really happen
  285. velocity = vec3_origin;
  286. break;
  287. }
  288. //
  289. // if this is the same plane we hit before, nudge origin
  290. // out along it, which fixes some epsilon issues with
  291. // non-axial planes (xswamp, q2dm1 sometimes...)
  292. //
  293. for (i = 0; i < numplanes; i++)
  294. {
  295. if (trace.plane.normal.dot(planes[i]) > 0.99f)
  296. {
  297. pml.origin.x += trace.plane.normal.x * 0.01f;
  298. pml.origin.y += trace.plane.normal.y * 0.01f;
  299. G_FixStuckObject_Generic(pml.origin, mins, maxs, trace_func);
  300. break;
  301. }
  302. }
  303. if (i < numplanes)
  304. continue;
  305. planes[numplanes] = trace.plane.normal;
  306. numplanes++;
  307. //
  308. // modify original_velocity so it parallels all of the clip planes
  309. //
  310. for (i = 0; i < numplanes; i++)
  311. {
  312. PM_ClipVelocity(velocity, planes[i], velocity, 1.01f);
  313. for (j = 0; j < numplanes; j++)
  314. if (j != i)
  315. {
  316. if (velocity.dot(planes[j]) < 0)
  317. break; // not ok
  318. }
  319. if (j == numplanes)
  320. break;
  321. }
  322. if (i != numplanes)
  323. { // go along this plane
  324. }
  325. else
  326. { // go along the crease
  327. if (numplanes != 2)
  328. {
  329. velocity = vec3_origin;
  330. break;
  331. }
  332. dir = planes[0].cross(planes[1]);
  333. d = dir.dot(velocity);
  334. velocity = dir * d;
  335. }
  336. //
  337. // if velocity is against the original velocity, stop dead
  338. // to avoid tiny oscillations in sloping corners
  339. //
  340. if (velocity.dot(primal_velocity) <= 0)
  341. {
  342. velocity = vec3_origin;
  343. break;
  344. }
  345. }
  346. if (has_time)
  347. {
  348. velocity = primal_velocity;
  349. }
  350. }
  351. inline void PM_StepSlideMove_()
  352. {
  353. PM_StepSlideMove_Generic(pml.origin, pml.velocity, pml.frametime, pm->mins, pm->maxs, pm->touch, pm->s.pm_time, PM_Trace_Auto);
  354. }
  355. /*
  356. ==================
  357. PM_StepSlideMove
  358. ==================
  359. */
  360. void PM_StepSlideMove()
  361. {
  362. vec3_t start_o, start_v;
  363. vec3_t down_o, down_v;
  364. trace_t trace;
  365. float down_dist, up_dist;
  366. // vec3_t delta;
  367. vec3_t up, down;
  368. start_o = pml.origin;
  369. start_v = pml.velocity;
  370. PM_StepSlideMove_();
  371. down_o = pml.origin;
  372. down_v = pml.velocity;
  373. up = start_o;
  374. up[2] += STEPSIZE;
  375. trace = PM_Trace(start_o, pm->mins, pm->maxs, up);
  376. if (trace.allsolid)
  377. return; // can't step up
  378. float stepSize = trace.endpos[2] - start_o[2];
  379. // try sliding above
  380. pml.origin = trace.endpos;
  381. pml.velocity = start_v;
  382. PM_StepSlideMove_();
  383. // push down the final amount
  384. down = pml.origin;
  385. down[2] -= stepSize;
  386. // [Paril-KEX] jitspoe suggestion for stair clip fix; store
  387. // the old down position, and pick a better spot for downwards
  388. // trace if the start origin's Z position is lower than the down end pt.
  389. vec3_t original_down = down;
  390. if (start_o[2] < down[2])
  391. down[2] = start_o[2] - 1.f;
  392. trace = PM_Trace(pml.origin, pm->mins, pm->maxs, down);
  393. if (!trace.allsolid)
  394. {
  395. // [Paril-KEX] from above, do the proper trace now
  396. trace_t real_trace = PM_Trace(pml.origin, pm->mins, pm->maxs, original_down);
  397. pml.origin = real_trace.endpos;
  398. // only an upwards jump is a stair clip
  399. if (pml.velocity.z > 0.f)
  400. {
  401. pm->step_clip = true;
  402. }
  403. }
  404. up = pml.origin;
  405. // decide which one went farther
  406. 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]);
  407. up_dist = (up[0] - start_o[0]) * (up[0] - start_o[0]) + (up[1] - start_o[1]) * (up[1] - start_o[1]);
  408. if (down_dist > up_dist || trace.plane.normal[2] < MIN_STEP_NORMAL)
  409. {
  410. pml.origin = down_o;
  411. pml.velocity = down_v;
  412. }
  413. // [Paril-KEX] NB: this line being commented is crucial for ramp-jumps to work.
  414. // thanks to Jitspoe for pointing this one out.
  415. else// if (pm->s.pm_flags & PMF_ON_GROUND)
  416. //!! Special case
  417. // if we were walking along a plane, then we need to copy the Z over
  418. pml.velocity[2] = down_v[2];
  419. // Paril: step down stairs/slopes
  420. if ((pm->s.pm_flags & PMF_ON_GROUND) && !(pm->s.pm_flags & PMF_ON_LADDER) &&
  421. (pm->waterlevel < WATER_WAIST || (!(pm->cmd.buttons & BUTTON_JUMP) && pml.velocity.z <= 0)))
  422. {
  423. down = pml.origin;
  424. down[2] -= STEPSIZE;
  425. trace = PM_Trace(pml.origin, pm->mins, pm->maxs, down);
  426. if (trace.fraction < 1.f)
  427. {
  428. pml.origin = trace.endpos;
  429. }
  430. }
  431. }
  432. /*
  433. ==================
  434. PM_Friction
  435. Handles both ground friction and water friction
  436. ==================
  437. */
  438. void PM_Friction()
  439. {
  440. float *vel;
  441. float speed, newspeed, control;
  442. float friction;
  443. float drop;
  444. vel = &pml.velocity.x;
  445. speed = sqrt(vel[0] * vel[0] + vel[1] * vel[1] + vel[2] * vel[2]);
  446. if (speed < 1)
  447. {
  448. vel[0] = 0;
  449. vel[1] = 0;
  450. return;
  451. }
  452. drop = 0;
  453. // apply ground friction
  454. if ((pm->groundentity && pml.groundsurface && !(pml.groundsurface->flags & SURF_SLICK)) || (pm->s.pm_flags & PMF_ON_LADDER))
  455. {
  456. friction = pm_friction;
  457. control = speed < pm_stopspeed ? pm_stopspeed : speed;
  458. drop += control * friction * pml.frametime;
  459. }
  460. // apply water friction
  461. if (pm->waterlevel && !(pm->s.pm_flags & PMF_ON_LADDER))
  462. drop += speed * pm_waterfriction * (float) pm->waterlevel * pml.frametime;
  463. // scale the velocity
  464. newspeed = speed - drop;
  465. if (newspeed < 0)
  466. {
  467. newspeed = 0;
  468. }
  469. newspeed /= speed;
  470. vel[0] = vel[0] * newspeed;
  471. vel[1] = vel[1] * newspeed;
  472. vel[2] = vel[2] * newspeed;
  473. }
  474. /*
  475. ==============
  476. PM_Accelerate
  477. Handles user intended acceleration
  478. ==============
  479. */
  480. void PM_Accelerate(const vec3_t &wishdir, float wishspeed, float accel)
  481. {
  482. int i;
  483. float addspeed, accelspeed, currentspeed;
  484. currentspeed = pml.velocity.dot(wishdir);
  485. addspeed = wishspeed - currentspeed;
  486. if (addspeed <= 0)
  487. return;
  488. accelspeed = accel * pml.frametime * wishspeed;
  489. if (accelspeed > addspeed)
  490. accelspeed = addspeed;
  491. for (i = 0; i < 3; i++)
  492. pml.velocity[i] += accelspeed * wishdir[i];
  493. }
  494. void PM_AirAccelerate(const vec3_t &wishdir, float wishspeed, float accel)
  495. {
  496. int i;
  497. float addspeed, accelspeed, currentspeed, wishspd = wishspeed;
  498. if (wishspd > 30)
  499. wishspd = 30;
  500. currentspeed = pml.velocity.dot(wishdir);
  501. addspeed = wishspd - currentspeed;
  502. if (addspeed <= 0)
  503. return;
  504. accelspeed = accel * wishspeed * pml.frametime;
  505. if (accelspeed > addspeed)
  506. accelspeed = addspeed;
  507. for (i = 0; i < 3; i++)
  508. pml.velocity[i] += accelspeed * wishdir[i];
  509. }
  510. /*
  511. =============
  512. PM_AddCurrents
  513. =============
  514. */
  515. void PM_AddCurrents(vec3_t &wishvel)
  516. {
  517. vec3_t v;
  518. float s;
  519. //
  520. // account for ladders
  521. //
  522. if (pm->s.pm_flags & PMF_ON_LADDER)
  523. {
  524. if (pm->cmd.buttons & (BUTTON_JUMP | BUTTON_CROUCH))
  525. {
  526. // [Paril-KEX]: if we're underwater, use full speed on ladders
  527. float ladder_speed = pm->waterlevel >= WATER_WAIST ? pm_maxspeed : 200;
  528. if (pm->cmd.buttons & BUTTON_JUMP)
  529. wishvel[2] = ladder_speed;
  530. else if (pm->cmd.buttons & BUTTON_CROUCH)
  531. wishvel[2] = -ladder_speed;
  532. }
  533. else if (pm->cmd.forwardmove)
  534. {
  535. // [Paril-KEX] clamp the speed a bit so we're not too fast
  536. float ladder_speed = std::clamp(pm->cmd.forwardmove, -200.f, 200.f);
  537. if (pm->cmd.forwardmove > 0)
  538. {
  539. if (pm->viewangles[PITCH] < 15)
  540. wishvel[2] = ladder_speed;
  541. else
  542. wishvel[2] = -ladder_speed;
  543. }
  544. // [Paril-KEX] allow using "back" arrow to go down on ladder
  545. else if (pm->cmd.forwardmove < 0)
  546. {
  547. // if we haven't touched ground yet, remove x/y so we don't
  548. // slide off of the ladder
  549. if (!pm->groundentity)
  550. wishvel[0] = wishvel[1] = 0;
  551. wishvel[2] = ladder_speed;
  552. }
  553. }
  554. else
  555. wishvel[2] = 0;
  556. // limit horizontal speed when on a ladder
  557. // [Paril-KEX] unless we're on the ground
  558. if (!pm->groundentity)
  559. {
  560. // [Paril-KEX] instead of left/right not doing anything,
  561. // have them move you perpendicular to the ladder plane
  562. if (pm->cmd.sidemove)
  563. {
  564. // clamp side speed so it's not jarring...
  565. float ladder_speed = std::clamp(pm->cmd.sidemove, -150.f, 150.f);
  566. if (pm->waterlevel < WATER_WAIST)
  567. ladder_speed *= pm_laddermod;
  568. // check for ladder
  569. vec3_t flatforward, spot;
  570. flatforward[0] = pml.forward[0];
  571. flatforward[1] = pml.forward[1];
  572. flatforward[2] = 0;
  573. flatforward.normalize();
  574. spot = pml.origin + (flatforward * 1);
  575. trace_t trace = PM_Trace(pml.origin, pm->mins, pm->maxs, spot, CONTENTS_LADDER);
  576. if (trace.fraction != 1.f && (trace.contents & CONTENTS_LADDER))
  577. {
  578. vec3_t right = trace.plane.normal.cross({ 0, 0, 1 });
  579. wishvel[0] = wishvel[1] = 0;
  580. wishvel += (right * -ladder_speed);
  581. }
  582. }
  583. else
  584. {
  585. if (wishvel[0] < -25)
  586. wishvel[0] = -25;
  587. else if (wishvel[0] > 25)
  588. wishvel[0] = 25;
  589. if (wishvel[1] < -25)
  590. wishvel[1] = -25;
  591. else if (wishvel[1] > 25)
  592. wishvel[1] = 25;
  593. }
  594. }
  595. }
  596. //
  597. // add water currents
  598. //
  599. if (pm->watertype & MASK_CURRENT)
  600. {
  601. v = {};
  602. if (pm->watertype & CONTENTS_CURRENT_0)
  603. v[0] += 1;
  604. if (pm->watertype & CONTENTS_CURRENT_90)
  605. v[1] += 1;
  606. if (pm->watertype & CONTENTS_CURRENT_180)
  607. v[0] -= 1;
  608. if (pm->watertype & CONTENTS_CURRENT_270)
  609. v[1] -= 1;
  610. if (pm->watertype & CONTENTS_CURRENT_UP)
  611. v[2] += 1;
  612. if (pm->watertype & CONTENTS_CURRENT_DOWN)
  613. v[2] -= 1;
  614. s = pm_waterspeed;
  615. if ((pm->waterlevel == WATER_FEET) && (pm->groundentity))
  616. s /= 2;
  617. wishvel += (v * s);
  618. }
  619. //
  620. // add conveyor belt velocities
  621. //
  622. if (pm->groundentity)
  623. {
  624. v = {};
  625. if (pml.groundcontents & CONTENTS_CURRENT_0)
  626. v[0] += 1;
  627. if (pml.groundcontents & CONTENTS_CURRENT_90)
  628. v[1] += 1;
  629. if (pml.groundcontents & CONTENTS_CURRENT_180)
  630. v[0] -= 1;
  631. if (pml.groundcontents & CONTENTS_CURRENT_270)
  632. v[1] -= 1;
  633. if (pml.groundcontents & CONTENTS_CURRENT_UP)
  634. v[2] += 1;
  635. if (pml.groundcontents & CONTENTS_CURRENT_DOWN)
  636. v[2] -= 1;
  637. wishvel += v * 100;
  638. }
  639. }
  640. /*
  641. ===================
  642. PM_WaterMove
  643. ===================
  644. */
  645. void PM_WaterMove()
  646. {
  647. int i;
  648. vec3_t wishvel;
  649. float wishspeed;
  650. vec3_t wishdir;
  651. //
  652. // user intentions
  653. //
  654. for (i = 0; i < 3; i++)
  655. wishvel[i] = pml.forward[i] * pm->cmd.forwardmove + pml.right[i] * pm->cmd.sidemove;
  656. if (!pm->cmd.forwardmove && !pm->cmd.sidemove &&
  657. !(pm->cmd.buttons & (BUTTON_JUMP | BUTTON_CROUCH)))
  658. {
  659. if (!pm->groundentity)
  660. wishvel[2] -= 60; // drift towards bottom
  661. }
  662. else
  663. {
  664. if (pm->cmd.buttons & BUTTON_CROUCH)
  665. wishvel[2] -= pm_waterspeed * 0.5f;
  666. else if (pm->cmd.buttons & BUTTON_JUMP)
  667. wishvel[2] += pm_waterspeed * 0.5f;
  668. }
  669. PM_AddCurrents(wishvel);
  670. wishdir = wishvel;
  671. wishspeed = wishdir.normalize();
  672. if (wishspeed > pm_maxspeed)
  673. {
  674. wishvel *= pm_maxspeed / wishspeed;
  675. wishspeed = pm_maxspeed;
  676. }
  677. wishspeed *= 0.5f;
  678. if ((pm->s.pm_flags & PMF_DUCKED) && wishspeed > pm_duckspeed)
  679. {
  680. wishvel *= pm_duckspeed / wishspeed;
  681. wishspeed = pm_duckspeed;
  682. }
  683. PM_Accelerate(wishdir, wishspeed, pm_wateraccelerate);
  684. PM_StepSlideMove();
  685. }
  686. /*
  687. ===================
  688. PM_AirMove
  689. ===================
  690. */
  691. void PM_AirMove()
  692. {
  693. int i;
  694. vec3_t wishvel;
  695. float fmove, smove;
  696. vec3_t wishdir;
  697. float wishspeed;
  698. float maxspeed;
  699. fmove = pm->cmd.forwardmove;
  700. smove = pm->cmd.sidemove;
  701. for (i = 0; i < 2; i++)
  702. wishvel[i] = pml.forward[i] * fmove + pml.right[i] * smove;
  703. wishvel[2] = 0;
  704. PM_AddCurrents(wishvel);
  705. wishdir = wishvel;
  706. wishspeed = wishdir.normalize();
  707. //
  708. // clamp to server defined max speed
  709. //
  710. maxspeed = (pm->s.pm_flags & PMF_DUCKED) ? pm_duckspeed : pm_maxspeed;
  711. if (wishspeed > maxspeed)
  712. {
  713. wishvel *= maxspeed / wishspeed;
  714. wishspeed = maxspeed;
  715. }
  716. if (pm->s.pm_flags & PMF_ON_LADDER)
  717. {
  718. PM_Accelerate(wishdir, wishspeed, pm_accelerate);
  719. if (!wishvel[2])
  720. {
  721. if (pml.velocity[2] > 0)
  722. {
  723. pml.velocity[2] -= pm->s.gravity * pml.frametime;
  724. if (pml.velocity[2] < 0)
  725. pml.velocity[2] = 0;
  726. }
  727. else
  728. {
  729. pml.velocity[2] += pm->s.gravity * pml.frametime;
  730. if (pml.velocity[2] > 0)
  731. pml.velocity[2] = 0;
  732. }
  733. }
  734. PM_StepSlideMove();
  735. }
  736. else if (pm->groundentity)
  737. { // walking on ground
  738. pml.velocity[2] = 0; //!!! this is before the accel
  739. PM_Accelerate(wishdir, wishspeed, pm_accelerate);
  740. // PGM -- fix for negative trigger_gravity fields
  741. // pml.velocity[2] = 0;
  742. if (pm->s.gravity > 0)
  743. pml.velocity[2] = 0;
  744. else
  745. pml.velocity[2] -= pm->s.gravity * pml.frametime;
  746. // PGM
  747. if (!pml.velocity[0] && !pml.velocity[1])
  748. return;
  749. PM_StepSlideMove();
  750. }
  751. else
  752. { // not on ground, so little effect on velocity
  753. if (pm_config.airaccel)
  754. PM_AirAccelerate(wishdir, wishspeed, pm_config.airaccel);
  755. else
  756. PM_Accelerate(wishdir, wishspeed, 1);
  757. // add gravity
  758. if (pm->s.pm_type != PM_GRAPPLE)
  759. pml.velocity[2] -= pm->s.gravity * pml.frametime;
  760. PM_StepSlideMove();
  761. }
  762. }
  763. inline void PM_GetWaterLevel(const vec3_t &position, water_level_t &level, contents_t &type)
  764. {
  765. //
  766. // get waterlevel, accounting for ducking
  767. //
  768. level = WATER_NONE;
  769. type = CONTENTS_NONE;
  770. int32_t sample2 = (int) (pm->s.viewheight - pm->mins[2]);
  771. int32_t sample1 = sample2 / 2;
  772. vec3_t point = position;
  773. point[2] += pm->mins[2] + 1;
  774. contents_t cont = pm->pointcontents(point);
  775. if (cont & MASK_WATER)
  776. {
  777. type = cont;
  778. level = WATER_FEET;
  779. point[2] = pml.origin[2] + pm->mins[2] + sample1;
  780. cont = pm->pointcontents(point);
  781. if (cont & MASK_WATER)
  782. {
  783. level = WATER_WAIST;
  784. point[2] = pml.origin[2] + pm->mins[2] + sample2;
  785. cont = pm->pointcontents(point);
  786. if (cont & MASK_WATER)
  787. level = WATER_UNDER;
  788. }
  789. }
  790. }
  791. /*
  792. =============
  793. PM_CatagorizePosition
  794. =============
  795. */
  796. void PM_CatagorizePosition()
  797. {
  798. vec3_t point;
  799. trace_t trace;
  800. // if the player hull point one unit down is solid, the player
  801. // is on ground
  802. // see if standing on something solid
  803. point[0] = pml.origin[0];
  804. point[1] = pml.origin[1];
  805. point[2] = pml.origin[2] - 0.25f;
  806. if (pml.velocity[2] > 180 || pm->s.pm_type == PM_GRAPPLE) //!!ZOID changed from 100 to 180 (ramp accel)
  807. {
  808. pm->s.pm_flags &= ~PMF_ON_GROUND;
  809. pm->groundentity = nullptr;
  810. }
  811. else
  812. {
  813. trace = PM_Trace(pml.origin, pm->mins, pm->maxs, point);
  814. pm->groundplane = trace.plane;
  815. pml.groundsurface = trace.surface;
  816. pml.groundcontents = trace.contents;
  817. // [Paril-KEX] to attempt to fix edge cases where you get stuck
  818. // wedged between a slope and a wall (which is irrecoverable
  819. // most of the time), we'll allow the player to "stand" on
  820. // slopes if they are right up against a wall
  821. bool slanted_ground = trace.fraction < 1.0f && trace.plane.normal[2] < 0.7f;
  822. if (slanted_ground)
  823. {
  824. trace_t slant = PM_Trace(pml.origin, pm->mins, pm->maxs, pml.origin + trace.plane.normal);
  825. if (slant.fraction < 1.0f && !slant.startsolid)
  826. slanted_ground = false;
  827. }
  828. if (trace.fraction == 1.0f || (slanted_ground && !trace.startsolid))
  829. {
  830. pm->groundentity = nullptr;
  831. pm->s.pm_flags &= ~PMF_ON_GROUND;
  832. }
  833. else
  834. {
  835. pm->groundentity = trace.ent;
  836. // hitting solid ground will end a waterjump
  837. if (pm->s.pm_flags & PMF_TIME_WATERJUMP)
  838. {
  839. pm->s.pm_flags &= ~(PMF_TIME_WATERJUMP | PMF_TIME_LAND | PMF_TIME_TELEPORT | PMF_TIME_TRICK);
  840. pm->s.pm_time = 0;
  841. }
  842. if (!(pm->s.pm_flags & PMF_ON_GROUND))
  843. {
  844. // just hit the ground
  845. // [Paril-KEX]
  846. if (!pm_config.n64_physics && pml.velocity[2] >= 100.f && pm->groundplane.normal[2] >= 0.9f && !(pm->s.pm_flags & PMF_DUCKED))
  847. {
  848. pm->s.pm_flags |= PMF_TIME_TRICK;
  849. pm->s.pm_time = 64;
  850. }
  851. // [Paril-KEX] calculate impact delta; this also fixes triple jumping
  852. vec3_t clipped_velocity;
  853. PM_ClipVelocity(pml.velocity, pm->groundplane.normal, clipped_velocity, 1.01f);
  854. pm->impact_delta = pml.start_velocity[2] - clipped_velocity[2];
  855. pm->s.pm_flags |= PMF_ON_GROUND;
  856. if (pm_config.n64_physics || (pm->s.pm_flags & PMF_DUCKED))
  857. {
  858. pm->s.pm_flags |= PMF_TIME_LAND;
  859. pm->s.pm_time = 128;
  860. }
  861. }
  862. }
  863. PM_RecordTrace(pm->touch, trace);
  864. }
  865. //
  866. // get waterlevel, accounting for ducking
  867. //
  868. PM_GetWaterLevel(pml.origin, pm->waterlevel, pm->watertype);
  869. }
  870. /*
  871. =============
  872. PM_CheckJump
  873. =============
  874. */
  875. void PM_CheckJump()
  876. {
  877. if (pm->s.pm_flags & PMF_TIME_LAND)
  878. { // hasn't been long enough since landing to jump again
  879. return;
  880. }
  881. if (!(pm->cmd.buttons & BUTTON_JUMP))
  882. { // not holding jump
  883. pm->s.pm_flags &= ~PMF_JUMP_HELD;
  884. return;
  885. }
  886. // must wait for jump to be released
  887. if (pm->s.pm_flags & PMF_JUMP_HELD)
  888. return;
  889. if (pm->s.pm_type == PM_DEAD)
  890. return;
  891. if (pm->waterlevel >= WATER_WAIST)
  892. { // swimming, not jumping
  893. pm->groundentity = nullptr;
  894. return;
  895. }
  896. if (pm->groundentity == nullptr)
  897. return; // in air, so no effect
  898. pm->s.pm_flags |= PMF_JUMP_HELD;
  899. pm->jump_sound = true;
  900. pm->groundentity = nullptr;
  901. pm->s.pm_flags &= ~PMF_ON_GROUND;
  902. float jump_height = 270.f;
  903. pml.velocity[2] += jump_height;
  904. if (pml.velocity[2] < jump_height)
  905. pml.velocity[2] = jump_height;
  906. }
  907. /*
  908. =============
  909. PM_CheckSpecialMovement
  910. =============
  911. */
  912. void PM_CheckSpecialMovement()
  913. {
  914. vec3_t spot;
  915. vec3_t flatforward;
  916. trace_t trace;
  917. if (pm->s.pm_time)
  918. return;
  919. pm->s.pm_flags &= ~PMF_ON_LADDER;
  920. // check for ladder
  921. flatforward[0] = pml.forward[0];
  922. flatforward[1] = pml.forward[1];
  923. flatforward[2] = 0;
  924. flatforward.normalize();
  925. spot = pml.origin + (flatforward * 1);
  926. trace = PM_Trace(pml.origin, pm->mins, pm->maxs, spot, CONTENTS_LADDER);
  927. if ((trace.fraction < 1) && (trace.contents & CONTENTS_LADDER) && pm->waterlevel < WATER_WAIST)
  928. pm->s.pm_flags |= PMF_ON_LADDER;
  929. if (!pm->s.gravity)
  930. return;
  931. // check for water jump
  932. // [Paril-KEX] don't try waterjump if we're moving against where we'll hop
  933. if (!(pm->cmd.buttons & BUTTON_JUMP)
  934. && pm->cmd.forwardmove <= 0)
  935. return;
  936. if (pm->waterlevel != WATER_WAIST)
  937. return;
  938. // [Paril-KEX]
  939. else if (pm->watertype & CONTENTS_NO_WATERJUMP)
  940. return;
  941. // quick check that something is even blocking us forward
  942. trace = PM_Trace(pml.origin, pm->mins, pm->maxs, pml.origin + (flatforward * 40), MASK_SOLID);
  943. // we aren't blocked, or what we're blocked by is something we can walk up
  944. if (trace.fraction == 1.0f || trace.plane.normal.z >= 0.7f)
  945. return;
  946. // [Paril-KEX] improved waterjump
  947. vec3_t waterjump_vel = flatforward * 50;
  948. waterjump_vel.z = 350;
  949. // simulate what would happen if we jumped out here, and
  950. // if we land on a dry spot we're good!
  951. // simulate 1 sec worth of movement
  952. touch_list_t touches;
  953. vec3_t waterjump_origin = pml.origin;
  954. float time = 0.1f;
  955. bool has_time = true;
  956. for (size_t i = 0; i < min(50, (int32_t) (10 * (800.f / pm->s.gravity))); i++)
  957. {
  958. waterjump_vel[2] -= pm->s.gravity * time;
  959. if (waterjump_vel[2] < 0)
  960. has_time = false;
  961. PM_StepSlideMove_Generic(waterjump_origin, waterjump_vel, time, pm->mins, pm->maxs, touches, has_time, PM_Trace_Auto);
  962. }
  963. // snap down to ground
  964. trace = PM_Trace(waterjump_origin, pm->mins, pm->maxs, waterjump_origin - vec3_t { 0, 0, 2.f }, MASK_SOLID);
  965. // can't stand here
  966. if (trace.fraction == 1.0f || trace.plane.normal.z < 0.7f ||
  967. trace.endpos.z < pml.origin.z)
  968. return;
  969. // we're currently standing on ground, and the snapped position
  970. // is a step
  971. if (pm->groundentity && fabsf(pml.origin.z - trace.endpos.z) <= STEPSIZE)
  972. return;
  973. water_level_t level;
  974. contents_t type;
  975. PM_GetWaterLevel(trace.endpos, level, type);
  976. // the water jump spot will be under water, so we're
  977. // probably hitting something weird that isn't important
  978. if (level >= WATER_WAIST)
  979. return;
  980. // valid waterjump!
  981. // jump out of water
  982. pml.velocity = flatforward * 50;
  983. pml.velocity[2] = 350;
  984. pm->s.pm_flags |= PMF_TIME_WATERJUMP;
  985. pm->s.pm_time = 2048;
  986. }
  987. /*
  988. ===============
  989. PM_FlyMove
  990. ===============
  991. */
  992. void PM_FlyMove(bool doclip)
  993. {
  994. float speed, drop, friction, control, newspeed;
  995. float currentspeed, addspeed, accelspeed;
  996. int i;
  997. vec3_t wishvel;
  998. float fmove, smove;
  999. vec3_t wishdir;
  1000. float wishspeed;
  1001. pm->s.viewheight = doclip ? 0 : 22;
  1002. // friction
  1003. speed = pml.velocity.length();
  1004. if (speed < 1)
  1005. {
  1006. pml.velocity = vec3_origin;
  1007. }
  1008. else
  1009. {
  1010. drop = 0;
  1011. friction = pm_friction * 1.5f; // extra friction
  1012. control = speed < pm_stopspeed ? pm_stopspeed : speed;
  1013. drop += control * friction * pml.frametime;
  1014. // scale the velocity
  1015. newspeed = speed - drop;
  1016. if (newspeed < 0)
  1017. newspeed = 0;
  1018. newspeed /= speed;
  1019. pml.velocity *= newspeed;
  1020. }
  1021. // accelerate
  1022. fmove = pm->cmd.forwardmove;
  1023. smove = pm->cmd.sidemove;
  1024. pml.forward.normalize();
  1025. pml.right.normalize();
  1026. for (i = 0; i < 3; i++)
  1027. wishvel[i] = pml.forward[i] * fmove + pml.right[i] * smove;
  1028. if (pm->cmd.buttons & BUTTON_JUMP)
  1029. wishvel[2] += (pm_waterspeed * 0.5f);
  1030. if (pm->cmd.buttons & BUTTON_CROUCH)
  1031. wishvel[2] -= (pm_waterspeed * 0.5f);
  1032. wishdir = wishvel;
  1033. wishspeed = wishdir.normalize();
  1034. //
  1035. // clamp to server defined max speed
  1036. //
  1037. if (wishspeed > pm_maxspeed)
  1038. {
  1039. wishvel *= pm_maxspeed / wishspeed;
  1040. wishspeed = pm_maxspeed;
  1041. }
  1042. // Paril: newer clients do this
  1043. wishspeed *= 2;
  1044. currentspeed = pml.velocity.dot(wishdir);
  1045. addspeed = wishspeed - currentspeed;
  1046. if (addspeed > 0)
  1047. {
  1048. accelspeed = pm_accelerate * pml.frametime * wishspeed;
  1049. if (accelspeed > addspeed)
  1050. accelspeed = addspeed;
  1051. for (i = 0; i < 3; i++)
  1052. pml.velocity[i] += accelspeed * wishdir[i];
  1053. }
  1054. if (doclip)
  1055. {
  1056. /*for (i = 0; i < 3; i++)
  1057. end[i] = pml.origin[i] + pml.frametime * pml.velocity[i];
  1058. trace = PM_Trace(pml.origin, pm->mins, pm->maxs, end);
  1059. pml.origin = trace.endpos;*/
  1060. PM_StepSlideMove();
  1061. }
  1062. else
  1063. {
  1064. // move
  1065. pml.origin += (pml.velocity * pml.frametime);
  1066. }
  1067. }
  1068. void PM_SetDimensions()
  1069. {
  1070. pm->mins[0] = -16;
  1071. pm->mins[1] = -16;
  1072. pm->maxs[0] = 16;
  1073. pm->maxs[1] = 16;
  1074. if (pm->s.pm_type == PM_GIB)
  1075. {
  1076. pm->mins[2] = 0;
  1077. pm->maxs[2] = 16;
  1078. pm->s.viewheight = 8;
  1079. return;
  1080. }
  1081. pm->mins[2] = -24;
  1082. if ((pm->s.pm_flags & PMF_DUCKED) || pm->s.pm_type == PM_DEAD)
  1083. {
  1084. pm->maxs[2] = 4;
  1085. pm->s.viewheight = -2;
  1086. }
  1087. else
  1088. {
  1089. pm->maxs[2] = 32;
  1090. pm->s.viewheight = 22;
  1091. }
  1092. }
  1093. inline bool PM_AboveWater()
  1094. {
  1095. const vec3_t below = pml.origin - vec3_t{ 0, 0, 8 };
  1096. bool solid_below = pm->trace(pml.origin, &pm->mins, &pm->maxs, below, pm->player, MASK_SOLID).fraction < 1.0f;
  1097. if (solid_below)
  1098. return false;
  1099. bool water_below = pm->trace(pml.origin, &pm->mins, &pm->maxs, below, pm->player, MASK_WATER).fraction < 1.0f;
  1100. if (water_below)
  1101. return true;
  1102. return false;
  1103. }
  1104. /*
  1105. ==============
  1106. PM_CheckDuck
  1107. Sets mins, maxs, and pm->viewheight
  1108. ==============
  1109. */
  1110. bool PM_CheckDuck()
  1111. {
  1112. if (pm->s.pm_type == PM_GIB)
  1113. return false;
  1114. trace_t trace;
  1115. bool flags_changed = false;
  1116. if (pm->s.pm_type == PM_DEAD)
  1117. {
  1118. if (!(pm->s.pm_flags & PMF_DUCKED))
  1119. {
  1120. pm->s.pm_flags |= PMF_DUCKED;
  1121. flags_changed = true;
  1122. }
  1123. }
  1124. else if (
  1125. (pm->cmd.buttons & BUTTON_CROUCH) &&
  1126. (pm->groundentity || (pm->waterlevel <= WATER_FEET && !PM_AboveWater())) &&
  1127. !(pm->s.pm_flags & PMF_ON_LADDER) &&
  1128. !pm_config.n64_physics)
  1129. { // duck
  1130. if (!(pm->s.pm_flags & PMF_DUCKED))
  1131. {
  1132. // check that duck won't be blocked
  1133. vec3_t check_maxs = { pm->maxs[0], pm->maxs[1], 4 };
  1134. trace = PM_Trace(pml.origin, pm->mins, check_maxs, pml.origin);
  1135. if (!trace.allsolid)
  1136. {
  1137. pm->s.pm_flags |= PMF_DUCKED;
  1138. flags_changed = true;
  1139. }
  1140. }
  1141. }
  1142. else
  1143. { // stand up if possible
  1144. if (pm->s.pm_flags & PMF_DUCKED)
  1145. {
  1146. // try to stand up
  1147. vec3_t check_maxs = { pm->maxs[0], pm->maxs[1], 32 };
  1148. trace = PM_Trace(pml.origin, pm->mins, check_maxs, pml.origin);
  1149. if (!trace.allsolid)
  1150. {
  1151. pm->s.pm_flags &= ~PMF_DUCKED;
  1152. flags_changed = true;
  1153. }
  1154. }
  1155. }
  1156. if (!flags_changed)
  1157. return false;
  1158. PM_SetDimensions();
  1159. return true;
  1160. }
  1161. /*
  1162. ==============
  1163. PM_DeadMove
  1164. ==============
  1165. */
  1166. void PM_DeadMove()
  1167. {
  1168. float forward;
  1169. if (!pm->groundentity)
  1170. return;
  1171. // extra friction
  1172. forward = pml.velocity.length();
  1173. forward -= 20;
  1174. if (forward <= 0)
  1175. {
  1176. pml.velocity = {};
  1177. }
  1178. else
  1179. {
  1180. pml.velocity.normalize();
  1181. pml.velocity *= forward;
  1182. }
  1183. }
  1184. bool PM_GoodPosition()
  1185. {
  1186. if (pm->s.pm_type == PM_NOCLIP)
  1187. return true;
  1188. trace_t trace = PM_Trace(pm->s.origin, pm->mins, pm->maxs, pm->s.origin);
  1189. return !trace.allsolid;
  1190. }
  1191. /*
  1192. ================
  1193. PM_SnapPosition
  1194. On exit, the origin will have a value that is pre-quantized to the PMove
  1195. precision of the network channel and in a valid position.
  1196. ================
  1197. */
  1198. void PM_SnapPosition()
  1199. {
  1200. pm->s.velocity = pml.velocity;
  1201. pm->s.origin = pml.origin;
  1202. if (PM_GoodPosition())
  1203. return;
  1204. if (G_FixStuckObject_Generic(pm->s.origin, pm->mins, pm->maxs, PM_Trace_Auto) == stuck_result_t::NO_GOOD_POSITION) {
  1205. pm->s.origin = pml.previous_origin;
  1206. return;
  1207. }
  1208. }
  1209. /*
  1210. ================
  1211. PM_InitialSnapPosition
  1212. ================
  1213. */
  1214. void PM_InitialSnapPosition()
  1215. {
  1216. int x, y, z;
  1217. vec3_t base;
  1218. constexpr int offset[3] = { 0, -1, 1 };
  1219. base = pm->s.origin;
  1220. for (z = 0; z < 3; z++)
  1221. {
  1222. pm->s.origin[2] = base[2] + offset[z];
  1223. for (y = 0; y < 3; y++)
  1224. {
  1225. pm->s.origin[1] = base[1] + offset[y];
  1226. for (x = 0; x < 3; x++)
  1227. {
  1228. pm->s.origin[0] = base[0] + offset[x];
  1229. if (PM_GoodPosition())
  1230. {
  1231. pml.origin = pm->s.origin;
  1232. pml.previous_origin = pm->s.origin;
  1233. return;
  1234. }
  1235. }
  1236. }
  1237. }
  1238. }
  1239. /*
  1240. ================
  1241. PM_ClampAngles
  1242. ================
  1243. */
  1244. void PM_ClampAngles()
  1245. {
  1246. if (pm->s.pm_flags & PMF_TIME_TELEPORT)
  1247. {
  1248. pm->viewangles[YAW] = pm->cmd.angles[YAW] + pm->s.delta_angles[YAW];
  1249. pm->viewangles[PITCH] = 0;
  1250. pm->viewangles[ROLL] = 0;
  1251. }
  1252. else
  1253. {
  1254. // circularly clamp the angles with deltas
  1255. pm->viewangles = pm->cmd.angles + pm->s.delta_angles;
  1256. // don't let the player look up or down more than 90 degrees
  1257. if (pm->viewangles[PITCH] > 89 && pm->viewangles[PITCH] < 180)
  1258. pm->viewangles[PITCH] = 89;
  1259. else if (pm->viewangles[PITCH] < 271 && pm->viewangles[PITCH] >= 180)
  1260. pm->viewangles[PITCH] = 271;
  1261. }
  1262. AngleVectors(pm->viewangles, pml.forward, pml.right, pml.up);
  1263. }
  1264. // [Paril-KEX]
  1265. static void PM_ScreenEffects()
  1266. {
  1267. // add for contents
  1268. vec3_t vieworg = pml.origin + pm->viewoffset + vec3_t{ 0, 0, (float) pm->s.viewheight };
  1269. contents_t contents = pm->pointcontents(vieworg);
  1270. if (contents & (CONTENTS_LAVA | CONTENTS_SLIME | CONTENTS_WATER))
  1271. pm->rdflags |= RDF_UNDERWATER;
  1272. else
  1273. pm->rdflags &= ~RDF_UNDERWATER;
  1274. if (contents & (CONTENTS_SOLID | CONTENTS_LAVA))
  1275. G_AddBlend(1.0f, 0.3f, 0.0f, 0.6f, pm->screen_blend);
  1276. else if (contents & CONTENTS_SLIME)
  1277. G_AddBlend(0.0f, 0.1f, 0.05f, 0.6f, pm->screen_blend);
  1278. else if (contents & CONTENTS_WATER)
  1279. G_AddBlend(0.5f, 0.3f, 0.2f, 0.4f, pm->screen_blend);
  1280. }
  1281. /*
  1282. ================
  1283. Pmove
  1284. Can be called by either the server or the client
  1285. ================
  1286. */
  1287. void Pmove(pmove_t *pmove)
  1288. {
  1289. pm = pmove;
  1290. // clear results
  1291. pm->touch.num = 0;
  1292. pm->viewangles = {};
  1293. pm->s.viewheight = 0;
  1294. pm->groundentity = nullptr;
  1295. pm->watertype = CONTENTS_NONE;
  1296. pm->waterlevel = WATER_NONE;
  1297. pm->screen_blend = {};
  1298. pm->rdflags = RDF_NONE;
  1299. pm->jump_sound = false;
  1300. pm->step_clip = false;
  1301. pm->impact_delta = 0;
  1302. // clear all pmove local vars
  1303. pml = {};
  1304. // convert origin and velocity to float values
  1305. pml.origin = pm->s.origin;
  1306. pml.velocity = pm->s.velocity;
  1307. pml.start_velocity = pml.velocity;
  1308. // save old org in case we get stuck
  1309. pml.previous_origin = pm->s.origin;
  1310. pml.frametime = pm->cmd.msec * 0.001f;
  1311. PM_ClampAngles();
  1312. if (pm->s.pm_type == PM_SPECTATOR || pm->s.pm_type == PM_NOCLIP)
  1313. {
  1314. pm->s.pm_flags = PMF_NONE;
  1315. if (pm->s.pm_type == PM_SPECTATOR)
  1316. {
  1317. pm->mins[0] = -8;
  1318. pm->mins[1] = -8;
  1319. pm->maxs[0] = 8;
  1320. pm->maxs[1] = 8;
  1321. pm->mins[2] = -8;
  1322. pm->maxs[2] = 8;
  1323. }
  1324. PM_FlyMove(pm->s.pm_type == PM_SPECTATOR);
  1325. PM_SnapPosition();
  1326. return;
  1327. }
  1328. if (pm->s.pm_type >= PM_DEAD)
  1329. {
  1330. pm->cmd.forwardmove = 0;
  1331. pm->cmd.sidemove = 0;
  1332. pm->cmd.buttons &= ~(BUTTON_JUMP | BUTTON_CROUCH);
  1333. }
  1334. if (pm->s.pm_type == PM_FREEZE)
  1335. return; // no movement at all
  1336. // set mins, maxs, and viewheight
  1337. PM_SetDimensions();
  1338. // catagorize for ducking
  1339. PM_CatagorizePosition();
  1340. if (pm->snapinitial)
  1341. PM_InitialSnapPosition();
  1342. // set groundentity, watertype, and waterlevel
  1343. if (PM_CheckDuck())
  1344. PM_CatagorizePosition();
  1345. if (pm->s.pm_type == PM_DEAD)
  1346. PM_DeadMove();
  1347. PM_CheckSpecialMovement();
  1348. // drop timing counter
  1349. if (pm->s.pm_time)
  1350. {
  1351. if (pm->cmd.msec >= pm->s.pm_time)
  1352. {
  1353. pm->s.pm_flags &= ~(PMF_TIME_WATERJUMP | PMF_TIME_LAND | PMF_TIME_TELEPORT | PMF_TIME_TRICK);
  1354. pm->s.pm_time = 0;
  1355. }
  1356. else
  1357. pm->s.pm_time -= pm->cmd.msec;
  1358. }
  1359. if (pm->s.pm_flags & PMF_TIME_TELEPORT)
  1360. { // teleport pause stays exactly in place
  1361. }
  1362. else if (pm->s.pm_flags & PMF_TIME_WATERJUMP)
  1363. { // waterjump has no control, but falls
  1364. pml.velocity[2] -= pm->s.gravity * pml.frametime;
  1365. if (pml.velocity[2] < 0)
  1366. { // cancel as soon as we are falling down again
  1367. pm->s.pm_flags &= ~(PMF_TIME_WATERJUMP | PMF_TIME_LAND | PMF_TIME_TELEPORT | PMF_TIME_TRICK);
  1368. pm->s.pm_time = 0;
  1369. }
  1370. PM_StepSlideMove();
  1371. }
  1372. else
  1373. {
  1374. PM_CheckJump();
  1375. PM_Friction();
  1376. if (pm->waterlevel >= WATER_WAIST)
  1377. PM_WaterMove();
  1378. else
  1379. {
  1380. vec3_t angles;
  1381. angles = pm->viewangles;
  1382. if (angles[PITCH] > 180)
  1383. angles[PITCH] = angles[PITCH] - 360;
  1384. angles[PITCH] /= 3;
  1385. AngleVectors(angles, pml.forward, pml.right, pml.up);
  1386. PM_AirMove();
  1387. }
  1388. }
  1389. // set groundentity, watertype, and waterlevel for final spot
  1390. PM_CatagorizePosition();
  1391. // trick jump
  1392. if (pm->s.pm_flags & PMF_TIME_TRICK)
  1393. PM_CheckJump();
  1394. // [Paril-KEX]
  1395. PM_ScreenEffects();
  1396. PM_SnapPosition();
  1397. }