Line data Source code
1 : #include "SoldierPhysics.hpp"
2 :
3 : #include <math.h>
4 :
5 : #include "core/animations/AnimationData.hpp"
6 : #include "core/animations/AnimationState.hpp"
7 : #include "core/physics/SoldierPhysics.hpp"
8 : #include "core/physics/SoldierSkeletonPhysics.hpp"
9 :
10 : #include "core/math/Calc.hpp"
11 : #include "core/entities/Bullet.hpp"
12 : #include "core/types/TeamType.hpp"
13 : #include "core/types/WeaponType.hpp"
14 : #include "core/entities/WeaponParametersFactory.hpp"
15 :
16 : #include "core/physics/Constants.hpp"
17 :
18 : #include "spdlog/spdlog.h"
19 :
20 : #include <cmath>
21 : #include <utility>
22 : #include <vector>
23 : #include <algorithm>
24 :
25 : namespace Soldank::SoldierPhysics
26 : {
27 0 : const Weapon& GetPrimaryWeapon(Soldier& soldier)
28 : {
29 0 : return soldier.weapons[soldier.active_weapon];
30 : }
31 :
32 0 : const Weapon& GetSecondaryWeapon(Soldier& soldier)
33 : {
34 0 : return soldier.weapons[(soldier.active_weapon + 1) % 2];
35 : }
36 :
37 0 : const Weapon& GetTertiaryWeapon(Soldier& soldier)
38 : {
39 0 : return soldier.weapons[2];
40 : }
41 :
42 0 : void SwitchWeapon(Soldier& soldier)
43 : {
44 0 : int new_active_weapon = (soldier.active_weapon + 1) % 2;
45 0 : soldier.active_weapon = new_active_weapon;
46 : // weapons[new_active_weapon].start_up_time_count =
47 : // weapons[new_active_weapon].GetWeaponParameters().start_up_time;
48 0 : soldier.weapons[new_active_weapon].ResetStartUpTimeCount();
49 : // weapons[new_active_weapon].reload_time_prev = weapons[new_active_weapon].reload_time_count;
50 0 : soldier.weapons[new_active_weapon].SetReloadTimePrev(
51 0 : soldier.weapons[new_active_weapon].GetReloadTimeCount());
52 0 : }
53 :
54 0 : void UpdateKeys(Soldier& soldier, const Control& control)
55 : {
56 0 : soldier.control = control;
57 0 : }
58 :
59 0 : void HandleSpecialPolytypes(const Map& map, PMSPolygonType polytype, Soldier& soldier)
60 : {
61 0 : if (polytype == PMSPolygonType::Deadly || polytype == PMSPolygonType::BloodyDeadly ||
62 : polytype == PMSPolygonType::Explosive) {
63 0 : soldier.particle.position = glm::vec2(map.GetSpawnPoints()[0].x, map.GetSpawnPoints()[0].y);
64 : }
65 0 : }
66 :
67 0 : void Update(StateManager& state_manager,
68 : Soldier& soldier,
69 : const PhysicsEvents& physics_events,
70 : const AnimationDataManager& animation_data_manager,
71 : std::vector<BulletParams>& bullet_emitter,
72 : float gravity)
73 : {
74 0 : const Map& map = state_manager.GetConstMap();
75 0 : float body_y = 0.0F;
76 0 : float arm_s = 0.0F;
77 :
78 0 : soldier.particle.Euler();
79 :
80 0 : if (!soldier.control.fire) {
81 0 : soldier.is_shooting = false;
82 : }
83 :
84 0 : if (soldier.legs_animation->GetSpeed() < 1) {
85 0 : soldier.legs_animation->SetSpeed(1);
86 : }
87 :
88 0 : if (soldier.legs_animation->GetSpeed() < 1) {
89 0 : soldier.legs_animation->SetSpeed(1);
90 : }
91 :
92 0 : if (soldier.body_animation->GetSpeed() < 1) {
93 0 : soldier.body_animation->SetSpeed(1);
94 : }
95 :
96 0 : auto conflicting_keys_pressed = [](const Control& c) {
97 0 : return ((int)c.throw_grenade + (int)c.change + (int)c.drop + (int)c.reload) > 1;
98 : };
99 :
100 : // Handle simultaneous key presses that would conflict
101 0 : if (conflicting_keys_pressed(soldier.control)) {
102 : // At least two buttons pressed, so deactivate any previous one
103 0 : if (soldier.control.was_throwing_grenade) {
104 0 : soldier.control.throw_grenade = false;
105 0 : } else if (soldier.control.was_changing_weapon) {
106 0 : soldier.control.change = false;
107 0 : } else if (soldier.control.was_throwing_weapon) {
108 0 : soldier.control.drop = false;
109 0 : } else if (soldier.control.was_reloading_weapon) {
110 0 : soldier.control.reload = false;
111 : }
112 :
113 : // If simultaneously pressing two or more new buttons, then deactivate them
114 : // in order of least preference
115 0 : while (conflicting_keys_pressed(soldier.control)) {
116 0 : if (soldier.control.reload) {
117 0 : soldier.control.reload = false;
118 0 : } else if (soldier.control.change) {
119 0 : soldier.control.change = false;
120 0 : } else if (soldier.control.drop) {
121 0 : soldier.control.drop = false;
122 0 : } else if (soldier.control.throw_grenade) {
123 0 : soldier.control.throw_grenade = false;
124 : }
125 : }
126 : } else {
127 0 : soldier.control.was_throwing_grenade = soldier.control.throw_grenade;
128 0 : soldier.control.was_changing_weapon = soldier.control.change;
129 0 : soldier.control.was_throwing_weapon = soldier.control.drop;
130 0 : soldier.control.was_reloading_weapon = soldier.control.reload;
131 : }
132 :
133 : // self.fired = 0;
134 0 : soldier.control.mouse_aim_x =
135 0 : (int)((float)soldier.control.mouse_aim_x + soldier.particle.GetVelocity().x);
136 0 : soldier.control.mouse_aim_y =
137 0 : (int)((float)soldier.control.mouse_aim_y + soldier.particle.GetVelocity().y);
138 :
139 0 : auto maybe_new_legs_animation_state_machine = soldier.legs_animation->HandleInput(soldier);
140 0 : if (maybe_new_legs_animation_state_machine.has_value()) {
141 0 : soldier.legs_animation->Exit(soldier, physics_events);
142 0 : soldier.legs_animation = *maybe_new_legs_animation_state_machine;
143 0 : soldier.legs_animation->Enter(soldier);
144 : }
145 :
146 0 : soldier.body_animation->TryToShoot(soldier, physics_events);
147 0 : soldier.body_animation->TryToThrowFlags(soldier, physics_events);
148 0 : auto maybe_new_body_animation_state_machine = soldier.body_animation->HandleInput(soldier);
149 0 : if (maybe_new_body_animation_state_machine.has_value()) {
150 0 : soldier.body_animation->Exit(soldier, physics_events);
151 0 : soldier.body_animation = *maybe_new_body_animation_state_machine;
152 0 : soldier.body_animation->Enter(soldier);
153 : }
154 :
155 0 : soldier.legs_animation->Update(soldier, physics_events);
156 0 : soldier.body_animation->Update(soldier, physics_events);
157 :
158 0 : bool jets_can_be_applied = true;
159 0 : if (soldier.legs_animation->GetType() == AnimationType::RollBack && soldier.control.up) {
160 : // jets cannot be applied during RollBack animation when "up" is pressed because
161 : // that animation adds its forces on the soldier
162 0 : jets_can_be_applied = false;
163 : }
164 :
165 0 : if (jets_can_be_applied && soldier.control.jets && (soldier.jets_count > 0)) {
166 0 : if (soldier.on_ground) {
167 0 : glm::vec2 particle_force = soldier.particle.GetForce();
168 0 : if (gravity > 0.05F) {
169 0 : soldier.particle.SetForce({ particle_force.x, -2.5F * PhysicsConstants::JETSPEED });
170 : } else {
171 0 : soldier.particle.SetForce({ particle_force.x, -2.5F * (gravity * 2.0F) });
172 : }
173 0 : } else if (soldier.stance != PhysicsConstants::STANCE_PRONE) {
174 0 : glm::vec2 particle_force = soldier.particle.GetForce();
175 0 : if (gravity > 0.05F) {
176 0 : soldier.particle.SetForce(
177 0 : { particle_force.x, particle_force.y - PhysicsConstants::JETSPEED });
178 : } else {
179 0 : soldier.particle.SetForce({ particle_force.x, particle_force.y - gravity * 2.0F });
180 : }
181 : } else {
182 0 : glm::vec2 particle_force = soldier.particle.GetForce();
183 0 : soldier.particle.SetForce(
184 0 : { particle_force.x +
185 0 : (float)soldier.direction *
186 0 : (gravity > 0.05F ? PhysicsConstants::JETSPEED / 2.0F : gravity),
187 : particle_force.y });
188 : }
189 0 : soldier.jets_count -= 1;
190 : }
191 :
192 0 : RepositionSoldierSkeletonParts(soldier);
193 :
194 0 : for (int i = 1; i <= 20; i++) {
195 0 : if ((soldier.dead_meat || soldier.half_dead) && (i < 17) && (i != 7) && (i != 8)) {
196 0 : auto xy = soldier.particle.position;
197 0 : soldier.on_ground = CheckSkeletonMapCollision(soldier, map, i, xy.x, xy.y);
198 : }
199 : }
200 :
201 0 : if (!soldier.dead_meat) {
202 0 : soldier.body_animation->DoAnimation();
203 0 : soldier.legs_animation->DoAnimation();
204 :
205 0 : soldier.on_ground = false;
206 :
207 0 : auto xy = soldier.particle.position;
208 :
209 0 : CheckMapCollision(soldier, map, xy.x - 3.5, xy.y - 12.0, 1, physics_events);
210 :
211 0 : xy = soldier.particle.position;
212 :
213 0 : CheckMapCollision(soldier, map, xy.x + 3.5, xy.y - 12.0, 1, physics_events);
214 :
215 0 : body_y = 0.0;
216 0 : arm_s = 0.0;
217 :
218 : // Walking either left or right (though only one can be active at once)
219 0 : if (soldier.control.left ^ soldier.control.right) {
220 0 : if (soldier.control.left ^ (soldier.direction == 1)) {
221 : // WRONG
222 0 : arm_s = 0.25;
223 : } else {
224 0 : body_y = 0.25;
225 : }
226 : }
227 : // If a leg is inside a polygon, caused by the modification of ArmS and
228 : // BodyY, this is there to not lose contact to ground on slope polygons
229 0 : if (std::abs(body_y) <= 0.00001) {
230 0 : glm::vec2 leg_vector = { soldier.particle.position.x + 2.0F,
231 0 : soldier.particle.position.y + 1.9F };
232 0 : float leg_distance = 0.0F;
233 0 : if (map.RayCast(leg_vector, leg_vector, leg_distance, 10)) {
234 0 : body_y = 0.25;
235 : }
236 : }
237 0 : if (std::abs(arm_s) <= 0.00001) {
238 0 : glm::vec2 leg_vector = { soldier.particle.position.x - 2.0F,
239 0 : soldier.particle.position.y + 1.9F };
240 0 : float leg_distance = 0.0F;
241 0 : if (map.RayCast(leg_vector, leg_vector, leg_distance, 10)) {
242 0 : arm_s = 0.25;
243 : }
244 : }
245 :
246 0 : xy = soldier.particle.position;
247 0 : soldier.on_ground =
248 0 : CheckMapCollision(soldier, map, xy.x + 2.0, xy.y + 2.0 - body_y, 0, physics_events);
249 :
250 0 : xy = soldier.particle.position;
251 0 : soldier.on_ground =
252 0 : soldier.on_ground ||
253 0 : CheckMapCollision(soldier, map, xy.x - 2.0, xy.y + 2.0 - arm_s, 0, physics_events);
254 :
255 0 : xy = soldier.particle.position;
256 0 : auto grounded = soldier.on_ground;
257 0 : soldier.on_ground_for_law =
258 0 : CheckRadiusMapCollision(soldier, map, xy.x, xy.y - 1.0, grounded, physics_events);
259 :
260 0 : xy = soldier.particle.position;
261 0 : grounded = soldier.on_ground || soldier.on_ground_for_law;
262 0 : soldier.on_ground =
263 0 : CheckMapVerticesCollision(soldier, map, xy.x, xy.y, 3.0, grounded, physics_events) ||
264 0 : soldier.on_ground;
265 :
266 0 : if (!(soldier.on_ground ^ soldier.on_ground_last_frame)) {
267 0 : soldier.on_ground_permanent = soldier.on_ground;
268 : }
269 :
270 0 : soldier.on_ground_last_frame = soldier.on_ground;
271 :
272 0 : if ((soldier.jets_count < map.GetJetCount()) && !(soldier.control.jets)) {
273 : // if self.on_ground
274 : /* (MainTickCounter mod 2 = 0) */
275 : {
276 0 : soldier.jets_count += 1;
277 : }
278 : }
279 0 : soldier.alpha = 255;
280 :
281 0 : state_manager.TransformItems([&](auto& item) {
282 0 : if (item.holding_soldier_id == soldier.id && item.style == ItemType::Parachute) {
283 0 : glm::vec2 force = soldier.particle.GetForce();
284 0 : soldier.particle.SetForce(
285 : { force.x, PhysicsConstants::SOLDIER_SPEED_WITH_PARACHUTE });
286 : // {$IFDEF SERVER}
287 : // if CeaseFireCounter < 1 then
288 : // {$ELSE}
289 : // if ((sv_survivalmode.Value) and (CeaseFireCounter < CeaseFireTime * 3 - 30)) or
290 : // (CeaseFireCounter < CeaseFireTime - 30) then
291 : // {$ENDIF}
292 0 : if (soldier.on_ground || soldier.control.jets) {
293 0 : item.holding_soldier_id = 0;
294 : // TODO
295 : // Dec(Thing[HoldedThing].Skeleton.ConstraintCount);
296 0 : item.time_out = 3 * 60;
297 : // HoldedThing := 0;
298 : }
299 : }
300 0 : });
301 :
302 0 : soldier.skeleton->DoVerletTimestepFor(22, 29);
303 0 : soldier.skeleton->DoVerletTimestepFor(24, 30);
304 : }
305 :
306 0 : if (soldier.dead_meat) {
307 0 : soldier.skeleton->DoVerletTimestep();
308 0 : soldier.particle.position = soldier.skeleton->GetPos(12);
309 : // CheckSkeletonOutOfBounds;
310 :
311 0 : state_manager.TransformItems([&](auto& item) {
312 0 : if (item.holding_soldier_id == soldier.id && item.style == ItemType::Parachute) {
313 0 : glm::vec2 force = soldier.skeleton->GetForce(12);
314 0 : soldier.skeleton->SetForce(
315 : 12, { force.x, 25 * PhysicsConstants::SOLDIER_SPEED_WITH_PARACHUTE });
316 0 : if (soldier.on_ground) {
317 0 : item.holding_soldier_id = 0;
318 : // TODO
319 : // Dec(Thing[HoldedThing].Skeleton.ConstraintCount);
320 0 : item.time_out = 3 * 60;
321 : }
322 : }
323 0 : });
324 : }
325 :
326 0 : if (soldier.particle.velocity_.x > PhysicsConstants::MAX_VELOCITY) {
327 0 : soldier.particle.velocity_.x = PhysicsConstants::MAX_VELOCITY;
328 : }
329 0 : if (soldier.particle.velocity_.x < -PhysicsConstants::MAX_VELOCITY) {
330 0 : soldier.particle.velocity_.x = -PhysicsConstants::MAX_VELOCITY;
331 : }
332 0 : if (soldier.particle.velocity_.y > PhysicsConstants::MAX_VELOCITY) {
333 0 : soldier.particle.velocity_.y = PhysicsConstants::MAX_VELOCITY;
334 : }
335 0 : if (soldier.particle.velocity_.y < -PhysicsConstants::MAX_VELOCITY) {
336 0 : soldier.particle.velocity_.y = -PhysicsConstants::MAX_VELOCITY;
337 : }
338 0 : }
339 :
340 0 : bool CheckMapCollision(Soldier& soldier,
341 : const Map& map,
342 : float x,
343 : float y,
344 : int area,
345 : const PhysicsEvents& physics_events)
346 : {
347 0 : auto pos = glm::vec2(x, y) + soldier.particle.velocity_;
348 0 : auto rx = ((int)std::round((pos.x / (float)map.GetSectorsSize()))) + 25;
349 0 : auto ry = ((int)std::round((pos.y / (float)map.GetSectorsSize()))) + 25;
350 :
351 0 : if ((rx > 0) && (rx < map.GetSectorsCount() + 25) && (ry > 0) &&
352 0 : (ry < map.GetSectorsCount() + 25)) {
353 0 : for (int j = 0; j < map.GetSector(rx, ry).polygons.size(); j++) {
354 0 : auto poly = map.GetSector(rx, ry).polygons[j] - 1;
355 0 : auto polytype = map.GetPolygons()[poly].polygon_type;
356 :
357 0 : if ((polytype != PMSPolygonType::NoCollide) &&
358 : (polytype != PMSPolygonType::OnlyBulletsCollide)) {
359 0 : auto polygons = map.GetPolygons()[poly];
360 :
361 0 : if (Map::PointInPoly(pos, polygons)) {
362 0 : HandleSpecialPolytypes(map, polytype, soldier);
363 :
364 0 : auto dist = 0.0F;
365 0 : auto k = 0;
366 :
367 0 : auto perp = map.ClosestPerpendicular(poly, pos, &dist, &k);
368 :
369 0 : auto step = perp;
370 :
371 0 : perp = Calc::Vec2Normalize(perp);
372 0 : perp *= dist;
373 0 : dist = Calc::Vec2Length(soldier.particle.velocity_);
374 :
375 0 : if (Calc::Vec2Length(perp) > dist) {
376 0 : perp = Calc::Vec2Normalize(perp);
377 0 : perp *= dist;
378 : }
379 0 : if ((area == 0) ||
380 0 : ((area == 1) &&
381 0 : ((soldier.particle.velocity_.y < 0.0) ||
382 0 : (soldier.particle.velocity_.x > PhysicsConstants::SLIDELIMIT) ||
383 0 : (soldier.particle.velocity_.x < -PhysicsConstants::SLIDELIMIT)))) {
384 0 : soldier.particle.old_position = soldier.particle.position;
385 0 : soldier.particle.position -= perp;
386 0 : if (map.GetPolygons()[poly].polygon_type == PMSPolygonType::Bouncy) {
387 0 : perp = Calc::Vec2Normalize(perp);
388 0 : perp *= map.GetPolygons()[poly].bounciness * dist;
389 : }
390 0 : soldier.particle.velocity_ -= perp;
391 : }
392 :
393 0 : if (area == 0) {
394 0 : if ((soldier.legs_animation->GetType() == AnimationType::Stand) ||
395 0 : (soldier.legs_animation->GetType() == AnimationType::Crouch) ||
396 0 : (soldier.legs_animation->GetType() == AnimationType::Prone) ||
397 0 : (soldier.legs_animation->GetType() == AnimationType::ProneMove) ||
398 0 : (soldier.legs_animation->GetType() == AnimationType::GetUp) ||
399 0 : (soldier.legs_animation->GetType() == AnimationType::Fall) ||
400 0 : (soldier.legs_animation->GetType() == AnimationType::Mercy) ||
401 0 : (soldier.legs_animation->GetType() == AnimationType::Mercy2) ||
402 0 : (soldier.legs_animation->GetType() == AnimationType::Own)) {
403 0 : if ((soldier.particle.velocity_.x < PhysicsConstants::SLIDELIMIT) &&
404 0 : (soldier.particle.velocity_.x > -PhysicsConstants::SLIDELIMIT) &&
405 0 : (step.y > PhysicsConstants::SLIDELIMIT)) {
406 0 : soldier.particle.position = soldier.particle.old_position;
407 0 : glm::vec2 particle_force = soldier.particle.GetForce();
408 0 : particle_force.y -= PhysicsConstants::GRAV;
409 0 : soldier.particle.SetForce(particle_force);
410 : }
411 :
412 0 : if ((step.y > PhysicsConstants::SLIDELIMIT) &&
413 0 : (polytype != PMSPolygonType::Ice) &&
414 : (polytype != PMSPolygonType::Bouncy)) {
415 0 : if ((soldier.legs_animation->GetType() == AnimationType::Stand) ||
416 0 : (soldier.legs_animation->GetType() == AnimationType::Fall) ||
417 0 : (soldier.legs_animation->GetType() == AnimationType::Crouch)) {
418 0 : soldier.particle.velocity_.x *=
419 : PhysicsConstants::STANDSURFACECOEFX;
420 0 : soldier.particle.velocity_.y *=
421 : PhysicsConstants::STANDSURFACECOEFY;
422 :
423 0 : glm::vec2 particle_force = soldier.particle.GetForce();
424 0 : particle_force.x -= soldier.particle.velocity_.x;
425 0 : soldier.particle.SetForce(particle_force);
426 0 : } else if (soldier.legs_animation->GetType() ==
427 : AnimationType::Prone) {
428 0 : if (soldier.legs_animation->GetFrame() > 24) {
429 0 : if (!(soldier.control.down &&
430 0 : (soldier.control.left || soldier.control.right))) {
431 0 : soldier.particle.velocity_.x *=
432 : PhysicsConstants::STANDSURFACECOEFX;
433 0 : soldier.particle.velocity_.y *=
434 : PhysicsConstants::STANDSURFACECOEFY;
435 :
436 0 : glm::vec2 particle_force = soldier.particle.GetForce();
437 0 : particle_force.x -= soldier.particle.velocity_.x;
438 0 : soldier.particle.SetForce(particle_force);
439 : }
440 : } else {
441 0 : soldier.particle.velocity_.x *=
442 : PhysicsConstants::SURFACECOEFX;
443 0 : soldier.particle.velocity_.y *=
444 : PhysicsConstants::SURFACECOEFY;
445 : }
446 0 : } else if (soldier.legs_animation->GetType() ==
447 : AnimationType::GetUp) {
448 0 : soldier.particle.velocity_.x *= PhysicsConstants::SURFACECOEFX;
449 0 : soldier.particle.velocity_.y *= PhysicsConstants::SURFACECOEFY;
450 0 : } else if (soldier.legs_animation->GetType() ==
451 : AnimationType::ProneMove) {
452 0 : soldier.particle.velocity_.x *=
453 : PhysicsConstants::STANDSURFACECOEFX;
454 0 : soldier.particle.velocity_.y *=
455 : PhysicsConstants::STANDSURFACECOEFY;
456 : }
457 : }
458 0 : } else if ((soldier.legs_animation->GetType() ==
459 0 : AnimationType::CrouchRun) ||
460 0 : (soldier.legs_animation->GetType() ==
461 : AnimationType::CrouchRunBack)) {
462 0 : soldier.particle.velocity_.x *=
463 : PhysicsConstants::CROUCHMOVESURFACECOEFX;
464 0 : soldier.particle.velocity_.y *=
465 : PhysicsConstants::CROUCHMOVESURFACECOEFY;
466 : } else {
467 0 : soldier.particle.velocity_.x *= PhysicsConstants::SURFACECOEFX;
468 0 : soldier.particle.velocity_.y *= PhysicsConstants::SURFACECOEFY;
469 : }
470 : }
471 :
472 0 : physics_events.soldier_collides_with_polygon.Notify(soldier, polygons);
473 0 : return true;
474 : }
475 : }
476 : }
477 : }
478 :
479 0 : return false;
480 : }
481 :
482 0 : bool CheckMapVerticesCollision(Soldier& soldier,
483 : const Map& map,
484 : float x,
485 : float y,
486 : float r,
487 : bool has_collided,
488 : const PhysicsEvents& physics_events)
489 : {
490 0 : auto pos = glm::vec2(x, y);
491 0 : auto rx = ((int)std::round(pos.x / (float)map.GetSectorsSize())) + 25;
492 0 : auto ry = ((int)std::round(pos.y / (float)map.GetSectorsSize())) + 25;
493 :
494 0 : if ((rx > 0) && (rx < map.GetSectorsCount() + 25) && (ry > 0) &&
495 0 : (ry < map.GetSectorsCount() + 25)) {
496 0 : for (int j = 0; j < map.GetSector(rx, ry).polygons.size(); ++j) {
497 0 : auto poly = map.GetSector(rx, ry).polygons[j] - 1;
498 0 : PMSPolygonType polytype = map.GetPolygons()[poly].polygon_type;
499 :
500 : // TODO: this if has more poly types
501 0 : if (polytype != PMSPolygonType::NoCollide &&
502 : polytype != PMSPolygonType::OnlyBulletsCollide) {
503 0 : for (int i = 0; i < 3; i++) {
504 0 : auto vert = glm::vec2(map.GetPolygons()[poly].vertices[i].x,
505 0 : map.GetPolygons()[poly].vertices[i].y);
506 :
507 0 : auto dist = Calc::Distance(vert, pos);
508 0 : if (dist < r) {
509 0 : if (!has_collided) {
510 0 : HandleSpecialPolytypes(map, polytype, soldier);
511 : }
512 0 : auto dir = pos - vert;
513 0 : dir = Calc::Vec2Normalize(dir);
514 0 : soldier.particle.position += dir;
515 0 : physics_events.soldier_collides_with_polygon.Notify(
516 0 : soldier, map.GetPolygons()[poly]);
517 :
518 0 : return true;
519 : }
520 : }
521 : }
522 : }
523 : }
524 0 : return false;
525 : }
526 :
527 0 : bool CheckRadiusMapCollision(Soldier& soldier,
528 : const Map& map,
529 : float x,
530 : float y,
531 : bool has_collided,
532 : const PhysicsEvents& physics_events)
533 : {
534 0 : auto s_pos = glm::vec2(x, y - 3.0f);
535 :
536 0 : auto det_acc = (int)Calc::Vec2Length(soldier.particle.velocity_);
537 0 : if (det_acc == 0) {
538 0 : det_acc = 1;
539 : }
540 :
541 0 : auto step = soldier.particle.velocity_ * (1.0f / (float)det_acc);
542 :
543 0 : for (int _z = 0; _z < det_acc; _z++) {
544 0 : s_pos += step;
545 :
546 0 : auto rx = ((int)std::round(s_pos.x / (float)map.GetSectorsSize())) + 25;
547 0 : auto ry = ((int)std::round(s_pos.y / (float)map.GetSectorsSize())) + 25;
548 :
549 0 : if ((rx > 0) && (rx < map.GetSectorsCount() + 25) && (ry > 0) &&
550 0 : (ry < map.GetSectorsCount() + 25)) {
551 0 : for (int j = 0; j < map.GetSector(rx, ry).polygons.size(); j++) {
552 0 : auto poly = map.GetSector(rx, ry).polygons[j] - 1;
553 0 : auto polytype = map.GetPolygons()[poly].polygon_type;
554 :
555 0 : if (polytype != PMSPolygonType::NoCollide &&
556 : polytype != PMSPolygonType::OnlyBulletsCollide) {
557 0 : for (int k = 0; k < 2; k++) { // TODO: czy tu powinno być k < 3?
558 0 : auto norm = glm::vec2(map.GetPolygons()[poly].perpendiculars[k].x,
559 0 : map.GetPolygons()[poly].perpendiculars[k].y);
560 0 : norm *= -PhysicsConstants::SOLDIER_COL_RADIUS;
561 :
562 0 : auto pos = s_pos + norm;
563 :
564 0 : if (map.PointInPolyEdges(pos.x, pos.y, poly)) {
565 0 : if (!has_collided) {
566 0 : HandleSpecialPolytypes(map, polytype, soldier);
567 : }
568 0 : auto d = 0.0f;
569 0 : auto b = 0;
570 0 : auto perp = map.ClosestPerpendicular(poly, pos, &d, &b);
571 :
572 0 : auto p1 = glm::vec2(0.0, 0.0);
573 0 : auto p2 = glm::vec2(0.0, 0.0);
574 0 : switch (b) {
575 0 : case 1: {
576 0 : p1 = glm::vec2(map.GetPolygons()[poly].vertices[0].x,
577 0 : map.GetPolygons()[poly].vertices[0].y);
578 0 : p2 = glm::vec2(map.GetPolygons()[poly].vertices[1].x,
579 0 : map.GetPolygons()[poly].vertices[1].y);
580 0 : break;
581 : }
582 0 : case 2: {
583 0 : p1 = glm::vec2(map.GetPolygons()[poly].vertices[1].x,
584 0 : map.GetPolygons()[poly].vertices[1].y);
585 0 : p2 = glm::vec2(map.GetPolygons()[poly].vertices[2].x,
586 0 : map.GetPolygons()[poly].vertices[2].y);
587 0 : break;
588 : }
589 0 : case 3: {
590 0 : p1 = glm::vec2(map.GetPolygons()[poly].vertices[2].x,
591 0 : map.GetPolygons()[poly].vertices[2].y);
592 0 : p2 = glm::vec2(map.GetPolygons()[poly].vertices[0].x,
593 0 : map.GetPolygons()[poly].vertices[0].y);
594 0 : break;
595 : }
596 : }
597 :
598 0 : auto p3 = pos;
599 0 : d = Calc::PointLineDistance(p1, p2, p3);
600 0 : perp *= d;
601 :
602 0 : soldier.particle.position = soldier.particle.old_position;
603 0 : soldier.particle.velocity_ = soldier.particle.GetForce() - perp;
604 0 : physics_events.soldier_collides_with_polygon.Notify(
605 0 : soldier, map.GetPolygons()[poly]);
606 :
607 0 : return true;
608 : }
609 : }
610 : }
611 : }
612 : }
613 : }
614 :
615 0 : return false;
616 : }
617 :
618 0 : bool CheckSkeletonMapCollision(Soldier& soldier, const Map& map, unsigned int i, float x, float y)
619 : {
620 0 : auto result = false;
621 0 : auto pos = glm::vec2(x - 1.0f, y + 4.0f);
622 0 : auto rx = ((int)std::round(pos.x / (float)map.GetSectorsSize())) + 25;
623 0 : auto ry = ((int)std::round(pos.y / (float)map.GetSectorsSize())) + 25;
624 :
625 0 : if ((rx > 0) && (rx < map.GetSectorsCount() + 25) && (ry > 0) &&
626 0 : (ry < map.GetSectorsCount() + 25)) {
627 0 : for (int j = 0; j < map.GetSector(rx, ry).polygons.size(); j++) {
628 0 : auto poly = map.GetSector(rx, ry).polygons[j] - 1;
629 :
630 0 : if (map.PointInPolyEdges(pos.x, pos.y, poly)) {
631 0 : auto dist = 0.0f;
632 0 : auto b = 0;
633 0 : auto perp = map.ClosestPerpendicular(poly, pos, &dist, &b);
634 0 : perp = Calc::Vec2Normalize(perp);
635 0 : perp *= dist;
636 :
637 0 : soldier.skeleton->SetPos(i, soldier.skeleton->GetOldPos(i) - perp);
638 :
639 0 : result = true;
640 : }
641 : }
642 : }
643 :
644 0 : if (result) {
645 0 : auto pos = glm::vec2(x, y + 1.0);
646 0 : auto rx = ((int)std::round(pos.x / (float)map.GetSectorsSize())) + 25;
647 0 : auto ry = ((int)std::round(pos.y / (float)map.GetSectorsSize())) + 25;
648 :
649 0 : if ((rx > 0) && (rx < map.GetSectorsCount() + 25) && (ry > 0) &&
650 0 : (ry < map.GetSectorsCount() + 25)) {
651 0 : for (int j = 0; j < map.GetSector(rx, ry).polygons.size(); j++) {
652 0 : auto poly = map.GetSector(rx, ry).polygons[j] - 1;
653 : // if (Map.PolyType[poly] <> POLY_TYPE_DOESNT) and (Map.PolyType[poly] <>
654 : // POLY_TYPE_ONLY_BULLETS) then
655 0 : if (map.PointInPolyEdges(pos.x, pos.y, poly)) {
656 0 : auto dist = 0.0F;
657 0 : auto b = 0;
658 0 : auto perp = map.ClosestPerpendicular(poly, pos, &dist, &b);
659 0 : perp = Calc::Vec2Normalize(perp);
660 0 : perp *= dist;
661 :
662 0 : soldier.skeleton->SetPos(i, soldier.skeleton->GetOldPos(i) - perp);
663 :
664 0 : result = true;
665 : }
666 : }
667 : }
668 : }
669 :
670 0 : return result;
671 : }
672 :
673 0 : void Fire(Soldier& soldier, std::vector<BulletParams>& bullet_emitter)
674 : {
675 0 : auto weapon = GetPrimaryWeapon(soldier);
676 :
677 : glm::vec2 dir;
678 0 : if (weapon.GetWeaponParameters().bullet_style == BulletType::Blade ||
679 0 : soldier.body_animation->GetType() == AnimationType::Mercy ||
680 0 : soldier.body_animation->GetType() == AnimationType::Mercy2) {
681 0 : dir = Calc::Vec2Normalize(soldier.skeleton->GetPos(15) - soldier.skeleton->GetPos(16));
682 : } else {
683 0 : auto aim_x = (float)soldier.control.mouse_aim_x;
684 0 : auto aim_y = (float)soldier.control.mouse_aim_y;
685 0 : dir = Calc::Vec2Normalize(glm::vec2(aim_x, aim_y) - soldier.skeleton->GetPos(15));
686 : };
687 :
688 0 : auto pos = soldier.skeleton->GetPos(15) + dir * 4.0F - glm::vec2(0.0, 2.0);
689 0 : auto bullet_velocity = dir * weapon.GetWeaponParameters().speed;
690 : auto inherited_velocity =
691 0 : soldier.particle.velocity_ * weapon.GetWeaponParameters().inherited_velocity;
692 :
693 0 : BulletParams params{
694 0 : weapon.GetWeaponParameters().bullet_style,
695 0 : weapon.GetWeaponParameters().kind,
696 : pos,
697 0 : bullet_velocity + inherited_velocity,
698 0 : (std::int16_t)weapon.GetWeaponParameters().timeout,
699 0 : weapon.GetWeaponParameters().hit_multiply,
700 : TeamType::None,
701 0 : soldier.id,
702 0 : };
703 :
704 0 : switch (weapon.GetWeaponParameters().kind) {
705 0 : case WeaponType::DesertEagles: {
706 0 : if (!soldier.is_shooting) {
707 0 : bullet_emitter.push_back(params);
708 :
709 0 : auto signx = dir.x > 0.0F ? 1.0F : (dir.x < 0.0F ? -1.0F : 0.0F);
710 0 : auto signy = dir.x > 0.0F ? 1.0F : (dir.x < 0.0F ? -1.0F : 0.0F);
711 :
712 0 : params.position += glm::vec2(-signx * dir.y, signy * dir.x) * 3.0F;
713 0 : bullet_emitter.push_back(params);
714 : }
715 0 : break;
716 : }
717 0 : case WeaponType::Spas12:
718 : case WeaponType::Flamer:
719 : case WeaponType::NoWeapon:
720 : case WeaponType::Knife:
721 : case WeaponType::Chainsaw:
722 0 : break;
723 0 : case WeaponType::LAW: {
724 0 : if ((soldier.on_ground || soldier.on_ground_permanent || soldier.on_ground_for_law) &&
725 0 : (((soldier.legs_animation->GetType() == AnimationType::Crouch &&
726 0 : soldier.legs_animation->GetFrame() > 13) ||
727 0 : soldier.legs_animation->GetType() == AnimationType::CrouchRun ||
728 0 : soldier.legs_animation->GetType() == AnimationType::CrouchRunBack) ||
729 0 : (soldier.legs_animation->GetType() == AnimationType::Prone &&
730 0 : soldier.legs_animation->GetFrame() > 23))) {
731 0 : bullet_emitter.push_back(params);
732 : }
733 0 : break;
734 : }
735 0 : default: {
736 0 : bullet_emitter.push_back(params);
737 : }
738 : };
739 :
740 0 : soldier.is_shooting = true;
741 0 : }
742 : } // namespace Soldank::SoldierPhysics
|