-
Notifications
You must be signed in to change notification settings - Fork 98
/
Copy pathMain.cpp
2805 lines (2416 loc) · 102 KB
/
Main.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
//////////////////////////////////////////////////////////////////////////////////////////
///\file Main.cpp
/// Main driver implementation of the Retro Terrain Engine.
///\author Copyright 2001 - 2006 Data Realms, LLC - http://www.datarealms.com
///\author Daniel Tabar
// Without this nested includes somewhere deep inside Allegro will summon winsock.h and it will conflict with winsock2.h from RakNet
// and we can't move "Network.h" here because for whatever reasons everything will collapse
#define WIN32_LEAN_AND_MEAN
#include "RTEManagers.h"
#include "MetaMan.h"
#include "ConsoleMan.h"
#include "GUI.h"
#include "GUICollectionBox.h"
#include "GUIProgressBar.h"
#include "GUIListBox.h"
#include "GUILabel.h"
#include "AllegroInput.h"
#include "AllegroScreen.h"
#include "AllegroBitmap.h"
#include "MainMenuGUI.h"
#include "ScenarioGUI.h"
#include "MetagameGUI.h"
#include "DataModule.h"
#include "SceneLayer.h"
#include "MOSParticle.h"
#include "MOSRotating.h"
#include "Controller.h"
#include "MultiplayerServerLobby.h"
#include "Network.h"
#include <DebugTool/DebugTool.h>
#include <Profiler/Profiler.h>
#include <algorithm>
#include <string>
#include <list>
#include "Reader.h"
#include "Writer.h"
#include "System.h"
#include "math.h"
#include "unzip.h"
#include <thread>
#if defined(__APPLE__)
#include "OsxUtil.h"
#endif // defined(__APPLE__)
#if defined(STEAM_BUILD)
#include "steam_api.h"
#include "SteamUGCMan.h"
#endif // defined (STEAM_BUILD)
// Has its own checks for steam build so we don't have to surround every achievement call
#include "AchievementMan.h"
#include "NetworkServer.h"
#include "NetworkClient.h"
#define MAX_FILENAME 512
#define FILEBUFFER_SIZE 8192
#define MAX_UNZIPPED_FILE_SIZE 104857600
using namespace RTE;
//////////////////////////////////////////////////////////////////////////////////////////
// Globals
enum TITLESEQUENCE
{
START = 0,
// DRL Logo
LOGOFADEIN,
LOGODISPLAY,
LOGOFADEOUT,
// Game notice
NOTICEFADEIN,
NOTICEDISPLAY,
NOTICEFADEOUT,
// Intro
FADEIN,
SPACEPAUSE1,
SHOWSLIDE1,
SHOWSLIDE2,
SHOWSLIDE3,
SHOWSLIDE4,
SHOWSLIDE5,
SHOWSLIDE6,
SHOWSLIDE7,
SHOWSLIDE8,
PRETITLE,
TITLEAPPEAR,
PLANETSCROLL,
PREMENU,
MENUAPPEAR,
// Main menu is active and operational
MENUACTIVE,
// Scenario mode views and transitions
MAINTOSCENARIO,
// Back from a scenario game to the scenario selection menu
SCENARIOFADEIN,
SCENARIOMENU,
// Campaign mode views and transitions
MAINTOCAMPAIGN,
// Back from a battle to the campaign view
CAMPAIGNFADEIN,
CAMPAIGNPLAY,
// Going back to the main menu view from a planet-centered view
PLANETTOMAIN,
FADESCROLLOUT,
FADEOUT,
END
};
// Intro slides
enum SLIDES
{
SLIDEPAST = 0,
SLIDENOW,
SLIDEVR,
SLIDETRAVEL,
SLIDEALIENS,
SLIDETRADE,
SLIDEPEACE,
SLIDEFRONTIER,
SLIDECOUNT
};
volatile bool g_Quit = false;
bool g_InActivity = false;
bool g_ResetActivity = false;
bool g_ResumeActivity = false;
bool g_ReturnToMainMenu = false;
int g_IntroState = START;
int g_TeamCount = 2;
int g_PlayerCount = 3;
int g_DifficultySetting = 4;
int g_StationOffsetX, g_StationOffsetY;
std::string g_LoadSingleModule = "";
MainMenuGUI *g_pMainMenuGUI = 0;
ScenarioGUI *g_pScenarioGUI = 0;
GUIControlManager *g_pLoadingGUI = 0;
BITMAP * g_pLoadingGUIBitmap = 0;
int g_LoadingGUIPosX = 0;
int g_LoadingGUIPosY = 0;
Writer *g_pLoadingLogWriter = 0;
AllegroInput *g_pGUIInput = 0;
AllegroScreen *g_pGUIScreen = 0;
Controller *g_pMainMenuController = 0;
enum StarSize
{
StarSmall = 0,
StarLarge,
StarHuge,
};
struct Star
{
// Bitmap representation
BITMAP *m_pBitmap;
// Center locaiton on screen
Vector m_Pos;
// Bitmap offset
// int m_Offset;
// Scrolling ratio
float m_ScrollRatio;
// Normalized intensity 0-1.0
float m_Intensity;
// Type
StarSize m_Size;
Star() { m_pBitmap = 0; m_Pos.Reset(); m_ScrollRatio = 1.0; m_Intensity = 1.0; m_Size = StarSmall; }
Star(BITMAP *pBitmap, Vector &pos, float scrollRatio, float intensity)
{ m_pBitmap = pBitmap; m_Pos = pos; m_ScrollRatio = scrollRatio; m_Intensity = intensity; }
};
//////////////////////////////////////////////////////////////////////////////////////////
// This handles when the quit or exit button is pressed on the window
void QuitHandler(void)
{
g_Quit = true;
}
END_OF_FUNCTION(QuitHandler)
//////////////////////////////////////////////////////////////////////////////////////////
// This updates the loading list [DEPRECATED DUE TO HIGH OVERHEAD, BUT KEPT HERE JUST IN CASE]
void _LoadingSplashProgressReport(std::string reportString, bool newItem = false)
{
if (g_pLoadingGUI)
{
// GUIProgressBar *pProgressBar = dynamic_cast<GUIProgressBar *>(g_pLoadingGUI->GetControl("ProgressBar"));
GUIListBox *pProgressBox = dynamic_cast<GUIListBox *>(g_pLoadingGUI->GetControl("ProgressBox"));
if (newItem || pProgressBox->GetItemList()->empty())
{
// Write out the last line to the log file before starting a new one
if (g_pLoadingLogWriter->WriterOK() && !pProgressBox->GetItemList()->empty())
*g_pLoadingLogWriter << pProgressBox->GetItemList()->back()->m_Name << "\n";
// Add the new report line
pProgressBox->AddItem(reportString);
}
else
{
int lastItemIndex = pProgressBox->GetItemList()->size() - 1;
GUIListPanel::Item *pItem = pProgressBox->GetItem(lastItemIndex);
pItem->m_Name = reportString;
pProgressBox->SetItemValues(lastItemIndex, *pItem);
}
g_UInputMan.Update();
g_pLoadingGUI->Update();
g_pLoadingGUI->Draw();
g_FrameMan.FlipFrameBuffers();
#if defined(STEAM_BUILD)
// pump steam while loading game too
// g_SteamUGCMan.Update();
// Two managers use the Steam API. Probably better to just use it here directly.
SteamAPI_RunCallbacks();
#endif //
// Quit if we're commanded to during loading
if (g_Quit)
exit(0);
}
}
//////////////////////////////////////////////////////////////////////////////////////////
// This updates the loading list. An optimizied version compared to previous one
void LoadingSplashProgressReport(std::string reportString, bool newItem = false)
{
if (g_pLoadingGUI)
{
g_UInputMan.Update();
if (newItem)
{
// Write out the last line to the log file before starting a new one
if (g_pLoadingLogWriter->WriterOK())
*g_pLoadingLogWriter << reportString << "\n";
// Scroll bitmap upwards
if (g_pLoadingGUIBitmap)
blit(g_pLoadingGUIBitmap, g_pLoadingGUIBitmap, 2, 12, 2, 2, g_pLoadingGUIBitmap->w - 3, g_pLoadingGUIBitmap->h - 12);
}
if (g_pLoadingGUIBitmap)
{
AllegroBitmap bmp(g_pLoadingGUIBitmap);
// Clear current line
rectfill(g_pLoadingGUIBitmap, 2, g_pLoadingGUIBitmap->h - 12, g_pLoadingGUIBitmap->w - 3, g_pLoadingGUIBitmap->h - 3, 54);
// Print new line
g_FrameMan.GetSmallFont()->DrawAligned(&bmp, 5, g_pLoadingGUIBitmap->h - 12, reportString.c_str(), GUIFont::Left);
// DrawAligned - MaxWidth is useless here, so we're just drawing lines manually
vline(g_pLoadingGUIBitmap, g_pLoadingGUIBitmap->w - 2, g_pLoadingGUIBitmap->h - 12, g_pLoadingGUIBitmap->h - 2, 33);
vline(g_pLoadingGUIBitmap, g_pLoadingGUIBitmap->w - 1, g_pLoadingGUIBitmap->h - 12, g_pLoadingGUIBitmap->h - 2, 33);
// Draw onto current frame buffer
blit(g_pLoadingGUIBitmap, g_FrameMan.GetBackBuffer32(), 0, 0, g_LoadingGUIPosX, g_LoadingGUIPosY, g_pLoadingGUIBitmap->w, g_pLoadingGUIBitmap->h);
g_FrameMan.FlipFrameBuffers();
}
#if defined(STEAM_BUILD)
// pump steam while loading game too
// g_SteamUGCMan.Update();
// Two managers use the Steam API. Probably better to just use it here directly.
SteamAPI_RunCallbacks();
#endif //
// Quit if we're commanded to during loading
if (g_Quit)
exit(0);
}
}
//////////////////////////////////////////////////////////////////////////////////////////
// Finding and loading all DataModule:s
bool LoadDataModules()
{
// TODO: REMOVE
// return true;
// Loading splash screen
g_FrameMan.ClearBackBuffer32();
// g_FrameMan.LoadPalette("Base.rte/palette.bmp");
SceneLayer *pLoadingSplash = new SceneLayer();
pLoadingSplash->Create(ContentFile("Base.rte/GUIs/LoadingSplash.bmp"), false, Vector(), true, false, Vector(1.0, 0));
// hcoded offset to make room for the loading box
pLoadingSplash->SetOffset(Vector(((pLoadingSplash->GetBitmap()->w - g_FrameMan.GetResX()) / 2) + 110, 0));
// Draw onto wrapped strip centered vertically on the screen
Box splashBox(Vector(0, (g_FrameMan.GetResY() - pLoadingSplash->GetBitmap()->h) / 2), g_FrameMan.GetResX(), pLoadingSplash->GetBitmap()->h);
pLoadingSplash->Draw(g_FrameMan.GetBackBuffer32(), splashBox);
delete pLoadingSplash;
pLoadingSplash = 0;
/*int x = g_FrameMan.GetResX() / 2;
int y = g_FrameMan.GetResY() - 50;
AllegroBitmap bmp(g_FrameMan.GetBackBuffer32());
g_FrameMan.GetLargeFont()->DrawAligned(&bmp, x, y, "PLANETOID PIONEERS FACT #1", 1);
g_FrameMan.GetLargeFont()->DrawAligned(&bmp, x, y + 12, "Mods are loaded orders of magnitude faster!", 1);*/
g_FrameMan.FlipFrameBuffers();
// Set up the loading GUI
if (!g_pLoadingGUI)
{
g_pLoadingGUI = new GUIControlManager();
// TODO: This should be using the 32bpp main menu skin, but isn't becuase it needs the config of the base for its listbox
// Can get away with this hack for now because the list box that the laoding menu uses displays ok when drawn on a 32bpp buffer,
// when it's 8bpp internally, since it does not use any masked_blit calls to draw listboxes.
// Note also how the GUIScreen passed in here has been created with an 8bpp bitmap, since that is what determines what the gui manager uses internally
if(!g_pLoadingGUI->Create(g_pGUIScreen, g_pGUIInput, "Base.rte/GUIs/Skins/MainMenu", "LoadingSkin.ini"))
DDTAbort("Failed to create GUI Control Manager and load it from Base.rte/GUIs/Skins/MainMenu/LoadingSkin.ini");
g_pLoadingGUI->Load("Base.rte/GUIs/LoadingGUI.ini");
}
// Place and clear the sectionProgress box
dynamic_cast<GUICollectionBox *>(g_pLoadingGUI->GetControl("root"))->SetSize(g_FrameMan.GetResX(), g_FrameMan.GetResY());
GUIListBox *pBox = dynamic_cast<GUIListBox *>(g_pLoadingGUI->GetControl("ProgressBox"));
// Make the box a bit bigger if there's room in higher, HD resolutions
if (g_FrameMan.GetResX() >= 960)
{
// Make the loading progress box fill the right third of the screen
pBox->Resize((g_FrameMan.GetResX() / 3) - 12, pBox->GetHeight());
pBox->SetPositionRel(g_FrameMan.GetResX() - pBox->GetWidth() - 12, (g_FrameMan.GetResY() / 2) - (pBox->GetHeight() / 2));
}
// Legacy positioning and sizing when running low resolutions
else
pBox->SetPositionRel(g_FrameMan.GetResX() - pBox->GetWidth() - 12, (g_FrameMan.GetResY() / 2) - (pBox->GetHeight() / 2));
pBox->ClearList();
// Show and position the registration notice label
GUILabel *pRegLabel = dynamic_cast<GUILabel *>(g_pLoadingGUI->GetControl("LabelRegisterNotice"));
if (!g_LicenseMan.HasValidatedLicense())
{
// Make room for the notice over the list
pBox->SetSize(pBox->GetWidth(), 258);
pBox->SetPositionRel(pBox->GetXPos(), pBox->GetYPos() + pRegLabel->GetHeight());
// Show the notice label
pRegLabel->SetPositionRel(pBox->GetXPos(), pBox->GetYPos() - pRegLabel->GetHeight() - 6);
pRegLabel->SetText("Unregistered Copy");
pRegLabel->SetVisible(true);
}
else
pRegLabel->SetVisible(false);
if (!g_SettingsMan.DisableLoadingScreen())
{
//New mechanism to speed up loading times as it turned out that a massive amount of time is spent
// to update UI control.
if (!g_pLoadingGUIBitmap)
{
pBox->SetVisible(false);
g_pLoadingGUIBitmap = create_bitmap_ex(8, pBox->GetWidth(), pBox->GetHeight());
clear_to_color(g_pLoadingGUIBitmap, 54);
rect(g_pLoadingGUIBitmap, 0, 0, pBox->GetWidth() - 1, pBox->GetHeight() - 1, 33);
rect(g_pLoadingGUIBitmap, 1, 1, pBox->GetWidth() - 2, pBox->GetHeight() - 2, 33);
g_LoadingGUIPosX = pBox->GetXPos();
g_LoadingGUIPosY = pBox->GetYPos();
}
}
// Create the loading log writer
if (!g_pLoadingLogWriter)
g_pLoadingLogWriter = new Writer("LogLoading.txt");
// Clear out the PresetMan and all its DataModules
g_PresetMan.Destroy();
g_PresetMan.Create();
#if defined(STEAM_BUILD)
// Download all subscribed-to data module files from Steam and copy them all into the game install dir
// so they can be unzipped next and loaded
g_SteamUGCMan.DownloadAllWorkshopDataModules(&LoadingSplashProgressReport);
#endif // STEAM_BUILD
// Unzip all *.rte.zip files found in the install dir, overwriting all files already existing
// This will cause extracted and available data modules to be updated to whatever is within their corresponding zip files
// The point of this is that it facilitates downloaded mods being loaded without having to be manually unzipped first by the user
al_ffblk zippedModuleInfo;
unzFile zipFile;
for (int result = al_findfirst("*.rte.zip", &zippedModuleInfo, FA_ALL); result == 0; result = al_findnext(&zippedModuleInfo))
{
// Report that we are attempting to unzip this thing
LoadingSplashProgressReport("Unzipping " + string(zippedModuleInfo.name), true);
// THIS IS WRONG - rely on the working directory instead; this hard method will fail when the exe is not in the install dir like when running in visual studio
/*
// Get the absolute path to the zip, which lies next to the game exe in the same dir
get_executable_name(zipFilePath, sizeof(zipFilePath));
// Replace the exe filename with the zip one we found while enumerating all rte.zip files
replace_filename(zipFilePath, zipFilePath, zippedModuleInfo.name, sizeof(zipFilePath));
*/
// Try to open the zipped and unzip it into place as an exposed data module
if (strlen(zippedModuleInfo.name) > 0 && (zipFile = unzOpen(zippedModuleInfo.name)))
{
// Go through and extract every file inside this zip, overwriting every colliding file that already exists in the install dir
// Get info about the zip file
unz_global_info zipFileInfo;
if (unzGetGlobalInfo(zipFile, &zipFileInfo) != UNZ_OK)
LoadingSplashProgressReport("Could not read global file info of: " + string(zippedModuleInfo.name), true);
// Buffer to hold data read from the zip file.
char fileBuffer[FILEBUFFER_SIZE];
// Loop to extract all files
bool abortExtract = false;
for (uLong i = 0; i < zipFileInfo.number_entry && !abortExtract; ++i)
{
// Get info about current file.
unz_file_info fileInfo;
char outputFileName[MAX_FILENAME];
if (unzGetCurrentFileInfo(zipFile, &fileInfo, outputFileName, MAX_FILENAME, NULL, 0, NULL, 0) != UNZ_OK)
LoadingSplashProgressReport("Could not read file info of: " + string(outputFileName), true);
// Check if the directory we are trying to extract into exists, and if not, create it
char outputDirName[MAX_FILENAME];
char parentDirName[MAX_FILENAME];
// Copy the file path to a separate dir path
strcpy(outputDirName, outputFileName);
// Find the last slash in the dir path, so we can cut off everything after that (ie the actual filename), and only have the directory path left
char *pSlashPos = strrchr(outputDirName, '/');
// Try to find the other kind of slash if we found none
if (!pSlashPos)
pSlashPos = strrchr(outputDirName, '\\');
// Now that we have the slash position, terminate the directory path string right after there
if (pSlashPos)
*(++pSlashPos) = 0;
// If that file's directory doesn't exist yet, then create it, and all its parent directories above if need be
for (int nested = 0; !file_exists(outputDirName, FA_DIREC, 0) && pSlashPos; ++nested)
{
// Keep making new working copies of the path that we can dice up
strcpy(parentDirName, outputDirName[0] == '.' ? &(outputDirName[2]) : outputDirName);
// Start off at the beginning
pSlashPos = parentDirName;
for (int j = 0; j <= nested && pSlashPos; ++j)
{
// Find the first slash so we can isolate the folders in the hierarchy, in descending seniority
pSlashPos = strchr(pSlashPos, '/');
// If we can't find any more slashes, then quit
if (!pSlashPos)
break;
// If we did find a slash, go to one past it slash and try to find the next one
pSlashPos++;
}
// No more nested folders to make
if (!pSlashPos)
break;
// Terminate there so we are making the most senior folder
*(pSlashPos) = 0;
g_System.MakeDirectory(parentDirName);
}
// Check if this entry is a directory or file
if (outputFileName[strlen(outputFileName) - 1] == '/' || outputFileName[strlen(outputFileName) - 1] == '\\')
{
// Entry is a directory, so create it.
LoadingSplashProgressReport("Creating Dir: " + string(outputFileName), true);
g_System.MakeDirectory(outputFileName);
}
else
// So it's a file
{
// Validate so only certain filetypes are extracted: .ini .txt .lua .cfg .bmp .png .jpg .jpeg .wav .ogg .mp3
// Get the file extension
string extension(get_extension(outputFileName));
std::transform(extension.begin(), extension.end(), extension.begin(), ::tolower);
const char *ext = extension.c_str();
// Validate only certain filetypes to be included! .ini .txt .lua .cfg .bmp .png .jpg .jpeg .wav .ogg .mp3
if (!(strcmp(ext, "ini") == 0 || strcmp(ext, "txt") == 0 || strcmp(ext, "lua") == 0 || strcmp(ext, "cfg") == 0 ||
strcmp(ext, "bmp") == 0 || strcmp(ext, "png") == 0 || strcmp(ext, "jpg") == 0 || strcmp(ext, "jpeg") == 0 ||
strcmp(ext, "wav") == 0 || strcmp(ext, "ogg") == 0 || strcmp(ext, "mp3") == 0 ||
strcmp(ext, "xlsx") == 0 || strcmp(ext, "rtf") == 0 || strcmp(ext, "dat") == 0))
{
LoadingSplashProgressReport("Skipping: " + string(outputFileName) + " - bad extension!", true);
// Keep going though!!
// Close the read file within the zip archive
unzCloseCurrentFile(zipFile);
// Go the the next entry listed in the zip file.
if ((i + 1) < zipFileInfo.number_entry)
{
if (unzGoToNextFile(zipFile) != UNZ_OK)
{
LoadingSplashProgressReport("Could not read next file inside zip " + string(zippedModuleInfo.name) + " - Aborting extraction!", true);
abortExtract = true;
break;
}
}
// Onto the next file
continue;
}
// Entry is a file, so extract it.
LoadingSplashProgressReport("Extracting: " + string(outputFileName), true);
if (unzOpenCurrentFile(zipFile) != UNZ_OK)
LoadingSplashProgressReport("Could not open file within " + string(zippedModuleInfo.name), true);
// Open a file to write out the data.
FILE *outputFile = fopen(outputFileName, "wb");
if (outputFile == NULL)
LoadingSplashProgressReport("Could not open/create destination file while unzipping " + string(zippedModuleInfo.name), true);
// Write the entire file out, reading in buffer size chunks and spitting them out to the output stream
int bytesRead = 0;
int64_t totalBytesRead = 0;
do
{
// Read a chunk
bytesRead = unzReadCurrentFile(zipFile, fileBuffer, FILEBUFFER_SIZE);
// Add to total tally
totalBytesRead += bytesRead;
// Sanity check how damn big this file we're writing is becoming.. could prevent zip bomb exploits: http://en.wikipedia.org/wiki/Zip_bomb
if (totalBytesRead >= MAX_UNZIPPED_FILE_SIZE)
{
LoadingSplashProgressReport("File inside zip " + string(zippedModuleInfo.name) + " is turning out WAY TOO LARGE - Aborting extraction!", true);
abortExtract = true;
break;
}
// Write data to the output file
if (bytesRead > 0)
fwrite(fileBuffer, bytesRead, 1, outputFile);
else if (bytesRead < 0)
{
LoadingSplashProgressReport("Error while reading zip " + string(zippedModuleInfo.name), true);
abortExtract = true;
break;
}
}
// Keep going while bytes are still being read (0 means end of file)
while (bytesRead > 0 && outputFile);
// Close the output file
fclose(outputFile);
// Close the read file within the zip archive
unzCloseCurrentFile(zipFile);
}
// Go the the next entry listed in the zip file.
if ((i + 1) < zipFileInfo.number_entry)
{
if (unzGoToNextFile(zipFile) != UNZ_OK)
{
LoadingSplashProgressReport("Could not read next file inside zip " + string(zippedModuleInfo.name) + " - Aborting extraction!", true);
break;
}
}
}
// Close the zip file we've opened
unzClose(zipFile);
// DELETE the zip in the install dir after decompression
// (whether successful or not - any rte.zip in the install dir is throwaway and shouldn't keep failing each load in case they do fail)
LoadingSplashProgressReport("Deleting extracted Data Module zip: " + string(zippedModuleInfo.name), true);
delete_file(zippedModuleInfo.name);
}
// Indicate that the unzip went awry
else
{
// DELETE the zip in the install dir after decompression
// (whether successful or not - any rte.zip in the install dir is throwaway and shouldn't keep failing each load in case they do fail)
LoadingSplashProgressReport("FAILED to unzip " + string(zippedModuleInfo.name) + " - deleting it now!", true);
delete_file(zippedModuleInfo.name);
}
}
// Close the file search to avoid memory leaks
al_findclose(&zippedModuleInfo);
///////////////////////////////////////////////////////////////
// Load all the official modules first!
if (!g_PresetMan.LoadDataModule("Base.rte", true, &LoadingSplashProgressReport))
return false;
if (g_LoadSingleModule != "")
{
if (g_LoadSingleModule != "Base.rte")
if (!g_PresetMan.LoadDataModule(g_LoadSingleModule, false, &LoadingSplashProgressReport))
return false;
return true;
}
///* TODO: REPLACE
if (!g_PresetMan.LoadDataModule("Coalition.rte", true, &LoadingSplashProgressReport))
return false;
if (!g_PresetMan.LoadDataModule("Techion.rte", true, &LoadingSplashProgressReport))
return false;
if (!g_PresetMan.LoadDataModule("Imperatus.rte", true, &LoadingSplashProgressReport))
return false;
if (!g_PresetMan.LoadDataModule("Ronin.rte", true, &LoadingSplashProgressReport))
return false;
if (!g_PresetMan.LoadDataModule("Dummy.rte", true, &LoadingSplashProgressReport))
return false;
if (!g_PresetMan.LoadDataModule("Browncoats.rte", true, &LoadingSplashProgressReport))
return false;
if (!g_PresetMan.LoadDataModule("Tutorial.rte", true, &LoadingSplashProgressReport))
return false;
if (!g_PresetMan.LoadDataModule("Missions.rte", true, &LoadingSplashProgressReport))
return false;
//Read module properties to find out which modules should be loaded earlier than others
al_ffblk moduleInfo;
int moduleID = 0;
std::list<std::string> loadFirst;
for (int result = al_findfirst("*.rte", &moduleInfo, FA_DIREC | FA_RDONLY); result == 0; result = al_findnext(&moduleInfo))
{
moduleID = g_PresetMan.GetModuleID(moduleInfo.name);
// Make sure we don't load properties of already loaded official modules
if (strlen(moduleInfo.name) > 0 && (moduleID < 0 || moduleID >= g_PresetMan.GetOfficialModuleCount()) && string(moduleInfo.name) != "Metagames.rte" && string(moduleInfo.name) != "Scenes.rte")
{
// See if we can find that phantom property in this data module's index.ini that would indicate it should have prioritized loading
if (ASCIIFileContainsString(string(moduleInfo.name) + "/Index.ini", "LoadFirst = 1"))
loadFirst.push_back(moduleInfo.name);
}
else
{
}
}
// Close the file search to avoid memory leaks
al_findclose(&moduleInfo);
//Load preceding modules first
for (std::list<std::string>::iterator itr = loadFirst.begin(); itr != loadFirst.end(); ++itr)
{
if (!g_SettingsMan.IsModDisabled(*itr))
{
moduleID = g_PresetMan.GetModuleID(*itr);
// Make sure we don't add the official metagames module among these; they should be loaded in explicit order before and after these unofficial ones
if ((*itr).length() > 0 && (moduleID < 0 || moduleID >= g_PresetMan.GetOfficialModuleCount()) && *itr != "Metagames.rte" && *itr != "Scenes.rte")
{
// Actually load the unofficial data module
if (!g_PresetMan.LoadDataModule(*itr, false, &LoadingSplashProgressReport))
{
// Report error?
}
}
}
}
loadFirst.clear();
////////////////////////////////////////////////////////////////////////////////////////////////////
// Search for any additional data modules, if license is registered! - NAH let them load mods
// if (g_LicenseMan.HasValidatedLicense())
// {
moduleID = 0;
for (int result = al_findfirst("*.rte", &moduleInfo, FA_DIREC | FA_RDONLY); result == 0; result = al_findnext(&moduleInfo))
{
if (!g_SettingsMan.IsModDisabled(moduleInfo.name))
{
moduleID = g_PresetMan.GetModuleID(moduleInfo.name);
// Make sure we don't add the official metagames module among these; they should be loaded in explicit order before and after these unofficial ones
if (strlen(moduleInfo.name) > 0 && (moduleID < 0 || moduleID >= g_PresetMan.GetOfficialModuleCount()) && string(moduleInfo.name) != "Metagames.rte" && string(moduleInfo.name) != "Scenes.rte")
{
/* Redundant with weegee's other ssytem that allows sideloading etc
// If workshop is enabled, then SKIP loading any unofficial mods that are neither subscribed-to nor published by this user
if (g_SteamUGCMan.IsCloudEnabled() && (!g_SteamUGCMan.IsModuleSubscribedTo(moduleInfo.name) && !g_SteamUGCMan.IsModulePublished(moduleInfo.name)))
{
LoadingSplashProgressReport("NOT Loading Data Module: " + string(moduleInfo.name) + " - it is not subscribed to in the Workshop!", true);
continue;
}
*/
// Actually load the unofficial data module
if (!g_PresetMan.LoadDataModule(string(moduleInfo.name), false, &LoadingSplashProgressReport))
{
// Report error?
}
}
else
{
// TODO: Log this and continue gracefully instead
// LoadDataModule can return false (esp since it amy try to load already loaded modules, and that's ok) and shouldn't cause stop
// char error[512];
// sprintf(error, "Failed to load Data Module: %s\n\nMake sure it contains an Index.ini file that defines a \"DataModule\"!", moduleInfo.name);
// DDTAbort(error);
// return false;
}
}
}
// Close the file search to avoid memory leaks
al_findclose(&moduleInfo);
// }
//*/
// Load scenes and metagames AFTER all other techs etc are loaded; might be referring to stuff in user mods
if (!g_PresetMan.LoadDataModule("Scenes.rte", false, &LoadingSplashProgressReport))
return false;
if (!g_PresetMan.LoadDataModule("Metagames.rte", false, &LoadingSplashProgressReport))
return false;
/* We are now doing this as line by line reports come in to LoadingSplashProgressReport
// Write out entire loading log to a file
Writer writer("LogLoading.txt");
if (writer.WriterOK())
{
GUIListBox *pProgressBox = dynamic_cast<GUIListBox *>(g_pLoadingGUI->GetControl("ProgressBox"));
for (std::vector<GUIListBox::Item *>::iterator itr = pProgressBox->GetItemList()->begin(); itr != pProgressBox->GetItemList()->end(); itr++)
writer << (*itr)->m_Name << "\n";
}
*/
return true;
}
//////////////////////////////////////////////////////////////////////////////////////////
// Load and init the Main menu
bool InitMainMenu()
{
// Load the palette
g_FrameMan.LoadPalette("Base.rte/palette.bmp");
// Create the Main Menu GUI
g_pGUIInput = new AllegroInput(-1);
g_pGUIScreen = new AllegroScreen(g_FrameMan.GetBackBuffer32());
// Have to load the data modules in here becuase it needs the GUIScreen and input for the loading GUI
LoadDataModules();
// Create the main menu interface
g_pMainMenuGUI = new MainMenuGUI();
g_pMainMenuController = new Controller(Controller::CIM_PLAYER, 0);
g_pMainMenuController->SetTeam(0);
g_pMainMenuGUI->Create(g_pMainMenuController);
// As well as the Scenario setup menu interface
g_pScenarioGUI = new ScenarioGUI();
g_pScenarioGUI->Create(g_pMainMenuController);
// And the Metagame GUI too
g_MetaMan.GetGUI()->Create(g_pMainMenuController);
return true;
}
//////////////////////////////////////////////////////////////////////////////////////////
// Load all Managers
bool ResetActivity()
{
g_ResetActivity = false;
// Clear and reset out things
g_FrameMan.ClearBackBuffer8();
g_FrameMan.FlipFrameBuffers();
g_AudioMan.StopAll();
// Quit if we should
if (g_Quit)
return false;
// TODO: Deal with GUI resetting here!$@#")
// Clear out all MO's
g_MovableMan.PurgeAllMOs();
// Have to reset TimerMan before creating anything else because all timers are reset against it
g_TimerMan.ResetTime();
/*
// Load all the modules anew
LoadDataModules();
// g_PresetMan.Create();
// g_AudioMan.Create();
char report[512];
sprintf(report, "Building Scene: \"%s\"...", g_ActivityMan.GetActivity()->GetSceneName().c_str());
LoadingSplashProgressReport(report, true);
g_SceneMan.LoadScene(g_ActivityMan.GetActivity()->GetSceneName());
sprintf(report, "\tDone! %c", -42);
LoadingSplashProgressReport(report, true);
LoadingSplashProgressReport(" ", true);
// Ask user to press key before start
LoadingSplashProgressReport("PRESS ANY KEY TO START!", true);
Timer blinkTimer;
do
{
sprintf(report, "PRESS ANY KEY TO START! %c", blinkTimer.AlternateSim(300) ? -65 : ' ');
LoadingSplashProgressReport(report, false);
// Reset the key press states
g_UInputMan.Update();
g_TimerMan.Update();
rest(30);
}
while (!g_UInputMan.AnyPress() && !g_Quit);
*/
g_FrameMan.LoadPalette("Base.rte/palette.bmp");
g_FrameMan.FlipFrameBuffers();
// Reset timerman again after loading so there's no residual delay
g_TimerMan.ResetTime();
// Enable time averaging since it helps with animation jerkyness
g_TimerMan.EnableAveraging(true);
// Unpause
g_TimerMan.PauseSim(false);
// TODO: Remove
// g_ActivityMan.GetActivity()->SetActivityState(Activity::TESTING);
// Start the game with previous settings
int error = g_ActivityMan.RestartActivity();
if (error >= 0)
g_InActivity = true;
// Somehting went wrong when restarting, so drop out to scenario menu and open the console to show the error messages
else
{
g_InActivity = false;
g_ActivityMan.PauseActivity();
g_ConsoleMan.SetEnabled(true);
g_IntroState = MAINTOSCENARIO;
return false;
}
return true;
}
//////////////////////////////////////////////////////////////////////////////////////////
// Start the simulation back up after being paused
void ResumeActivity()
{
if (g_ActivityMan.GetActivity()->GetActivityState() != Activity::NOTSTARTED)
{
g_Quit = false;
g_InActivity = true;
g_ResumeActivity = false;
g_FrameMan.ClearBackBuffer8();
g_FrameMan.FlipFrameBuffers();
// Load in-game palette
g_FrameMan.LoadPalette("Base.rte/palette.bmp");
// Unpause the game
g_FrameMan.ResetFrameTimer();
// Enable time averaging since it helps with animation jerkyness
g_TimerMan.EnableAveraging(true);
// Unpause the sim
g_TimerMan.PauseSim(false);
g_ActivityMan.PauseActivity(false);
}
}
//////////////////////////////////////////////////////////////////////////////////////////
// Launch multiplayer lobby activity
void EnterMultiplayerLobby()
{
//g_ActivityMan.EndActivity();
// Start multiplayer lobby
g_SceneMan.SetSceneToLoad("Multiplayer Scene");
MultiplayerServerLobby *pMultiplayerServerLobby = new MultiplayerServerLobby;
pMultiplayerServerLobby->Create();
pMultiplayerServerLobby->ClearPlayers(true);
pMultiplayerServerLobby->AddPlayer(0, true, 0, 0);
pMultiplayerServerLobby->AddPlayer(1, true, 0, 1);
pMultiplayerServerLobby->AddPlayer(2, true, 0, 2);
pMultiplayerServerLobby->AddPlayer(3, true, 0, 3);
//g_FrameMan.ResetSplitScreens(true, true);
g_ActivityMan.SetStartActivity(pMultiplayerServerLobby);
g_ResetActivity = true;
}
//////////////////////////////////////////////////////////////////////////////////////////
// Load and display the into, title and menu sequence
bool PlayIntroTitle()
{
// Disable time averaging since it can make the music timing creep off target.
g_TimerMan.EnableAveraging(false);
// Untrap the mouse and keyboard
g_UInputMan.DisableKeys(false);
g_UInputMan.TrapMousePos(false);
// Stop all audio
g_AudioMan.StopAll();
g_FrameMan.ClearBackBuffer32();
g_FrameMan.FlipFrameBuffers();
int resX = g_FrameMan.GetResX();
int resY = g_FrameMan.GetResY();
// The fadein/out screens
BITMAP *pFadeScreen = create_bitmap_ex(32, resX, resY);
clear_to_color(pFadeScreen, 0);
int fadePos = 0;
// Load the Intro slides
BITMAP **apIntroSlides = new BITMAP *[SLIDECOUNT];
ContentFile introSlideFile("Base.rte/Title/IntroSlideA.bmp");
apIntroSlides[SLIDEPAST] = introSlideFile.LoadAndReleaseBitmap();
introSlideFile.SetDataPath("Base.rte/Title/IntroSlideB.bmp");
apIntroSlides[SLIDENOW] = introSlideFile.LoadAndReleaseBitmap();
introSlideFile.SetDataPath("Base.rte/Title/IntroSlideC.bmp");
apIntroSlides[SLIDEVR] = introSlideFile.LoadAndReleaseBitmap();
introSlideFile.SetDataPath("Base.rte/Title/IntroSlideD.bmp");
apIntroSlides[SLIDETRAVEL] = introSlideFile.LoadAndReleaseBitmap();
introSlideFile.SetDataPath("Base.rte/Title/IntroSlideE.bmp");
apIntroSlides[SLIDEALIENS] = introSlideFile.LoadAndReleaseBitmap();
introSlideFile.SetDataPath("Base.rte/Title/IntroSlideF.bmp");
apIntroSlides[SLIDETRADE] = introSlideFile.LoadAndReleaseBitmap();
introSlideFile.SetDataPath("Base.rte/Title/IntroSlideG.bmp");
apIntroSlides[SLIDEPEACE] = introSlideFile.LoadAndReleaseBitmap();
introSlideFile.SetDataPath("Base.rte/Title/IntroSlideH.bmp");
apIntroSlides[SLIDEFRONTIER] = introSlideFile.LoadAndReleaseBitmap();
int normalSlideWidth = 640;
int slideFadeDistance = 42;
ContentFile alphaFile;
BITMAP *pAlpha = 0;
MOSParticle *pDRLogo = new MOSParticle();
pDRLogo->Create(ContentFile("Base.rte/Title/DRLogo5x.bmp"));
pDRLogo->SetWrapDoubleDrawing(false);
SceneLayer *pBackdrop = new SceneLayer();
pBackdrop->Create(ContentFile("Base.rte/Title/Nebula.bmp"), false, Vector(), false, false, Vector(0, -1.0));//startYOffset + resY));
float backdropScrollRatio = 1.0f / 3.0f;
MOSParticle *pTitle = new MOSParticle();
pTitle->Create(ContentFile("Base.rte/Title/Title.bmp"));
pTitle->SetWrapDoubleDrawing(false);
// Logo glow effect
MOSParticle *pTitleGlow = new MOSParticle();
pTitleGlow->Create(ContentFile("Base.rte/Title/TitleGlow.bmp"));
pTitleGlow->SetWrapDoubleDrawing(false);
// Add alpha
alphaFile.SetDataPath("Base.rte/Title/TitleAlpha.bmp");
set_write_alpha_blender();
draw_trans_sprite(pTitle->GetSpriteFrame(0), alphaFile.GetAsBitmap(), 0, 0);
MOSParticle *pPlanet = new MOSParticle();
pPlanet->Create(ContentFile("Base.rte/Title/Planet.bmp"));
pPlanet->SetWrapDoubleDrawing(false);
// Add alpha
alphaFile.SetDataPath("Base.rte/Title/PlanetAlpha.bmp");
set_write_alpha_blender();
draw_trans_sprite(pPlanet->GetSpriteFrame(0), alphaFile.GetAsBitmap(), 0, 0);
MOSParticle *pMoon = new MOSParticle();
pMoon->Create(ContentFile("Base.rte/Title/Moon.bmp"));
pMoon->SetWrapDoubleDrawing(false);
// Add alpha
alphaFile.SetDataPath("Base.rte/Title/MoonAlpha.bmp");
set_write_alpha_blender();
draw_trans_sprite(pMoon->GetSpriteFrame(0), alphaFile.GetAsBitmap(), 0, 0);
MOSRotating *pStation = new MOSRotating();
pStation->Create(ContentFile("Base.rte/Title/Station.bmp"));
pStation->SetWrapDoubleDrawing(false);
MOSRotating *pPioneerCapsule = new MOSRotating();
pPioneerCapsule->Create(ContentFile("Base.rte/Title/PioneerCapsule.bmp"));
pPioneerCapsule->SetWrapDoubleDrawing(false);
MOSRotating *pPioneerScreaming = new MOSRotating();
pPioneerScreaming->Create(ContentFile("Base.rte/Title/PioneerScreaming.bmp"));