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 // NOTE in future, use make_unique() to make unique_ptr-s (since C++14)
31
32 #include "../core/core.h"
33 #include "../config/config.h"
34 #include "../ui/cursor.h"
35 #include "../ui/game_speed.h"
36 #include "../ui/game/text.h"
37 #include "../ui/game/stopwatch.h"
38 #include "../assets/audio.h"
39 #include "../assets/texture.h"
40 #include "../gfx/star_system.h"
41 #include "../gfx/shadow_map.h"
42 #include "../script/script.h"
43 #include "../object3d/space_ship/space_ship.h"
44 #include "../command.h"
45 #include "../game/camera.h"
46 #include "../game/weapon_panel.h"
47 #include "../game/hud.h"
48 #include "../game.h" // FIXME "game.h" should be replaced by individual headers
49 #include <sstream>
50 #include <iomanip>
51
52 // NOTE switch to nested namespace definition (namespace A::B::C { ... }) (since C++17)
53 namespace viewizard {
54 namespace astromenace {
55
56 namespace {
57
58 std::unique_ptr<cMissionScript> MissionScript{};
59
60 eCommand GameExitCommand{eCommand::DO_NOTHING};
61
62 } // unnamed namespace
63
64
65
66
67
68
69
70 // замедление снарядов NPC ... 1-3...
71 int GameEnemyWeaponPenalty = 1;
72 // ум. защиты NPC объектов
73 int GameEnemyArmorPenalty = 1;
74 // "замедление" наведения NPC ... 1-4
75 int GameEnemyTargetingSpeedPenalty = 1;
76 // 0-ограничено, 1-нет
77 int GameUnlimitedAmmo = 0;
78 // 0-может быть уничтожено, 1-нет
79 int GameUndestroyableWeapon = 0;
80 // 1-аркада, 0-симулятор
81 int GameWeaponTargetingMode = 0;
82 // 1-аркада, 0-симулятор
83 int GameSpaceShipControlMode = 0;
84
85 int GameEngineSystem = 1;
86 int GameTargetingSystem = 1;
87 int GameAdvancedProtectionSystem = 0;
88 int GamePowerSystem = 1;
89 int GameTargetingMechanicSystem = 1;
90
91 // присваиваем в профайл только по завершению уровня!
92 float GameMoney = 0;
93 float GameExperience = 0;
94
95 int AlienShipsKillQuant;
96 float AlienShipsKillBonus;
97 int AlienMotherShipsKillQuant;
98 float AlienMotherShipsKillBonus;
99 int PirateShipsKillQuant;
100 float PirateShipsKillBonus;
101 int PirateVehiclesKillQuant;
102 float PirateVehiclesKillBonus;
103 int PirateBuildingsKillQuant;
104 float PirateBuildingsKillBonus;
105 int AsteroidsKillQuant;
106 float AsteroidsKillBonus;
107
108
109 // статус завершена игра или нет
110 bool GameMissionCompleteStatus = false;
111 bool GameMissionCompleteStatusShowDialog = false;
112
113 // собственно сам файтер
114 std::weak_ptr<cSpaceShip> PlayerFighter{};
115
116
117
118 // флаг отображения меню
119 bool GameMenu = false;
120 float GameContentTransp = 0.0f;
121 float LastGameUpdateTime = 0.0f;
122 eGameMenuStatus GameMenuStatus = eGameMenuStatus::GAME_MENU;
123
124 float GameButton1Transp = 1.0f;
125 float LastGameButton1UpdateTime = 0.0f;
126 float GameButton2Transp = 1.0f;
127 float LastGameButton2UpdateTime = 0.0f;
128 float GameButton3Transp = 1.0f;
129 float LastGameButton3UpdateTime = 0.0f;
130 float GameButton4Transp = 1.0f;
131 float LastGameButton4UpdateTime = 0.0f;
132 bool NeedShowGameMenu = false;
133 bool NeedHideGameMenu = false;
134
135
136 // работа с морганием вывода
137 extern float CurrentAlert2;
138 extern float CurrentAlert3;
139 extern float CurrentTime;
140
141 // работа с кораблем игрока
142 void InitGamePlayerShip();
143 void GamePlayerShip();
144 float GetShipMaxEnergy(int Num);
145 extern float CurrentPlayerShipEnergy;
146 extern int LastMouseX;
147 extern int LastMouseY;
148 extern int LastMouseXR;
149 extern int LastMouseYR;
150
151 // щит или дефлектор
152 extern std::weak_ptr<cParticleSystem> Shild1;
153 extern std::weak_ptr<cParticleSystem> Shild2;
154
155 // для звука открытия-закрытия меню в игре
156 unsigned int SoundShowHideMenu{0};
157
158
159 float LastGameOnOffUpdateTime = 0.0f;
160 float GameBlackTransp = 0.0f;
161 bool NeedOnGame = false;
162 bool NeedOffGame = false;
163
164
165
166
167 //------------------------------------------------------------------------------------
168 // Инициализация игровой части
169 //------------------------------------------------------------------------------------
InitGame()170 void InitGame()
171 {
172 ShadowMap_SizeSetup(eShadowMapSetup::Game);
173
174 if ((CurrentProfile < 0) || (CurrentProfile > 4))
175 CurrentProfile = 0;
176 if (CurrentMission == -1)
177 CurrentMission = 0;
178
179
180 GameEnemyWeaponPenalty = GameConfig().Profile[CurrentProfile].EnemyWeaponPenalty;
181 GameEnemyArmorPenalty = GameConfig().Profile[CurrentProfile].EnemyArmorPenalty;
182 GameEnemyTargetingSpeedPenalty = GameConfig().Profile[CurrentProfile].EnemyTargetingSpeedPenalty;
183 GameUnlimitedAmmo = GameConfig().Profile[CurrentProfile].UnlimitedAmmo;
184 GameUndestroyableWeapon = GameConfig().Profile[CurrentProfile].UndestroyableWeapon;
185 GameWeaponTargetingMode = GameConfig().Profile[CurrentProfile].WeaponTargetingMode;
186 GameSpaceShipControlMode = GameConfig().Profile[CurrentProfile].SpaceShipControlMode;
187
188 GameEngineSystem = GameConfig().Profile[CurrentProfile].EngineSystem;
189 // если симулятивный режим, ставим 1...
190 if (GameSpaceShipControlMode == 1)
191 if (GameEngineSystem == 0) GameEngineSystem = 1;
192
193 GameTargetingSystem = GameConfig().Profile[CurrentProfile].TargetingSystem;
194 GameAdvancedProtectionSystem = GameConfig().Profile[CurrentProfile].AdvancedProtectionSystem;
195 GamePowerSystem = GameConfig().Profile[CurrentProfile].PowerSystem;
196 GameTargetingMechanicSystem = GameConfig().Profile[CurrentProfile].TargetingMechanicSystem;
197 GameMoney = GameConfig().Profile[CurrentProfile].Money * 1.0f;
198
199 // убираем данные этого уровня
200 GameExperience = (GameConfig().Profile[CurrentProfile].Experience - GameConfig().Profile[CurrentProfile].ByMissionExperience[CurrentMission]) * 1.0f;
201
202 // grab mouse control for both - windows and fullscren mode (need this for multi-monitor systems)
203 SDL_SetWindowGrab(vw_GetSDLWindow(), SDL_TRUE);
204
205
206 // сбрасываем все кнопки мыши
207 vw_ResetMouseButtons();
208 // установка мышки на центр
209 float tmpViewportWidth, tmpViewportHeight;
210 vw_GetViewport(nullptr, nullptr, &tmpViewportWidth, &tmpViewportHeight);
211 SDL_WarpMouseInWindow(vw_GetSDLWindow(), tmpViewportWidth / 2, tmpViewportHeight / 2);
212 SetShowGameCursor(false);
213
214 LastMouseXR = 0;
215 LastMouseYR = 0;
216 SDL_GetMouseState(&LastMouseXR, &LastMouseYR);
217
218
219
220 cGameSpeed::GetInstance().InitGameSpeed();
221 cStopwatch::GetInstance().Reset(false); // should be after cGameSpeed init
222
223
224
225 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
226 // иним камеру, всегда до работы со скриптом (!!!)
227 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
228 InitCamera();
229
230
231 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
232 // иним корабль
233 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
234 InitGamePlayerShip();
235
236
237
238 // !!! пока загрузка идет полная на уровень, и наверно так и нужно оставить
239 // иначе нужно выносить перечень загружаемого в скрипт (менять не смогут уровни)
240
241 StarSystemInitByType(eDrawType::GAME); // should be before RunScript()
242
243 MissionScript.reset(new cMissionScript);
244 if (!MissionScript->RunScript(GetCurrentMissionFileName(), vw_GetTimeThread(1)))
245 MissionScript.reset();
246
247
248 SetupMissionNumberText(3.0f, CurrentMission + 1);
249 SetupMissionFailedText(0.0f); // reset previous status on game restart after fail
250
251
252 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
253 // немного "прокручиваем", чтобы сразу по появлению было заполнено
254 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
255 vw_ResizeScene(45.0f, GameConfig().InternalWidth / GameConfig().InternalHeight, 1.0f, 2000.0f);
256 vw_SetCameraLocation(sVECTOR3D{0.0f, 65.0f, -100.0f + 10.0f});
257 vw_SetCameraMoveAroundPoint(sVECTOR3D{0.0f, 0.0f, 10.0f}, 0.0f, sVECTOR3D{0.0f, 0.0f, 0.0f});
258
259
260 InitHUD(PlayerFighter,
261 GamePowerSystem ? (CurrentPlayerShipEnergy / GetShipMaxEnergy(GamePowerSystem)) : 0.0f,
262 GameConfig().Profile[CurrentProfile].Experience -
263 GameConfig().Profile[CurrentProfile].ByMissionExperience[CurrentMission],
264 GameConfig().Profile[CurrentProfile].Money);
265
266
267
268 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
269 // инициализация игрового меню
270 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
271 GameContentTransp = 0.0f;
272 LastGameUpdateTime = vw_GetTimeThread(0);
273 GameButton1Transp = 1.0f;
274 LastGameButton1UpdateTime = 0.0f;
275 GameButton2Transp = 1.0f;
276 LastGameButton2UpdateTime = 0.0f;
277 GameButton3Transp = 1.0f;
278 LastGameButton3UpdateTime = 0.0f;
279 GameButton4Transp = 1.0f;
280 LastGameButton4UpdateTime = 0.0f;
281 GameMenu = false;
282 NeedShowGameMenu = false;
283 NeedHideGameMenu = false;
284
285 GameMenuStatus = eGameMenuStatus::GAME_MENU;
286
287 AlienShipsKillQuant = 0;
288 AlienShipsKillBonus = 0.0f;
289 AlienMotherShipsKillQuant = 0;
290 AlienMotherShipsKillBonus = 0.0f;
291 PirateShipsKillQuant = 0;
292 PirateShipsKillBonus = 0.0f;
293 PirateVehiclesKillQuant = 0;
294 PirateVehiclesKillBonus = 0.0f;
295 PirateBuildingsKillQuant = 0;
296 PirateBuildingsKillBonus = 0.0f;
297 AsteroidsKillQuant = 0;
298 AsteroidsKillBonus = 0.0f;
299
300 CurrentTime = vw_GetTimeThread(0);
301 CurrentAlert2 = 1.0f;
302 CurrentAlert3 = 1.0f;
303
304 MenuStatus = eMenuStatus::GAME;
305
306 GameMissionCompleteStatus = false;
307 GameMissionCompleteStatusShowDialog = false;
308
309 SoundShowHideMenu = 0;
310
311 LastGameOnOffUpdateTime = vw_GetTimeThread(0);
312 GameBlackTransp = 1.0f;
313 NeedOnGame = true;
314 }
315
316
317
318
319
320
321
322 //------------------------------------------------------------------------------------
323 // Завершаем игру
324 //------------------------------------------------------------------------------------
ExitGame(eCommand Command)325 void ExitGame(eCommand Command)
326 {
327 GameExitCommand = Command;
328 NeedOffGame = true;
329 LastGameOnOffUpdateTime = vw_GetTimeThread(0);
330
331 // убираем меню
332 if (GameMenu) {
333 GameMenu = false;
334 NeedShowGameMenu = false;
335 NeedHideGameMenu = true;
336 SetShowGameCursor(false);
337 // установка в последюю точку указателя
338 SDL_WarpMouseInWindow(vw_GetSDLWindow(), LastMouseXR, LastMouseYR);
339 }
340 }
RealExitGame()341 void RealExitGame()
342 {
343 // удаляем корабль игрока
344 ReleaseSpaceShip(PlayerFighter);
345
346 vw_ReleaseAllParticleSystems2D();
347
348 vw_ReleaseParticleSystem(Shild1);
349 vw_ReleaseParticleSystem(Shild2);
350
351 // release mouse control
352 SDL_SetWindowGrab(vw_GetSDLWindow(), SDL_FALSE);
353 }
354
355 //------------------------------------------------------------------------------------
356 // Завершаем игру, нужно сохранить параметры
357 //------------------------------------------------------------------------------------
ExitGameWithSave(eCommand Command)358 void ExitGameWithSave(eCommand Command)
359 {
360 // данные по деньгам и опыту
361 ChangeGameConfig().Profile[CurrentProfile].Money = static_cast<int>(GameMoney);
362
363 // если получили больше опыта
364 if (GameConfig().Profile[CurrentProfile].Experience < static_cast<int>(GameExperience)) {
365 int Incr = static_cast<int>(GameExperience) - GameConfig().Profile[CurrentProfile].Experience;
366 ChangeGameConfig().Profile[CurrentProfile].ByMissionExperience[CurrentMission] += Incr;
367 ChangeGameConfig().Profile[CurrentProfile].Experience += Incr;
368 }
369 // увеличиваем счетчик пройденной миссии
370 ChangeGameConfig().Profile[CurrentProfile].MissionReplayCount[CurrentMission]++;
371
372 if (auto sharedPlayerFighter = PlayerFighter.lock()) {
373 // состояние корпуса коробля
374 ChangeGameConfig().Profile[CurrentProfile].ArmorStatus = sharedPlayerFighter->ArmorCurrentStatus;
375
376 // учет состояния оружия
377 for (unsigned i = 0; i < sharedPlayerFighter->WeaponSlots.size(); i++) {
378 if (GameConfig().Profile[CurrentProfile].Weapon[i] != 0) {
379 if (auto sharedWeapon = sharedPlayerFighter->WeaponSlots[i].Weapon.lock()) {
380 // если оружие было уничтожено во время игры
381 if (sharedWeapon->ArmorCurrentStatus <= 0.0f) {
382 ChangeGameConfig().Profile[CurrentProfile].WeaponAmmo[i] = 0;
383 ChangeGameConfig().Profile[CurrentProfile].Weapon[i] = 0;
384 } else {
385 // если все ок, нужно запомнить сколько осталось в боекомплекте
386 ChangeGameConfig().Profile[CurrentProfile].WeaponAmmo[i] = sharedWeapon->Ammo;
387 }
388 }
389 }
390 }
391 }
392
393 // ставим следующую миссию
394 CurrentMission++;
395 // перемещаем ограничитель дальше, если это нужно
396 if (GameConfig().Profile[CurrentProfile].OpenLevelNum < CurrentMission)
397 ChangeGameConfig().Profile[CurrentProfile].OpenLevelNum = CurrentMission;
398
399 // если дальше уже ничего нет, просто снимаем все... пусть игрок сам выберет
400 if (CurrentMission > (AllMission - 1)) {
401 CurrentMission = -1;
402 // это была последняя миссия, показываем список авторов
403 Command = eCommand::SWITCH_FROM_GAME_TO_CREDITS;
404 }
405
406 vw_ResetWheelStatus();
407 // ставим нужный лист миссий
408 StartMission = 0;
409 EndMission = 4;
410 if (CurrentMission != -1)
411 if (CurrentMission > 2) { // нужно сдвинуть лист, чтобы выбранный элемент был по середине списка
412 StartMission = CurrentMission-2;
413 EndMission = CurrentMission+2;
414
415 if (CurrentMission >= AllMission-2) {
416 StartMission = AllMission-5;
417 EndMission = AllMission-1;
418 }
419 }
420
421
422 ChangeGameConfig().Profile[CurrentProfile].LastMission = CurrentMission;
423
424 ExitGame(Command);
425 }
426
427
428
429
430
431
432 //------------------------------------------------------------------------------------
433 // Завершение игры, выиграли
434 //------------------------------------------------------------------------------------
SetGameMissionComplete()435 void SetGameMissionComplete()
436 {
437 // если убили, не устанавливаем!
438 if (PlayerFighter.expired())
439 return;
440 GameMissionCompleteStatus = true;
441 GameMissionCompleteStatusShowDialog = true;
442 }
443
444
445
446
447
448
449 //------------------------------------------------------------------------------------
450 // прорисовка игровой части
451 //------------------------------------------------------------------------------------
DrawGame()452 void DrawGame()
453 {
454
455 float TimeDelta = vw_GetTimeThread(0) - CurrentTime;
456 CurrentTime = vw_GetTimeThread(0);
457
458
459 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
460 // просчитываем индикацию
461 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
462 CurrentAlert2 -= TimeDelta;
463 if (CurrentAlert2 < 0.1f)
464 CurrentAlert2 = 1.0f;
465 CurrentAlert3 -= 1.9f * TimeDelta;
466 if (CurrentAlert3 < 0.1f)
467 CurrentAlert3 = 1.0f;
468
469
470
471
472 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
473 // Работа с 3д частью... прорисовка, просчет
474 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
475 CameraUpdate(vw_GetTimeThread(1));
476 vw_CameraLookAt();
477
478
479 // всегда первым рисуем скайбокс и "далекое" окружение
480 StarSystemDraw(eDrawType::GAME);
481
482
483 // рисуем все 3д объекты
484 DrawAllObject3D(eDrawType::GAME);
485
486
487 // после полной прорисовки делаем обновление данных
488 UpdateAllObject3D(vw_GetTimeThread(1));
489 vw_UpdateAllParticleSystems(vw_GetTimeThread(1));
490
491 // проверяем на столкновения
492 if (GameContentTransp < 0.99f) // не нужно проверять коллизии, включено меню
493 DetectCollisionAllObject3D();
494
495
496 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
497 // работаем со скриптом, пока он есть
498 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
499 if (MissionScript &&
500 (!MissionScript->Update(vw_GetTimeThread(1))))
501 MissionScript.reset();
502
503
504
505
506
507
508
509 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
510 // 2д часть
511 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
512 vw_Start2DMode(-1,1);
513
514
515
516
517
518 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
519 // Обработка состояния корабля игрока
520 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
521 GamePlayerShip();
522
523
524 UpdateHUD(PlayerFighter,
525 GamePowerSystem ? (CurrentPlayerShipEnergy / GetShipMaxEnergy(GamePowerSystem)) : 0.0f);
526 DrawHUD();
527 DrawWeaponPanels(PlayerFighter); // (?) part of HUD
528
529 cGameSpeed::GetInstance().Draw();
530
531
532 DrawMissionNumberText();
533 DrawMissionFailedText();
534
535
536
537
538 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
539 // Рисуем меню, всегда самое последнее в игровой 2д части
540 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
541 // делаем плавное появление меню
542 if (NeedShowGameMenu) {
543 GameContentTransp += 2.0f*(vw_GetTimeThread(0)-LastGameUpdateTime);
544 if (GameContentTransp >= 1.0f) {
545 GameContentTransp = 1.0f;
546 NeedShowGameMenu = false;
547 SetShowGameCursor(true);
548
549 // release mouse control
550 SDL_SetWindowGrab(vw_GetSDLWindow(), SDL_FALSE);
551 SDL_WarpMouseInWindow(vw_GetSDLWindow(), LastMouseXR, LastMouseYR);
552 }
553 // плавно возвращаем игре сокрость
554 if (GameContentTransp != 0.0f)
555 cGameSpeed::GetInstance().SetThreadSpeed((1.0f - GameContentTransp) * GameConfig().GameSpeed);
556 }
557 // делаем полавное угасание меню
558 if (NeedHideGameMenu) {
559 GameContentTransp -= vw_GetTimeThread(0) - LastGameUpdateTime;
560 if (GameContentTransp <= 0.0f) {
561 GameContentTransp = 0.0f;
562 NeedHideGameMenu = false;
563 GameMenuStatus = eGameMenuStatus::GAME_MENU;
564
565 // grab mouse control for both - windows and fullscren mode (need this for multi-monitor systems)
566 SDL_SetWindowGrab(vw_GetSDLWindow(), SDL_TRUE);
567 SDL_WarpMouseInWindow(vw_GetSDLWindow(), LastMouseXR, LastMouseYR);
568 }
569 // останавливаем игру
570 cGameSpeed::GetInstance().SetThreadSpeed((1.0f - GameContentTransp) * GameConfig().GameSpeed);
571 }
572 LastGameUpdateTime = vw_GetTimeThread(0);
573
574 // если можем - рисуем игровое меню
575 if (GameContentTransp > 0.0f) {
576 if (GameMissionCompleteStatus) {
577 // выводим подложку меню
578 sRECT SrcRect(2, 2, 564-2, 564-2);
579 sRECT DstRect(GameConfig().InternalWidth / 2 - 256 - 26, 128 - 28, GameConfig().InternalWidth / 2 - 256 + 534, 128 + 532);
580 vw_Draw2D(DstRect, SrcRect, GetPreloadedTextureAsset("menu/dialog512_512.tga"),
581 true, GameContentTransp);
582 // название меню
583 int Size = vw_TextWidthUTF32(vw_GetTextUTF32("Mission Complete"));
584 float WScale = 0;
585 if (Size > 190) {
586 Size = 190;
587 WScale = -190;
588 }
589 vw_DrawTextUTF32(GameConfig().InternalWidth / 2 - 123 - Size / 2, 128+21, WScale, 0, 1.0f, sRGBCOLOR{eRGBCOLOR::yellow}, 0.7f * GameContentTransp, vw_GetTextUTF32("Mission Complete"));
590
591
592 int Y = 128+90;
593 int Prir = 36;
594
595 vw_DrawTextUTF32(GameConfig().InternalWidth / 2 - 256+38, Y, 0, 0, 1.0f, sRGBCOLOR{eRGBCOLOR::yellow}, 0.5f * GameContentTransp, vw_GetTextUTF32("Type"));
596 Size = vw_TextWidthUTF32(vw_GetTextUTF32("Killed"));
597 WScale = 0;
598 if (Size > 70) {
599 Size = 70;
600 WScale = -70;
601 }
602 vw_DrawTextUTF32(GameConfig().InternalWidth / 2 - 31 + Size / 2, Y, WScale, 0, 1.0f, sRGBCOLOR{eRGBCOLOR::yellow}, 0.5f * GameContentTransp, vw_GetTextUTF32("Killed"));
603 Size = vw_TextWidthUTF32(vw_GetTextUTF32("Bonus"));
604 WScale = 0;
605 if (Size > 70) {
606 Size = 70;
607 WScale = -70;
608 }
609 vw_DrawTextUTF32(GameConfig().InternalWidth / 2 + 97 + Size / 2, Y, WScale, 0, 1.0f, sRGBCOLOR{eRGBCOLOR::yellow}, 0.5f * GameContentTransp, vw_GetTextUTF32("Bonus"));
610 Y += Prir;
611
612 WScale = -210;
613
614 // FIXME ostringstream is not so fast, move all string initialization into setup,
615 // all ostringstream-related code should be called only one time in dialog init
616 std::ostringstream tmpStream;
617
618 tmpStream << std::fixed << std::setw(4) << std::setfill('0') << AlienShipsKillQuant;
619 std::string AlienShipsKillQuantString{tmpStream.str()};
620 tmpStream.clear();
621 tmpStream.str(std::string{});
622 tmpStream << std::fixed << std::setw(6) << std::setprecision(0) << std::setfill('0') << AlienShipsKillBonus;
623 std::string AlienShipsKillBonusString{tmpStream.str()};
624 tmpStream.clear();
625 tmpStream.str(std::string{});
626
627 tmpStream << std::fixed << std::setw(4) << std::setfill('0') << AlienMotherShipsKillQuant;
628 std::string AlienMotherShipsKillQuantString{tmpStream.str()};
629 tmpStream.clear();
630 tmpStream.str(std::string{});
631 tmpStream << std::fixed << std::setw(6) << std::setprecision(0) << std::setfill('0') << AlienMotherShipsKillBonus;
632 std::string AlienMotherShipsKillBonusString{tmpStream.str()};
633 tmpStream.clear();
634 tmpStream.str(std::string{});
635
636 tmpStream << std::fixed << std::setw(4) << std::setfill('0') << PirateShipsKillQuant;
637 std::string PirateShipsKillQuantString{tmpStream.str()};
638 tmpStream.clear();
639 tmpStream.str(std::string{});
640 tmpStream << std::fixed << std::setw(6) << std::setprecision(0) << std::setfill('0') << PirateShipsKillBonus;
641 std::string PirateShipsKillBonusString{tmpStream.str()};
642 tmpStream.clear();
643 tmpStream.str(std::string{});
644
645 tmpStream << std::fixed << std::setw(4) << std::setfill('0') << PirateVehiclesKillQuant;
646 std::string PirateVehiclesKillQuantString{tmpStream.str()};
647 tmpStream.clear();
648 tmpStream.str(std::string{});
649 tmpStream << std::fixed << std::setw(6) << std::setprecision(0) << std::setfill('0') << PirateVehiclesKillBonus;
650 std::string PirateVehiclesKillBonusString{tmpStream.str()};
651 tmpStream.clear();
652 tmpStream.str(std::string{});
653
654 tmpStream << std::fixed << std::setw(4) << std::setfill('0') << PirateBuildingsKillQuant;
655 std::string PirateBuildingsKillQuantString{tmpStream.str()};
656 tmpStream.clear();
657 tmpStream.str(std::string{});
658 tmpStream << std::fixed << std::setw(6) << std::setprecision(0) << std::setfill('0') << PirateBuildingsKillBonus;
659 std::string PirateBuildingsKillBonusString{tmpStream.str()};
660 tmpStream.clear();
661 tmpStream.str(std::string{});
662
663 tmpStream << std::fixed << std::setw(4) << std::setfill('0') << AsteroidsKillQuant;
664 std::string AsteroidsKillQuantString{tmpStream.str()};
665 tmpStream.clear();
666 tmpStream.str(std::string{});
667 tmpStream << std::fixed << std::setw(6) << std::setprecision(0) << std::setfill('0') << AsteroidsKillBonus;
668 std::string AsteroidsKillBonusString{tmpStream.str()};
669 tmpStream.clear();
670 tmpStream.str(std::string{});
671
672 tmpStream << std::fixed << std::setw(4) << std::setfill('0') << AlienShipsKillQuant +
673 AlienMotherShipsKillQuant + PirateShipsKillQuant + PirateVehiclesKillQuant +
674 PirateBuildingsKillQuant + AsteroidsKillQuant;
675 std::string SummaryQuantString{tmpStream.str()};
676 tmpStream.clear();
677 tmpStream.str(std::string{});
678 tmpStream << std::fixed << std::setw(6) << std::setprecision(0) << std::setfill('0') << GameMoney - GameConfig().Profile[CurrentProfile].Money;
679 std::string SummaryBonusString{tmpStream.str()};
680 tmpStream.clear();
681 tmpStream.str(std::string{});
682
683 vw_DrawTextUTF32(GameConfig().InternalWidth / 2 - 256+38, Y, WScale, 0, 1.0f, sRGBCOLOR{eRGBCOLOR::white}, GameContentTransp, vw_GetTextUTF32("Alien Spaceships"));
684 vw_DrawText(GameConfig().InternalWidth / 2 + 10, Y, 0, 0, 1.0f, sRGBCOLOR{eRGBCOLOR::white}, GameContentTransp, AlienShipsKillQuantString);
685 vw_DrawText(GameConfig().InternalWidth / 2 + 126, Y, 0, 0, 1.0f, sRGBCOLOR{eRGBCOLOR::white}, GameContentTransp, AlienShipsKillBonusString);
686 Y += Prir;
687 vw_DrawTextUTF32(GameConfig().InternalWidth / 2 - 256+38, Y, WScale, 0, 1.0f, sRGBCOLOR{eRGBCOLOR::white}, GameContentTransp, vw_GetTextUTF32("Alien Motherships"));
688 vw_DrawText(GameConfig().InternalWidth / 2 + 10, Y, 0, 0, 1.0f, sRGBCOLOR{eRGBCOLOR::white}, GameContentTransp, AlienMotherShipsKillQuantString);
689 vw_DrawText(GameConfig().InternalWidth / 2 + 126, Y, 0, 0, 1.0f, sRGBCOLOR{eRGBCOLOR::white}, GameContentTransp, AlienMotherShipsKillBonusString);
690 Y += Prir;
691 vw_DrawTextUTF32(GameConfig().InternalWidth / 2 - 256+38, Y, WScale, 0, 1.0f, sRGBCOLOR{eRGBCOLOR::white}, GameContentTransp, vw_GetTextUTF32("Pirate Spaceships"));
692 vw_DrawText(GameConfig().InternalWidth / 2 + 10, Y, 0, 0, 1.0f, sRGBCOLOR{eRGBCOLOR::white}, GameContentTransp, PirateShipsKillQuantString);
693 vw_DrawText(GameConfig().InternalWidth / 2 + 126, Y, 0, 0, 1.0f, sRGBCOLOR{eRGBCOLOR::white}, GameContentTransp, PirateShipsKillBonusString);
694 Y += Prir;
695 vw_DrawTextUTF32(GameConfig().InternalWidth / 2 - 256+38, Y, WScale, 0, 1.0f, sRGBCOLOR{eRGBCOLOR::white}, GameContentTransp, vw_GetTextUTF32("Pirate Vehicles"));
696 vw_DrawText(GameConfig().InternalWidth / 2 + 10, Y, 0, 0, 1.0f, sRGBCOLOR{eRGBCOLOR::white}, GameContentTransp, PirateVehiclesKillQuantString);
697 vw_DrawText(GameConfig().InternalWidth / 2 + 126, Y, 0, 0, 1.0f, sRGBCOLOR{eRGBCOLOR::white}, GameContentTransp, PirateVehiclesKillBonusString);
698 Y += Prir;
699 vw_DrawTextUTF32(GameConfig().InternalWidth / 2 - 256+38, Y, WScale, 0, 1.0f, sRGBCOLOR{eRGBCOLOR::white}, GameContentTransp, vw_GetTextUTF32("Pirate Buildings"));
700 vw_DrawText(GameConfig().InternalWidth / 2 + 10, Y, 0, 0, 1.0f, sRGBCOLOR{eRGBCOLOR::white}, GameContentTransp, PirateBuildingsKillQuantString);
701 vw_DrawText(GameConfig().InternalWidth / 2 + 126, Y, 0, 0, 1.0f, sRGBCOLOR{eRGBCOLOR::white}, GameContentTransp, PirateBuildingsKillBonusString);
702 Y += Prir;
703 vw_DrawTextUTF32(GameConfig().InternalWidth / 2 - 256+38, Y, 0, 0, 1.0f, sRGBCOLOR{eRGBCOLOR::white}, GameContentTransp, vw_GetTextUTF32("Asteroids"));
704 vw_DrawText(GameConfig().InternalWidth / 2 + 10, Y, 0, 0, 1.0f, sRGBCOLOR{eRGBCOLOR::white}, GameContentTransp, AsteroidsKillQuantString);
705 vw_DrawText(GameConfig().InternalWidth / 2 + 126, Y, 0, 0, 1.0f, sRGBCOLOR{eRGBCOLOR::white}, GameContentTransp, AsteroidsKillBonusString);
706
707 Y += (int)(Prir*1.5);
708 vw_DrawTextUTF32(GameConfig().InternalWidth / 2 - 256+38, Y, WScale, 0, 1.0f, sRGBCOLOR{eRGBCOLOR::yellow}, GameContentTransp, vw_GetTextUTF32("Total"));
709 vw_DrawText(GameConfig().InternalWidth / 2 + 10, Y, 0, 0, 1.0f, sRGBCOLOR{eRGBCOLOR::white}, GameContentTransp, SummaryQuantString);
710 vw_DrawText(GameConfig().InternalWidth / 2+126, Y, 0, 0, 1.0f, sRGBCOLOR{eRGBCOLOR::white}, GameContentTransp, SummaryBonusString);
711
712 // выводим кнопки меню
713 int X = GameConfig().InternalWidth / 2 - 192;
714 Y = 545;
715 // продолжение игры
716 if (DrawButton384(X,Y, vw_GetTextUTF32("NEXT"), GameContentTransp, GameButton4Transp, LastGameButton4UpdateTime))
717 ExitGameWithSave(eCommand::SWITCH_FROM_GAME_TO_MISSION_MENU);
718 } else {
719 switch (GameMenuStatus) {
720 // основное меню игры
721 case eGameMenuStatus::GAME_MENU: {
722 // выводим подложку меню
723 sRECT SrcRect(2, 2, 564-2, 564-2);
724 sRECT DstRect(GameConfig().InternalWidth / 2 - 256+4-30, 128+2-30, GameConfig().InternalWidth / 2 - 256+564-30, 128+564-2-30);
725 vw_Draw2D(DstRect, SrcRect, GetPreloadedTextureAsset("menu/dialog512_512.tga"),
726 true, GameContentTransp);
727 // название меню
728 int SizeI = 17 + (234-vw_TextWidthUTF32(vw_GetTextUTF32("GAME MENU")))/2;
729 vw_DrawTextUTF32(GameConfig().InternalWidth / 2 - 256 + SizeI, 128+22, 0, 0, 1.0f, sRGBCOLOR{eRGBCOLOR::yellow}, 0.7f * GameContentTransp, vw_GetTextUTF32("GAME MENU"));
730
731 // выводим кнопки меню
732
733
734 int X = GameConfig().InternalWidth / 2 - 192;
735 int Y = 225;
736 int Prir = 100;
737
738 // продолжаем игру
739 if (DrawButton384(X,Y, vw_GetTextUTF32("RESUME"), GameContentTransp, GameButton1Transp, LastGameButton1UpdateTime)) {
740 GameMenu = false;
741 NeedShowGameMenu = false;
742 NeedHideGameMenu = true;
743 SetShowGameCursor(false);
744 // установка в последюю точку указателя
745 SDL_WarpMouseInWindow(vw_GetSDLWindow(), LastMouseXR, LastMouseYR);
746
747 if (vw_IsSoundAvailable(SoundShowHideMenu))
748 vw_StopSound(SoundShowHideMenu, 150);
749 SoundShowHideMenu = PlayMenuSFX(eMenuSFX::MissionHideMenu, 1.0f);
750 }
751
752 // выход в настройки
753 Y = Y+Prir;
754 if (DrawButton384(X,Y, vw_GetTextUTF32("OPTIONS"), GameContentTransp, GameButton2Transp, LastGameButton2UpdateTime)) {
755 SetOptionsMenu(eMenuStatus::OPTIONS);
756 GameMenuStatus = eGameMenuStatus::OPTIONS;
757 }
758
759 // прерываем игру
760 Y = Y+Prir;
761 if (DrawButton384(X,Y, vw_GetTextUTF32("RESTART"), GameContentTransp, GameButton3Transp, LastGameButton3UpdateTime)) {
762 // если убили, выводить диалог не нужно
763 if (PlayerFighter.expired())
764 ExitGame(eCommand::SWITCH_FROM_MENU_TO_GAME);
765 else
766 SetCurrentDialogBox(eDialogBox::RestartLevelNoSave);
767 }
768
769 // выход из игры
770 Y = Y+Prir;
771 if (DrawButton384(X,Y, vw_GetTextUTF32("QUIT"), GameContentTransp, GameButton4Transp, LastGameButton4UpdateTime)) {
772 // если убили, выводить диалог не нужно
773 if (PlayerFighter.expired())
774 ExitGame(eCommand::SWITCH_FROM_GAME_TO_MAIN_MENU);
775 else
776 SetCurrentDialogBox(eDialogBox::QuiToMenuNoSave);
777 }
778
779 break;
780 }
781
782 // основное меню настроек
783 case eGameMenuStatus::OPTIONS:
784 OptionsMenu(GameContentTransp, GameButton1Transp, LastGameButton1UpdateTime, GameButton2Transp, LastGameButton2UpdateTime);
785 break;
786 // меню продвинутых настроек
787 case eGameMenuStatus::OPTIONS_ADVANCED:
788 OptionsAdvMenu(GameContentTransp, GameButton1Transp, LastGameButton1UpdateTime, GameButton2Transp, LastGameButton2UpdateTime);
789 break;
790 // меню настройки интерфейса
791 case eGameMenuStatus::INTERFACE:
792 InterfaceMenu(GameContentTransp, GameButton1Transp, LastGameButton1UpdateTime);
793 break;
794 // меню настройки управления
795 case eGameMenuStatus::CONFCONTROL:
796 ConfControlMenu(GameContentTransp, GameButton1Transp, LastGameButton1UpdateTime);
797 break;
798
799
800 }
801
802
803 // вывод надписи пауза
804 sRECT SrcRect(0, 0, 256, 64);
805 sRECT DstRect(GameConfig().InternalWidth - 256 + 60, 768 - 54, GameConfig().InternalWidth + 60, 768 + 10);
806 if (GameContentTransp == 1.0f)
807 vw_Draw2D(DstRect, SrcRect, GetPreloadedTextureAsset(vw_GetText("lang/en/game/pause.tga")), true, CurrentAlert2*GameContentTransp);
808 else
809 vw_Draw2D(DstRect, SrcRect, GetPreloadedTextureAsset(vw_GetText("lang/en/game/pause.tga")), true, GameContentTransp);
810
811 }
812
813 }
814
815
816
817
818
819
820 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
821 // открываем меню
822 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
823 // если в игре - меню, если в меню - выход
824 if (!isDialogBoxDrawing()) {
825 if (!PlayerFighter.expired()) { // если не убили
826 if (vw_GetKeyStatus(SDLK_ESCAPE) || GameMissionCompleteStatusShowDialog) {
827 bool NeedPlaySfx = true;
828 if (GameMissionCompleteStatusShowDialog) {
829 // если уже было открыто меню и появляется меню окончания миссии, не проигрываем sfx
830 if (GameMenu)
831 NeedPlaySfx = false;
832 else
833 GameMenu = true;
834 } else
835 GameMenu = !GameMenu;
836
837 if (GameMenu && (!GameMissionCompleteStatus || GameMissionCompleteStatusShowDialog)) { // открытываем меню с результатом миссии и больше не даем ничего открывать, после завершения миссии
838 NeedShowGameMenu = true;
839 NeedHideGameMenu = false;
840 if (NeedPlaySfx && vw_IsSoundAvailable(SoundShowHideMenu))
841 vw_StopSound(SoundShowHideMenu, 150);
842 if (NeedPlaySfx)
843 SoundShowHideMenu = PlayMenuSFX(eMenuSFX::MissionShowMenu, 1.0f);
844 // сброс кнопки мышки, чтобы случайно не нажали
845 vw_GetMouseLeftClick(true);
846 } else if (!GameMenu && !GameMissionCompleteStatus) { // открыто меню с выводом результата миссии, нельзя давать его закрывать
847 NeedShowGameMenu = false;
848 NeedHideGameMenu = true;
849 // установка в последюю точку указателя
850 SDL_WarpMouseInWindow(vw_GetSDLWindow(), LastMouseXR, LastMouseYR);
851
852 if (NeedPlaySfx && vw_IsSoundAvailable(SoundShowHideMenu))
853 vw_StopSound(SoundShowHideMenu, 150);
854 if (NeedPlaySfx)
855 SoundShowHideMenu = PlayMenuSFX(eMenuSFX::MissionHideMenu, 1.0f);
856 SetShowGameCursor(false);
857 }
858
859 if (GameMissionCompleteStatus && !GameMissionCompleteStatusShowDialog) // в процессе вывода результатов разрешаем только выход в основное меню (отображение диалога)
860 SetCurrentDialogBox(eDialogBox::QuiToMenuNoSave);
861 GameMissionCompleteStatusShowDialog = false;
862 vw_SetKeyStatus(SDLK_ESCAPE, false);
863 }
864 }
865 }
866
867
868
869
870 // черное затемнение, если нужно
871 if (NeedOnGame) {
872 GameBlackTransp = 1.0f - 2.4f*(vw_GetTimeThread(0) - LastGameOnOffUpdateTime);
873 if (GameBlackTransp <= 0.0f) {
874 GameBlackTransp = 0.0f;
875 NeedOnGame = false;
876 }
877
878 sRECT SrcRect(0, 0, 2, 2);
879 sRECT DstRect(0, 0, GameConfig().InternalWidth, 768);
880 vw_Draw2D(DstRect, SrcRect, GetPreloadedTextureAsset("menu/blackpoint.tga"), true, GameBlackTransp);
881 }
882
883 // черное затемнение, если нужно
884 if (NeedOffGame) {
885 GameBlackTransp = 2.4f * (vw_GetTimeThread(0) - LastGameOnOffUpdateTime);
886 if (GameBlackTransp >= 1.0f) {
887 GameBlackTransp = 1.0f;
888 NeedOffGame = false;
889
890 // выходим из игры
891 RealExitGame();
892 cCommand::GetInstance().Set(GameExitCommand);
893 }
894
895 sRECT SrcRect(0, 0, 2, 2);
896 sRECT DstRect(0, 0, GameConfig().InternalWidth, 768);
897 vw_Draw2D(DstRect, SrcRect, GetPreloadedTextureAsset("menu/blackpoint.tga"), true, GameBlackTransp);
898 }
899
900
901
902 cStopwatch::GetInstance().Update();
903 cStopwatch::GetInstance().Draw();
904
905
906 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
907 // завершение 2д части
908 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
909 vw_End2DMode();
910 }
911
912 } // astromenace namespace
913 } // viewizard namespace
914