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 translate comments
29
30 #include "../core/core.h"
31 #include "../config/config.h"
32 #include "../platform/platform.h"
33 #include "../ui/font.h"
34 #include "../ui/game/text.h"
35 #include "../assets/audio.h"
36 #include "../assets/texture.h"
37 #include "../game/camera.h"
38 #include "../object3d/explosion/explosion.h"
39 #include "../object3d/space_object/space_object.h"
40 #include "../object3d/ground_object/ground_object.h"
41 #include "../object3d/space_ship/space_ship.h"
42 #include "../object3d/projectile/projectile.h"
43 #include "../game.h" // FIXME "game.h" should be replaced by individual headers
44
45 // NOTE switch to nested namespace definition (namespace A::B::C { ... }) (since C++17)
46 namespace viewizard {
47 namespace astromenace {
48
49 // режим неубиваемости... отладка
50 bool UndeadDebugMode = false;
51
52 // состояние управления, нужно, чтобы определять что менялось
53 int LastMouseX = -1;
54 int LastMouseY = -1;
55 // для восстановления положения курсора в меню, точнее при выходе из него
56 int LastMouseXR = 0;
57 int LastMouseYR = 0;
58
59 // в показателях от -1.0f до 1.0f
60 // назад-вперед
61 float MoveFB = 0.0f;
62 // лево-право
63 float MoveLR = 0.0f;
64
65 // текущая энергия корабля
66 float CurrentPlayerShipEnergy;
67
68 // для управления в аркадном режиме маневровыми двигателями
69 bool PlayerFighterLeftEng = false;
70 bool PlayerFighterRightEng = false;
71
72 std::weak_ptr<cParticleSystem> Shild1{};
73 std::weak_ptr<cParticleSystem> Shild2{};
74 float ShildRadius;
75 float ShildEnergyStatus;
76 float ShildStartHitStatus;
77
78 // голос с ворнингом, если столкнулись с несбиваемой частью
79 unsigned int VoiceWarningCollisionDetected{0};
80
81 // Номер, для проигрывания голосового сообщения об обнаружении ракеты
82 unsigned int VoiceMissileDetected{0};
83 bool VoiceMissileDetectedStatus{false};
84 // номер, для проигрывания голосового сообщения о проблемах в орудии
85 // Номер, для проигрывания голосового сообщения об отсутствии снарядов в боекомплекте
86 unsigned int VoiceWeaponMalfunction{0};
87 // для звука - мало жизни
88 unsigned int SoundLowLife{0};
89
90
91 // тут храним какая часть взорвалась на корабле игрока
92 int PlayerDeadObjectPieceNum;
93
94
95 // симулятивный режим
96 sVECTOR3D CurrentMovementVel(0.0f, 0.0f, 0.0f);
97
98 // работа с морганием вывода
99 extern float CurrentAlert2;
100 extern float CurrentAlert3;
101
102 // для переменного типа стрельбы
103 int PrimaryGroupCurrentFireWeaponNum = 1;
104 float PrimaryGroupCurrentFireWeaponDelay = 0.0f;
105 int SecondaryGroupCurrentFireWeaponNum = 1;
106 float SecondaryGroupCurrentFireWeaponDelay = 0.0f;
107
108
109
110
111 //------------------------------------------------------------------------------------
112 // Получаем максимально возможное значение энергии для устройства реактора-батареи
113 //------------------------------------------------------------------------------------
GetShipMaxEnergy(int Num)114 float GetShipMaxEnergy(int Num)
115 {
116 switch (Num) {
117 case 0:
118 return 0.0f;
119 // аккамулятор
120 case 1:
121 return 100.0f;
122 // ядерный
123 case 2:
124 return 200.0f;
125 // плазменный
126 case 3:
127 return 400.0f;
128 // антиматерия
129 case 4:
130 return 800.0f;
131
132 default:
133 std::cerr << __func__ << "(): " << "wrong Num.\n";
134 break;
135 }
136
137 return -1.0f;
138 }
139 //------------------------------------------------------------------------------------
140 // Получаем перезарядку энергии, в секунду
141 //------------------------------------------------------------------------------------
GetShipRechargeEnergy(int Num)142 float GetShipRechargeEnergy(int Num)
143 {
144 switch (Num) {
145 case 0:
146 return 0.0f;
147 // аккамулятор
148 case 1:
149 return 20.0f;
150 // ядерный
151 case 2:
152 return 50.0f;
153 // плазменный
154 case 3:
155 return 130.0f;
156 // антиматерия
157 case 4:
158 return 250.0f;
159
160 default:
161 std::cerr << __func__ << "(): " << "wrong Num.\n";
162 break;
163 }
164
165 return -1.0f;
166 }
167 //------------------------------------------------------------------------------------
168 // Получаем расход энергии в секунду для доп систем (GameAdvancedProtectionSystem)
169 //------------------------------------------------------------------------------------
GetShipProtectionSystemEnergyUse(int Num)170 float GetShipProtectionSystemEnergyUse(int Num)
171 {
172 switch (Num) {
173 // нано роботы
174 case 1:
175 return 10.0f;
176 // спец защитный слой
177 case 2:
178 return 0.0f;
179 // щит
180 case 3:
181 return 50.0f;
182 // отражатель
183 case 4:
184 return 100.0f;
185
186 default:
187 std::cerr << __func__ << "(): " << "wrong Num.\n";
188 break;
189 }
190
191 return 0.0f;
192 }
193 //------------------------------------------------------------------------------------
194 // Получаем расход энергии в секунду для двигателей GameEngineSystem
195 //------------------------------------------------------------------------------------
GetShipEngineSystemEnergyUse(int Num)196 float GetShipEngineSystemEnergyUse(int Num)
197 {
198 switch (Num) {
199 // обычные двигатели
200 case 1:
201 return 5.0f;
202 // фатоновые
203 case 2:
204 return 10.0f;
205 // плазменные
206 case 3:
207 return 30.0f;
208 // на антиматерии
209 case 4:
210 return 60.0f;
211
212 default:
213 std::cerr << __func__ << "(): " << "wrong Num.\n";
214 break;
215 }
216
217 return 0.0f;
218 }
219
220
221
222
223
224
225 //------------------------------------------------------------------------------------
226 // Инициализация корабля игрока
227 //------------------------------------------------------------------------------------
InitGamePlayerShip()228 void InitGamePlayerShip()
229 {
230 // создаем корабль игрока по настройкам в профайле
231 VoiceMissileDetected = 0;
232 VoiceMissileDetectedStatus = false;
233 VoiceWeaponMalfunction = 0;
234 SoundLowLife = 0;
235
236 int TMPGameEnemyArmorPenalty = GameEnemyArmorPenalty;
237 GameEnemyArmorPenalty = 1;
238
239 // если не создано, здесь будет ноль скорее всего
240 if (GameConfig().Profile[CurrentProfile].ShipHull == 0)
241 std::cerr << __func__ << "(): " << "Error, Pilot Profile not created.\n";
242
243 PlayerFighter = CreateEarthSpaceFighter(GameConfig().Profile[CurrentProfile].ShipHull);
244 auto sharedPlayerFighter = PlayerFighter.lock();
245 if (!sharedPlayerFighter)
246 return;
247
248 sharedPlayerFighter->ShipShake.emplace_back(sVECTOR3D{0.0f, 0.0f, 1.0f},
249 0,
250 0.035f,
251 [] () {return vw_fRand0() * 0.1f;});
252
253 sharedPlayerFighter->ObjectStatus = eObjectStatus::Player;
254 sharedPlayerFighter->ArmorInitialStatus *= GameConfig().Profile[CurrentProfile].ShipHullUpgrade;
255 sharedPlayerFighter->ArmorCurrentStatus = GameConfig().Profile[CurrentProfile].ArmorStatus;
256 sharedPlayerFighter->ShowStatus = false;
257
258 // создаем оружие
259 for (unsigned i=0; i<sharedPlayerFighter->WeaponSlots.size(); i++) {
260 if (GameConfig().Profile[CurrentProfile].Weapon[i] != 0) {
261 if (SetEarthSpaceFighterWeapon(PlayerFighter, i+1, GameConfig().Profile[CurrentProfile].Weapon[i])) {
262 if (auto sharedWeapon = sharedPlayerFighter->WeaponSlots[i].Weapon.lock())
263 sharedWeapon->Ammo = GameConfig().Profile[CurrentProfile].WeaponAmmo[i];
264 sharedPlayerFighter->WeaponSlots[i].YAngle = -GameConfig().Profile[CurrentProfile].WeaponSlotYAngle[i];
265 }
266 }
267 }
268
269 // создаем системы (визуальные)
270 SetEarthSpaceFighterEngine(PlayerFighter, GameEngineSystem);
271 SetEarthSpaceFighterArmor(PlayerFighter, GameConfig().Profile[CurrentProfile].ShipHullUpgrade - 1);
272
273 GameEnemyArmorPenalty = TMPGameEnemyArmorPenalty;
274
275
276
277 float Width2 = sharedPlayerFighter->Width/2.0f;
278 float Length2 = sharedPlayerFighter->Length/2.0f;
279 ShildRadius = vw_sqrtf(Width2*Width2+Length2*Length2);
280 ShildEnergyStatus = 0.0f;
281 ShildStartHitStatus = 0.0f;
282
283
284
285 if (GameConfig().Profile[CurrentProfile].AdvancedProtectionSystem == 3) {
286 Shild1 = vw_CreateParticleSystem();
287 if (auto sharedShild1 = Shild1.lock()) {
288 sharedShild1->ColorStart.r = 0.20f;
289 sharedShild1->ColorStart.g = 0.50f;
290 sharedShild1->ColorStart.b = 0.10f;
291 sharedShild1->ColorEnd.r = 0.20f;
292 sharedShild1->ColorEnd.g = 0.50f;
293 sharedShild1->ColorEnd.b = 0.10f;
294 sharedShild1->AlphaStart = 1.00f;
295 sharedShild1->AlphaEnd = 0.00f;
296 sharedShild1->SizeStart = 0.60f;
297 sharedShild1->SizeVar = 0.10f;
298 sharedShild1->SizeEnd = 0.10f;
299 sharedShild1->Speed = 0.00f;
300 sharedShild1->SpeedOnCreation = -1.00f;
301 sharedShild1->Theta = 360.00f;
302 sharedShild1->Life = 1.00f;
303 sharedShild1->ParticlesPerSec = (int)(40 * ShildRadius);
304 sharedShild1->CreationType = eParticleCreationType::Sphere;
305 sharedShild1->CreationSize = sVECTOR3D{ShildRadius, 0.05f * ShildRadius, ShildRadius};
306 sharedShild1->DeadZone = ShildRadius - 0.05f;
307 sharedShild1->AlphaShowHide = true;
308 sharedShild1->IsMagnet = true;
309 sharedShild1->MagnetFactor = -3.0f;
310 sharedShild1->Texture = GetPreloadedTextureAsset("gfx/flare1.tga");
311 sharedShild1->Direction = sVECTOR3D{0.0f, 0.0f, -1.0f};
312 sharedShild1->SetStartLocation(sharedPlayerFighter->Location + sharedPlayerFighter->OBB.Location);
313 }
314
315 ShildStartHitStatus = 100.0f;
316 ShildEnergyStatus = 1.0f;
317 }
318 if (GameConfig().Profile[CurrentProfile].AdvancedProtectionSystem == 4) {
319 Shild1 = vw_CreateParticleSystem();
320 if (auto sharedShild1 = Shild1.lock()) {
321 sharedShild1->ColorStart.r = 0.50f;
322 sharedShild1->ColorStart.g = 0.50f;
323 sharedShild1->ColorStart.b = 1.00f;
324 sharedShild1->ColorEnd.r = 0.50f;
325 sharedShild1->ColorEnd.g = 0.50f;
326 sharedShild1->ColorEnd.b = 1.00f;
327 sharedShild1->AlphaStart = 0.50f;
328 sharedShild1->AlphaEnd = 0.00f;
329 sharedShild1->SizeStart = 0.40f;
330 sharedShild1->SizeVar = 0.10f;
331 sharedShild1->SizeEnd = 0.20f;
332 sharedShild1->Speed = 0.00f;
333 sharedShild1->SpeedOnCreation = -1.00f;
334 sharedShild1->Theta = 360.00f;
335 sharedShild1->Life = 1.00f;
336 sharedShild1->ParticlesPerSec = (int)(40 * ShildRadius);
337 sharedShild1->CreationType = eParticleCreationType::Sphere;
338 sharedShild1->CreationSize = sVECTOR3D{ShildRadius, 0.05f * ShildRadius, ShildRadius};
339 sharedShild1->DeadZone = ShildRadius - 0.05f;
340 sharedShild1->IsMagnet = true;
341 sharedShild1->AlphaShowHide = true;
342 sharedShild1->MagnetFactor = 2.5f;
343 sharedShild1->Texture = GetPreloadedTextureAsset("gfx/flare1.tga");
344 sharedShild1->Direction = sVECTOR3D{0.0f, 0.0f, -1.0f};
345 sharedShild1->SetStartLocation(sharedPlayerFighter->Location + sharedPlayerFighter->OBB.Location);
346 }
347
348 Shild2 = vw_CreateParticleSystem();
349 if (auto sharedShild2 = Shild2.lock()) {
350 sharedShild2->ColorStart.r = 0.50f;
351 sharedShild2->ColorStart.g = 0.50f;
352 sharedShild2->ColorStart.b = 1.00f;
353 sharedShild2->ColorEnd.r = 0.50f;
354 sharedShild2->ColorEnd.g = 0.50f;
355 sharedShild2->ColorEnd.b = 1.00f;
356 sharedShild2->AlphaStart = 0.70f;
357 sharedShild2->AlphaEnd = 0.10f;
358 sharedShild2->SizeStart = 0.50f;
359 sharedShild2->SizeVar = 0.10f;
360 sharedShild2->SizeEnd = 0.30f;
361 sharedShild2->Speed = 0.00f;
362 sharedShild2->SpeedOnCreation = -1.00f;
363 sharedShild2->Theta = 360.00f;
364 sharedShild2->Life = 1.00f;
365 sharedShild2->ParticlesPerSec = (int)(5 * ShildRadius);
366 sharedShild2->CreationType = eParticleCreationType::Sphere;
367 sharedShild2->CreationSize = sVECTOR3D{ShildRadius, 0.05f * ShildRadius, ShildRadius};
368 sharedShild2->DeadZone = ShildRadius - 0.05f;
369 sharedShild2->IsMagnet = true;
370 sharedShild2->MagnetFactor = 20.0f;
371 sharedShild2->Texture = GetPreloadedTextureAsset("gfx/flare1.tga");
372 sharedShild2->Direction = sVECTOR3D{0.0f, 0.0f, -1.0f};
373 }
374
375 ShildStartHitStatus = 150.0f;
376 ShildEnergyStatus = 1.0f;
377 }
378
379
380
381 // предварительная установка, полностью заряженное устройство
382 CurrentPlayerShipEnergy = GetShipMaxEnergy(GamePowerSystem);
383
384 // предварительно иним состояния управления
385 LastMouseX = -1;
386 LastMouseY = -1;
387 MoveFB = 0.0f;
388 MoveLR = 0.0f;
389 CurrentMovementVel = sVECTOR3D{0.0f, 0.0f, 0.0f};
390
391 // сброс стрельбы...
392 PrimaryGroupCurrentFireWeaponNum = 1;
393 PrimaryGroupCurrentFireWeaponDelay = 0.0f;
394 SecondaryGroupCurrentFireWeaponNum = 1;
395 SecondaryGroupCurrentFireWeaponDelay = 0.0f;
396 }
397
398
399
400
401
402
403
404
405 //------------------------------------------------------------------------------------
406 // Основная процедура обработки состояния корабля игрока
407 //------------------------------------------------------------------------------------
GamePlayerShip()408 void GamePlayerShip()
409 {
410 auto sharedPlayerFighter = PlayerFighter.lock();
411 if (!sharedPlayerFighter)
412 return;
413
414 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
415 // проверяем, корабль живой еще, или сбили и нужно его удалить...
416 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
417 if (sharedPlayerFighter->ArmorCurrentStatus <= 0.0f) {
418 // редкий случай
419 if (UndeadDebugMode) {
420 sharedPlayerFighter->ArmorCurrentStatus = sharedPlayerFighter->ArmorInitialStatus;
421 } else {
422 // делаем взрыв
423 // + 10.0f движение камеры
424 CreateSpaceExplosion(*sharedPlayerFighter, 31, sharedPlayerFighter->Location, sharedPlayerFighter->Speed+10.0f, PlayerDeadObjectPieceNum);
425
426 // включаем музыку и отображение "миссия провалена"
427 PlayMusicTheme(eMusicTheme::FAILED, 2000, 2000);
428
429 // удаляем и уходим отсюда
430 ReleaseSpaceShip(PlayerFighter);
431
432 SetupMissionFailedText(20.0f);
433
434 return;
435 }
436 }
437
438
439
440 // голос выводим только в игре! в меню включается пауза
441 // и если не закончился уровень
442 if (GameContentTransp < 0.99f && !GameMissionCompleteStatus) {
443 int WarningMessagesCount = 0;
444
445 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
446 // Вывод голосового предупреждения, если навелась ракета
447 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
448 bool CheckStatus{false};
449 ForEachProjectile([&] (const cProjectile &Projectile) {
450 if (auto sharedTarget = Projectile.Target.lock()) {
451 if ((sharedTarget.get() == sharedPlayerFighter.get()) &&
452 // homing missile targeted on this ship, but not homing mine
453 ((Projectile.Num < 26) || (Projectile.Num > 29)))
454 CheckStatus = true;
455 }
456 });
457
458 if (CheckStatus) {
459 // проверяем, действительно еще играем (играем только 1 раз!)
460 if (!vw_IsSoundAvailable(VoiceMissileDetected) &&
461 !VoiceMissileDetectedStatus) {
462 VoiceMissileDetected = PlayVoicePhrase(eVoicePhrase::MissileDetected, 1.0f);
463 VoiceMissileDetectedStatus = true;
464 }
465
466 // визуальный вывод - выводим постоянно
467 vw_SetFontSize(24);
468 int TmpFontSize = (GameConfig().InternalWidth - vw_TextWidthUTF32(vw_GetTextUTF32("Missile Detected"))) / 2;
469 vw_DrawTextUTF32(TmpFontSize, 720 - 40*WarningMessagesCount, 0, 0, 1.0f, sRGBCOLOR{eRGBCOLOR::orange}, CurrentAlert3, vw_GetTextUTF32("Missile Detected"));
470 ResetFontSize();
471 WarningMessagesCount++;
472 } else {
473 if (CurrentAlert3 == 1.0f) { // сделали полный цикл , предыдущее значение счетчика было минимальное
474 VoiceMissileDetectedStatus = false;
475 } else if (VoiceMissileDetectedStatus) {
476 // визуальный вывод - выводим постоянно
477 vw_SetFontSize(24);
478 int TmpFontSize = (GameConfig().InternalWidth - vw_TextWidthUTF32(vw_GetTextUTF32("Missile Detected"))) / 2;
479 vw_DrawTextUTF32(TmpFontSize, 720 - 40*WarningMessagesCount, 0, 0, 1.0f, sRGBCOLOR{eRGBCOLOR::orange}, CurrentAlert3, vw_GetTextUTF32("Missile Detected"));
480 ResetFontSize();
481 WarningMessagesCount++;
482 }
483 }
484
485
486
487 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
488 // Вывод голосового предупреждения если возможно столкновение
489 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
490 bool CollisionDetected = false;
491 ForEachSpaceObject([&CollisionDetected, &sharedPlayerFighter] (const cSpaceObject &tmpSpace, eSpaceCycle &Command) {
492 // test with "immortal" big asteroids
493 if ((tmpSpace.ObjectType == eObjectType::BigAsteroid) &&
494 (vw_SphereSphereCollision(sharedPlayerFighter->Radius, sharedPlayerFighter->Location,
495 tmpSpace.Radius, tmpSpace.Location, tmpSpace.PrevLocation)) &&
496 (vw_SphereAABBCollision(tmpSpace.AABB, tmpSpace.Location, sharedPlayerFighter->Radius,
497 sharedPlayerFighter->Location, sharedPlayerFighter->PrevLocation))) {
498 CollisionDetected = true;
499 Command = eSpaceCycle::Break;
500 }
501 });
502 ForEachGroundObject([&CollisionDetected, &sharedPlayerFighter] (const cGroundObject &tmpGround, eGroundCycle &Command) {
503 // test with "immortal" civilian buildings
504 if ((tmpGround.ObjectType == eObjectType::CivilianBuilding) &&
505 (vw_SphereSphereCollision(sharedPlayerFighter->Radius, sharedPlayerFighter->Location,
506 tmpGround.Radius, tmpGround.Location, tmpGround.PrevLocation)) &&
507 (vw_SphereAABBCollision(tmpGround.AABB, tmpGround.Location, sharedPlayerFighter->Radius,
508 sharedPlayerFighter->Location, sharedPlayerFighter->PrevLocation)) &&
509 (vw_SphereOBBCollision(tmpGround.OBB.Box, tmpGround.OBB.Location, tmpGround.Location,
510 tmpGround.CurrentRotationMat, sharedPlayerFighter->Radius,
511 sharedPlayerFighter->Location, sharedPlayerFighter->PrevLocation))) {
512 CollisionDetected = true;
513 Command = eGroundCycle::Break;
514 }
515 });
516 if (CollisionDetected) {
517 // голос, ворнинг, можем столкнуться с объектом
518 // проверяем, действительно еще играем
519 if (!vw_IsSoundAvailable(VoiceWarningCollisionDetected))
520 VoiceWarningCollisionDetected = PlayVoicePhrase(eVoicePhrase::Warning, 1.0f);
521
522 // визуальный вывод - выводим постоянно
523 vw_SetFontSize(24);
524 int TmpFontSize = (GameConfig().InternalWidth - vw_TextWidthUTF32(vw_GetTextUTF32("Collision Course Detected"))) / 2;
525 vw_DrawTextUTF32(TmpFontSize, 720 - 40*WarningMessagesCount, 0, 0, 1.0f, sRGBCOLOR{eRGBCOLOR::red}, CurrentAlert3, vw_GetTextUTF32("Collision Course Detected"));
526 ResetFontSize();
527 WarningMessagesCount++;
528 }
529
530
531
532
533
534 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
535 // Вывод голосового предупреждения, если в оружие нет пуль
536 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
537 if (!sharedPlayerFighter->WeaponSlots.empty()) { // если вообще есть оружие
538 for (const auto &tmpWeaponSlot : sharedPlayerFighter->WeaponSlots) {
539 // если нажали стрелять, а патронов нет в одном из орудий
540 if (auto sharedWeapon = tmpWeaponSlot.Weapon.lock()) {
541 if (tmpWeaponSlot.SetFire &&
542 (sharedWeapon->Ammo <= 0) &&
543 !vw_IsSoundAvailable(VoiceWeaponMalfunction)) // проверяем, действительно еще играем
544 VoiceWeaponMalfunction = PlayVoicePhrase(eVoicePhrase::WeaponMalfunction, 1.0f);
545 }
546 }
547 }
548
549
550 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
551 // Звуковое оповещение, если жизни менее 10%
552 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
553 // если меньше 10% нужно бить тревогу
554 if ((sharedPlayerFighter->ArmorCurrentStatus < sharedPlayerFighter->ArmorInitialStatus / 10.0f) &&
555 !vw_IsSoundAvailable(SoundLowLife)) // если не играем, запускаем звук сирены
556 SoundLowLife = PlayMenuSFX(eMenuSFX::WarningLowLife, 1.0f);
557 }
558
559
560
561
562
563 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
564 // управление кораблем - движение
565 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
566 if (GameContentTransp < 1.0f) { // если не в меню нажимают
567 // получаем данные, для обоих типов управления
568 // уже получили данные, нужно игнорировать остальные источникик
569 bool NeedSkip = false;
570
571 // mouse + joystick (since we emulate mouse movements)
572 if (GameConfig().MouseControl) {
573 SDL_GetMouseState(&LastMouseXR, &LastMouseYR);
574
575 int X, Y;
576 vw_GetMousePos(X, Y);
577 if (LastMouseX == -1 && LastMouseY == -1) {
578 LastMouseX = X;
579 LastMouseY = Y;
580 } else {
581 if (X != LastMouseX || Y != LastMouseY) {
582 // 0.9+0.1 = 1.0 - минимум, всегда 1.0 должен быть!
583 float Koef = 0.9f + GameConfig().ControlSensivity / 10.0f;
584
585 // при любом реальном разрешении у нас x и y меняются с учетом AspectRatio
586 float AWw2 = GameConfig().InternalWidth / 2.0f;
587 float AHw2 = GameConfig().InternalHeight / 2.0f;
588
589 MoveFB += (-(Y-LastMouseY)/AHw2)*Koef;
590 MoveLR += ( (X-LastMouseX)/AWw2)*Koef;
591
592 NeedSkip = true;
593 }
594
595 LastMouseX = X;
596 LastMouseY = Y;
597 }
598
599 }
600
601 // клавиатура
602 if (!NeedSkip) {
603 if (vw_GetKeyStatus(GameConfig().KeyBoardDown))
604 MoveFB -= 2.0f * (GameConfig().ControlSensivity / 10.0f) * sharedPlayerFighter->TimeDelta;
605 if (vw_GetKeyStatus(GameConfig().KeyBoardUp))
606 MoveFB += 2.0f * (GameConfig().ControlSensivity / 10.0f) * sharedPlayerFighter->TimeDelta;
607 if (vw_GetKeyStatus(GameConfig().KeyBoardLeft))
608 MoveLR -= 2.0f * (GameConfig().ControlSensivity / 10.0f) * sharedPlayerFighter->TimeDelta;
609 if (vw_GetKeyStatus(GameConfig().KeyBoardRight))
610 MoveLR += 2.0f * (GameConfig().ControlSensivity / 10.0f) * sharedPlayerFighter->TimeDelta;
611 }
612
613
614
615 // дополнительная проверка, т.к. можем выйти выйти за пределы
616 if (MoveFB < -1.0f) MoveFB = -1.0f;
617 if (MoveFB > 1.0f) MoveFB = 1.0f;
618 if (MoveLR < -1.0f) MoveLR = -1.0f;
619 if (MoveLR > 1.0f) MoveLR = 1.0f;
620
621
622
623
624
625
626 // находим конечную точку перемещения
627 sVECTOR3D PlayerFighterEndLocation;
628 if (GameConfig().InternalWidth == 1024)
629 PlayerFighterEndLocation = sVECTOR3D{-(73.15f-sharedPlayerFighter->Width/2.0f+MoveFB*(20.05f-sharedPlayerFighter->Length/6.0f))*MoveLR,
630 0.0f,
631 (46.0f-sharedPlayerFighter->Length/2.0f)*MoveFB};
632 else
633 PlayerFighterEndLocation = sVECTOR3D{-(70.0f-sharedPlayerFighter->Width/2.0f+MoveFB*(23.2f-sharedPlayerFighter->Length/6.0f))*MoveLR,
634 0.0f,
635 (46.0f-sharedPlayerFighter->Length/2.0f)*MoveFB};
636
637 PlayerFighterEndLocation += GetCameraCoveredDistance();
638
639 // если есть двигатель
640 if (GameEngineSystem != 0) {
641 // в зависимости от типа управления выполняем действия
642 if (GameConfig().Profile[CurrentProfile].SpaceShipControlMode == 1) {
643 // аркадный режим
644
645 // запускаем маневровые двигатели, если тянем корабль в сторону
646 if ((int)sharedPlayerFighter->Location.x > (int)PlayerFighterEndLocation.x) {
647 PlayerFighterLeftEng = true;
648 PlayerFighterRightEng = false;
649 }
650 if ((int)sharedPlayerFighter->Location.x < (int)PlayerFighterEndLocation.x) {
651 PlayerFighterLeftEng = false;
652 PlayerFighterRightEng = true;
653 }
654 // если не двигаем, останавливаем маневровые двигатели
655 if ((int)sharedPlayerFighter->Location.x == (int)PlayerFighterEndLocation.x) {
656 PlayerFighterLeftEng = false;
657 PlayerFighterRightEng = false;
658 }
659
660
661 // находим расстояние
662 sVECTOR3D PlayerFighterNewDirection = PlayerFighterEndLocation - sharedPlayerFighter->Location;
663 float EndLocationDistance = PlayerFighterNewDirection.Length();
664
665 // находим направление движения
666 PlayerFighterNewDirection.Normalize();
667
668 float SimMoveSpeed = EndLocationDistance;
669
670 if (SimMoveSpeed > 30.0f) SimMoveSpeed = 30.0f;
671
672 SimMoveSpeed = SimMoveSpeed*4.0f*sharedPlayerFighter->TimeDelta;
673
674
675 // получаем текущее движение
676 CurrentMovementVel = PlayerFighterNewDirection^SimMoveSpeed;
677
678 // проверка
679 float MaxSpeed = CurrentMovementVel.Length();
680 CurrentMovementVel.Normalize();
681 if (MaxSpeed > 30.0f) MaxSpeed = 30.0f;
682
683 CurrentMovementVel = CurrentMovementVel^MaxSpeed;
684
685 } else {
686 // симулятивный режим
687
688
689 // запускаем маневровые двигатели, если тянем корабль в сторону
690 if ((int)sharedPlayerFighter->Location.x > (int)PlayerFighterEndLocation.x) {
691 PlayerFighterLeftEng = true;
692 PlayerFighterRightEng = false;
693 }
694 if ((int)sharedPlayerFighter->Location.x < (int)PlayerFighterEndLocation.x) {
695 PlayerFighterLeftEng = false;
696 PlayerFighterRightEng = true;
697 }
698 // если не двигаем, останавливаем маневровые двигатели
699 if ((int)sharedPlayerFighter->Location.x == (int)PlayerFighterEndLocation.x) {
700 PlayerFighterLeftEng = false;
701 PlayerFighterRightEng = false;
702 }
703
704
705 // находим расстояние
706 sVECTOR3D PlayerFighterNewDirection = PlayerFighterEndLocation - sharedPlayerFighter->Location;
707 float EndLocationDistance = PlayerFighterNewDirection.Length();
708
709 // находим направление движения
710 PlayerFighterNewDirection.Normalize();
711
712 float SimMoveSpeed = EndLocationDistance;
713
714 if (SimMoveSpeed > sharedPlayerFighter->MaxSpeed)
715 SimMoveSpeed = sharedPlayerFighter->MaxSpeed;
716
717 SimMoveSpeed = SimMoveSpeed*(sharedPlayerFighter->MaxAcceler/14.0f)*sharedPlayerFighter->TimeDelta;
718
719
720 // получаем текущее движение
721 CurrentMovementVel = PlayerFighterNewDirection^SimMoveSpeed;
722
723 // проверка
724 float MaxSpeed = CurrentMovementVel.Length();
725 CurrentMovementVel.Normalize();
726 if (MaxSpeed > sharedPlayerFighter->MaxSpeed)
727 MaxSpeed = sharedPlayerFighter->MaxSpeed;
728
729 CurrentMovementVel = CurrentMovementVel^MaxSpeed;
730
731 }
732 }
733
734 // переносим корабль
735 sVECTOR3D CurrentVel = sharedPlayerFighter->Location + CurrentMovementVel;
736 CurrentVel.y = 0.0f;
737 sharedPlayerFighter->SetLocationArcadePlayer(CurrentVel);
738
739
740
741 // если стандартный аспект рейшен, надо перемещать камеру в дополнении к перемещению корабля
742 if (GameConfig().InternalWidth == 1024) {
743 float DeviationSize = 14.55f;
744
745 if (sharedPlayerFighter->Location.x < 0.0f) {
746 float Diff = sharedPlayerFighter->Location.x / 3.5f;
747 if (Diff < -DeviationSize)
748 Diff = -DeviationSize;
749
750 sVECTOR3D TMPCameraLocation;
751 vw_GetCameraLocation(&TMPCameraLocation);
752 TMPCameraLocation.x = Diff;
753 vw_SetCameraLocation(TMPCameraLocation);
754 } else {
755 float Diff = sharedPlayerFighter->Location.x / 3.5f;
756 if (Diff > DeviationSize)
757 Diff = DeviationSize;
758
759 sVECTOR3D TMPCameraLocation;
760 vw_GetCameraLocation(&TMPCameraLocation);
761 TMPCameraLocation.x = Diff;
762 vw_SetCameraLocation(TMPCameraLocation);
763 }
764 }
765
766 }
767
768
769
770
771
772 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
773 // управление кораблем - стрельба
774 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
775 if (GameContentTransp < 0.5f) // если не в меню нажимают
776 if (!sharedPlayerFighter->WeaponSlots.empty()) { // если вообще есть оружие
777
778 int PrimCount = 0;
779 float PrimTime = 0.0f;
780 int SecCount = 0;
781 float SecTime = 0.0f;
782
783 PrimaryGroupCurrentFireWeaponDelay -= sharedPlayerFighter->TimeDelta;
784 SecondaryGroupCurrentFireWeaponDelay -= sharedPlayerFighter->TimeDelta;
785
786 // находим кол-во оружия в группах
787 for (unsigned i = 0; i < sharedPlayerFighter->WeaponSlots.size(); i++) {
788 if (GameConfig().Profile[CurrentProfile].Weapon[i] != 0) { // если это оружие установлено
789
790 if (GameConfig().Profile[CurrentProfile].WeaponControl[i] == 1 ||
791 GameConfig().Profile[CurrentProfile].WeaponControl[i] == 3) {
792 if (auto sharedWeapon = sharedPlayerFighter->WeaponSlots[i].Weapon.lock()) {
793 PrimCount++;
794 PrimTime += sharedWeapon->NextFireTime;
795 }
796 }
797
798 if (GameConfig().Profile[CurrentProfile].WeaponControl[i] == 2 ||
799 GameConfig().Profile[CurrentProfile].WeaponControl[i] == 3) {
800 if (auto sharedWeapon = sharedPlayerFighter->WeaponSlots[i].Weapon.lock()) {
801 SecCount++;
802 SecTime += sharedWeapon->NextFireTime;
803 }
804 }
805 }
806 }
807
808
809 int PrimNum = 0;
810 int SecNum = 0;
811
812 for (unsigned i = 0; i < sharedPlayerFighter->WeaponSlots.size(); i++) {
813 if (GameConfig().Profile[CurrentProfile].Weapon[i] != 0) { // если это оружие установлено
814
815 sharedPlayerFighter->WeaponSlots[i].SetFire = false;
816
817 // получаем данные, в какую группу относится
818 bool primary_fire = false;
819 bool secondary_fire = false;
820 if (GameConfig().Profile[CurrentProfile].WeaponControl[i] == 1 ||
821 GameConfig().Profile[CurrentProfile].WeaponControl[i] ==3)
822 primary_fire = true;
823 if (GameConfig().Profile[CurrentProfile].WeaponControl[i] == 2 ||
824 GameConfig().Profile[CurrentProfile].WeaponControl[i] ==3)
825 secondary_fire = true;
826
827 // мышка
828 if (GameConfig().MouseControl) {
829 // primary fire
830 if (primary_fire)
831 if (vw_GetMouseButtonStatus(GameConfig().MousePrimary)) {
832 if (GameConfig().Profile[CurrentProfile].PrimaryWeaponFireMode == 1) {
833 sharedPlayerFighter->WeaponSlots[i].SetFire = true;
834 } else {
835 PrimNum++;
836 if (PrimaryGroupCurrentFireWeaponNum == PrimNum &&
837 PrimaryGroupCurrentFireWeaponDelay <= 0.0f) {
838 PrimaryGroupCurrentFireWeaponDelay = PrimTime / (PrimCount * PrimCount);
839 sharedPlayerFighter->WeaponSlots[i].SetFire = true;
840 PrimaryGroupCurrentFireWeaponNum++;
841 if (PrimaryGroupCurrentFireWeaponNum > PrimCount)
842 PrimaryGroupCurrentFireWeaponNum = 1;
843 }
844 }
845 }
846
847 // secondary fire
848 if (secondary_fire)
849 if (vw_GetMouseButtonStatus(GameConfig().MouseSecondary)) {
850 if (GameConfig().Profile[CurrentProfile].SecondaryWeaponFireMode == 1) {
851 sharedPlayerFighter->WeaponSlots[i].SetFire = true;
852 } else {
853 SecNum++;
854 if (SecondaryGroupCurrentFireWeaponNum == SecNum &&
855 SecondaryGroupCurrentFireWeaponDelay <= 0.0f) {
856 SecondaryGroupCurrentFireWeaponDelay = SecTime / (SecCount * SecCount);
857 sharedPlayerFighter->WeaponSlots[i].SetFire = true;
858 SecondaryGroupCurrentFireWeaponNum++;
859 if (SecondaryGroupCurrentFireWeaponNum > SecCount)
860 SecondaryGroupCurrentFireWeaponNum = 1;
861 }
862 }
863 }
864
865 // альтернативное управление
866 if (GameConfig().Profile[CurrentProfile].WeaponAltControl[i] == 2)
867 if (vw_GetMouseButtonStatus(GameConfig().Profile[CurrentProfile].WeaponAltControlData[i]))
868 sharedPlayerFighter->WeaponSlots[i].SetFire = true;
869 }
870
871
872 // джойстик
873 if (isJoystickAvailable()) {
874 // primary fire
875 if (primary_fire)
876 if (GetJoystickButton(GameConfig().JoystickPrimary)) {
877 if (GameConfig().Profile[CurrentProfile].PrimaryWeaponFireMode == 1) {
878 sharedPlayerFighter->WeaponSlots[i].SetFire = true;
879 } else {
880 PrimNum++;
881 if (PrimaryGroupCurrentFireWeaponNum == PrimNum &&
882 PrimaryGroupCurrentFireWeaponDelay <= 0.0f) {
883 PrimaryGroupCurrentFireWeaponDelay = PrimTime / (PrimCount * PrimCount);
884 sharedPlayerFighter->WeaponSlots[i].SetFire = true;
885 PrimaryGroupCurrentFireWeaponNum++;
886 if (PrimaryGroupCurrentFireWeaponNum > PrimCount)
887 PrimaryGroupCurrentFireWeaponNum = 1;
888 }
889 }
890 }
891
892 // secondary fire
893 if (secondary_fire)
894 if (GetJoystickButton(GameConfig().JoystickSecondary)) {
895 if (GameConfig().Profile[CurrentProfile].SecondaryWeaponFireMode == 1) {
896 sharedPlayerFighter->WeaponSlots[i].SetFire = true;
897 } else {
898 SecNum++;
899 if (SecondaryGroupCurrentFireWeaponNum == SecNum &&
900 SecondaryGroupCurrentFireWeaponDelay <= 0.0f) {
901 SecondaryGroupCurrentFireWeaponDelay = SecTime / (SecCount * SecCount);
902 sharedPlayerFighter->WeaponSlots[i].SetFire = true;
903 SecondaryGroupCurrentFireWeaponNum++;
904 if (SecondaryGroupCurrentFireWeaponNum > SecCount)
905 SecondaryGroupCurrentFireWeaponNum = 1;
906 }
907 }
908 }
909
910 // альтернативное управление
911 if (GameConfig().Profile[CurrentProfile].WeaponAltControl[i] == 3)
912 if (GetJoystickButton(GameConfig().Profile[CurrentProfile].WeaponAltControlData[i]))
913 sharedPlayerFighter->WeaponSlots[i].SetFire = true;
914 }
915
916 // клавиатура
917
918 // primary fire
919 if (primary_fire)
920 if (vw_GetKeyStatus(GameConfig().KeyBoardPrimary)) {
921 if (GameConfig().Profile[CurrentProfile].PrimaryWeaponFireMode == 1) {
922 sharedPlayerFighter->WeaponSlots[i].SetFire = true;
923 } else {
924 PrimNum++;
925 if (PrimaryGroupCurrentFireWeaponNum == PrimNum &&
926 PrimaryGroupCurrentFireWeaponDelay <= 0.0f) {
927 PrimaryGroupCurrentFireWeaponDelay = PrimTime / (PrimCount * PrimCount);
928 sharedPlayerFighter->WeaponSlots[i].SetFire = true;
929 PrimaryGroupCurrentFireWeaponNum++;
930 if (PrimaryGroupCurrentFireWeaponNum > PrimCount)
931 PrimaryGroupCurrentFireWeaponNum = 1;
932 }
933 }
934 }
935
936 // secondary fire
937 if (secondary_fire)
938 if (vw_GetKeyStatus(GameConfig().KeyBoardSecondary)) {
939 if (GameConfig().Profile[CurrentProfile].SecondaryWeaponFireMode == 1) {
940 sharedPlayerFighter->WeaponSlots[i].SetFire = true;
941 } else {
942 SecNum++;
943 if (SecondaryGroupCurrentFireWeaponNum == SecNum &&
944 SecondaryGroupCurrentFireWeaponDelay <= 0.0f) {
945 SecondaryGroupCurrentFireWeaponDelay = SecTime / (SecCount * SecCount);
946 sharedPlayerFighter->WeaponSlots[i].SetFire = true;
947 SecondaryGroupCurrentFireWeaponNum++;
948 if (SecondaryGroupCurrentFireWeaponNum > SecCount)
949 SecondaryGroupCurrentFireWeaponNum = 1;
950 }
951 }
952 }
953
954 // альтернативное управление
955 if (GameConfig().Profile[CurrentProfile].WeaponAltControl[i] == 1)
956 if (vw_GetKeyStatus(GameConfig().Profile[CurrentProfile].WeaponAltControlData[i]))
957 sharedPlayerFighter->WeaponSlots[i].SetFire = true;
958
959 }
960 }
961 }
962
963
964
965
966
967 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
968 // управление и работа внутренних систем корабля
969 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
970 // сделать:
971 // учитывать, как работает двигатель... стоим или летим...
972 // если не аркадный режим...
973 if (GameSpaceShipControlMode != 1) {
974 if (CurrentPlayerShipEnergy < GetShipEngineSystemEnergyUse(GameEngineSystem)*sharedPlayerFighter->TimeDelta) {
975 sharedPlayerFighter->MaxSpeed = 0.0f;
976 sharedPlayerFighter->MaxAcceler = 0.0f;
977 sharedPlayerFighter->MaxSpeedRotate = 0.0f;
978 // глушим двигатели
979 for (auto &tmpEngine : sharedPlayerFighter->Engines) {
980 if (auto sharedEngine = tmpEngine.lock())
981 sharedEngine->IsSuppressed = true;
982 }
983 if (!sharedPlayerFighter->EnginesLeft.empty()) {
984 for (auto &tmpEngineLeft : sharedPlayerFighter->EnginesLeft) {
985 if (auto sharedEngineLeft = tmpEngineLeft.lock())
986 sharedEngineLeft->IsSuppressed = true;
987 }
988 }
989 if (!sharedPlayerFighter->EnginesRight.empty()) {
990 for (auto &tmpEngineRight : sharedPlayerFighter->EnginesRight) {
991 if (auto sharedEngineRight = tmpEngineRight.lock())
992 sharedEngineRight->IsSuppressed = true;
993 }
994 }
995 } else {
996 sharedPlayerFighter->MaxSpeed = GetEnginePower(GameEngineSystem);
997 sharedPlayerFighter->MaxAcceler = GetEngineAcceleration(GameEngineSystem);
998 sharedPlayerFighter->MaxSpeedRotate = GetEngineRotatePower(GameEngineSystem);
999 // запускаем прорисовку
1000 for (auto &tmpEngine : sharedPlayerFighter->Engines) {
1001 if (auto sharedEngine = tmpEngine.lock())
1002 sharedEngine->IsSuppressed = false;
1003 }
1004 if (!sharedPlayerFighter->EnginesLeft.empty()) {
1005 for (auto &tmpEngineLeft : sharedPlayerFighter->EnginesLeft) {
1006 if (auto sharedEngineLeft = tmpEngineLeft.lock())
1007 sharedEngineLeft->IsSuppressed = false;
1008 }
1009 }
1010 if (!sharedPlayerFighter->EnginesRight.empty()) {
1011 for (auto &tmpEngineRight : sharedPlayerFighter->EnginesRight) {
1012 if (auto sharedEngineRight = tmpEngineRight.lock())
1013 sharedEngineRight->IsSuppressed = false;
1014 }
1015 }
1016 CurrentPlayerShipEnergy -= GetShipEngineSystemEnergyUse(GameEngineSystem)*sharedPlayerFighter->TimeDelta;
1017 }
1018 }
1019
1020
1021
1022 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1023 // энергия для перезарядки и выстрела...
1024 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1025 // сейчас получаем всю энергию для перезарядки и выстрела
1026 // потом лучше будет переделать на постепенный отбор энергии
1027 for (unsigned i = 0; i < sharedPlayerFighter->WeaponSlots.size(); i++) {
1028 if (GameConfig().Profile[CurrentProfile].Weapon[i] != 0) {
1029 if (auto sharedWeapon = sharedPlayerFighter->WeaponSlots[i].Weapon.lock()) {
1030 if (sharedWeapon->CurrentEnergyAccumulated < sharedWeapon->EnergyUse) {
1031 // если энергии не достаточно для зарядки орудия
1032 if (CurrentPlayerShipEnergy < sharedWeapon->EnergyUse) {
1033 // останавливаем перезарядку оружия
1034 sharedWeapon->LastFireTime += sharedPlayerFighter->TimeDelta;
1035 if (auto sharedFire = sharedWeapon->Fire.lock())
1036 sharedFire->IsSuppressed = true;
1037 } else {
1038 // если энергии достаточно, все нормально берем ее и перезаряжаем оружие
1039 sharedWeapon->CurrentEnergyAccumulated = sharedWeapon->EnergyUse;
1040 CurrentPlayerShipEnergy -= sharedWeapon->EnergyUse;
1041 }
1042 }
1043 }
1044 }
1045 }
1046
1047
1048 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1049 // питание других (защитных) систем
1050 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1051 if (CurrentPlayerShipEnergy >= GetShipEngineSystemEnergyUse(GameEngineSystem)*sharedPlayerFighter->TimeDelta) {
1052
1053 switch (GameAdvancedProtectionSystem) {
1054 // нано роботы
1055 case 1:
1056 // восстанавливаем на 0.5% в секунду
1057 if (sharedPlayerFighter->ArmorCurrentStatus < sharedPlayerFighter->ArmorInitialStatus) {
1058 CurrentPlayerShipEnergy -= GetShipProtectionSystemEnergyUse(GameAdvancedProtectionSystem) * sharedPlayerFighter->TimeDelta;
1059 sharedPlayerFighter->ArmorCurrentStatus += (sharedPlayerFighter->ArmorInitialStatus / 200.0f) * sharedPlayerFighter->TimeDelta;
1060 if (sharedPlayerFighter->ArmorCurrentStatus > sharedPlayerFighter->ArmorInitialStatus)
1061 sharedPlayerFighter->ArmorCurrentStatus = sharedPlayerFighter->ArmorInitialStatus;
1062 }
1063 break;
1064 // спец защитный слой
1065 case 2:
1066 break; // ничего не делаем
1067 // щит
1068 case 3:
1069 // восстанавливаем полностью за 4 секунды
1070 if (ShildEnergyStatus < 1.0f) {
1071 CurrentPlayerShipEnergy -= GetShipProtectionSystemEnergyUse(GameAdvancedProtectionSystem) * sharedPlayerFighter->TimeDelta;
1072 ShildEnergyStatus += 0.02f * sharedPlayerFighter->TimeDelta;
1073 if (ShildEnergyStatus > 1.0f)
1074 ShildEnergyStatus = 1.0f;
1075 }
1076 break;
1077 // отражатель
1078 case 4:
1079 // восстанавливаем полностью за 2 секунды
1080 if (ShildEnergyStatus < 1.0f) {
1081 CurrentPlayerShipEnergy -= GetShipProtectionSystemEnergyUse(GameAdvancedProtectionSystem) * sharedPlayerFighter->TimeDelta;
1082 ShildEnergyStatus += 0.03f * sharedPlayerFighter->TimeDelta;
1083 if (ShildEnergyStatus > 1.0f)
1084 ShildEnergyStatus = 1.0f;
1085 }
1086 break;
1087 }
1088 }
1089
1090
1091 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1092 // управление визуализацией щитов-дефлекторов
1093 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1094 if (auto sharedShild1 = Shild1.lock()) {
1095 sharedShild1->MoveSystem(sharedPlayerFighter->Location + sharedPlayerFighter->OBB.Location);
1096 sharedShild1->SetStartLocation(sharedPlayerFighter->Location + sharedPlayerFighter->OBB.Location);
1097 sharedShild1->RotateSystemAndParticlesByAngle(sharedPlayerFighter->Rotation);
1098 sharedShild1->ParticlesPerSec = (int)(40 * ShildEnergyStatus * ShildRadius);
1099 }
1100 if (auto sharedShild2 = Shild2.lock()) {
1101 sharedShild2->MoveSystem(sharedPlayerFighter->Location + sharedPlayerFighter->OBB.Location);
1102 sharedShild2->SetStartLocation(sharedPlayerFighter->Location + sharedPlayerFighter->OBB.Location);
1103 sharedShild2->RotateSystemAndParticlesByAngle(sharedPlayerFighter->Rotation);
1104 sharedShild2->ParticlesPerSec = (int)(5 * ShildEnergyStatus * ShildRadius);
1105 }
1106
1107
1108 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1109 // если реактор - можем генерировать энергию, если баттарея - нет
1110 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1111 CurrentPlayerShipEnergy += GetShipRechargeEnergy(GamePowerSystem)*sharedPlayerFighter->TimeDelta;
1112 if (CurrentPlayerShipEnergy > GetShipMaxEnergy(GamePowerSystem)) CurrentPlayerShipEnergy = GetShipMaxEnergy(GamePowerSystem);
1113
1114 }
1115
1116 } // astromenace namespace
1117 } // viewizard namespace
1118