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