1 /************************************************************************************
2
3 AstroMenace
4 Hardcore 3D space scroll-shooter with spaceship upgrade possibilities.
5 Copyright (c) 2006-2019 Mikhail Kurinnoi, Viewizard
6
7
8 AstroMenace is free software: you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 3 of the License, or
11 (at your option) any later version.
12
13 AstroMenace is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with AstroMenace. If not, see <https://www.gnu.org/licenses/>.
20
21
22 Website: https://viewizard.com/
23 Project: https://github.com/viewizard/astromenace
24 E-mail: viewizard@viewizard.com
25
26 *************************************************************************************/
27
28 // TODO codestyle should be fixed
29
30 // TODO a lot of code duplication, should be fixed
31
32 #include "space_ship.h"
33 #include "functions.h"
34 #include "../weapon/functions.h"
35 #include "../projectile/projectile.h"
36 #include "../../game.h"
37 #include "../../config/config.h"
38 #include "../../script/script.h"
39 #include "../../game/camera.h"
40
41 // NOTE switch to nested namespace definition (namespace A::B::C { ... }) (since C++17)
42 namespace viewizard {
43 namespace astromenace {
44
45 namespace {
46
47 // all ship list
48 std::list<std::shared_ptr<cSpaceShip>> ShipList{};
49
50 } // unnamed namespace
51
52 // FIXME should be fixed, don't allow global scope interaction for local variables
53 extern bool PlayerFighterLeftEng;
54 extern bool PlayerFighterRightEng;
55
56
57 /*
58 * Create cAlienSpaceFighter object.
59 */
CreateAlienSpaceFighter(const int SpaceShipNum)60 std::weak_ptr<cSpaceShip> CreateAlienSpaceFighter(const int SpaceShipNum)
61 {
62 // NOTE emplace_front() return reference to the inserted element (since C++17)
63 // this two lines could be combined
64 ShipList.emplace_front(new cAlienSpaceFighter{SpaceShipNum}, [](cAlienSpaceFighter *p) {delete p;});
65 return ShipList.front();
66 }
67
68 /*
69 * Create cAlienSpaceMotherShip object.
70 */
CreateAlienSpaceMotherShip(const int SpaceShipNum)71 std::weak_ptr<cSpaceShip> CreateAlienSpaceMotherShip(const int SpaceShipNum)
72 {
73 // NOTE emplace_front() return reference to the inserted element (since C++17)
74 // this two lines could be combined
75 ShipList.emplace_front(new cAlienSpaceMotherShip{SpaceShipNum}, [](cAlienSpaceMotherShip *p) {delete p;});
76 return ShipList.front();
77 }
78
79 /*
80 * Create cEarthSpaceFighter object.
81 */
CreateEarthSpaceFighter(const int SpaceShipNum)82 std::weak_ptr<cSpaceShip> CreateEarthSpaceFighter(const int SpaceShipNum)
83 {
84 ShipList.emplace_front(new cEarthSpaceFighter{SpaceShipNum}, [](cEarthSpaceFighter *p) {delete p;});
85
86 std::weak_ptr<cSpaceShip> tmpSpaceShip = ShipList.front();
87
88 SetEarthSpaceFighterEngine(tmpSpaceShip, 1);
89 for (unsigned int i = 0; i < ShipList.front()->Engines.size(); i++) {
90 if (auto sharedEngine = ShipList.front()->Engines[i].lock()) {
91 // находим кол-во внутренних источников света
92 if (!sharedEngine->Light.expired())
93 ShipList.front()->InternalLights++;
94 }
95 }
96
97 // default armor
98 SetEarthSpaceFighterArmor(tmpSpaceShip, 0);
99
100 return ShipList.front();
101 }
102
103 /*
104 * Create cPirateShip object.
105 */
CreatePirateShip(const int SpaceShipNum)106 std::weak_ptr<cSpaceShip> CreatePirateShip(const int SpaceShipNum)
107 {
108 // NOTE emplace_front() return reference to the inserted element (since C++17)
109 // this two lines could be combined
110 ShipList.emplace_front(new cPirateShip{SpaceShipNum}, [](cPirateShip *p) {delete p;});
111 return ShipList.front();
112 }
113
114 /*
115 * Update and remove (erase) dead objects.
116 */
UpdateAllSpaceShip(float Time)117 void UpdateAllSpaceShip(float Time)
118 {
119 // NOTE use std::erase_if here (since C++20)
120 for (auto iter = ShipList.begin(); iter != ShipList.end();) {
121 if (!iter->get()->Update(Time))
122 iter = ShipList.erase(iter);
123 else
124 ++iter;
125 }
126 }
127
128 /*
129 * Draw all objects.
130 */
DrawAllSpaceShips(bool VertexOnlyPass,unsigned int ShadowMap)131 void DrawAllSpaceShips(bool VertexOnlyPass, unsigned int ShadowMap)
132 {
133 for (auto &tmpShip : ShipList) {
134 tmpShip.get()->Draw(VertexOnlyPass, ShadowMap);
135 }
136 }
137
138 /*
139 * Release particular space ship.
140 */
ReleaseSpaceShip(std::weak_ptr<cSpaceShip> & Ship)141 void ReleaseSpaceShip(std::weak_ptr<cSpaceShip> &Ship)
142 {
143 auto sharedObject = Ship.lock();
144 if (!sharedObject)
145 return;
146
147 for (auto iter = ShipList.begin(); iter != ShipList.end();) {
148 if (iter->get() == sharedObject.get()) {
149 ShipList.erase(iter);
150 return;
151 }
152 ++iter;
153 }
154 }
155
156 /*
157 * Release all objects.
158 */
ReleaseAllSpaceShips()159 void ReleaseAllSpaceShips()
160 {
161 ShipList.clear();
162 }
163
164 /*
165 * Cycle for each space ship.
166 * Note, caller must guarantee, that 'Object' will not released in callback function call.
167 */
ForEachSpaceShip(std::function<void (cSpaceShip & Object)> function)168 void ForEachSpaceShip(std::function<void (cSpaceShip &Object)> function)
169 {
170 for (auto &tmpShip : ShipList) {
171 function(*tmpShip);
172 }
173 }
174
175 /*
176 * Managed cycle for each space ship.
177 * Note, caller must guarantee, that 'Object' will not released in callback function call.
178 */
ForEachSpaceShip(std::function<void (cSpaceShip & Object,eShipCycle & Command)> function)179 void ForEachSpaceShip(std::function<void (cSpaceShip &Object, eShipCycle &Command)> function)
180 {
181 // NOTE use std::erase_if here (since C++20)
182 for (auto iter = ShipList.begin(); iter != ShipList.end();) {
183 eShipCycle Command{eShipCycle::Continue};
184 function(*iter->get(), Command);
185
186 switch (Command) {
187 case eShipCycle::Continue:
188 ++iter;
189 break;
190 case eShipCycle::Break:
191 return;
192 case eShipCycle::DeleteObjectAndContinue:
193 iter = ShipList.erase(iter);
194 break;
195 case eShipCycle::DeleteObjectAndBreak:
196 ShipList.erase(iter);
197 return;
198 }
199 }
200 }
201
202 /*
203 * Managed cycle for each space ship pair.
204 * Note, caller must guarantee, that 'FirstObject' and 'SecondObject' will not released in callback function call.
205 */
ForEachSpaceShipPair(std::function<void (cSpaceShip & FirstObject,cSpaceShip & SecondObject,eShipPairCycle & Command)> function)206 void ForEachSpaceShipPair(std::function<void (cSpaceShip &FirstObject,
207 cSpaceShip &SecondObject,
208 eShipPairCycle &Command)> function)
209 {
210 for (auto iterFirst = ShipList.begin(); iterFirst != ShipList.end();) {
211 eShipPairCycle Command{eShipPairCycle::Continue};
212
213 for (auto iterSecond = std::next(iterFirst, 1); iterSecond != ShipList.end();) {
214 Command = eShipPairCycle::Continue;
215 function(*iterFirst->get(), *iterSecond->get(), Command);
216
217 // NOTE (?) use std::erase_if here (since C++20)
218 if ((Command == eShipPairCycle::DeleteSecondObjectAndContinue) ||
219 (Command == eShipPairCycle::DeleteBothObjectsAndContinue))
220 iterSecond = ShipList.erase(iterSecond);
221 else
222 ++iterSecond;
223
224 // break second cycle
225 if ((Command == eShipPairCycle::DeleteFirstObjectAndContinue) ||
226 (Command == eShipPairCycle::DeleteBothObjectsAndContinue))
227 break;
228 }
229
230 // NOTE (?) use std::erase_if here (since C++20)
231 if ((Command == eShipPairCycle::DeleteFirstObjectAndContinue) ||
232 (Command == eShipPairCycle::DeleteBothObjectsAndContinue))
233 iterFirst = ShipList.erase(iterFirst);
234 else
235 ++iterFirst;
236 }
237 }
238
239 /*
240 * Get object ptr by reference.
241 */
GetSpaceShipPtr(const cSpaceShip & Object)242 std::weak_ptr<cObject3D> GetSpaceShipPtr(const cSpaceShip &Object)
243 {
244 for (auto &tmpShip : ShipList) {
245 if (tmpShip.get() == &Object)
246 return tmpShip;
247 }
248
249 return std::weak_ptr<cObject3D>{};
250 }
251
252 /*
253 * Destructor.
254 */
~cSpaceShip()255 cSpaceShip::~cSpaceShip()
256 {
257 for (auto &tmpEngine : Engines) {
258 if (auto sharedEngine = tmpEngine.lock()) {
259 if (!EngineDestroyType) {
260 sharedEngine->IsSuppressed = true;
261 sharedEngine->DestroyIfNoParticles = true;
262 } else
263 vw_ReleaseParticleSystem(sharedEngine);
264 }
265 }
266
267 if (!EnginesLeft.empty()) {
268 for (auto &tmpEngineLeft : EnginesLeft) {
269 if (auto sharedEngineLeft = tmpEngineLeft.lock()) {
270 if (!EngineDestroyType) {
271 sharedEngineLeft->IsSuppressed = true;
272 sharedEngineLeft->DestroyIfNoParticles = true;
273 } else
274 vw_ReleaseParticleSystem(sharedEngineLeft);
275 }
276 }
277 }
278
279 if (!EnginesRight.empty()) {
280 for (auto &tmpEngineRight : EnginesRight) {
281 if (auto sharedEngineRight = tmpEngineRight.lock()) {
282 if (!EngineDestroyType) {
283 sharedEngineRight->IsSuppressed = true;
284 sharedEngineRight->DestroyIfNoParticles = true;
285 } else
286 vw_ReleaseParticleSystem(sharedEngineRight);
287 }
288 }
289 }
290 }
291
292 /*
293 * Set location.
294 */
SetLocation(const sVECTOR3D & NewLocation)295 void cSpaceShip::SetLocation(const sVECTOR3D &NewLocation)
296 {
297 cObject3D::SetLocation(NewLocation);
298
299 if (!WeaponSlots.empty()) {
300 for (auto &tmpWeaponSlot : WeaponSlots) {
301 if (auto sharedWeapon = tmpWeaponSlot.Weapon.lock())
302 sharedWeapon->SetLocation(tmpWeaponSlot.Location + NewLocation);
303 }
304 }
305
306 if (!BossWeaponSlots.empty()) {
307 for (auto &tmpBossWeaponSlot : BossWeaponSlots) {
308 if (auto sharedWeapon = tmpBossWeaponSlot.Weapon.lock())
309 sharedWeapon->SetLocation(tmpBossWeaponSlot.Location + NewLocation);
310 }
311 }
312
313 if (!FlareWeaponSlots.empty()) {
314 for (auto &tmpFlareWeaponSlot : FlareWeaponSlots) {
315 if (auto sharedWeapon = tmpFlareWeaponSlot.Weapon.lock())
316 sharedWeapon->SetLocation(tmpFlareWeaponSlot.Location + NewLocation);
317 }
318 }
319
320 for (unsigned int i = 0; i < Engines.size(); i++) {
321 if (auto sharedEngine = Engines[i].lock()) {
322 sharedEngine->MoveSystem(NewLocation + EnginesLocation[i]);
323 sharedEngine->SetStartLocation(EnginesLocation[i] + NewLocation);
324 }
325 }
326
327 if (!EnginesLeft.empty()) {
328 for (unsigned int i = 0; i < EnginesLeft.size(); i++) {
329 if (auto sharedEngineLeft = EnginesLeft[i].lock()) {
330 sharedEngineLeft->MoveSystem(NewLocation + EnginesLeftLocation[i]);
331 sharedEngineLeft->SetStartLocation(EnginesLeftLocation[i] + NewLocation);
332 }
333 }
334 }
335
336 if (!EnginesRight.empty()) {
337 for (unsigned int i = 0; i < EnginesRight.size(); i++) {
338 if (auto sharedEngineRight = EnginesRight[i].lock()) {
339 sharedEngineRight->MoveSystem(NewLocation + EnginesRightLocation[i]);
340 sharedEngineRight->SetStartLocation(EnginesRightLocation[i] + NewLocation);
341 }
342 }
343 }
344 }
345
346 /*
347 * Set location.
348 */
SetLocationArcadePlayer(const sVECTOR3D & NewLocation)349 void cSpaceShip::SetLocationArcadePlayer(const sVECTOR3D &NewLocation)
350 {
351 cObject3D::SetLocation(NewLocation);
352
353 if (!WeaponSlots.empty()) {
354 for (auto &tmpWeaponSlot : WeaponSlots) {
355 if (auto sharedWeapon = tmpWeaponSlot.Weapon.lock())
356 sharedWeapon->SetLocation(tmpWeaponSlot.Location + NewLocation);
357 }
358 }
359
360 if (!BossWeaponSlots.empty()) {
361 for (auto &tmpBossWeaponSlot : BossWeaponSlots) {
362 if (auto sharedWeapon = tmpBossWeaponSlot.Weapon.lock())
363 sharedWeapon->SetLocation(tmpBossWeaponSlot.Location + NewLocation);
364 }
365 }
366
367 if (!FlareWeaponSlots.empty()) {
368 for (auto &tmpFlareWeaponSlot : FlareWeaponSlots) {
369 if (auto sharedWeapon = tmpFlareWeaponSlot.Weapon.lock())
370 sharedWeapon->SetLocation(tmpFlareWeaponSlot.Location + NewLocation);
371 }
372 }
373
374 for (unsigned int i = 0; i < Engines.size(); i++) {
375 if (auto sharedEngine = Engines[i].lock()) {
376 sharedEngine->MoveSystem(NewLocation + EnginesLocation[i]);
377 sharedEngine->SetStartLocation(NewLocation + EnginesLocation[i]);
378 }
379 }
380
381 if (!EnginesLeft.empty()) {
382 for (unsigned int i = 0; i < EnginesLeft.size(); i++) {
383 if (auto sharedEngineLeft = EnginesLeft[i].lock()) {
384 sharedEngineLeft->MoveSystem(NewLocation + EnginesLeftLocation[i]);
385 sharedEngineLeft->SetStartLocation(NewLocation + EnginesLeftLocation[i]);
386 }
387 }
388 }
389
390 if (!EnginesRight.empty()) {
391 for (unsigned int i = 0; i < EnginesRight.size(); i++) {
392 if (auto sharedEngineRight = EnginesRight[i].lock()) {
393 sharedEngineRight->MoveSystem(NewLocation + EnginesRightLocation[i]);
394 sharedEngineRight->SetStartLocation(NewLocation + EnginesRightLocation[i]);
395 }
396 }
397 }
398 }
399
400 /*
401 * Set rotation.
402 */
SetRotation(const sVECTOR3D & NewRotation)403 void cSpaceShip::SetRotation(const sVECTOR3D &NewRotation)
404 {
405 cObject3D::SetRotation(NewRotation);
406
407 if (!WeaponSlots.empty()) {
408 for (auto &tmpWeaponSlot : WeaponSlots) {
409 vw_Matrix33CalcPoint(tmpWeaponSlot.Location, OldInvRotationMat);
410 vw_Matrix33CalcPoint(tmpWeaponSlot.Location, CurrentRotationMat);
411
412 if (auto sharedWeapon = tmpWeaponSlot.Weapon.lock()) {
413 sharedWeapon->SetRotation(NewRotation);
414 sharedWeapon->SetLocation(Location + tmpWeaponSlot.Location);
415 }
416 }
417 }
418
419 if (!BossWeaponSlots.empty()) {
420 for (auto &tmpBossWeaponSlot : BossWeaponSlots) {
421 vw_Matrix33CalcPoint(tmpBossWeaponSlot.Location, OldInvRotationMat);
422 vw_Matrix33CalcPoint(tmpBossWeaponSlot.Location, CurrentRotationMat);
423
424 if (auto sharedWeapon = tmpBossWeaponSlot.Weapon.lock()) {
425 sharedWeapon->SetRotation(NewRotation);
426 sharedWeapon->SetLocation(Location + tmpBossWeaponSlot.Location);
427 }
428 }
429 }
430
431 if (!FlareWeaponSlots.empty()) {
432 for (auto &tmpFlareWeaponSlot : FlareWeaponSlots) {
433 vw_Matrix33CalcPoint(tmpFlareWeaponSlot.Location, OldInvRotationMat);
434 vw_Matrix33CalcPoint(tmpFlareWeaponSlot.Location, CurrentRotationMat);
435
436 if (auto sharedWeapon = tmpFlareWeaponSlot.Weapon.lock()) {
437 sharedWeapon->SetRotation(NewRotation);
438 sharedWeapon->SetLocation(Location + tmpFlareWeaponSlot.Location);
439 }
440 }
441 }
442
443 for (unsigned int i = 0; i < Engines.size(); i++) {
444 vw_Matrix33CalcPoint(EnginesLocation[i], OldInvRotationMat);
445 vw_Matrix33CalcPoint(EnginesLocation[i], CurrentRotationMat);
446
447 if (auto sharedEngine = Engines[i].lock()) {
448 if (sharedEngine->SpeedOnCreation == -1.0f) {
449 sharedEngine->MoveSystem(EnginesLocation[i] + Location);
450 sharedEngine->SetStartLocation(EnginesLocation[i] + Location);
451 sharedEngine->RotateSystemAndParticlesByAngle(Rotation);
452 } else {
453 sharedEngine->MoveSystemLocation(EnginesLocation[i] + Location);
454 sharedEngine->RotateSystemByAngle(Rotation);
455 }
456 }
457 }
458 if (!EnginesLeft.empty()) {
459 for (unsigned int i = 0; i < EnginesLeft.size(); i++) {
460 vw_Matrix33CalcPoint(EnginesLeftLocation[i], OldInvRotationMat);
461 vw_Matrix33CalcPoint(EnginesLeftLocation[i], CurrentRotationMat);
462
463 if (auto sharedEngineLeft = EnginesLeft[i].lock()) {
464 sharedEngineLeft->MoveSystemLocation(EnginesLeftLocation[i] + Location);
465 sharedEngineLeft->SetStartLocation(EnginesLeftLocation[i] + Location);
466 sharedEngineLeft->RotateSystemByAngle(Rotation);
467 }
468 }
469 }
470 if (!EnginesRight.empty()) {
471 for (unsigned int i = 0; i < EnginesRight.size(); i++) {
472 vw_Matrix33CalcPoint(EnginesRightLocation[i], OldInvRotationMat);
473 vw_Matrix33CalcPoint(EnginesRightLocation[i], CurrentRotationMat);
474
475 if (auto sharedEngineRight = EnginesRight[i].lock()) {
476 sharedEngineRight->MoveSystemLocation(EnginesRightLocation[i] + Location);
477 sharedEngineRight->SetStartLocation(EnginesRightLocation[i] + Location);
478 sharedEngineRight->RotateSystemByAngle(Rotation);
479 }
480 }
481 }
482 }
483
484 /*
485 * Update.
486 */
Update(float Time)487 bool cSpaceShip::Update(float Time)
488 {
489 if (!cObject3D::Update(Time))
490 return false;
491
492 if (TimeDelta == 0.0f)
493 return true;
494
495 if (!TimeSheetList.empty() &&
496 !TimeSheetList.front().InUse) {
497 TimeSheetList.front().InUse = true;
498
499 NeedSpeed = TimeSheetList.front().Speed;
500 NeedAcceler = TimeSheetList.front().Acceler;
501 NeedSpeedLR = TimeSheetList.front().SpeedLR;
502 NeedAccelerLR = TimeSheetList.front().AccelerLR;
503 NeedSpeedUD = TimeSheetList.front().SpeedUD;
504 NeedAccelerUD = TimeSheetList.front().AccelerUD;
505
506 NeedSpeedByCamFB = TimeSheetList.front().SpeedByCamFB;
507 NeedAccelerByCamFB = TimeSheetList.front().AccelerByCamFB;
508 NeedSpeedByCamLR = TimeSheetList.front().SpeedByCamLR;
509 NeedAccelerByCamLR = TimeSheetList.front().AccelerByCamLR;
510 NeedSpeedByCamUD = TimeSheetList.front().SpeedByCamUD;
511 NeedAccelerByCamUD = TimeSheetList.front().AccelerByCamUD;
512
513 NeedRotate = TimeSheetList.front().Rotation;
514 RotationSpeed = TimeSheetList.front().RotationAcceler;
515
516 if (!WeaponSlots.empty()) {
517 for (auto &tmpWeaponSlot : WeaponSlots) {
518 if (!tmpWeaponSlot.Weapon.expired())
519 tmpWeaponSlot.SetFire = TimeSheetList.front().Fire;
520 }
521 }
522 if (!BossWeaponSlots.empty()) {
523 for (auto &tmpBossWeaponSlot : BossWeaponSlots) {
524 if (!tmpBossWeaponSlot.Weapon.expired())
525 tmpBossWeaponSlot.SetFire = TimeSheetList.front().BossFire;
526 }
527 }
528 }
529
530 if (!FlareWeaponSlots.empty()) {
531 bool NeedFlare{false};
532 ForEachProjectile([&] (cProjectile &Projectile) {
533 // homing missile or homing mine targeted on this ship
534 auto sharedTarget = Projectile.Target.lock();
535 if (sharedTarget.get() == this) {
536 NeedFlare = true;
537 Projectile.Target.reset(); // reset target, since we will fire flares
538 }
539 });
540
541 if (NeedFlare) {
542 for (auto &tmpFlareWeaponSlot : FlareWeaponSlots) {
543 if (auto sharedWeapon = tmpFlareWeaponSlot.Weapon.lock())
544 sharedWeapon->WeaponFire(Time);
545 }
546 }
547 }
548
549 if (ObjectStatus == eObjectStatus::Player) {
550 if ((MoveForward > 0.0f) ||
551 (MoveBackward > 0.0f)) {
552 NeedSpeed = MaxSpeed * MoveForward - MaxSpeed * MoveBackward;
553 } else
554 NeedSpeed = 0.0f;
555
556 if ((MoveLeft > 0.0f) ||
557 (MoveRight > 0.0f)) {
558 NeedRotate.y = MaxAcceler * MaxSpeed * MoveRight - MaxAcceler * MaxSpeed * MoveLeft;
559 } else
560 NeedRotate.y = 0.0f;
561
562 if ((MoveUp > 0.0f) ||
563 (MoveDown > 0.0f)) {
564 NeedRotate.x = MaxAcceler * MaxSpeed * MoveUp - MaxAcceler * MaxSpeed * MoveDown;
565 } else
566 NeedRotate.x = 0.0f;
567 }
568
569 if (ObjectStatus != eObjectStatus::Player) {
570
571 if (!EnginesLeft.empty()) {
572 for (auto &tmpEngineLeft : EnginesLeft) {
573 if (auto sharedEngineLeft = tmpEngineLeft.lock())
574 sharedEngineLeft->IsSuppressed = true;
575 }
576 }
577 if (!EnginesRight.empty()) {
578 for (auto &tmpEngineRight : EnginesRight) {
579 if (auto sharedEngineRight = tmpEngineRight.lock())
580 sharedEngineRight->IsSuppressed = true;
581 }
582 }
583
584 if ((NeedRotate.x != 0.0f) ||
585 (NeedRotate.y != 0.0f) ||
586 (NeedRotate.z != 0.0f)) {
587 sVECTOR3D tmpRotate(0.0f, 0.0f, 0.0f);
588
589 if (NeedRotate.x != 0.0f) {
590 float Sign{1.0f};
591 if (NeedRotate.x < 0.0f)
592 Sign = -1.0f;
593
594 tmpRotate.x = Sign * MaxSpeedRotate * RotationSpeed.x * TimeDelta;
595
596 if (Sign == 1.0f) {
597 if (tmpRotate.x >= NeedRotate.x) {
598 tmpRotate.x = NeedRotate.x;
599 NeedRotate.x = 0.0f;
600 }
601 } else {
602 if (tmpRotate.x <= NeedRotate.x) {
603 tmpRotate.x = NeedRotate.x;
604 NeedRotate.x = 0.0f;
605 }
606 }
607
608 if (NeedRotate.x != 0.0f)
609 NeedRotate.x -= tmpRotate.x;
610 }
611
612 if (NeedRotate.y != 0.0f) {
613 float Sign{1.0f};
614 if (NeedRotate.y < 0.0f)
615 Sign = -1.0f;
616
617 tmpRotate.y = Sign * MaxSpeedRotate * RotationSpeed.y * TimeDelta;
618
619 if (Sign == 1.0f) {
620 if (tmpRotate.y >= NeedRotate.y) {
621 tmpRotate.y = NeedRotate.y;
622 NeedRotate.y = 0.0f;
623 }
624 } else {
625 if (tmpRotate.y <= NeedRotate.y) {
626 tmpRotate.y = NeedRotate.y;
627 NeedRotate.y = 0.0f;
628 }
629 }
630
631 if (NeedRotate.y != 0.0f)
632 NeedRotate.y -= tmpRotate.y;
633
634 if (NeedRotate.y < 0.0f) {
635 if (!EnginesLeft.empty()) {
636 for (auto &tmpEngineLeft : EnginesLeft) {
637 if (auto sharedEngineLeft = tmpEngineLeft.lock())
638 sharedEngineLeft->IsSuppressed = false;
639 }
640 }
641 } else {
642 if (!EnginesRight.empty()) {
643 for (auto &tmpEngineRight : EnginesRight) {
644 if (auto sharedEngineRight = tmpEngineRight.lock())
645 sharedEngineRight->IsSuppressed = false;
646 }
647 }
648 }
649 }
650
651 if (NeedRotate.z != 0.0f) {
652 float Sign{1.0f};
653 if (NeedRotate.z < 0.0f)
654 Sign = -1.0f;
655
656 tmpRotate.z = Sign * MaxSpeedRotate * RotationSpeed.z * TimeDelta;
657
658 if (Sign == 1.0f) {
659 if (tmpRotate.z >= NeedRotate.z) {
660 tmpRotate.z = NeedRotate.z;
661 NeedRotate.z = 0.0f;
662 }
663 } else {
664 if (tmpRotate.z <= NeedRotate.z) {
665 tmpRotate.z = NeedRotate.z;
666 NeedRotate.z = 0.0f;
667 }
668 }
669
670 if (NeedRotate.z != 0.0f)
671 NeedRotate.z -= tmpRotate.z;
672 }
673
674 SetRotation(tmpRotate);
675
676 }
677 } else {
678 if (!EnginesLeft.empty()) {
679 for (auto &tmpEngineLeft : EnginesLeft) {
680 if (auto sharedEngineLeft = tmpEngineLeft.lock())
681 sharedEngineLeft->IsSuppressed = !PlayerFighterLeftEng;
682 }
683 }
684 if (!EnginesRight.empty()) {
685 for (auto &tmpEngineRight : EnginesRight) {
686 if (auto sharedEngineRight = tmpEngineRight.lock())
687 sharedEngineRight->IsSuppressed = !PlayerFighterRightEng;
688 }
689 }
690 }
691
692 if ((NeedSpeed != 0.0f) ||
693 ((ObjectStatus == eObjectStatus::Player) && (Speed != 0.0f))) {
694 float Sign{1.0f};
695 if (NeedSpeed < 0.0f)
696 Sign = -1.0f;
697
698 if (Sign == 1.0f)
699 vw_Clamp(NeedSpeed, 0.0f, MaxSpeed);
700 else
701 vw_Clamp(NeedSpeed, -MaxSpeed, 0.0f);
702
703 if (Sign == 1.0f) {
704 if (NeedSpeed < Speed)
705 Sign = -1.0f;
706 } else {
707 if (NeedSpeed > Speed)
708 Sign = 1.0f;
709 }
710
711 Acceler = Sign * MaxAcceler * NeedAcceler;
712 Speed = Speed + Acceler * TimeDelta;
713
714 if (Sign == 1.0f) {
715 if (NeedSpeed <= Speed) {
716 Speed = NeedSpeed;
717 NeedSpeed = 0.0f;
718 }
719 } else {
720 if (NeedSpeed >= Speed) {
721 Speed = NeedSpeed;
722 NeedSpeed = 0.0f;
723 }
724 }
725
726 if (Sign == -1.0f) {
727 if (!EnginesLeft.empty()) {
728 for (auto &tmpEngineLeft : EnginesLeft) {
729 if (auto sharedEngineLeft = tmpEngineLeft.lock())
730 sharedEngineLeft->IsSuppressed = false;
731 }
732 }
733 if (!EnginesRight.empty()) {
734 for (auto &tmpEngineRight : EnginesRight) {
735 if (auto sharedEngineRight = tmpEngineRight.lock())
736 sharedEngineRight->IsSuppressed = false;
737 }
738 }
739 }
740 }
741
742 if (NeedSpeedLR != 0.0f) {
743 float Sign{1.0f};
744 if (NeedSpeedLR < 0.0f)
745 Sign = -1.0f;
746
747 if (Sign == 1.0f) {
748 vw_Clamp(NeedSpeedLR, 0.0f, MaxSpeed);
749 } else {
750 vw_Clamp(NeedSpeedLR, -MaxSpeed, 0.0f);
751 }
752
753 if (Sign == 1.0f) {
754 if (NeedSpeedLR < SpeedLR) Sign = -1.0f;
755 } else {
756 if (NeedSpeedLR > SpeedLR) Sign = 1.0f;
757 }
758
759 AccelerLR = Sign * MaxAcceler * NeedAccelerLR;
760 SpeedLR = SpeedLR + AccelerLR * TimeDelta;
761
762 if (Sign == 1.0f) {
763 if (NeedSpeedLR <= SpeedLR) {
764 SpeedLR = NeedSpeedLR;
765 NeedSpeedLR = 0.0f;
766 }
767 } else {
768 if (NeedSpeedLR >= SpeedLR) {
769 SpeedLR = NeedSpeedLR;
770 NeedSpeedLR = 0.0f;
771 }
772 }
773 }
774
775 if (NeedSpeedUD != 0.0f) {
776 float Sign{1.0f};
777 if (NeedSpeedUD < 0.0f)
778 Sign = -1.0f;
779
780 if (Sign == 1.0f)
781 vw_Clamp(NeedSpeedUD, 0.0f, MaxSpeed);
782 else
783 vw_Clamp(NeedSpeedUD, -MaxSpeed, 0.0f);
784
785 if (Sign == 1.0f) {
786 if (NeedSpeedUD < SpeedUD)
787 Sign = -1.0f;
788 } else {
789 if (NeedSpeedUD > SpeedUD)
790 Sign = 1.0f;
791 }
792
793 AccelerUD = Sign * MaxAcceler * NeedAccelerUD;
794 SpeedUD = SpeedUD + AccelerUD * TimeDelta;
795
796 if (Sign == 1.0f) {
797 if (NeedSpeedUD <= SpeedUD) {
798 SpeedUD = NeedSpeedUD;
799 NeedSpeedUD = 0.0f;
800 }
801 } else {
802 if (NeedSpeedUD >= SpeedUD) {
803 SpeedUD = NeedSpeedUD;
804 NeedSpeedUD = 0.0f;
805 }
806 }
807 }
808
809 if (NeedSpeedByCamFB != 0.0f) {
810 float Sign{1.0f};
811 if (NeedSpeedByCamFB < 0.0f)
812 Sign = -1.0f;
813
814 if (Sign == 1.0f)
815 vw_Clamp(NeedSpeedByCamFB, 0.0f, MaxSpeed);
816 else
817 vw_Clamp(NeedSpeedByCamFB, -MaxSpeed, 0.0f);
818
819 if (Sign == 1.0f) {
820 if (NeedSpeedByCamFB < SpeedByCamFB)
821 Sign = -1.0f;
822 } else {
823 if (NeedSpeedByCamFB > SpeedByCamFB)
824 Sign = 1.0f;
825 }
826
827 AccelerByCamFB = Sign * MaxAcceler * NeedAccelerByCamFB;
828 SpeedByCamFB = SpeedByCamFB + AccelerByCamFB * TimeDelta;
829
830 if (Sign == 1.0f) {
831 if (NeedSpeedByCamFB <= SpeedByCamFB) {
832 SpeedByCamFB = NeedSpeedByCamFB;
833 NeedSpeedByCamFB = 0.0f;
834 }
835 } else {
836 if (NeedSpeedByCamFB >= SpeedByCamFB) {
837 SpeedByCamFB = NeedSpeedByCamFB;
838 NeedSpeedByCamFB = 0.0f;
839 }
840 }
841 }
842 if (NeedSpeedByCamLR != 0.0f) {
843 float Sign{1.0f};
844 if (NeedSpeedByCamLR < 0.0f)
845 Sign = -1.0f;
846
847 if (Sign == 1.0f)
848 vw_Clamp(NeedSpeedByCamLR, 0.0f, MaxSpeed);
849 else
850 vw_Clamp(NeedSpeedByCamLR, -MaxSpeed, 0.0f);
851
852 if (Sign == 1.0f) {
853 if (NeedSpeedByCamLR < SpeedByCamLR)
854 Sign = -1.0f;
855 } else {
856 if (NeedSpeedByCamLR > SpeedByCamLR)
857 Sign = 1.0f;
858 }
859
860 AccelerByCamLR = Sign * MaxAcceler * NeedAccelerByCamLR;
861 SpeedByCamLR = SpeedByCamLR + AccelerByCamLR * TimeDelta;
862
863 if (Sign == 1.0f) {
864 if (NeedSpeedByCamLR <= SpeedByCamLR) {
865 SpeedByCamLR = NeedSpeedByCamLR;
866 NeedSpeedByCamLR = 0.0f;
867 }
868 } else {
869 if (NeedSpeedByCamLR >= SpeedByCamLR) {
870 SpeedByCamLR = NeedSpeedByCamLR;
871 NeedSpeedByCamLR = 0.0f;
872 }
873 }
874 }
875
876 if (NeedSpeedByCamUD != 0.0f) {
877 float Sign{1.0f};
878 if (NeedSpeedByCamUD < 0.0f)
879 Sign = -1.0f;
880
881 if (Sign == 1.0f)
882 vw_Clamp(NeedSpeedByCamUD, 0.0f, MaxSpeed);
883 else
884 vw_Clamp(NeedSpeedByCamUD, -MaxSpeed, 0.0f);
885
886 if (Sign == 1.0f) {
887 if (NeedSpeedByCamUD < SpeedByCamUD)
888 Sign = -1.0f;
889 } else {
890 if (NeedSpeedByCamUD > SpeedByCamUD)
891 Sign = 1.0f;
892 }
893
894 AccelerByCamUD = Sign * MaxAcceler * NeedAccelerByCamUD;
895 SpeedByCamUD = SpeedByCamUD + AccelerByCamUD * TimeDelta;
896
897 if (Sign == 1.0f) {
898 if (NeedSpeedByCamUD <= SpeedByCamUD) {
899 SpeedByCamUD = NeedSpeedByCamUD;
900 NeedSpeedByCamUD = 0.0f;
901 }
902 } else {
903 if (NeedSpeedByCamUD >= SpeedByCamUD) {
904 SpeedByCamUD = NeedSpeedByCamUD;
905 NeedSpeedByCamUD = 0.0f;
906 }
907 }
908 }
909
910 if (!WeaponSlots.empty()) {
911 // volley fire
912 if ((WeaponFireType == 1) ||
913 (ObjectStatus == eObjectStatus::Player)) {
914 for (auto &tmpWeaponSlot : WeaponSlots) {
915 if (tmpWeaponSlot.SetFire)
916 if (auto sharedWeapon = tmpWeaponSlot.Weapon.lock())
917 sharedWeapon->WeaponFire(Time);
918 }
919 } else { // alternate fire
920 int PrimCount = 0;
921 float PrimTime = 0.0f;
922 unsigned FirstWeapon = WeaponSlots.size();
923 unsigned LastWeapon = 0;
924
925 WeaponGroupCurrentFireDelay -= TimeDelta;
926
927 for (unsigned i = 0; i < WeaponSlots.size(); i++) {
928 if (auto sharedWeapon = WeaponSlots[i].Weapon.lock()) {
929 PrimCount++;
930 PrimTime += sharedWeapon->NextFireTime;
931 if (FirstWeapon > i)
932 FirstWeapon = i;
933 if (LastWeapon < i)
934 LastWeapon = i;
935 }
936 }
937 if (WeaponGroupCurrentFireNum == -1)
938 WeaponGroupCurrentFireNum = FirstWeapon;
939
940 for (unsigned i = 0; i < WeaponSlots.size(); i++)
941 if (!WeaponSlots[i].Weapon.expired() &&
942 WeaponSlots[i].SetFire &&
943 (WeaponGroupCurrentFireNum == static_cast<int>(i)) &&
944 (WeaponGroupCurrentFireDelay <= 0.0f)) {
945 if (auto sharedWeapon = WeaponSlots[i].Weapon.lock())
946 sharedWeapon->WeaponFire(Time);
947
948 WeaponGroupCurrentFireDelay = PrimTime / (PrimCount * PrimCount);
949 WeaponGroupCurrentFireNum++;
950 if (WeaponGroupCurrentFireNum > static_cast<int>(LastWeapon))
951 WeaponGroupCurrentFireNum = FirstWeapon;
952
953 if (WeaponSlots[WeaponGroupCurrentFireNum].Weapon.expired()) {
954 bool exit{false};
955 while (!exit) {
956 WeaponGroupCurrentFireNum++;
957 if (WeaponGroupCurrentFireNum > static_cast<int>(LastWeapon))
958 WeaponGroupCurrentFireNum = FirstWeapon;
959 if (!WeaponSlots[WeaponGroupCurrentFireNum].Weapon.expired())
960 exit = true;
961 }
962 }
963 }
964 }
965 }
966 if (!BossWeaponSlots.empty()) {
967 if (BossWeaponFireType == 1) { // volley fire
968 for (auto &tmpBossWeaponSlot : BossWeaponSlots) {
969 if (tmpBossWeaponSlot.SetFire)
970 if (auto sharedWeapon = tmpBossWeaponSlot.Weapon.lock())
971 sharedWeapon->WeaponFire(Time);
972 }
973 } else { // alternate fire
974 int PrimCount = 0;
975 float PrimTime = 0.0f;
976 unsigned FirstWeapon = BossWeaponSlots.size();
977 unsigned LastWeapon = 0;
978
979 BossWeaponGroupCurrentFireDelay -= TimeDelta;
980
981 for (unsigned i = 0; i < BossWeaponSlots.size(); i++) {
982 if (auto sharedWeapon = BossWeaponSlots[i].Weapon.lock()) {
983 PrimCount++;
984 PrimTime += sharedWeapon->NextFireTime;
985 if (FirstWeapon > i)
986 FirstWeapon = i;
987 if (LastWeapon < i)
988 LastWeapon = i;
989 }
990 }
991 if (BossWeaponGroupCurrentFireNum == -1)
992 BossWeaponGroupCurrentFireNum = FirstWeapon;
993
994 for (unsigned i = 0; i < BossWeaponSlots.size(); i++) {
995 if (!BossWeaponSlots[i].Weapon.expired() &&
996 BossWeaponSlots[i].SetFire &&
997 (BossWeaponGroupCurrentFireNum == static_cast<int>(i)) &&
998 (BossWeaponGroupCurrentFireDelay <= 0.0f)) {
999 if (auto sharedWeapon = BossWeaponSlots[i].Weapon.lock())
1000 sharedWeapon->WeaponFire(Time);
1001
1002 BossWeaponGroupCurrentFireDelay = PrimTime / (PrimCount * PrimCount);
1003 BossWeaponGroupCurrentFireNum++;
1004 if (BossWeaponGroupCurrentFireNum > static_cast<int>(LastWeapon))
1005 BossWeaponGroupCurrentFireNum = FirstWeapon;
1006
1007 if (BossWeaponSlots[BossWeaponGroupCurrentFireNum].Weapon.expired()) {
1008 bool exit{false};
1009 while (!exit) {
1010 BossWeaponGroupCurrentFireNum++;
1011 if (BossWeaponGroupCurrentFireNum > static_cast<int>(LastWeapon))
1012 BossWeaponGroupCurrentFireNum = FirstWeapon;
1013 if (!BossWeaponSlots[BossWeaponGroupCurrentFireNum].Weapon.expired())
1014 exit = true;
1015 }
1016 }
1017 }
1018 }
1019 }
1020 }
1021
1022 if (!ShipShake.empty()) {
1023 ShipShake[0].Update(TimeDelta, [&] (const float ShakeIncrement,
1024 const sVECTOR3D &ShakeDirection,
1025 const unsigned UNUSED(ShakeChunkNum)) {
1026 SetRotation(ShakeDirection ^ (ShakeIncrement * 50.0f));
1027 });
1028 }
1029
1030 Velocity = Orientation ^ (Speed * TimeDelta);
1031 if (fabs(SpeedLR) > 0.01f) {
1032 sVECTOR3D tmp(SpeedLR * TimeDelta, 0.0f, 0.0f);
1033 vw_Matrix33CalcPoint(tmp, CurrentRotationMat);
1034 Velocity += tmp;
1035 }
1036 if (fabs(SpeedUD) > 0.01f) {
1037 sVECTOR3D tmp(0.0f, SpeedUD * TimeDelta, 0.0f);
1038 vw_Matrix33CalcPoint(tmp, CurrentRotationMat);
1039 Velocity += tmp;
1040 }
1041
1042 if (fabs(SpeedByCamFB) > 0.01f) {
1043 sVECTOR3D tmp = GetCameraMovementDirection() ^ (SpeedByCamFB * TimeDelta);
1044 Velocity += tmp;
1045 }
1046 if (fabs(SpeedByCamLR) > 0.01f) {
1047 sVECTOR3D tmp = GetCameraMovementDirection() ^ (SpeedByCamLR * TimeDelta);
1048 vw_RotatePoint(tmp, sVECTOR3D{0.0, -90.0f ,0.0f});
1049 Velocity += tmp;
1050 }
1051 if (fabs(SpeedByCamUD) > 0.01f) {
1052 sVECTOR3D tmp = GetCameraMovementDirection() ^ (SpeedByCamUD * TimeDelta);
1053 vw_RotatePoint(tmp, sVECTOR3D{90.0f, 0.0f, 0.0f});
1054 Velocity += tmp;
1055 }
1056
1057 if ((Velocity.x != 0.0f) ||
1058 (Velocity.y != 0.0f) ||
1059 (Velocity.z != 0.0f) )
1060 SetLocation(Location + Velocity);
1061
1062 if (!Engines.empty()) {
1063 float tmpSpeed = Speed;
1064 if (tmpSpeed > 6.0f)
1065 tmpSpeed = 6.0f;
1066 else if (tmpSpeed < -6.0f)
1067 tmpSpeed = -6.0f;
1068 tmpSpeed /= 2.0f;
1069
1070 for (auto &tmpEngine : Engines) {
1071 if (auto sharedEngine = tmpEngine.lock())
1072 if (sharedEngine->SpeedOnCreation != -1.0f)
1073 sharedEngine->Speed = sharedEngine->SpeedOnCreation + tmpSpeed;
1074 }
1075 }
1076
1077 bool NeedFire{false};
1078 if (!WeaponSlots.empty()) {
1079 for (auto &tmpWeaponSlot : WeaponSlots) {
1080 if (!tmpWeaponSlot.Weapon.expired() &&
1081 tmpWeaponSlot.SetFire) {
1082 NeedFire = true;
1083 break;
1084 }
1085 }
1086 }
1087 bool NeedBossFire = false;
1088 if (!BossWeaponSlots.empty()) {
1089 for (auto &tmpBossWeaponSlot : BossWeaponSlots) {
1090 if (!tmpBossWeaponSlot.Weapon.expired() &&
1091 tmpBossWeaponSlot.SetFire) {
1092 NeedBossFire = true;
1093 break;
1094 }
1095 }
1096 }
1097
1098 if ((ObjectStatus == eObjectStatus::Enemy) && NeedFire && !WeaponSlots.empty()) {
1099 for (auto &tmpWeaponSlot : WeaponSlots) {
1100 if (auto sharedWeapon = tmpWeaponSlot.Weapon.lock()) {
1101 if (sharedWeapon->NeedRotateOnTargeting) {
1102 sVECTOR3D tmpNeedAngle{};
1103 sVECTOR3D tmpTargetLocation{};
1104 sVECTOR3D tmpWeaponLocation = tmpWeaponSlot.Location +
1105 sharedWeapon->FireLocation +
1106 Location;
1107 if (FindTargetLocationWithPrediction(ObjectStatus, tmpWeaponLocation,
1108 sharedWeapon->InternalType, tmpTargetLocation) &&
1109 GetTurretOnTargetOrientation(tmpWeaponLocation, Rotation, CurrentRotationMat,
1110 tmpTargetLocation, tmpNeedAngle))
1111 sharedWeapon->SetRotation(sVECTOR3D{-sharedWeapon->Rotation.x - tmpNeedAngle.x,
1112 0.0f,
1113 0.0f});
1114 }
1115 }
1116 }
1117 }
1118 // FIXME remove this code duplication (same as above)
1119 if ((ObjectStatus == eObjectStatus::Enemy) && NeedBossFire && !BossWeaponSlots.empty()) {
1120 for (auto &tmpWeaponSlot : BossWeaponSlots) {
1121 if (auto sharedWeapon = tmpWeaponSlot.Weapon.lock()) {
1122 if (sharedWeapon->NeedRotateOnTargeting) {
1123 sVECTOR3D tmpNeedAngle{};
1124 sVECTOR3D tmpTargetLocation{};
1125 sVECTOR3D tmpWeaponLocation = tmpWeaponSlot.Location +
1126 sharedWeapon->FireLocation +
1127 Location;
1128 if (FindTargetLocationWithPrediction(ObjectStatus, tmpWeaponLocation,
1129 sharedWeapon->InternalType, tmpTargetLocation) &&
1130 GetTurretOnTargetOrientation(tmpWeaponLocation, Rotation, CurrentRotationMat,
1131 tmpTargetLocation, tmpNeedAngle))
1132 sharedWeapon->SetRotation(sVECTOR3D{-sharedWeapon->Rotation.x - tmpNeedAngle.x,
1133 0.0f,
1134 0.0f});
1135 }
1136 }
1137 }
1138 }
1139
1140 if (ObjectStatus == eObjectStatus::Ally) {
1141 // weapons 'center' point
1142 sVECTOR3D WeaponAvLocation(0.0f, 0.0f, 0.0f);
1143 int UsedWeaponQunt = 0;
1144 if (!WeaponSlots.empty()) {
1145 for (auto &tmpWeaponSlot : WeaponSlots) {
1146 if (auto sharedWeapon = tmpWeaponSlot.Weapon.lock()) {
1147 WeaponAvLocation = WeaponAvLocation + tmpWeaponSlot.Location + sharedWeapon->FireLocation + Location;
1148 UsedWeaponQunt++;
1149 }
1150 }
1151 }
1152 WeaponAvLocation.x = WeaponAvLocation.x / UsedWeaponQunt;
1153 WeaponAvLocation.y = WeaponAvLocation.y / UsedWeaponQunt;
1154 WeaponAvLocation.z = WeaponAvLocation.z / UsedWeaponQunt;
1155
1156 sVECTOR3D NeedAngle = Rotation;
1157
1158 if (!WeaponSlots.empty()) {
1159 float TargetingSpeed{1.0f};
1160
1161 for (unsigned i = 0; i < WeaponSlots.size(); i++) {
1162 if (auto sharedWeapon = WeaponSlots[i].Weapon.lock()) {
1163 if (sharedWeapon->NeedRotateOnTargeting) {
1164 NeedAngle = Rotation;
1165 NeedAngle.y += WeaponSlots[i].YAngle;
1166
1167 GetWeaponOnTargetOrientation(ObjectStatus, Location + WeaponSlots[i].Location + sharedWeapon->FireLocation,
1168 Location + WeaponSlots[i].Location + sharedWeapon->FireLocation, Rotation,
1169 Length, CurrentRotationMat, NeedAngle, true, sharedWeapon->InternalType);
1170
1171 sVECTOR3D NeedAngleTmp = NeedAngle;
1172
1173 if (sharedWeapon->Rotation.x < NeedAngle.x) {
1174 float NeedAngle_x = sharedWeapon->Rotation.x + 40.0f * TargetingSpeed * TimeDelta;
1175 if (NeedAngle_x > NeedAngle.x)
1176 NeedAngle_x = NeedAngle.x;
1177 NeedAngle.x = NeedAngle_x;
1178
1179 }
1180 if (sharedWeapon->Rotation.x > NeedAngle.x) {
1181 float NeedAngle_x = sharedWeapon->Rotation.x - 40.0f * TargetingSpeed * TimeDelta;
1182 if (NeedAngle_x < NeedAngle.x)
1183 NeedAngle_x = NeedAngle.x;
1184 NeedAngle.x = NeedAngle_x;
1185 }
1186
1187 float Min{0.0f};
1188 float Max{0.0f};
1189 GetShipWeaponSlotAngle(GameConfig().Profile[CurrentProfile].ShipHull, i, Min, Max);
1190 if (sharedWeapon->Rotation.y < NeedAngle.y) {
1191 float NeedAngle_y = sharedWeapon->Rotation.y + 40.0f * TargetingSpeed * TimeDelta;
1192 if (NeedAngle_y > NeedAngle.y)
1193 NeedAngle_y = NeedAngle.y;
1194 NeedAngle.y = NeedAngle_y;
1195 if (NeedAngle.y > Max + Rotation.y)
1196 NeedAngle.y = Max + Rotation.y;
1197 }
1198 if (sharedWeapon->Rotation.y > NeedAngle.y) {
1199 float NeedAngle_y = sharedWeapon->Rotation.y - 40.0f * TargetingSpeed * TimeDelta;
1200 if (NeedAngle_y < NeedAngle.y)
1201 NeedAngle_y = NeedAngle.y;
1202 NeedAngle.y = NeedAngle_y;
1203 if (NeedAngle.y < Min + Rotation.y)
1204 NeedAngle.y = Min + Rotation.y;
1205 }
1206
1207 if (GameWeaponTargetingMode == 1)
1208 NeedAngle = NeedAngleTmp;
1209
1210 if (sharedWeapon->InternalType < 16) { // not missile
1211 sharedWeapon->SetRotation(sharedWeapon->Rotation ^ (-1));
1212 sharedWeapon->SetRotation(NeedAngle);
1213 }
1214 }
1215 }
1216 }
1217 }
1218 }
1219
1220 if (ObjectStatus == eObjectStatus::Player) {
1221 float TargetingSpeed = static_cast<float>(GameTargetingMechanicSystem);
1222
1223 // weapons 'center' point
1224 sVECTOR3D WeaponAvLocation(0.0f, 0.0f, 0.0f);
1225 int UsedWeaponQunt = 0;
1226 if (!WeaponSlots.empty()) {
1227 for (auto &tmpWeaponSlot : WeaponSlots) {
1228 if (auto sharedWeapon = tmpWeaponSlot.Weapon.lock()) {
1229 WeaponAvLocation = WeaponAvLocation + tmpWeaponSlot.Location + sharedWeapon->FireLocation + Location;
1230 UsedWeaponQunt++;
1231 }
1232 }
1233 }
1234 WeaponAvLocation.x = WeaponAvLocation.x / UsedWeaponQunt;
1235 WeaponAvLocation.y = WeaponAvLocation.y / UsedWeaponQunt;
1236 WeaponAvLocation.z = WeaponAvLocation.z / UsedWeaponQunt;
1237
1238 sVECTOR3D NeedAngle = Rotation;
1239
1240 if (!WeaponSlots.empty()) {
1241 for (unsigned i = 0; i < WeaponSlots.size(); i++) {
1242 if (auto sharedWeapon = WeaponSlots[i].Weapon.lock()) {
1243 if (sharedWeapon->NeedRotateOnTargeting) {
1244 NeedAngle = Rotation;
1245 NeedAngle.y += WeaponSlots[i].YAngle;
1246
1247 switch (GameTargetingSystem) {
1248 case 1: // for all weapon by height only
1249 GetWeaponOnTargetOrientation(ObjectStatus, Location + WeaponSlots[i].Location + sharedWeapon->FireLocation,
1250 WeaponAvLocation, Rotation, Length, CurrentRotationMat, NeedAngle, false,
1251 sharedWeapon->InternalType);
1252 break;
1253 case 2: // for all weapon by height, with correction to target center
1254 GetWeaponOnTargetOrientation(ObjectStatus, Location + WeaponSlots[i].Location + sharedWeapon->FireLocation,
1255 WeaponAvLocation, Rotation, Length, CurrentRotationMat, NeedAngle, true,
1256 sharedWeapon->InternalType);
1257 break;
1258 case 3: // for each weapon by height only
1259 GetWeaponOnTargetOrientation(ObjectStatus, Location + WeaponSlots[i].Location + sharedWeapon->FireLocation,
1260 Location + WeaponSlots[i].Location + sharedWeapon->FireLocation, sharedWeapon->Rotation,
1261 Length, sharedWeapon->CurrentRotationMat, NeedAngle, false,
1262 sharedWeapon->InternalType);
1263 break;
1264 case 4: // for each weapon by height, with correction to target center
1265 GetWeaponOnTargetOrientation(ObjectStatus, Location + WeaponSlots[i].Location + sharedWeapon->FireLocation,
1266 Location + WeaponSlots[i].Location + sharedWeapon->FireLocation,
1267 sVECTOR3D{sharedWeapon->Rotation.x, WeaponSlots[i].YAngle, sharedWeapon->Rotation.z},
1268 Length, sharedWeapon->CurrentRotationMat, NeedAngle, true,
1269 sharedWeapon->InternalType);
1270 break;
1271 }
1272
1273 sVECTOR3D NeedAngleTmp = NeedAngle;
1274
1275 if (sharedWeapon->Rotation.x < NeedAngle.x) {
1276 float NeedAngle_x = sharedWeapon->Rotation.x + 40.0f * TargetingSpeed * TimeDelta;
1277 if (NeedAngle_x > NeedAngle.x)
1278 NeedAngle_x = NeedAngle.x;
1279 NeedAngle.x = NeedAngle_x;
1280
1281 }
1282 if (sharedWeapon->Rotation.x > NeedAngle.x) {
1283 float NeedAngle_x = sharedWeapon->Rotation.x - 40.0f * TargetingSpeed * TimeDelta;
1284 if (NeedAngle_x < NeedAngle.x)
1285 NeedAngle_x = NeedAngle.x;
1286 NeedAngle.x = NeedAngle_x;
1287 }
1288
1289 float Min{0.0f};
1290 float Max{0.0f};
1291 GetShipWeaponSlotAngle(GameConfig().Profile[CurrentProfile].ShipHull, i, Min, Max);
1292 if (sharedWeapon->Rotation.y > NeedAngle.y) {
1293 float NeedAngle_y = sharedWeapon->Rotation.y + 40.0f * TargetingSpeed * TimeDelta;
1294 if (NeedAngle_y > NeedAngle.y)
1295 NeedAngle_y = NeedAngle.y;
1296 NeedAngle.y = NeedAngle_y;
1297 if (NeedAngle.y > Max + sharedWeapon->Rotation.y)
1298 NeedAngle.y = Max + sharedWeapon->Rotation.y;
1299 }
1300 if (sharedWeapon->Rotation.y < NeedAngle.y) {
1301 float NeedAngle_y = sharedWeapon->Rotation.y - 40.0f * TargetingSpeed * TimeDelta;
1302 if (NeedAngle_y < NeedAngle.y)
1303 NeedAngle_y = NeedAngle.y;
1304 NeedAngle.y = NeedAngle_y;
1305 if (NeedAngle.y < Min + sharedWeapon->Rotation.y)
1306 NeedAngle.y = Min + sharedWeapon->Rotation.y;
1307 }
1308
1309 if (GameWeaponTargetingMode == 1)
1310 NeedAngle = NeedAngleTmp;
1311
1312 sharedWeapon->SetRotation(sharedWeapon->Rotation ^ (-1));
1313 sharedWeapon->SetRotation(NeedAngle);
1314 }
1315 }
1316 }
1317 }
1318 }
1319
1320 return true;
1321 }
1322
1323 } // astromenace namespace
1324 } // viewizard namespace
1325